Skip to content

Commit 848e2c5

Browse files
committed
fix: keep a sibling declarator's dead-zone read out of a let merge
Hoisting a let-before-a-loop assignment into its declaration (added by this branch) can fold a later declarator's read into an earlier one, throwing where the un-hoisted statements ran fine. Reject a value that reads any declarator at or after the one being filled, not just itself. CodeRabbit found this reviewing the hoist commit.
1 parent 8d56ddc commit 848e2c5

2 files changed

Lines changed: 19 additions & 3 deletions

File tree

‎lib/javascript/syntax-printer.js‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32000,14 +32000,19 @@ const installImprove = (modules) => {
3200032000
) {
3200132001
break;
3200232002
}
32003-
// Moved into the declaration, a read of the `let` is in its dead zone:
32004-
// one in the value, or one in a function or `eval` the value may run.
32003+
// Moved into the declaration, a read of the `let` is in its dead
32004+
// zone: itself, a declarator the same `let` declares after it,
32005+
// or one in a function or `eval` the value may run.
3200532006
if (
3200632007
!isVar &&
3200732008
(A.walk(assign.right, (/** @type {Node} */ node) =>
3200832009
A.isLambdaNode(node)
3200932010
? true
32010-
: A.isSymbolRefNode(node) && node.definition === definition
32011+
: A.isSymbolRefNode(node) &&
32012+
declarations.some(
32013+
(/** @type {Node} */ sibling, /** @type {number} */ j) =>
32014+
j >= index && sibling.id.definition === node.definition
32015+
)
3201132016
? A.walk_abort
3201232017
: undefined
3201332018
) ||

‎test/unitCases/javascript/printer.unittest.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9772,6 +9772,17 @@ describe("syntax-printer", () => {
97729772
}
97739773
});
97749774

9775+
it("should keep an assignment out of a `let` declaration where its value reads a declarator the same `let` declares after it, in its dead zone", async () => {
9776+
const { minify } = await load();
9777+
for (const input of [
9778+
"function f() { let a, b; b = (() => 1)(); for (a = b; a < 3; a++) console.log(a, b); return a; } console.log(f());",
9779+
"function f() { let b, a; a = b = (() => 1)(); for (; a < 3; a++) console.log(a, b); return a; } console.log(f());"
9780+
]) {
9781+
const { code } = await minify(input, { compress: {}, mangle: false });
9782+
expect(runProgram(/** @type {string} */ (code))).toBe(runProgram(input));
9783+
}
9784+
});
9785+
97759786
it("should keep a literal's missing key a built-in's prototype the program writes may hold", async () => {
97769787
const { minify } = await load();
97779788
for (const input of [

0 commit comments

Comments
 (0)