about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-06-25 15:14:14 +0200
committerGitHub <noreply@github.com>2022-06-25 15:14:14 +0200
commit1f923c2a415288c4122800e0862e2c478a2ad9c9 (patch)
tree3915fc63ef97a2b39de400aeca5e6f7a4e6ac442
parentea07b969eacb4d932afba25ad64050719c7fe73a (diff)
parent1dfb53b7dad1d5f68466a68b068b8030d216ce3f (diff)
downloadrust-1f923c2a415288c4122800e0862e2c478a2ad9c9.tar.gz
rust-1f923c2a415288c4122800e0862e2c478a2ad9c9.zip
Rollup merge of #98431 - WaffleLapkin:mut_pat_suggestions, r=compiler-errors
Suggest defining variable as mutable on `&mut _` type mismatch in pats

Suggest writing `mut a` where `&mut a` was written but a non-ref type provided.

Since we still don't have "apply either one of the suggestions but not both" kind of thing, the interaction with the suggestion of removing `&[mut]` or moving it to the type is weird, and idk how to make it better..

r? ``@compiler-errors``
-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..e1ec9f13cd1 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(_) => "parameter",
+                    hir::Node::Local(_) => "variable",
+                    hir::Node::Arm(_) => "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(..) => "binding",
+
+                        PatKind::Wild
+                        | PatKind::Binding(..)
+                        | PatKind::Path(..)
+                        | PatKind::Box(..)
+                        | PatKind::Ref(..)
+                        | PatKind::Lit(..)
+                        | PatKind::Range(..) => break 'block None,
+                    },
+
+                    // Don't provide suggestions in other cases
+                    _ => break 'block None,
+                };
+
+                Some((
+                    pat.span,
+                    format!("to declare a mutable {ident_kind} use"),
+                    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..d9501a9bbc6 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 _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 _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 _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 _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 _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 _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 _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..f064a25a9c9 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 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 {