diff --git a/src/com/google/javascript/jscomp/AstValidator.java b/src/com/google/javascript/jscomp/AstValidator.java index 8b9bcfb01fe..3155dc817b7 100644 --- a/src/com/google/javascript/jscomp/AstValidator.java +++ b/src/com/google/javascript/jscomp/AstValidator.java @@ -1129,7 +1129,7 @@ private void validateGetPropGetElemInLHS(Token contextType, Node n) { } private void validateArrayPattern(Token type, Node n) { - validateFeature(Feature.DESTRUCTURING, n); + validateFeature(Feature.ARRAY_DESTRUCTURING, n); validateNodeType(Token.ARRAY_PATTERN, n); for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { switch (c.getToken()) { @@ -1149,7 +1149,7 @@ private void validateArrayPattern(Token type, Node n) { } private void validateObjectPattern(Token type, Node n) { - validateFeature(Feature.DESTRUCTURING, n); + validateFeature(Feature.OBJECT_DESTRUCTURING, n); validateNodeType(Token.OBJECT_PATTERN, n); for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { switch (c.getToken()) { diff --git a/src/com/google/javascript/jscomp/Es6RewriteDestructuring.java b/src/com/google/javascript/jscomp/Es6RewriteDestructuring.java index 04289134abe..81af4d6f914 100644 --- a/src/com/google/javascript/jscomp/Es6RewriteDestructuring.java +++ b/src/com/google/javascript/jscomp/Es6RewriteDestructuring.java @@ -83,7 +83,10 @@ private Es6RewriteDestructuring(Builder builder) { case REWRITE_ALL_OBJECT_PATTERNS: this.featuresToTriggerRunningPass = FeatureSet.BARE_MINIMUM.with( - Feature.DEFAULT_PARAMETERS, Feature.DESTRUCTURING, Feature.ARRAY_PATTERN_REST); + Feature.DEFAULT_PARAMETERS, + Feature.ARRAY_DESTRUCTURING, + Feature.ARRAY_PATTERN_REST, + Feature.OBJECT_DESTRUCTURING); // If OBJECT_PATTERN_REST were to be present in featuresToTriggerRunningPass and not the // input language featureSet (such as ES6=>ES5) the pass would be skipped. diff --git a/src/com/google/javascript/jscomp/Es6SplitVariableDeclarations.java b/src/com/google/javascript/jscomp/Es6SplitVariableDeclarations.java index 22bce347bb9..ec7f1bdce1d 100644 --- a/src/com/google/javascript/jscomp/Es6SplitVariableDeclarations.java +++ b/src/com/google/javascript/jscomp/Es6SplitVariableDeclarations.java @@ -42,7 +42,7 @@ public final class Es6SplitVariableDeclarations extends NodeTraversal.AbstractPostOrderCallback implements HotSwapCompilerPass { private final AbstractCompiler compiler; private static final FeatureSet transpiledFeatures = - FeatureSet.BARE_MINIMUM.with(Feature.DESTRUCTURING); + FeatureSet.BARE_MINIMUM.with(Feature.ARRAY_DESTRUCTURING, Feature.OBJECT_DESTRUCTURING); public Es6SplitVariableDeclarations(AbstractCompiler compiler) { this.compiler = compiler; diff --git a/src/com/google/javascript/jscomp/parsing/IRFactory.java b/src/com/google/javascript/jscomp/parsing/IRFactory.java index 26f4559de35..348e1d25659 100644 --- a/src/com/google/javascript/jscomp/parsing/IRFactory.java +++ b/src/com/google/javascript/jscomp/parsing/IRFactory.java @@ -1026,7 +1026,7 @@ Node processArrayLiteral(ArrayLiteralExpressionTree tree) { } Node processArrayPattern(ArrayPatternTree tree) { - maybeWarnForFeature(tree, Feature.DESTRUCTURING); + maybeWarnForFeature(tree, Feature.ARRAY_DESTRUCTURING); Node node = newNode(Token.ARRAY_PATTERN); for (ParseTree child : tree.elements) { @@ -1043,7 +1043,7 @@ Node processArrayPattern(ArrayPatternTree tree) { } Node processObjectPattern(ObjectPatternTree tree) { - maybeWarnForFeature(tree, Feature.DESTRUCTURING); + maybeWarnForFeature(tree, Feature.OBJECT_DESTRUCTURING); Node node = newNode(Token.OBJECT_PATTERN); for (ParseTree child : tree.fields) { @@ -1527,8 +1527,10 @@ Node processRestParameter(RestParameterTree tree) { maybeWarnForFeature(tree, Feature.REST_PARAMETERS); Node assignmentTarget = transformNodeWithInlineJsDoc(tree.assignmentTarget); - if (assignmentTarget.isDestructuringPattern()) { - maybeWarnForFeature(tree.assignmentTarget, Feature.DESTRUCTURING); + if (assignmentTarget.isObjectPattern()) { + maybeWarnForFeature(tree.assignmentTarget, Feature.OBJECT_DESTRUCTURING); + } else if (assignmentTarget.isArrayPattern()) { + maybeWarnForFeature(tree.assignmentTarget, Feature.ARRAY_DESTRUCTURING); } return newNode(Token.REST, assignmentTarget); } diff --git a/src/com/google/javascript/jscomp/parsing/parser/FeatureSet.java b/src/com/google/javascript/jscomp/parsing/parser/FeatureSet.java index fadb2783c54..602f7c87be9 100644 --- a/src/com/google/javascript/jscomp/parsing/parser/FeatureSet.java +++ b/src/com/google/javascript/jscomp/parsing/parser/FeatureSet.java @@ -81,7 +81,8 @@ public final class FeatureSet implements Serializable { .without(Feature.CLASS_EXTENDS) .without(Feature.CLASS_GETTER_SETTER) .without(Feature.DEFAULT_PARAMETERS) - .without(Feature.DESTRUCTURING) + .without(Feature.ARRAY_DESTRUCTURING) + .without(Feature.OBJECT_DESTRUCTURING) .without(Feature.MODULES) .without(Feature.NEW_TARGET); @@ -127,7 +128,8 @@ public enum Feature { COMPUTED_PROPERTIES("computed property", LangVersion.ES6), CONST_DECLARATIONS("const declaration", LangVersion.ES6), DEFAULT_PARAMETERS("default parameter", LangVersion.ES6), - DESTRUCTURING("destructuring", LangVersion.ES6), + ARRAY_DESTRUCTURING("array destructuring", LangVersion.ES6), + OBJECT_DESTRUCTURING("object destructuring", LangVersion.ES6), EXTENDED_OBJECT_LITERALS("extended object literal", LangVersion.ES6), FOR_OF("for-of loop", LangVersion.ES6), GENERATORS("generator", LangVersion.ES6), diff --git a/test/com/google/javascript/jscomp/AstValidatorTest.java b/test/com/google/javascript/jscomp/AstValidatorTest.java index 4c50723e4a8..47a8035708f 100644 --- a/test/com/google/javascript/jscomp/AstValidatorTest.java +++ b/test/com/google/javascript/jscomp/AstValidatorTest.java @@ -492,13 +492,19 @@ public void testFeatureValidation_defaultParameters() { } @Test - public void testFeatureValidation_destructuring() { - testFeatureValidation("var x, {a, b} = obj;", Feature.DESTRUCTURING); - testFeatureValidation("var x, [a, b] = arr;", Feature.DESTRUCTURING); - testFeatureValidation("(x = 0, {a, b} = obj);", Feature.DESTRUCTURING); - testFeatureValidation("x = 0, [a, b] = obj;", Feature.DESTRUCTURING); - testFeatureValidation("for ({a, b} of c) {}", Feature.DESTRUCTURING); - testFeatureValidation("for ([a, b] of c) {}", Feature.DESTRUCTURING); + public void testFeatureValidation_arrayDestructuring() { + testFeatureValidation("var x, [a, b] = arr;", Feature.ARRAY_DESTRUCTURING); + testFeatureValidation("x = 0, [a, b] = obj;", Feature.ARRAY_DESTRUCTURING); + testFeatureValidation("for ([a, b] of c) {}", Feature.ARRAY_DESTRUCTURING); + testFeatureValidation("function f([a, b]) {}", Feature.ARRAY_DESTRUCTURING); + } + + @Test + public void testFeatureValidation_objectDestructuring() { + testFeatureValidation("var x, {a, b} = obj;", Feature.OBJECT_DESTRUCTURING); + testFeatureValidation("(x = 0, {a, b} = obj);", Feature.OBJECT_DESTRUCTURING); + testFeatureValidation("for ({a, b} of c) {}", Feature.OBJECT_DESTRUCTURING); + testFeatureValidation("function f({a, b}) {}", Feature.OBJECT_DESTRUCTURING); } @Test diff --git a/test/com/google/javascript/jscomp/parsing/ParserTest.java b/test/com/google/javascript/jscomp/parsing/ParserTest.java index 0d481f346bb..137b77289ba 100644 --- a/test/com/google/javascript/jscomp/parsing/ParserTest.java +++ b/test/com/google/javascript/jscomp/parsing/ParserTest.java @@ -1991,9 +1991,8 @@ public void testAnonymousFunctionExpression() { public void testArrayDestructuringVar() { mode = LanguageMode.ECMASCRIPT5; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); - parseWarning("var [x,y] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING)); + expectFeatures(Feature.ARRAY_DESTRUCTURING); + parseWarning("var [x,y] = foo();", getRequiresEs6Message(Feature.ARRAY_DESTRUCTURING)); mode = LanguageMode.ECMASCRIPT6; parse("var [x,y] = foo();"); @@ -2010,9 +2009,8 @@ public void testArrayDestructuringVarInvalid() { public void testArrayDestructuringAssign() { mode = LanguageMode.ECMASCRIPT5; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); - parseWarning("[x,y] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING)); + expectFeatures(Feature.ARRAY_DESTRUCTURING); + parseWarning("[x,y] = foo();", getRequiresEs6Message(Feature.ARRAY_DESTRUCTURING)); mode = LanguageMode.ECMASCRIPT6; parse("[x,y] = foo();"); @@ -2024,7 +2022,7 @@ public void testArrayDestructuringAssign() { public void testArrayDestructuringInitializer() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.ARRAY_DESTRUCTURING); parse("var [x=1,y] = foo();"); parse("[x=1,y] = foo();"); parse("var [x,y=2] = foo();"); @@ -2048,7 +2046,7 @@ public void testArrayDestructuringDeclarationRest() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING, Feature.ARRAY_PATTERN_REST); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.ARRAY_PATTERN_REST); parse("var [first, ...rest] = foo();"); parse("let [first, ...rest] = foo();"); parse("const [first, ...rest] = foo();"); @@ -2066,7 +2064,7 @@ public void testArrayDestructuringDeclarationRest() { mode = LanguageMode.ECMASCRIPT5; parseWarning( "var [first, ...rest] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING), + getRequiresEs6Message(Feature.ARRAY_DESTRUCTURING), getRequiresEs6Message(Feature.ARRAY_PATTERN_REST)); } @@ -2075,7 +2073,7 @@ public void testObjectDestructuringDeclarationRest() { mode = LanguageMode.ES_NEXT; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING, Feature.OBJECT_PATTERN_REST); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.OBJECT_PATTERN_REST); parse("var {first, ...rest} = foo();"); parse("let {first, ...rest} = foo();"); parse("const {first, ...rest} = foo();"); @@ -2130,7 +2128,7 @@ public void testObjectLiteralDeclarationSpread() { public void testArrayDestructuringAssignRest() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING, Feature.ARRAY_PATTERN_REST); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.ARRAY_PATTERN_REST); parse("[first, ...rest] = foo();"); // nested destructuring in regular parameters and rest parameters parse("[first, {a, b}, ...[re, st, ...{length}]] = foo();"); @@ -2138,8 +2136,9 @@ public void testArrayDestructuringAssignRest() { parse("[x, ...y[15]] = foo();"); mode = LanguageMode.ECMASCRIPT5; - parseWarning("var [first, ...rest] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING), + parseWarning( + "var [first, ...rest] = foo();", + getRequiresEs6Message(Feature.ARRAY_DESTRUCTURING), getRequiresEs6Message(Feature.ARRAY_PATTERN_REST)); } @@ -2147,7 +2146,7 @@ public void testArrayDestructuringAssignRest() { public void testObjectDestructuringAssignRest() { mode = LanguageMode.ES_NEXT; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING, Feature.OBJECT_PATTERN_REST); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.OBJECT_PATTERN_REST); parse("const {first, ...rest} = foo();"); mode = LanguageMode.ECMASCRIPT6; @@ -2171,7 +2170,7 @@ public void testArrayDestructuringAssignRestInvalid() { public void testArrayDestructuringFnDeclaration() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.ARRAY_DESTRUCTURING); parse("function f([x, y]) { use(x); use(y); }"); parse("function f([x, [y, z]]) {}"); parse("function f([x, {y, foo: z}]) {}"); @@ -2197,7 +2196,7 @@ public void testArrayDestructuringFnDeclarationInvalid() { public void testObjectDestructuringVar() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("var {x, y} = foo();"); parse("var {x: x, y: y} = foo();"); parse("var {x: {y, z}} = foo();"); @@ -2219,7 +2218,7 @@ public void testObjectDestructuringVarInvalid() { public void testObjectDestructuringVarWithInitializer() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING, Feature.DEFAULT_PARAMETERS); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.DEFAULT_PARAMETERS); parse("var {x = 1} = foo();"); parse("var {x: {y = 1}} = foo();"); parse("var {x: y = 1} = foo();"); @@ -2232,7 +2231,7 @@ public void testObjectDestructuringAssign() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; parseError("({x, y}) = foo();", "invalid assignment target"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("({x, y} = foo());"); parse("({x: x, y: y} = foo());"); parse("({x: {y, z}} = foo());"); @@ -2247,7 +2246,7 @@ public void testObjectDestructuringAssignWithInitializer() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; parseError("({x = 1}) = foo();", "invalid assignment target"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("({x = 1} = foo());"); parse("({x: {y = 1}} = foo());"); parse("({x: y = 1} = foo());"); @@ -2267,7 +2266,7 @@ public void testObjectDestructuringWithInitializerInvalid() { public void testObjectDestructuringFnDeclaration() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("function f({x, y}) { use(x); use(y); }"); parse("function f({w, x: {y, z}}) {}"); parse("function f({x, y} = {x:1, y:2}) {}"); @@ -2297,7 +2296,7 @@ public void testObjectDestructuringComputedProp() { parseError("var {[x]} = z;", "':' expected"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("var {[x]: y} = z;"); parse("var { [foo()] : [x,y,z] = bar() } = baz();"); } @@ -2312,7 +2311,7 @@ public void testObjectDestructuringStringAndNumberKeys() { parseError("var { 'hello' = 'world' } = foo();", "':' expected"); parseError("var { 2 = 5 } = foo();", "':' expected"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("var {'s': x} = foo();"); parse("var {3: x} = foo();"); } @@ -2334,7 +2333,7 @@ public void testObjectNumberKeysSpecial() { public void testObjectDestructuringKeywordKeys() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("var {if: x, else: y} = foo();"); parse("var {while: x=1, for: y} = foo();"); parse("var {type} = foo();"); @@ -2361,7 +2360,7 @@ public void testObjectDestructuringComplexTarget() { "var {foo: bar[x]} = baz();", "Only an identifier or destructuring pattern is allowed here."); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("({foo: bar.x} = baz());"); parse("for ({foo: bar.x} in baz());"); @@ -2373,11 +2372,12 @@ public void testObjectDestructuringComplexTarget() { public void testObjectDestructuringExtraParens() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("({x: y} = z);"); parse("({x: (y)} = z);"); parse("({x: ((y))} = z);"); + expectFeatures(Feature.ARRAY_DESTRUCTURING); parse("([x] = y);"); parse("[(x), y] = z;"); parse("[x, (y)] = z;"); @@ -2400,7 +2400,7 @@ public void testObjectLiteralCannotUseDestructuring() { public void testMixedDestructuring() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.OBJECT_DESTRUCTURING); parse("var {x: [y, z]} = foo();"); parse("var [x, {y, z}] = foo();"); @@ -2415,7 +2415,7 @@ public void testMixedDestructuring() { public void testMixedDestructuringWithInitializer() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.OBJECT_DESTRUCTURING); parse("var {x: [y, z] = [1, 2]} = foo();"); parse("var [x, {y, z} = {y: 3, z: 4}] = foo();"); @@ -4001,7 +4001,7 @@ public void testDestructuredRestParameters() { parseError( "function f(...[a[0]]) {}", "Only an identifier or destructuring pattern is allowed here."); - expectFeatures(Feature.REST_PARAMETERS, Feature.DESTRUCTURING); + expectFeatures(Feature.REST_PARAMETERS, Feature.ARRAY_DESTRUCTURING); parse("(...[x]) => xs"); parse("(...[x, y]) => xs"); parse("(a, b, c, ...[x, y, z]) => x"); @@ -4471,28 +4471,28 @@ public void testForInDestructuring() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("for ({a} in b) c;"); parse("for (var {a} in b) c;"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.LET_DECLARATIONS); parse("for (let {a} in b) c;"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for (const {a} in b) c;"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.OBJECT_DESTRUCTURING); parse("for ({a: b} in c) d;"); parse("for (var {a: b} in c) d;"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.LET_DECLARATIONS); parse("for (let {a: b} in c) d;"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); + expectFeatures(Feature.OBJECT_DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for (const {a: b} in c) d;"); - expectFeatures(Feature.DESTRUCTURING); + expectFeatures(Feature.ARRAY_DESTRUCTURING); parse("for ([a] in b) c;"); parse("for (var [a] in b) c;"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.LET_DECLARATIONS); parse("for (let [a] in b) c;"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); + expectFeatures(Feature.ARRAY_DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for (const [a] in b) c;"); } @@ -4654,30 +4654,38 @@ public void testInvalidDestructuring() { @Test public void testForOfPatterns() { - expectFeatures(Feature.FOR_OF, Feature.DESTRUCTURING); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; + expectFeatures(Feature.FOR_OF, Feature.OBJECT_DESTRUCTURING); parse("for({x} of b) c;"); parse("for({x: y} of b) c;"); + + expectFeatures(Feature.FOR_OF, Feature.ARRAY_DESTRUCTURING); parse("for([x, y] of b) c;"); parse("for([x, ...y] of b) c;"); - expectFeatures(Feature.FOR_OF, Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); + expectFeatures(Feature.FOR_OF, Feature.OBJECT_DESTRUCTURING, Feature.LET_DECLARATIONS); parse("for(let {x} of b) c;"); parse("for(let {x: y} of b) c;"); + + expectFeatures(Feature.FOR_OF, Feature.ARRAY_DESTRUCTURING, Feature.LET_DECLARATIONS); parse("for(let [x, y] of b) c;"); parse("for(let [x, ...y] of b) c;"); - expectFeatures(Feature.FOR_OF, Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); + expectFeatures(Feature.FOR_OF, Feature.OBJECT_DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for(const {x} of b) c;"); parse("for(const {x: y} of b) c;"); + + expectFeatures(Feature.FOR_OF, Feature.ARRAY_DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for(const [x, y] of b) c;"); parse("for(const [x, ...y] of b) c;"); - expectFeatures(Feature.FOR_OF, Feature.DESTRUCTURING); + expectFeatures(Feature.FOR_OF, Feature.OBJECT_DESTRUCTURING); parse("for(var {x} of b) c;"); parse("for(var {x: y} of b) c;"); + + expectFeatures(Feature.FOR_OF, Feature.ARRAY_DESTRUCTURING); parse("for(var [x, y] of b) c;"); parse("for(var [x, ...y] of b) c;"); }