about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2019-09-30 13:09:10 -0300
committerSantiago Pastorino <spastorino@gmail.com>2019-10-02 10:53:22 -0300
commit79dc862d4a8c0690fbc50d7ebd129fab2e199a49 (patch)
treebb77f7893f1288488a0c7dfc2b6b2cff951bd458
parentbf8491e72ef0d5ea0ef683e9d149408a717545e4 (diff)
downloadrust-79dc862d4a8c0690fbc50d7ebd129fab2e199a49.tar.gz
rust-79dc862d4a8c0690fbc50d7ebd129fab2e199a49.zip
Use PlaceBuilder to avoid a lot of slice -> vec -> slice convertions
-rw-r--r--src/librustc_mir/build/expr/as_place.rs144
1 files changed, 114 insertions, 30 deletions
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 09b33c6654a..ecbf4699015 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -6,13 +6,79 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
 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 @@ impl<'a, 'tcx> Builder<'a, '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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     block,
                     source_info, // len = len(slice)
                     &len,
-                    Rvalue::Len(slice.clone()),
+                    Rvalue::Len(slice),
                 );
                 this.cfg.push_assign(
                     block,
@@ -110,30 +193,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         },
                     );
                 }
-                block.and(place)
+                block.and(place_builder)
             }
             ExprKind::ValueTypeAscription { source, user_ty } => {
                 let source = this.hir.mirror(source);
@@ -185,7 +269,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         },
                     );
                 }
-                block.and(Place::from(temp))
+                block.and(PlaceBuilder::from(temp))
             }
 
             ExprKind::Array { .. }
@@ -221,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 });
                 let temp =
                     unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
-                block.and(Place::from(temp))
+                block.and(PlaceBuilder::from(temp))
             }
         }
     }