Skip to content

Commit e4368de

Browse files
committed
Suggestion for call on immutable binding of mutable type
When calling a method requiring a mutable self borrow on an inmutable to a mutable borrow of the type, suggest making the binding mutable. Fix #83241.
1 parent 757a65b commit e4368de

File tree

6 files changed

+188
-34
lines changed

6 files changed

+188
-34
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

+53-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
55
use rustc_middle::ty::{self, Ty, TyCtxt};
66
use rustc_middle::{
77
hir::place::PlaceBase,
8-
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
8+
mir::{
9+
self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
10+
LocalKind, Location,
11+
},
912
};
1013
use rustc_span::source_map::DesugaringKind;
1114
use rustc_span::symbol::{kw, Symbol};
@@ -241,13 +244,56 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
241244
.map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local]))
242245
.unwrap_or(false) =>
243246
{
247+
let decl = &self.body.local_decls[local];
244248
err.span_label(span, format!("cannot {ACT}", ACT = act));
245-
err.span_suggestion(
246-
span,
247-
"try removing `&mut` here",
248-
String::new(),
249-
Applicability::MaybeIncorrect,
250-
);
249+
if let Some(mir::Statement {
250+
source_info,
251+
kind:
252+
mir::StatementKind::Assign(box (
253+
_,
254+
mir::Rvalue::Ref(
255+
_,
256+
mir::BorrowKind::Mut { allow_two_phase_borrow: false },
257+
_,
258+
),
259+
)),
260+
..
261+
}) = &self.body[location.block].statements.get(location.statement_index)
262+
{
263+
match decl.local_info {
264+
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
265+
mir::VarBindingForm {
266+
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
267+
opt_ty_info: Some(sp),
268+
opt_match_place: _,
269+
pat_span: _,
270+
},
271+
)))) => {
272+
err.span_note(sp, "the binding is already a mutable borrow");
273+
}
274+
_ => {
275+
err.span_note(
276+
decl.source_info.span,
277+
"the binding is already a mutable borrow",
278+
);
279+
}
280+
}
281+
err.span_help(source_info.span, "try removing `&mut` here");
282+
} else if decl.mutability == Mutability::Not
283+
&& !matches!(
284+
decl.local_info,
285+
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
286+
ImplicitSelfKind::MutRef
287+
))))
288+
)
289+
{
290+
err.span_suggestion_verbose(
291+
decl.source_info.span.shrink_to_lo(),
292+
"consider making the binding mutable",
293+
"mut ".to_string(),
294+
Applicability::MachineApplicable,
295+
);
296+
}
251297
}
252298

253299
// We want to suggest users use `let mut` for local (user

src/test/ui/borrowck/mut-borrow-of-mut-ref.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,36 @@
22
#![crate_type = "rlib"]
33

44
pub fn f(b: &mut i32) {
5-
g(&mut b);
5+
//~^ NOTE the binding is already a mutable borrow
6+
//~| NOTE the binding is already a mutable borrow
7+
h(&mut b);
68
//~^ ERROR cannot borrow
9+
//~| NOTE cannot borrow as mutable
710
//~| HELP try removing `&mut` here
811
g(&mut &mut b);
912
//~^ ERROR cannot borrow
13+
//~| NOTE cannot borrow as mutable
1014
//~| HELP try removing `&mut` here
1115
}
1216

