Skip to content

Commit

Permalink
Add help message for mutation though overloaded place operators
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper committed Jul 7, 2019
1 parent 5b86c60 commit 38306ad
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 140 deletions.
20 changes: 20 additions & 0 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,26 @@ impl BorrowedContentSource<'tcx> {
}
}

pub(super) fn describe_for_immutable_place(&self) -> String {
match *self {
BorrowedContentSource::DerefRawPointer => format!("a `*const` pointer"),
BorrowedContentSource::DerefSharedRef => format!("a `&` reference"),
BorrowedContentSource::DerefMutableRef => {
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
},
BorrowedContentSource::OverloadedDeref(ty) => {
if ty.is_rc() {
format!("an `Rc`")
} else if ty.is_arc() {
format!("an `Arc`")
} else {
format!("a dereference of `{}`", ty)
}
}
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
}
}

fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
match func.sty {
ty::FnDef(def_id, substs) => {
Expand Down
97 changes: 32 additions & 65 deletions src/librustc_mir/borrow_check/mutability_errors.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
use rustc::hir;
use rustc::hir::Node;
use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Body};
use rustc::mir::{
Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind,
};
use rustc::mir::{Terminator, TerminatorKind};
use rustc::ty::{self, Const, DefIdTree, Ty, TyS, TyCtxt};
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
use rustc::mir::{Mutability, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
use syntax_pos::symbol::kw;

use crate::dataflow::move_paths::InitLocation;
use crate::borrow_check::MirBorrowckCtxt;
use crate::borrow_check::error_reporting::BorrowedContentSource;
use crate::util::borrowck_errors::{BorrowckErrors, Origin};
use crate::util::collect_writes::FindAssignments;
use crate::util::suggest_ref_mut;
Expand Down Expand Up @@ -43,6 +40,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let mut err;
let item_msg;
let reason;
let mut opt_source = None;
let access_place_desc = self.describe_place(access_place);
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);

Expand Down Expand Up @@ -103,23 +101,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
item_msg = format!("`{}`", access_place_desc.unwrap());
reason = ", as it is immutable for the pattern guard".to_string();
} else {
let pointer_type =
if base.ty(self.body, self.infcx.tcx).ty.is_region_ptr() {
"`&` reference"
} else {
"`*const` pointer"
};
let source = self.borrowed_content_source(base);
let pointer_type = source.describe_for_immutable_place();
opt_source = Some(source);
if let Some(desc) = access_place_desc {
item_msg = format!("`{}`", desc);
reason = match error_access {
AccessKind::Move |
AccessKind::Mutate => format!(" which is behind a {}", pointer_type),
AccessKind::Mutate => format!(" which is behind {}", pointer_type),
AccessKind::MutableBorrow => {
format!(", as it is behind a {}", pointer_type)
format!(", as it is behind {}", pointer_type)
}
}
} else {
item_msg = format!("data in a {}", pointer_type);
item_msg = format!("data in {}", pointer_type);
reason = String::new();
}
}
Expand Down Expand Up @@ -457,59 +452,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}

Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(local)),
base: _,
elem: ProjectionElem::Deref,
}) if error_access == AccessKind::MutableBorrow => {
}) => {
err.span_label(span, format!("cannot {ACT}", ACT = act));

let mpi = self.move_data.rev_lookup.find_local(*local);
for i in self.move_data.init_path_map[mpi].iter() {
if let InitLocation::Statement(location) = self.move_data.inits[*i].location {
if let Some(
Terminator {
kind: TerminatorKind::Call {
func: Operand::Constant(box Constant {
literal: Const {
ty: &TyS {
sty: ty::FnDef(id, substs),
..
},
..
},
..
}),
..
},
..
}
) = &self.body.basic_blocks()[location.block].terminator {
let index_trait = self.infcx.tcx.lang_items().index_trait();
if self.infcx.tcx.parent(id) == index_trait {
let mut found = false;
self.infcx.tcx.for_each_relevant_impl(
self.infcx.tcx.lang_items().index_mut_trait().unwrap(),
substs.type_at(0),
|_relevant_impl| {
found = true;
}
);

let extra = if found {
String::new()
} else {
format!(", but it is not implemented for `{}`",
substs.type_at(0))
};

err.help(
&format!(
"trait `IndexMut` is required to modify indexed content{}",
extra,
),
);
}
}
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
err.help(
&format!(
"trait `DerefMut` is required to modify through a dereference, \
but it is not implemented for `{}`",
ty,
),
);
},
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
err.help(
&format!(
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{}`",
ty,
),
);
}
_ => (),
}
}

Expand Down
13 changes: 1 addition & 12 deletions src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,7 @@
// Deref and not DerefMut is implemented.

use std::ops::Deref;

struct Rc<T> {
value: *const T
}

impl<T> Deref for Rc<T> {
type Target = T;

fn deref(&self) -> &T {
unsafe { &*self.value }
}
}
use std::rc::Rc;

struct Point {
x: isize,
Expand Down
84 changes: 56 additions & 28 deletions src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
Original file line number Diff line number Diff line change
@@ -1,86 +1,114 @@
error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:47:19
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:36:19
|
LL | let __isize = &mut x.y;
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:51:19
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:40:19
|
LL | let __isize = &mut x.y;
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:59:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:48:5
|
LL | &mut x.y
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:63:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:52:5
|
LL | &mut x.y
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0594]: cannot assign to data in a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:67:5
error[E0594]: cannot assign to data in an `Rc`
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:56:5
|
LL | x.y = 3;
| ^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0594]: cannot assign to data in a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:71:5
error[E0594]: cannot assign to data in an `Rc`
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:60:5
|
LL | x.y = 3;
| ^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0594]: cannot assign to data in a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:75:5
error[E0594]: cannot assign to data in an `Rc`
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:64:5
|
LL | x.y = 3;
| ^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:83:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5
|
LL | x.set(0, 0);
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:87:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5
|
LL | x.set(0, 0);
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:95:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5
|
LL | x.y_mut()
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:99:5
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5
|
LL | x.y_mut()
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:103:6
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6
|
LL | *x.y_mut() = 3;
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:107:6
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6
|
LL | *x.y_mut() = 3;
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:111:6
error[E0596]: cannot borrow data in an `Rc` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6
|
LL | *x.y_mut() = 3;
| ^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`

error: aborting due to 14 previous errors

Expand Down
13 changes: 1 addition & 12 deletions src/test/ui/borrowck/borrowck-borrow-overloaded-deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,7 @@
// Deref and not DerefMut is implemented.

use std::ops::Deref;

struct Rc<T> {
value: *const T
}

impl<T> Deref for Rc<T> {
type Target = T;

fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self.value }
}
}
use std::rc::Rc;

fn deref_imm(x: Rc<isize>) {
let __isize = &*x;
Expand Down
Loading

0 comments on commit 38306ad

Please sign in to comment.