Repository navigation
Fix escaped keyword ASI (#64883) and new-expression emit parens (#64981) - #65013
Timur Vural (timurzvural) wants to merge 1 commit into
Conversation
…ens (microsoft#64981) - Do not treat Unicode-escaped keywords as binary operators so `\u{69}n` / `\u{69}nstanceof` after a class field initializer become IdentifierNames (microsoft#64883). - Parenthesize new-expression operands whose leftmost expression is a call, including after as/satisfies/non-null erasure, so `new (f() as T).C()` emits as `new (f().C)()` (microsoft#64981). - Add regression tests for parser, printer, and type eraser. AI assistance disclosure: this change was authored with Cursor Agent.
|
Why are there two fixes in one PR |
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
🟡 Changes recommended
The shared helper’s deeper traversal adds redundant parentheses to already-parenthesized arrow bodies, conflicting with existing emit baselines; it should be scoped to the new-expression check.
1 open issue
What changed in this PR
This PR addresses two native TypeScript compiler bugs: escaped keywords preventing automatic semicolon insertion after class fields (#64883), and missing parentheses changing the meaning of emitted new expressions (#64981).
Changes:
- Exclude Unicode-escaped keywords from binary-operator parsing.
- Detect calls within constructor expressions to preserve required parentheses.
- Add parser, printer, and type-erasure regression tests.
| File | Description |
|---|---|
tsc/internal/transformers/tstransforms/typeeraser_test.go |
Tests constructor grouping after type syntax is erased. |
tsc/internal/printer/printer.go |
Extends call detection when emitting new expressions. |
tsc/internal/printer/printer_test.go |
Tests constructor property access rooted in a call. |
tsc/internal/parser/parser.go |
Prevents escaped keywords from acting as binary operators. |
tsc/internal/parser/parser_test.go |
Tests escaped class fields and unescaped in continuation. |
tsc/internal/ast/precedence.go |
Makes leftmost-expression traversal cross parentheses. |
Review effort: Balanced
| KindPropertyAccessExpression, | ||
| KindNonNullExpression, | ||
| KindPartiallyEmittedExpression, | ||
| KindParenthesizedExpression, |
|
Closing this combined PR in favor of two focused single-issue PRs (one bug each):
Please review those instead. Thanks! |

Summary
Fixes two native Go / TS7+ bugs:
Fixes #64883 — Escaped
in/instanceofafter class field initializersAfter a class field initializer, Unicode-escaped
\u{69}n/\u{69}nstanceofon the next line were parsed as thein/instanceofoperators (TS1260 + parse error). Per ECMA-262, keyword terminals cannot be expressed with Unicode escapes, so these should be IdentifierNames (matching V8).Change: Treat escaped keywords as non-operators in the binary-operator path so ASI can end the previous expression and the escaped name can start a new class member. Unescaped
inafter a field initializer still continues the expression (test262fields-asi-5.js).Fixes #64981 —
new (f() as T).C()drops required parentheses on emitnew (getPlugins() as any).Linker()was emitted asnew getPlugins().Linker()(i.e.(new getPlugins()).Linker()), causing a runtime TypeError.Change: Parenthesize when the leftmost expression (stopping at calls, walking through parentheses / partially-emitted / assertion wrappers) is a
CallExpression, matching classic TS6 emit:new (getPlugins().Linker)().Test plan
parser_test.go,printer_test.go, andtypeeraser_test.goAI assistance disclosure
This change was authored with Cursor Agent (an LLM-based coding agent). A human operator directed the investigation at these specific open issues, reviewed the resulting patch, and is submitting it for review. Per CONTRIBUTING.md, AI tool use is disclosed here.