Rollup merge of #151493 - Unique-Usman:ua/missinglet, r=estebank
[RFC] rustc_parse: improve the error diagnostic for "missing let in let chain"
This commit is contained in:
commit
41caa6e22d
5 changed files with 73 additions and 40 deletions
|
|
@ -2760,9 +2760,13 @@ impl<'a> Parser<'a> {
|
|||
let (mut cond, _) =
|
||||
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
|
||||
|
||||
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
|
||||
|
||||
Ok(cond)
|
||||
let mut checker = CondChecker::new(self, let_chains_policy);
|
||||
checker.visit_expr(&mut cond);
|
||||
Ok(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
self.mk_expr_err(cond.span, guar)
|
||||
} else {
|
||||
cond
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a `let $pat = $expr` pseudo-expression.
|
||||
|
|
@ -3484,13 +3488,19 @@ impl<'a> Parser<'a> {
|
|||
let if_span = self.prev_token.span;
|
||||
let mut cond = self.parse_match_guard_condition()?;
|
||||
|
||||
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
|
||||
checker.visit_expr(&mut cond);
|
||||
|
||||
if has_let_expr(&cond) {
|
||||
let span = if_span.to(cond.span);
|
||||
self.psess.gated_spans.gate(sym::if_let_guard, span);
|
||||
}
|
||||
Ok(Some(cond))
|
||||
|
||||
Ok(Some(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
self.mk_expr_err(cond.span, guar)
|
||||
} else {
|
||||
cond
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
|
||||
|
|
@ -3511,13 +3521,23 @@ impl<'a> Parser<'a> {
|
|||
let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
|
||||
let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
|
||||
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
|
||||
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
|
||||
checker.visit_expr(&mut cond);
|
||||
|
||||
let right = self.prev_token.span;
|
||||
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
||||
span: vec![left, right],
|
||||
sugg: errors::ParenthesesInMatchPatSugg { left, right },
|
||||
});
|
||||
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
|
||||
|
||||
Ok((
|
||||
self.mk_pat(span, ast::PatKind::Wild),
|
||||
(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
Some(self.mk_expr_err(cond.span, guar))
|
||||
} else {
|
||||
Some(cond)
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Ok((pat, self.parse_match_arm_guard()?))
|
||||
}
|
||||
|
|
@ -4208,6 +4228,7 @@ struct CondChecker<'a> {
|
|||
forbid_let_reason: Option<ForbiddenLetReason>,
|
||||
missing_let: Option<errors::MaybeMissingLet>,
|
||||
comparison: Option<errors::MaybeComparison>,
|
||||
found_incorrect_let_chain: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
impl<'a> CondChecker<'a> {
|
||||
|
|
@ -4218,6 +4239,7 @@ impl<'a> CondChecker<'a> {
|
|||
missing_let: None,
|
||||
comparison: None,
|
||||
let_chains_policy,
|
||||
found_incorrect_let_chain: None,
|
||||
depth: 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -4236,12 +4258,19 @@ impl MutVisitor for CondChecker<'_> {
|
|||
NotSupportedOr(or_span) => {
|
||||
self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
|
||||
}
|
||||
_ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
|
||||
span,
|
||||
reason,
|
||||
missing_let: self.missing_let,
|
||||
comparison: self.comparison,
|
||||
}),
|
||||
_ => {
|
||||
let guar =
|
||||
self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
|
||||
span,
|
||||
reason,
|
||||
missing_let: self.missing_let,
|
||||
comparison: self.comparison,
|
||||
});
|
||||
if let Some(_) = self.missing_let {
|
||||
self.found_incorrect_let_chain = Some(guar);
|
||||
}
|
||||
guar
|
||||
}
|
||||
};
|
||||
*recovered = Recovered::Yes(error);
|
||||
} else if self.depth > 1 {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
fn a() {
|
||||
if let x = 1 && i = 2 {}
|
||||
//~^ ERROR cannot find value `i` in this scope
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR expected expression, found `let` statement
|
||||
//~^ ERROR expected expression, found `let` statement
|
||||
}
|
||||
|
||||
fn b() {
|
||||
|
|
|
|||
|
|
@ -15,13 +15,7 @@ LL | if let x = 1 && i == 2 {}
|
|||
| +
|
||||
|
||||
error[E0425]: cannot find value `i` in this scope
|
||||
--> $DIR/bad-if-let-suggestion.rs:2:21
|
||||
|
|
||||
LL | if let x = 1 && i = 2 {}
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `i` in this scope
|
||||
--> $DIR/bad-if-let-suggestion.rs:9:9
|
||||
--> $DIR/bad-if-let-suggestion.rs:7:9
|
||||
|
|
||||
LL | fn a() {
|
||||
| ------ similarly named function `a` defined here
|
||||
|
|
@ -36,7 +30,7 @@ LL + if (a + j) = i {}
|
|||
|
|
||||
|
||||
error[E0425]: cannot find value `j` in this scope
|
||||
--> $DIR/bad-if-let-suggestion.rs:9:13
|
||||
--> $DIR/bad-if-let-suggestion.rs:7:13
|
||||
|
|
||||
LL | fn a() {
|
||||
| ------ similarly named function `a` defined here
|
||||
|
|
@ -51,7 +45,7 @@ LL + if (i + a) = i {}
|
|||
|
|
||||
|
||||
error[E0425]: cannot find value `i` in this scope
|
||||
--> $DIR/bad-if-let-suggestion.rs:9:18
|
||||
--> $DIR/bad-if-let-suggestion.rs:7:18
|
||||
|
|
||||
LL | fn a() {
|
||||
| ------ similarly named function `a` defined here
|
||||
|
|
@ -66,7 +60,7 @@ LL + if (i + j) = a {}
|
|||
|
|
||||
|
||||
error[E0425]: cannot find value `x` in this scope
|
||||
--> $DIR/bad-if-let-suggestion.rs:16:8
|
||||
--> $DIR/bad-if-let-suggestion.rs:14:8
|
||||
|
|
||||
LL | fn a() {
|
||||
| ------ similarly named function `a` defined here
|
||||
|
|
@ -80,18 +74,6 @@ LL - if x[0] = 1 {}
|
|||
LL + if a[0] = 1 {}
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-if-let-suggestion.rs:2:8
|
||||
|
|
||||
LL | if let x = 1 && i = 2 {}
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||
|
|
||||
help: you might have meant to compare for equality
|
||||
|
|
||||
LL | if let x = 1 && i == 2 {}
|
||||
| +
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0425.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
|
|
|
|||
6
tests/ui/missing/missing-let.rs
Normal file
6
tests/ui/missing/missing-let.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
let x = Some(42);
|
||||
if let Some(_) = x
|
||||
&& Some(x) = x //~^ ERROR expected expression, found `let` statement
|
||||
{}
|
||||
}
|
||||
18
tests/ui/missing/missing-let.stderr
Normal file
18
tests/ui/missing/missing-let.stderr
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
error: expected expression, found `let` statement
|
||||
--> $DIR/missing-let.rs:3:8
|
||||
|
|
||||
LL | if let Some(_) = x
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly in conditions of `if` and `while` expressions
|
||||
help: you might have meant to continue the let-chain
|
||||
|
|
||||
LL | && let Some(x) = x
|
||||
| +++
|
||||
help: you might have meant to compare for equality
|
||||
|
|
||||
LL | && Some(x) == x
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue