Skip to content

Fix crash in isolatedDeclarations on this.x = … assignments - #64471

Open
Mateusz Burzyński (Andarist) wants to merge 2 commits into
microsoft:mainfrom
Andarist:fix/isolated-decls-this-expando-crash
Open

Mateusz Burzyński (Andarist) wants to merge 2 commits into
microsoft:mainfrom
Andarist:fix/isolated-decls-this-expando-crash

Conversation

@Andarist

@Andarist Mateusz Burzyński (Andarist) commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

fixes a crash reported here: #64458 (comment) (fallout from microsoft/typescript-go#4513)

…assignments

isBoundExpando resolved the root of any `a.b = ...` assignment as though it
were an identifier, so `this.x = foo()` (and `super.x = ...`, `f().x = ...`)
reached referenceResolver with a non-Identifier and panicked in Node.Text.
Use the same expando-host definition as transformExpandoAssignment: the
leftmost access expression must be an identifier.

Fixes microsoft#64458
Copilot AI balanced review requested due to automatic review settings September 26, 2026 17:49
@typescript-automation typescript-automation Bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Sep 26, 2026
@typescript-automation

Copy link
Copy Markdown

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

if !(ast.IsExpandoPropertyDeclaration(node) && ast.IsPropertyAccessExpression(node.AsBinaryExpression().Left)) {
return false
}
ref := s.resolver.GetReferencedValueDeclarationUnsafe(ast.GetLeftmostExpression(node.AsBinaryExpression().Left, true))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

With isolatedDeclarations on, if a type can't be inferred, the Go declaration emitter reports an error. Before reporting, it checks if the node is inside an expando assignment like f.x = …, so it doesn't report the same problem twice. This check (isBoundExpando) treated every a.b = … assignment as rooted at a name and passed that root to name lookup.

But with this.x = foo() the root is the this keyword, not a name, so the lookup's Node.Text() would just panic.

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.

Copilot review overview

🟢 Approval recommended

The focused guard matches existing transformation behavior and includes regression coverage for the reported crash and related assignment roots.

Review effort: Balanced
Findings: None

What changed in this PR

Prevents declaration emit crashes by rejecting non-identifier-rooted assignments as expando bindings.

Changes:

  • Aligns expando tracking with declaration transformation logic.
  • Adds TypeScript and JavaScript regression coverage.
  • Records expected diagnostics, symbols, types, and declaration output.
File Description
tsc/​internal/​transformers/​declarations/​tracker.go Guards expando resolution by requiring an identifier root.
tsc/​testdata/​tests/​cases/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference.ts Tests this, super, and call-expression assignment roots.
tsc/​testdata/​tests/​cases/​compiler/​isolatedDeclarationsJsThisPropertyAssignmentInference.ts Reproduces the JavaScript this.x crash.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=true).types Captures isolated-declaration types.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=true).symbols Captures isolated-declaration symbols.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=true).errors.txt Captures expected inference diagnostics.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=false).types Captures standard-mode types.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=false).symbols Captures standard-mode symbols.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsNonIdentifierAssignmentInference(isolateddeclarations=false).js Captures declaration output without isolation.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsJsThisPropertyAssignmentInference.types Captures JavaScript inference types.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsJsThisPropertyAssignmentInference.symbols Captures JavaScript symbols.
tsc/​testdata/​baselines/​reference/​compiler/​isolatedDeclarationsJsThisPropertyAssignmentInference.errors.txt Captures JavaScript diagnostics.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

2 participants