Skip to content

Commit 1ea642a

Browse files
EatingWTyler Breisacher
authored and
Tyler Breisacher
committed
In ES6RewriteDestructuring visitArrayPattern, if the parent of the destructuring assignment is not an expr result, for example, a for loop or another assignment, then transformed the destructuring assignment into an arrow function whose result is the original destructuring assignment.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158769794
1 parent 481ef6f commit 1ea642a

File tree

5 files changed

+399
-17
lines changed

5 files changed

+399
-17
lines changed

src/com/google/javascript/jscomp/Es6RewriteDestructuring.java

+61-16
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
5353
@Override
5454
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
5555
switch (n.getToken()) {
56+
case FUNCTION:
57+
visitFunction(t, n);
58+
break;
5659
case PARAM_LIST:
5760
visitParamList(t, n, parent);
5861
break;
@@ -82,6 +85,19 @@ public void visit(NodeTraversal t, Node n, Node parent) {
8285
}
8386
}
8487

88+
/**
89+
* If the function is an arrow function, wrap the body in a block if it is not already a block.
90+
*/
91+
private void visitFunction(NodeTraversal t, Node function) {
92+
Node body = function.getLastChild();
93+
if (!body.isNormalBlock()) {
94+
body.detach();
95+
Node replacement = IR.block(IR.returnNode(body)).useSourceInfoIfMissingFromForTree(body);
96+
function.addChildToBack(replacement);
97+
t.reportCodeChange();
98+
}
99+
}
100+
85101
/**
86102
* Processes trailing default and rest parameters.
87103
*/
@@ -203,7 +219,8 @@ private void visitForOf(Node node) {
203219
}
204220

