Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--Cargo.lock1
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe.rs2
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs2
-rw-r--r--crates/parser/Cargo.toml1
-rw-r--r--crates/parser/src/grammar/expressions.rs29
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs28
-rw-r--r--crates/parser/src/grammar/paths.rs11
-rw-r--r--crates/parser/src/grammar/types.rs3
-rw-r--r--crates/parser/src/tests.rs6
-rw-r--r--crates/parser/src/tests/top_entries.rs2
-rw-r--r--crates/parser/test_data/parser/err/0022_bad_exprs.rast16
-rw-r--r--crates/parser/test_data/parser/err/0024_many_type_parens.rast196
-rw-r--r--crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast77
-rw-r--r--crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs5
14 files changed, 247 insertions, 132 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ef0316f30f..c3800f09b4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1173,6 +1173,7 @@ dependencies = [
"limit",
"rustc-ap-rustc_lexer",
"sourcegen",
+ "stdx",
]
[[package]]
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 49bbc64bff..7a3e8c3b05 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -1476,7 +1476,7 @@ macro_rules! m {
/* parse error: expected identifier */
/* parse error: expected SEMICOLON */
/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
+/* parse error: expected expression, item or let statement */
fn f() {
K::(C("0"));
}
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index d2505e7caf..910917ac68 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -831,7 +831,7 @@ macro_rules! rgb_color {
/* parse error: expected R_ANGLE */
/* parse error: expected SEMICOLON */
/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
+/* parse error: expected expression, item or let statement */
pub fn new() {
let _ = 0as u32<<(8+8);
}
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 08359133f1..6e962abd75 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -20,4 +20,5 @@ limit.workspace = true
[dev-dependencies]
expect-test = "1.4.0"
+stdx.workspace = true
sourcegen.workspace = true
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 7516ac3c4b..4d6097b5ab 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -68,6 +68,12 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
Err(m) => m,
};
+ if !p.at_ts(EXPR_FIRST) {
+ p.err_and_bump("expected expression, item or let statement");
+ m.abandon(p);
+ return;
+ }
+
if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
// test no_semi_after_block
@@ -227,6 +233,12 @@ fn expr_bp(
attributes::outer_attrs(p);
m
});
+
+ if !p.at_ts(EXPR_FIRST) {
+ p.err_recover("expected expression", atom::EXPR_RECOVERY_SET);
+ m.abandon(p);
+ return None;
+ }
let mut lhs = match lhs(p, r) {
Some((lhs, blocklike)) => {
let lhs = lhs.extend_to(p, m);
@@ -551,6 +563,12 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
m.complete(p, CAST_EXPR)
}
+// test_err arg_list_recovery
+// fn main() {
+// foo(bar::);
+// foo(bar:);
+// foo(bar+);
+// }
fn arg_list(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
let m = p.start();
@@ -563,8 +581,15 @@ fn arg_list(p: &mut Parser<'_>) {
if !expr(p) {
break;
}
- if !p.at(T![')']) && !p.expect(T![,]) {
- break;
+ if !p.at(T![,]) {
+ if p.at_ts(EXPR_FIRST) {
+ p.error("expected `,`");
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ p.bump(T![,]);
}
}
p.eat(T![')']);
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index a23f900b73..c3c5d474cb 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -40,26 +40,28 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
T!['{'],
T!['['],
T![|],
- T![move],
+ T![async],
T![box],
+ T![break],
+ T![const],
+ T![continue],
+ T![do],
+ T![for],
T![if],
- T![while],
+ T![let],
+ T![loop],
T![match],
- T![unsafe],
+ T![move],
T![return],
- T![yield],
- T![do],
- T![break],
- T![continue],
- T![async],
+ T![static],
T![try],
- T![const],
- T![loop],
- T![for],
+ T![unsafe],
+ T![while],
+ T![yield],
LIFETIME_IDENT,
]));
-const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]);
+pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]);
pub(super) fn atom_expr(
p: &mut Parser<'_>,
@@ -157,7 +159,7 @@ pub(super) fn atom_expr(
T![for] => for_expr(p, None),
_ => {
- p.err_recover("expected expression", EXPR_RECOVERY_SET);
+ p.err_and_bump("expected expression");
return None;
}
};
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index af3b6f63cf..1064ae9970 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -67,6 +67,10 @@ fn path_for_qualifier(
}
}
+const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet =
+ items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]]));
+const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET;
+
fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
let m = p.start();
// test qual_paths
@@ -102,7 +106,12 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
m.complete(p, NAME_REF);
}
_ => {
- p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
+ let recover_set = match mode {
+ Mode::Use => items::ITEM_RECOVERY_SET,
+ Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET,
+ Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET,
+ };
+ p.err_recover("expected identifier", recover_set);
if empty {
// test_err empty_segment
// use crate::;
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 5c6e18fee8..7d0b156c5a 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -17,8 +17,9 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
T![Self],
]));
-const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
+pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![')'],
+ T![>],
T![,],
// test_err struct_field_recover
// struct S { f pub g: () }
diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs
index c1b4e9a7d8..2fec765bd7 100644
--- a/crates/parser/src/tests.rs
+++ b/crates/parser/src/tests.rs
@@ -15,6 +15,7 @@ use crate::{LexedStr, TopEntryPoint};
#[test]
fn lex_ok() {
for case in TestCase::list("lexer/ok") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
}
@@ -23,6 +24,7 @@ fn lex_ok() {
#[test]
fn lex_err() {
for case in TestCase::list("lexer/err") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
}
@@ -46,6 +48,7 @@ fn lex(text: &str) -> String {
#[test]
fn parse_ok() {
for case in TestCase::list("parser/ok") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
@@ -55,6 +58,7 @@ fn parse_ok() {
#[test]
fn parse_inline_ok() {
for case in TestCase::list("parser/inline/ok") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
@@ -64,6 +68,7 @@ fn parse_inline_ok() {
#[test]
fn parse_err() {
for case in TestCase::list("parser/err") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
@@ -73,6 +78,7 @@ fn parse_err() {
#[test]
fn parse_inline_err() {
for case in TestCase::list("parser/inline/err") {
+ let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs
index eb640dc7fc..49dd9e293b 100644
--- a/crates/parser/src/tests/top_entries.rs
+++ b/crates/parser/src/tests/top_entries.rs
@@ -65,7 +65,7 @@ fn macro_stmt() {
MACRO_STMTS
ERROR
SHEBANG "#!/usr/bin/rust"
- error 0: expected expression
+ error 0: expected expression, item or let statement
"##]],
);
check(
diff --git a/crates/parser/test_data/parser/err/0022_bad_exprs.rast b/crates/parser/test_data/parser/err/0022_bad_exprs.rast
index 900394bd96..36a025dc0a 100644
--- a/crates/parser/test_data/parser/err/0022_bad_exprs.rast
+++ b/crates/parser/test_data/parser/err/0022_bad_exprs.rast
@@ -145,27 +145,27 @@ SOURCE_FILE
error 16: expected expression
error 17: expected R_BRACK
error 17: expected SEMICOLON
-error 17: expected expression
+error 17: expected expression, item or let statement
error 25: expected a name
error 26: expected `;`, `{`, or `(`
error 30: expected pattern
error 31: expected SEMICOLON
error 53: expected expression
error 54: expected SEMICOLON
-error 54: expected expression
+error 54: expected expression, item or let statement
error 60: expected type
error 60: expected `{`
-error 60: expected expression
+error 60: expected expression, item or let statement
error 65: expected pattern
error 65: expected SEMICOLON
-error 65: expected expression
+error 65: expected expression, item or let statement
error 92: expected expression
error 93: expected SEMICOLON
-error 93: expected expression
-error 95: expected expression
-error 96: expected expression
+error 93: expected expression, item or let statement
+error 95: expected expression, item or let statement
+error 96: expected expression, item or let statement
error 103: expected a name
error 104: expected `{`
error 108: expected pattern
error 108: expected SEMICOLON
-error 108: expected expression
+error 108: expected expression, item or let statement
diff --git a/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/crates/parser/test_data/parser/err/0024_many_type_parens.rast
index d374f86610..a2cf225af8 100644
--- a/crates/parser/test_data/parser/err/0024_many_type_parens.rast
+++ b/crates/parser/test_data/parser/err/0024_many_type_parens.rast
@@ -180,63 +180,9 @@ SOURCE_FILE
ERROR
PLUS "+"
WHITESPACE " "
- TUPLE_EXPR
- L_PAREN "("
- CLOSURE_EXPR
- FOR_KW "for"
- GENERIC_PARAM_LIST
- L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- WHITESPACE " "
- BIN_EXPR
- BIN_EXPR
- BIN_EXPR
- BIN_EXPR
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Trait"
- L_ANGLE "<"
- ERROR
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- ERROR
- R_PAREN ")"
- WHITESPACE " "
- PLUS "+"
- WHITESPACE " "
- PAREN_EXPR
- L_PAREN "("
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Copy"
- R_PAREN ")"
- R_ANGLE ">"
- ERROR
- SEMICOLON ";"
- WHITESPACE "\n "
- LET_EXPR
- LET_KW "let"
- WHITESPACE " "
- WILDCARD_PAT
- UNDERSCORE "_"
- ERROR
- COLON ":"
- WHITESPACE " "
+ EXPR_STMT
BIN_EXPR
BIN_EXPR
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Box"
- L_ANGLE "<"
TUPLE_EXPR
L_PAREN "("
CLOSURE_EXPR
@@ -250,78 +196,120 @@ SOURCE_FILE
WHITESPACE " "
BIN_EXPR
BIN_EXPR
- BIN_EXPR
- BIN_EXPR
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Trait"
- L_ANGLE "<"
- ERROR
- LIFETIME_IDENT "'a"
- R_ANGLE ">"
- ERROR
- R_PAREN ")"
- WHITESPACE " "
- PLUS "+"
- WHITESPACE " "
- PAREN_EXPR
- L_PAREN "("
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "Copy"
- R_PAREN ")"
- WHITESPACE " "
- PLUS "+"
- WHITESPACE " "
- PAREN_EXPR
- L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ L_ANGLE "<"
ERROR
- QUESTION "?"
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
- IDENT "Sized"
+ IDENT "Copy"
R_PAREN ")"
R_ANGLE ">"
ERROR
SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ DYN_TRAIT_TYPE
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PAREN_TYPE
+ L_PAREN "("
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ QUESTION "?"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ R_PAREN ")"
+ ERROR
+ R_ANGLE ">"
+ SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
error 88: expected COMMA
error 88: expected R_ANGLE
error 121: expected SEMICOLON
-error 121: expected expression
+error 121: expected expression, item or let statement
error 140: expected type
error 141: expected R_PAREN
error 141: expected COMMA
error 141: expected R_ANGLE
error 141: expected SEMICOLON
error 146: expected SEMICOLON
-error 146: expected expression
-error 148: expected expression
+error 146: expected expression, item or let statement
+error 148: expected expression, item or let statement
error 158: expected `|`
error 158: expected COMMA
error 165: expected expression
error 168: expected expression
error 179: expected expression
-error 180: expected COMMA
-error 190: expected EQ
-error 190: expected expression
-error 191: expected COMMA
-error 204: expected `|`
-error 204: expected COMMA
-error 211: expected expression
-error 214: expected expression
-error 228: expected expression
-error 229: expected R_PAREN
-error 229: expected COMMA
-error 236: expected expression
-error 237: expected COMMA
-error 237: expected expression
-error 237: expected R_PAREN
+error 180: expected SEMICOLON
+error 215: expected COMMA
+error 215: expected R_ANGLE
+error 235: expected SEMICOLON
+error 235: expected expression, item or let statement
diff --git a/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast b/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast
new file mode 100644
index 0000000000..6e065f8f80
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast
@@ -0,0 +1,77 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ COLON2 "::"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ ERROR
+ COLON ":"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ PLUS "+"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 25: expected identifier
+error 39: expected `,`
+error 39: expected expression
+error 55: expected expression
diff --git a/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs b/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs
new file mode 100644
index 0000000000..0e7ac9cc30
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs
@@ -0,0 +1,5 @@
+fn main() {
+ foo(bar::);
+ foo(bar:);
+ foo(bar+);
+}