about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2025-08-30 16:24:26 +0000
committerEsteban Küber <esteban@kuber.com.ar>2025-08-30 16:24:26 +0000
commit00f6fe1b6cbb211c4396b306566816f91a4ed371 (patch)
treeec70227ecaf84c69e675d493f61f8dd784bbc600
parentcb9cd8f8306e6e1b16661704aed8d6f09aa5db73 (diff)
downloadrust-00f6fe1b6cbb211c4396b306566816f91a4ed371.tar.gz
rust-00f6fe1b6cbb211c4396b306566816f91a4ed371.zip
On unused binding in pattern, suggest unit struct/variant with similar name
When encountering a typo in a pattern that gets interpreted as an unused binding, look for unit struct/variant of the same type as the binding:

```
error: unused variable: `Non`
  --> $DIR/binding-typo-2.rs:36:9
   |
LL |         Non => {}
   |         ^^^
   |
help: if this is intentional, prefix it with an underscore
   |
LL |         _Non => {}
   |         +
help: you might have meant to pattern match on the similarly named variant `None`
   |
LL -         Non => {}
LL +         std::prelude::v1::None => {}
   |
```
-rw-r--r--compiler/rustc_passes/messages.ftl1
-rw-r--r--compiler/rustc_passes/src/errors.rs18
-rw-r--r--compiler/rustc_passes/src/liveness.rs33
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed8
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs8
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr25
-rw-r--r--tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr32
-rw-r--r--tests/ui/or-patterns/binding-typo-2.rs25
-rw-r--r--tests/ui/or-patterns/binding-typo-2.stderr197
-rw-r--r--tests/ui/or-patterns/binding-typo.fixed6
-rw-r--r--tests/ui/or-patterns/binding-typo.rs6
-rw-r--r--tests/ui/or-patterns/binding-typo.stderr25
12 files changed, 279 insertions, 105 deletions
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 00a41e31a02..99b1aae8b74 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -681,6 +681,7 @@ passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
 
 passes_unused_var_remove_field = unused variable: `{$name}`
 passes_unused_var_remove_field_suggestion = try removing the field
+passes_unused_var_typo = you might have meant to pattern match on the similarly named {$kind} `{$item_name}`
 
 passes_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 4fec6b0798a..ebd8f6fc820 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1346,6 +1346,22 @@ pub(crate) struct UnusedVarRemoveFieldSugg {
 #[note]
 pub(crate) struct UnusedVarAssignedOnly {
     pub name: String,
+    #[subdiagnostic]
+    pub typo: Option<PatternTypo>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    passes_unused_var_typo,
+    style = "verbose",
+    applicability = "machine-applicable"
+)]
+pub(crate) struct PatternTypo {
+    #[suggestion_part(code = "{code}")]
+    pub span: Span,
+    pub code: String,
+    pub item_name: String,
+    pub kind: String,
 }
 
 #[derive(LintDiagnostic)]
@@ -1413,6 +1429,8 @@ pub(crate) struct UnusedVariableTryPrefix {
     #[subdiagnostic]
     pub sugg: UnusedVariableSugg,
     pub name: String,
+    #[subdiagnostic]
+    pub typo: Option<PatternTypo>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 801a533c943..2ae68c445f8 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -95,8 +95,10 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, find_attr};
 use rustc_index::IndexVec;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
+use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{BytePos, Span, Symbol};
 use tracing::{debug, instrument};
 
@@ -1688,6 +1690,34 @@ impl<'tcx> Liveness<'_, 'tcx> {
             let is_assigned =
                 if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };
 
