about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2025-08-24 19:22:51 +0000
committerEsteban Küber <esteban@kuber.com.ar>2025-08-25 15:16:25 +0000
commit8dbdb1760b23112f87aedad37e4dad97559bc750 (patch)
treedd2cd17a9704e56eac5416f6c5c9883ebd6deaf5
parent41a79f1862aa6b81bac674598e275e80e9f09eb9 (diff)
downloadrust-8dbdb1760b23112f87aedad37e4dad97559bc750.tar.gz
rust-8dbdb1760b23112f87aedad37e4dad97559bc750.zip
On binding not present in all patterns, suggest potential typo
```
error[E0408]: variable `Ban` is not bound in all patterns
 --> f12.rs:9:9
  |
9 |         (Foo,Bar)|(Ban,Foo) => {}
  |         ^^^^^^^^^  --- variable not in all patterns
  |         |
  |         pattern doesn't bind `Ban`
  |
help: you might have meant to use the similarly named previously used binding `Bar`
  |
9 -         (Foo,Bar)|(Ban,Foo) => {}
9 +         (Foo,Bar)|(Bar,Foo) => {}
  |
```
-rw-r--r--compiler/rustc_resolve/messages.ftl2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs53
-rw-r--r--compiler/rustc_resolve/src/errors.rs12
-rw-r--r--compiler/rustc_resolve/src/late.rs52
-rw-r--r--compiler/rustc_resolve/src/lib.rs4
-rw-r--r--tests/ui/or-patterns/mismatched-bindings-async-fn.stderr24
-rw-r--r--tests/ui/or-patterns/missing-bindings.stderr81
-rw-r--r--tests/ui/or-patterns/nested-undelimited-precedence.stderr6
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr12
-rw-r--r--tests/ui/resolve/resolve-inconsistent-names.rs6
-rw-r--r--tests/ui/resolve/resolve-inconsistent-names.stderr46
-rw-r--r--tests/ui/span/issue-39698.stderr24
12 files changed, 268 insertions, 54 deletions
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 47280a93677..0e566e20a12 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -470,6 +470,8 @@ resolve_variable_bound_with_different_mode =
     .label = bound in different ways
     .first_binding_span = first binding
 
+resolve_variable_is_a_typo = you might have meant to use the similarly named previously used binding `{$typo}`
+
 resolve_variable_is_not_bound_in_all_patterns =
     variable `{$name}` is not bound in all patterns
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 337e7d2dd86..324310ff48b 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -661,8 +661,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
                 let BindingError { name, target, origin, could_be_path } = binding_error;
 
-                let target_sp = target.iter().copied().collect::<Vec<_>>();
-                let origin_sp = origin.iter().copied().collect::<Vec<_>>();
+                let mut target_sp = target.iter().map(|pat| pat.span).collect::<Vec<_>>();
+                target_sp.sort();
+                target_sp.dedup();
+                let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::<Vec<_>>();
+                origin_sp.sort();
+                origin_sp.dedup();
 
                 let msp = MultiSpan::from_spans(target_sp.clone());
                 let mut err = self
@@ -671,8 +675,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 for sp in target_sp {
                     err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
                 }
-                for sp in origin_sp {
-                    err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp });
+                for sp in &origin_sp {
+                    err.subdiagnostic(errors::VariableNotInAllPatterns { span: *sp });
+                }
+                let mut target_visitor = BindingVisitor::default();
+                for pat in &target {
+                    target_visitor.visit_pat(pat);
+                }
+                target_visitor.identifiers.sort();
+                target_visitor.identifiers.dedup();
+                let mut origin_visitor = BindingVisitor::default();
+                for (_, pat) in &origin {
+                    origin_visitor.visit_pat(pat);
+                }
+                origin_visitor.identifiers.sort();
+                origin_visitor.identifiers.dedup();
+                // Find if the binding could have been a typo
+                let mut suggested_typo = false;
+                if let Some(typo) =
+                    find_best_match_for_name(&target_visitor.identifiers, name.name, None)
+                    && !origin_visitor.identifiers.contains(&typo)
+                {
+                    err.subdiagnostic(errors::PatternBindingTypo { spans: origin_sp, typo });
+                    suggested_typo = true;
                 }
                 if could_be_path {
                     let import_suggestions = self.lookup_import_candidates(
@@ -693,7 +718,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         },
                     );
 
