Skip to content

Commit e9b3ef1

Browse files
Fix holes handling in optimized array destructuring (#14984)
1 parent 4748947 commit e9b3ef1

5 files changed

Lines changed: 35 additions & 19 deletions

File tree

packages/babel-plugin-transform-destructuring/src/util.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import type { File } from "@babel/core";
33
import type { Scope, NodePath } from "@babel/traverse";
44
import type { TraversalAncestors } from "@babel/types";
55

6+
function isPureVoid(node: t.Node) {
7+
return (
8+
t.isUnaryExpression(node) &&
9+
node.operator === "void" &&
10+
t.isPureish(node.argument)
11+
);
12+
}
13+
614
export function unshiftForXStatementBody(
715
statementPath: NodePath<t.ForXStatement>,
816
newStatements: t.Statement[],
@@ -194,10 +202,11 @@ export class DestructuringTransformer {
194202
{ left, right }: t.AssignmentPattern,
195203
valueRef: t.Expression | null,
196204
) {
197-
// handle array init hole
198-
// const [x = 42] = [,];
205+
// handle array init with void 0. This also happens when
206+
// the value was originally a hole.
207+
// const [x = 42] = [void 0,];
199208
// -> const x = 42;
200-
if (valueRef === null) {
209+
if (isPureVoid(valueRef)) {
201210
this.push(left, right);
202211
return;
203212
}
@@ -274,15 +283,15 @@ export class DestructuringTransformer {
274283
}
275284
}
276285

277-
pushObjectPattern(pattern: t.ObjectPattern, objRef: t.Expression | null) {
286+
pushObjectPattern(pattern: t.ObjectPattern, objRef: t.Expression) {
278287
// https://github.com/babel/babel/issues/681
279288

280-
if (!pattern.properties.length || objRef === null) {
289+
if (!pattern.properties.length) {
281290
this.nodes.push(
282291
t.expressionStatement(
283292
t.callExpression(
284293
this.addHelper("objectDestructuringEmpty"),
285-
objRef !== null ? [objRef] : [],
294+
isPureVoid(objRef) ? [] : [objRef],
286295
),
287296
),
288297
);
@@ -391,12 +400,18 @@ export class DestructuringTransformer {
391400
pattern: t.ArrayPattern,
392401
arr: UnpackableArrayExpression,
393402
) {
403+
const holeToUndefined = (el: t.Expression) =>
404+
el ?? this.scope.buildUndefinedNode();
405+
394406
for (let i = 0; i < pattern.elements.length; i++) {
395407
const elem = pattern.elements[i];
396408
if (t.isRestElement(elem)) {
397-
this.push(elem.argument, t.arrayExpression(arr.elements.slice(i)));
409+
this.push(
410+
elem.argument,
411+
t.arrayExpression(arr.elements.slice(i).map(holeToUndefined)),
412+
);
398413
} else {
399-
this.push(elem, arr.elements[i]);
414+
this.push(elem, holeToUndefined(arr.elements[i]));
400415
}
401416
}
402417
}

packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/array-unpack-optimisation/output.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var _ref7 = [clazz.foo(), bar],
3434
var _ref8 = [clazz.foo, bar],
3535
a = _ref8[0],
3636
b = _ref8[1];
37-
var a,
37+
var a = void 0,
3838
b = 2;
3939
a = 1;
4040
b = 2;

packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/init-hole/exec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ expect(b).toEqual(1);
1919

2020
const arr = [c = 42] = [,];
2121
expect(c).toEqual(42);
22-
expect(arr).toEqual([,]);
22+
expect(arr).toStrictEqual([,]);
2323

2424
var iterCount = 0;
2525

@@ -35,7 +35,7 @@ expect(iterCount).toEqual(1);
3535
const [...d] = [,];
3636
const [...{ 0: e }] = [,];
3737

38-
expect(d).toEqual([,]);
38+
expect(d).toStrictEqual([undefined,]);
3939
expect(e).toEqual(undefined);
4040

4141
const [f] = [,];

packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/init-hole/input.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ expect(b).toEqual(1);
1919

2020
const arr = [c = 42] = [,];
2121
expect(c).toEqual(42);
22-
expect(arr).toEqual([,]);
22+
expect(arr).toStrictEqual([,]);
2323

2424
var iterCount = 0;
2525

@@ -35,7 +35,7 @@ expect(iterCount).toEqual(1);
3535
const [...d] = [,];
3636
const [...{ 0: e }] = [,];
3737

38-
expect(d).toEqual([,]);
38+
expect(d).toStrictEqual([,]);
3939
expect(e).toEqual(undefined);
4040

4141
const [f] = [,];

packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/init-hole/output.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ expect(a).toEqual(2);
2121
expect(b).toEqual(1);
2222
const arr = (_ref2 = [,], _ref2$ = _ref2[0], c = _ref2$ === void 0 ? 42 : _ref2$, _ref2);
2323
expect(c).toEqual(42);
24-
expect(arr).toEqual([,]);
24+
expect(arr).toStrictEqual([,]);
2525
var iterCount = 0;
2626

2727
for (const x = 23; iterCount < 1;) {
@@ -31,13 +31,13 @@ for (const x = 23; iterCount < 1;) {
3131
}
3232

3333
expect(iterCount).toEqual(1);
34-
const d = [,];
35-
const e = [,][0];
36-
expect(d).toEqual([,]);
34+
const d = [void 0];
35+
const e = [void 0][0];
36+
expect(d).toStrictEqual([,]);
3737
expect(e).toEqual(undefined);
3838
const f = void 0;
3939
expect(f).toEqual(undefined);
40-
let g;
40+
let g = void 0;
4141
expect(g).toEqual(undefined);
4242
let thrown;
4343

@@ -52,7 +52,8 @@ expect(thrown).toEqual(true);
5252

5353
try {
5454
thrown = false;
55-
babelHelpers.objectDestructuringEmpty();
55+
56+
var _ = babelHelpers.toArray(void 0);
5657
} catch (e) {
5758
thrown = true;
5859
}

0 commit comments

Comments
 (0)