about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-06-23 20:33:40 +0400
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-06-23 21:16:32 +0400
commit3c7f1f16016d8a19a549f2c34a05cfdf8f79968b (patch)
treea53e1e1ef9d6aecbbd6c93f9ad45eab4546ac49f
parent10f4ce324baf7cfb7ce2b2096662b82b79204944 (diff)
downloadrust-3c7f1f16016d8a19a549f2c34a05cfdf8f79968b.tar.gz
rust-3c7f1f16016d8a19a549f2c34a05cfdf8f79968b.zip
Suggest defining variable as mutable on `&mut _` type mismatch in pats
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs51
-rw-r--r--src/test/ui/mismatched_types/ref-pat-suggestions.fixed13
-rw-r--r--src/test/ui/mismatched_types/ref-pat-suggestions.rs13
-rw-r--r--src/test/ui/mismatched_types/ref-pat-suggestions.stderr92
-rw-r--r--src/test/ui/pattern/for-loop-bad-item.stderr5
5 files changed, 173 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index f45b94bcdff..58fd11200c9 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -663,6 +663,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ast::Mutability::Not => "",
             };
 
+            let mut_var_suggestion = 'block: {
+                if !matches!(mutbl, ast::Mutability::Mut) {
+                    break 'block None;
+                }
+
+                let ident_kind = match binding_parent {
+                    hir::Node::Param(_) => Some("parameter"),
+                    hir::Node::Local(_) => Some("variable"),
+                    hir::Node::Arm(_) => Some("binding"),
+
+                    // Provide diagnostics only if the parent pattern is struct-like,
+                    // i.e. where `mut binding` makes sense
+                    hir::Node::Pat(Pat { kind, .. }) => match kind {
+                        PatKind::Struct(..)
+                        | PatKind::TupleStruct(..)
+                        | PatKind::Or(..)
+                        | PatKind::Tuple(..)
+                        | PatKind::Slice(..) => Some("binding"),
+
+                        PatKind::Wild
+                        | PatKind::Binding(..)
+                        | PatKind::Path(..)
+                        | PatKind::Box(..)
+                        | PatKind::Ref(..)
+                        | PatKind::Lit(..)
+                        | PatKind::Range(..) => None,
+                    },
+
+                    // Don't provide suggestions in other cases
+                    _ => None,
+                };
+
+                ident_kind.map(|thing| (
+                    pat.span,
+                    format!("to declare a mutable {thing} use `mut variable_name`"),
+                    format!("mut {binding}"),
+                ))
+
+            };
+
             match binding_parent {
                 // Check that there is explicit type (ie this is not a closure param with inferred type)
                 // so we don't suggest moving something to the type that does not exist
@@ -675,6 +715,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ],
                         Applicability::MachineApplicable
                     );
+
+                    if let Some((sp, msg, sugg)) = mut_var_suggestion {
+                        err.span_note(sp, format!("{msg}: `{sugg}`"));
+                    }
                 }
                 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
                     // rely on match ergonomics or it might be nested `&&pat`
@@ -684,6 +728,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "",
                         Applicability::MaybeIncorrect,
                     );
+
+                    if let Some((sp, msg, sugg)) = mut_var_suggestion {
+                        err.span_note(sp, format!("{msg}: `{sugg}`"));
+                    }
+                }
+                _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
+                    err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
                 }
                 _ => {} // don't provide suggestions in other cases #55175
             }
diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.fixed b/src/test/ui/mismatched_types/ref-pat-suggestions.fixed
index ab8483eef49..d50acd1ac62 100644
--- a/src/test/ui/mismatched_types/ref-pat-suggestions.fixed
+++ b/src/test/ui/mismatched_types/ref-pat-suggestions.fixed
@@ -21,4 +21,17 @@ fn main() {
     let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
     let _ = |&_a: &u32| (); //~ ERROR mismatched types
     let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
+
+    #[allow(unused_mut)]
+    {
+        struct S(u8);
+
+        let mut _a = 0; //~ ERROR mismatched types
+        let S(_b) = S(0); //~ ERROR mismatched types
+        let (_c,) = (0,); //~ ERROR mismatched types
+
+        match 0 {
+            _d => {} //~ ERROR mismatched types
+        }
+    }
 }
diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.rs b/src/test/ui/mismatched_types/ref-pat-suggestions.rs
index 7e55539aa3d..1a77f687692 100644
--- a/src/test/ui/mismatched_types/ref-pat-suggestions.rs
+++ b/src/test/ui/mismatched_types/ref-pat-suggestions.rs
@@ -21,4 +21,17 @@ fn main() {
     let _ = |&mut &_a: &mut u32| (); //~ ERROR mismatched types
     let _ = |&&mut _a: &u32| (); //~ ERROR mismatched types
     let _ = |&mut &mut _a: &mut u32| (); //~ ERROR mismatched types
+
+    #[allow(unused_mut)]
+    {
+        struct S(u8);
+
+        let &mut _a = 0; //~ ERROR mismatched types
+        let S(&mut _b) = S(0); //~ ERROR mismatched types
+        let (&mut _c,) = (0,); //~ ERROR mismatched types
+
+        match 0 {
+            &mut _d => {} //~ ERROR mismatched types
+        }
+    }
 }
diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.stderr b/src/test/ui/mismatched_types/ref-pat-suggestions.stderr
index 0e8f8853fb7..cd86bb532ab 100644
--- a/src/test/ui/mismatched_types/ref-pat-suggestions.stderr
+++ b/src/test/ui/mismatched_types/ref-pat-suggestions.stderr
@@ -24,6 +24,11 @@ LL | fn _f1(&mut _a: u32) {}
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
+note: to declare a mutable parameter use `mut variable_name`: `mut _a`
+  --> $DIR/ref-pat-suggestions.rs:4:8
+   |
+LL | fn _f1(&mut _a: u32) {}
+   |        ^^^^^^^
 help: to take parameter `_a` by reference, move `&mut` to the type
    |
 LL - fn _f1(&mut _a: u32) {}
@@ -122,6 +127,11 @@ LL |     let _: fn(u32) = |&mut _a| ();
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
+note: to declare a mutable parameter use `mut variable_name`: `mut _a`
+  --> $DIR/ref-pat-suggestions.rs:12:23
+   |
+LL |     let _: fn(u32) = |&mut _a| ();
+   |                       ^^^^^^^
 help: consider removing `&mut` from the pattern
    |
 LL -     let _: fn(u32) = |&mut _a| ();
@@ -222,6 +232,11 @@ LL |     let _ = |&mut _a: u32| ();
    |
    = note:           expected type `u32`
            found mutable reference `&mut _`
+note: to declare a mutable parameter use `mut variable_name`: `mut _a`
+  --> $DIR/ref-pat-suggestions.rs:19:14
+   |
+LL |     let _ = |&mut _a: u32| ();
+   |              ^^^^^^^
 help: to take parameter `_a` by reference, move `&mut` to the type
    |
 LL -     let _ = |&mut _a: u32| ();
@@ -292,6 +307,81 @@ LL -     let _ = |&mut &mut _a: &mut u32| ();
 LL +     let _ = |&mut _a: &mut u32| ();
    |
 
-error: aborting due to 18 previous errors
+error[E0308]: mismatched types
+  --> $DIR/ref-pat-suggestions.rs:29:13
+   |
+LL |         let &mut _a = 0;
+   |             ^^^^^^^   - this expression has type `{integer}`
+   |             |
+   |             expected integer, found `&mut _`
+   |             help: to declare a mutable variable use `mut variable_name`: `mut _a`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref-pat-suggestions.rs:30:15
+   |
+LL |         let S(&mut _b) = S(0);
+   |               ^^^^^^^    ---- this expression has type `S`
+   |               |
+   |               expected `u8`, found `&mut _`
+   |
+   = note:           expected type `u8`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use `mut variable_name`: `mut _b`
+  --> $DIR/ref-pat-suggestions.rs:30:15
+   |
+LL |         let S(&mut _b) = S(0);
+   |               ^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -         let S(&mut _b) = S(0);
+LL +         let S(_b) = S(0);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/ref-pat-suggestions.rs:31:14
+   |
+LL |         let (&mut _c,) = (0,);
+   |              ^^^^^^^     ---- this expression has type `({integer},)`
+   |              |
+   |              expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use `mut variable_name`: `mut _c`
+  --> $DIR/ref-pat-suggestions.rs:31:14
+   |
+LL |         let (&mut _c,) = (0,);
+   |              ^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -         let (&mut _c,) = (0,);
+LL +         let (_c,) = (0,);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/ref-pat-suggestions.rs:34:13
+   |
+LL |         match 0 {
+   |               - this expression has type `{integer}`
+LL |             &mut _d => {}
+   |             ^^^^^^^ expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use `mut variable_name`: `mut _d`
+  --> $DIR/ref-pat-suggestions.rs:34:13
+   |
+LL |             &mut _d => {}
+   |             ^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -             &mut _d => {}
+LL +             _d => {}
+   |
+
+error: aborting due to 22 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/pattern/for-loop-bad-item.stderr b/src/test/ui/pattern/for-loop-bad-item.stderr
index ad737f7bd15..212d66f6497 100644
--- a/src/test/ui/pattern/for-loop-bad-item.stderr
+++ b/src/test/ui/pattern/for-loop-bad-item.stderr
@@ -8,6 +8,11 @@ LL |     for ((_, _), (&mut c, _)) in &mut map {
    |
    = note:           expected type `char`
            found mutable reference `&mut _`
+note: to declare a mutable binding use `mut variable_name`: `mut c`
+  --> $DIR/for-loop-bad-item.rs:7:19
+   |
+LL |     for ((_, _), (&mut c, _)) in &mut map {
+   |                   ^^^^^^
 help: consider removing `&mut` from the pattern
    |
 LL -     for ((_, _), (&mut c, _)) in &mut map {