@@ -6,13 +6,79 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
66use crate :: hair:: * ;
77use rustc:: mir:: interpret:: { PanicInfo :: BoundsCheck } ;
88use rustc:: mir:: * ;
9- use rustc:: ty:: { CanonicalUserTypeAnnotation , Variance } ;
9+ use rustc:: ty:: { CanonicalUserTypeAnnotation , Ty , Variance } ;
1010
1111use rustc_data_structures:: indexed_vec:: Idx ;
1212
13+ /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
14+ /// place by pushing more and more projections onto the end, and then convert the final set into a
15+ /// place using the `into_place` method.
16+ ///
17+ /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
18+ /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
19+ #[ derive( Clone ) ]
20+ struct PlaceBuilder < ' tcx > {
21+ base : PlaceBase < ' tcx > ,
22+ projection : Vec < PlaceElem < ' tcx > > ,
23+ }
24+
25+ impl PlaceBuilder < ' tcx > {
26+ fn into_place ( self ) -> Place < ' tcx > {
27+ Place {
28+ base : self . base ,
29+ projection : self . projection . into_boxed_slice ( ) ,
30+ }
31+ }
32+
33+ fn field ( self , f : Field , ty : Ty < ' tcx > ) -> Self {
34+ self . project ( PlaceElem :: Field ( f, ty) )
35+ }
36+
37+ fn deref ( self ) -> Self {
38+ self . project ( PlaceElem :: Deref )
39+ }
40+
41+ fn index ( self , index : Local ) -> Self {
42+ self . project ( PlaceElem :: Index ( index) )
43+ }
44+
45+ fn project ( mut self , elem : PlaceElem < ' tcx > ) -> Self {
46+ self . projection . push ( elem) ;
47+ self
48+ }
49+ }
50+
51+ impl From < Local > for PlaceBuilder < ' tcx > {
52+ fn from ( local : Local ) -> Self {
53+ Self {
54+ base : local. into ( ) ,
55+ projection : Vec :: new ( ) ,
56+ }
57+ }
58+ }
59+
60+ impl From < PlaceBase < ' tcx > > for PlaceBuilder < ' tcx > {
61+ fn from ( base : PlaceBase < ' tcx > ) -> Self {
62+ Self {
63+ base,
64+ projection : Vec :: new ( ) ,
65+ }
66+ }
67+ }
68+
1369impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1470 /// Compile `expr`, yielding a place that we can move from etc.
15- pub fn as_place < M > ( & mut self , block : BasicBlock , expr : M ) -> BlockAnd < Place < ' tcx > >
71+ pub fn as_place < M > ( & mut self , mut block : BasicBlock , expr : M ) -> BlockAnd < Place < ' tcx > >
72+ where
73+ M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
74+ {
75+ let place_builder = unpack ! ( block = self . as_place_builder( block, expr) ) ;
76+ block. and ( place_builder. into_place ( ) )
77+ }
78+
79+ /// This is used when constructing a compound `Place`, so that we can avoid creating
80+ /// intermediate `Place` values until we know the full set of projections.
81+ fn as_place_builder < M > ( & mut self , block : BasicBlock , expr : M ) -> BlockAnd < PlaceBuilder < ' tcx > >
1682 where
1783 M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
1884 {
@@ -25,7 +91,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2591 /// place. The place itself may or may not be mutable:
2692 /// * If this expr is a place expr like a.b, then we will return that place.
2793 /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
28- pub fn as_read_only_place < M > ( & mut self , block : BasicBlock , expr : M ) -> BlockAnd < Place < ' tcx > >
94+ pub fn as_read_only_place < M > ( & mut self , mut block : BasicBlock , expr : M ) -> BlockAnd < Place < ' tcx > >
95+ where
96+ M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
97+ {
98+ let place_builder = unpack ! ( block = self . as_read_only_place_builder( block, expr) ) ;
99+ block. and ( place_builder. into_place ( ) )
100+ }
101+
102+ /// This is used when constructing a compound `Place`, so that we can avoid creating
103+ /// intermediate `Place` values until we know the full set of projections.
104+ /// Mutability note: The caller of this method promises only to read from the resulting
105+ /// place. The place itself may or may not be mutable:
106+ /// * If this expr is a place expr like a.b, then we will return that place.
107+ /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
108+ fn as_read_only_place_builder < M > (
109+ & mut self ,
110+ block : BasicBlock ,
111+ expr : M ,
112+ ) -> BlockAnd < PlaceBuilder < ' tcx > >
29113 where
30114 M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
31115 {
@@ -38,7 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
38122 mut block : BasicBlock ,
39123 expr : Expr < ' tcx > ,
40124 mutability : Mutability ,
41- ) -> BlockAnd < Place < ' tcx > > {
125+ ) -> BlockAnd < PlaceBuilder < ' tcx > > {
42126 debug ! (
43127 "expr_as_place(block={:?}, expr={:?}, mutability={:?})" ,
44128 block, expr, mutability
@@ -54,25 +138,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
54138 value,
55139 } => this. in_scope ( ( region_scope, source_info) , lint_level, |this| {
56140 if mutability == Mutability :: Not {
57- this. as_read_only_place ( block, value)
141+ this. as_read_only_place_builder ( block, value)
58142 } else {
59- this. as_place ( block, value)
143+ this. as_place_builder ( block, value)
60144 }
61145 } ) ,
62146 ExprKind :: Field { lhs, name } => {
63- let place = unpack ! ( block = this. as_place( block, lhs) ) ;
64- let place = place. field ( name, expr. ty ) ;
65- block. and ( place)
147+ let place_builder = unpack ! ( block = this. as_place_builder( block, lhs) ) ;
148+ block. and ( place_builder. field ( name, expr. ty ) )
66149 }
67150 ExprKind :: Deref { arg } => {
68- let place = unpack ! ( block = this. as_place( block, arg) ) ;
69- let place = place. deref ( ) ;
70- block. and ( place)
151+ let place_builder = unpack ! ( block = this. as_place_builder( block, arg) ) ;
152+ block. and ( place_builder. deref ( ) )
71153 }
72154 ExprKind :: Index { lhs, index } => {
73155 let ( usize_ty, bool_ty) = ( this. hir . usize_ty ( ) , this. hir . bool_ty ( ) ) ;
74156
75- let slice = unpack ! ( block = this. as_place ( block, lhs) ) ;
157+ let place_builder = unpack ! ( block = this. as_place_builder ( block, lhs) ) ;
76158 // Making this a *fresh* temporary also means we do not have to worry about
77159 // the index changing later: Nothing will ever change this temporary.
78160 // The "retagging" transformation (for Stacked Borrows) relies on this.
@@ -83,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
83165 Mutability :: Not ,
84166 ) ) ;
85167
168+ let slice = place_builder. clone ( ) . into_place ( ) ;
86169 // bounds check:
87170 let ( len, lt) = (
88171 this. temp ( usize_ty. clone ( ) , expr_span) ,
@@ -92,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
92175 block,
93176 source_info, // len = len(slice)
94177 & len,
95- Rvalue :: Len ( slice. clone ( ) ) ,
178+ Rvalue :: Len ( slice) ,
96179 ) ;
97180 this. cfg . push_assign (
98181 block,
@@ -110,30 +193,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
110193 index : Operand :: Copy ( Place :: from ( idx) ) ,
111194 } ;
112195 let success = this. assert ( block, Operand :: Move ( lt) , true , msg, expr_span) ;
113- success. and ( slice . index ( idx) )
196+ success. and ( place_builder . index ( idx) )
114197 }
115- ExprKind :: SelfRef => block. and ( Place :: from ( Local :: new ( 1 ) ) ) ,
198+ ExprKind :: SelfRef => block. and ( PlaceBuilder :: from ( Local :: new ( 1 ) ) ) ,
116199 ExprKind :: VarRef { id } => {
117- let place = if this. is_bound_var_in_guard ( id) {
200+ let place_builder = if this. is_bound_var_in_guard ( id) {
118201 let index = this. var_local_id ( id, RefWithinGuard ) ;
119- Place :: from ( index) . deref ( )
202+ PlaceBuilder :: from ( index) . deref ( )
120203 } else {
121204 let index = this. var_local_id ( id, OutsideGuard ) ;
122- Place :: from ( index)
205+ PlaceBuilder :: from ( index)
123206 } ;
124- block. and ( place )
207+ block. and ( place_builder )
125208 }
126- ExprKind :: StaticRef { id } => block. and ( Place {
127- base : PlaceBase :: Static ( Box :: new ( Static {
209+ ExprKind :: StaticRef { id } => block. and ( PlaceBuilder :: from (
210+ PlaceBase :: Static ( Box :: new ( Static {
128211 ty : expr. ty ,
129212 kind : StaticKind :: Static ,
130213 def_id : id,
131- } ) ) ,
132- projection : box [ ] ,
133- } ) ,
214+ } ) )
215+ ) ) ,
134216
135217 ExprKind :: PlaceTypeAscription { source, user_ty } => {
136- let place = unpack ! ( block = this. as_place ( block, source) ) ;
218+ let place_builder = unpack ! ( block = this. as_place_builder ( block, source) ) ;
137219 if let Some ( user_ty) = user_ty {
138220 let annotation_index = this. canonical_user_type_annotations . push (
139221 CanonicalUserTypeAnnotation {
@@ -142,21 +224,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
142224 inferred_ty : expr. ty ,
143225 }
144226 ) ;
227+
228+ let place = place_builder. clone ( ) . into_place ( ) ;
145229 this. cfg . push (
146230 block,
147231 Statement {
148232 source_info,
149233 kind : StatementKind :: AscribeUserType (
150234 box (
151- place. clone ( ) ,
235+ place,
152236 UserTypeProjection { base : annotation_index, projs : vec ! [ ] , }
153237 ) ,
154238 Variance :: Invariant ,
155239 ) ,
156240 } ,
157241 ) ;
158242 }
159- block. and ( place )
243+ block. and ( place_builder )
160244 }
161245 ExprKind :: ValueTypeAscription { source, user_ty } => {
162246 let source = this. hir . mirror ( source) ;
@@ -185,7 +269,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
185269 } ,
186270 ) ;
187271 }
188- block. and ( Place :: from ( temp) )
272+ block. and ( PlaceBuilder :: from ( temp) )
189273 }
190274
191275 ExprKind :: Array { .. }
@@ -221,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
221305 } ) ;
222306 let temp =
223307 unpack ! ( block = this. as_temp( block, expr. temp_lifetime, expr, mutability) ) ;
224- block. and ( Place :: from ( temp) )
308+ block. and ( PlaceBuilder :: from ( temp) )
225309 }
226310 }
227311 }
0 commit comments