Skip to content

Commit d2a30be

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

5 files changed

Lines changed: 88 additions & 3 deletions

File tree

compiler/rustc_parse/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,11 @@ 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+
.rhs_label = let expression later in the condition
540+
.suggestion = add `let` before the expression
541+
537542
parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later
538543
539544
parse_lifetime_after_mut = lifetime must precede `mut`

compiler/rustc_parse/src/errors.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,19 @@ 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+
#[label(parse_rhs_label)]
523+
pub rhs_span: Span,
524+
#[suggestion(applicability = "maybe-incorrect", code = "let ", style = "verbose")]
525+
pub sug_span: Span,
526+
}
527+
515528
#[derive(Diagnostic)]
516529
#[diag(parse_or_in_let_chain)]
517530
pub(crate) struct OrInLetChain {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4304,7 +4304,38 @@ impl MutVisitor for CondChecker<'_> {
43044304
mut_visit::walk_expr(self, e);
43054305
self.forbid_let_reason = forbid_let_reason;
43064306
}
4307-
ExprKind::Assign(ref lhs, _, span) => {
4307+
ExprKind::Assign(ref lhs, ref rhs, span) => {
4308+
if let ExprKind::Call(_, _) = &lhs.kind {
4309+
fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4310+
fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4311+
match &e.kind {
4312+
ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4313+
ExprKind::Path(_, path) => Some((depth, path)),
4314+
_ => None,
4315+
}
4316+
}
4317+
4318+
inner(e, 0)
4319+
}
4320+
4321+
if let Some((depth, path)) = get_path_from_rhs(rhs)
4322+
&& let ExprKind::Binary(_, _, later_rhs) = &rhs.kind
4323+
{
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+
rhs_span: later_rhs.span,
4331+
sug_span: lhs.span.shrink_to_lo(),
4332+
});
4333+
4334+
self.found_incorrect_let_chain = Some(guar);
4335+
}
4336+
}
4337+
}
4338+
43084339
let forbid_let_reason = self.forbid_let_reason;
43094340
self.forbid_let_reason = Some(OtherForbidden);
43104341
let missing_let = self.missing_let;

tests/ui/missing/missing-let.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
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: let expression later in the condition
16+
//~| NOTE: only supported directly in conditions of `if` and `while` expressions
517
{}
618
}

tests/ui/missing/missing-let.stderr

Lines changed: 26 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,29 @@ 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+
LL | let Some(_) = z
34+
| --------------- let expression later in the condition
35+
|
36+
help: add `let` before the expression
37+
|
38+
LL | if let Some(_) = y &&
39+
| +++
40+
41+
error: aborting due to 3 previous errors
1842

0 commit comments

Comments
 (0)