fix: Improve parser recovery a bit

This commit is contained in:
Lukas Wirth 2025-04-30 15:51:58 +02:00
parent 62e7e2b489
commit e0dca847ad
15 changed files with 86 additions and 20 deletions

View file

@ -285,8 +285,6 @@ fn main() {
/* parse error: expected expression */ /* parse error: expected expression */
builtin #format_args (x = ); builtin #format_args (x = );
/* parse error: expected expression */ /* parse error: expected expression */
/* parse error: expected R_PAREN */
/* parse error: expected expression, item or let statement */
builtin #format_args (x = , x = 2); builtin #format_args (x = , x = 2);
/* parse error: expected expression */ /* parse error: expected expression */
builtin #format_args ("{}", x = ); builtin #format_args ("{}", x = );

View file

@ -661,9 +661,8 @@ fn expected_type_and_name(
)) ))
} else { } else {
cov_mark::hit!(expected_type_struct_field_without_leading_char); cov_mark::hit!(expected_type_struct_field_without_leading_char);
let expr_field = token.prev_sibling_or_token()? cov_mark::hit!(expected_type_struct_field_followed_by_comma);
.into_node() let expr_field = previous_non_trivia_token(token.clone())?.parent().and_then(ast::RecordExprField::cast)?;
.and_then(ast::RecordExprField::cast)?;
let (_, _, ty) = sema.resolve_record_field(&expr_field)?; let (_, _, ty) = sema.resolve_record_field(&expr_field)?;
Some(( Some((
Some(ty), Some(ty),
@ -681,7 +680,6 @@ fn expected_type_and_name(
.or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original)); .or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original));
(ty, field_name) (ty, field_name)
} else { } else {
cov_mark::hit!(expected_type_struct_field_followed_by_comma);
(field_ty, field_name) (field_ty, field_name)
} }
}, },

View file

@ -4,7 +4,7 @@ use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*; use super::*;
pub(super) use atom::{LITERAL_FIRST, literal}; pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal};
pub(crate) use atom::{block_expr, match_arm_list}; pub(crate) use atom::{block_expr, match_arm_list};
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]

View file

@ -46,7 +46,6 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
T!['['], T!['['],
T![|], T![|],
T![async], T![async],
T![box],
T![break], T![break],
T![const], T![const],
T![continue], T![continue],
@ -68,7 +67,8 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
LIFETIME_IDENT, LIFETIME_IDENT,
])); ]));
pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]); pub(in crate::grammar) const EXPR_RECOVERY_SET: TokenSet =
TokenSet::new(&[T!['}'], T![')'], T![']'], T![,]]);
pub(super) fn atom_expr( pub(super) fn atom_expr(
p: &mut Parser<'_>, p: &mut Parser<'_>,

View file

@ -32,6 +32,9 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![impl], T![impl],
T![trait], T![trait],
T![const], T![const],
T![async],
T![unsafe],
T![extern],
T![static], T![static],
T![let], T![let],
T![mod], T![mod],

View file

@ -81,7 +81,7 @@ fn path_for_qualifier(
} }
const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet =
items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); expressions::EXPR_RECOVERY_SET.union(items::ITEM_RECOVERY_SET);
const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET;
fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<CompletedMarker> { fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<CompletedMarker> {

View file

@ -199,8 +199,19 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
} }
} }
const PAT_RECOVERY_SET: TokenSet = const PAT_RECOVERY_SET: TokenSet = TokenSet::new(&[
TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]); T![let],
T![if],
T![while],
T![loop],
T![match],
T![')'],
T![']'],
T!['}'],
T![,],
T![=],
T![&],
]);
fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option<CompletedMarker> { fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option<CompletedMarker> {
let m = match p.current() { let m = match p.current() {

View file

@ -20,10 +20,15 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[ pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![')'], T![')'],
// test_err type_in_array_recover
// const _: [&];
T![']'],
T!['}'],
T![>], T![>],
T![,], T![,],
// test_err struct_field_recover // test_err struct_field_recover
// struct S { f pub g: () } // struct S { f pub g: () }
// struct S { f: pub g: () }
T![pub], T![pub],
]); ]);

View file

@ -870,6 +870,10 @@ mod err {
run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs"); run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs");
} }
#[test] #[test]
fn type_in_array_recover() {
run_and_expect_errors("test_data/parser/inline/err/type_in_array_recover.rs");
}
#[test]
fn unsafe_block_in_mod() { fn unsafe_block_in_mod() {
run_and_expect_errors("test_data/parser/inline/err/unsafe_block_in_mod.rs"); run_and_expect_errors("test_data/parser/inline/err/unsafe_block_in_mod.rs");
} }

View file

@ -149,7 +149,8 @@ error 17: expected expression, item or let statement
error 25: expected a name error 25: expected a name
error 26: expected `;`, `{`, or `(` error 26: expected `;`, `{`, or `(`
error 30: expected pattern error 30: expected pattern
error 31: expected SEMICOLON error 30: expected SEMICOLON
error 30: expected expression, item or let statement
error 53: expected expression error 53: expected expression
error 54: expected R_PAREN error 54: expected R_PAREN
error 54: expected SEMICOLON error 54: expected SEMICOLON

View file

@ -23,7 +23,6 @@ SOURCE_FILE
L_CURLY "{" L_CURLY "{"
WHITESPACE " " WHITESPACE " "
DOT2 ".." DOT2 ".."
ERROR
COMMA "," COMMA ","
WHITESPACE " " WHITESPACE " "
R_CURLY "}" R_CURLY "}"
@ -39,7 +38,6 @@ SOURCE_FILE
L_CURLY "{" L_CURLY "{"
WHITESPACE " " WHITESPACE " "
DOT2 ".." DOT2 ".."
ERROR
COMMA "," COMMA ","
WHITESPACE " " WHITESPACE " "
RECORD_EXPR_FIELD RECORD_EXPR_FIELD
@ -55,5 +53,6 @@ SOURCE_FILE
R_CURLY "}" R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"
error 21: expected expression error 21: expected expression
error 21: cannot use a comma after the base struct
error 36: expected expression error 36: expected expression
error 37: expected COMMA error 36: cannot use a comma after the base struct

View file

@ -26,6 +26,36 @@ SOURCE_FILE
WHITESPACE " " WHITESPACE " "
R_CURLY "}" R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"
STRUCT
STRUCT_KW "struct"
WHITESPACE " "
NAME
IDENT "S"
WHITESPACE " "
RECORD_FIELD_LIST
L_CURLY "{"
WHITESPACE " "
RECORD_FIELD
NAME
IDENT "f"
COLON ":"
WHITESPACE " "
RECORD_FIELD
VISIBILITY
PUB_KW "pub"
WHITESPACE " "
NAME
IDENT "g"
COLON ":"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
error 12: expected COLON error 12: expected COLON
error 12: expected type error 12: expected type
error 12: expected COMMA error 12: expected COMMA
error 38: expected type
error 38: expected COMMA

View file

@ -1 +1,2 @@
struct S { f pub g: () } struct S { f pub g: () }
struct S { f: pub g: () }

View file

@ -0,0 +1,15 @@
SOURCE_FILE
CONST
CONST_KW "const"
WHITESPACE " "
UNDERSCORE "_"
COLON ":"
WHITESPACE " "
SLICE_TYPE
L_BRACK "["
REF_TYPE
AMP "&"
R_BRACK "]"
SEMICOLON ";"
WHITESPACE "\n"
error 11: expected type

View file

@ -0,0 +1 @@
const _: [&];