Skip to content

Commit 879f7c1

Browse files
csmoespastorino
authored andcommitted
rewrite methods with NeoPlace in mir/tcx
1 parent 93c5ebb commit 879f7c1

File tree

5 files changed

+174
-36
lines changed

5 files changed

+174
-36
lines changed

src/librustc/mir/tcx.rs

Lines changed: 151 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
2525
mem::size_of::<PlaceTy<'_>>() <= 24
2626
);
2727

28-
impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
29-
pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
28+
impl From<Ty<'tcx>> for PlaceTy<'tcx> {
29+
fn from(ty: Ty<'tcx>) -> Self {
3030
PlaceTy::Ty { ty }
3131
}
32+
}
3233

34+
impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
3335
pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
3436
match *self {
3537
PlaceTy::Ty { ty } =>
@@ -168,38 +170,162 @@ impl<'tcx> Place<'tcx> {
168170
}
169171
}
170172

173+
// If this is a field projection, and the field is being projected from a closure type,
174+
// then returns the index of the field being projected. Note that this closure will always
175+
// be `self` in the current MIR, because that is the only time we directly access the fields
176+
// of a closure type.
177+
//pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
178+
// tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
179+
// let (place, by_ref) = if let Place::Projection(ref proj) = self {
180+
// if let ProjectionElem::Deref = proj.elem {
181+
// (&proj.base, true)
182+
// } else {
183+
// (self, false)
184+
// }
185+
// } else {
186+
// (self, false)
187+
// };
188+
189+
// match place {
190+
// Place::Projection(ref proj) => match proj.elem {
191+
// ProjectionElem::Field(field, _ty) => {
192+
// let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
193+
194+
// if (base_ty.is_closure() || base_ty.is_generator()) &&
195+
// (!by_ref || mir.upvar_decls[field.index()].by_ref)
196+
// {
197+
// Some(field)
198+
// } else {
199+
// None
200+
// }
201+
// },
202+
// _ => None,
203+
// }
204+
// _ => None,
205+
// }
206+
//}
207+
}
208+
209+
impl<'tcx> PlaceBase<'tcx> {
210+
pub fn ty(&self, local_decls: &impl HasLocalDecls<'tcx>) -> Ty<'tcx> {
211+
match self {
212+
PlaceBase::Local(index) => local_decls.local_decls()[*index].ty,
213+
PlaceBase::Promoted(data) => data.1,
214+
PlaceBase::Static(data) => data.ty,
215+
}
216+
}
217+
}
218+
219+
impl<'tcx> NeoPlace<'tcx> {
220+
pub fn ty<'a, 'gcx>(
221+
&self,
222+
local_decls: &impl HasLocalDecls<'tcx>,
223+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
224+
) -> PlaceTy<'tcx> {
225+
// the PlaceTy is the *final* type with all projection applied
226+
// if there is no projection, that just refers to `base`:
227+
//
228+
// Place: base.[a, b, c]
229+
// ^-- projection
230+
// ^-- PlaceTy
231+
//
232+
// Place: base.[]
233+
// ^^-- no projection
234+
// ^^^^-- PlaceTy
235+
236+
let mut place_ty = PlaceTy::from(self.base.ty(local_decls));
237+
238+
// apply .projection_ty() to all elems but only returns the final one.
239+
for elem in self.elems.iter() {
240+
place_ty = place_ty.projection_ty(tcx, elem);
241+
}
242+
243+
place_ty
244+
}
245+
171246
/// If this is a field projection, and the field is being projected from a closure type,
172247
/// then returns the index of the field being projected. Note that this closure will always
173248
/// be `self` in the current MIR, because that is the only time we directly access the fields
174249
/// of a closure type.
175-
pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
176-
tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
177-
let (place, by_ref) = if let Place::Projection(ref proj) = self {
178-
if let ProjectionElem::Deref = proj.elem {
179-
(&proj.base, true)
250+
pub fn is_upvar_field_projection<'cx, 'gcx>(
251+
&self,
252+
mir: &'cx Mir<'tcx>,
253+
tcx: &TyCtxt<'cx, 'gcx, 'tcx>,
254+
) -> Option<Field> {
255+
// Look for either *(Place.field) or Place.field,
256+
// where P is a place with closure type,
257+
// these sorts of places represent accesses to the closure's captured upvars.
258+
259+
// unwrap inner place when Deref matched.
260+
// *(closure.field)
261+
// ^ ^^^^^ inner projection_elem
262+
// |-- Deref
263+
let (elems, by_ref) =
264+
if let Some(ProjectionElem::Deref) = self.elems.last() {
265+
(&self.elems[..self.elems.len()-1], true)
266+
} else {
267+
(&self.elems[..], false)
268+
};
269+
let mut elems = elems.iter().rev();
270+
271+
// closure.field
272+
// ^^^^^
273+
if let Some(ProjectionElem::Field(field, _ty)) = elems.next() {
274+
let base_ty = self.base.ty_with_projections(mir, *tcx, elems.rev());
275+
if (base_ty.is_closure() || base_ty.is_generator()) &&
276+
(!by_ref || mir.upvar_decls[field.index()].by_ref)
277+
{
278+
Some(*field)
180279
} else {
181-
(self, false)
280+
None
182281
}
183282
} else {
184-
(self, false)
185-
};
283+
None
284+
}
285+
}
186286

187-
match place {
188-
Place::Projection(ref proj) => match proj.elem {
189-
ProjectionElem::Field(field, _ty) => {
190-
let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
191-
192-
if (base_ty.is_closure() || base_ty.is_generator()) &&
193-
(!by_ref || mir.upvar_decls[field.index()].by_ref)
194-
{
195-
Some(field)
196-
} else {
197-
None
198-
}
287+
// for Place:
288+
// (Base.[a, b, c])
289+
// ^^^^^^^^^^ ^-- projection
290+
// |-- base_place
291+
//
292+
// Base.[]
293+
// ^^^^ ^^-- no projection(empty)
294+
// |-- base_place
295+
pub fn split_projection<'cx, 'gcx>(
296+
&self,
297+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
298+
) -> (NeoPlace<'tcx>, Option<&'tcx PlaceElem<'tcx>>) {
299+
// split place_elems
300+
// Base.[a, b, c]
301+
// ^^^^ ^-- projection(projection lives in the last elem)
302+
// |-- place_elems
303+
match self.elems.split_last() {
304+
Some((projection, place_elems)) => (
305+
NeoPlace {
306+
base: self.clone().base,
307+
elems: tcx.intern_place_elems(place_elems),
199308
},
200-
_ => None,
201-
}
202-
_ => None,
309+
Some(projection),
310+
),
311+
_ => (self.clone(), None)
312+
}
313+
}
314+
315+
pub fn has_no_projection(&self) -> bool {
316+
self.elems.is_empty()
317+
}
318+
319+
// for projection returns the base place;
320+
// Base.[a, b, c] => Base.[a, b]
321+
// ^-- projection
322+
// if no projection returns the place itself,
323+
// Base.[] => Base.[]
324+
// ^^-- no projection
325+
pub fn projection_base<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> NeoPlace<'tcx> {
326+
match self.split_projection(tcx) {
327+
(place, Some(_)) => place,
328+
(_, None) => self.clone(),
203329
}
204330
}
205331
}

src/librustc_mir/borrow_check/error_reporting.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,8 +1598,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15981598
Place::Projection(ref proj) => {
15991599
match proj.elem {
16001600
ProjectionElem::Deref => {
1601+
let neo_place = self.infcx.tcx.as_new_place(place);
16011602
let upvar_field_projection =
1602-
place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
1603+
neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
16031604
if let Some(field) = upvar_field_projection {
16041605
let var_index = field.index();
16051606
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
@@ -1659,9 +1660,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16591660
}
16601661
ProjectionElem::Field(field, _ty) => {
16611662
autoderef = true;
1662-
1663+
let neo_place = self.infcx.tcx.as_new_place(place);
16631664
let upvar_field_projection =
1664-
place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
1665+
neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
16651666
if let Some(field) = upvar_field_projection {
16661667
let var_index = field.index();
16671668
let name = self.mir.upvar_decls[var_index].debug_name.to_string();

src/librustc_mir/borrow_check/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
12351235
}
12361236
Operand::Move(ref place @ Place::Projection(_))
12371237
| Operand::Copy(ref place @ Place::Projection(_)) => {
1238-
if let Some(field) = place.is_upvar_field_projection(
1238+
let neo_place = self.infcx.tcx.as_new_place(place);
1239+
if let Some(field) = neo_place.is_upvar_field_projection(
12391240
self.mir, &self.infcx.tcx) {
12401241
self.used_mut_upvars.push(field);
12411242
}
@@ -1965,7 +1966,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
19651966
place: place @ Place::Projection(_),
19661967
is_local_mutation_allowed: _,
19671968
} => {
1968-
if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) {
1969+
let place = self.infcx.tcx.as_new_place(&place);
1970+
if let Some(field) =
1971+
place.is_upvar_field_projection(self.mir, &self.infcx.tcx) {
19691972
self.used_mut_upvars.push(field);
19701973
}
19711974
}
@@ -2038,7 +2041,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
20382041
// Mutably borrowed data is mutable, but only if we have a
20392042
// unique path to the `&mut`
20402043
hir::MutMutable => {
2041-
let mode = match place.is_upvar_field_projection(
2044+
let neo_place = self.infcx.tcx.as_new_place(place);
2045+
let mode = match neo_place.is_upvar_field_projection(
20422046
self.mir, &self.infcx.tcx)
20432047
{
20442048
Some(field)
@@ -2084,7 +2088,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
20842088
| ProjectionElem::ConstantIndex { .. }
20852089
| ProjectionElem::Subslice { .. }
20862090
| ProjectionElem::Downcast(..) => {
2087-
let upvar_field_projection = place.is_upvar_field_projection(
2091+
let neo_place = self.infcx.tcx.as_new_place(place);
2092+
let upvar_field_projection = neo_place.is_upvar_field_projection(
20882093
self.mir, &self.infcx.tcx);
20892094
if let Some(field) = upvar_field_projection {
20902095
let decl = &self.mir.upvar_decls[field.index()];

src/librustc_mir/borrow_check/move_errors.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
254254
},
255255
};
256256
let origin = Origin::Mir;
257+
let neo_place = self.infcx.tcx.as_new_place(original_path);
258+
let upvar_field_projection =
259+
neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
257260
debug!("report: original_path={:?} span={:?}, kind={:?} \
258261
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
259-
original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx));
262+
upvar_field_projection);
260263
(
261264
match kind {
262265
IllegalMoveOriginKind::Static => {
@@ -269,6 +272,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
269272
let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
270273
let is_upvar_field_projection =
271274
self.prefixes(&original_path, PrefixSet::All)
275+
.map(|p| self.infcx.tcx.as_new_place(&p))
272276
.any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx)
273277
.is_some());
274278
debug!("report: ty={:?}", ty);
@@ -303,6 +307,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
303307
span, place_description, origin);
304308

305309
for prefix in self.prefixes(&original_path, PrefixSet::All) {
310+
let prefix = self.infcx.tcx.as_new_place(prefix);
306311
if let Some(field) = prefix.is_upvar_field_projection(
307312
self.mir, &self.infcx.tcx) {
308313
let upvar_decl = &self.mir.upvar_decls[field.index()];

src/librustc_mir/borrow_check/mutability_errors.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
6666
));
6767

6868
item_msg = format!("`{}`", access_place_desc.unwrap());
69-
if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() {
69+
let neo_place = self.infcx.tcx.as_new_place(access_place);
70+
if neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() {
7071
reason = ", as it is not declared as mutable".to_string();
7172
} else {
7273
let name = self.mir.upvar_decls[upvar_index.index()].debug_name;
@@ -84,8 +85,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
8485
debug_assert!(is_closure_or_generator(
8586
the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx)
8687
));
87-
88-
reason = if access_place.is_upvar_field_projection(self.mir,
88+
let neo_place = self.infcx.tcx.as_new_place(access_place);
89+
reason = if neo_place.is_upvar_field_projection(self.mir,
8990
&self.infcx.tcx).is_some() {
9091
", as it is a captured variable in a `Fn` closure".to_string()
9192
} else {

0 commit comments

Comments
 (0)