Repository navigation
Fix initialization of nested for loop head declarations - #18088
Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/61819 |
|
commit: |
There was a problem hiding this comment.
Pull request overview
This PR fixes a semantic bug in @babel/plugin-transform-block-scoping where let declarations without initializers inside a nested for-statement initializer could retain their previous value after being lowered to var, changing runtime behavior across outer-loop iterations.
Changes:
- Initialize uninitialized block-scoped declarators in nested
ForStatement.initpositions tovoid 0when lowering tovar. - Preserve existing behavior for loop-body declarations, while avoiding unnecessary initialization for top-level loop-head declarations.
- Add regression fixture covering both expected output and runtime behavior for #18087.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/babel-plugin-transform-block-scoping/src/index.ts | Extends loop-related initialization logic to also cover nested for initializer declarations. |
| packages/babel-plugin-transform-block-scoping/src/loop.ts | Adds helper to detect VariableDeclaration nodes in ForStatement.init. |
| packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-18087/input.js | Adds a minimal reproduction input for the nested for initializer case. |
| packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-18087/output.js | Asserts the transformed output includes = void 0 in the nested for initializer. |
| packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-18087/exec.js | Adds a runtime regression check ensuring the loop runs the expected number of times. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (let done; !done; done = true) { | ||
| count++; | ||
| } | ||
| } |
There was a problem hiding this comment.
Could you add a new test case where a for statement is indirectly nested within another for statement? For example,
for (let outer = 0; outer < 2; outer++) {
do {
for (let done; !done; done = true) {
count++;
}
} while (false)
}There was a problem hiding this comment.
Added the indirect nested case.
This PR fixes an issue in
@babel/plugin-transform-block-scopingwhere an uninitializedletdeclaration in a nestedforstatement initializer could retain its value across outer loop iterations after being transformed tovar.For example:
Before this change, the inner done declaration was transformed without an initializer:
Because
varis function-scoped,donecould keep the value from the previous outer iteration. This PR initializes nestedforstatement initializers withvoid 0when needed:The existing loop-body declaration initialization behavior is preserved, while top-level loop-head declarations are not unnecessarily initialized.
Added a regression fixture for #18087 covering both output and runtime behavior.