diff --git a/src/com/google/javascript/jscomp/parsing/IRFactory.java b/src/com/google/javascript/jscomp/parsing/IRFactory.java index ef466bc20fa..9024648438a 100644 --- a/src/com/google/javascript/jscomp/parsing/IRFactory.java +++ b/src/com/google/javascript/jscomp/parsing/IRFactory.java @@ -1021,6 +1021,7 @@ Node processObjectPattern(ObjectPatternTree tree) { } Node processAssignmentRestElement(AssignmentRestElementTree tree) { + maybeWarnForFeature(tree, Feature.ARRAY_PATTERN_REST); return newNode(Token.REST, transformNodeWithInlineJsDoc(tree.assignmentTarget)); } diff --git a/src/com/google/javascript/jscomp/parsing/parser/Parser.java b/src/com/google/javascript/jscomp/parsing/parser/Parser.java index c0aff2462a1..5905dc5a3d4 100644 --- a/src/com/google/javascript/jscomp/parsing/parser/Parser.java +++ b/src/com/google/javascript/jscomp/parsing/parser/Parser.java @@ -948,7 +948,6 @@ private ParseTree parseAsyncMethod() { } private ParseTree parseAsyncMethod(PartialClassElement partial) { - features = features.with(Feature.ASYNC_FUNCTIONS); eatPredefinedString(ASYNC); if (peekIdOrKeyword()) { IdentifierToken name = eatIdOrKeywordAsId(); @@ -1214,7 +1213,6 @@ private ParseTree parseFunctionExpression() { private ParseTree parseAsyncFunctionDeclaration() { SourcePosition start = getTreeStartLocation(); - features = features.with(Feature.ASYNC_FUNCTIONS); eatAsyncFunctionStart(); if (peek(TokenType.STAR)) { @@ -1234,7 +1232,6 @@ private ParseTree parseAsyncFunctionDeclaration() { private ParseTree parseAsyncFunctionExpression() { SourcePosition start = getTreeStartLocation(); - features = features.with(Feature.ASYNC_FUNCTIONS); eatAsyncFunctionStart(); if (peek(TokenType.STAR)) { @@ -1314,7 +1311,6 @@ private ParseTree parseParameter(ParamContext context) { if (context == ParamContext.IMPLEMENTATION && !parameter.isRestParameter() && peek(TokenType.EQUAL)) { - features = features.with(Feature.DEFAULT_PARAMETERS); eat(TokenType.EQUAL); ParseTree defaultValue = parseAssignmentExpression(); parameter = new DefaultParameterTree(getTreeLocation(start), parameter, defaultValue); @@ -1329,7 +1325,6 @@ && peek(TokenType.EQUAL)) { } private ParseTree parseRestParameter() { - features = features.with(Feature.REST_PARAMETERS); SourcePosition start = getTreeStartLocation(); eat(TokenType.SPREAD); return new RestParameterTree( @@ -1709,17 +1704,11 @@ private VariableDeclarationListTree parseVariableDeclarationList( TokenType token = peekType(); switch (token) { - case CONST: - features = features.with(Feature.CONST_DECLARATIONS); - eat(token); - break; - case LET: - features = features.with(Feature.LET_DECLARATIONS); - eat(token); - break; - case VAR: - eat(token); - break; + case CONST: + case LET: + case VAR: + eat(token); + break; default: reportError(peekToken(), "expected declaration"); return null; @@ -1926,10 +1915,8 @@ private void checkVanillaForInitializers(VariableDeclarationListTree variables) /** Reports if declaration requires an initializer, assuming initializer is absent. */ private void maybeReportNoInitializer(TokenType token, ParseTree lvalue) { if (token == TokenType.CONST) { - features = features.with(Feature.CONST_DECLARATIONS); reportError("const variables must have an initializer"); } else if (lvalue.isPattern()) { - features = features.with(Feature.DESTRUCTURING); reportError("destructuring must have an initializer"); } } @@ -2828,9 +2815,6 @@ private ParseTree parseAssignment(Expression expressionIn) { reportError("invalid assignment target"); } Token operator = nextToken(); - if (TokenType.STAR_STAR_EQUAL.equals(operator.type)) { - features = features.with(Feature.EXPONENT_OP); - } ParseTree right = parseAssignment(expressionIn); return new BinaryOperatorTree(getTreeLocation(start), left, operator, right); } @@ -2877,7 +2861,6 @@ private ParseTree completeAssignmentExpressionParseAtArrow( private ParseTree completeArrowFunctionParseAtArrow( ParseTree leftOfArrow, Expression expressionIn) { - features = features.with(Feature.ARROW_FUNCTIONS); FormalParameterListTree arrowFormalParameters = transformToArrowFormalParameters(leftOfArrow); if (peekImplicitSemiColon()) { reportError("No newline allowed before '=>'"); @@ -2939,7 +2922,6 @@ private ParseTree completeAssignmentExpressionParseAtArrow(CallExpressionTree ca private ParseTree parseAsyncArrowFunction(Expression expressionIn) { SourcePosition start = getTreeStartLocation(); - features = features.with(Feature.ARROW_FUNCTIONS, Feature.ASYNC_FUNCTIONS); eatPredefinedString(ASYNC); if (peekImplicitSemiColon()) { reportError("No newline allowed between `async` and arrow function parameter list"); @@ -3275,7 +3257,6 @@ private ParseTree parseExponentiationExpression() { "Unary operator '%s' requires parentheses before '**'", left.asUnaryExpression().operator); } - features = features.with(Feature.EXPONENT_OP); Token operator = nextToken(); ParseTree right = parseExponentiationExpression(); return new BinaryOperatorTree(getTreeLocation(start), left, operator, right); @@ -3471,7 +3452,6 @@ private ParseTree parseNewExpression() { private ParseTree parseNewDotSomething() { // currently only "target" is valid after "new." - features = features.with(Feature.NEW_TARGET); SourcePosition start = getTreeStartLocation(); eat(TokenType.NEW); eat(TokenType.PERIOD); @@ -3540,7 +3520,6 @@ private boolean peekPatternStart() { } private ParseTree parsePattern(PatternKind kind) { - features = features.with(Feature.DESTRUCTURING); switch (peekType()) { case OPEN_SQUARE: return parseArrayPattern(kind); @@ -3566,7 +3545,6 @@ private ParseTree parseArrayPatternElement(PatternKind patternKind) { } private ParseTree parseArrayPatternRest(PatternKind patternKind) { - features = features.with(Feature.ARRAY_PATTERN_REST); SourcePosition start = getTreeStartLocation(); eat(TokenType.SPREAD); ParseTree patternAssignmentTarget = parseRestAssignmentTarget(patternKind); @@ -3583,7 +3561,6 @@ private ParseTree parseRestAssignmentTarget(PatternKind patternKind) { // Pattern ::= ... | "[" Element? ("," Element?)* "]" private ParseTree parseArrayPattern(PatternKind kind) { - features = features.with(Feature.DESTRUCTURING); SourcePosition start = getTreeStartLocation(); ImmutableList.Builder elements = ImmutableList.builder(); eat(TokenType.OPEN_SQUARE); @@ -3613,7 +3590,6 @@ private ParseTree parseArrayPattern(PatternKind kind) { // Pattern ::= "{" (Field ("," Field)* ","?)? "}" | ... private ParseTree parseObjectPattern(PatternKind kind) { - features = features.with(Feature.DESTRUCTURING); SourcePosition start = getTreeStartLocation(); ImmutableList.Builder fields = ImmutableList.builder(); eat(TokenType.OPEN_CURLY); diff --git a/test/com/google/javascript/jscomp/parsing/ParserTest.java b/test/com/google/javascript/jscomp/parsing/ParserTest.java index 9ec1792d717..b81b2ae5349 100644 --- a/test/com/google/javascript/jscomp/parsing/ParserTest.java +++ b/test/com/google/javascript/jscomp/parsing/ParserTest.java @@ -88,20 +88,21 @@ protected void setUp() throws Exception { public void testExponentOperator() { mode = LanguageMode.ECMASCRIPT7; strictMode = STRICT; + + parseError("-x**y", "Unary operator '-' requires parentheses before '**'"); + expectFeatures(Feature.EXPONENT_OP); - parse("x**y"); + parse("x**y"); // Parentheses are required for disambiguation when a unary expression is desired as // the left operand. parse("-(x**y)"); parse("(-x)**y"); - parseError("-x**y", "Unary operator '-' requires parentheses before '**'"); // Parens are not required for unary operator on the right operand parse("x**-y"); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.EXPONENT_OP); parseWarning( "x**y", requiresLanguageModeMessage(LanguageMode.ECMASCRIPT7, Feature.EXPONENT_OP)); } @@ -1370,6 +1371,9 @@ public void testArrayDestructuringVar() { mode = LanguageMode.ECMASCRIPT6; parse("var [x,y] = foo();"); + } + + public void testArrayDestructuringVarInvalid() { // arbitrary LHS assignment target not allowed parseError( "var [x,y[15]] = foo();", "Only an identifier or destructuring pattern is allowed here."); @@ -1401,6 +1405,9 @@ public void testArrayDestructuringInitializer() { parse("[[a] = ['b']] = [];"); // arbitrary LHS target allowed in assignment, but not declaration parse("[[a.x] = ['b']] = [];"); + } + + public void testArrayDestructuringInitializerInvalid() { parseError( "var [[a.x] = ['b']] = [];", "Only an identifier or destructuring pattern is allowed here."); @@ -1423,6 +1430,7 @@ public void testArrayDestructuringDeclarationRest() { expectFeatures(Feature.DESTRUCTURING, Feature.ARRAY_PATTERN_REST); parse("var [first, {a, b}, ...[re, st, ...{length}]] = foo();"); + expectFeatures(); parseError( "var [first, ...more = 'default'] = foo();", "A default value cannot be specified after '...'"); @@ -1432,7 +1440,8 @@ public void testArrayDestructuringDeclarationRest() { mode = LanguageMode.ECMASCRIPT5; parseWarning( "var [first, ...rest] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING)); + getRequiresEs6Message(Feature.DESTRUCTURING), + getRequiresEs6Message(Feature.ARRAY_PATTERN_REST)); } public void testArrayDestructuringAssignRest() { @@ -1444,6 +1453,14 @@ public void testArrayDestructuringAssignRest() { parse("[first, {a, b}, ...[re, st, ...{length}]] = foo();"); // arbitrary LHS assignment target is allowed parse("[x, ...y[15]] = foo();"); + + mode = LanguageMode.ECMASCRIPT5; + parseWarning("var [first, ...rest] = foo();", + getRequiresEs6Message(Feature.DESTRUCTURING), + getRequiresEs6Message(Feature.ARRAY_PATTERN_REST)); + } + + public void testArrayDestructuringAssignRestInvalid() { // arbitrary LHS assignment target not allowed parseError( "var [x, ...y[15]] = foo();", @@ -1452,11 +1469,6 @@ public void testArrayDestructuringAssignRest() { parseError( "[first, ...more = 'default'] = foo();", "A default value cannot be specified after '...'"); parseError("var [first, ...more, last] = foo();", "']' expected"); - - - mode = LanguageMode.ECMASCRIPT5; - parseWarning("var [first, ...rest] = foo();", - getRequiresEs6Message(Feature.DESTRUCTURING)); } public void testArrayDestructuringFnDeclaration() { @@ -1468,6 +1480,9 @@ public void testArrayDestructuringFnDeclaration() { parse("function f([x, {y, foo: z}]) {}"); parse("function f([x, y] = [1, 2]) { use(x); use(y); }"); parse("function f([x, x]) {}"); + } + + public void testArrayDestructuringFnDeclarationInvalid() { // arbitrary LHS expression not allowed as a formal parameter parseError( "function f([a[0], x]) {}", "Only an identifier or destructuring pattern is allowed here."); @@ -1491,6 +1506,9 @@ public void testObjectDestructuringVar() { // Useless, but legal. parse("var {} = foo();"); + } + + public void testObjectDestructuringVarInvalid() { // Arbitrary LHS target not allowed in declaration parseError("var {x.a, y} = foo();", "'}' expected"); parseError( @@ -1535,9 +1553,7 @@ public void testObjectDestructuringAssignWithInitializer() { } public void testObjectDestructuringWithInitializerInvalid() { - expectFeatures(Feature.DESTRUCTURING); parseError("var {{x}} = foo();", "'}' expected"); - expectFeatures(); parseError("({{x}}) = foo();", "'}' expected"); parseError("({{a} = {a: 'b'}}) = foo();", "'}' expected"); parseError("({{a : b} = {a: 'b'}}) = foo();", "'}' expected"); @@ -1551,6 +1567,9 @@ public void testObjectDestructuringFnDeclaration() { parse("function f({w, x: {y, z}}) {}"); parse("function f({x, y} = {x:1, y:2}) {}"); parse("function f({x, x}) {}"); + } + + public void testObjectDestructuringFnDeclarationInvalid() { // arbitrary LHS expression not allowed as a formal parameter parseError("function f({a[0], x}) {}", "'}' expected"); parseError( @@ -1568,23 +1587,26 @@ public void testObjectDestructuringFnDeclaration() { public void testObjectDestructuringComputedProp() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; + + parseError("var {[x]} = z;", "':' expected"); + expectFeatures(Feature.DESTRUCTURING); parse("var {[x]: y} = z;"); parse("var { [foo()] : [x,y,z] = bar() } = baz();"); - parseError("var {[x]} = z;", "':' expected"); } public void testObjectDestructuringStringAndNumberKeys() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); - parse("var {'s': x} = foo();"); - parse("var {3: x} = foo();"); parseError("var { 'hello world' } = foo();", "':' expected"); parseError("var { 4 } = foo();", "':' expected"); parseError("var { 'hello' = 'world' } = foo();", "':' expected"); parseError("var { 2 = 5 } = foo();", "':' expected"); + + expectFeatures(Feature.DESTRUCTURING); + parse("var {'s': x} = foo();"); + parse("var {3: x} = foo();"); } /** @@ -1611,7 +1633,9 @@ public void testObjectDestructuringKeywordKeys() { parse("var {declare} = foo();"); parse("var {module} = foo();"); parse("var {namespace} = foo();"); + } + public void testObjectDestructuringKeywordKeysInvalid() { parseError("var {while} = foo();", "cannot use keyword 'while' here."); parseError("var {implements} = foo();", "cannot use keyword 'implements' here."); } @@ -1619,16 +1643,18 @@ public void testObjectDestructuringKeywordKeys() { public void testObjectDestructuringComplexTarget() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); parseError( "var {foo: bar.x} = baz();", "Only an identifier or destructuring pattern is allowed here."); - parse("({foo: bar.x} = baz());"); - parse("for ({foo: bar.x} in baz());"); parseError( "var {foo: bar[x]} = baz();", "Only an identifier or destructuring pattern is allowed here."); + + expectFeatures(Feature.DESTRUCTURING); + parse("({foo: bar.x} = baz());"); + parse("for ({foo: bar.x} in baz());"); + parse("({foo: bar[x]} = baz());"); parse("for ({foo: bar[x]} in baz());"); } @@ -1644,6 +1670,9 @@ public void testObjectDestructuringExtraParens() { parse("([x] = y);"); parse("[(x), y] = z;"); parse("[x, (y)] = z;"); + } + + public void testObjectDestructuringExtraParensInvalid() { parseError("[x, ([y])] = z;", INVALID_ASSIGNMENT_TARGET); parseError("[x, (([y]))] = z;", INVALID_ASSIGNMENT_TARGET); } @@ -1686,25 +1715,14 @@ public void testDestructuringNoRHS() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); parseError("var {x: y};", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); parseError("let {x: y};", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parseError("const {x: y};", "const variables must have an initializer"); - - expectFeatures(Feature.DESTRUCTURING); parseError("var {x};", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); parseError("let {x};", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parseError("const {x};", "const variables must have an initializer"); - - expectFeatures(Feature.DESTRUCTURING); parseError("var [x, y];", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); parseError("let [x, y];", "destructuring must have an initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parseError("const [x, y];", "const variables must have an initializer"); } @@ -1716,17 +1734,13 @@ public void testComprehensions() { // array comprehensions parseError("[for (x of y) z];", error); - expectFeatures(Feature.DESTRUCTURING); // Note: the object pattern triggers this parseError("[for ({x,y} of z) x+y];", error); - expectFeatures(); parseError("[for (x of y) if (x<10) z];", error); parseError("[for (a = 5 of v) a];", "'identifier' expected"); // generator comprehensions parseError("(for (x of y) z);", error); - expectFeatures(Feature.DESTRUCTURING); // Note: the object pattern triggers this parseError("(for ({x,y} of z) x+y);", error); - expectFeatures(); parseError("(for (x of y) if (x<10) z);", error); parseError("(for (a = 5 of v) a);", "'identifier' expected"); } @@ -1743,7 +1757,7 @@ public void testLetForbidden2() { getRequiresEs6Message(Feature.LET_DECLARATIONS)); } - public void xtestLetForbidden3() { + public void testLetForbidden3() { mode = LanguageMode.ECMASCRIPT5; strictMode = STRICT; parseError("function f() { var let = 3; }", @@ -1926,11 +1940,13 @@ public void testLet() { public void testConst() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.CONST_DECLARATIONS); parseError("const x;", "const variables must have an initializer"); - parse("const x = 1;"); parseError("const x, y = 2;", "const variables must have an initializer"); + + expectFeatures(Feature.CONST_DECLARATIONS); + + parse("const x = 1;"); parse("const x = 1, y = 2;"); } @@ -2370,7 +2386,6 @@ public void testReservedKeywords() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; - expectFeatures(Feature.CONST_DECLARATIONS); parseError("const else = 1;", "'identifier' expected"); } @@ -2818,25 +2833,28 @@ public void testDefaultParameters() { public void testRestParameters() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; + + parseError("(...xs, x) => xs", "')' expected"); + parseError( + "function f(...a[0]) {}", "Only an identifier or destructuring pattern is allowed here."); + expectFeatures(Feature.REST_PARAMETERS); parse("function f(...b) {}"); parse("(...xs) => xs"); parse("(x, ...xs) => xs"); parse("(x, y, ...xs) => xs"); - parseError("(...xs, x) => xs", "')' expected"); - parseError( - "function f(...a[0]) {}", "Only an identifier or destructuring pattern is allowed here."); } public void testDestructuredRestParameters() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; + parseError( + "function f(...[a[0]]) {}", "Only an identifier or destructuring pattern is allowed here."); + expectFeatures(Feature.REST_PARAMETERS, Feature.DESTRUCTURING); parse("(...[x]) => xs"); parse("(...[x, y]) => xs"); parse("(a, b, c, ...[x, y, z]) => x"); - parseError( - "function f(...[a[0]]) {}", "Only an identifier or destructuring pattern is allowed here."); } public void testRestParameters_ES5() { @@ -2851,7 +2869,6 @@ public void testExpressionsThatLookLikeParameters1() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; parseError("();", "invalid parenthesized expression"); - expectFeatures(Feature.REST_PARAMETERS); parseError("(...xs);", "invalid parenthesized expression"); parseError("(x, ...xs);", "A rest parameter must be in a parameter list."); parseError("(a, b, c, ...xs);", "A rest parameter must be in a parameter list."); @@ -2868,7 +2885,6 @@ public void testExpressionsThatLookLikeParameters2() { } public void testExpressionsThatLookLikeParameters3() { - expectFeatures(Feature.REST_PARAMETERS); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; parseError("!(...x)", "invalid parenthesized expression"); @@ -2881,11 +2897,12 @@ public void testExpressionsThatLookLikeParameters3() { public void testDefaultParametersWithRestParameters() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; + parseError("function f(a=1, ...b=3) {}", "A default value cannot be specified after '...'"); + expectFeatures(Feature.DEFAULT_PARAMETERS, Feature.REST_PARAMETERS); parse("function f(a=0, ...b) {}"); parse("function f(a, b=0, ...c) {}"); parse("function f(a, b=0, c=1, ...d) {}"); - parseError("function f(a=1, ...b=3) {}", "A default value cannot be specified after '...'"); } public void testClass1() { @@ -3014,7 +3031,6 @@ public void testNewTarget() { } public void testNewDotSomethingInvalid() { - expectFeatures(Feature.NEW_TARGET); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; @@ -3047,7 +3063,6 @@ public void testArrowInvalid1() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; parseError("*()=>1;", "primary expression expected"); - expectFeatures(Feature.ARROW_FUNCTIONS); parseError("var f = x\n=>2", "No newline allowed before '=>'"); parseError("f = (x,y)\n=>2;", "No newline allowed before '=>'"); parseError("f( (x,y)\n=>2)", "No newline allowed before '=>'"); @@ -3100,7 +3115,6 @@ public void testAsyncNamedFunction() { public void testInvalidAsyncFunction() { mode = LanguageMode.ECMASCRIPT8; strictMode = STRICT; - expectFeatures(Feature.ASYNC_FUNCTIONS); parseError("async function *f(){}", "async functions cannot be generators"); parseError("f = async function *(){}", "async functions cannot be generators"); } @@ -3180,7 +3194,9 @@ public void testAwaitExpression() { parse("f = async(p)=>await p"); parse("class C{async m(p){await p}}"); parse("class C{static async m(p){await p}}"); - // await must have an operand + } + + public void testAwaitExpressionInvalid() { parseError("async function f() { await; }", "primary expression expected"); } @@ -3207,12 +3223,15 @@ public void testFor_ES6() { parse("for (let x = 0; x != 10; x++);"); expectFeatures(Feature.CONST_DECLARATIONS); - parseError("for (const x; x != 10; x = next()) {}", "const variables must have an initializer"); - parseError("for (const x; x != 10; x = next());", "const variables must have an initializer"); parse("for (const x = 0; x != 10; x++) {}"); parse("for (const x = 0; x != 10; x++);"); } + public void testForConstNoInitializer() { + parseError("for (const x; x != 10; x = next()) {}", "const variables must have an initializer"); + parseError("for (const x; x != 10; x = next());", "const variables must have an initializer"); + } + public void testForIn_ES6() { mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; @@ -3232,26 +3251,17 @@ public void testForIn_ES6() { "for (var a,b in c) d;", "for-in statement may not have more than one variable declaration"); - expectFeatures(Feature.LET_DECLARATIONS); parseError( "for (let a,b in c) d;", "for-in statement may not have more than one variable declaration"); - expectFeatures(Feature.CONST_DECLARATIONS); parseError( "for (const a,b in c) d;", "for-in statement may not have more than one variable declaration"); - expectFeatures(); parseError("for (a=1 in b) c;", INVALID_ASSIGNMENT_TARGET); - - expectFeatures(Feature.LET_DECLARATIONS); parseError("for (let a=1 in b) c;", "for-in statement may not have initializer"); - - expectFeatures(Feature.CONST_DECLARATIONS); parseError("for (const a=1 in b) c;", "for-in statement may not have initializer"); - - expectFeatures(); parseError("for (var a=1 in b) c;", "for-in statement may not have initializer"); parseError("for (\"a\" in b) c;", INVALID_ASSIGNMENT_TARGET); } @@ -3294,21 +3304,20 @@ public void testForInDestructuring() { parse("for (let [a] in b) c;"); expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parse("for (const [a] in b) c;"); + } + + public void testForInDestructuringInvalid() { + mode = LanguageMode.ECMASCRIPT6; + strictMode = SLOPPY; - expectFeatures(Feature.DESTRUCTURING); parseError("for ({a: b} = foo() in c) d;", INVALID_ASSIGNMENT_TARGET); parseError("for (var {a: b} = foo() in c) d;", "for-in statement may not have initializer"); - expectFeatures(Feature.DESTRUCTURING); parseError("for (let {a: b} = foo() in c) d;", "for-in statement may not have initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parseError("for (const {a: b} = foo() in c) d;", "for-in statement may not have initializer"); - expectFeatures(Feature.DESTRUCTURING); parseError("for ([a] = foo() in b) c;", INVALID_ASSIGNMENT_TARGET); parseError("for (var [a] = foo() in b) c;", "for-in statement may not have initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.LET_DECLARATIONS); parseError("for (let [a] = foo() in b) c;", "for-in statement may not have initializer"); - expectFeatures(Feature.DESTRUCTURING, Feature.CONST_DECLARATIONS); parseError("for (const [a] = foo() in b) c;", "for-in statement may not have initializer"); } @@ -3355,7 +3364,6 @@ public void testForOf4() { } public void testDestructuringInForLoops() { - expectFeatures(Feature.DESTRUCTURING); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY; @@ -3381,7 +3389,6 @@ public void testDestructuringInForLoops() { } public void testInvalidDestructuring() { - expectFeatures(Feature.DESTRUCTURING); mode = LanguageMode.ECMASCRIPT6; strictMode = SLOPPY;