Skip to content

Commit 41caa6e

Browse files
Rollup merge of #151493 - Unique-Usman:ua/missinglet, r=estebank
[RFC] rustc_parse: improve the error diagnostic for "missing let in let chain"
2 parents 3f23c09 + 9ca8ed3 commit 41caa6e

5 files changed

Lines changed: 73 additions & 40 deletions

File tree

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 42 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,19 @@ 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+
if let Some(_) = self.missing_let {
4270+
self.found_incorrect_let_chain = Some(guar);
4271+
}
4272+
guar
4273+
}
42454274
};
42464275
*recovered = Recovered::Yes(error);
42474276
} 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/missing/missing-let.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn main() {
2+
let x = Some(42);
3+
if let Some(_) = x
4+
&& Some(x) = x //~^ ERROR expected expression, found `let` statement
5+
{}
6+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: expected expression, found `let` statement
2+
--> $DIR/missing-let.rs:3:8
3+
|
4+
LL | if let Some(_) = x
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: only supported directly in conditions of `if` and `while` expressions
8+
help: you might have meant to continue the let-chain
9+
|
10+
LL | && let Some(x) = x
11+
| +++
12+
help: you might have meant to compare for equality
13+
|
14+
LL | && Some(x) == x
15+
| +
16+
17+
error: aborting due to 1 previous error
18+

0 commit comments

Comments
 (0)