Skip to content

Commit 1f923c2

Browse files
authored
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``
2 parents ea07b96 + 1dfb53b commit 1f923c2

File tree

5 files changed

+173
-1
lines changed

5 files changed

+173
-1
lines changed

compiler/rustc_typeck/src/check/pat.rs

+51
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
663663
ast::Mutability::Not => "",
664664
};
665665

666+
let mut_var_suggestion = 'block: {
667+
if !matches!(mutbl, ast::Mutability::Mut) {
668+
break 'block None;
669+
}
670+
671+
let ident_kind = match binding_parent {
672+
hir::Node::Param(_) => "parameter",
673+
hir::Node::Local(_) => "variable",
674+
hir::Node::Arm(_) => "binding",
675+
676+
// Provide diagnostics only if the parent pattern is struct-like,
677+
// i.e. where `mut binding` makes sense
678+
hir::Node::Pat(Pat { kind, .. }) => match kind {
679+
PatKind::Struct(..)
680+
| PatKind::TupleStruct(..)
681+
| PatKind::Or(..)
682+
| PatKind::Tuple(..)
683+
| PatKind::Slice(..) => "binding",
684+
685+
PatKind::Wild
686+
| PatKind::Binding(..)
687+
| PatKind::Path(..)
688+
| PatKind::Box(..)
689+
| PatKind::Ref(..)
690+
| PatKind::Lit(..)
691+
| PatKind::Range(..) => break 'block None,
692+
},
693+
694+
// Don't provide suggestions in other cases
695+
_ => break 'block None,
696+
};
697+
698+
Some((
699+
pat.span,
700+
format!("to declare a mutable {ident_kind} use"),
701+
format!("mut {binding}"),
702+
))
703+
704+
};
705+
666706
match binding_parent {
667707
// Check that there is explicit type (ie this is not a closure param with inferred type)
668708
// so we don't suggest moving something to the type that does not exist
@@ -675,6 +715,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
675715
],
676716
Applicability::MachineApplicable
677717
);
718+
719+
if let Some((sp, msg, sugg)) = mut_var_suggestion {
720+
err.span_note(sp, format!("{msg}: `{sugg}`"));
721+
}
678722
}
679723
hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
680724
// rely on match ergonomics or it might be nested `&&pat`
@@ -684,6 +728,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
684728
"",
685729
Applicability::MaybeIncorrect,
686730
);
731+
732+
if let Some((sp, msg, sugg)) = mut_var_suggestion {
733+
err.span_note(sp, format!("{msg}: `{sugg}`"));
734+
}
735+
}
736+
_ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
737+
err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
687738
}
688739
_ => {} // don't provide suggestions in other cases #55175
689740
}

src/test/ui/mismatched_types/ref-pat-suggestions.fixed

+13
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,17 @@ fn main() {
2121
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
2222
let _ = |&_a: &u32| (); //~ ERROR mismatched types
2323
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
24+
25+
#[allow(unused_mut)]
26+
{
27+
struct S(u8);
28+
29+
let mut _a = 0; //~ ERROR mismatched types
30+
let S(_b) = S(0); //~ ERROR mismatched types
31+
let (_c,) = (0,); //~ ERROR mismatched types
32+
33+
match 0 {
34+
_d => {} //~ ERROR mismatched types
35+
}
36+
}
2437
}

src/test/ui/mismatched_types/ref-pat-suggestions.rs

+13
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,17 @@ fn main() {
2121
let _ = |&mut &_a: &mut u32| (); //~ ERROR mismatched types
2222
let _ = |&&mut _a: &u32| (); //~ ERROR mismatched types
2323
let _ = |&mut &mut _a: &mut u32| (); //~ ERROR mismatched types
24+
25+
#[allow(unused_mut)]
26+
{
27+
struct S(u8);
28+
29+
let &mut _a = 0; //~ ERROR mismatched types
30+
let S(&mut _b) = S(0); //~ ERROR mismatched types
31+
let (&mut _c,) = (0,); //~ ERROR mismatched types
32+
33+
match 0 {
34+
&mut _d => {} //~ ERROR mismatched types
35+
}
36+
}
2437
}

src/test/ui/mismatched_types/ref-pat-suggestions.stderr

