Skip to content

Commit 97bf7b9

Browse files
committed
Improve suggestion to change struct field to &mut
1 parent 23c2723 commit 97bf7b9

File tree

4 files changed

+42
-35
lines changed

4 files changed

+42
-35
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+13-26
Original file line numberDiff line numberDiff line change
@@ -229,15 +229,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
229229
} => {
230230
err.span_label(span, format!("cannot {ACT}", ACT = act));
231231

232-
if let Some((span, message)) = annotate_struct_field(
232+
if let Some(span) = get_mut_span_in_struct_field(
233233
self.infcx.tcx,
234234
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
235235
field,
236236
) {
237-
err.span_suggestion(
237+
err.span_suggestion_verbose(
238238
span,
239239
"consider changing this to be mutable",
240-
message,
240+
"mut ".into(),
241241
Applicability::MaybeIncorrect,
242242
);
243243
}
@@ -1059,18 +1059,18 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
10591059
ty.is_closure() || ty.is_generator()
10601060
}
10611061

1062-
/// Adds a suggestion to a struct definition given a field access to a local.
1063-
/// This function expects the local to be a reference to a struct in order to produce a suggestion.
1062+
/// Given a field that needs to be mutuable, returns a span where the mut could go.
1063+
/// This function expects the local to be a reference to a struct in order to produce a span.
10641064
///
10651065
/// ```text
10661066
/// LL | s: &'a String
1067-
/// | ---------- use `&'a mut String` here to make mutable
1067+
/// | ^ returns a span pointing here
10681068
/// ```
1069-
fn annotate_struct_field<'tcx>(
1069+
fn get_mut_span_in_struct_field<'tcx>(
10701070
tcx: TyCtxt<'tcx>,
10711071
ty: Ty<'tcx>,
10721072
field: &mir::Field,
1073-
) -> Option<(Span, String)> {
1073+
) -> Option<Span> {
10741074
// Expect our local to be a reference to a struct of some kind.
10751075
if let ty::Ref(_, ty, _) = ty.kind() {
10761076
if let ty::Adt(def, _) = ty.kind() {
@@ -1081,25 +1081,12 @@ fn annotate_struct_field<'tcx>(
10811081
// Now we're dealing with the actual struct that we're going to suggest a change to,
10821082
// we can expect a field that is an immutable reference to a type.
10831083
if let hir::Node::Field(field) = node {
1084-
if let hir::TyKind::Rptr(
1085-
lifetime,
1086-
hir::MutTy { mutbl: hir::Mutability::Not, ref ty },
1087-
) = field.ty.kind
1084+
if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, .. }) =
1085+
field.ty.kind
10881086
{
1089-
// Get the snippets in two parts - the named lifetime (if there is one) and
1090-
// type being referenced, that way we can reconstruct the snippet without loss
1091-
// of detail.
1092-
let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
1093-
let lifetime_snippet = if !lifetime.is_elided() {
1094-
format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
1095-
} else {
1096-
String::new()
1097-
};
1098-
1099-
return Some((
1100-
field.ty.span,
1101-
format!("&{}mut {}", lifetime_snippet, &*type_snippet,),
1102-
));
1087+
return Some(
1088+
lifetime.span.with_hi(lifetime.span.hi() + BytePos(1)).shrink_to_hi(),
1089+
);
11031090
}
11041091
}
11051092
}

src/test/ui/did_you_mean/issue-38147-2.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
struct Bar<'a> {
2-
s: &'a String
2+
s: &'a String,
3+
// use wonky spaces to ensure we are creating the span correctly
4+
longer_name: & 'a Vec<u8>
35
}
46

57
impl<'a> Bar<'a> {
68
fn f(&mut self) {
79
self.s.push('x');
810
//~^ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference
11+
12+
self.longer_name.push(13);
13+
//~^ ERROR cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
914
}
1015
}
1116

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
2-
--> $DIR/issue-38147-2.rs:7:9
2+
--> $DIR/issue-38147-2.rs:9:9
33
|
4-
LL | s: &'a String
5-
| ---------- help: consider changing this to be mutable: `&'a mut String`
6-
...
74
LL | self.s.push('x');
85
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
help: consider changing this to be mutable
8+
|
9+
LL | s: &'a mut String,
10+
| +++
11+
12+
error[E0596]: cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
13+
--> $DIR/issue-38147-2.rs:12:9
14+
|
15+
LL | self.longer_name.push(13);
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
17+
|
18+
help: consider changing this to be mutable
19+
|
20+
LL | longer_name: & 'a mut Vec<u8>
21+
| +++
922

10-
error: aborting due to previous error
23+
error: aborting due to 2 previous errors
1124

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

src/test/ui/did_you_mean/issue-38147-3.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
22
--> $DIR/issue-38147-3.rs:7:9
33
|
4-
LL | s: &'a String
5-
| ---------- help: consider changing this to be mutable: `&'a mut String`
6-
...
74
LL | self.s.push('x');
85
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
help: consider changing this to be mutable
8+
|
9+
LL | s: &'a mut String
10+
| +++
911

1012
error: aborting due to previous error
1113

0 commit comments

Comments
 (0)