Skip to content

Commit e865d45

Browse files
ohno418Veykril
authored andcommitted
fix: Recover from missing argument in call expressions
Previously, when parsing an argument list with a missing argument (e.g., `(a, , b)` in `foo(a, , b)`), the parser would stop upon an unexpected token (at the second comma in the example), resulting in an incorrect parse tree. This commit improves error handling in such cases, ensuring a more accurate parse tree is built.
1 parent bcc8a09 commit e865d45

File tree

4 files changed

+53
-22
lines changed

4 files changed

+53
-22
lines changed

crates/hir-expand/src/fixup.rs

-14
Original file line numberDiff line numberDiff line change
@@ -631,20 +631,6 @@ fn foo () {a . b ; bar () ;}
631631
)
632632
}
633633

634-
#[test]
635-
fn extraneous_comma() {
636-
check(
637-
r#"
638-
fn foo() {
639-
bar(,);
640-
}
641-
"#,
642-
expect![[r#"
643-
fn foo () {__ra_fixup ;}
644-
"#]],
645-
)
646-
}
647-
648634
#[test]
649635
fn fixup_if_1() {
650636
check(

crates/parser/src/grammar/expressions.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
611611
// foo(bar::);
612612
// foo(bar:);
613613
// foo(bar+);
614+
// foo(a, , b);
614615
// }
615616
fn arg_list(p: &mut Parser<'_>) {
616617
assert!(p.at(T!['(']));
@@ -619,14 +620,30 @@ fn arg_list(p: &mut Parser<'_>) {
619620
// fn main() {
620621
// foo(#[attr] 92)
621622
// }
622-
delimited(
623-
p,
624-
T!['('],
625-
T![')'],
626-
T![,],
627-
EXPR_FIRST.union(ATTRIBUTE_FIRST),
628-
|p: &mut Parser<'_>| expr(p).is_some(),
629-
);
623+
p.bump(T!['(']);
624+
while !p.at(T![')']) && !p.at(EOF) {
625+
if p.at(T![,]) {
626+
// Recover if an argument is missing and only got a delimiter,
627+
// e.g. `(a, , b)`.
628+
p.error("expected expression");
629+
p.bump(T![,]);
630+
continue;
631+
}
632+
633+
if expr(p).is_none() {
634+
break;
635+
}
636+
if !p.at(T![,]) {
637+
if p.at_ts(EXPR_FIRST.union(ATTRIBUTE_FIRST)) {
638+
p.error(format!("expected {:?}", T![,]));
639+
} else {
640+
break;
641+
}
642+
} else {
643+
p.bump(T![,]);
644+
}
645+
}
646+
p.expect(T![')']);
630647
m.complete(p, ARG_LIST);
631648
}
632649

crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast

+27
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,37 @@ SOURCE_FILE
6868
PLUS "+"
6969
R_PAREN ")"
7070
SEMICOLON ";"
71+
WHITESPACE "\n "
72+
EXPR_STMT
73+
CALL_EXPR
74+
PATH_EXPR
75+
PATH
76+
PATH_SEGMENT
77+
NAME_REF
78+
IDENT "foo"
79+
ARG_LIST
80+
L_PAREN "("
81+
PATH_EXPR
82+
PATH
83+
PATH_SEGMENT
84+
NAME_REF
85+
IDENT "a"
86+
COMMA ","
87+
WHITESPACE " "
88+
COMMA ","
89+
WHITESPACE " "
90+
PATH_EXPR
91+
PATH
92+
PATH_SEGMENT
93+
NAME_REF
94+
IDENT "b"
95+
R_PAREN ")"
96+
SEMICOLON ";"
7197
WHITESPACE "\n"
7298
R_CURLY "}"
7399
WHITESPACE "\n"
74100
error 25: expected identifier
75101
error 39: expected COMMA
76102
error 39: expected expression
77103
error 55: expected expression
104+
error 68: expected expression

crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ fn main() {
22
foo(bar::);
33
foo(bar:);
44
foo(bar+);
5+
foo(a, , b);
56
}

0 commit comments

Comments
 (0)