Skip to content

Commit 22973a8

Browse files
Rollup merge of #83251 - estebank:issue-83241, r=oli-obk
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.
2 parents 8eb50ce + 5b6f4b9 commit 22973a8

File tree

6 files changed

+210
-38
lines changed

6 files changed

+210
-38
lines changed

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

+72-8
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ 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};
12-
use rustc_span::Span;
15+
use rustc_span::{BytePos, Span};
1316

1417
use crate::borrow_check::diagnostics::BorrowedContentSource;
1518
use crate::borrow_check::MirBorrowckCtxt;
@@ -241,13 +244,74 @@ 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+
if let Ok(snippet) =
282+
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
283+
{
284+
if snippet.starts_with("&mut ") {
285+
// We don't have access to the HIR to get accurate spans, but we can
286+
// give a best effort structured suggestion.
287+
err.span_suggestion_verbose(
288+
source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
289+
"try removing `&mut` here",
290+
String::new(),
291+
Applicability::MachineApplicable,
292+
);
293+
} else {
294+
// This can occur with things like `(&mut self).foo()`.
295+
err.span_help(source_info.span, "try removing `&mut` here");
296+
}
297+
} else {
298+
err.span_help(source_info.span, "try removing `&mut` here");
299+
}
300+
} else if decl.mutability == Mutability::Not
301+
&& !matches!(
302+
decl.local_info,
303+
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
304+
ImplicitSelfKind::MutRef
305+
))))
306+
)
307+
{
308+
err.span_suggestion_verbose(
309+
decl.source_info.span.shrink_to_lo(),
310+
"consider making the binding mutable",
311+
"mut ".to_string(),
312+
Applicability::MachineApplicable,
313+
);
314+
}
251315
}
252316

253317
// 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);
5-
| ^^^^^^
6-
| |
7-
| cannot borrow as mutable
8-
| help: try removing `&mut` here
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+
|
14+
LL - h(&mut b);
15+
LL + h(b);
16+
|
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);
14-
| ^^^^^^
15-
| |
16-
| cannot borrow as mutable
17-
| help: try removing `&mut` here
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+
|
31+
LL - g(&mut &mut b);
32+
LL + g(&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+
|
48+
LL - h(&mut &mut b);
49+
LL + h(&mut b);
50+
|
51+
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+
| +++
1862

19-
error: aborting due to 2 previous errors
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

+12-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@ error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
22
--> $DIR/issue-34126.rs:6:18
33
|
44
LL | self.run(&mut self);
5-
| ^^^^^^^^^
6-
| |
7-
| cannot borrow as mutable
8-
| help: try removing `&mut` here
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+
|
14+
LL - self.run(&mut self);
15+
LL + self.run(self);
16+
|
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)