Skip to content

Commit d274114

Browse files
committed
Auto merge of #44985 - zilbuz:issue-44974, r=pnkfelix
MIR borrowck: print lvalues in error messages in the same way that the AST borrowck Fix #44974 - Print fields with `.name` rather than `.<num>` - Autoderef values if followed by a field or an index - Output `[..]` when borrowing inside a slice
2 parents fbb5054 + e32e81c commit d274114

File tree

5 files changed

+439
-35
lines changed

5 files changed

+439
-35
lines changed

src/librustc_mir/borrow_check.rs

+100-26
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId};
1414
use rustc::infer::{InferCtxt};
1515
use rustc::ty::{self, TyCtxt, ParamEnv};
1616
use rustc::ty::maps::Providers;
17-
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue};
17+
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local};
1818
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
1919
use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
2020
use rustc::mir::transform::{MirSource};
@@ -1080,49 +1080,52 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
10801080
// End-user visible description of `lvalue`
10811081
fn describe_lvalue(&self, lvalue: &Lvalue) -> String {
10821082
let mut buf = String::new();
1083-
self.append_lvalue_to_string(lvalue, &mut buf);
1083+
self.append_lvalue_to_string(lvalue, &mut buf, None);
10841084
buf
10851085
}
10861086

10871087
// Appends end-user visible description of `lvalue` to `buf`.
1088-
fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String) {
1088+
fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option<bool>) {
10891089
match *lvalue {
10901090
Lvalue::Local(local) => {
1091-
let local = &self.mir.local_decls[local];
1092-
match local.name {
1093-
Some(name) => buf.push_str(&format!("{}", name)),
1094-
None => buf.push_str("_"),
1095-
}
1091+
self.append_local_to_string(local, buf, "_");
10961092
}
10971093
Lvalue::Static(ref static_) => {
10981094
buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
10991095
}
11001096
Lvalue::Projection(ref proj) => {
1097+
let mut autoderef = autoderef.unwrap_or(false);
11011098
let (prefix, suffix, index_operand) = match proj.elem {
1102-
ProjectionElem::Deref =>
1103-
("(*", format!(")"), None),
1099+
ProjectionElem::Deref => {
1100+
if autoderef {
1101+
("", format!(""), None)
1102+
} else {
1103+
("(*", format!(")"), None)
1104+
}
1105+
},
11041106
ProjectionElem::Downcast(..) =>
11051107
("", format!(""), None), // (dont emit downcast info)
1106-
ProjectionElem::Field(field, _ty) =>
1107-
("", format!(".{}", field.index()), None), // FIXME: report name of field
1108-
ProjectionElem::Index(index) =>
1109-
("", format!(""), Some(index)),
1110-
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
1111-
("", format!("[{} of {}]", offset, min_length), None),
1112-
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
1113-
("", format!("[-{} of {}]", offset, min_length), None),
1114-
ProjectionElem::Subslice { from, to: 0 } =>
1115-
("", format!("[{}:]", from), None),
1116-
ProjectionElem::Subslice { from: 0, to } =>
1117-
("", format!("[:-{}]", to), None),
1118-
ProjectionElem::Subslice { from, to } =>
1119-
("", format!("[{}:-{}]", from, to), None),
1108+
ProjectionElem::Field(field, _ty) => {
1109+
autoderef = true;
1110+
("", format!(".{}", self.describe_field(&proj.base, field.index())), None)
1111+
},
1112+
ProjectionElem::Index(index) => {
1113+
autoderef = true;
1114+
("", format!(""), Some(index))
1115+
},
1116+
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1117+
autoderef = true;
1118+
// Since it isn't possible to borrow an element on a particular index and
1119+
// then use another while the borrow is held, don't output indices details
1120+
// to avoid confusing the end-user
1121+
("", format!("[..]"), None)
1122+
},
11201123
};
11211124
buf.push_str(prefix);
1122-
self.append_lvalue_to_string(&proj.base, buf);
1125+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
11231126
if let Some(index) = index_operand {
11241127
buf.push_str("[");
1125-
self.append_lvalue_to_string(&Lvalue::Local(index), buf);
1128+
self.append_local_to_string(index, buf, "..");
11261129
buf.push_str("]");
11271130
} else {
11281131
buf.push_str(&suffix);
@@ -1131,6 +1134,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
11311134
}
11321135
}
11331136

1137+
// Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have
1138+
// a name, then `none_string` is appended instead
1139+
fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) {
1140+
let local = &self.mir.local_decls[local_index];
1141+
match local.name {
1142+
Some(name) => buf.push_str(&format!("{}", name)),
1143+
None => buf.push_str(none_string)
1144+
}
1145+
}
1146+
1147+
// End-user visible description of the `field_index`nth field of `base`
1148+
fn describe_field(&self, base: &Lvalue, field_index: usize) -> String {
1149+
match *base {
1150+
Lvalue::Local(local) => {
1151+
let local = &self.mir.local_decls[local];
1152+
self.describe_field_from_ty(&local.ty, field_index)
1153+
},
1154+
Lvalue::Static(ref static_) => {
1155+
self.describe_field_from_ty(&static_.ty, field_index)
1156+
},
1157+
Lvalue::Projection(ref proj) => {
1158+
match proj.elem {
1159+
ProjectionElem::Deref =>
1160+
self.describe_field(&proj.base, field_index),
1161+
ProjectionElem::Downcast(def, variant_index) =>
1162+
format!("{}", def.variants[variant_index].fields[field_index].name),
1163+
ProjectionElem::Field(_, field_type) =>
1164+
self.describe_field_from_ty(&field_type, field_index),
1165+
ProjectionElem::Index(..)
1166+
| ProjectionElem::ConstantIndex { .. }
1167+
| ProjectionElem::Subslice { .. } =>
1168+
format!("{}", self.describe_field(&proj.base, field_index)),
1169+
}
1170+
}
1171+
}
1172+
}
1173+
1174+
// End-user visible description of the `field_index`nth field of `ty`
1175+
fn describe_field_from_ty(&self, ty: &ty::Ty, field_index: usize) -> String {
1176+
if ty.is_box() {
1177+
// If the type is a box, the field is described from the boxed type
1178+
self.describe_field_from_ty(&ty.boxed_ty(), field_index)
1179+
}
1180+
else {
1181+
match ty.sty {
1182+
ty::TyAdt(def, _) => {
1183+
if def.is_enum() {
1184+
format!("{}", field_index)
1185+
}
1186+
else {
1187+
format!("{}", def.struct_variant().fields[field_index].name)
1188+
}
1189+
},
1190+
ty::TyTuple(_, _) => {
1191+
format!("{}", field_index)
1192+
},
1193+
ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
1194+
self.describe_field_from_ty(&tnm.ty, field_index)
1195+
},
1196+
ty::TyArray(ty, _) | ty::TySlice(ty) => {
1197+
self.describe_field_from_ty(&ty, field_index)
1198+
}
1199+
_ => {
1200+
// Might need a revision when the fields in trait RFC is implemented
1201+
// (https://github.com/rust-lang/rfcs/pull/1546)
1202+
bug!("End-user description not implemented for field access on `{:?}`", ty.sty);
1203+
}
1204+
}
1205+
}
1206+
}
1207+
11341208
// Retrieve span of given borrow from the current MIR representation
11351209
fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
11361210
self.mir.source_info(borrow.location).span

