diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 6a2a9adce15c..19da297b58cc 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -376,6 +376,16 @@ fn error_block(p: &mut Parser<'_>, message: &str) { m.complete(p, ERROR); } +// test_err top_level_let +// let ref foo: fn() = 1 + 3; +fn error_let_stmt(p: &mut Parser<'_>, message: &str) { + assert!(p.at(T![let])); + let m = p.start(); + p.error(message); + expressions::let_stmt(p, expressions::Semicolon::Optional); + m.complete(p, ERROR); +} + /// The `parser` passed this is required to at least consume one token if it returns `true`. /// If the `parser` returns false, parsing will stop. fn delimited( diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index 8542d6b86b1b..e346ece2f94b 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -59,7 +59,8 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) { attributes::outer_attrs(p); if p.at(T![let]) { - let_stmt(p, m, semicolon); + let_stmt(p, semicolon); + m.complete(p, LET_STMT); return; } @@ -109,54 +110,53 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) { m.complete(p, EXPR_STMT); } } +} - // test let_stmt - // fn f() { let x: i32 = 92; } - fn let_stmt(p: &mut Parser<'_>, m: Marker, with_semi: Semicolon) { - p.bump(T![let]); - patterns::pattern(p); - if p.at(T![:]) { - // test let_stmt_ascription - // fn f() { let x: i32; } - types::ascription(p); - } +// test let_stmt +// fn f() { let x: i32 = 92; } +pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) { + p.bump(T![let]); + patterns::pattern(p); + if p.at(T![:]) { + // test let_stmt_ascription + // fn f() { let x: i32; } + types::ascription(p); + } - let mut expr_after_eq: Option = None; - if p.eat(T![=]) { - // test let_stmt_init - // fn f() { let x = 92; } - expr_after_eq = expressions::expr(p); - } + let mut expr_after_eq: Option = None; + if p.eat(T![=]) { + // test let_stmt_init + // fn f() { let x = 92; } + expr_after_eq = expressions::expr(p); + } - if p.at(T![else]) { - // test_err let_else_right_curly_brace - // fn func() { let Some(_) = {Some(1)} else { panic!("h") };} - if let Some(expr) = expr_after_eq { - if BlockLike::is_blocklike(expr.kind()) { - p.error( - "right curly brace `}` before `else` in a `let...else` statement not allowed", - ) - } + if p.at(T![else]) { + // test_err let_else_right_curly_brace + // fn func() { let Some(_) = {Some(1)} else { panic!("h") };} + if let Some(expr) = expr_after_eq { + if BlockLike::is_blocklike(expr.kind()) { + p.error( + "right curly brace `}` before `else` in a `let...else` statement not allowed", + ) } - - // test let_else - // fn f() { let Some(x) = opt else { return }; } - let m = p.start(); - p.bump(T![else]); - block_expr(p); - m.complete(p, LET_ELSE); } - match with_semi { - Semicolon::Forbidden => (), - Semicolon::Optional => { - p.eat(T![;]); - } - Semicolon::Required => { - p.expect(T![;]); - } + // test let_else + // fn f() { let Some(x) = opt else { return }; } + let m = p.start(); + p.bump(T![else]); + block_expr(p); + m.complete(p, LET_ELSE); + } + + match with_semi { + Semicolon::Forbidden => (), + Semicolon::Optional => { + p.eat(T![;]); + } + Semicolon::Required => { + p.expect(T![;]); } - m.complete(p, LET_STMT); } } diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 4e850b1f74df..34fd3420f1c9 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -79,6 +79,7 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { e.complete(p, ERROR); } EOF | T!['}'] => p.error("expected an item"), + T![let] => error_let_stmt(p, "expected an item"), _ => p.err_and_bump("expected an item"), } } diff --git a/crates/parser/test_data/parser/inline/err/0024_top_level_let.rast b/crates/parser/test_data/parser/inline/err/0024_top_level_let.rast new file mode 100644 index 000000000000..5ddef5f3f03f --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0024_top_level_let.rast @@ -0,0 +1,30 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + REF_KW "ref" + WHITESPACE " " + NAME + IDENT "foo" + COLON ":" + WHITESPACE " " + FN_PTR_TYPE + FN_KW "fn" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + LITERAL + INT_NUMBER "1" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + LITERAL + INT_NUMBER "3" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item diff --git a/crates/parser/test_data/parser/inline/err/0024_top_level_let.rs b/crates/parser/test_data/parser/inline/err/0024_top_level_let.rs new file mode 100644 index 000000000000..3d3e7dd56c71 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0024_top_level_let.rs @@ -0,0 +1 @@ +let ref foo: fn() = 1 + 3;