diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c31a4798b471e..44c6acec88660 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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>)> { @@ -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, missing_let: Option, comparison: Option, + found_incorrect_let_chain: Option, } 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 { diff --git a/tests/ui/expr/if/bad-if-let-suggestion.rs b/tests/ui/expr/if/bad-if-let-suggestion.rs index b0d0676e1ea75..c462e32c9ef55 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.rs +++ b/tests/ui/expr/if/bad-if-let-suggestion.rs @@ -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() { diff --git a/tests/ui/expr/if/bad-if-let-suggestion.stderr b/tests/ui/expr/if/bad-if-let-suggestion.stderr index 4244a3bb06eea..d0838fec67d66 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.stderr +++ b/tests/ui/expr/if/bad-if-let-suggestion.stderr @@ -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 7 previous errors +error: aborting due to 5 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`. diff --git a/tests/ui/missing/missing-let.rs b/tests/ui/missing/missing-let.rs new file mode 100644 index 0000000000000..36db7bc95826b --- /dev/null +++ b/tests/ui/missing/missing-let.rs @@ -0,0 +1,6 @@ +fn main() { + let x = Some(42); + if let Some(_) = x + && Some(x) = x //~^ ERROR expected expression, found `let` statement + {} +} diff --git a/tests/ui/missing/missing-let.stderr b/tests/ui/missing/missing-let.stderr new file mode 100644 index 0000000000000..897ff6329d593 --- /dev/null +++ b/tests/ui/missing/missing-let.stderr @@ -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 +