Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 42 additions & 13 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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>>)> {
Expand All @@ -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()?))
}
Expand Down Expand Up @@ -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> {
Expand All @@ -4218,6 +4239,7 @@ impl<'a> CondChecker<'a> {
missing_let: None,
comparison: None,
let_chains_policy,
found_incorrect_let_chain: None,
depth: 0,
}
}
Expand All @@ -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 {
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/expr/if/bad-if-let-suggestion.rs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
30 changes: 6 additions & 24 deletions tests/ui/expr/if/bad-if-let-suggestion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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`.
6 changes: 6 additions & 0 deletions tests/ui/missing/missing-let.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn main() {
let x = Some(42);
if let Some(_) = x
&& Some(x) = x //~^ ERROR expected expression, found `let` statement
{}
}
18 changes: 18 additions & 0 deletions tests/ui/missing/missing-let.stderr
Original file line number Diff line number Diff line change
@@ -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