+            let mut typo = None;
+            for (hir_id, _, span) in &hir_ids_and_spans {
+                let ty = self.typeck_results.node_type(*hir_id);
+                if let ty::Adt(adt, _) = ty.peel_refs().kind() {
+                    let name = Symbol::intern(&name);
+                    let adt_def = self.ir.tcx.adt_def(adt.did());
+                    let variant_names: Vec<_> = adt_def
+                        .variants()
+                        .iter()
+                        .filter(|v| matches!(v.ctor, Some((CtorKind::Const, _))))
+                        .map(|v| v.name)
+                        .collect();
+                    if let Some(name) = find_best_match_for_name(&variant_names, name, None)
+                        && let Some(variant) = adt_def.variants().iter().find(|v| {
+                            v.name == name && matches!(v.ctor, Some((CtorKind::Const, _)))
+                        })
+                    {
+                        typo = Some(errors::PatternTypo {
+                            span: *span,
+                            code: with_no_trimmed_paths!(self.ir.tcx.def_path_str(variant.def_id)),
+                            kind: self.ir.tcx.def_descr(variant.def_id).to_string(),
+                            item_name: variant.name.to_string(),
+                        });
+                    }
+                }
+            }
+            // FIXME(estebank): look for consts of the same type with similar names as well, not
+            // just unit structs and variants.
             if is_assigned {
                 self.ir.tcx.emit_node_span_lint(
                     lint::builtin::UNUSED_VARIABLES,
@@ -1696,7 +1726,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
                         .into_iter()
                         .map(|(_, _, ident_span)| ident_span)
                         .collect::<Vec<_>>(),
-                    errors::UnusedVarAssignedOnly { name },
+                    errors::UnusedVarAssignedOnly { name, typo },
                 )
             } else if can_remove {
                 let spans = hir_ids_and_spans
@@ -1788,6 +1818,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
                             name,
                             sugg,
                             string_interp: suggestions,
+                            typo,
                         },
                     );
                 }
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
index b58c3a6720d..14d5de0261d 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![deny(unused_assignments, unused_variables)]
+#![deny(unused_assignments)]
 #![allow(unused_mut)]
 struct Object;
 
@@ -8,15 +8,15 @@ fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
    *object = object2; //~ ERROR mismatched types
 }
 
-fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
-   //~^ HELP you might have meant to mutate
+fn change_object2(object: &mut Object) {
+    //~^ HELP you might have meant to mutate
    let object2 = Object;
    *object = object2;
    //~^ ERROR `object2` does not live long enough
    //~| ERROR value assigned to `object` is never read
 }
 
