Skip to content

Commit f2cccdd

Browse files
Fix crash on destructuring assignment with async
The following code doesn't make quick-lint-js to crash now: let { async = 3, get = 4, set = 5 } = {};
1 parent 1ae9125 commit f2cccdd

File tree

2 files changed

+47
-24
lines changed

2 files changed

+47
-24
lines changed

src/parse.cpp

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,32 @@ expression* parser::parse_object_literal() {
13811381
this->skip();
13821382
return property_name;
13831383
};
1384+
auto parse_equal = [&](token key_token, expression* key) {
1385+
expression* lhs;
1386+
bool missing_key;
1387+
switch (key_token.type) {
1388+
case token_type::number:
1389+
case token_type::string:
1390+
lhs = this->make_expression<expression::literal>(key_token.span());
1391+
missing_key = true;
1392+
break;
1393+
default:
1394+
lhs = this->make_expression<expression::variable>(
1395+
key_token.identifier_name(), key_token.type);
1396+
missing_key = false;
1397+
break;
1398+
}
1399+
this->skip();
1400+
expression* rhs = this->parse_expression(precedence{.commas = false});
1401+
expression* value = this->make_expression<expression::assignment>(
1402+
expression_kind::assignment, lhs, rhs);
1403+
if (missing_key) {
1404+
this->error_reporter_->report(error_missing_key_for_object_entry{
1405+
.expression = value->span(),
1406+
});
1407+
}
1408+
entries.emplace_back(key, value);
1409+
};
13841410
auto parse_method_entry = [&](const char8* key_span_begin, expression* key,
13851411
function_attributes attributes) -> void {
13861412
buffering_visitor* v = this->expressions_.make_buffering_visitor();
@@ -1562,30 +1588,7 @@ expression* parser::parse_object_literal() {
15621588
break;
15631589

15641590
case token_type::equal: {
1565-
expression* lhs;
1566-
bool missing_key;
1567-
switch (key_token.type) {
1568-
case token_type::number:
1569-
case token_type::string:
1570-
lhs = this->make_expression<expression::literal>(key_token.span());
1571-
missing_key = true;
1572-
break;
1573-
default:
1574-
lhs = this->make_expression<expression::variable>(
1575-
key_token.identifier_name(), key_token.type);
1576-
missing_key = false;
1577-
break;
1578-
}
1579-
this->skip();
1580-
expression* rhs = this->parse_expression(precedence{.commas = false});
1581-
expression* value = this->make_expression<expression::assignment>(
1582-
expression_kind::assignment, lhs, rhs);
1583-
if (missing_key) {
1584-
this->error_reporter_->report(error_missing_key_for_object_entry{
1585-
.expression = value->span(),
1586-
});
1587-
}
1588-
entries.emplace_back(key, value);
1591+
parse_equal(key_token, key);
15891592
break;
15901593
}
15911594

@@ -1707,6 +1710,7 @@ expression* parser::parse_object_literal() {
17071710
bool is_async = this->peek().type == token_type::kw_async;
17081711
function_attributes method_attributes =
17091712
is_async ? function_attributes::async : function_attributes::normal;
1713+
token keyword_token = this->peek();
17101714
source_code_span keyword_span = this->peek().span();
17111715
token_type keyword_type = this->peek().type;
17121716
this->skip();
@@ -1771,6 +1775,13 @@ expression* parser::parse_object_literal() {
17711775
break;
17721776
}
17731777

1778+
case token_type::equal: {
1779+
expression* key =
1780+
this->make_expression<expression::literal>(keyword_span);
1781+
parse_equal(keyword_token, key);
1782+
break;
1783+
}
1784+
17741785
// { get: value }
17751786
// { async: value }
17761787
case token_type::colon: {

test/test-parse-var.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,18 @@ TEST(test_parse, variables_can_be_named_contextual_keywords) {
13481348
EXPECT_EQ(v.variable_declarations[0].kind, variable_kind::_let);
13491349
}
13501350

1351+
{
1352+
spy_visitor v =
1353+
parse_and_visit_statement(u8"let {" + name + u8" = 10 } = initial;",
1354+
function_attributes::normal);
1355+
EXPECT_THAT(v.visits,
1356+
ElementsAre("visit_variable_use", // initial
1357+
"visit_variable_declaration")); // (name)
1358+
ASSERT_EQ(v.variable_declarations.size(), 1);
1359+
EXPECT_EQ(v.variable_declarations[0].name, name);
1360+
EXPECT_EQ(v.variable_declarations[0].kind, variable_kind::_let);
1361+
}
1362+
13511363
{
13521364
spy_visitor v = parse_and_visit_statement(
13531365
u8"const " + name + u8" = initial;", function_attributes::normal);

0 commit comments

Comments
 (0)