Skip to content

Commit f1467c2

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

10 files changed

Lines changed: 318 additions & 626 deletions

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,9 +2760,13 @@ impl<'a> Parser<'a> {
27602760
let (mut cond, _) =
27612761
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
27622762

2763-
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
2764-
2765-
Ok(cond)
2763+
let mut checker = CondChecker::new(self, let_chains_policy);
2764+
checker.visit_expr(&mut cond);
2765+
Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2766+
self.mk_expr_err(cond.span, guar)
2767+
} else {
2768+
cond
2769+
})
27662770
}
27672771

27682772
/// Parses a `let $pat = $expr` pseudo-expression.
@@ -3484,13 +3488,19 @@ impl<'a> Parser<'a> {
34843488
let if_span = self.prev_token.span;
34853489
let mut cond = self.parse_match_guard_condition()?;
34863490

3487-
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3491+
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3492+
checker.visit_expr(&mut cond);
34883493

34893494
if has_let_expr(&cond) {
34903495
let span = if_span.to(cond.span);
34913496
self.psess.gated_spans.gate(sym::if_let_guard, span);
34923497
}
3493-
Ok(Some(cond))
3498+
3499+
Ok(Some(if let Some(guar) = checker.found_incorrect_let_chain {
3500+
self.mk_expr_err(cond.span, guar)
3501+
} else {
3502+
cond
3503+
}))
34943504
}
34953505

34963506
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
@@ -3511,13 +3521,23 @@ impl<'a> Parser<'a> {
35113521
let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
35123522
let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
35133523
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
3514-
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3524+
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3525+
checker.visit_expr(&mut cond);
3526+
35153527
let right = self.prev_token.span;
35163528
self.dcx().emit_err(errors::ParenthesesInMatchPat {
35173529
span: vec![left, right],
35183530
sugg: errors::ParenthesesInMatchPatSugg { left, right },
35193531
});
3520-
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
3532+
3533+
Ok((
3534+
self.mk_pat(span, ast::PatKind::Wild),
3535+
(if let Some(guar) = checker.found_incorrect_let_chain {
3536+
Some(self.mk_expr_err(cond.span, guar))
3537+
} else {
3538+
Some(cond)
3539+
}),
3540+
))
35213541
} else {
35223542
Ok((pat, self.parse_match_arm_guard()?))
35233543
}
@@ -4208,6 +4228,7 @@ struct CondChecker<'a> {
42084228
forbid_let_reason: Option<ForbiddenLetReason>,
42094229
missing_let: Option<errors::MaybeMissingLet>,
42104230
comparison: Option<errors::MaybeComparison>,
4231+
found_incorrect_let_chain: Option<ErrorGuaranteed>,
42114232
}
42124233

