Fix panic in the optional-chain transform when a chain ends in a tagged template - #63968
Fix panic in the optional-chain transform when a chain ends in a tagged template#63968bigboateng wants to merge 3 commits into
Conversation
flattenChain stops walking when the chain head is a tagged template, but then unconditionally read chain.Expression(), which is unhandled for TaggedTemplateExpression. Use the template's tag as the chain base and re-tag the template onto the checked value when rebuilding the chain.
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
Pull request overview
Prevents optional-chain lowering from panicking when encountering malformed chains containing tagged templates.
Changes:
- Handles tagged templates when flattening and rebuilding optional chains.
- Adds regression cases and diagnostic, emit, type, and symbol baselines.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tsc/internal/transformers/estransforms/optionalchain.go |
Supports tagged-template chain segments. |
tsc/testdata/tests/cases/compiler/optionalChainTaggedTemplateNoCrash.ts |
Adds regression scenarios. |
tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplateNoCrash.errors.txt |
Captures expected diagnostics. |
tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplateNoCrash.js |
Captures downlevel emit. |
tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplateNoCrash.symbols |
Captures symbol information. |
tsc/testdata/baselines/reference/compiler/optionalChainTaggedTemplateNoCrash.types |
Captures inferred types. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Nit: can we rename this to something that doesn't say "no crash"?
There was a problem hiding this comment.
Renamed to optionalChainTaggedTemplate.ts.
| // @target: es2017 | ||
| // @filename: repro.ts | ||
| e?.``( | ||
| // @filename: siblings.ts |
There was a problem hiding this comment.
Maybe we should ensure that we do the right thing when we don't transform optional chaining away by adding a second target:
| // @target: es2017 | |
| // @filename: repro.ts | |
| e?.``( | |
| // @filename: siblings.ts | |
| // @target: es2017, es2024 | |
| // @filename: repro.ts | |
| e?.``( | |
| // @filename: siblings.ts |
Not sure what others think.
There was a problem hiding this comment.
Good idea, applied as suggested. The es2024 baselines show the chain reaching emit untransformed. The printer keeps ?. on the property access ((a?.b) c), but it drops `?.` on the tagged template itself (`e ();`). There is no legal syntax for a tagged template in an optional chain, which is why TS1358 exists. The output matches what 5.9 emits for the same input, so this is existing behavior, now pinned by the test.
Address review feedback: drop the NoCrash suffix from the test name and add es2024 as a second target so the emit is also covered when optional chaining is not lowered.
Fixes #63965
flattenChainintsc/internal/transformers/estransforms/optionalchain.gowalks inward until the chain head is a tagged template or carries a?.token, but then unconditionally callschain.Expression().TaggedTemplateExpressionhas aTagrather than an expression, soNode.Expression()panics with an unhandled-kind error.The input is malformed (TS1358 makes tagged templates in optional chains a grammar error), but the compiler should report the diagnostics rather than crash — the transform runs regardless because the error is recoverable.
flattenChainstops walking at it). The repro now emitse === null || e === void 0 ? void 0 : e``();.a?.bc``, a tagged template followed by a call, and property access on a tagged-template head).This fix was developed with AI assistance; I reviewed, tested, and take responsibility for every line.