+91-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ LL | fn _f1(&mut _a: u32) {}
2424
|
2525
= note: expected type `u32`
2626
found mutable reference `&mut _`
27+
note: to declare a mutable parameter use: `mut _a`
28+
--> $DIR/ref-pat-suggestions.rs:4:8
29+
|
30+
LL | fn _f1(&mut _a: u32) {}
31+
| ^^^^^^^
2732
help: to take parameter `_a` by reference, move `&mut` to the type
2833
|
2934
LL - fn _f1(&mut _a: u32) {}
@@ -122,6 +127,11 @@ LL | let _: fn(u32) = |&mut _a| ();
122127
|
123128
= note: expected type `u32`
124129
found mutable reference `&mut _`
130+
note: to declare a mutable parameter use: `mut _a`
131+
--> $DIR/ref-pat-suggestions.rs:12:23
132+
|
133+
LL | let _: fn(u32) = |&mut _a| ();
134+
| ^^^^^^^
125135
help: consider removing `&mut` from the pattern
126136
|
127137
LL - let _: fn(u32) = |&mut _a| ();
@@ -222,6 +232,11 @@ LL | let _ = |&mut _a: u32| ();
222232
|
223233
= note: expected type `u32`
224234
found mutable reference `&mut _`
235+
note: to declare a mutable parameter use: `mut _a`
236+
--> $DIR/ref-pat-suggestions.rs:19:14
237+
|
238+
LL | let _ = |&mut _a: u32| ();
239+
| ^^^^^^^
225240
help: to take parameter `_a` by reference, move `&mut` to the type
226241
|
227242
LL - let _ = |&mut _a: u32| ();
@@ -292,6 +307,81 @@ LL - let _ = |&mut &mut _a: &mut u32| ();
292307
LL + let _ = |&mut _a: &mut u32| ();
293308
|
294309

295-
error: aborting due to 18 previous errors
310+
error[E0308]: mismatched types
311+
--> $DIR/ref-pat-suggestions.rs:29:13
312+
|
313+
LL | let &mut _a = 0;
314+
| ^^^^^^^ - this expression has type `{integer}`
315+
| |
316+
| expected integer, found `&mut _`
317+
| help: to declare a mutable variable use: `mut _a`
318+
|
319+
= note: expected type `{integer}`
320+
found mutable reference `&mut _`
321+
322+
error[E0308]: mismatched types
323+
--> $DIR/ref-pat-suggestions.rs:30:15
324+
|
325+
LL | let S(&mut _b) = S(0);
326+
| ^^^^^^^ ---- this expression has type `S`
327+
| |
328+
| expected `u8`, found `&mut _`
329+
|
330+
= note: expected type `u8`
331+
found mutable reference `&mut _`
332+
note: to declare a mutable binding use: `mut _b`
333+
--> $DIR/ref-pat-suggestions.rs:30:15
334+
|
335+
LL | let S(&mut _b) = S(0);
336+
| ^^^^^^^
337+
help: consider removing `&mut` from the pattern
338+
|
339+
LL - let S(&mut _b) = S(0);
340+
LL + let S(_b) = S(0);
341+
|
342+
343+
error[E0308]: mismatched types
344+
--> $DIR/ref-pat-suggestions.rs:31:14
345+
|
346+
LL | let (&mut _c,) = (0,);
347+
| ^^^^^^^ ---- this expression has type `({integer},)`
348+
| |
349+
| expected integer, found `&mut _`
350+
|
351+
= note: expected type `{integer}`
352+
found mutable reference `&mut _`
353+
note: to declare a mutable binding use: `mut _c`
354+
--> $DIR/ref-pat-suggestions.rs:31:14
355+
|
356+
LL | let (&mut _c,) = (0,);
357+
| ^^^^^^^
358+
help: consider removing `&mut` from the pattern
359+
|
360+
LL - let (&mut _c,) = (0,);
361+
LL + let (_c,) = (0,);
362+
|
363+
364+
error[E0308]: mismatched types
365+
--> $DIR/ref-pat-suggestions.rs:34:13
366+
|
367+
LL | match 0 {
368+
| - this expression has type `{integer}`
369+
LL | &mut _d => {}
370+
| ^^^^^^^ expected integer, found `&mut _`
371+
|
372+
= note: expected type `{integer}`
373+
found mutable reference `&mut _`
374+
note: to declare a mutable binding use: `mut _d`
375+
--> $DIR/ref-pat-suggestions.rs:34:13
376+
|
377+
LL | &mut _d => {}
378+
| ^^^^^^^
379+
help: consider removing `&mut` from the pattern
380+
|
381+
LL - &mut _d => {}
382+
LL + _d => {}
383+
|
384+
385+
error: aborting due to 22 previous errors
296386

297387
For more information about this error, try `rustc --explain E0308`.

src/test/ui/pattern/for-loop-bad-item.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ LL | for ((_, _), (&mut c, _)) in &mut map {
88
|
99
= note: expected type `char`
1010
found mutable reference `&mut _`
11+
note: to declare a mutable binding use: `mut c`
12+
--> $DIR/for-loop-bad-item.rs:7:19
13+
|
14+
LL | for ((_, _), (&mut c, _)) in &mut map {
15+
| ^^^^^^
1116
help: consider removing `&mut` from the pattern
1217
|
1318
LL - for ((_, _), (&mut c, _)) in &mut map {

0 commit comments

Comments
 (0)