@@ -25,11 +25,13 @@ static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
25
25
mem:: size_of:: <PlaceTy <' _>>( ) <= 24
26
26
) ;
27
27
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 {
30
30
PlaceTy :: Ty { ty }
31
31
}
32
+ }
32
33
34
+ impl < ' a , ' gcx , ' tcx > PlaceTy < ' tcx > {
33
35
pub fn to_ty ( & self , tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> Ty < ' tcx > {
34
36
match * self {
35
37
PlaceTy :: Ty { ty } =>
@@ -168,38 +170,162 @@ impl<'tcx> Place<'tcx> {
168
170
}
169
171
}
170
172
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
+
171
246
/// If this is a field projection, and the field is being projected from a closure type,
172
247
/// then returns the index of the field being projected. Note that this closure will always
173
248
/// be `self` in the current MIR, because that is the only time we directly access the fields
174
249
/// 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)
180
279
} else {
181
- ( self , false )
280
+ None
182
281
}
183
282
} else {
184
- ( self , false )
185
- } ;
283
+ None
284
+ }
285
+ }
186
286
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) ,
199
308
} ,
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 ( ) ,
203
329
}
204
330
}
205
331
}
0 commit comments