Use PlaceBuilder to avoid a lot of slice -> vec -> slice convertions
This commit is contained in:
parent
bf8491e72e
commit
79dc862d4a
@ -6,13 +6,79 @@
|
||||
use crate::hair::*;
|
||||
use rustc::mir::interpret::{PanicInfo::BoundsCheck};
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
|
||||
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance};
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
|
||||
/// place by pushing more and more projections onto the end, and then convert the final set into a
|
||||
/// place using the `into_place` method.
|
||||
///
|
||||
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
|
||||
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
|
||||
#[derive(Clone)]
|
||||
struct PlaceBuilder<'tcx> {
|
||||
base: PlaceBase<'tcx>,
|
||||
projection: Vec<PlaceElem<'tcx>>,
|
||||
}
|
||||
|
||||
impl PlaceBuilder<'tcx> {
|
||||
fn into_place(self) -> Place<'tcx> {
|
||||
Place {
|
||||
base: self.base,
|
||||
projection: self.projection.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
|
||||
self.project(PlaceElem::Field(f, ty))
|
||||
}
|
||||
|
||||
fn deref(self) -> Self {
|
||||
self.project(PlaceElem::Deref)
|
||||
}
|
||||
|
||||
fn index(self, index: Local) -> Self {
|
||||
self.project(PlaceElem::Index(index))
|
||||
}
|
||||
|
||||
fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
|
||||
self.projection.push(elem);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Local> for PlaceBuilder<'tcx> {
|
||||
fn from(local: Local) -> Self {
|
||||
Self {
|
||||
base: local.into(),
|
||||
projection: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PlaceBase<'tcx>> for PlaceBuilder<'tcx> {
|
||||
fn from(base: PlaceBase<'tcx>) -> Self {
|
||||
Self {
|
||||
base,
|
||||
projection: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// Compile `expr`, yielding a place that we can move from etc.
|
||||
pub fn as_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
|
||||
pub fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let place_builder = unpack!(block = self.as_place_builder(block, expr));
|
||||
block.and(place_builder.into_place())
|
||||
}
|
||||
|
||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||
/// intermediate `Place` values until we know the full set of projections.
|
||||
fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
@ -25,7 +91,25 @@ pub fn as_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx
|
||||
/// place. The place itself may or may not be mutable:
|
||||
/// * If this expr is a place expr like a.b, then we will return that place.
|
||||
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
||||
pub fn as_read_only_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
|
||||
pub fn as_read_only_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
|
||||
block.and(place_builder.into_place())
|
||||
}
|
||||
|
||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||
/// intermediate `Place` values until we know the full set of projections.
|
||||
/// Mutability note: The caller of this method promises only to read from the resulting
|
||||
/// place. The place itself may or may not be mutable:
|
||||
/// * If this expr is a place expr like a.b, then we will return that place.
|
||||
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
|
||||
fn as_read_only_place_builder<M>(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M,
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>>
|
||||
where
|
||||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
@ -38,7 +122,7 @@ fn expr_as_place(
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<'tcx>,
|
||||
mutability: Mutability,
|
||||
) -> BlockAnd<Place<'tcx>> {
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||
debug!(
|
||||
"expr_as_place(block={:?}, expr={:?}, mutability={:?})",
|
||||
block, expr, mutability
|
||||
@ -54,25 +138,23 @@ fn expr_as_place(
|
||||
value,
|
||||
} => this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||
if mutability == Mutability::Not {
|
||||
this.as_read_only_place(block, value)
|
||||
this.as_read_only_place_builder(block, value)
|
||||
} else {
|
||||
this.as_place(block, value)
|
||||
this.as_place_builder(block, value)
|
||||
}
|
||||
}),
|
||||
ExprKind::Field { lhs, name } => {
|
||||
let place = unpack!(block = this.as_place(block, lhs));
|
||||
let place = place.field(name, expr.ty);
|
||||
block.and(place)
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, lhs));
|
||||
block.and(place_builder.field(name, expr.ty))
|
||||
}
|
||||
ExprKind::Deref { arg } => {
|
||||
let place = unpack!(block = this.as_place(block, arg));
|
||||
let place = place.deref();
|
||||
block.and(place)
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, arg));
|
||||
block.and(place_builder.deref())
|
||||
}
|
||||
ExprKind::Index { lhs, index } => {
|
||||
let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
|
||||
|
||||
let slice = unpack!(block = this.as_place(block, lhs));
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, lhs));
|
||||
// Making this a *fresh* temporary also means we do not have to worry about
|
||||
// the index changing later: Nothing will ever change this temporary.
|
||||
// The "retagging" transformation (for Stacked Borrows) relies on this.
|
||||
@ -83,6 +165,7 @@ fn expr_as_place(
|
||||
Mutability::Not,
|
||||
));
|
||||
|
||||
let slice = place_builder.clone().into_place();
|
||||
// bounds check:
|
||||
let (len, lt) = (
|
||||
this.temp(usize_ty.clone(), expr_span),
|
||||
@ -92,7 +175,7 @@ fn expr_as_place(
|
||||
block,
|
||||
source_info, // len = len(slice)
|
||||
&len,
|
||||
Rvalue::Len(slice.clone()),
|
||||
Rvalue::Len(slice),
|
||||
);
|
||||
this.cfg.push_assign(
|
||||
block,
|
||||
@ -110,30 +193,29 @@ fn expr_as_place(
|
||||
index: Operand::Copy(Place::from(idx)),
|
||||
};
|
||||
let success = this.assert(block, Operand::Move(lt), true, msg, expr_span);
|
||||
success.and(slice.index(idx))
|
||||
success.and(place_builder.index(idx))
|
||||
}
|
||||
ExprKind::SelfRef => block.and(Place::from(Local::new(1))),
|
||||
ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
|
||||
ExprKind::VarRef { id } => {
|
||||
let place = if this.is_bound_var_in_guard(id) {
|
||||
let place_builder = if this.is_bound_var_in_guard(id) {
|
||||
let index = this.var_local_id(id, RefWithinGuard);
|
||||
Place::from(index).deref()
|
||||
PlaceBuilder::from(index).deref()
|
||||
} else {
|
||||
let index = this.var_local_id(id, OutsideGuard);
|
||||
Place::from(index)
|
||||
PlaceBuilder::from(index)
|
||||
};
|
||||
block.and(place)
|
||||
block.and(place_builder)
|
||||
}
|
||||
ExprKind::StaticRef { id } => block.and(Place {
|
||||
base: PlaceBase::Static(Box::new(Static {
|
||||
ExprKind::StaticRef { id } => block.and(PlaceBuilder::from(
|
||||
PlaceBase::Static(Box::new(Static {
|
||||
ty: expr.ty,
|
||||
kind: StaticKind::Static,
|
||||
def_id: id,
|
||||
})),
|
||||
projection: box [],
|
||||
}),
|
||||
}))
|
||||
)),
|
||||
|
||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||
let place = unpack!(block = this.as_place(block, source));
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, source));
|
||||
if let Some(user_ty) = user_ty {
|
||||
let annotation_index = this.canonical_user_type_annotations.push(
|
||||
CanonicalUserTypeAnnotation {
|
||||
@ -142,13 +224,15 @@ fn expr_as_place(
|
||||
inferred_ty: expr.ty,
|
||||
}
|
||||
);
|
||||
|
||||
let place = place_builder.clone().into_place();
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
box(
|
||||
place.clone(),
|
||||
place,
|
||||
UserTypeProjection { base: annotation_index, projs: vec![], }
|
||||
),
|
||||
Variance::Invariant,
|
||||
@ -156,7 +240,7 @@ fn expr_as_place(
|
||||
},
|
||||
);
|
||||
}
|
||||
block.and(place)
|
||||
block.and(place_builder)
|
||||
}
|
||||
ExprKind::ValueTypeAscription { source, user_ty } => {
|
||||
let source = this.hir.mirror(source);
|
||||
@ -185,7 +269,7 @@ fn expr_as_place(
|
||||
},
|
||||
);
|
||||
}
|
||||
block.and(Place::from(temp))
|
||||
block.and(PlaceBuilder::from(temp))
|
||||
}
|
||||
|
||||
ExprKind::Array { .. }
|
||||
@ -221,7 +305,7 @@ fn expr_as_place(
|
||||
});
|
||||
let temp =
|
||||
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
|
||||
block.and(Place::from(temp))
|
||||
block.and(PlaceBuilder::from(temp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user