Skip to content

fix(checker): avoid stack overflow for self-referential computed enum member names#63567

Open
yen0304 wants to merge 1 commit into
microsoft:mainfrom
yen0304:fix/enum-computed-name-self-reference-crash
Open

fix(checker): avoid stack overflow for self-referential computed enum member names#63567
yen0304 wants to merge 1 commit into
microsoft:mainfrom
yen0304:fix/enum-computed-name-self-reference-crash

Conversation

@yen0304

@yen0304 yen0304 commented Jun 20, 2026

Copy link
Copy Markdown

Fixes #63173

Problem

A computed enum member name that refers back to a member of the same enum crashes the checker with RangeError: Maximum call stack size exceeded:

declare const enum E {
    [object] = 1,
    A,
    object = 10,
}
E.A.toString();

Root cause

getDeclaredTypeOfEnum iterates the members and calls hasBindableName(member) for each. For the computed name [object], that goes through hasLateBindableNamecheckComputedPropertyName, which resolves the type of the referenced member object. Resolving an enum member's type calls getDeclaredTypeOfEnumMembergetDeclaredTypeOfEnum for the same enum, whose declared type is not set until the member loop finishes — so determining [object]'s bindability requires the enum type, which requires [object]'s bindability, and so on until the stack overflows.

Observed stack:

hasDynamicName  ->  hasBindableName  ->  getDeclaredTypeOfEnum  ->  getDeclaredTypeOfEnumMember
 ->  getTypeOfEnumMember  ->  getTypeOfSymbol  ->  getNarrowedTypeOfSymbol  ->  checkIdentifier  ->  ...

Fix

Track the enum symbols whose member names are currently being late-bound (enumsResolvingLateBoundNames). While an enum is in that set, computed (dynamic) member names are treated as non-bindable rather than being late-bound again, which breaks the cycle.

This only changes behavior for the recursive case:

  • Computed property names are not permitted on enum members anyway — TS1164 is still reported, so this path is always already an error.
  • The benign, terminating re-entrancy that ordinary enums rely on (e.g. a member initializer that reads another member, as in the existing enumBasics2/enumBasics3 tests) goes through initializer evaluation, not name late-binding, so it is unaffected. Only the late-binding determination is guarded.

After the fix the example no longer crashes and reports the expected error:

error TS1164: Computed property names are not allowed in enums.

Tests

  • Added tests/cases/compiler/enumComputedNameSelfReferenceCrash.ts covering const enum (ambient and non-ambient) and a regular enum, with both bare-identifier ([object]) and qualified ([F.A]) computed names.
  • hereby runtests — full suite passes (106373 passing, 0 failing); no baseline changes outside the new test.
  • hereby lint clean on the changed file.

… member names

A computed enum member name that refers back to a member of the same enum
(e.g. `enum E { [object] = 1, object = 2 }`) caused the checker to recurse until
the stack overflowed: getDeclaredTypeOfEnum determines whether each member name
is late-bindable, which resolves the referenced member's type, which re-enters
getDeclaredTypeOfEnum for the same enum.

Track the enums whose member names are currently being late-bound and skip
late-binding of computed names while that resolution is in progress. Computed
names are not permitted on enum members anyway (TS1164 is still reported), so
this only affects already-invalid code, and the non-recursive paths are
unchanged (no baseline updates outside the new regression test).

Fixes microsoft#63173
Copilot AI review requested due to automatic review settings June 20, 2026 06:08
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Jun 20, 2026
@typescript-automation typescript-automation Bot added the For Backlog Bug PRs that fix a backlog bug label Jun 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a checker stack overflow triggered by self-referential computed enum member names (invalid code, but should not crash). The change adds a re-entrancy guard during enum declared-type construction and introduces a compiler regression test covering const enum (ambient + non-ambient) and regular enum cases.

Changes:

  • Add enumsResolvingLateBoundNames tracking to prevent recursive late-binding of computed enum member names from re-entering getDeclaredTypeOfEnum indefinitely.
  • Adjust enum declared-type caching to avoid overwriting a declared type that may have been established by a re-entrant call.
  • Add a compiler test + baselines to ensure the scenario reports TS1164 and does not crash.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/compiler/checker.ts Adds a recursion guard when determining enum member name bindability during enum type construction.
tests/cases/compiler/enumComputedNameSelfReferenceCrash.ts New regression test reproducing the prior stack overflow and validating non-crash behavior.
tests/baselines/reference/enumComputedNameSelfReferenceCrash.errors.txt Baseline for expected TS1164 diagnostics.
tests/baselines/reference/enumComputedNameSelfReferenceCrash.js Baseline for JS/declaration emit under error conditions.
tests/baselines/reference/enumComputedNameSelfReferenceCrash.symbols Baseline for symbol binding expectations in the test.
tests/baselines/reference/enumComputedNameSelfReferenceCrash.types Baseline for type display expectations in the test.

Comment thread src/compiler/checker.ts
Comment on lines 13563 to +13567
for (const declaration of symbol.declarations) {
if (declaration.kind === SyntaxKind.EnumDeclaration) {
for (const member of (declaration as EnumDeclaration).members) {
if (hasBindableName(member)) {
const bindable = resolvingLateBoundNames ? !hasDynamicName(member) : hasBindableName(member);
if (bindable) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Crash: Maximum call stack size exceeded when declare const enum has a computed property named [object] followed by an object member

2 participants