@@ -218,7 +218,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
218
218
let upvar_resolved_place_builder = PlaceBuilder :: construct_local_place_builder (
219
219
cx,
220
220
upvar_resolved_local,
221
- local_projection. to_vec ( ) ,
221
+ local_projection. as_slice ( ) ,
222
222
upvar_projection,
223
223
) ;
224
224
@@ -266,7 +266,7 @@ fn strip_prefix<'a, 'tcx>(
266
266
mut base_ty : Ty < ' tcx > ,
267
267
projections : & ' a [ UpvarProjectionElem < ' tcx > ] ,
268
268
prefix_projections : & [ HirProjection < ' tcx > ] ,
269
- ) -> Vec < UpvarProjectionElem < ' tcx > > {
269
+ ) -> impl Iterator < Item = UpvarProjectionElem < ' tcx > > + ' a {
270
270
let mut iter = projections
271
271
. iter ( )
272
272
// Filter out opaque casts, they are unnecessary in the prefix.
@@ -293,7 +293,7 @@ fn strip_prefix<'a, 'tcx>(
293
293
base_ty = projection. ty ;
294
294
}
295
295
296
- iter. collect :: < Vec < _ > > ( )
296
+ iter
297
297
}
298
298
299
299
impl < ' tcx > PlaceBuilder < ' tcx > {
@@ -342,10 +342,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
342
342
343
343
#[ instrument( skip( cx) , level = "debug" ) ]
344
344
pub ( crate ) fn field ( self , cx : & Builder < ' _ , ' tcx > , f : Field ) -> Self {
345
- let field_ty = match self {
346
- PlaceBuilder :: Local ( ..) => {
347
- let base_place = self . clone ( ) ;
348
- PlaceBuilder :: compute_field_ty ( cx, f, base_place)
345
+ let field_ty = match self . clone ( ) {
346
+ PlaceBuilder :: Local ( local, projection) => {
347
+ let base_place = PlaceBuilder :: Local ( local, projection) ;
348
+ let PlaceTy { ty, variant_index } =
349
+ base_place. to_place ( cx) . ty ( & cx. local_decls , cx. tcx ) ;
350
+ let base_ty = cx. tcx . normalize_erasing_regions ( cx. param_env , ty) ;
351
+
352
+ PlaceBuilder :: compute_field_ty ( cx, f, base_ty, variant_index)
349
353
}
350
354
PlaceBuilder :: UpVar ( ..) => {
351
355
let dummy_ty = cx. tcx . mk_ty_infer ( ty:: FreshTy ( 0 ) ) ;
@@ -410,13 +414,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
410
414
fn compute_field_ty (
411
415
cx : & Builder < ' _ , ' tcx > ,
412
416
field : Field ,
413
- base_place : PlaceBuilder < ' tcx > ,
417
+ base_ty : Ty < ' tcx > ,
418
+ variant_index : Option < VariantIdx > ,
414
419
) -> Ty < ' tcx > {
415
420
let field_idx = field. as_usize ( ) ;
416
- let PlaceTy { ty, variant_index } = base_place. to_place ( cx) . ty ( & cx. local_decls , cx. tcx ) ;
417
- let base_ty = cx. tcx . normalize_erasing_regions ( cx. param_env , ty) ;
418
- debug ! ( ?base_ty) ;
419
-
420
421
let field_ty = match base_ty. kind ( ) {
421
422
ty:: Adt ( adt_def, substs) if adt_def. is_enum ( ) => {
422
423
let variant_idx = variant_index. unwrap ( ) ;
@@ -479,41 +480,38 @@ impl<'tcx> PlaceBuilder<'tcx> {
479
480
/// contains the projections of the captured upvar and `upvar_projection` the
480
481
/// projections that are applied to the captured upvar. The main purpose of this
481
482
/// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
482
- #[ instrument( skip( cx, local) ) ]
483
+ #[ instrument( skip( cx, local, upvar_projection ) ) ]
483
484
fn construct_local_place_builder (
484
485
cx : & Builder < ' _ , ' tcx > ,
485
486
local : Local ,
486
- mut local_projection : Vec < PlaceElem < ' tcx > > ,
487
- upvar_projection : Vec < UpvarProjectionElem < ' tcx > > ,
487
+ local_projection : & [ PlaceElem < ' tcx > ] ,
488
+ upvar_projection : impl Iterator < Item = UpvarProjectionElem < ' tcx > > ,
488
489
) -> Self {
489
- // We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
490
- // the ancestor projections, i.e. those projection elements that come before the field projection,
491
- // to get the `Ty` for the field.
492
-
493
- for proj in upvar_projection. iter ( ) {
494
- debug ! ( "proj: {:?}, local_projection: {:?}" , proj, local_projection) ;
495
- match * proj {
490
+ // We maintain a `Ty` to which we apply a projection in each iteration over `upvar_projection`.
491
+ // This `ancestor_ty` let's us infer the field type whenever we encounter a
492
+ // `ProjectionElem::Field`.
493
+ let ( mut ancestor_ty, mut opt_variant_idx) =
494
+ local_projections_to_ty ( cx, local, local_projection) ;
495
+
496
+ // We add all projection elements we encounter to this `Vec`.
497
+ let mut local_projection = local_projection. to_vec ( ) ;
498
+
499
+ for ( i, proj) in upvar_projection. enumerate ( ) {
500
+ debug ! ( "i: {:?}, proj: {:?}, local_projection: {:?}" , i, proj, local_projection) ;
501
+ match proj {
496
502
ProjectionElem :: Field ( field, _) => {
497
- let ancestor_proj = local_projection. to_vec ( ) ;
498
- let base_place = PlaceBuilder :: Local ( local, ancestor_proj) ;
499
- let field_ty = PlaceBuilder :: compute_field_ty ( cx, field, base_place) ;
503
+ let field_ty =
504
+ PlaceBuilder :: compute_field_ty ( cx, field, ancestor_ty, opt_variant_idx) ;
500
505
debug ! ( ?field_ty) ;
501
506
502
507
local_projection. push ( ProjectionElem :: Field ( field, field_ty) ) ;
503
- debug ! ( ?local_projection) ;
504
- }
505
- ProjectionElem :: Deref => local_projection. push ( ProjectionElem :: Deref ) ,
506
- ProjectionElem :: Index ( idx) => local_projection. push ( ProjectionElem :: Index ( idx) ) ,
507
- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => local_projection
508
- . push ( ProjectionElem :: ConstantIndex { offset, min_length, from_end } ) ,
509
- ProjectionElem :: Subslice { from, to, from_end } => {
510
- local_projection. push ( ProjectionElem :: Subslice { from, to, from_end } )
508
+ ancestor_ty = field_ty;
509
+ opt_variant_idx = None ;
511
510
}
512
- ProjectionElem :: Downcast ( sym, variant_idx) => {
513
- local_projection. push ( ProjectionElem :: Downcast ( sym, variant_idx) )
514
- }
515
- ProjectionElem :: OpaqueCast ( ty) => {
516
- local_projection. push ( ProjectionElem :: OpaqueCast ( ty) )
511
+ _ => {
512
+ let proj = upvar_proj_to_place_elem_no_field_proj ( proj) ;
513
+ ( ancestor_ty, opt_variant_idx) = project_ty ( cx. tcx , ancestor_ty, proj) ;
514
+ local_projection. push ( proj) ;
517
515
}
518
516
}
519
517
}
@@ -534,6 +532,81 @@ impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
534
532
}
535
533
}
536
534
535
+ fn project_ty < ' tcx > (
536
+ tcx : TyCtxt < ' tcx > ,
537
+ ty : Ty < ' tcx > ,
538
+ elem : PlaceElem < ' tcx > ,
539
+ ) -> ( Ty < ' tcx > , Option < VariantIdx > ) {
540
+ match elem {
541
+ ProjectionElem :: Deref => {
542
+ let updated_ty = ty
543
+ . builtin_deref ( true )
544
+ . unwrap_or_else ( || bug ! ( "deref projection of non-dereferenceable ty {:?}" , ty) )
545
+ . ty ;
546
+
547
+ ( updated_ty, None )
548
+ }
549
+ ProjectionElem :: Index ( _) | ProjectionElem :: ConstantIndex { .. } => {
550
+ ( ty. builtin_index ( ) . unwrap ( ) , None )
551
+ }
552
+ ProjectionElem :: Subslice { from, to, from_end } => {
553
+ let ty = match ty. kind ( ) {
554
+ ty:: Slice ( ..) => ty,
555
+ ty:: Array ( inner, _) if !from_end => tcx. mk_array ( * inner, ( to - from) as u64 ) ,
556
+ ty:: Array ( inner, size) if from_end => {
557
+ let size = size. eval_usize ( tcx, ty:: ParamEnv :: empty ( ) ) ;
558
+ let len = size - ( from as u64 ) - ( to as u64 ) ;
559
+ tcx. mk_array ( * inner, len)
560
+ }
561
+ _ => bug ! ( "cannot subslice non-array type: `{:?}`" , ty) ,
562
+ } ;
563
+
564
+ ( ty, None )
565
+ }
566
+ ProjectionElem :: Downcast ( _, variant_idx) => ( ty, Some ( variant_idx) ) ,
567
+ ProjectionElem :: Field ( _, ty) => {
568
+ if matches ! ( ty. kind( ) , ty:: Infer ( ..) ) {
569
+ bug ! ( "Field ty should have been resolved" ) ;
570
+ }
571
+
572
+ ( ty, None )
573
+ }
574
+ ProjectionElem :: OpaqueCast ( ..) => bug ! ( "didn't expect OpaqueCast" ) ,
575
+ }
576
+ }
577
+
578
+ fn local_projections_to_ty < ' a , ' tcx > (
579
+ cx : & ' a Builder < ' a , ' tcx > ,
580
+ local : Local ,
581
+ projection : & ' a [ PlaceElem < ' tcx > ] ,
582
+ ) -> ( Ty < ' tcx > , Option < VariantIdx > ) {
583
+ let local_ty = cx. local_decls . local_decls ( ) [ local] . ty ;
584
+ projection. iter ( ) . fold ( ( local_ty, None ) , |ty_variant_idx, elem| {
585
+ let ty = ty_variant_idx. 0 ;
586
+ project_ty ( cx. tcx , ty, * elem)
587
+ } )
588
+ }
589
+
590
+ // Converts an `UpvarProjectionElem` to `PlaceElem`, ICE'ing when being passed a
591
+ // field projection.
592
+ fn upvar_proj_to_place_elem_no_field_proj < ' tcx > (
593
+ upvar_proj : UpvarProjectionElem < ' tcx > ,
594
+ ) -> PlaceElem < ' tcx > {
595
+ match upvar_proj {
596
+ ProjectionElem :: Deref => ProjectionElem :: Deref ,
597
+ ProjectionElem :: Index ( i) => ProjectionElem :: Index ( i) ,
598
+ ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
599
+ ProjectionElem :: ConstantIndex { offset, min_length, from_end }
600
+ }
601
+ ProjectionElem :: Subslice { from, to, from_end } => {
602
+ ProjectionElem :: Subslice { from, to, from_end }
603
+ }
604
+ ProjectionElem :: Downcast ( ty, variant_idx) => ProjectionElem :: Downcast ( ty, variant_idx) ,
605
+ ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
606
+ ProjectionElem :: Field ( ..) => bug ! ( "should not be called with `ProjectionElem::Field`" ) ,
607
+ }
608
+ }
609
+
537
610
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
538
611
/// Compile `expr`, yielding a place that we can move from etc.
539
612
///
0 commit comments