diff --git a/src/parse.cpp b/src/parse.cpp index cdbe1e3112..dd82dc9ce2 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -701,6 +701,27 @@ expression* parser::parse_async_expression_only(token async_token, } expression* parser::parse_await_expression(token await_token, precedence prec) { + bool is_followed_by_arrow = [&]() -> bool { + switch (this->peek().type) { + case token_type::left_paren: + case token_type::identifier: { + buffering_error_reporter temp_error_reporter(&this->temporary_memory_); + error_reporter* old_error_reporter = + std::exchange(this->error_reporter_, &temp_error_reporter); + lexer_transaction transaction = this->lexer_.begin_transaction(); + + expression* ast = this->parse_expression(prec); + + this->lexer_.roll_back_transaction(std::move(transaction)); + this->error_reporter_ = old_error_reporter; + + return this->is_arrow_kind(ast); + } + default: + return false; + } + }(); + bool is_identifier = [&]() -> bool { if (this->in_async_function_ || (this->in_top_level_ && @@ -783,6 +804,9 @@ expression* parser::parse_await_expression(token await_token, precedence prec) { return is_identifier_result; } + case token_type::left_paren: + return !this->in_top_level_ && !is_followed_by_arrow; + case token_type::kw_of: // HACK(strager): This works around for-of parsing. Remove this case // when for-of parsing is fixed. @@ -793,7 +817,6 @@ expression* parser::parse_await_expression(token await_token, precedence prec) { [[fallthrough]]; case token_type::complete_template: case token_type::incomplete_template: - case token_type::left_paren: case token_type::left_square: case token_type::minus: case token_type::plus: @@ -836,18 +859,23 @@ expression* parser::parse_await_expression(token await_token, precedence prec) { }); } - expression* child = this->parse_expression(prec); + expression* child; + + if (is_followed_by_arrow) { + this->error_reporter_->report(error_await_followed_by_arrow_function{ + .await_operator = operator_span, + }); + child = this->parse_async_expression(await_token, prec); + } else { + child = this->parse_expression(prec); + } if (child->kind() == expression_kind::_invalid) { this->error_reporter_->report(error_missing_operand_for_operator{ .where = operator_span, }); - } else if (this->in_async_function_ && this->is_arrow_kind(child) && - child->attributes() != function_attributes::async) { - this->error_reporter_->report(error_await_followed_by_arrow_function{ - .await_operator = operator_span, - }); } + return this->make_expression(child, operator_span); } } diff --git a/test/test-parse-expression.cpp b/test/test-parse-expression.cpp index 57ee46faeb..9c7576caad 100644 --- a/test/test-parse-expression.cpp +++ b/test/test-parse-expression.cpp @@ -961,6 +961,100 @@ TEST_F(test_parse_expression, await_followed_by_arrow_function) { error_await_followed_by_arrow_function, await_operator, offsets_matcher(p.code(), 0, u8"await")))); } + + { + test_parser p(u8"await x => {}"_sv); + auto guard = p.parser().enter_function(function_attributes::normal); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT( + p.errors(), + ElementsAre( + ERROR_TYPE_FIELD(error_await_operator_outside_async, await_operator, + offsets_matcher(p.code(), 0, u8"await")), + ERROR_TYPE_FIELD(error_await_followed_by_arrow_function, + await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } + + { + test_parser p(u8"await () => {}"_sv); + auto guard = p.parser().enter_function(function_attributes::normal); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT( + p.errors(), + ElementsAre( + ERROR_TYPE_FIELD(error_await_operator_outside_async, await_operator, + offsets_matcher(p.code(), 0, u8"await")), + ERROR_TYPE_FIELD(error_await_followed_by_arrow_function, + await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } + + { + test_parser p(u8"await () => { await g(); }"_sv); + auto guard = p.parser().enter_function(function_attributes::async); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT(p.errors(), + ElementsAre(ERROR_TYPE_FIELD( + error_await_followed_by_arrow_function, await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } + + { + test_parser p(u8"await x => { await g(); }"_sv); + auto guard = p.parser().enter_function(function_attributes::async); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT(p.errors(), + ElementsAre(ERROR_TYPE_FIELD( + error_await_followed_by_arrow_function, await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } + + { + test_parser p(u8"await () => { await g(); }"_sv); + auto guard = p.parser().enter_function(function_attributes::normal); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT( + p.errors(), + ElementsAre( + ERROR_TYPE_FIELD(error_await_operator_outside_async, await_operator, + offsets_matcher(p.code(), 0, u8"await")), + ERROR_TYPE_FIELD(error_await_followed_by_arrow_function, + await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } + + { + test_parser p(u8"await x => { await g(); }"_sv); + auto guard = p.parser().enter_function(function_attributes::normal); + expression* ast = p.parse_expression(); + EXPECT_EQ(ast->kind(), expression_kind::await); + EXPECT_EQ(ast->child_0()->kind(), + expression_kind::arrow_function_with_statements); + EXPECT_THAT( + p.errors(), + ElementsAre( + ERROR_TYPE_FIELD(error_await_operator_outside_async, await_operator, + offsets_matcher(p.code(), 0, u8"await")), + ERROR_TYPE_FIELD(error_await_followed_by_arrow_function, + await_operator, + offsets_matcher(p.code(), 0, u8"await")))); + } } TEST_F(test_parse_expression,