Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/pink-gifts-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
swc_ecma_minifier: patch
swc_core: patch
---

fix(es/minifier): Prevent array destructuring optimization in assignment contexts
12 changes: 12 additions & 0 deletions crates/swc_ecma_minifier/src/compress/pure/evaluate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ impl Pure<'_> {
return;
}

// Don't optimize arrays used as assignment targets in destructuring
// assignments, as delete operands, or as arguments to update operators
// (++/--). This prevents invalid transformations like: [obj.prop] =
// [true] => [!0] = [!0]
if self.ctx.intersects(
Ctx::IN_DELETE
.union(Ctx::IS_UPDATE_ARG)
.union(Ctx::IS_LHS_OF_ASSIGN),
) {
return;
}
Comment on lines +80 to +86
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 76-79 states this prevents transformations like '[obj.prop] = [true] => [!0] = [!0]', but this example is misleading. The actual problematic transformation would be '[obj.prop] = [true] => [obj.prop] = [!0]' where the right-hand side array's boolean literal gets optimized. The left-hand side array should never be transformed to '[!0]' as it's an assignment target, not a literal.

Copilot uses AI. Check for mistakes.

let Expr::Array(ArrayLit { elems, .. }) = e else {
return;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"booleans": true,
"properties": true,
"evaluate": true
}
19 changes: 19 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/11084/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Test case 1: Object property destructuring assignment
const bin = { hasMore: false, hasDisorder: false };
[bin.hasMore, bin.hasDisorder] = [true, true];
console.log(bin.hasMore, bin.hasDisorder);

// Test case 2: Array element destructuring assignment
const arr = [1, 2];
[arr[0], arr[1]] = [arr[1], arr[0]];
console.log(arr);

// Test case 3: Nested object destructuring
const obj = { a: { x: 0 }, b: { y: 0 } };
[obj.a.x, obj.b.y] = [10, 20];
console.log(obj.a.x, obj.b.y);

// Test case 4: Mixed literals and expressions
const state = { flag: false };
[state.flag] = [true];
console.log(state.flag);
42 changes: 42 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/11084/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Test case 1: Object property destructuring assignment
const bin = {
hasMore: !1,
hasDisorder: !1
};
[bin.hasMore, bin.hasDisorder] = [
!0,
!0
];
console.log(bin.hasMore, bin.hasDisorder);
// Test case 2: Array element destructuring assignment
const arr = [
1,
2
];
[arr[0], arr[1]] = [
arr[1],
arr[0]
];
console.log(arr);
// Test case 3: Nested object destructuring
const obj = {
a: {
x: 0
},
b: {
y: 0
}
};
[obj.a.x, obj.b.y] = [
10,
20
];
console.log(obj.a.x, obj.b.y);
// Test case 4: Mixed literals and expressions
const state = {
flag: !1
};
[state.flag] = [
!0
];
console.log(state.flag);
Loading