Repository: jshint/jshint
Pull request #3126 (2017-04-30 19:00:15)

[[FIX]] Parse `for-in/of` head LHS as asnmt target
Previously, the left-hand side of the `for-in/of` head re-used the code
path for `var` declaration lists. This was undesirable for a number of
reasons:

- it made the `var` statement's parsing logic more complex
- it tended to produce inaccurate error messages, e.g. "destructuring
  binding is available in ES6"
- it disallowed syntactically valid code, e.g. `for (a.b in {}) {}` or
  `for ([x[y]] of []) {}`

Refactor the parsing logic of `for-in/of` heads to more faithfully match
the actual language grammar. Update the expected errors in the project's
unit test suite according to the more accurate messages that this change
produces.  Simplify `var` statement parsing logic by removing the code
intended to support this condition. Maintain support for initializers
and the comma operator in order to improve error messages in the case of
common programming mistakes.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index f4e22485..794de19c 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -3649,10 +3649,6 @@ var JSHINT = (function() {
     var inexport = context && context.inexport;
     var tokens, lone, value;
 
-    // If the `implied` option is set, bindings are set differently.
-    var implied = context && context.implied;
-    var report = !(context && context.ignore);
-
     this.first = [];
     for (;;) {
       var names = [];
@@ -3664,7 +3660,7 @@ var JSHINT = (function() {
         lone = true;
       }
 
-      if (!(prefix && implied) && report && state.option.varstmt) {
+      if (state.option.varstmt) {
         warning("W132", this);
       }
 
@@ -3673,7 +3669,7 @@ var JSHINT = (function() {
       for (var t in tokens) {
         if (tokens.hasOwnProperty(t)) {
           t = tokens[t];
-          if (!implied && state.funct["(global)"] && !state.impliedClosure()) {
+          if (state.funct["(global)"] && !state.impliedClosure()) {
             if (predefined[t.id] === false) {
               warning("W079", t.token, t.id);
             } else if (state.option.futurehostile === false) {
@@ -3684,20 +3680,12 @@ var JSHINT = (function() {
             }
           }
           if (t.id) {
-            if (implied === "for") {
+            state.funct["(scope)"].addlabel(t.id, {
+              type: "var",
+              token: t.token });
 
-              if (!state.funct["(scope)"].has(t.id)) {
-                if (report) warning("W088", t.token, t.id);
-              }
-              state.funct["(scope)"].block.use(t.id, t.token);
-            } else {
-              state.funct["(scope)"].addlabel(t.id, {
-                type: "var",
-                token: t.token });
-
-              if (lone && inexport) {
-                state.funct["(scope)"].setExported(t.id, t.token);
-              }
+            if (lone && inexport) {
+              state.funct["(scope)"].setExported(t.id, t.token);
             }
             names.push(t.token);
           }
@@ -3709,7 +3697,7 @@ var JSHINT = (function() {
 
         advance("=");
         if (peek(0).id === "=" && state.tokens.next.identifier) {
-          if (!prefix && report &&
+          if (!prefix &&
               !state.funct["(params)"] ||
               state.funct["(params)"].indexOf(state.tokens.next.value) === -1) {
             warning("W120", state.tokens.next, state.tokens.next.value);
@@ -3718,7 +3706,7 @@ var JSHINT = (function() {
         var id = state.tokens.prev;
         // don't accept `in` in expression if prefix is used for ForIn/Of loop.
         value = expression(prefix ? 120 : 10);
-        if (value && !prefix && report && !state.funct["(loopage)"] && value.type === "undefined") {
+        if (value && !prefix && !state.funct["(loopage)"] && value.type === "undefined") {
           warning("W080", id, id.value);
         }
         if (lone) {
@@ -4259,6 +4247,8 @@ var JSHINT = (function() {
     var comma; // First comma punctuator at level 0
     var initializer; // First initializer at level 0
     var bindingPower;
+    var targets;
+    var target;
 
     // If initial token is a BindingPattern, count it as such.
     if (checkPunctuators(state.tokens.next, ["{", "["])) ++level;
@@ -4286,7 +4276,6 @@ var JSHINT = (function() {
         bindingPower = 0;
       }
 
-      var ok = !(initializer || comma);
       if (initializer) {
         error("W133", comma, nextop.value, "initializer is forbidden");
       }
@@ -4305,10 +4294,48 @@ var JSHINT = (function() {
         state.funct["(scope)"].stack();
         state.tokens.curr.fud({ prefix: true });
       } else {
-        // Parse as a var statement, with implied bindings. Ignore errors if an error
-        // was already reported
-        Object.create(varstatement).fud({ prefix: true, implied: "for", ignore: !ok });
+        targets = [];
+
+        // The following parsing logic recognizes initializers and the comma
+        // operator despite the fact that they are not supported by the
+        // grammar. Doing so allows JSHint to emit more a meaningful error
+        // message (i.e. W133) in response to a common programming mistake.
+        do {
+          if (checkPunctuators(state.tokens.next, ["{", "["])) {
+            destructuringPattern({ assignment: true }).forEach(function(elem) {
+              this.push(elem.token);
+            }, targets);
+          } else {
+            target = expression(120);
+
+            if (target.type === "(identifier)") {
+              targets.push(target);
+            }
+
+            checkLeftSideAssign(target, nextop);
+          }
+
+          if (checkPunctuator(state.tokens.next, "=")) {
+            advance("=");
+            expression(120);
+          }
+
+          if (checkPunctuator(state.tokens.next, ",")) {
+            advance(",");
+          }
+        } while (state.tokens.next !== nextop);
+
+        // In the event of a syntax error, do no issue warnings regarding the
+        // implicit creation of bindings.
+        if (!initializer && !comma) {
+          targets.forEach(function(token) {
+            if (!state.funct["(scope)"].has(token.value)) {
+              warning("W088", token, token.value);
+            }
+          });
+        }
       }
+
       advance(nextop.value);
       // The binding power is variable because for-in statements accept any
       // Expression in this position, while for-of statements are limited to


Test patch:
diff --git a/tests/test262/expectations.txt b/tests/test262/expectations.txt
index acea48a5..51512519 100644
--- a/tests/test262/expectations.txt
+++ b/tests/test262/expectations.txt
@@ -936,7 +936,6 @@ language/statements/for-in/decl-gen.js
 language/statements/for-in/dstr-array-rest-init.js
 language/statements/for-in/head-const-bound-names-fordecl-tdz.js
 language/statements/for-in/head-let-bound-names-fordecl-tdz.js
-language/statements/for-in/head-lhs-cover.js
 language/statements/for-in/head-lhs-let.js
 language/statements/for-in/head-var-bound-names-let.js
 language/statements/for/decl-cls.js
@@ -1143,7 +1142,6 @@ language/statements/return/S12.9_A1_T7.js
 language/statements/return/S12.9_A1_T8.js
 language/statements/return/S12.9_A1_T9.js
 language/statements/for-of/arguments-mapped-mutation.js
-language/statements/for-of/body-put-error.js
 language/statements/for-of/decl-cls.js
 language/statements/for-of/decl-fun.js
 language/statements/for-of/decl-gen.js
@@ -1177,7 +1175,6 @@ language/statements/for-of/dstr-array-rest-iter-rtrn-close.js
 language/statements/for-of/dstr-array-rest-iter-thrw-close-err.js
 language/statements/for-of/dstr-array-rest-iter-thrw-close.js
 language/statements/for-of/dstr-array-rest-lref-err.js
-language/statements/for-of/dstr-array-rest-lref.js
 language/statements/for-of/dstr-array-rest-nested-array-iter-thrw-close-skip.js
 language/statements/for-of/dstr-array-rest-nested-array-null.js
 language/statements/for-of/dstr-array-rest-nested-array-undefined-hole.js
@@ -1227,8 +1224,6 @@ language/statements/for-of/dstr-var-ary-ptrn-rest-obj-id.js
 language/statements/for-of/dstr-var-ary-ptrn-rest-obj-prop-id.js
 language/statements/for-of/head-const-bound-names-fordecl-tdz.js
 language/statements/for-of/head-let-bound-names-fordecl-tdz.js
-language/statements/for-of/head-lhs-cover.js
-language/statements/for-of/head-lhs-member.js
 language/statements/for-of/head-var-bound-names-let.js
 language/statements/switch/S12.11_A2_T1.js
 language/statements/switch/scope-lex-close-case.js
diff --git a/tests/unit/core.js b/tests/unit/core.js
index b02b5f9a..4df6729a 100644
--- a/tests/unit/core.js
+++ b/tests/unit/core.js
@@ -709,7 +709,7 @@ exports.testForIn = function (test) {
   ];
 
   TestRun(test)
-    .addError(2, "Expected an identifier and instead saw 'i'.")
+    .addError(2, "Bad assignment.")
     .test(src);
 
   src = [
@@ -744,6 +744,20 @@ exports.testForIn = function (test) {
     .addError(5, "Invalid for-in loop left-hand-side: initializer is forbidden.")
     .test(src, { esnext: true });
 
+  TestRun(test, "Left-hand side as MemberExpression")
+    .test([
+      "for (x.y in {}) {}",
+      "for (x[z] in {}) {}",
+    ]);
+
+  TestRun(test, "Left-hand side as MemberExpression (invalid)")
+    .addError(1, "Bad assignment.", {character: 10})
+    .addError(2, "Bad assignment.", {character: 13})
+    .test([
+      "for (x+y in {}) {}",
+      "for ((this) in {}) {}"
+    ]);
+
   test.done();
 };
 
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index 44b7e72e..3b3a7a9b 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -4300,6 +4300,20 @@ exports["for of as esnext"] = function (test) {
     .addError(18, "Invalid for-of loop left-hand-side: more than one ForBinding.")
     .test(code, {esnext: true, undef: true, predef: ["print"]});
 
+  TestRun(test, "Left-hand side as MemberExpression")
+    .test([
+      "for (x.y of []) {}",
+      "for (x[z] of []) {}",
+    ], {esversion: 2015});
+
+  TestRun(test, "Left-hand side as MemberExpression (invalid)")
+    .addError(1, "Bad assignment.", {character: 10})
+    .addError(2, "Bad assignment.", {character: 13})
+    .test([
+      "for (x+y of {}) {}",
+      "for ((this) of {}) {}"
+    ], {esversion: 2015});
+
   test.done();
 };
 
@@ -4500,7 +4514,7 @@ exports["array destructuring for of as es5"] = function (test) {
 
   TestRun(test, "basic")
     .addError(1, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(1, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(1, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(1, "Creating global 'for' variable. Should be 'for (var i ...'.")
     .addError(1, "Creating global 'for' variable. Should be 'for (var v ...'.")
     .addError(2, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4525,16 +4539,16 @@ exports["array destructuring for of as es5"] = function (test) {
   TestRun(test, "errors #1")
     .addError(1, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.")
-    .addError(1, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(1, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(2, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(2, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(2, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(2, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(2, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(3, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(3, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(3, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(3, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(3, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4603,7 +4617,7 @@ exports["array destructuring for of as legacy JS"] = function (test) {
 
   TestRun(test, "basic")
     .addError(1, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(1, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(1, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(1, "Creating global 'for' variable. Should be 'for (var i ...'.")
     .addError(1, "Creating global 'for' variable. Should be 'for (var v ...'.")
     .addError(2, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4628,16 +4642,16 @@ exports["array destructuring for of as legacy JS"] = function (test) {
   TestRun(test, "errors #1")
     .addError(1, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.")
-    .addError(1, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(1, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(2, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(2, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(2, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(2, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(2, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(3, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(3, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(3, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(3, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(3, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4774,8 +4788,8 @@ exports["object destructuring for of as es5"] = function (test) {
 
   TestRun(test, "basic")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Creating global 'for' variable. Should be 'for (var key ...'.")
     .addError(4, "Creating global 'for' variable. Should be 'for (var value ...'.")
     .addError(5, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4806,19 +4820,19 @@ exports["object destructuring for of as es5"] = function (test) {
   TestRun(test, "errors #1")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(5, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(6, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(7, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(7, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4903,8 +4917,8 @@ exports["object destructuring for of as legacy JS"] = function (test) {
 
   TestRun(test, "basic")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Creating global 'for' variable. Should be 'for (var key ...'.")
     .addError(4, "Creating global 'for' variable. Should be 'for (var value ...'.")
     .addError(5, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
@@ -4935,19 +4949,20 @@ exports["object destructuring for of as legacy JS"] = function (test) {
   TestRun(test, "errors #1")
     .addError(4, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(4, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(4, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(5, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(5, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(5, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(6, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
-    .addError(6, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
+    .addError(6, "'destructuring assignment' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(7, "'for of' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")
     .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.")
     .addError(7, "'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).")