Skip to content

Commit

Permalink
Rollup merge of rust-lang#91516 - rukai:improve_mut_addition_help, r=…
Browse files Browse the repository at this point in the history
…estebank

Improve suggestion to change struct field to &mut

r? `@estebank`

Now displays a proper underline style suggestion instead of including the code change inline with the message.
  • Loading branch information
matthiaskrgr authored Dec 18, 2021
2 parents 2e4a2c9 + e573075 commit 6427c3c
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 36 deletions.
39 changes: 12 additions & 27 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));

if let Some((span, message)) = annotate_struct_field(
if let Some(span) = get_mut_span_in_struct_field(
self.infcx.tcx,
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
field,
) {
err.span_suggestion(
err.span_suggestion_verbose(
span,
"consider changing this to be mutable",
message,
" mut ".into(),
Applicability::MaybeIncorrect,
);
}
Expand Down Expand Up @@ -1059,18 +1059,18 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
ty.is_closure() || ty.is_generator()
}

/// Adds a suggestion to a struct definition given a field access to a local.
/// This function expects the local to be a reference to a struct in order to produce a suggestion.
/// Given a field that needs to be mutable, returns a span where the " mut " could go.
/// This function expects the local to be a reference to a struct in order to produce a span.
///
/// ```text
/// LL | s: &'a String
/// | ---------- use `&'a mut String` here to make mutable
/// LL | s: &'a String
/// | ^^^ returns a span taking up the space here
/// ```
fn annotate_struct_field<'tcx>(
fn get_mut_span_in_struct_field<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
field: &mir::Field,
) -> Option<(Span, String)> {
) -> Option<Span> {
// Expect our local to be a reference to a struct of some kind.
if let ty::Ref(_, ty, _) = ty.kind() {
if let ty::Adt(def, _) = ty.kind() {
Expand All @@ -1081,25 +1081,10 @@ fn annotate_struct_field<'tcx>(
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
if let hir::Node::Field(field) = node {
if let hir::TyKind::Rptr(
lifetime,
hir::MutTy { mutbl: hir::Mutability::Not, ref ty },
) = field.ty.kind
if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) =
field.ty.kind
{
// Get the snippets in two parts - the named lifetime (if there is one) and
// type being referenced, that way we can reconstruct the snippet without loss
// of detail.
let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
let lifetime_snippet = if !lifetime.is_elided() {
format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
} else {
String::new()
};

return Some((
field.ty.span,
format!("&{}mut {}", lifetime_snippet, &*type_snippet,),
));
return Some(lifetime.span.between(ty.span));
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/test/ui/did_you_mean/issue-38147-2.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
struct Bar<'a> {
s: &'a String
s: &'a String,
// use wonky spaces to ensure we are creating the span correctly
longer_name: & 'a Vec<u8>
}

impl<'a> Bar<'a> {
fn f(&mut self) {
self.s.push('x');
//~^ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference

self.longer_name.push(13);
//~^ ERROR cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
}
}

Expand Down
23 changes: 18 additions & 5 deletions src/test/ui/did_you_mean/issue-38147-2.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-2.rs:7:9
--> $DIR/issue-38147-2.rs:9:9
|
LL | s: &'a String
| ---------- help: consider changing this to be mutable: `&'a mut String`
...
LL | self.s.push('x');
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
LL | s: &'a mut String,
| +++

error[E0596]: cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-2.rs:12:9
|
LL | self.longer_name.push(13);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
LL | longer_name: & 'a mut Vec<u8>
| +++

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0596`.
8 changes: 5 additions & 3 deletions src/test/ui/did_you_mean/issue-38147-3.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-3.rs:7:9
|
LL | s: &'a String
| ---------- help: consider changing this to be mutable: `&'a mut String`
...
LL | self.s.push('x');
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
LL | s: &'a mut String
| +++

error: aborting due to previous error

Expand Down

0 comments on commit 6427c3c

Please sign in to comment.