[compiler] Add Realm.asProgram() facade for chained mutation pipelines#10693
Draft
FionaBronwen wants to merge 1 commit into
Draft
[compiler] Add Realm.asProgram() facade for chained mutation pipelines#10693FionaBronwen wants to merge 1 commit into
FionaBronwen wants to merge 1 commit into
Conversation
Today the mutator framework returns a Realm. Realm holds cloned types and a
layered state map but does not implement Program, so it cannot be fed back
into the next mutation stage or consumed by emitters that expect a Program.
This change makes a mutated realm consumable as a Program:
- Realm gains an optional cloned global namespace slot (#globalNamespace)
with a public getter and an internal setter (setGlobalNamespace). The
mutator engine records the cloned global on the realm when it runs a
namespace-rooted mutation.
- Realm.asProgram() returns a Program-shaped facade. Pass-through members
(compilerOptions, host, checker, resolver, sourceFiles, etc.) come from
the parent program. Realm-aware overrides reflect realm-local state:
* getGlobalNamespaceType -> the cloned global if recorded, otherwise
the parent's global
* stateMap, stateSet -> realm-layered views (writes are realm-local;
reads fall back to the parent and to original types via the clone
back-link)
* stateMaps, stateSets -> proxy views that route per-key lookups
through the layered stateMap/stateSet helpers
- StateMapRealmView and the new StateSetRealmView fall back to the parent's
state keyed by the original type when reading on a clone. This is
achieved through a non-enumerable Symbol-for back-link recorded at clone
time (Realm.cloneIntoRealm), so decorator state set on the original
remains visible under the clone without an eager copy.
Multiple stages can now be chained as:
const stage1 = mutateSubgraphWithNamespace(program, ms1, program.getGlobalNamespaceType());
const p1 = stage1.realm?.asProgram() ?? program;
const stage2 = mutateSubgraphWithNamespace(p1, ms2, p1.getGlobalNamespaceType());
...
A new test file (test/experimental/realm-as-program.test.ts) exercises the
facade end-to-end: getGlobalNamespaceType returns the cloned tree,
navigateProgram on the facade walks the mutated tree, and a two-stage chain
sees both stage 1 and stage 2 mutations. All existing experimental tests
continue to pass.
Member
There was a problem hiding this comment.
an intresting approach, I had some branch where I experimented with something that I believe also solve the same issue you are trying to solve here but introducing the concept of type graph. A program can then have multiple type graphs which can have realms. But the idea unlike realm which are mixed a type graph is a completely independent version. It felt like it worked well for what my pr was doing(adding typespec emitter options instead of json schema) but also was opening the door for having those type graph mutator that would take a type graph and return a whole new one
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Today the mutator framework returns a
Realm.Realmholds cloned types and a layered state map but does not implementProgram, so it cannot be fed back into a subsequent mutation stage or consumed by emitters that expect aProgram.This change makes a mutated realm consumable as a
Program:Realmgains an optional cloned global namespace slot (#globalNamespace) with a public getter and an internal setter (setGlobalNamespace). The mutator engine records the cloned global on the realm when it runs a namespace-rooted mutation.Realm.asProgram()returns aProgram-shaped facade. Pass-through members (compilerOptions,host,checker,resolver,sourceFiles, etc.) come from the parent program. Realm-aware overrides reflect realm-local state:getGlobalNamespaceType-> the cloned global if recorded, otherwise the parent's globalstateMap,stateSet-> realm-layered views (writes are realm-local; reads fall back to the parent and to original types via the clone back-link)stateMaps,stateSets-> proxy views that route per-key lookups through the layeredstateMap/stateSethelpersStateMapRealmViewand the newStateSetRealmViewfall back to the parent's state keyed by the original type when reading on a clone. This is achieved through a non-enumerable Symbol-for back-link recorded at clone time (Realm.cloneIntoRealm), so decorator state set on the original remains visible under the clone without an eager copy.Multiple mutation stages can now be chained as:
A new test file (
test/experimental/realm-as-program.test.ts) exercises the facade end-to-end:getGlobalNamespaceTypereturns the cloned tree,navigateProgramon the facade walks the mutated tree, and a two-stage chain sees both stage 1 and stage 2 mutations. All existing experimental tests continue to pass.