diff --git a/scripts/test262_whitelist.txt b/scripts/test262_whitelist.txt index 6b6afda233..1922d09b1c 100644 --- a/scripts/test262_whitelist.txt +++ b/scripts/test262_whitelist.txt @@ -123,8 +123,6 @@ language/expressions/async-arrow-function/early-errors-arrow-formals-body-duplic language/expressions/async-arrow-function/early-errors-arrow-formals-body-duplicate.js(strict mode) language/expressions/async-arrow-function/escaped-async.js(default) language/expressions/async-arrow-function/escaped-async.js(strict mode) -language/expressions/async-arrow-function/rest-params-trailing-comma-early-error.js(default) -language/expressions/async-arrow-function/rest-params-trailing-comma-early-error.js(strict mode) language/expressions/async-function/early-errors-expression-formals-body-duplicate.js(default) language/expressions/async-function/early-errors-expression-formals-body-duplicate.js(strict mode) language/expressions/async-function/escaped-async.js(default) diff --git a/src/parser/expression.js b/src/parser/expression.js index 547bf121bb..a535be291f 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -494,14 +494,29 @@ export default class ExpressionParser extends LValParser { const node = this.startNodeAt(startPos, startLoc); node.callee = base; + + // TODO: Clean up/merge this into `this.state` or a class like acorn's + // `DestructuringErrors` alongside refShorthandDefaultPos and + // refNeedsArrowPos. + const refTrailingCommaPos: Pos = { start: -1 }; + node.arguments = this.parseCallExpressionArguments( tt.parenR, possibleAsync, + refTrailingCommaPos, ); this.finishCallExpression(node); if (possibleAsync && this.shouldParseAsyncArrow()) { state.stop = true; + + if (refTrailingCommaPos.start > -1) { + this.raise( + refTrailingCommaPos.start, + "A trailing comma is not permitted after the rest element", + ); + } + return this.parseAsyncArrowFromCallExpression( this.startNodeAt(startPos, startLoc), node, @@ -547,6 +562,7 @@ export default class ExpressionParser extends LValParser { parseCallExpressionArguments( close: TokenType, possibleAsyncArrow: boolean, + refTrailingCommaPos?: Pos, ): $ReadOnlyArray { const elts = []; let innerParenStart; @@ -570,6 +586,7 @@ export default class ExpressionParser extends LValParser { false, possibleAsyncArrow ? { start: 0 } : undefined, possibleAsyncArrow ? { start: 0 } : undefined, + possibleAsyncArrow ? refTrailingCommaPos : undefined, ), ); } @@ -911,6 +928,14 @@ export default class ExpressionParser extends LValParser { spreadNodeStartLoc, ), ); + + if (this.match(tt.comma) && this.lookahead().type === tt.parenR) { + this.raise( + this.state.start, + "A trailing comma is not permitted after the rest element", + ); + } + break; } else { exprList.push( @@ -1539,12 +1564,17 @@ export default class ExpressionParser extends LValParser { allowEmpty: ?boolean, refShorthandDefaultPos: ?Pos, refNeedsArrowPos: ?Pos, + refTrailingCommaPos?: Pos, ): ?N.Expression { let elt; if (allowEmpty && this.match(tt.comma)) { elt = null; } else if (this.match(tt.ellipsis)) { elt = this.parseSpread(refShorthandDefaultPos); + + if (refTrailingCommaPos && this.match(tt.comma)) { + refTrailingCommaPos.start = this.state.start; + } } else { elt = this.parseMaybeAssign( false, diff --git a/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/actual.js b/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/actual.js new file mode 100644 index 0000000000..d55ef5bce0 --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/actual.js @@ -0,0 +1 @@ +(...a,) => {}; diff --git a/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/options.json b/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/options.json new file mode 100644 index 0000000000..a85e470aeb --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/params-invalid-rest-trailing-comma/options.json @@ -0,0 +1,3 @@ +{ + "throws": "A trailing comma is not permitted after the rest element (1:5)" +} diff --git a/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/actual.js b/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/actual.js new file mode 100644 index 0000000000..417005c23f --- /dev/null +++ b/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/actual.js @@ -0,0 +1 @@ +async (...a,) => {}; diff --git a/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/options.json b/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/options.json new file mode 100644 index 0000000000..52560b0a85 --- /dev/null +++ b/test/fixtures/es2017/async-functions/params-invalid-rest-trailing-comma/options.json @@ -0,0 +1,3 @@ +{ + "throws": "A trailing comma is not permitted after the rest element (1:11)" +}