Suggest defining variable as mutable on &mut _ type mismatch in pats

This commit is contained in:
Maybe Waffle 2022-06-23 20:33:40 +04:00
parent 10f4ce324b
commit 3c7f1f1601
5 changed files with 173 additions and 1 deletions

View File

@ -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
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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`.

View File

@ -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 {