42134234
impl<'a> CondChecker<'a> {
@@ -4218,6 +4239,7 @@ impl<'a> CondChecker<'a> {
42184239
missing_let: None,
42194240
comparison: None,
42204241
let_chains_policy,
4242+
found_incorrect_let_chain: None,
42214243
depth: 0,
42224244
}
42234245
}
@@ -4236,12 +4258,17 @@ impl MutVisitor for CondChecker<'_> {
42364258
NotSupportedOr(or_span) => {
42374259
self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
42384260
}
4239-
_ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
4240-
span,
4241-
reason,
4242-
missing_let: self.missing_let,
4243-
comparison: self.comparison,
4244-
}),
4261+
_ => {
4262+
let guar =
4263+
self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
4264+
span,
4265+
reason,
4266+
missing_let: self.missing_let,
4267+
comparison: self.comparison,
4268+
});
4269+
self.found_incorrect_let_chain = Some(guar);
4270+
guar
4271+
}
42454272
};
42464273
*recovered = Recovered::Yes(error);
42474274
} else if self.depth > 1 {

tests/ui/expr/if/bad-if-let-suggestion.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
fn a() {
22
if let x = 1 && i = 2 {}
3-
//~^ ERROR cannot find value `i` in this scope
4-
//~| ERROR mismatched types
5-
//~| ERROR expected expression, found `let` statement
3+
//~^ ERROR expected expression, found `let` statement
64
}
75

86
fn b() {

tests/ui/expr/if/bad-if-let-suggestion.stderr

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,7 @@ LL | if let x = 1 && i == 2 {}
1515
| +
1616

1717
error[E0425]: cannot find value `i` in this scope
18-
--> $DIR/bad-if-let-suggestion.rs:2:21
19-
|
20-
LL | if let x = 1 && i = 2 {}
21-
| ^ not found in this scope
22-
23-
error[E0425]: cannot find value `i` in this scope
24-
--> $DIR/bad-if-let-suggestion.rs:9:9
18+
--> $DIR/bad-if-let-suggestion.rs:7:9
2519
|
2620
LL | fn a() {
2721
| ------ similarly named function `a` defined here
@@ -36,7 +30,7 @@ LL + if (a + j) = i {}
3630
|
3731

3832
error[E0425]: cannot find value `j` in this scope
39-
--> $DIR/bad-if-let-suggestion.rs:9:13
33+
--> $DIR/bad-if-let-suggestion.rs:7:13
4034
|
4135
LL | fn a() {
4236
| ------ similarly named function `a` defined here
@@ -51,7 +45,7 @@ LL + if (i + a) = i {}
5145
|
5246

5347
error[E0425]: cannot find value `i` in this scope
54-
--> $DIR/bad-if-let-suggestion.rs:9:18
48+
--> $DIR/bad-if-let-suggestion.rs:7:18
5549
|
5650
LL | fn a() {
5751
| ------ similarly named function `a` defined here
@@ -66,7 +60,7 @@ LL + if (i + j) = a {}
6660
|
6761

6862
error[E0425]: cannot find value `x` in this scope
69-
--> $DIR/bad-if-let-suggestion.rs:16:8
63+
--> $DIR/bad-if-let-suggestion.rs:14:8
7064
|
7165
LL | fn a() {
7266
| ------ similarly named function `a` defined here
@@ -80,18 +74,6 @@ LL - if x[0] = 1 {}
8074
LL + if a[0] = 1 {}
8175
|
8276

83-
error[E0308]: mismatched types
84-
--> $DIR/bad-if-let-suggestion.rs:2:8
85-
|
86-
LL | if let x = 1 && i = 2 {}
87-
| ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
88-
|
89-
help: you might have meant to compare for equality
90-
|
91-
LL | if let x = 1 && i == 2 {}
92-
| +
93-
94-
error: aborting due to 7 previous errors
77+
error: aborting due to 5 previous errors
9578

96-
Some errors have detailed explanations: E0308, E0425.
97-
For more information about an error, try `rustc --explain E0308`.
79+
For more information about this error, try `rustc --explain E0425`.

tests/ui/parser/let-chains-assign-add-incorrect.fixed

Lines changed: 0 additions & 36 deletions
This file was deleted.

tests/ui/parser/let-chains-assign-add-incorrect.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ edition:2024
2-
//@ run-rustfix
32

43
#![allow(irrefutable_let_patterns)]
54

@@ -8,26 +7,13 @@ fn test_where_left_is_not_let() {
87
if let _ = 1 && true && y += 2 {};
98
//~^ ERROR expected expression, found `let` statement
109
//~| NOTE only supported directly in conditions of `if` and `while` expressions
11-
//~| ERROR mismatched types
12-
//~| NOTE expected `bool`, found integer
13-
//~| NOTE you are add-assigning the right-hand side expression to the result of this let-chain
14-
//~| NOTE expected because this is `bool`
15-
//~| ERROR binary assignment operation `+=` cannot be used in a let chain
16-
//~| NOTE cannot use `+=` in a let chain
17-
//~| HELP you might have meant to compare with `==` instead of assigning with `+=`
1810
}
1911

2012
fn test_where_left_is_let() {
2113
let y = 2;
2214
if let _ = 1 && y += 2 {};
2315
//~^ ERROR expected expression, found `let` statement
2416
//~| NOTE only supported directly in conditions of `if` and `while` expressions
25-
//~| ERROR mismatched types
26-
//~| NOTE expected `bool`, found integer
27-
//~| NOTE you are add-assigning the right-hand side expression to the result of this let-chain
28-
//~| ERROR binary assignment operation `+=` cannot be used in a let chain
29-
//~| NOTE cannot use `+=` in a let chain
30-
//~| HELP you might have meant to compare with `==` instead of assigning with `+=`
3117
}
3218

3319
fn main() {
Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,18 @@
11
error: expected expression, found `let` statement
2-
--> $DIR/let-chains-assign-add-incorrect.rs:8:8
2+
--> $DIR/let-chains-assign-add-incorrect.rs:7:8
33
|
44
LL | if let _ = 1 && true && y += 2 {};
55
| ^^^^^^^^^
66
|
77
= note: only supported directly in conditions of `if` and `while` expressions
88

99
error: expected expression, found `let` statement
10-
--> $DIR/let-chains-assign-add-incorrect.rs:22:8
10+
--> $DIR/let-chains-assign-add-incorrect.rs:14:8
1111
|
1212
LL | if let _ = 1 && y += 2 {};
1313
| ^^^^^^^^^
1414
|
1515
= note: only supported directly in conditions of `if` and `while` expressions
1616

17-
error[E0308]: mismatched types
18-
--> $DIR/let-chains-assign-add-incorrect.rs:8:29
19-
|
20-
LL | if let _ = 1 && true && y += 2 {};
21-
| ----------------- ^ expected `bool`, found integer
22-
| |
23-
| expected because this is `bool`
24-
25-
error: binary assignment operation `+=` cannot be used in a let chain
26-
--> $DIR/let-chains-assign-add-incorrect.rs:8:31
27-
|
28-
LL | if let _ = 1 && true && y += 2 {};
29-
| ---------------------- ^^ cannot use `+=` in a let chain
30-
| |
31-
| you are add-assigning the right-hand side expression to the result of this let-chain
32-
|
33-
help: you might have meant to compare with `==` instead of assigning with `+=`
34-
|
35-
LL - if let _ = 1 && true && y += 2 {};
36-
LL + if let _ = 1 && true && y == 2 {};
37-
|
38-
39-
error[E0308]: mismatched types
40-
--> $DIR/let-chains-assign-add-incorrect.rs:22:21
41-
|
42-
LL | if let _ = 1 && y += 2 {};
43-
| ^ expected `bool`, found integer
44-
45-
error: binary assignment operation `+=` cannot be used in a let chain
46-
--> $DIR/let-chains-assign-add-incorrect.rs:22:23
47-
|
48-
LL | if let _ = 1 && y += 2 {};
49-
| -------------- ^^ cannot use `+=` in a let chain
50-
| |
51-
| you are add-assigning the right-hand side expression to the result of this let-chain
52-
|
53-
help: you might have meant to compare with `==` instead of assigning with `+=`
54-
|
55-
LL - if let _ = 1 && y += 2 {};
56-
LL + if let _ = 1 && y == 2 {};
57-
|
58-
59-
error: aborting due to 6 previous errors
17+
error: aborting due to 2 previous errors
6018

61-
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)