Skip to content

Commit d1abdc0

Browse files
committed
rustc_parse: improve the error diagnostic for "missing let"
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
1 parent ba284f4 commit d1abdc0

5 files changed

Lines changed: 80 additions & 3 deletions

File tree

compiler/rustc_parse/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,10 @@ parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
534534
parse_left_arrow_operator = unexpected token: `<-`
535535
.suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
536536
537+
parse_let_chain_missing_let = let-chain with missing `let`
538+
.label = expected `let` expression, found assignment
539+
.suggestion = add `let` before the expression
540+
537541
parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later
538542
539543
parse_lifetime_after_mut = lifetime must precede `mut`

compiler/rustc_parse/src/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,17 @@ pub(crate) struct ExpectedExpressionFoundLet {
512512
pub comparison: Option<MaybeComparison>,
513513
}
514514

515+
#[derive(Diagnostic)]
516+
#[diag(parse_let_chain_missing_let)]
517+
pub(crate) struct LetChainMissingLet {
518+
#[primary_span]
519+
pub span: Span,
520+
#[label]
521+
pub label_span: Span,
522+
#[suggestion(applicability = "maybe-incorrect", code = "let ", style = "verbose")]
523+
pub sug_span: Span,
524+
}
525+
515526
#[derive(Diagnostic)]
516527
#[diag(parse_or_in_let_chain)]
517528
pub(crate) struct OrInLetChain {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4245,6 +4245,20 @@ impl<'a> CondChecker<'a> {
42454245
}
42464246
}
42474247

4248+
impl CondChecker<'_> {
4249+
fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4250+
Self::get_path_from_rhs_inner(e, 0)
4251+
}
4252+
4253+
fn get_path_from_rhs_inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4254+
match &e.kind {
4255+
ExprKind::Binary(_, lhs, _) => Self::get_path_from_rhs_inner(lhs, depth + 1),
4256+
ExprKind::Path(_, path) => Some((depth, path)),
4257+
_ => None,
4258+
}
4259+
}
4260+
}
4261+
42484262
impl MutVisitor for CondChecker<'_> {
42494263
fn visit_expr(&mut self, e: &mut Expr) {
42504264
self.depth += 1;
@@ -4304,7 +4318,23 @@ impl MutVisitor for CondChecker<'_> {
43044318
mut_visit::walk_expr(self, e);
43054319
self.forbid_let_reason = forbid_let_reason;
43064320
}
4307-
ExprKind::Assign(ref lhs, _, span) => {
4321+
ExprKind::Assign(ref lhs, ref rhs, span) => {
4322+
if let ExprKind::Call(_, _) = &lhs.kind {
4323+
if let Some((depth, path)) = CondChecker::get_path_from_rhs(rhs) {
4324+
let expr_span = lhs.span.to(path.span);
4325+
4326+
if depth > 0 {
4327+
let guar = self.parser.dcx().emit_err(errors::LetChainMissingLet {
4328+
span: lhs.span,
4329+
label_span: expr_span,
4330+
sug_span: lhs.span.shrink_to_lo(),
4331+
});
4332+
4333+
self.found_incorrect_let_chain = Some(guar);
4334+
}
4335+
}
4336+
}
4337+
43084338
let forbid_let_reason = self.forbid_let_reason;
43094339
self.forbid_let_reason = Some(OtherForbidden);
43104340
let missing_let = self.missing_let;

tests/ui/missing/missing-let.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
fn main() {
22
let x = Some(42);
3+
let y = Some(42);
4+
let z = Some(42);
35
if let Some(_) = x
46
&& Some(x) = x //~^ ERROR expected expression, found `let` statement
7+
//~| NOTE: only supported directly in conditions of `if` and `while` expressions
8+
{}
9+
10+
if Some(_) = y &&
11+
//~^ NOTE expected `let` expression, found assignment
12+
//~| ERROR let-chain with missing `let`
13+
let Some(_) = z
14+
//~^ ERROR: expected expression, found `let` statement
15+
//~| NOTE: only supported directly in conditions of `if` and `while` expressions
516
{}
617
}

tests/ui/missing/missing-let.stderr

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: expected expression, found `let` statement
2-
--> $DIR/missing-let.rs:3:8
2+
--> $DIR/missing-let.rs:5:8
33
|
44
LL | if let Some(_) = x
55
| ^^^^^^^^^^^^^^^
@@ -14,5 +14,26 @@ help: you might have meant to compare for equality
1414
LL | && Some(x) == x
1515
| +
1616

17-
error: aborting due to 1 previous error
17+
error: expected expression, found `let` statement
18+
--> $DIR/missing-let.rs:13:9
19+
|
20+
LL | let Some(_) = z
21+
| ^^^
22+
|
23+
= note: only supported directly in conditions of `if` and `while` expressions
24+
25+
error: let-chain with missing `let`
26+
--> $DIR/missing-let.rs:10:8
27+
|
28+
LL | if Some(_) = y &&
29+
| ^^^^^^^----
30+
| |
31+
| expected `let` expression, found assignment
32+
|
33+
help: add `let` before the expression
34+
|
35+
LL | if let Some(_) = y &&
36+
| +++
37+
38+
error: aborting due to 3 previous errors
1839

0 commit comments

Comments
 (0)