Auto merge of #16885 - Veykril:match-recovery, r=Veykril

fix: Improve error recovery for match arms

This should make use of the recovery token sets, but I think it'd be better to fix that as a whole while fixing the other places for these adhoc recovery checks.
This commit is contained in:
bors 2024-03-19 09:58:31 +00:00
commit 054ebf9482
3 changed files with 164 additions and 16 deletions

View File

@ -490,6 +490,18 @@ fn match_expr(p: &mut Parser<'_>) -> CompletedMarker {
m.complete(p, MATCH_EXPR)
}
// test_err match_arms_recovery
// fn foo() {
// match () {
// _ => (),,
// _ => ,
// _ => (),
// => (),
// if true => (),
// _ => (),
// () if => (),
// }
// }
pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
assert!(p.at(T!['{']));
let m = p.start();
@ -511,6 +523,10 @@ pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
error_block(p, "expected match arm");
continue;
}
if p.at(T![,]) {
p.err_and_bump("expected pattern");
continue;
}
match_arm(p);
}
p.expect(T!['}']);
@ -544,26 +560,30 @@ fn match_arm(p: &mut Parser<'_>) {
// }
attributes::outer_attrs(p);
patterns::pattern_top_r(p, TokenSet::EMPTY);
patterns::pattern_top_r(p, TokenSet::new(&[T![=], T![if]]));
if p.at(T![if]) {
match_guard(p);
}
p.expect(T![=>]);
let blocklike = match expr_stmt(p, None) {
Some((_, blocklike)) => blocklike,
None => BlockLike::NotBlock,
};
if p.eat(T![,]) {
p.error("expected expression");
} else {
let blocklike = match expr_stmt(p, None) {
Some((_, blocklike)) => blocklike,
None => BlockLike::NotBlock,
};
// test match_arms_commas
// fn foo() {
// match () {
// _ => (),
// _ => {}
// _ => ()
// }
// }
if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
p.error("expected `,`");
// test match_arms_commas
// fn foo() {
// match () {
// _ => (),
// _ => {}
// _ => ()
// }
// }
if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
p.error("expected `,`");
}
}
m.complete(p, MATCH_ARM);
}
@ -579,7 +599,11 @@ fn match_guard(p: &mut Parser<'_>) -> CompletedMarker {
assert!(p.at(T![if]));
let m = p.start();
p.bump(T![if]);
expr(p);
if p.at(T![=]) {
p.error("expected expression");
} else {
expr(p);
}
m.complete(p, MATCH_GUARD)
}

View File

@ -0,0 +1,113 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
WHITESPACE "\n "
MATCH_EXPR
MATCH_KW "match"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE "\n "
MATCH_ARM
WILDCARD_PAT
UNDERSCORE "_"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
ERROR
COMMA ","
WHITESPACE "\n "
MATCH_ARM
WILDCARD_PAT
UNDERSCORE "_"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
COMMA ","
WHITESPACE "\n "
MATCH_ARM
WILDCARD_PAT
UNDERSCORE "_"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
MATCH_ARM
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
MATCH_ARM
MATCH_GUARD
IF_KW "if"
WHITESPACE " "
LITERAL
TRUE_KW "true"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
MATCH_ARM
WILDCARD_PAT
UNDERSCORE "_"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
MATCH_ARM
TUPLE_PAT
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
MATCH_GUARD
IF_KW "if"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
R_CURLY "}"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
error 42: expected pattern
error 58: expected expression
error 85: expected pattern
error 100: expected pattern
error 145: expected expression

View File

@ -0,0 +1,11 @@
fn foo() {
match () {
_ => (),,
_ => ,
_ => (),
=> (),
if true => (),
_ => (),
() if => (),
}
}