-                    if import_suggestions.is_empty() {
+                    if import_suggestions.is_empty() && !suggested_typo {
                         let help_msg = format!(
                             "if you meant to match on a variant or a `const` item, consider \
                              making the path in the pattern qualified: `path::to::ModOrType::{name}`",
@@ -3395,7 +3420,7 @@ impl UsePlacementFinder {
     }
 }
 
-impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     fn visit_crate(&mut self, c: &Crate) {
         if self.target_module == CRATE_NODE_ID {
             let inject = c.spans.inject_use_span;
@@ -3423,6 +3448,22 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
     }
 }
 
+#[derive(Default)]
+struct BindingVisitor {
+    identifiers: Vec<Symbol>,
+    spans: FxHashMap<Symbol, Vec<Span>>,
+}
+
+impl<'tcx> Visitor<'tcx> for BindingVisitor {
+    fn visit_pat(&mut self, pat: &ast::Pat) {
+        if let ast::PatKind::Ident(_, ident, _) = pat.kind {
+            self.identifiers.push(ident.name);
+            self.spans.entry(ident.name).or_default().push(ident.span);
+        }
+        visit::walk_pat(self, pat);
+    }
+}
+
 fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> {
     for item in items {
         if let ItemKind::Use(..) = item.kind
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 63d6fa23a14..72be94e58db 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -986,6 +986,18 @@ pub(crate) struct VariableNotInAllPatterns {
     pub(crate) span: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    resolve_variable_is_a_typo,
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub(crate) struct PatternBindingTypo {
+    #[suggestion_part(code = "{typo}")]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) typo: Symbol,
+}
+
 #[derive(Diagnostic)]
 #[diag(resolve_name_defined_multiple_time)]
 #[note]
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 679e663f886..6f1bd4572dd 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -8,7 +8,6 @@
 
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
-use std::collections::BTreeSet;
 use std::collections::hash_map::Entry;
 use std::mem::{replace, swap, take};
 
@@ -3682,31 +3681,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // 2) Record any missing bindings or binding mode inconsistencies.
         for (map_outer, pat_outer) in not_never_pats.iter() {
             // Check against all arms except for the same pattern which is always self-consistent.
-            let inners = not_never_pats
-                .iter()
-                .filter(|(_, pat)| pat.id != pat_outer.id)
-                .flat_map(|(map, _)| map);
-
-            for (&name, binding_inner) in inners {
-                match map_outer.get(&name) {
-                    None => {
-                        // The inner binding is missing in the outer.
-                        let binding_error =
-                            missing_vars.entry(name).or_insert_with(|| BindingError {
-                                name,
-                                origin: BTreeSet::new(),
-                                target: BTreeSet::new(),
-                                could_be_path: name.as_str().starts_with(char::is_uppercase),
-                            });
-                        binding_error.origin.insert(binding_inner.span);
-                        binding_error.target.insert(pat_outer.span);
-                    }
-                    Some(binding_outer) => {
-                        if binding_outer.annotation != binding_inner.annotation {
-                            // The binding modes in the outer and inner bindings differ.
-                            inconsistent_vars
-                                .entry(name)
-                                .or_insert((binding_inner.span, binding_outer.span));
+            let inners = not_never_pats.iter().filter(|(_, pat)| pat.id != pat_outer.id);
+
+            for (map, pat) in inners {
+                for (&name, binding_inner) in map {
+                    match map_outer.get(&name) {
+                        None => {
+                            // The inner binding is missing in the outer.
+                            let binding_error =
+                                missing_vars.entry(name).or_insert_with(|| BindingError {
+                                    name,
+                                    origin: Default::default(),
+                                    target: Default::default(),
+                                    could_be_path: name.as_str().starts_with(char::is_uppercase),
+                                });
+                            binding_error.origin.push((binding_inner.span, (***pat).clone()));
+                            binding_error.target.push((***pat_outer).clone());
+                        }
+                        Some(binding_outer) => {
+                            if binding_outer.annotation != binding_inner.annotation {
+                                // The binding modes in the outer and inner bindings differ.
+                                inconsistent_vars
+                                    .entry(name)
+                                    .or_insert((binding_inner.span, binding_outer.span));
+                            }
                         }
                     }
                 }
@@ -3719,7 +3717,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 v.could_be_path = false;
             }
             self.report_error(
-                *v.origin.iter().next().unwrap(),
+                v.origin.iter().next().unwrap().0,
                 ResolutionError::VariableNotBoundInPattern(v, self.parent_scope),
             );
         }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 2afb52ef4d4..c36a6883300 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -230,8 +230,8 @@ enum Used {
 #[derive(Debug)]
 struct BindingError {
     name: Ident,
-    origin: BTreeSet<Span>,
-    target: BTreeSet<Span>,
+    origin: Vec<(Span, ast::Pat)>,
+    target: Vec<ast::Pat>,
     could_be_path: bool,
 }
 
diff --git a/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr b/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr
index 81602fffa8d..523cdf959e7 100644
--- a/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr
+++ b/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr
@@ -5,6 +5,12 @@ LL | async fn a((x | s): String) {}
    |             ^   - variable not in all patterns
    |             |
    |             pattern doesn't bind `s`
+   |
+help: you might have meant to use the similarly named previously used binding `x`
+   |
+LL - async fn a((x | s): String) {}
+LL + async fn a((x | x): String) {}
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/mismatched-bindings-async-fn.rs:4:17
@@ -13,6 +19,12 @@ LL | async fn a((x | s): String) {}
    |             -   ^ pattern doesn't bind `x`
    |             |
    |             variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `s`
+   |
+LL - async fn a((x | s): String) {}
+LL + async fn a((s | s): String) {}
+   |
 
 error[E0408]: variable `s` is not bound in all patterns
   --> $DIR/mismatched-bindings-async-fn.rs:9:10
@@ -21,6 +33,12 @@ LL |     let (x | s) = String::new();
    |          ^   - variable not in all patterns
    |          |
    |          pattern doesn't bind `s`
+   |
+help: you might have meant to use the similarly named previously used binding `x`
+   |
+LL -     let (x | s) = String::new();
+LL +     let (x | x) = String::new();
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/mismatched-bindings-async-fn.rs:9:14
@@ -29,6 +47,12 @@ LL |     let (x | s) = String::new();
    |          -   ^ pattern doesn't bind `x`
    |          |
    |          variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `s`
+   |
+LL -     let (x | s) = String::new();
+LL +     let (s | s) = String::new();
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/or-patterns/missing-bindings.stderr b/tests/ui/or-patterns/missing-bindings.stderr
index 6288cc58913..636f7016647 100644
--- a/tests/ui/or-patterns/missing-bindings.stderr
+++ b/tests/ui/or-patterns/missing-bindings.stderr
@@ -86,6 +86,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |            ^^^^^^^     - variable not in all patterns
    |            |
    |            pattern doesn't bind `c`
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(a), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:22
@@ -94,6 +100,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |              -       ^^^^ pattern doesn't bind `a`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(c, b) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `b` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:22
@@ -102,6 +114,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                 -    ^^^^ pattern doesn't bind `b`
    |                 |
    |                 variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, c) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `e` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:10
@@ -110,6 +128,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |          ^^^^^^^^^^^^^^^^^^^^     - variable not in all patterns
    |          |
    |          pattern doesn't bind `e`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(c), d) | B(c)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -118,6 +142,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |              -                  ^^^^ pattern doesn't bind `a`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(e, b) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `b` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -126,6 +156,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                 -               ^^^^ pattern doesn't bind `b`
    |                 |
    |                 variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, e) | B(c), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -134,6 +170,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                        -        ^^^^ pattern doesn't bind `c`
    |                        |
    |                        variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(e), d) | B(e)) = Y;
+   |
 
 error[E0408]: variable `d` is not bound in all patterns
   --> $DIR/missing-bindings.rs:47:33
@@ -142,6 +184,12 @@ LL |     let (A(A(a, b) | B(c), d) | B(e)) = Y;
    |                            -    ^^^^ pattern doesn't bind `d`
    |                            |
    |                            variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `e`
+   |
+LL -     let (A(A(a, b) | B(c), d) | B(e)) = Y;
+LL +     let (A(A(a, b) | B(c), e) | B(e)) = Y;
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:63:29
@@ -158,6 +206,12 @@ LL |                     A(_, a) |
    |                     ^^^^^^^ pattern doesn't bind `b`
 LL |                     B(b),
    |                       - variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -                     B(b),
+LL +                     B(a),
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:71:21
@@ -166,6 +220,12 @@ LL |                     A(_, a) |
    |                          - variable not in all patterns
 LL |                     B(b),
    |                     ^^^^ pattern doesn't bind `a`
+   |
+help: you might have meant to use the similarly named previously used binding `b`
+   |
+LL -                     A(_, a) |
+LL +                     A(_, b) |
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:74:17
@@ -202,6 +262,12 @@ LL |                       B(b),
 ...
 LL |               V3(c),
    |               ^^^^^ pattern doesn't bind `b`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -                     B(b),
+LL +                     B(c),
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/missing-bindings.rs:59:13
@@ -223,6 +289,12 @@ LL | |             ) |
    | |_____________^ pattern doesn't bind `c`
 LL |               V3(c),
    |                  - variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -             V3(c),
+LL +             V3(a),
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/missing-bindings.rs:78:13
@@ -235,6 +307,15 @@ LL |                     A(_, a) |
 ...
 LL |             V3(c),
    |             ^^^^^ pattern doesn't bind `a`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL ~                 B(Ok(a) | Err(c))
+LL |             ) |
+LL |             V2(
+LL |                 A(
+LL ~                     A(_, c) |
+   |
 
 error[E0170]: pattern binding `beta` is named the same as one of the variants of the type `check_handling_of_paths::bar::foo`
   --> $DIR/missing-bindings.rs:19:18
diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
index 0835ca1929f..10dbc9d16c0 100644
--- a/tests/ui/or-patterns/nested-undelimited-precedence.stderr
+++ b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
@@ -60,6 +60,12 @@ LL |     let b @ A | B: E = A;
    |         -       ^ pattern doesn't bind `b`
    |         |
    |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `B`
+   |
+LL -     let b @ A | B: E = A;
+LL +     let B @ A | B: E = A;
+   |
 
 error[E0308]: mismatched types
   --> $DIR/nested-undelimited-precedence.rs:34:9
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
index d76e60478a1..a5d9fd2b1a6 100644
--- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
@@ -5,6 +5,12 @@ LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |          ^^^^^^^^^^^^        - variable not in all patterns
    |          |
    |          pattern doesn't bind `y`
+   |
+help: you might have meant to use the similarly named previously used binding `x`
+   |
+LL -         ((Ok(x) if y) | (Err(y) if x),) => x && y,
+LL +         ((Ok(x) if y) | (Err(x) if x),) => x && y,
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/name-resolution.rs:37:25
@@ -13,6 +19,12 @@ LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |              -          ^^^^^^^^^^^^^ pattern doesn't bind `x`
    |              |
    |              variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `y`
+   |
+LL -         ((Ok(x) if y) | (Err(y) if x),) => x && y,
+LL +         ((Ok(y) if y) | (Err(y) if x),) => x && y,
+   |
 
 error[E0408]: variable `x` is not bound in all patterns
   --> $DIR/name-resolution.rs:63:28
diff --git a/tests/ui/resolve/resolve-inconsistent-names.rs b/tests/ui/resolve/resolve-inconsistent-names.rs
index 9a40b20346c..bf74a4ba0f3 100644
--- a/tests/ui/resolve/resolve-inconsistent-names.rs
+++ b/tests/ui/resolve/resolve-inconsistent-names.rs
@@ -10,8 +10,10 @@ pub mod m {
 fn main() {
     let y = 1;
     match y {
-       a | b => {} //~  ERROR variable `a` is not bound in all patterns
-                   //~| ERROR variable `b` is not bound in all patterns
+        a | b => {} //~  ERROR variable `a` is not bound in all patterns
+        //~| ERROR variable `b` is not bound in all patterns
+        //~| HELP you might have meant to use the similarly named previously used binding `a`
+        //~| HELP you might have meant to use the similarly named previously used binding `b`
     }
 
     let x = (E::A, E::B);
diff --git a/tests/ui/resolve/resolve-inconsistent-names.stderr b/tests/ui/resolve/resolve-inconsistent-names.stderr
index 5fac622eef2..152c16ad404 100644
--- a/tests/ui/resolve/resolve-inconsistent-names.stderr
+++ b/tests/ui/resolve/resolve-inconsistent-names.stderr
@@ -1,21 +1,33 @@
 error[E0408]: variable `b` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:13:8
+  --> $DIR/resolve-inconsistent-names.rs:13:9
+   |
+LL |         a | b => {}
+   |         ^   - variable not in all patterns
+   |         |
+   |         pattern doesn't bind `b`
+   |
+help: you might have meant to use the similarly named previously used binding `a`
+   |
+LL -         a | b => {}
+LL +         a | a => {}
    |
-LL |        a | b => {}
-   |        ^   - variable not in all patterns
-   |        |
-   |        pattern doesn't bind `b`
 
 error[E0408]: variable `a` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:13:12
+  --> $DIR/resolve-inconsistent-names.rs:13:13
+   |
+LL |         a | b => {}
+   |         -   ^ pattern doesn't bind `a`
+   |         |
+   |         variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `b`
+   |
+LL -         a | b => {}
+LL +         b | b => {}
    |
-LL |        a | b => {}
-   |        -   ^ pattern doesn't bind `a`
-   |        |
-   |        variable not in all patterns
 
 error[E0408]: variable `c` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:19:9
+  --> $DIR/resolve-inconsistent-names.rs:21:9
    |
 LL |         (A, B) | (ref B, c) | (c, A) => ()
    |         ^^^^^^           -     - variable not in all patterns
@@ -24,7 +36,7 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |         pattern doesn't bind `c`
 
 error[E0408]: variable `A` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:19:18
+  --> $DIR/resolve-inconsistent-names.rs:21:18
    |
 LL |         (A, B) | (ref B, c) | (c, A) => ()
    |          -       ^^^^^^^^^^       - variable not in all patterns
@@ -38,7 +50,7 @@ LL |         (E::A, B) | (ref B, c) | (c, A) => ()
    |          +++
 
 error[E0408]: variable `B` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:19:31
+  --> $DIR/resolve-inconsistent-names.rs:21:31
    |
 LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             -         -       ^^^^^^ pattern doesn't bind `B`
@@ -47,7 +59,7 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             variable not in all patterns
 
 error[E0409]: variable `B` is bound inconsistently across alternatives separated by `|`
-  --> $DIR/resolve-inconsistent-names.rs:19:23
+  --> $DIR/resolve-inconsistent-names.rs:21:23
    |
 LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             -         ^ bound in different ways
@@ -55,7 +67,7 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             first binding
 
 error[E0408]: variable `Const2` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:31:9
+  --> $DIR/resolve-inconsistent-names.rs:33:9
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |         ^^^^^^^^^^^       ------ variable not in all patterns
@@ -68,7 +80,7 @@ LL |         (CONST1, _) | (_, m::Const2) => ()
    |                           +++
 
 error[E0408]: variable `CONST1` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:31:23
+  --> $DIR/resolve-inconsistent-names.rs:33:23
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |          ------       ^^^^^^^^^^^ pattern doesn't bind `CONST1`
@@ -82,7 +94,7 @@ LL |     const CONST1: usize = 10;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0308]: mismatched types
-  --> $DIR/resolve-inconsistent-names.rs:19:19
+  --> $DIR/resolve-inconsistent-names.rs:21:19
    |
 LL |     match x {
    |           - this expression has type `(E, E)`
diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr
index 73fcc5c8477..eb18969c3c0 100644
--- a/tests/ui/span/issue-39698.stderr
+++ b/tests/ui/span/issue-39698.stderr
@@ -7,6 +7,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |         |                      |    pattern doesn't bind `b`
    |         |                      variable not in all patterns
    |         pattern doesn't bind `b`
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, d) | T::T2(d, c) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `c` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:9
@@ -17,6 +23,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |         |             |                   variable not in all patterns
    |         |             pattern doesn't bind `c`
    |         pattern doesn't bind `c`
+   |
+help: you might have meant to use the similarly named previously used binding `d`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, d) | T::T2(d, b) | T::T3(d) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `a` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:23
@@ -27,6 +39,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |               |       |             pattern doesn't bind `a`
    |               |       pattern doesn't bind `a`
    |               variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(c, d) | T::T2(d, b) | T::T3(c) | T::T4(c) => { println!("{:?}", a); }
+   |
 
 error[E0408]: variable `d` is not bound in all patterns
   --> $DIR/issue-39698.rs:10:37
@@ -37,6 +55,12 @@ LL |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}
    |                  |          |       pattern doesn't bind `d`
    |                  |          variable not in all patterns
    |                  variable not in all patterns
+   |
+help: you might have meant to use the similarly named previously used binding `c`
+   |
+LL -         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+LL +         T::T1(a, c) | T::T2(c, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |
 
 error[E0381]: used binding `a` is possibly-uninitialized
   --> $DIR/issue-39698.rs:10:79