mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Auto merge of #15961 - ohno418:top-level-let-stmt, r=Veykril
Improve error handling for top-level `let` statements This commit addresses the issue of excessive and unrelated errors generated by top-level `let` statements. Now, only a single error is produced, indicating that `let` statements are invalid at the top level. --- Fixes https://github.com/rust-lang/rust-analyzer/issues/14963. While I'm not really sure if handling a particular case in a special manner is appropriate, it would be good to suppress the excessive number of annoying and unrelated errors.
This commit is contained in:
commit
57e90240a5
@ -376,6 +376,16 @@ fn error_block(p: &mut Parser<'_>, message: &str) {
|
|||||||
m.complete(p, ERROR);
|
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`.
|
/// The `parser` passed this is required to at least consume one token if it returns `true`.
|
||||||
/// If the `parser` returns false, parsing will stop.
|
/// If the `parser` returns false, parsing will stop.
|
||||||
fn delimited(
|
fn delimited(
|
||||||
|
@ -59,7 +59,8 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
|
|||||||
attributes::outer_attrs(p);
|
attributes::outer_attrs(p);
|
||||||
|
|
||||||
if p.at(T![let]) {
|
if p.at(T![let]) {
|
||||||
let_stmt(p, m, semicolon);
|
let_stmt(p, semicolon);
|
||||||
|
m.complete(p, LET_STMT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,54 +110,53 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
|
|||||||
m.complete(p, EXPR_STMT);
|
m.complete(p, EXPR_STMT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test let_stmt
|
// test let_stmt
|
||||||
// fn f() { let x: i32 = 92; }
|
// fn f() { let x: i32 = 92; }
|
||||||
fn let_stmt(p: &mut Parser<'_>, m: Marker, with_semi: Semicolon) {
|
pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
|
||||||
p.bump(T![let]);
|
p.bump(T![let]);
|
||||||
patterns::pattern(p);
|
patterns::pattern(p);
|
||||||
if p.at(T![:]) {
|
if p.at(T![:]) {
|
||||||
// test let_stmt_ascription
|
// test let_stmt_ascription
|
||||||
// fn f() { let x: i32; }
|
// fn f() { let x: i32; }
|
||||||
types::ascription(p);
|
types::ascription(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expr_after_eq: Option<CompletedMarker> = None;
|
let mut expr_after_eq: Option<CompletedMarker> = None;
|
||||||
if p.eat(T![=]) {
|
if p.eat(T![=]) {
|
||||||
// test let_stmt_init
|
// test let_stmt_init
|
||||||
// fn f() { let x = 92; }
|
// fn f() { let x = 92; }
|
||||||
expr_after_eq = expressions::expr(p);
|
expr_after_eq = expressions::expr(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.at(T![else]) {
|
if p.at(T![else]) {
|
||||||
// test_err let_else_right_curly_brace
|
// test_err let_else_right_curly_brace
|
||||||
// fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
|
// fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
|
||||||
if let Some(expr) = expr_after_eq {
|
if let Some(expr) = expr_after_eq {
|
||||||
if BlockLike::is_blocklike(expr.kind()) {
|
if BlockLike::is_blocklike(expr.kind()) {
|
||||||
p.error(
|
p.error(
|
||||||
"right curly brace `}` before `else` in a `let...else` statement not allowed",
|
"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![;]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.complete(p, LET_STMT);
|
|
||||||
|
// 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![;]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) {
|
|||||||
e.complete(p, ERROR);
|
e.complete(p, ERROR);
|
||||||
}
|
}
|
||||||
EOF | T!['}'] => p.error("expected an item"),
|
EOF | T!['}'] => p.error("expected an item"),
|
||||||
|
T![let] => error_let_stmt(p, "expected an item"),
|
||||||
_ => p.err_and_bump("expected an item"),
|
_ => p.err_and_bump("expected an item"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
let ref foo: fn() = 1 + 3;
|
Loading…
x
Reference in New Issue
Block a user