Skip to content

Commit 38306ad

Browse files
committed
Add help message for mutation though overloaded place operators
1 parent 5b86c60 commit 38306ad

12 files changed

+149
-140
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+20
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,26 @@ impl BorrowedContentSource<'tcx> {
653653
}
654654
}
655655

656+
pub(super) fn describe_for_immutable_place(&self) -> String {
657+
match *self {
658+
BorrowedContentSource::DerefRawPointer => format!("a `*const` pointer"),
659+
BorrowedContentSource::DerefSharedRef => format!("a `&` reference"),
660+
BorrowedContentSource::DerefMutableRef => {
661+
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
662+
},
663+
BorrowedContentSource::OverloadedDeref(ty) => {
664+
if ty.is_rc() {
665+
format!("an `Rc`")
666+
} else if ty.is_arc() {
667+
format!("an `Arc`")
668+
} else {
669+
format!("a dereference of `{}`", ty)
670+
}
671+
}
672+
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
673+
}
674+
}
675+
656676
fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
657677
match func.sty {
658678
ty::FnDef(def_id, substs) => {

src/librustc_mir/borrow_check/mutability_errors.rs

+32-65
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
use rustc::hir;
22
use rustc::hir::Node;
3-
use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Body};
4-
use rustc::mir::{
5-
Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind,
6-
};
7-
use rustc::mir::{Terminator, TerminatorKind};
8-
use rustc::ty::{self, Const, DefIdTree, Ty, TyS, TyCtxt};
3+
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
4+
use rustc::mir::{Mutability, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind};
5+
use rustc::ty::{self, Ty, TyCtxt};
96
use rustc_data_structures::indexed_vec::Idx;
107
use syntax_pos::Span;
118
use syntax_pos::symbol::kw;
129

13-
use crate::dataflow::move_paths::InitLocation;
1410
use crate::borrow_check::MirBorrowckCtxt;
11+
use crate::borrow_check::error_reporting::BorrowedContentSource;
1512
use crate::util::borrowck_errors::{BorrowckErrors, Origin};
1613
use crate::util::collect_writes::FindAssignments;
1714
use crate::util::suggest_ref_mut;
@@ -43,6 +40,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
4340
let mut err;
4441
let item_msg;
4542
let reason;
43+
let mut opt_source = None;
4644
let access_place_desc = self.describe_place(access_place);
4745
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
4846

@@ -103,23 +101,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
103101
item_msg = format!("`{}`", access_place_desc.unwrap());
104102
reason = ", as it is immutable for the pattern guard".to_string();
105103
} else {
106-
let pointer_type =
107-
if base.ty(self.body, self.infcx.tcx).ty.is_region_ptr() {
108-
"`&` reference"
109-
} else {
110-
"`*const` pointer"
111-
};
104+
let source = self.borrowed_content_source(base);
105+
let pointer_type = source.describe_for_immutable_place();
106+
opt_source = Some(source);
112107
if let Some(desc) = access_place_desc {
113108
item_msg = format!("`{}`", desc);
114109
reason = match error_access {
115110
AccessKind::Move |
116-
AccessKind::Mutate => format!(" which is behind a {}", pointer_type),
111+
AccessKind::Mutate => format!(" which is behind {}", pointer_type),
117112
AccessKind::MutableBorrow => {
118-
format!(", as it is behind a {}", pointer_type)
113+
format!(", as it is behind {}", pointer_type)
119114
}
120115
}
121116
} else {
122-
item_msg = format!("data in a {}", pointer_type);
117+
item_msg = format!("data in {}", pointer_type);
123118
reason = String::new();
124119
}
125120
}
@@ -457,59 +452,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
457452
}
458453

459454
Place::Projection(box Projection {
460-
base: Place::Base(PlaceBase::Local(local)),
455+
base: _,
461456
elem: ProjectionElem::Deref,
462-
}) if error_access == AccessKind::MutableBorrow => {
457+
}) => {
463458
err.span_label(span, format!("cannot {ACT}", ACT = act));
464459

465-
let mpi = self.move_data.rev_lookup.find_local(*local);
466-
for i in self.move_data.init_path_map[mpi].iter() {
467-
if let InitLocation::Statement(location) = self.move_data.inits[*i].location {
468-
if let Some(
469-
Terminator {
470-
kind: TerminatorKind::Call {
471-
func: Operand::Constant(box Constant {
472-
literal: Const {
473-
ty: &TyS {
474-
sty: ty::FnDef(id, substs),
475-
..
476-
},
477-
..
478-
},
479-
..
480-
}),
481-
..
482-
},
483-
..
484-
}
485-
) = &self.body.basic_blocks()[location.block].terminator {
486-
let index_trait = self.infcx.tcx.lang_items().index_trait();
487-
if self.infcx.tcx.parent(id) == index_trait {
488-
let mut found = false;
489-
self.infcx.tcx.for_each_relevant_impl(
490-
self.infcx.tcx.lang_items().index_mut_trait().unwrap(),
491-
substs.type_at(0),
492-
|_relevant_impl| {
493-
found = true;
494-
}
495-
);
496-
497-
let extra = if found {
498-
String::new()
499-
} else {
500-
format!(", but it is not implemented for `{}`",
501-
substs.type_at(0))
502-
};
503-
504-
err.help(
505-
&format!(
506-
"trait `IndexMut` is required to modify indexed content{}",
507-
extra,
508-
),
509-
);
510-
}
511-
}
460+
match opt_source {
461+
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
462+
err.help(
463+
&format!(
464+
"trait `DerefMut` is required to modify through a dereference, \
465+
but it is not implemented for `{}`",
466+
ty,
467+
),
468+
);
469+
},
470+
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
471+
err.help(
472+
&format!(
473+
"trait `IndexMut` is required to modify indexed content, \
474+
but it is not implemented for `{}`",
475+
ty,
476+
),
477+
);
512478
}
479+
_ => (),
513480
}
514481
}
515482

src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,7 @@
22
// Deref and not DerefMut is implemented.
33

44
use std::ops::Deref;
5-
6-
struct Rc<T> {
7-
value: *const T
8-
}
9-
10-
impl<T> Deref for Rc<T> {
11-
type Target = T;
12-
13-
fn deref(&self) -> &T {
14-
unsafe { &*self.value }
15-
}
16-
}
5+
use std::rc::Rc;
176

187
struct Point {
198
x: isize,

src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr

+56-28
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,114 @@
1-
error[E0596]: cannot borrow data in a `&` reference as mutable
2-
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:47:19
1+
error[E0596]: cannot borrow data in an `Rc` as mutable
2+
--> $DIR/borrowck-borrow-overloaded-auto-deref.rs:36:19
33
|
44
LL | let __isize = &mut x.y;
55
| ^^^^^^^^ cannot borrow as mutable
6+
|
7+
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc<Point>`
68

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

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

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

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

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

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

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

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

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

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

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

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

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

85113
error: aborting due to 14 previous errors
86114

src/test/ui/borrowck/borrowck-borrow-overloaded-deref.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,7 @@
22
// Deref and not DerefMut is implemented.
33

44
use std::ops::Deref;
5-
6-
struct Rc<T> {
7-
value: *const T
8-
}
9-
10-
impl<T> Deref for Rc<T> {
11-
type Target = T;
12-
13-
fn deref<'a>(&'a self) -> &'a T {
14-
unsafe { &*self.value }
15-
}
16-
}
5+
use std::rc::Rc;
176

187
fn deref_imm(x: Rc<isize>) {
198
let __isize = &*x;

0 commit comments

Comments
 (0)