Repository navigation
fix: Fix MemberList panic on merged enum element access - #64746
Andre Fajar N (andre-fajar-n) wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Alias exports targeting enum members must be resolved before applying the new flag guard.
1 open finding
What changed in this PR
Prevents a compiler panic when bracket access resolves to a non-enum export on a merged enum/namespace.
Changes:
- Guards enum evaluation with
SymbolFlagsEnumMember. - Adds a regression test and diagnostic, emit, type, and symbol baselines.
| File | Description |
|---|---|
tsc/internal/checker/checker.go |
Restricts bracket-access enum evaluation. |
tsc/testdata/tests/cases/compiler/enumInitializerNamespaceExportElementAccess.ts |
Adds the crash regression case. |
tsc/testdata/baselines/reference/compiler/enumInitializerNamespaceExportElementAccess.errors.txt |
Records TS18033. |
tsc/testdata/baselines/reference/compiler/enumInitializerNamespaceExportElementAccess.js |
Records emitted JavaScript. |
tsc/testdata/baselines/reference/compiler/enumInitializerNamespaceExportElementAccess.symbols |
Records resolved symbols. |
tsc/testdata/baselines/reference/compiler/enumInitializerNamespaceExportElementAccess.types |
Records inferred types. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Wesley Wigham (weswigham)
left a comment
There was a problem hiding this comment.
Good, but needs a bit of cleanup.
| if location != nil { | ||
| return c.evaluateEnumMember(expr, member, location) | ||
| // Follow aliases like resolveEntityName (property-access path), e.g. export import C = F.A. | ||
| for member.Flags()&ast.SymbolFlagsValue == 0 && member.Flags()&ast.SymbolFlagsAlias != 0 { |
There was a problem hiding this comment.
Extract this to a helper we can share with resolveEntityName, so the comment is less needed. (resolveAliasRecursively?) It's interesting that these two places are the only ones we actually do a fully recursive alias resolve.
| } | ||
| // Merged namespace+enum symbols can export non-enum members (e.g. a class). | ||
| // Only treat EnumMember exports as constant enum values — mirror the identifier path. | ||
| if member.Flags()&ast.SymbolFlagsEnumMember != 0 { |
There was a problem hiding this comment.
And extract this to a helper we can share with the Identifier+PropertyAccessExpression case, so it's clear we're doing the same thing and stays in-sync. Or shift it to a common block after the switch for the same reason - that might be better.

Fixes #64668
AI assistance disclosure: This patch was authored with Cursor (AI coding agent). I
have read and understood the change, and I will shepherd review and revisions myself.
Analysis
When an enum and a namespace share a name, element access like
E["C"]in an enummember initializer can resolve a namespace export (e.g. a class) via
rootSymbol.Exports()[name].The element-access path in
evaluateEntitytreated any non-nil export as an enum memberand called
getEnumMemberValue→computeEnumMemberValues(node.Parent)→Members().For a class declaration,
Parentis aModuleBlock, soNode.MemberListpanicked:panic: Unhandled case in Node.MemberList: KindModuleBlockRepro:
The identifier/property-access path already requires
SymbolFlagsEnumMember; elementaccess did not.
Fix
In
evaluateEntity'sKindElementAccessExpressionbranch, only constant-evaluate whenthe export has
SymbolFlagsEnumMember(same guard as the identifier path).Non-enum-member exports fall through to a non-constant result and produce a normal
diagnostic (TS18033) instead of crashing.
Alternate considered: widening
Node.MemberListto acceptKindModuleBlock— rejected;the bug is incorrect enum evaluation, not a missing AST list case.