Skip to content

Commit 2c937d0

Browse files
committed
Suggest ref mut for pattern matching assignment
1 parent 757b8ef commit 2c937d0

File tree

7 files changed

+147
-33
lines changed

7 files changed

+147
-33
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -3053,7 +3053,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
30533053
| None => (self.describe_any_place(place.as_ref()), assigned_span),
30543054
Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
30553055
};
3056-
30573056
let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
30583057
let msg = if from_arg {
30593058
"cannot assign to immutable argument"
@@ -3073,6 +3072,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
30733072
format!("mut {name}"),
30743073
Applicability::MachineApplicable,
30753074
);
3075+
if !from_arg && decl.has_pattern_match() {
3076+
err.span_suggestion(
3077+
decl.source_info.span,
3078+
"to modify the original value, take a borrow instead",
3079+
format!("ref mut {name}"),
3080+
Applicability::MaybeIncorrect,
3081+
);
3082+
}
30763083
}
30773084
err.span_label(span, msg);
30783085
self.buffer_error(err);

compiler/rustc_middle/src/mir/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,17 @@ impl<'tcx> LocalDecl<'tcx> {
10611061
)
10621062
}
10631063

1064+
pub fn has_pattern_match(&self) -> bool {
1065+
matches!(
1066+
self.local_info(),
1067+
LocalInfo::User(BindingForm::Var(VarBindingForm {
1068+
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
1069+
opt_match_place: Some((Some(_), _)),
1070+
..
1071+
}))
1072+
)
1073+
}
1074+
10641075
/// Returns `true` if local is definitely not a `ref ident` or
10651076
/// `ref mut ident` binding. (Such bindings cannot be made into
10661077
/// mutable bindings, but the inverse does not necessarily hold).

tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr

+50-20
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,86 @@ error[E0384]: cannot assign twice to immutable variable `x`
22
--> $DIR/borrowck-match-binding-is-assignment.rs:14:13
33
|
44
LL | x => {
5-
| -
6-
| |
7-
| first assignment to `x`
8-
| help: consider making this binding mutable: `mut x`
5+
| - first assignment to `x`
96
LL | x += 1;
107
| ^^^^^^ cannot assign twice to immutable variable
8+
|
9+
help: consider making this binding mutable
10+
|
11+
LL | mut x => {
12+
| ~~~~~
13+
help: to modify the original value, take a borrow instead
14+
|
15+
LL | ref mut x => {
16+
| ~~~~~~~~~
1117

1218
error[E0384]: cannot assign twice to immutable variable `x`
1319
--> $DIR/borrowck-match-binding-is-assignment.rs:20:13
1420
|
1521
LL | E::Foo(x) => {
16-
| -
17-
| |
18-
| first assignment to `x`
19-
| help: consider making this binding mutable: `mut x`
22+
| - first assignment to `x`
2023
LL | x += 1;
2124
| ^^^^^^ cannot assign twice to immutable variable
25+
|
26+
help: consider making this binding mutable
27+
|
28+
LL | E::Foo(mut x) => {
29+
| ~~~~~
30+
help: to modify the original value, take a borrow instead
31+
|
32+
LL | E::Foo(ref mut x) => {
33+
| ~~~~~~~~~
2234

2335
error[E0384]: cannot assign twice to immutable variable `x`
2436
--> $DIR/borrowck-match-binding-is-assignment.rs:26:13
2537
|
2638
LL | S { bar: x } => {
27-
| -
28-
| |
29-
| first assignment to `x`
30-
| help: consider making this binding mutable: `mut x`
39+
| - first assignment to `x`
3140
LL | x += 1;
3241
| ^^^^^^ cannot assign twice to immutable variable
42+
|
43+
help: consider making this binding mutable
44+
|
45+
LL | S { bar: mut x } => {
46+
| ~~~~~
47+
help: to modify the original value, take a borrow instead
48+
|
49+
LL | S { bar: ref mut x } => {
50+
| ~~~~~~~~~
3351

3452
error[E0384]: cannot assign twice to immutable variable `x`
3553
--> $DIR/borrowck-match-binding-is-assignment.rs:32:13
3654
|
3755
LL | (x,) => {
38-
| -
39-
| |
40-
| first assignment to `x`
41-
| help: consider making this binding mutable: `mut x`
56+
| - first assignment to `x`
4257
LL | x += 1;
4358
| ^^^^^^ cannot assign twice to immutable variable
59+
|
60+
help: consider making this binding mutable
61+
|
62+
LL | (mut x,) => {
63+
| ~~~~~
64+
help: to modify the original value, take a borrow instead
65+
|
66+
LL | (ref mut x,) => {
67+
| ~~~~~~~~~
4468

4569
error[E0384]: cannot assign twice to immutable variable `x`
4670
--> $DIR/borrowck-match-binding-is-assignment.rs:38:13
4771
|
4872
LL | [x,_,_] => {
49-
| -
50-
| |
51-
| first assignment to `x`
52-
| help: consider making this binding mutable: `mut x`
73+
| - first assignment to `x`
5374
LL | x += 1;
5475
| ^^^^^^ cannot assign twice to immutable variable
76+
|
77+
help: consider making this binding mutable
78+
|
79+
LL | [mut x,_,_] => {
80+
| ~~~~~
81+
help: to modify the original value, take a borrow instead
82+
|
83+
LL | [ref mut x,_,_] => {
84+
| ~~~~~~~~~
5585

5686
error: aborting due to 5 previous errors
5787

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
let y = Some(0);
3+
if let Some(x) = y {
4+
x = 2; //~ ERROR cannot assign twice to immutable variable `x`
5+
}
6+
7+
let mut arr = [1, 2, 3];
8+
let [x, ref xs_hold @ ..] = arr;
9+
x = 0; //~ ERROR cannot assign twice to immutable variable `x`
10+
eprintln!("{:?}", arr);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error[E0384]: cannot assign twice to immutable variable `x`
2+
--> $DIR/issue-118596-suggest-ref-mut.rs:4:9
3+
|
4+
LL | if let Some(x) = y {
5+
| - first assignment to `x`
6+
LL | x = 2;
7+
| ^^^^^ cannot assign twice to immutable variable
8+
|
9+
help: consider making this binding mutable
10+
|
11+
LL | if let Some(mut x) = y {
12+
| ~~~~~
13+
help: to modify the original value, take a borrow instead
14+
|
15+
LL | if let Some(ref mut x) = y {
16+
| ~~~~~~~~~
17+
18+
error[E0384]: cannot assign twice to immutable variable `x`
19+
--> $DIR/issue-118596-suggest-ref-mut.rs:9:5
20+
|
21+
LL | let [x, ref xs_hold @ ..] = arr;
22+
| - first assignment to `x`
23+
LL | x = 0;
24+
| ^^^^^ cannot assign twice to immutable variable
25+
|
26+
help: consider making this binding mutable
27+
|
28+
LL | let [mut x, ref xs_hold @ ..] = arr;
29+
| ~~~~~
30+
help: to modify the original value, take a borrow instead
31+
|
32+
LL | let [ref mut x, ref xs_hold @ ..] = arr;
33+
| ~~~~~~~~~
34+
35+
error: aborting due to 2 previous errors
36+
37+
For more information about this error, try `rustc --explain E0384`.

tests/ui/mut/mut-pattern-internal-mutability.stderr

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ error[E0384]: cannot assign twice to immutable variable `x`
22
--> $DIR/mut-pattern-internal-mutability.rs:5:5
33
|
44
LL | let &mut x = foo;
5-
| -
6-
| |
7-
| first assignment to `x`
8-
| help: consider making this binding mutable: `mut x`
5+
| - first assignment to `x`
96
LL | x += 1;
107
| ^^^^^^ cannot assign twice to immutable variable
8+
|
9+
help: consider making this binding mutable
10+
|
11+
LL | let &mut mut x = foo;
12+
| ~~~~~
13+
help: to modify the original value, take a borrow instead
14+
|
15+
LL | let &mut ref mut x = foo;
16+
| ~~~~~~~~~
1117

1218
error[E0506]: cannot assign to `*foo` because it is borrowed
1319
--> $DIR/mut-pattern-internal-mutability.rs:13:5

tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr

+20-8
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1`
1515
--> $DIR/borrowck-move-ref-pattern.rs:9:5
1616
|
1717
LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
18-
| ---
19-
| |
20-
| first assignment to `_x1`
21-
| help: consider making this binding mutable: `mut _x1`
18+
| --- first assignment to `_x1`
2219
LL | _x1 = U;
2320
| ^^^^^^^ cannot assign twice to immutable variable
21+
|
22+
help: consider making this binding mutable
23+
|
24+
LL | let [ref _x0_hold, mut _x1, ref xs_hold @ ..] = arr;
25+
| ~~~~~~~
26+
help: to modify the original value, take a borrow instead
27+
|
28+
LL | let [ref _x0_hold, ref mut _x1, ref xs_hold @ ..] = arr;
29+
| ~~~~~~~~~~~
2430

2531
error[E0505]: cannot move out of `arr[..]` because it is borrowed
2632
--> $DIR/borrowck-move-ref-pattern.rs:11:10
@@ -73,12 +79,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1`
7379
--> $DIR/borrowck-move-ref-pattern.rs:23:5
7480
|
7581
LL | let (ref _x0, _x1, ref _x2, ..) = tup;
76-
| ---
77-
| |
78-
| first assignment to `_x1`
79-
| help: consider making this binding mutable: `mut _x1`
82+
| --- first assignment to `_x1`
8083
LL | _x1 = U;
8184
| ^^^^^^^ cannot assign twice to immutable variable
85+
|
86+
help: consider making this binding mutable
87+
|
88+
LL | let (ref _x0, mut _x1, ref _x2, ..) = tup;
89+
| ~~~~~~~
90+
help: to modify the original value, take a borrow instead
91+
|
92+
LL | let (ref _x0, ref mut _x1, ref _x2, ..) = tup;
93+
| ~~~~~~~~~~~
8294

8395
error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
8496
--> $DIR/borrowck-move-ref-pattern.rs:24:20

0 commit comments

Comments
 (0)