diff --git a/src/com/google/javascript/jscomp/AstValidator.java b/src/com/google/javascript/jscomp/AstValidator.java index feb81652a7c..f8da8eab317 100644 --- a/src/com/google/javascript/jscomp/AstValidator.java +++ b/src/com/google/javascript/jscomp/AstValidator.java @@ -240,6 +240,8 @@ public void validateExpression(Node n) { // Assignments case ASSIGN: + validateAssignmentExpression(n); + return; case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: @@ -252,7 +254,7 @@ public void validateExpression(Node n) { case ASSIGN_DIV: case ASSIGN_MOD: case ASSIGN_EXPONENT: - validateAssignmentExpression(n); + validateCompoundAssignmentExpression(n); return; case HOOK: @@ -770,19 +772,11 @@ private void validateParameters(Node n) { } } - private void validateDefaultValue(Token type, Node n) { + private void validateDefaultValue(Token contextType, Node n) { validateFeature(Feature.DEFAULT_PARAMETERS, n); - validateAssignmentExpression(n); - Node lhs = n.getFirstChild(); - - // LHS can only be a name or destructuring pattern. - if (lhs.isName()) { - validateName(lhs); - } else if (lhs.isArrayPattern()) { - validateArrayPattern(type, lhs); - } else { - validateObjectPattern(type, lhs); - } + validateChildCount(n); + validateLHS(contextType, n.getFirstChild()); + validateExpression(n.getLastChild()); } private void validateCall(Node n) { @@ -1171,6 +1165,24 @@ private void validateAssignmentExpression(Node n) { validateExpression(n.getLastChild()); } + private void validateCompoundAssignmentExpression(Node n) { + validateChildCount(n); + Token contextType = n.getToken(); + Node lhs = n.getFirstChild(); + switch (lhs.getToken()) { + case NAME: + validateName(lhs); + break; + case GETPROP: + case GETELEM: + validateGetPropGetElemInLHS(contextType, lhs); + break; + default: + violation("Invalid child for " + contextType + " node", lhs); + } + validateExpression(n.getLastChild()); + } + private void validateGetProp(Node n) { validateNodeType(Token.GETPROP, n); validateChildCount(n); diff --git a/test/com/google/javascript/jscomp/AstValidatorTest.java b/test/com/google/javascript/jscomp/AstValidatorTest.java index b771b55eb18..c4b545ccb29 100644 --- a/test/com/google/javascript/jscomp/AstValidatorTest.java +++ b/test/com/google/javascript/jscomp/AstValidatorTest.java @@ -164,12 +164,76 @@ public void testAwaitExpressionNoFunction() { expectInvalid(n, Check.EXPRESSION); } - public void testValidDestructuringAssignment() { + public void testInvalidArrayPattern0() { setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015); + + setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015); + + // [...x = 1] = []; + Node n = IR.assign( + new Node(Token.ARRAY_PATTERN, + new Node(Token.REST, + new Node(Token.DEFAULT_VALUE, + IR.name("x"), IR.arraylit()))), + IR.arraylit()); + expectInvalid(n, Check.EXPRESSION); + } + + public void testValidDestructuringAssignment0() { + setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015); + valid("var [x] = obj;"); + valid("var [x = 1] = obj;"); + valid("var [...y] = obj;"); valid("var [x, ...y] = obj;"); + + valid("[x] = [];"); + valid("[x = 1] = [];"); + valid("[x.y] = [];"); + valid("[x.y = 1] = [];"); + valid("[x['y']] = [];"); + valid("[x['y'] = 1] = [];"); + valid("[x().y] = [];"); + valid("[x().y = 1] = [];"); + valid("[x()['y']] = [];"); + valid("[x()['y'] = 1] = [];"); + + valid("([...y] = obj);"); + valid("([x, ...y] = obj);"); valid("([...this.x] = obj);"); + valid("([...this['x']] = obj);"); + valid("([...x.y] = obj);"); + valid("([...x['y']] = obj);"); + valid("([...x().y] = obj);"); + valid("([...x()['y']] = obj);"); + } + + public void testValidDestructuringAssignment1() { + setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015); valid("var {a:b} = obj;"); - valid("({a:this.b} = obj);"); + valid("({a:b} = obj);"); + valid("({a:b.c} = obj);"); + valid("({a:b().c} = obj);"); + valid("({a:b['c']} = obj);"); + valid("({a:b()['c']} = obj);"); + valid("({a:b.c = 1} = obj);"); + valid("({a:b().c = 1} = obj);"); + valid("({a:b['c'] = 1} = obj);"); + valid("({a:b()['c'] = 1} = obj);"); + } + + public void testValidDestructuringAssignment2() { + setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015); + valid("var {['a']:b} = obj;"); + valid("({['a']:b} = obj);"); + valid("({['a']:this.b} = obj);"); + valid("({['a']:b.c} = obj);"); + valid("({['a']:b.c = 1} = obj);"); + valid("({['a']:b().c} = obj);"); + valid("({['a']:b().c = 1} = obj);"); + valid("({['a']:b['c']} = obj);"); + valid("({['a']:b['c'] = 1} = obj);"); + valid("({['a']:b()['c']} = obj);"); + valid("({['a']:b()['c'] = 1} = obj);"); } public void testInvalidDestructuringAssignment() {