feat(compiler): allow declarations to be used as expressions#11019
Draft
timotheeguerin wants to merge 7 commits into
Draft
feat(compiler): allow declarations to be used as expressions#11019timotheeguerin wants to merge 7 commits into
timotheeguerin wants to merge 7 commits into
Conversation
Allow model, enum, union, and scalar declarations to be used in expression position (e.g. alias RHS, property types). In expression position they are anonymous (name is "") and the resulting type has expression: true; they are not registered in the enclosing namespace. A diagnostic is reported when template parameters are used on a declaration in expression position.
commit: |
Contributor
|
All changed packages have been documented.
Show changes
|
|
You can try these changes here
|
A keyword-form union (`union { a, b }`) used in expression position is marked
`expression: true`, which caused checkUnionExpression to flatten its (possibly
named) variants into the parent union, silently dropping colliding members.
Flatten only unions originating from the `|` operator (UnionExpression node).
Add tests for: - expression: false on statement declarations - name retention on named declaration expressions - named expressions not being referenceable - union namespace non-registration - alias-resolved types, op return/param, union variant usage - member access via alias, decorator rejection - enum values, union named variants, scalar constructors, model spread - parser negatives for interface/op in expression position - formatter named & nested declaration expressions
Anonymous declarations used in expression position rendered with a stray
namespace prefix (e.g. `Ns.` for enum/scalar, `Ns.{ x: string }` for
keyword-form model). Render them inline and un-prefixed, mirroring union
expression naming.
Also extract a single shared `isDeclarationInExpressionPosition` helper used
by both the binder and checker so the two position predicates cannot drift,
and add regression tests (type names, keyword-form union as `|` operand,
template parameter referenced inside an expression declaration).
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.
Summary
Allow
model,enum,union, andscalardeclarations to be used as expressions (e.g. the right-hand side of analias, property types, return types, union variants).In expression position these declarations:
nameis""expression: true(so the type graph explicitly records that it came from an expression)Named forms in expression position are also allowed (e.g.
nested: model Inner { x: string }), and declarations can be nested.Approach
Rather than introducing new
*ExpressionAST node kinds, the existing statement node kinds are reused with an optionalid(OptionallyNamedDeclarationNode), and these kinds are added to theExpressionunion. Whether a declaration is in statement vs expression position is determined by its parent node kind.OptionallyNamedDeclarationNode(optionalid);expression: booleanonModel/Enum/Scalar(Unionalready had it); the 4 statement kinds added to theExpressionunion.parsePrimaryExpressiondispatch for themodel/enum/union/scalarkeywords; ascalarin expression position no longer consumes the alias trailing;."-"symbol) vs named binding depending on position.name/expression; skip namespace registration for expression-form types; route expression decls through the namespace walk-up ingetParentNamespaceType; newtemplated-declaration-in-expressiondiagnostic.;for anonymous scalars.id.Diagnostics
Template parameters on a declaration in expression position are rejected (
templated-declaration-in-expression) since an anonymous declaration cannot be referenced or instantiated.Tests
test/checker/declaration-expressions.test.ts(14 tests)test/parser.test.ts— new "declaration expressions" block (11 cases)test/formatter/formatter.test.ts— new "declaration expressions" block (5 cases)Full compiler suite: 3982 passed / 6 skipped.
tsc --noEmit,pnpm format, andpnpm lintare all clean.Follow-ups (not in this PR)
Type.namebut not referenceable).Expressionunion members.