205221
private void visitObjectPattern(NodeTraversal t, Node objectPattern, Node parent) {
206-
Node rhs, nodeToDetach;
222+
Node rhs;
223+
Node nodeToDetach;
207224
if (NodeUtil.isNameDeclaration(parent) && !NodeUtil.isEnhancedFor(parent.getParent())) {
208225
rhs = objectPattern.getNext();
209226
nodeToDetach = parent;
@@ -244,7 +261,8 @@ private void visitObjectPattern(NodeTraversal t, Node objectPattern, Node parent
244261
for (Node child = objectPattern.getFirstChild(), next; child != null; child = next) {
245262
next = child.getNext();
246263

247-
Node newLHS, newRHS;
264+
Node newLHS;
265+
Node newRHS;
248266
if (child.isStringKey()) {
249267
if (!child.hasChildren()) { // converting shorthand
250268
Node name = IR.name(child.getString());
@@ -314,35 +332,35 @@ private void visitObjectPattern(NodeTraversal t, Node objectPattern, Node parent
314332
}
315333

316334
private void visitArrayPattern(NodeTraversal t, Node arrayPattern, Node parent) {
317-
Node rhs, nodeToDetach;
318335
if (NodeUtil.isNameDeclaration(parent) && !NodeUtil.isEnhancedFor(parent.getParent())) {
319-
rhs = arrayPattern.getNext();
320-
nodeToDetach = parent;
336+
replaceArrayPattern(t, arrayPattern, arrayPattern.getNext(), parent, parent);
321337
} else if (parent.isAssign()) {
322-
rhs = arrayPattern.getNext();
323-
nodeToDetach = parent.getParent();
324-
Preconditions.checkState(nodeToDetach.isExprResult());
338+
if (parent.getParent().isExprResult()) {
339+
replaceArrayPattern(t, arrayPattern, arrayPattern.getNext(), parent, parent.getParent());
340+
} else {
341+
wrapAssignmentInCallToArrow(t, parent);
342+
}
325343
} else if (parent.isArrayPattern()
326344
|| parent.isRest()
327345
|| parent.isDefaultValue()
328346
|| parent.isStringKey()) {
329347
// This is a nested array pattern. Don't do anything now; we'll visit it
330348
// after visiting the parent.
331-
return;
332349
} else if (NodeUtil.isEnhancedFor(parent) || NodeUtil.isEnhancedFor(parent.getParent())) {
333350
visitDestructuringPatternInEnhancedFor(arrayPattern);
334-
return;
335351
} else if (parent.isCatch()) {
336352
visitDestructuringPatternInCatch(arrayPattern);
337-
return;
338353
} else {
339354
throw new IllegalStateException("Unexpected ARRAY_PATTERN parent: " + parent);
340355
}
356+
}
341357

342-
// Convert 'var [x, y] = rhs' to:
343-
// var temp = $jscomp.makeIterator(rhs);
344-
// var x = temp.next().value;
345-
// var y = temp.next().value;
358+
/**
359+
* Convert 'var [x, y] = rhs' to: var temp = $jscomp.makeIterator(rhs); var x = temp.next().value;
360+
* var y = temp.next().value;
361+
*/
362+
private void replaceArrayPattern(
363+
NodeTraversal t, Node arrayPattern, Node rhs, Node parent, Node nodeToDetach) {
346364
String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
347365
Node tempDecl = IR.var(
348366
IR.name(tempVarName),
@@ -361,7 +379,8 @@ private void visitArrayPattern(NodeTraversal t, Node arrayPattern, Node parent)
361379
continue;
362380
}
363381

364-
Node newLHS, newRHS;
382+
Node newLHS;
383+
Node newRHS;
365384
if (child.isDefaultValue()) {
366385
// [x = defaultValue] = rhs;
367386
// becomes
@@ -423,6 +442,32 @@ private void visitArrayPattern(NodeTraversal t, Node arrayPattern, Node parent)
423442
t.reportCodeChange();
424443
}
425444

445+
/**
446+
* Convert the assignment '[x, y] = rhs' (used as an expression and not an expr result) to: (() =>
447+
* { var temp = $jscomp.makeIterator(rhs); var x = temp.next().value; var y = temp.next().value;
448+
* return temp; })
449+
*/
450+
private void wrapAssignmentInCallToArrow(NodeTraversal t, Node assignment) {
451+
String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
452+
Node rhs = assignment.getLastChild().detach();
453+
Node newAssignment = IR.let(IR.name(tempVarName), rhs);
454+
Node replacementExpr = IR.assign(assignment.getFirstChild().detach(), IR.name(tempVarName));
455+
Node exprResult = IR.exprResult(replacementExpr);
456+
Node returnNode = IR.returnNode(IR.name(tempVarName));
457+
Node block = IR.block(newAssignment, exprResult, returnNode);
458+
Node call = IR.call(IR.arrowFunction(IR.name(""), IR.paramList(), block));
459+
call.useSourceInfoIfMissingFromForTree(assignment);
460+
call.putBooleanProp(Node.FREE_CALL, true);
461+
assignment.getParent().replaceChild(assignment, call);
462+
NodeUtil.markNewScopesChanged(call, compiler);
463+
replaceArrayPattern(
464+
t,
465+
replacementExpr.getFirstChild(),
466+
replacementExpr.getLastChild(),
467+
replacementExpr,
468+
exprResult);
469+
}
470+
426471
private void visitDestructuringPatternInEnhancedFor(Node pattern) {
427472
Preconditions.checkArgument(pattern.isDestructuringPattern());
428473
String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);

src/com/google/javascript/jscomp/TranspilationPasses.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ public static void addEs2017Passes(List<PassFactory> passes) {
4444
public static void addEs6EarlyPasses(List<PassFactory> passes) {
4545
passes.add(es6SuperCheck);
4646
passes.add(es6ConvertSuper);
47-
passes.add(es6RewriteArrowFunction);
4847
passes.add(es6RenameVariablesInParamLists);
4948
passes.add(es6SplitVariableDeclarations);
5049
passes.add(es6RewriteDestructuring);
50+
passes.add(es6RewriteArrowFunction);
5151
}
5252

5353
/**

test/com/google/javascript/jscomp/Es6RewriteDestructuringTest.java

+133
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,139 @@ public void testTypeCheck_inlineAnnotations() {
638638
TYPE_MISMATCH_WARNING);
639639
}
640640

641+
public void testDestructuringNotInExprResult() {
642+
test(
643+
LINE_JOINER.join("var x, a, b;", "x = ([a,b] = [1,2])"),
644+
LINE_JOINER.join(
645+
"var x,a,b;",
646+
"x = (()=>{",
647+
" let $jscomp$destructuring$var0 = [1,2];",
648+
" var $jscomp$destructuring$var1 = $jscomp.makeIterator($jscomp$destructuring$var0);",
649+
" a = $jscomp$destructuring$var1.next().value;",
650+
" b = $jscomp$destructuring$var1.next().value;",
651+
" return $jscomp$destructuring$var0;",
652+
"})();"));
653+
654+
test(
655+
LINE_JOINER.join(
656+
"var foo = function () {", "var x, a, b;", "x = ([a,b] = [1,2]);", "}", "foo();"),
657+
LINE_JOINER.join(
658+
"var foo = function () {",
659+
" var x, a, b;",
660+
" x = (()=>{",
661+
" let $jscomp$destructuring$var0 = [1,2];",
662+
" var $jscomp$destructuring$var1 = $jscomp.makeIterator($jscomp$destructuring$var0);",
663+
" a = $jscomp$destructuring$var1.next().value;",
664+
" b = $jscomp$destructuring$var1.next().value;",
665+
" return $jscomp$destructuring$var0;",
666+
" })();",
667+
"}",
668+
"foo();"));
669+
670+
test(
671+
LINE_JOINER.join("var prefix;", "for (;;[, prefix] = /\\.?([^.]+)$/.exec(prefix)){", "}"),
672+
LINE_JOINER.join(
673+
"var prefix;",
674+
"for (;;(() => {",
675+
" let $jscomp$destructuring$var0 = /\\.?([^.]+)$/.exec(prefix)",
676+
" var $jscomp$destructuring$var1 = ",
677+
"$jscomp.makeIterator($jscomp$destructuring$var0);",
678+
" $jscomp$destructuring$var1.next();",
679+
" prefix = $jscomp$destructuring$var1.next().value;",
680+
" return $jscomp$destructuring$var0;",
681+
" })()){",
682+
"}"));
683+
684+
test(
685+
LINE_JOINER.join(
686+
"var prefix;",
687+
"for (;;[, prefix] = /\\.?([^.]+)$/.exec(prefix)){",
688+
" console.log(prefix);",
689+
"}"),
690+
LINE_JOINER.join(
691+
"var prefix;",
692+
"for (;;(() => {",
693+
" let $jscomp$destructuring$var0 = /\\.?([^.]+)$/.exec(prefix)",
694+
" var $jscomp$destructuring$var1 = ",
695+
"$jscomp.makeIterator($jscomp$destructuring$var0);",
696+
" $jscomp$destructuring$var1.next();",
697+
" prefix = $jscomp$destructuring$var1.next().value;",
698+
" return $jscomp$destructuring$var0;",
699+
" })()){",
700+
" console.log(prefix);",
701+
"}"));
702+
703+
test(
704+
LINE_JOINER.join("for (var x = 1; x < 3; [x,] = [3,4]){", " console.log(x);", "}"),
705+
LINE_JOINER.join(
706+
"for (var x = 1; x < 3; (()=>{",
707+
" let $jscomp$destructuring$var0 = [3,4]",
708+
" var $jscomp$destructuring$var1 = $jscomp.makeIterator($jscomp$destructuring$var0);",
709+
" x = $jscomp$destructuring$var1.next().value;",
710+
" return $jscomp$destructuring$var0;",
711+
" })()){",
712+
"console.log(x);",
713+
"}"));
714+
}
715+
716+
public void testNestedDestructuring() {
717+
test(
718+
"var [[x]] = [[1]];",
719+
LINE_JOINER.join(
720+
"var $jscomp$destructuring$var0 = $jscomp.makeIterator([[1]]);",
721+
"var $jscomp$destructuring$var1 = ",
722+
"$jscomp.makeIterator($jscomp$destructuring$var0.next().value);",
723+
"var x = $jscomp$destructuring$var1.next().value;"));
724+
725+
test(
726+
"var [[x,y],[z]] = [[1,2],[3]];",
727+
LINE_JOINER.join(
728+
"var $jscomp$destructuring$var0 = $jscomp.makeIterator([[1,2],[3]]);",
729+
"var $jscomp$destructuring$var1 = ",
730+
"$jscomp.makeIterator($jscomp$destructuring$var0.next().value);",
731+
"var x = $jscomp$destructuring$var1.next().value;",
732+
"var y = $jscomp$destructuring$var1.next().value;",
733+
"var $jscomp$destructuring$var2 = ",
734+
"$jscomp.makeIterator($jscomp$destructuring$var0.next().value);",
735+
"var z = $jscomp$destructuring$var2.next().value;"));
736+
737+
test(
738+
"var [[x,y],z] = [[1,2],3];",
739+
LINE_JOINER.join(
740+
"var $jscomp$destructuring$var0 = $jscomp.makeIterator([[1,2],3]);",
741+
"var $jscomp$destructuring$var1 = ",
742+
"$jscomp.makeIterator($jscomp$destructuring$var0.next().value);",
743+
"var x = $jscomp$destructuring$var1.next().value;",
744+
"var y = $jscomp$destructuring$var1.next().value;",
745+
"var z = $jscomp$destructuring$var0.next().value;"));
746+
}
747+
748+
public void testTryCatch() {
749+
test(
750+
LINE_JOINER.join("var x = 1;", "try {", " throw [];", "} catch ([x]) {}"),
751+
LINE_JOINER.join(
752+
"var x = 1;",
753+
"try {",
754+
" throw [];",
755+
"} catch ($jscomp$destructuring$var0) {",
756+
" var $jscomp$destructuring$var1 = $jscomp.makeIterator($jscomp$destructuring$var0);",
757+
" let x = $jscomp$destructuring$var1.next().value;",
758+
"}"));
759+
760+
test(
761+
LINE_JOINER.join("var x = 1;", "try {", " throw [[]];", "} catch ([[x]]) {}"),
762+
LINE_JOINER.join(
763+
"var x = 1;",
764+
"try {",
765+
" throw [[]];",
766+
"} catch ($jscomp$destructuring$var0) {",
767+
" var $jscomp$destructuring$var1 = $jscomp.makeIterator($jscomp$destructuring$var0);",
768+
" var $jscomp$destructuring$var2 = ",
769+
"$jscomp.makeIterator($jscomp$destructuring$var1.next().value);",
770+
" let x = $jscomp$destructuring$var2.next().value;",
771+
"}"));
772+
}
773+
641774
@Override
642775
protected Compiler createCompiler() {
643776
return new NoninjectingCompiler();

0 commit comments

Comments
 (0)