13-
pub fn g(_: &mut i32) {}
17+
pub fn g(b: &mut i32) { //~ NOTE the binding is already a mutable borrow
18+
h(&mut &mut b);
19+
//~^ ERROR cannot borrow
20+
//~| NOTE cannot borrow as mutable
21+
//~| HELP try removing `&mut` here
22+
}
23+
24+
pub fn h(_: &mut i32) {}
25+
26+
trait Foo {
27+
fn bar(&mut self);
28+
}
29+
30+
impl Foo for &mut String {
31+
fn bar(&mut self) {}
32+
}
33+
34+
pub fn baz(f: &mut String) { //~ HELP consider making the binding mutable
35+
f.bar(); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable
36+
//~^ NOTE cannot borrow as mutable
37+
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,65 @@
11
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
2-
--> $DIR/mut-borrow-of-mut-ref.rs:5:7
2+
--> $DIR/mut-borrow-of-mut-ref.rs:7:7
33
|
4-
LL | g(&mut b);
4+
LL | h(&mut b);
5+
| ^^^^^^ cannot borrow as mutable
6+
|
7+
note: the binding is already a mutable borrow
8+
--> $DIR/mut-borrow-of-mut-ref.rs:4:13
9+
|
10+
LL | pub fn f(b: &mut i32) {
11+
| ^^^^^^^^
12+
help: try removing `&mut` here
13+
--> $DIR/mut-borrow-of-mut-ref.rs:7:7
14+
|
15+
LL | h(&mut b);
516
| ^^^^^^
6-
| |
7-
| cannot borrow as mutable
8-
| help: try removing `&mut` here
917

1018
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
11-
--> $DIR/mut-borrow-of-mut-ref.rs:8:12
19+
--> $DIR/mut-borrow-of-mut-ref.rs:11:12
1220
|
1321
LL | g(&mut &mut b);
22+
| ^^^^^^ cannot borrow as mutable
23+
|
24+
note: the binding is already a mutable borrow
25+
--> $DIR/mut-borrow-of-mut-ref.rs:4:13
26+
|
27+
LL | pub fn f(b: &mut i32) {
28+
| ^^^^^^^^
29+
help: try removing `&mut` here
30+
--> $DIR/mut-borrow-of-mut-ref.rs:11:12
31+
|
32+
LL | g(&mut &mut b);
33+
| ^^^^^^
34+
35+
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
36+
--> $DIR/mut-borrow-of-mut-ref.rs:18:12
37+
|
38+
LL | h(&mut &mut b);
39+
| ^^^^^^ cannot borrow as mutable
40+
|
41+
note: the binding is already a mutable borrow
42+
--> $DIR/mut-borrow-of-mut-ref.rs:17:13
43+
|
44+
LL | pub fn g(b: &mut i32) {
45+
| ^^^^^^^^
46+
help: try removing `&mut` here
47+
--> $DIR/mut-borrow-of-mut-ref.rs:18:12
48+
|
49+
LL | h(&mut &mut b);
1450
| ^^^^^^
15-
| |
16-
| cannot borrow as mutable
17-
| help: try removing `&mut` here
1851

19-
error: aborting due to 2 previous errors
52+
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
53+
--> $DIR/mut-borrow-of-mut-ref.rs:35:5
54+
|
55+
LL | f.bar();
56+
| ^ cannot borrow as mutable
57+
|
58+
help: consider making the binding mutable
59+
|
60+
LL | pub fn baz(mut f: &mut String) {
61+
| ^^^
62+
63+
error: aborting due to 4 previous errors
2064

2165
For more information about this error, try `rustc --explain E0596`.

src/test/ui/did_you_mean/issue-31424.stderr

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
22
--> $DIR/issue-31424.rs:7:9
33
|
4+
LL | (&mut self).bar();
5+
| ^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
note: the binding is already a mutable borrow
8+
--> $DIR/issue-31424.rs:6:12
9+
|
10+
LL | fn foo(&mut self) {
11+
| ^^^^^^^^^
12+
help: try removing `&mut` here
13+
--> $DIR/issue-31424.rs:7:9
14+
|
415
LL | (&mut self).bar();
516
| ^^^^^^^^^^^
6-
| |
7-
| cannot borrow as mutable
8-
| help: try removing `&mut` here
917

1018
warning: function cannot return without recursing
1119
--> $DIR/issue-31424.rs:13:5
@@ -22,11 +30,19 @@ LL | (&mut self).bar();
2230
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
2331
--> $DIR/issue-31424.rs:16:9
2432
|
33+
LL | (&mut self).bar();
34+
| ^^^^^^^^^^^ cannot borrow as mutable
35+
|
36+
note: the binding is already a mutable borrow
37+
--> $DIR/issue-31424.rs:13:18
38+
|
39+
LL | fn bar(self: &mut Self) {
40+
| ^^^^^^^^^
41+
help: try removing `&mut` here
42+
--> $DIR/issue-31424.rs:16:9
43+
|
2544
LL | (&mut self).bar();
2645
| ^^^^^^^^^^^
27-
| |
28-
| cannot borrow as mutable
29-
| help: try removing `&mut` here
3046

3147
error: aborting due to 2 previous errors; 1 warning emitted
3248

src/test/ui/did_you_mean/issue-34126.stderr

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
22
--> $DIR/issue-34126.rs:6:18
33
|
4+
LL | self.run(&mut self);
5+
| ^^^^^^^^^ cannot borrow as mutable
6+
|
7+
note: the binding is already a mutable borrow
8+
--> $DIR/issue-34126.rs:5:14
9+
|
10+
LL | fn start(&mut self) {
11+
| ^^^^^^^^^
12+
help: try removing `&mut` here
13+
--> $DIR/issue-34126.rs:6:18
14+
|
415
LL | self.run(&mut self);
516
| ^^^^^^^^^
6-
| |
7-
| cannot borrow as mutable
8-
| help: try removing `&mut` here
917

1018
error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
1119
--> $DIR/issue-34126.rs:6:18

src/test/ui/nll/issue-51191.stderr

+22-6
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@ LL | (&mut self).bar();
1313
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
1414
--> $DIR/issue-51191.rs:7:9
1515
|
16+
LL | (&mut self).bar();
17+
| ^^^^^^^^^^^ cannot borrow as mutable
18+
|
19+
note: the binding is already a mutable borrow
20+
--> $DIR/issue-51191.rs:4:18
21+
|
22+
LL | fn bar(self: &mut Self) {
23+
| ^^^^^^^^^
24+
help: try removing `&mut` here
25+
--> $DIR/issue-51191.rs:7:9
26+
|
1627
LL | (&mut self).bar();
1728
| ^^^^^^^^^^^
18-
| |
19-
| cannot borrow as mutable
20-
| help: try removing `&mut` here
2129

2230
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
2331
--> $DIR/issue-51191.rs:13:9
@@ -42,11 +50,19 @@ LL | (&mut self).bar();
4250
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
4351
--> $DIR/issue-51191.rs:28:9
4452
|
53+
LL | (&mut self).bar();
54+
| ^^^^^^^^^^^ cannot borrow as mutable
55+
|
56+
note: the binding is already a mutable borrow
57+
--> $DIR/issue-51191.rs:27:16
58+
|
59+
LL | fn mtblref(&mut self) {
60+
| ^^^^^^^^^
61+
help: try removing `&mut` here
62+
--> $DIR/issue-51191.rs:28:9
63+
|
4564
LL | (&mut self).bar();
4665
| ^^^^^^^^^^^
47-
| |
48-
| cannot borrow as mutable
49-
| help: try removing `&mut` here
5066

5167
error: aborting due to 5 previous errors; 1 warning emitted
5268

0 commit comments

Comments
 (0)