fix(transformer/class): parent generated constructors to class scope#23222
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
Pull request overview
Fixes a semantic-scope parenting bug in the TypeScript class-fields lowering path: when a synthesized constructor is generated (for useDefineForClassFields-style lowering), its scope is now parented to the class body scope instead of the enclosing traversal scope, aligning the “after transform” semantic tree with the rebuilt semantic tree.
Changes:
- Create the synthesized constructor’s scope via
ctx.create_child_scope(class_scope_id, ...)instead ofcreate_child_scope_of_current(...). - Update transform conformance snapshots to reflect the corrected scope parenting (and the resulting pass-count change).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| crates/oxc_transformer/src/typescript/class.rs | Parents generated constructor scopes to class_scope_id to match the constructor’s actual placement within the class body. |
| tasks/transform_conformance/snapshots/oxc.snap.md | Updates snapshot output to remove prior scope-parent mismatch reports and reflect the new pass count. |
Merge activity
|
…23222) ## Summary - Parent synthesized constructors for TypeScript class field lowering under the transformed class body scope instead of the current traversal scope. - Update the transform conformance snapshot now that the generated constructor scope matches the rebuilt semantic scope. ## Details When `useDefineForClassFields` lowering needs to synthesize a constructor, the traversal is still positioned in the scope that encloses the class. Static blocks created in the same transform already use `class_scope_id`, but generated constructors used `create_child_scope_of_current`, so their semantic parent could point outside the class. This changes the generated constructor scope creation to use `create_child_scope(class_scope_id, ...)`, matching where the constructor actually lives in the class body. ## Example ```ts class Cls { y = 1; [key] = 2; } ``` Conceptually this transform creates a constructor for the hoisted field initializers: ```ts class Cls { constructor() { this.y = 1; this[key] = 2; } } ``` Before this change, the constructor AST was nested in `Cls`, but its semantic scope was parented to the enclosing scope: ```mermaid flowchart TD Program["Program scope"] --> Class["Class body scope: Cls"] Program --> GeneratedCtor["Generated constructor scope"] Class --> StaticBlocks["Generated static blocks"] ``` After this change, the generated constructor scope is parented to the class body scope, matching the rebuilt semantic tree: ```mermaid flowchart TD Program["Program scope"] --> Class["Class body scope: Cls"] Class --> GeneratedCtor["Generated constructor scope"] Class --> StaticBlocks["Generated static blocks"] ``` The same mismatch showed up in the accessor backing field fixture: ```ts class Hello { private input = { foo }; accessor util = this.input.foo(); } ``` AI assistance: OpenAI Codex was used to prepare this change.
f06ce9f to
2c28748
Compare
### 💥 BREAKING CHANGES - 7a24911 codegen: [**BREAKING**] Borrow sourcemaps from codegen (#23422) (Boshen) - bb0ed44 transformer: [**BREAKING**] Disable styled-components transpileTemplateLiterals by default (#23171) (Boshen) ### 🚀 Features - 1490a0a linter/react: Implement react-compiler rule (#23202) (Boshen) - 6c0bdf0 transformer/react-refresh: Support `module.property.useHook()` (#23190) (Dunqing) - 47991bd semantic: Report TS1228 for invalid type predicates (#23174) (camc314) - 1d3af58 parser: Add TS2398 parameter property diagnostic (#23216) (camc314) - 44313da semantic: Add `scope_is_descendant_of` api (#22313) (camc314) - e5050c0 parser: Improve diagnostic for rest initializer (#23205) (camc314) - ec266bb transformer: Run React Compiler as a feature-gated transform pass (#23201) (Boshen) - e7374fe parser: Report error for `const` modifier on interface type parameter (#23173) (camc314) - a7c1c9b parser: Report ambient definite variable assertions (#23165) (camc314) - d169fcd parser: Report invalid class definite assertions (#23164) (camc314) - 00244d8 parser: Report definite property initializer errors (#23160) (camc314) ### 🐛 Bug Fixes - 52d0c31 transformer: Replace ambient dot defines (#23231) (camc314) - 2c28748 transformer/class: Parent generated constructors to class scope (#23222) (camc314) - 8edd234 parser: Report accessor definite assertion on token (#23203) (camc314) - de38a3f react_compiler: Keep imports referenced only by a local re-export (#23176) (Boshen) - f5721c2 codegen: Preserve parentheses around `intrinsic` type reference (#23156) (Boshen) - e89f81d parser: Don't emit TS1477 for parenthesized instantiation expression (#23147) (Boshen) - 8a04149 parser: Reject module-referencing imports/exports in a namespace body (#22829) (Boshen) ### ⚡ Performance - 2783295 parser: Table-driven operator precedence lookup (#23346) (Boshen) - 231d5de parser: Single-match member expression dispatch (#23347) (Boshen) - e89729b codegen: Accept one-shot wrap closures (#23265) (camc314) - a6c11fa parser: Force-inline read_non_decimal to fold per-digit number dispatch (#23157) (Boshen) - d74964c parser: Store class definite assertion offset (#23170) (camc314) - f0fda4d parser: Shrink-wrap cold diagnostic tails out of hot frames (#23159) (Boshen) - a082180 parser: Store definite assertion offset (#23167) (camc314) - 534f9c6 oxc: Conditionally rebuild semantic in compiler pipeline (#23153) (Boshen) - b435c6a parser: Skip checkpoint for `infer T extends U` constraint in disallow context (#23128) (Boshen) - 7464dce parser: Peek instead of checkpoint/rewind for `export default` modifier (#23124) (Boshen) - 80a9a32 parser: Fast-path single-keyword TS declarations (#23083) (Boshen) - da1a6c6 diagnostics: Migrate to allocation-optimized oxc-miette (#23094) (Boshen) - b7b08ce parser: Peek once for the static modifier disambiguation (#23079) (Boshen) - e7e07a3 parser: Fold unary dispatch into a single match (#23076) (Boshen) ### 📚 Documentation - d241add semantic: Add `AGENTS.md` test guidance for agents (#23441) (camc314) - 026f1ae parser: Add `AGENTS.md` test guidance for agents (#23440) (camc314) - 09755ac transformer: Add `AGENTS.md` test guidance for agents (#23439) (camc314) - e6bdfd4 lexer: Correct reference link for `byte_handlers!` (#23313) (Dunqing) - 65b6d7a allocator: Fix memory leaks in `Arena` examples (#23257) (overlookmotel) Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
…23222) ## Summary - Parent synthesized constructors for TypeScript class field lowering under the transformed class body scope instead of the current traversal scope. - Update the transform conformance snapshot now that the generated constructor scope matches the rebuilt semantic scope. ## Details When `useDefineForClassFields` lowering needs to synthesize a constructor, the traversal is still positioned in the scope that encloses the class. Static blocks created in the same transform already use `class_scope_id`, but generated constructors used `create_child_scope_of_current`, so their semantic parent could point outside the class. This changes the generated constructor scope creation to use `create_child_scope(class_scope_id, ...)`, matching where the constructor actually lives in the class body. ## Example ```ts class Cls { y = 1; [key] = 2; } ``` Conceptually this transform creates a constructor for the hoisted field initializers: ```ts class Cls { constructor() { this.y = 1; this[key] = 2; } } ``` Before this change, the constructor AST was nested in `Cls`, but its semantic scope was parented to the enclosing scope: ```mermaid flowchart TD Program["Program scope"] --> Class["Class body scope: Cls"] Program --> GeneratedCtor["Generated constructor scope"] Class --> StaticBlocks["Generated static blocks"] ``` After this change, the generated constructor scope is parented to the class body scope, matching the rebuilt semantic tree: ```mermaid flowchart TD Program["Program scope"] --> Class["Class body scope: Cls"] Class --> GeneratedCtor["Generated constructor scope"] Class --> StaticBlocks["Generated static blocks"] ``` The same mismatch showed up in the accessor backing field fixture: ```ts class Hello { private input = { foo }; accessor util = this.input.foo(); } ``` AI assistance: OpenAI Codex was used to prepare this change.
### 💥 BREAKING CHANGES - 7a24911 codegen: [**BREAKING**] Borrow sourcemaps from codegen (#23422) (Boshen) - bb0ed44 transformer: [**BREAKING**] Disable styled-components transpileTemplateLiterals by default (#23171) (Boshen) ### 🚀 Features - 1490a0a linter/react: Implement react-compiler rule (#23202) (Boshen) - 6c0bdf0 transformer/react-refresh: Support `module.property.useHook()` (#23190) (Dunqing) - 47991bd semantic: Report TS1228 for invalid type predicates (#23174) (camc314) - 1d3af58 parser: Add TS2398 parameter property diagnostic (#23216) (camc314) - 44313da semantic: Add `scope_is_descendant_of` api (#22313) (camc314) - e5050c0 parser: Improve diagnostic for rest initializer (#23205) (camc314) - ec266bb transformer: Run React Compiler as a feature-gated transform pass (#23201) (Boshen) - e7374fe parser: Report error for `const` modifier on interface type parameter (#23173) (camc314) - a7c1c9b parser: Report ambient definite variable assertions (#23165) (camc314) - d169fcd parser: Report invalid class definite assertions (#23164) (camc314) - 00244d8 parser: Report definite property initializer errors (#23160) (camc314) ### 🐛 Bug Fixes - 52d0c31 transformer: Replace ambient dot defines (#23231) (camc314) - 2c28748 transformer/class: Parent generated constructors to class scope (#23222) (camc314) - 8edd234 parser: Report accessor definite assertion on token (#23203) (camc314) - de38a3f react_compiler: Keep imports referenced only by a local re-export (#23176) (Boshen) - f5721c2 codegen: Preserve parentheses around `intrinsic` type reference (#23156) (Boshen) - e89f81d parser: Don't emit TS1477 for parenthesized instantiation expression (#23147) (Boshen) - 8a04149 parser: Reject module-referencing imports/exports in a namespace body (#22829) (Boshen) ### ⚡ Performance - 2783295 parser: Table-driven operator precedence lookup (#23346) (Boshen) - 231d5de parser: Single-match member expression dispatch (#23347) (Boshen) - e89729b codegen: Accept one-shot wrap closures (#23265) (camc314) - a6c11fa parser: Force-inline read_non_decimal to fold per-digit number dispatch (#23157) (Boshen) - d74964c parser: Store class definite assertion offset (#23170) (camc314) - f0fda4d parser: Shrink-wrap cold diagnostic tails out of hot frames (#23159) (Boshen) - a082180 parser: Store definite assertion offset (#23167) (camc314) - 534f9c6 oxc: Conditionally rebuild semantic in compiler pipeline (#23153) (Boshen) - b435c6a parser: Skip checkpoint for `infer T extends U` constraint in disallow context (#23128) (Boshen) - 7464dce parser: Peek instead of checkpoint/rewind for `export default` modifier (#23124) (Boshen) - 80a9a32 parser: Fast-path single-keyword TS declarations (#23083) (Boshen) - da1a6c6 diagnostics: Migrate to allocation-optimized oxc-miette (#23094) (Boshen) - b7b08ce parser: Peek once for the static modifier disambiguation (#23079) (Boshen) - e7e07a3 parser: Fold unary dispatch into a single match (#23076) (Boshen) ### 📚 Documentation - d241add semantic: Add `AGENTS.md` test guidance for agents (#23441) (camc314) - 026f1ae parser: Add `AGENTS.md` test guidance for agents (#23440) (camc314) - 09755ac transformer: Add `AGENTS.md` test guidance for agents (#23439) (camc314) - e6bdfd4 lexer: Correct reference link for `byte_handlers!` (#23313) (Dunqing) - 65b6d7a allocator: Fix memory leaks in `Arena` examples (#23257) (overlookmotel) Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Summary
Details
When
useDefineForClassFieldslowering needs to synthesize a constructor, the traversal is still positioned in the scope that encloses the class. Static blocks created in the same transform already useclass_scope_id, but generated constructors usedcreate_child_scope_of_current, so their semantic parent could point outside the class.This changes the generated constructor scope creation to use
create_child_scope(class_scope_id, ...), matching where the constructor actually lives in the class body.Example
Conceptually this transform creates a constructor for the hoisted field initializers:
Before this change, the constructor AST was nested in
Cls, but its semantic scope was parented to the enclosing scope:After this change, the generated constructor scope is parented to the class body scope, matching the rebuilt semantic tree:
The same mismatch showed up in the accessor backing field fixture:
AI assistance: OpenAI Codex was used to prepare this change.