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``
This commit is contained in:
Matthias Krüger 2022-06-25 15:14:14 +02:00 committed by GitHub
commit 1f923c2a41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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(_) => "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
}

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

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