-fn change_object3(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
+fn change_object3(object: &mut Object) {
     //~^ HELP you might have meant to mutate
     let mut object2 = Object; //~ HELP consider changing this to be mutable
     *object = object2;
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
index 1fd222e0db1..5805afb3369 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![deny(unused_assignments, unused_variables)]
+#![deny(unused_assignments)]
 #![allow(unused_mut)]
 struct Object;
 
@@ -8,15 +8,15 @@ fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
    object = object2; //~ ERROR mismatched types
 }
 
-fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
-   //~^ HELP you might have meant to mutate
+fn change_object2(mut object: &Object) {
+    //~^ HELP you might have meant to mutate
    let object2 = Object;
    object = &object2;
    //~^ ERROR `object2` does not live long enough
    //~| ERROR value assigned to `object` is never read
 }
 
-fn change_object3(mut object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
+fn change_object3(mut object: &mut Object) {
     //~^ HELP you might have meant to mutate
     let object2 = Object; //~ HELP consider changing this to be mutable
     object = &mut object2;
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
index 0330853d922..c2c7378f07a 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
@@ -23,7 +23,7 @@ LL |    object = &object2;
 note: the lint level is defined here
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
    |
-LL | #![deny(unused_assignments, unused_variables)]
+LL | #![deny(unused_assignments)]
    |         ^^^^^^^^^^^^^^^^^^
 help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
    |
@@ -33,19 +33,6 @@ LL |    let object2 = Object;
 LL ~    *object = object2;
    |
 
-error: variable `object` is assigned to, but never used
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:23
-   |
-LL | fn change_object2(mut object: &Object) {
-   |                       ^^^^^^
-   |
-   = note: consider using `_object` instead
-note: the lint level is defined here
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:29
-   |
-LL | #![deny(unused_assignments, unused_variables)]
-   |                             ^^^^^^^^^^^^^^^^
-
 error[E0597]: `object2` does not live long enough
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:13
    |
@@ -77,14 +64,6 @@ LL |     let object2 = Object;
 LL ~     *object = object2;
    |
 
-error: variable `object` is assigned to, but never used
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:19:23
-   |
-LL | fn change_object3(mut object: &mut Object) {
-   |                       ^^^^^^
-   |
-   = note: consider using `_object` instead
-
 error[E0596]: cannot borrow `object2` as mutable, as it is not declared as mutable
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:14
    |
@@ -96,7 +75,7 @@ help: consider changing this to be mutable
 LL |     let mut object2 = Object;
    |         +++
 
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0308, E0596, E0597.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
index b0c56003957..e5f2e65fd91 100644
--- a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
+++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr
@@ -16,7 +16,7 @@ warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |         ^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-uppercase-variables.rs:1:9
@@ -24,12 +24,29 @@ note: the lint level is defined here
 LL | #![warn(unused)]
    |         ^^^^^^
    = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Foo => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |         foo::Foo::Foo => {}
+   |         ++++++++++
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |     let _Foo = foo::Foo::Foo;
+   |         +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |     let foo::Foo::Foo = foo::Foo::Foo;
+   |         ++++++++++
 
 error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
@@ -41,7 +58,16 @@ warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
-   |                 ^^^ help: if this is intentional, prefix it with an underscore: `_Foo`
+   |                 ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |     fn in_param(_Foo: foo::Foo) {}
+   |                 +
+help: you might have meant to pattern match on the similarly named variant `Foo`
+   |
+LL |     fn in_param(foo::Foo::Foo: foo::Foo) {}
+   |                 ++++++++++
 
 error: structure field `X` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:10:5
diff --git a/tests/ui/or-patterns/binding-typo-2.rs b/tests/ui/or-patterns/binding-typo-2.rs
index 4dfb84d4f0c..d763ce60ce9 100644
--- a/tests/ui/or-patterns/binding-typo-2.rs
+++ b/tests/ui/or-patterns/binding-typo-2.rs
@@ -17,6 +17,7 @@ fn foo(x: (Lol, Lol)) {
         //~| NOTE: variable not in all patterns
         //~| ERROR: variable `Ban` is assigned to, but never used
         //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
         _ => {}
     }
     match &x {
@@ -27,15 +28,18 @@ fn foo(x: (Lol, Lol)) {
         //~| NOTE: variable not in all patterns
         //~| ERROR: variable `Ban` is assigned to, but never used
         //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
         _ => {}
     }
     match Some(42) {
+        Some(_) => {}
         Non => {}
         //~^ ERROR: unused variable: `Non`
         //~| HELP: if this is intentional, prefix it with an underscore
-        _ => {}
+        //~| HELP: you might have meant to pattern match on the similarly named
     }
     match Some(42) {
+        Some(_) => {}
         Non | None => {}
         //~^ ERROR: unused variable: `Non`
         //~| HELP: if this is intentional, prefix it with an underscore
@@ -43,7 +47,7 @@ fn foo(x: (Lol, Lol)) {
         //~| NOTE: pattern doesn't bind `Non`
         //~| NOTE: variable not in all patterns
         //~| HELP: you might have meant to use the similarly named previously used binding `None`
-        _ => {}
+        //~| HELP: you might have meant to pattern match on the similarly named
     }
     match Some(42) {
         Non | Some(_) => {}
@@ -53,14 +57,13 @@ fn foo(x: (Lol, Lol)) {
         //~| NOTE: pattern doesn't bind `Non`
         //~| NOTE: variable not in all patterns
         //~| HELP: you might have meant to use the similarly named unit variant `None`
-        _ => {}
+        //~| HELP: you might have meant to pattern match on the similarly named
     }
 }
 fn bar(x: (Lol, Lol)) {
     use Lol::*;
     use Bat;
     use Bay;
-    use std::option::Option::None;
     match &x {
         (Foo, _) | (Ban, Foo) => {}
         //~^ ERROR: variable `Ban` is not bound in all patterns
@@ -71,6 +74,7 @@ fn bar(x: (Lol, Lol)) {
         //~| NOTE: variable not in all patterns
         //~| ERROR: variable `Ban` is assigned to, but never used
         //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
         _ => {}
     }
 }
@@ -86,8 +90,21 @@ fn baz(x: (Lol, Lol)) {
         //~| NOTE: variable not in all patterns
         //~| ERROR: variable `Ban` is assigned to, but never used
         //~| NOTE: consider using `_Ban` instead
+        //~| HELP: you might have meant to pattern match on the similarly named
         _ => {}
     }
+    match &x {
+        (Ban, _) => {}
+        //~^ ERROR: unused variable: `Ban`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
+    match Bay {
+        Ban => {}
+        //~^ ERROR: unused variable: `Ban`
+        //~| HELP: if this is intentional, prefix it with an underscore
+        //~| HELP: you might have meant to pattern match on the similarly named
+    }
 }
 
 fn main() {
diff --git a/tests/ui/or-patterns/binding-typo-2.stderr b/tests/ui/or-patterns/binding-typo-2.stderr
index a2099572485..d683cb2b121 100644
--- a/tests/ui/or-patterns/binding-typo-2.stderr
+++ b/tests/ui/or-patterns/binding-typo-2.stderr
@@ -13,7 +13,48 @@ LL +         (Foo, Bar) | (Bar, Foo) => {}
    |
 
 error[E0408]: variable `Ban` is not bound in all patterns
-  --> $DIR/binding-typo-2.rs:23:9
+  --> $DIR/binding-typo-2.rs:24:9
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
+   |
+help: you might have meant to use the similarly named unit variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
+   |
+
+error[E0408]: variable `Non` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:43:15
+   |
+LL |         Non | None => {}
+   |         ---   ^^^^ pattern doesn't bind `Non`
+   |         |
+   |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `None`
+   |
+LL |         None | None => {}
+   |            +
+
+error[E0408]: variable `Non` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:53:15
+   |
+LL |         Non | Some(_) => {}
+   |         ---   ^^^^^^^ pattern doesn't bind `Non`
+   |         |
+   |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named unit variant `None`
+   |
+LL -         Non | Some(_) => {}
+LL +         core::option::Option::None | Some(_) => {}
+   |
+
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:68:9
    |
 LL |         (Foo, _) | (Ban, Foo) => {}
    |         ^^^^^^^^    --- variable not in all patterns
@@ -28,39 +69,31 @@ LL +         (Foo, _) | (Bar, Foo) => {}
 help: you might have meant to use the similarly named unit struct `Bay`
    |
 LL -         (Foo, _) | (Ban, Foo) => {}
-LL +         (Foo, _) | (::Bay, Foo) => {}
+LL +         (Foo, _) | (Bay, Foo) => {}
    |
 help: you might have meant to use the similarly named constant `Bat`
    |
 LL -         (Foo, _) | (Ban, Foo) => {}
-LL +         (Foo, _) | (::Bat, Foo) => {}
+LL +         (Foo, _) | (Bat, Foo) => {}
    |
 
-error[E0408]: variable `Non` is not bound in all patterns
-  --> $DIR/binding-typo-2.rs:41:16
-   |
-LL |         (Non | None)=> {}
-   |          ---   ^^^^ pattern doesn't bind `Non`
-   |          |
-   |          variable not in all patterns
+error[E0408]: variable `Ban` is not bound in all patterns
+  --> $DIR/binding-typo-2.rs:85:9
    |
-help: you might have meant to use the similarly named previously used binding `None`
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |         ^^^^^^^^    --- variable not in all patterns
+   |         |
+   |         pattern doesn't bind `Ban`
    |
-LL |         (None | None)=> {}
-   |             +
-
-error[E0408]: variable `Non` is not bound in all patterns
-  --> $DIR/binding-typo-2.rs:51:16
+help: you might have meant to use the similarly named unit variant `Bar`
    |
-LL |         (Non | Some(_))=> {}
-   |          ---   ^^^^^^^ pattern doesn't bind `Non`
-   |          |
-   |          variable not in all patterns
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bar, Foo) => {}
    |
-help: you might have meant to use the similarly named unit variant `None`
+help: you might have meant to use the similarly named constant `Bat`
    |
-LL -         (Non | Some(_))=> {}
-LL +         (core::option::Option::None | Some(_))=> {}
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Bat, Foo) => {}
    |
 
 error: variable `Ban` is assigned to, but never used
@@ -75,33 +108,131 @@ note: the lint level is defined here
    |
 LL | #![deny(unused_variables)]
    |         ^^^^^^^^^^^^^^^^
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, Bar) | (Ban, Foo) => {}
+LL +         (Foo, Bar) | (Lol::Bar, Foo) => {}
+   |
 
 error: variable `Ban` is assigned to, but never used
-  --> $DIR/binding-typo-2.rs:23:21
+  --> $DIR/binding-typo-2.rs:24:21
    |
 LL |         (Foo, _) | (Ban, Foo) => {}
    |                     ^^^
    |
    = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
 
 error: unused variable: `Non`
-  --> $DIR/binding-typo-2.rs:35:9
+  --> $DIR/binding-typo-2.rs:36:9
    |
 LL |         Non => {}
-   |         ^^^ help: if this is intentional, prefix it with an underscore: `_Non`
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non => {}
+LL +         std::prelude::v1::None => {}
+   |
 
 error: unused variable: `Non`
-  --> $DIR/binding-typo-2.rs:41:10
+  --> $DIR/binding-typo-2.rs:43:9
+   |
+LL |         Non | None => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non | None => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non | None => {}
+LL +         std::prelude::v1::None | None => {}
    |
-LL |         (Non | None)=> {}
-   |          ^^^ help: if this is intentional, prefix it with an underscore: `_Non`
 
 error: unused variable: `Non`
-  --> $DIR/binding-typo-2.rs:51:10
+  --> $DIR/binding-typo-2.rs:53:9
+   |
+LL |         Non | Some(_) => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Non | Some(_) => {}
+   |         +
+help: you might have meant to pattern match on the similarly named variant `None`
+   |
+LL -         Non | Some(_) => {}
+LL +         std::prelude::v1::None | Some(_) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:68:21
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |                     ^^^
+   |
+   = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
+
+error: variable `Ban` is assigned to, but never used
+  --> $DIR/binding-typo-2.rs:85:21
+   |
+LL |         (Foo, _) | (Ban, Foo) => {}
+   |                     ^^^
+   |
+   = note: consider using `_Ban` instead
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Foo, _) | (Ban, Foo) => {}
+LL +         (Foo, _) | (Lol::Bar, Foo) => {}
+   |
+
+error: unused variable: `Ban`
+  --> $DIR/binding-typo-2.rs:97:10
+   |
+LL |         (Ban, _) => {}
+   |          ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         (_Ban, _) => {}
+   |          +
+help: you might have meant to pattern match on the similarly named variant `Bar`
+   |
+LL -         (Ban, _) => {}
+LL +         (Lol::Bar, _) => {}
+   |
+
+error: unused variable: `Ban`
+  --> $DIR/binding-typo-2.rs:103:9
+   |
+LL |         Ban => {}
+   |         ^^^
+   |
+help: if this is intentional, prefix it with an underscore
+   |
+LL |         _Ban => {}
+   |         +
+help: you might have meant to pattern match on the similarly named struct `Bay`
+   |
+LL -         Ban => {}
+LL +         Bay => {}
    |
-LL |         (Non | Some(_))=> {}
-   |          ^^^ help: if this is intentional, prefix it with an underscore: `_Non`
 
-error: aborting due to 9 previous errors
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0408`.
diff --git a/tests/ui/or-patterns/binding-typo.fixed b/tests/ui/or-patterns/binding-typo.fixed
index 2902ca30393..f209ad644db 100644
--- a/tests/ui/or-patterns/binding-typo.fixed
+++ b/tests/ui/or-patterns/binding-typo.fixed
@@ -1,6 +1,6 @@
 // Issue #51976
 //@ run-rustfix
-#![deny(unused_variables)] //~ NOTE: the lint level is defined here
+#![allow(unused_variables)] // allowed so we don't get overlapping suggestions
 enum Lol {
     Foo,
     Bar,
@@ -14,8 +14,6 @@ fn foo(x: (Lol, Lol)) {
         //~| HELP: you might have meant to use the similarly named previously used binding `Bar`
         //~| NOTE: pattern doesn't bind `Ban`
         //~| NOTE: variable not in all patterns
-        //~| ERROR: variable `Ban` is assigned to, but never used
-        //~| NOTE: consider using `_Ban` instead
         _ => {}
     }
     match &x {
@@ -24,8 +22,6 @@ fn foo(x: (Lol, Lol)) {
         //~| HELP: you might have meant to use the similarly named unit variant `Bar`
         //~| NOTE: pattern doesn't bind `Ban`
         //~| NOTE: variable not in all patterns
-        //~| ERROR: variable `Ban` is assigned to, but never used
-        //~| NOTE: consider using `_Ban` instead
         _ => {}
     }
 }
diff --git a/tests/ui/or-patterns/binding-typo.rs b/tests/ui/or-patterns/binding-typo.rs
index 2ffe0e45c83..6be9b801a0d 100644
--- a/tests/ui/or-patterns/binding-typo.rs
+++ b/tests/ui/or-patterns/binding-typo.rs
@@ -1,6 +1,6 @@
 // Issue #51976
 //@ run-rustfix
-#![deny(unused_variables)] //~ NOTE: the lint level is defined here
+#![allow(unused_variables)] // allowed so we don't get overlapping suggestions
 enum Lol {
     Foo,
     Bar,
@@ -14,8 +14,6 @@ fn foo(x: (Lol, Lol)) {
         //~| HELP: you might have meant to use the similarly named previously used binding `Bar`
         //~| NOTE: pattern doesn't bind `Ban`
         //~| NOTE: variable not in all patterns
-        //~| ERROR: variable `Ban` is assigned to, but never used
-        //~| NOTE: consider using `_Ban` instead
         _ => {}
     }
     match &x {
@@ -24,8 +22,6 @@ fn foo(x: (Lol, Lol)) {
         //~| HELP: you might have meant to use the similarly named unit variant `Bar`
         //~| NOTE: pattern doesn't bind `Ban`
         //~| NOTE: variable not in all patterns
-        //~| ERROR: variable `Ban` is assigned to, but never used
-        //~| NOTE: consider using `_Ban` instead
         _ => {}
     }
 }
diff --git a/tests/ui/or-patterns/binding-typo.stderr b/tests/ui/or-patterns/binding-typo.stderr
index f90301d2cee..fb6d5f71209 100644
--- a/tests/ui/or-patterns/binding-typo.stderr
+++ b/tests/ui/or-patterns/binding-typo.stderr
@@ -13,7 +13,7 @@ LL +         (Foo, Bar) | (Bar, Foo) => {}
    |
 
 error[E0408]: variable `Ban` is not bound in all patterns
-  --> $DIR/binding-typo.rs:22:9
+  --> $DIR/binding-typo.rs:20:9
    |
 LL |         (Foo, _) | (Ban, Foo) => {}
    |         ^^^^^^^^    --- variable not in all patterns
@@ -26,27 +26,6 @@ LL -         (Foo, _) | (Ban, Foo) => {}
 LL +         (Foo, _) | (Bar, Foo) => {}
    |
 
-error: variable `Ban` is assigned to, but never used
-  --> $DIR/binding-typo.rs:12:23
-   |
-LL |         (Foo, Bar) | (Ban, Foo) => {}
-   |                       ^^^
-   |
-   = note: consider using `_Ban` instead
-note: the lint level is defined here
-  --> $DIR/binding-typo.rs:3:9
-   |
-LL | #![deny(unused_variables)]
-   |         ^^^^^^^^^^^^^^^^
-
-error: variable `Ban` is assigned to, but never used
-  --> $DIR/binding-typo.rs:22:21
-   |
-LL |         (Foo, _) | (Ban, Foo) => {}
-   |                     ^^^
-   |
-   = note: consider using `_Ban` instead
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0408`.