src/test/compile-fail/borrowck/borrowck-assign-comp.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn a() {
2222
// immutable. Otherwise the type of &_q.x (&isize) would be wrong.
2323
p.x = 5; //[ast]~ ERROR cannot assign to `p.x`
2424
//[mir]~^ ERROR cannot assign to `p.x` because it is borrowed (Ast)
25-
//[mir]~| ERROR cannot assign to `p.0` because it is borrowed (Mir)
25+
//[mir]~| ERROR cannot assign to `p.x` because it is borrowed (Mir)
2626
q.x;
2727
}
2828

@@ -47,7 +47,7 @@ fn d() {
4747
let q = &p.y;
4848
p.y = 5; //[ast]~ ERROR cannot assign to `p.y`
4949
//[mir]~^ ERROR cannot assign to `p.y` because it is borrowed (Ast)
50-
//[mir]~| ERROR cannot assign to `p.1` because it is borrowed (Mir)
50+
//[mir]~| ERROR cannot assign to `p.y` because it is borrowed (Mir)
5151
*q;
5252
}
5353

src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ fn g() {
8282
let c1 = || get(&*x.f);
8383
*x.f = 5; //[ast]~ ERROR cannot assign to `*x.f`
8484
//[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed (Ast)
85-
//[mir]~| ERROR cannot assign to `(*(*x).0)` because it is borrowed (Mir)
85+
//[mir]~| ERROR cannot assign to `(*x.f)` because it is borrowed (Mir)
8686
}
8787

8888
fn h() {

0 commit comments

Comments
 (0)