Commit 232a3360 authored by adamk's avatar adamk Committed by Commit bot

[async functions] Disallow 'await' in arrow params inside async functions

The following code was previously accepted:

  async function f() {
    let g = (await) => {};
  }

But per the spec, using 'await' is disallowed in arrow parameters
by an early error rule (just as 'yield' is disallowed in arrow
params inside generators).

There was special logic in ParseUnaryExpression which seems to have been
there only to allow that case. Having removed it, we get a SyntaxError in
the right cases anyway when ParseUnaryExpression chokes on whatever
illegal token follows 'await' in the cases this code previously handled.

Also removes the unnecessary AsyncBindingPatternProduction enum value.

R=caitp@igalia.com, littledan@chromium.org
BUG=v8:4483

Review-Url: https://codereview.chromium.org/2258313002
Cr-Commit-Position: refs/heads/master@{#38802}
parent db97c402
...@@ -12,20 +12,18 @@ ...@@ -12,20 +12,18 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#define ERROR_CODES(T) \
#define ERROR_CODES(T) \ T(ExpressionProduction, 0) \
T(ExpressionProduction, 0) \ T(FormalParameterInitializerProduction, 1) \
T(FormalParameterInitializerProduction, 1) \ T(BindingPatternProduction, 2) \
T(BindingPatternProduction, 2) \ T(AssignmentPatternProduction, 3) \
T(AssignmentPatternProduction, 3) \ T(DistinctFormalParametersProduction, 4) \
T(DistinctFormalParametersProduction, 4) \ T(StrictModeFormalParametersProduction, 5) \
T(StrictModeFormalParametersProduction, 5) \ T(ArrowFormalParametersProduction, 6) \
T(ArrowFormalParametersProduction, 6) \ T(LetPatternProduction, 7) \
T(LetPatternProduction, 7) \ T(ObjectLiteralProduction, 8) \
T(ObjectLiteralProduction, 8) \ T(TailCallExpressionProduction, 9) \
T(TailCallExpressionProduction, 9) \ T(AsyncArrowFormalParametersProduction, 10)
T(AsyncArrowFormalParametersProduction, 10) \
T(AsyncBindingPatternProduction, 11)
template <typename Traits> template <typename Traits>
class ExpressionClassifier { class ExpressionClassifier {
...@@ -62,12 +60,11 @@ class ExpressionClassifier { ...@@ -62,12 +60,11 @@ class ExpressionClassifier {
ERROR_CODES(DEFINE_PRODUCTION) ERROR_CODES(DEFINE_PRODUCTION)
#undef DEFINE_PRODUCTION #undef DEFINE_PRODUCTION
ExpressionProductions = ExpressionProductions =
(ExpressionProduction | FormalParameterInitializerProduction | (ExpressionProduction | FormalParameterInitializerProduction |
TailCallExpressionProduction), TailCallExpressionProduction),
PatternProductions = PatternProductions = (BindingPatternProduction |
(BindingPatternProduction | AssignmentPatternProduction | AssignmentPatternProduction | LetPatternProduction),
LetPatternProduction | AsyncBindingPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction | FormalParametersProductions = (DistinctFormalParametersProduction |
StrictModeFormalParametersProduction), StrictModeFormalParametersProduction),
AllProductions = AllProductions =
...@@ -150,10 +147,6 @@ class ExpressionClassifier { ...@@ -150,10 +147,6 @@ class ExpressionClassifier {
return is_valid(AsyncArrowFormalParametersProduction); return is_valid(AsyncArrowFormalParametersProduction);
} }
bool is_valid_async_binding_pattern() const {
return is_valid(AsyncBindingPatternProduction);
}
V8_INLINE const Error& expression_error() const { V8_INLINE const Error& expression_error() const {
return reported_error(kExpressionProduction); return reported_error(kExpressionProduction);
} }
...@@ -205,10 +198,6 @@ class ExpressionClassifier { ...@@ -205,10 +198,6 @@ class ExpressionClassifier {
return reported_error(kAsyncArrowFormalParametersProduction); return reported_error(kAsyncArrowFormalParametersProduction);
} }
V8_INLINE const Error& async_binding_pattern_error() const {
return reported_error(kAsyncBindingPatternProduction);
}
V8_INLINE bool is_simple_parameter_list() const { V8_INLINE bool is_simple_parameter_list() const {
return !(function_properties_ & NonSimpleParameter); return !(function_properties_ & NonSimpleParameter);
} }
...@@ -280,14 +269,6 @@ class ExpressionClassifier { ...@@ -280,14 +269,6 @@ class ExpressionClassifier {
Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg)); Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg));
} }
void RecordAsyncBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_async_binding_pattern()) return;
invalid_productions_ |= AsyncBindingPatternProduction;
Add(Error(loc, message, kAsyncBindingPatternProduction, arg));
}
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) { void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
if (!is_valid_formal_parameter_list_without_duplicates()) return; if (!is_valid_formal_parameter_list_without_duplicates()) return;
invalid_productions_ |= DistinctFormalParametersProduction; invalid_productions_ |= DistinctFormalParametersProduction;
......
...@@ -929,16 +929,8 @@ class ParserBase : public Traits { ...@@ -929,16 +929,8 @@ class ParserBase : public Traits {
void ValidateBindingPattern(const ExpressionClassifier* classifier, void ValidateBindingPattern(const ExpressionClassifier* classifier,
bool* ok) { bool* ok) {
if (!classifier->is_valid_binding_pattern() || if (!classifier->is_valid_binding_pattern()) {
!classifier->is_valid_async_binding_pattern()) { ReportClassifierError(classifier->binding_pattern_error());
const Scanner::Location& a = classifier->binding_pattern_error().location;
const Scanner::Location& b =
classifier->async_binding_pattern_error().location;
if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
ReportClassifierError(classifier->async_binding_pattern_error());
} else {
ReportClassifierError(classifier->binding_pattern_error());
}
*ok = false; *ok = false;
} }
} }
...@@ -2758,40 +2750,15 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier, ...@@ -2758,40 +2750,15 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
position()); position());
} else if (is_async_function() && peek() == Token::AWAIT) { } else if (is_async_function() && peek() == Token::AWAIT) {
int beg_pos = peek_position(); classifier->RecordFormalParameterInitializerError(
switch (PeekAhead()) { scanner()->peek_location(),
case Token::RPAREN: MessageTemplate::kAwaitExpressionFormalParameter);
case Token::RBRACK:
case Token::RBRACE:
case Token::ASSIGN:
case Token::COMMA: {
Next();
IdentifierT name = this->GetSymbol(scanner());
// Possibly async arrow formals --- record ExpressionError just in case.
ExpressionUnexpectedToken(classifier);
classifier->RecordAsyncBindingPatternError(
Scanner::Location(beg_pos, scanner()->location().end_pos),
MessageTemplate::kAwaitBindingIdentifier);
classifier->RecordAsyncArrowFormalParametersError(
Scanner::Location(beg_pos, scanner()->location().end_pos),
MessageTemplate::kAwaitBindingIdentifier);
return this->ExpressionFromIdentifier(name, beg_pos,
scanner()->location().end_pos);
}
default:
break;
}
int await_pos = peek_position(); int await_pos = peek_position();
Consume(Token::AWAIT); Consume(Token::AWAIT);
ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK); ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK);
classifier->RecordFormalParameterInitializerError(
Scanner::Location(beg_pos, scanner()->location().end_pos),
MessageTemplate::kAwaitExpressionFormalParameter);
return Traits::RewriteAwaitExpression(value, await_pos); return Traits::RewriteAwaitExpression(value, await_pos);
} else { } else {
return this->ParsePostfixExpression(classifier, ok); return this->ParsePostfixExpression(classifier, ok);
......
...@@ -7803,7 +7803,6 @@ TEST(AsyncAwait) { ...@@ -7803,7 +7803,6 @@ TEST(AsyncAwait) {
"function foo(await) { return await; }", "function foo(await) { return await; }",
"function* foo() { var await = 1; return await; }", "function* foo() { var await = 1; return await; }",
"function* foo(await) { return await; }", "function* foo(await) { return await; }",
"var f = (await) => await;",
"var f = () => { var await = 1; return await; }", "var f = () => { var await = 1; return await; }",
"var O = { method() { var await = 1; return await; } };", "var O = { method() { var await = 1; return await; } };",
"var O = { method(await) { return await; } };", "var O = { method(await) { return await; } };",
...@@ -7835,37 +7834,19 @@ TEST(AsyncAwaitErrors) { ...@@ -7835,37 +7834,19 @@ TEST(AsyncAwaitErrors) {
}; };
const char* error_data[] = { const char* error_data[] = {
"var asyncFn = async function() { var await = 1; };",
"var asyncFn = async function() { var { await } = 1; };",
"var asyncFn = async function() { var [ await ] = 1; };",
"var asyncFn = async function await() {};", "var asyncFn = async function await() {};",
"var asyncFn = async () => var await = 'test';", "var asyncFn = async () => var await = 'test';",
"var asyncFn = async await => await + 'test';", "var asyncFn = async await => await + 'test';",
"var asyncFn = async function(await) {};", "var asyncFn = async function(await) {};",
"var asyncFn = async function() { return async (await) => {}; }",
"var asyncFn = async (await) => 'test';", "var asyncFn = async (await) => 'test';",
"var asyncFn = async x => { var await = 1; }",
"var asyncFn = async x => { var { await } = 1; }",
"var asyncFn = async x => { var [ await ] = 1; }",
"async function f(await) {}", "async function f(await) {}",
"async function f() { var await = 1; }",
"async function f() { var { await } = 1; }",
"async function f() { var [ await ] = 1; }",
"var O = { async method(a, a) {} }", "var O = { async method(a, a) {} }",
"var O = { async ['meth' + 'od'](a, a) {} }", "var O = { async ['meth' + 'od'](a, a) {} }",
"var O = { async 'method'(a, a) {} }", "var O = { async 'method'(a, a) {} }",
"var O = { async 0(a, a) {} }", "var O = { async 0(a, a) {} }",
"async function f() { var O = { async [await](a, a) {} } }",
"var asyncFn = async function() { await; }",
"async function f() { await; }",
"var O = { async method() { await; } };",
"var f = async() => await;", "var f = async() => await;",
"var f = async() => { await; };",
"async function f() { return {await} }",
"var asyncFn = async function*() {}", "var asyncFn = async function*() {}",
"async function* f() {}", "async function* f() {}",
...@@ -7887,11 +7868,6 @@ TEST(AsyncAwaitErrors) { ...@@ -7887,11 +7868,6 @@ TEST(AsyncAwaitErrors) {
"var f = async() => ((async(x = await 1) => x)();", "var f = async() => ((async(x = await 1) => x)();",
"var asyncFn = async function() { function await() {} }",
"var asyncFn = async() => { function await() {} }",
"var O = { async method() { function await() {} } }",
"async function foo() { function await() {} }",
// Henrique Ferreiro's bug (tm) // Henrique Ferreiro's bug (tm)
"(async function foo1() { } foo2 => 1)", "(async function foo1() { } foo2 => 1)",
"(async function foo3() { } () => 1)", "(async function foo3() { } () => 1)",
...@@ -7976,6 +7952,48 @@ TEST(AsyncAwaitErrors) { ...@@ -7976,6 +7952,48 @@ TEST(AsyncAwaitErrors) {
RunParserSyncTest(context_data, formal_parameters_data, kError, NULL, 0, RunParserSyncTest(context_data, formal_parameters_data, kError, NULL, 0,
always_flags, arraysize(always_flags)); always_flags, arraysize(always_flags));
// clang-format off
const char* async_body_context_data[][2] = {
{ "async function f() {", "}" },
{ "var f = async function() {", "}" },
{ "var f = async() => {", "}" },
{ "var O = { async method() {", "} }" },
{ "'use strict'; async function f() {", "}" },
{ "'use strict'; var f = async function() {", "}" },
{ "'use strict'; var f = async() => {", "}" },
{ "'use strict'; var O = { async method() {", "} }" },
{ NULL, NULL }
};
const char* async_body_error_data[] = {
"var await = 1;",
"var { await } = 1;",
"var [ await ] = 1;",
"return async (await) => {};",
"var O = { async [await](a, a) {} }",
"await;",
"function await() {}",
"var f = await => 42;",
"var f = (await) => 42;",
"var f = (await, a) => 42;",
"var f = (...await) => 42;",
"var e = (await);",
"var e = (await, f);",
"var e = (await = 42)",
"var e = [await];",
"var e = {await};",
NULL
};
// clang-format on
RunParserSyncTest(async_body_context_data, async_body_error_data, kError,
NULL, 0, always_flags, arraysize(always_flags));
} }
TEST(AsyncAwaitModule) { TEST(AsyncAwaitModule) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment