Skip to content

Commit

Permalink
Add struct field suggestions.
Browse files Browse the repository at this point in the history
This commit adds suggestions to change the definitions of fields in
struct definitions from immutable references to mutable references.
  • Loading branch information
davidtwco committed Oct 8, 2018
1 parent 5de5281 commit f8c1b0c
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/librustc_mir/borrow_check/mutability_errors.rs
Expand Up @@ -218,6 +218,33 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);

match the_place_err {
// Suggest making an existing shared borrow in a struct definition a mutable borrow.
//
// This is applicable when we have a deref of a field access to a deref of a local -
// something like `*((*_1).0`. The local that we get will be a reference to the
// struct we've got a field access of (it must be a reference since there's a deref
// after the field access).
Place::Projection(box Projection {
base: Place::Projection(box Projection {
base: Place::Projection(box Projection {
base,
elem: ProjectionElem::Deref,
}),
elem: ProjectionElem::Field(field, _),
}),
elem: ProjectionElem::Deref,
}) => {
err.span_label(span, format!("cannot {ACT}", ACT = act));

if let Some((span, message)) = annotate_struct_field(
self.infcx.tcx,
base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx),
field,
) {
err.span_label(span, message);
}
},

// Suggest removing a `&mut` from the use of a mutable reference.
Place::Local(local)
if {
Expand Down Expand Up @@ -592,3 +619,56 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>(
fn is_closure_or_generator(ty: ty::Ty) -> bool {
ty.is_closure() || ty.is_generator()
}

/// Add 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.
///
/// ```text
/// LL | s: &'a String
/// | ---------- use `&'a mut String` here to make mutable
/// ```
fn annotate_struct_field(
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
ty: ty::Ty<'tcx>,
field: &mir::Field,
) -> Option<(Span, String)> {
// Expect our local to be a reference to a struct of some kind.
if let ty::TyKind::Ref(_, ty, _) = ty.sty {
if let ty::TyKind::Adt(def, _) = ty.sty {
let field = def.all_fields().nth(field.index())?;
let span = tcx.def_span(field.did);

// Use the HIR types to construct the diagnostic message.
let node_id = tcx.hir.as_local_node_id(field.did)?;
let node = tcx.hir.find(node_id)?;
// 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::MutImmutable,
ref ty
}) = field.ty.node {
// 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((
span,
format!(
"use `&{}mut {}` here to make mutable",
lifetime_snippet, &*type_snippet,
),
));
}
}
}
}

None
}
3 changes: 3 additions & 0 deletions src/test/ui/did_you_mean/issue-38147-2.nll.stderr
@@ -1,6 +1,9 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-2.rs:17:9
|
LL | s: &'a String
| ------------- use `&'a mut String` here to make mutable
...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable

Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/did_you_mean/issue-38147-3.nll.stderr
@@ -1,6 +1,9 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-3.rs:17:9
|
LL | s: &'a String
| ------------- use `&'a mut String` here to make mutable
...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable

Expand Down

0 comments on commit f8c1b0c

Please sign in to comment.