Skip to content

Commit 6fb0778

Browse files
committed
Supress suggest let else when no let in refutable bindings
Signed-off-by: xizheyin <[email protected]>
1 parent b7f3316 commit 6fb0778

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
66
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
77
use rustc_hir::def::*;
88
use rustc_hir::def_id::LocalDefId;
9-
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
9+
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LocalSource, MatchSource, Node};
1010
use rustc_infer::infer::TyCtxtInferExt;
1111
use rustc_lint::Level;
1212
use rustc_middle::bug;
@@ -715,6 +715,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
715715
&& self.tcx.sess.source_map().is_span_accessible(span)
716716
&& interpreted_as_const.is_none()
717717
&& scrut.is_some()
718+
// we only suggest `let else` when the pattern is not desugared from an assignment
719+
&& !self.is_pat_from_assign_desugar(pat)
718720
{
719721
let mut bindings = vec![];
720722
pat.each_binding(|name, _, _, _| bindings.push(name));
@@ -768,6 +770,32 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
768770
adt_defined_here,
769771
}));
770772
}
773+
774+
/// Check if `pat` is desugared into a `let`, i.e., `LocalSource::AssignDesugar`
775+
/// rather than a real `let` the user wrote.
776+
/// This helps suppress suggestions for `let` statements when
777+
/// we're dealing with an assignment like `Some(x) = rhs`.
778+
fn is_pat_from_assign_desugar(&self, pat: &Pat<'tcx>) -> bool {
779+
// Find a binding in the pattern
780+
let mut binding: Option<LocalVarId> = None;
781+
pat.walk(|p| {
782+
if let PatKind::Binding { var, .. } = p.kind {
783+
binding = Some(var);
784+
return false;
785+
}
786+
true
787+
});
788+
789+
// Walk up the HIR parents to the enclosing `LetStmt`, then check its `source`.
790+
if let Some(var) = binding {
791+
for (_, node) in self.tcx.hir_parent_iter(var.0) {
792+
if let Node::LetStmt(let_stmt) = node {
793+
return matches!(let_stmt.source, LocalSource::AssignDesugar(_));
794+
}
795+
}
796+
}
797+
false
798+
}
771799
}
772800

773801
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.

tests/ui/let-else/suggest-with-let-issue-145548.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// `Some(x) = Some(1)` is treated as a let statement,
2-
// so we should suggest to add`let ... else{...}`
2+
// so we should not suggest to add `let ... else{...}`
33

44
fn foo1(){
55
let x = 2;

tests/ui/let-else/suggest-with-let-issue-145548.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ LL | Some(x) = Some(1);
77
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
88
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
99
= note: the matched value is of type `Option<i32>`
10-
help: you might want to use `let else` to handle the variant that isn't matched
11-
|
12-
LL | Some(x) = Some(1) else { todo!() };
13-
| ++++++++++++++++
1410

1511
error[E0005]: refutable pattern in local binding
1612
--> $DIR/suggest-with-let-issue-145548.rs:11:9

0 commit comments

Comments
 (0)