use PlaceRef abstractions more consistently

This commit is contained in:
Eric Mark Martin 2023-06-25 20:38:01 -04:00
parent 0c2c243342
commit c07c10d1e4
10 changed files with 40 additions and 93 deletions

View File

@ -123,13 +123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
item_msg = access_place_desc; item_msg = access_place_desc;
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
debug_assert!(is_closure_or_generator( debug_assert!(is_closure_or_generator(
Place::ty_from( the_place_err.ty(self.body, self.infcx.tcx).ty
the_place_err.local,
the_place_err.projection,
self.body,
self.infcx.tcx
)
.ty
)); ));
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {

View File

@ -46,11 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
} }
} }
for (i, elem) in self.projection.iter().enumerate() { for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
let proj_base = &self.projection[..i];
if elem == ProjectionElem::Deref { if elem == ProjectionElem::Deref {
let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; let ty = proj_base.ty(body, tcx).ty;
match ty.kind() { match ty.kind() {
ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
// For references to thread-local statics, we do need // For references to thread-local statics, we do need

View File

@ -135,13 +135,11 @@ fn place_components_conflict<'tcx>(
} }
// loop invariant: borrow_c is always either equal to access_c or disjoint from it. // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, &access_c)) in for ((borrow_place, borrow_c), &access_c) in
iter::zip(borrow_place.projection, access_place.projection).enumerate() iter::zip(borrow_place.iter_projections(), access_place.projection)
{ {
debug!(?borrow_c, ?access_c); debug!(?borrow_c, ?access_c);
let borrow_proj_base = &borrow_place.projection[..i];
// Borrow and access path both have more components. // Borrow and access path both have more components.
// //
// Examples: // Examples:
@ -154,15 +152,7 @@ fn place_components_conflict<'tcx>(
// check whether the components being borrowed vs // check whether the components being borrowed vs
// accessed are disjoint (as in the second example, // accessed are disjoint (as in the second example,
// but not the first). // but not the first).
match place_projection_conflict( match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) {
tcx,
body,
borrow_local,
borrow_proj_base,
borrow_c,
access_c,
bias,
) {
Overlap::Arbitrary => { Overlap::Arbitrary => {
// We have encountered different fields of potentially // We have encountered different fields of potentially
// the same union - the borrow now partially overlaps. // the same union - the borrow now partially overlaps.
@ -193,8 +183,7 @@ fn place_components_conflict<'tcx>(
} }
if borrow_place.projection.len() > access_place.projection.len() { if borrow_place.projection.len() > access_place.projection.len() {
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) {
{
// Borrow path is longer than the access path. Examples: // Borrow path is longer than the access path. Examples:
// //
// - borrow of `a.b.c`, access to `a.b` // - borrow of `a.b.c`, access to `a.b`
@ -203,8 +192,7 @@ fn place_components_conflict<'tcx>(
// our place. This is a conflict if that is a part our // our place. This is a conflict if that is a part our
// access cares about. // access cares about.
let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; let base_ty = base.ty(body, tcx).ty;
let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
match (elem, &base_ty.kind(), access) { match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength))) (_, _, Shallow(Some(ArtificialField::ArrayLength)))
@ -308,8 +296,7 @@ fn place_base_conflict(l1: Local, l2: Local) -> Overlap {
fn place_projection_conflict<'tcx>( fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
pi1_local: Local, pi1: PlaceRef<'tcx>,
pi1_proj_base: &[PlaceElem<'tcx>],
pi1_elem: PlaceElem<'tcx>, pi1_elem: PlaceElem<'tcx>,
pi2_elem: PlaceElem<'tcx>, pi2_elem: PlaceElem<'tcx>,
bias: PlaceConflictBias, bias: PlaceConflictBias,
@ -331,7 +318,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint Overlap::EqualOrDisjoint
} else { } else {
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; let ty = pi1.ty(body, tcx).ty;
if ty.is_union() { if ty.is_union() {
// Different fields of a union, we are basically stuck. // Different fields of a union, we are basically stuck.
debug!("place_element_conflict: STUCK-UNION"); debug!("place_element_conflict: STUCK-UNION");

View File

@ -2499,7 +2499,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location, borrow_region, borrowed_place location, borrow_region, borrowed_place
); );
let mut cursor = borrowed_place.projection.as_ref();
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection( let field = path_utils::is_upvar_field_projection(
tcx, tcx,
@ -2513,14 +2512,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring ConstraintCategory::Boring
}; };
while let [proj_base @ .., elem] = cursor { for (base, elem) in borrowed_place.as_ref().iter_projections().rev() {
cursor = proj_base;
debug!("add_reborrow_constraint - iteration {:?}", elem); debug!("add_reborrow_constraint - iteration {:?}", elem);
match elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; let base_ty = base.ty(body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.kind() { match base_ty.kind() {

View File

@ -617,30 +617,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
} }
fn visit_projection_elem( fn visit_projection_elem(
&mut self, &mut self,
place_local: Local, place_ref: PlaceRef<'tcx>,
proj_base: &[PlaceElem<'tcx>],
elem: PlaceElem<'tcx>, elem: PlaceElem<'tcx>,
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
) { ) {
trace!( trace!(
"visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \ "visit_projection_elem: place_ref={:?} elem={:?} \
context={:?} location={:?}", context={:?} location={:?}",
place_local, place_ref,
proj_base,
elem, elem,
context, context,
location, location,
); );
self.super_projection_elem(place_local, proj_base, elem, context, location); self.super_projection_elem(place_ref, elem, context, location);
match elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; let base_ty = place_ref.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() { if base_ty.is_unsafe_ptr() {
if proj_base.is_empty() { if place_ref.projection.is_empty() {
let decl = &self.body.local_decls[place_local]; let decl = &self.body.local_decls[place_ref.local];
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
let span = decl.source_info.span; let span = decl.source_info.span;
self.check_static(def_id, span); self.check_static(def_id, span);

View File

@ -318,8 +318,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_projection_elem( fn visit_projection_elem(
&mut self, &mut self,
local: Local, place_ref: PlaceRef<'tcx>,
proj_base: &[PlaceElem<'tcx>],
elem: PlaceElem<'tcx>, elem: PlaceElem<'tcx>,
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
@ -334,7 +333,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ProjectionElem::Deref ProjectionElem::Deref
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) => if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
{ {
let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty; let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
if base_ty.is_box() { if base_ty.is_box() {
self.fail( self.fail(
@ -344,8 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
} }
ProjectionElem::Field(f, ty) => { ProjectionElem::Field(f, ty) => {
let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) }; let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds = |this: &Self, location| { let fail_out_of_bounds = |this: &Self, location| {
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty)); this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
}; };
@ -355,7 +353,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
location, location,
format!( format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`", "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
parent, f, ty, f_ty place_ref, f, ty, f_ty
) )
) )
} }
@ -434,7 +432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
_ => {} _ => {}
} }
self.super_projection_elem(local, proj_base, elem, context, location); self.super_projection_elem(place_ref, elem, context, location);
} }
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {

View File

@ -1136,13 +1136,12 @@ macro_rules! visit_place_fns {
fn visit_projection_elem( fn visit_projection_elem(
&mut self, &mut self,
local: Local, place_ref: PlaceRef<'tcx>,
proj_base: &[PlaceElem<'tcx>],
elem: PlaceElem<'tcx>, elem: PlaceElem<'tcx>,
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
) { ) {
self.super_projection_elem(local, proj_base, elem, context, location); self.super_projection_elem(place_ref, elem, context, location);
} }
fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
@ -1171,15 +1170,13 @@ macro_rules! visit_place_fns {
location: Location, location: Location,
) { ) {
for (base, elem) in place_ref.iter_projections().rev() { for (base, elem) in place_ref.iter_projections().rev() {
let base_proj = base.projection; self.visit_projection_elem(base, elem, context, location);
self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
} }
} }
fn super_projection_elem( fn super_projection_elem(
&mut self, &mut self,
_local: Local, _place_ref: PlaceRef<'tcx>,
_proj_base: &[PlaceElem<'tcx>],
elem: PlaceElem<'tcx>, elem: PlaceElem<'tcx>,
_context: PlaceContext, _context: PlaceContext,
location: Location, location: Location,

View File

@ -677,21 +677,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// check that we just did stays valid. Since we can't assign to // check that we just did stays valid. Since we can't assign to
// unsized values, we only need to ensure that none of the // unsized values, we only need to ensure that none of the
// pointers in the base place are modified. // pointers in the base place are modified.
for (idx, elem) in base_place.projection.iter().enumerate().rev() { for (base_place, elem) in base_place.iter_projections().rev() {
match elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let fake_borrow_deref_ty = Place::ty_from( let fake_borrow_deref_ty = base_place.ty(&self.local_decls, tcx).ty;
base_place.local,
&base_place.projection[..idx],
&self.local_decls,
tcx,
)
.ty;
let fake_borrow_ty = let fake_borrow_ty =
tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
let fake_borrow_temp = let fake_borrow_temp =
self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span)); self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
let projection = tcx.mk_place_elems(&base_place.projection[..idx]); let projection = tcx.mk_place_elems(&base_place.projection);
self.cfg.push_assign( self.cfg.push_assign(
block, block,
source_info, source_info,
@ -705,12 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fake_borrow_temps.push(fake_borrow_temp); fake_borrow_temps.push(fake_borrow_temp);
} }
ProjectionElem::Index(_) => { ProjectionElem::Index(_) => {
let index_ty = Place::ty_from( let index_ty = base_place.ty(&self.local_decls, tcx);
base_place.local,
&base_place.projection[..idx],
&self.local_decls,
tcx,
);
match index_ty.ty.kind() { match index_ty.ty.kind() {
// The previous index expression has already // The previous index expression has already
// done any index expressions needed here. // done any index expressions needed here.

View File

@ -113,22 +113,16 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// from `*(u.f: &_)` isn't allowed. // from `*(u.f: &_)` isn't allowed.
let mut union_path = None; let mut union_path = None;
for (i, elem) in place.projection.iter().enumerate() { for (place_ref, elem) in place.as_ref().iter_projections() {
let proj_base = &place.projection[..i];
let body = self.builder.body; let body = self.builder.body;
let tcx = self.builder.tcx; let tcx = self.builder.tcx;
let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; let place_ty = place_ref.ty(body, tcx).ty;
match place_ty.kind() { match place_ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => { ty::Ref(..) | ty::RawPtr(..) => {
let proj = &place.projection[..i + 1];
return Err(MoveError::cannot_move_out_of( return Err(MoveError::cannot_move_out_of(
self.loc, self.loc,
BorrowedContent { BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
target_place: Place {
local: place.local,
projection: tcx.mk_place_elems(proj),
},
},
)); ));
} }
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
@ -163,10 +157,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}; };
if union_path.is_none() { if union_path.is_none() {
base = self.add_move_path(base, elem, |tcx| Place { base = self.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
local: place.local,
projection: tcx.mk_place_elems(&place.projection[..i + 1]),
});
} }
} }

View File

@ -839,15 +839,13 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
/// to normalization failure. /// to normalization failure.
fn visit_projection_elem( fn visit_projection_elem(
&mut self, &mut self,
local: Local, place_ref: PlaceRef<'tcx>,
proj_base: &[PlaceElem<'tcx>],
elem: PlaceElem<'tcx>, elem: PlaceElem<'tcx>,
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
) { ) {
if let ProjectionElem::Field(f, ty) = elem { if let ProjectionElem::Field(f, ty) = elem {
let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) }; let parent_ty = place_ref.ty(&self.callee_body.local_decls, self.tcx);
let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx);
let check_equal = |this: &mut Self, f_ty| { let check_equal = |this: &mut Self, f_ty| {
if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) { if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
trace!(?ty, ?f_ty); trace!(?ty, ?f_ty);
@ -926,7 +924,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
} }
} }
self.super_projection_elem(local, proj_base, elem, context, location); self.super_projection_elem(place_ref, elem, context, location);
} }
} }