[compiler] Refactor checker to use context, fixing template decorator bugs#9588
Merged
timotheeguerin merged 9 commits intomicrosoft:mainfrom Feb 6, 2026
Merged
Conversation
commit: |
Contributor
|
All changed packages have been documented.
Show changes
|
Collaborator
|
You can try these changes here
|
timotheeguerin
approved these changes
Feb 6, 2026
github-merge-queue bot
pushed a commit
that referenced
this pull request
Feb 6, 2026
… bugs (#9588) This PR fixes several bugs related to the logic around running decorators on templates. Current decorator logic is insufficient because it is based on whether the `mapper` is set and the node has template arguments, but we have cases where this logic breaks down, like: ```tsp alias F<T> = { @dec prop: T; // dec runs here and observes uninstantiated `T`! } ``` ```tsp model X<T1> { prop: Y<T1>; } alias Y<T2> = { // This dec runs _twice_, once in the context of `Y`, observing uninstantiated `T2`, and // then _again_ in the context of `X` -> `Y<T1>`, observing uninstantiated `T1`. @dec prop: T2; } ``` This change fixes those problems by refactoring the checker to work with an immutable `CheckContext` that is passed through the checker API. Checking always begins with `CheckContext.DEFAULT` at any checker API entrypoint. The context carries (a) the current TypeMapper, (b) an integer set of flags (there is currently one flag: `CheckFlags.InTemplateDeclaration`), and (c) a set of observed template parameter instances in a certain scope. **There are no public API changes to the Checker, only internal changes to allow the Checker itself to pass `CheckContext` to functions that are also exposed in the public API without that option.** The context manages the state required to track whether the checker is currently declaring a template and how it should behave as it traverses references to declared types. - When the checker visits a declaration, it activates `CheckFlags.InTemplateDeclaration` if there is no type mapper, and the node has template parameters. - When the checker goes through a type reference, it deactivates `CheckFlags.InTemplateDeclaration` if the type reference is _concrete_ (does not contain a template parameter). - Under this model, logic around running decorators entirely collapses to `ctx.hasFlags(CheckFlags.InTemplateDeclaration)`, and decorators will only run on fully concrete instances and will be inhibited on any type instance that references a template parameter.
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.
This PR fixes several bugs related to the logic around running decorators on templates. Current decorator logic is insufficient because it is based on whether the
mapperis set and the node has template arguments, but we have cases where this logic breaks down, like:This change fixes those problems by refactoring the checker to work with an immutable
CheckContextthat is passed through the checker API. Checking always begins withCheckContext.DEFAULTat any checker API entrypoint. The context carries (a) the current TypeMapper, (b) an integer set of flags (there is currently one flag:CheckFlags.InTemplateDeclaration), and (c) a set of observed template parameter instances in a certain scope.There are no public API changes to the Checker, only internal changes to allow the Checker itself to pass
CheckContextto functions that are also exposed in the public API without that option.The context manages the state required to track whether the checker is currently declaring a template and how it should behave as it traverses references to declared types.
CheckFlags.InTemplateDeclarationif there is no type mapper, and the node has template parameters.CheckFlags.InTemplateDeclarationif the type reference is concrete (does not contain a template parameter).ctx.hasFlags(CheckFlags.InTemplateDeclaration), and decorators will only run on fully concrete instances and will be inhibited on any type instance that references a template parameter.