[parser] Fix parse errors for async arrow function edge cases

New test262 tests bring up a couple cases with async arrow functions
that V8 didn't seem to handle properly; this patch makes those cases
errors:
- async (...x,) => y -- Rest parameter must be last formal parameter
- async (...x = z) => y -- No default value for rest parameter
- async (...x, y) => z -- Rest parameter must be last formal parameter

Bug: v8:4483, v8:5051
Change-Id: I024d9ba0c854e8e5e75283df2ee53127b1be090d
Reviewed-on: https://chromium-review.googlesource.com/496057
Commit-Queue: Daniel Ehrenberg <littledan@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#45116}
This commit is contained in:
Daniel Ehrenberg 2017-05-05 00:08:28 +02:00 committed by Commit Bot
parent 6545911f30
commit c299fee21c
13 changed files with 80 additions and 7 deletions

View File

@ -608,6 +608,8 @@ class ErrorUtils : public AllStatic {
T(ArgStringTerminatesParametersEarly, \
"Arg string terminates parameters early") \
T(UnexpectedEndOfArgString, "Unexpected end of arg string") \
T(RestDefaultInitializer, \
"Rest parameter may not have a default initializer") \
T(RuntimeWrongNumArgs, "Runtime function given wrong number of arguments") \
T(SuperNotCalled, \
"Must call super constructor in derived class before accessing 'this' or " \

View File

@ -1972,6 +1972,11 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
int ellipsis_pos = position();
int pattern_pos = peek_position();
ExpressionT pattern = ParsePrimaryExpression(CHECK_OK);
if (peek() == Token::ASSIGN) {
ReportMessage(MessageTemplate::kRestDefaultInitializer);
*ok = false;
return result;
}
ValidateBindingPattern(CHECK_OK);
right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos);
} else {
@ -2715,6 +2720,10 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
spread_arg.beg_pos = start_pos;
spread_arg.end_pos = peek_position();
}
if (argument->IsAssignment()) {
classifier()->RecordAsyncArrowFormalParametersError(
scanner()->location(), MessageTemplate::kRestDefaultInitializer);
}
argument = factory()->NewSpread(argument, start_pos, expr_pos);
}
result->Add(argument, zone_);
@ -2727,6 +2736,10 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
done = (peek() != Token::COMMA);
if (!done) {
Next();
if (argument->IsSpread()) {
classifier()->RecordAsyncArrowFormalParametersError(
scanner()->location(), MessageTemplate::kParamAfterRest);
}
if (allow_harmony_trailing_commas() && peek() == Token::RPAREN) {
// allow trailing comma
done = true;
@ -3657,7 +3670,12 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
}
ExpressionT initializer = impl()->EmptyExpression();
if (!is_rest && Check(Token::ASSIGN)) {
if (Check(Token::ASSIGN)) {
if (is_rest) {
ReportMessage(MessageTemplate::kRestDefaultInitializer);
*ok = false;
return;
}
ExpressionClassifier init_classifier(this);
initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void));

View File

@ -4262,6 +4262,7 @@ TEST(ErrorsArrowFunctions) {
"(c, a.b) => {}",
"(a['b'], c) => {}",
"(c, a['b']) => {}",
"(...a = b) => b",
// crbug.com/582626
"(...rest - a) => b",
@ -8989,6 +8990,10 @@ TEST(AsyncAwaitErrors) {
// v8:5148 assert that errors are still thrown for calls that may have been
// async functions
"async({ foo33 = 1 })",
"async(...a = b) => b",
"async(...a,) => b",
"async(...a, b) => b",
NULL
};

View File

@ -1,4 +1,4 @@
*%(basename)s:7: SyntaxError: Unexpected token =
*%(basename)s:7: SyntaxError: Rest parameter may not have a default initializer
var f = (a, ...x = 10) => x;
^
SyntaxError: Unexpected token =
^
SyntaxError: Rest parameter may not have a default initializer

View File

@ -1,4 +1,4 @@
*%(basename)s:7: SyntaxError: Unexpected token =
*%(basename)s:7: SyntaxError: Rest parameter may not have a default initializer
var f = (...x = 10) => x;
^
SyntaxError: Unexpected token =
^
SyntaxError: Rest parameter may not have a default initializer

View File

@ -0,0 +1,8 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
var f = async (a, ...x = 10) => x;
f(1, 2, 3, 4, 5);

View File

@ -0,0 +1,4 @@
*%(basename)s:7: SyntaxError: Rest parameter may not have a default initializer
var f = async (a, ...x = 10) => x;
^^
SyntaxError: Rest parameter may not have a default initializer

View File

@ -0,0 +1,8 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
var f = async (...x = 10) => x;
f(1, 2, 3, 4, 5);

View File

@ -0,0 +1,4 @@
*%(basename)s:7: SyntaxError: Rest parameter may not have a default initializer
var f = async (...x = 10) => x;
^^
SyntaxError: Rest parameter may not have a default initializer

View File

@ -0,0 +1,7 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
async (...x, y) => 10

View File

@ -0,0 +1,5 @@
*%(basename)s:7: SyntaxError: Rest parameter must be last formal parameter
async (...x, y) => 10
^
SyntaxError: Rest parameter must be last formal parameter

View File

@ -0,0 +1,7 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
function f(...x, y) { }

View File

@ -0,0 +1,5 @@
*%(basename)s:7: SyntaxError: Rest parameter must be last formal parameter
function f(...x, y) { }
^
SyntaxError: Rest parameter must be last formal parameter