Repository: jshint/jshint
Pull request #3483 (2020-06-14 21:50:32)

[[FIX]] Allow "rest" operator in param dstrctrng
Previously, in the context of function parameter lists, JSHint only
allowed the "rest" operator to be applied to identifiers. Extend support
to destructuring patterns and update the Test262 "expectations" file
accordingly.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/31445426/badge)](https://coveralls.io/builds/31445426)

Coverage remained the same at 100.0% when pulling **b6a1c2ec62a390df8159d054274475b46a639668 on jugglinmike:improve-rest-params** into **cd3fda07c3dc6af74a0fb5ad087d54e45afb0e68 on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index c4b8a396..49e7b554 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -3522,6 +3522,8 @@ var JSHINT = (function() {
       // are added to the param scope
       var currentParams = [];
 
+      pastRest = spreadrest("rest");
+
       if (_.includes(["{", "["], state.tokens.next.id)) {
         hasDestructuring = true;
         tokens = destructuringPattern(context);
@@ -3533,7 +3535,6 @@ var JSHINT = (function() {
           }
         }
       } else {
-        pastRest = spreadrest("rest");
         ident = identifier(context);
 
         if (ident) {
diff --git a/src/lex.js b/src/lex.js
index c5431649..9a078ea7 100644
--- a/src/lex.js
+++ b/src/lex.js
@@ -966,11 +966,19 @@ Lexer.prototype = {
       }
     }
 
+    // TODO: Extend this check to other numeric literals
+    this.triggerAsync("warning", {
+      code: "W045",
+      line: this.line,
+      character: this.char + value.length,
+      data: [ value ]
+    }, checks, function() { return !isFinite(value); });
+
     return {
       type: Token.NumericLiteral,
       value: value,
       base: base,
-      isMalformed: !isFinite(value)
+      isMalformed: false
     };
   },
 
@@ -2143,10 +2151,8 @@ Lexer.prototype = {
 
       case Token.NumericLiteral:
         if (token.isMalformed) {
-          // This condition unequivocally describes a syntax error.
-          // TODO: Re-factor as an "error" (not a "warning").
-          this.trigger("warning", {
-            code: "W045",
+          this.trigger("error", {
+            code: "E067",
             line: this.line,
             character: this.char,
             data: [ token.value ]
diff --git a/src/messages.js b/src/messages.js
index cce95ff7..e541cdeb 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -82,7 +82,8 @@ var errors = {
   E064: "Super call may only be used within class method bodies.",
   E065: "Functions defined outside of strict mode with non-simple parameter lists may not " +
     "enable strict mode.",
-  E066: "Asynchronous iteration is only available with for-of loops."
+  E066: "Asynchronous iteration is only available with for-of loops.",
+  E067: "Malformed numeric literal: '{a}'."
 };
 
 var warnings = {
@@ -131,7 +132,8 @@ var warnings = {
   W042: "Avoid EOL escaping.",
   W043: "Bad escaping of EOL. Use option multistr if needed.",
   W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */
-  W045: "Bad number '{a}'.",
+  W045: "Value described by numeric literal cannot be accurately " +
+    "represented with a number value: '{a}'.",
   W046: "Don't use extra leading zeros '{a}'.",
   W047: "A trailing decimal point can be confused with a dot: '{a}'.",
   W048: "Unexpected control character in regular expression.",


Test patch:
diff --git a/tests/test262/expectations.txt b/tests/test262/expectations.txt
index d90d2ea0..2aef55d5 100644
--- a/tests/test262/expectations.txt
+++ b/tests/test262/expectations.txt
@@ -143,22 +143,10 @@ test/language/identifiers/vals-rus-alpha-lower-via-escape-hex.js(default)
 test/language/identifiers/vals-rus-alpha-lower-via-escape-hex.js(strict mode)
 test/language/identifiers/vals-rus-alpha-upper-via-escape-hex.js(default)
 test/language/identifiers/vals-rus-alpha-upper-via-escape-hex.js(strict mode)
-test/language/rest-parameters/array-pattern.js(default)
-test/language/rest-parameters/array-pattern.js(strict mode)
-test/language/rest-parameters/object-pattern.js(default)
-test/language/rest-parameters/object-pattern.js(strict mode)
 test/language/arguments-object/10.6-13-c-1-s.js(strict mode)
 test/language/arguments-object/10.6-1gs.js(strict mode)
 test/language/arguments-object/10.6-2gs.js(strict mode)
-test/language/literals/numeric/S7.8.3_A6.1_T1.js(default)
-test/language/literals/numeric/S7.8.3_A6.1_T1.js(strict mode)
-test/language/literals/numeric/S7.8.3_A6.1_T2.js(default)
-test/language/literals/numeric/S7.8.3_A6.1_T2.js(strict mode)
-test/language/literals/numeric/binary-invalid-truncated.js(default)
-test/language/literals/numeric/binary-invalid-truncated.js(strict mode)
 test/language/literals/numeric/non-octal-decimal-integer-strict.js(strict mode)
-test/language/literals/numeric/octal-invalid-truncated.js(default)
-test/language/literals/numeric/octal-invalid-truncated.js(strict mode)
 test/language/block-scope/syntax/function-declarations/in-statement-position-if-expression-statement-else-statement.js(strict mode)
 test/language/block-scope/syntax/function-declarations/in-statement-position-if-expression-statement.js(strict mode)
 test/language/destructuring/binding/syntax/array-elements-with-initializer.js(default)
@@ -199,10 +187,6 @@ test/language/expressions/template-literal/invalid-hexidecimal-character-escape-
 test/language/expressions/template-literal/invalid-legacy-octal-escape-sequence.js(default)
 test/language/expressions/template-literal/tv-utf16-escape-sequence.js(default)
 test/language/expressions/template-literal/tv-utf16-escape-sequence.js(strict mode)
-test/language/expressions/function/scope-param-rest-elem-var-close.js(default)
-test/language/expressions/function/scope-param-rest-elem-var-open.js(default)
-test/language/expressions/generators/scope-param-rest-elem-var-close.js(default)
-test/language/expressions/generators/scope-param-rest-elem-var-open.js(default)
 test/language/expressions/generators/yield-as-function-expression-binding-identifier.js(default)
 test/language/expressions/generators/yield-as-logical-or-expression.js(default)
 test/language/expressions/generators/yield-as-logical-or-expression.js(strict mode)
@@ -210,10 +194,6 @@ test/language/expressions/generators/yield-star-after-newline.js(default)
 test/language/expressions/generators/yield-star-after-newline.js(strict mode)
 test/language/expressions/class/getter-param-dflt.js(default)
 test/language/expressions/class/getter-param-dflt.js(strict mode)
-test/language/expressions/object/scope-gen-meth-param-rest-elem-var-close.js(default)
-test/language/expressions/object/scope-gen-meth-param-rest-elem-var-open.js(default)
-test/language/expressions/object/scope-meth-param-rest-elem-var-close.js(default)
-test/language/expressions/object/scope-meth-param-rest-elem-var-open.js(default)
 test/language/expressions/object/method-definition/yield-as-expression-with-rhs.js(default)
 test/language/expressions/object/method-definition/yield-as-expression-with-rhs.js(strict mode)
 test/language/expressions/object/method-definition/yield-as-expression-without-rhs.js(default)
@@ -223,8 +203,6 @@ test/language/expressions/object/method-definition/yield-as-logical-or-expressio
 test/language/expressions/object/method-definition/yield-as-logical-or-expression.js(strict mode)
 test/language/expressions/object/method-definition/yield-star-after-newline.js(default)
 test/language/expressions/object/method-definition/yield-star-after-newline.js(strict mode)
-test/language/expressions/arrow-function/scope-param-rest-elem-var-close.js(default)
-test/language/expressions/arrow-function/scope-param-rest-elem-var-open.js(default)
 test/language/expressions/arrow-function/syntax/early-errors/asi-restriction-invalid-parenless-parameters-expression-body.js(default)
 test/language/expressions/arrow-function/syntax/early-errors/asi-restriction-invalid-parenless-parameters-expression-body.js(strict mode)
 test/language/expressions/arrow-function/syntax/early-errors/asi-restriction-invalid-parenless-parameters.js(default)
@@ -265,8 +243,6 @@ test/language/statements/if/if-stmt-else-decl-strict.js(strict mode)
 test/language/statements/if/if-stmt-else-fun-strict.js(strict mode)
 test/language/statements/if/if-stmt-else-gen.js(default)
 test/language/statements/if/if-stmt-else-gen.js(strict mode)
-test/language/statements/generators/scope-param-rest-elem-var-close.js(default)
-test/language/statements/generators/scope-param-rest-elem-var-open.js(default)
 test/language/statements/generators/yield-as-function-expression-binding-identifier.js(default)
 test/language/statements/generators/yield-as-logical-or-expression.js(default)
 test/language/statements/generators/yield-as-logical-or-expression.js(strict mode)
@@ -283,8 +259,6 @@ test/language/statements/labeled/decl-gen.js(default)
 test/language/statements/labeled/decl-gen.js(strict mode)
 test/language/statements/labeled/decl-let.js(default)
 test/language/statements/labeled/decl-let.js(strict mode)
-test/language/statements/function/scope-param-rest-elem-var-close.js(default)
-test/language/statements/function/scope-param-rest-elem-var-open.js(default)
 test/language/statements/return/S12.9_A1_T1.js(default)
 test/language/statements/return/S12.9_A1_T1.js(strict mode)
 test/language/statements/return/S12.9_A1_T10.js(default)
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index 034a186c..c1c81592 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -537,7 +537,7 @@ exports.numbers = function (test) {
   ];
 
   TestRun(test)
-    .addError(2, 15, "Bad number '10e308'.")
+    .addError(2, 15, "Value described by numeric literal cannot be accurately represented with a number value: '10e308'.")
     .addError(5, 11, "A leading decimal point can be confused with a dot: '.3'.")
     .addError(6, 9, "Unexpected '0'.")
     .addError(7, 1, "Expected an identifier and instead saw 'var'.")
@@ -547,7 +547,7 @@ exports.numbers = function (test) {
     .addError(9, 9, "A dot following a number can be confused with a decimal point.")
     .addError(11, 9, "'Octal integer literal' is only available in ES6 (use 'esversion: 6').")
     .addError(12, 9, "'Binary integer literal' is only available in ES6 (use 'esversion: 6').")
-    .addError(13, 11, "Bad number '0x'.")
+    .addError(13, 11, "Malformed numeric literal: '0x'.")
     .addError(15, 9, "Unexpected '1'.")
     .addError(16, 11, "Expected an identifier and instead saw ';'.")
     .addError(16, 1, "Expected an identifier and instead saw 'var'.")
diff --git a/tests/unit/unstable/bigint.js b/tests/unit/unstable/bigint.js
index 174505bc..a299cca8 100644
--- a/tests/unit/unstable/bigint.js
+++ b/tests/unit/unstable/bigint.js
@@ -75,19 +75,19 @@ exports.invalid = function (test) {
     .test("void 1e3n;", {esversion: 6, unstable: {bigint: true}});
 
   TestRun(test, "invalid hex digit")
-    .addError(1, 8, "Bad number '0x'.")
+    .addError(1, 8, "Malformed numeric literal: '0x'.")
     .addError(1, 8, "Missing semicolon.")
     .addError(1, 8, "Expected an assignment or function call and instead saw an expression.")
     .test("void 0xgn;", {esversion: 6, unstable: {bigint: true}});
 
   TestRun(test, "invalid binary digit")
-    .addError(1, 8, "Bad number '0b'.")
+    .addError(1, 8, "Malformed numeric literal: '0b'.")
     .addError(1, 8, "Missing semicolon.")
     .addError(1, 8, "Expected an assignment or function call and instead saw an expression.")
     .test("void 0b2n;", {esversion: 6, unstable: {bigint: true}});
 
   TestRun(test, "invalid octal digit")
-    .addError(1, 8, "Bad number '0o'.")
+    .addError(1, 8, "Malformed numeric literal: '0o'.")
     .addError(1, 8, "Missing semicolon.")
     .addError(1, 8, "Expected an assignment or function call and instead saw an expression.")
     .test("void 0o8n;", {esversion: 6, unstable: {bigint: true}});