@@ -218,7 +218,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
218218 let upvar_resolved_place_builder = PlaceBuilder :: construct_local_place_builder (
219219 cx,
220220 upvar_resolved_local,
221- local_projection. to_vec ( ) ,
221+ local_projection. as_slice ( ) ,
222222 upvar_projection,
223223 ) ;
224224
@@ -266,7 +266,7 @@ fn strip_prefix<'a, 'tcx>(
266266 mut base_ty : Ty < ' tcx > ,
267267 projections : & ' a [ UpvarProjectionElem < ' tcx > ] ,
268268 prefix_projections : & [ HirProjection < ' tcx > ] ,
269- ) -> Vec < UpvarProjectionElem < ' tcx > > {
269+ ) -> impl Iterator < Item = UpvarProjectionElem < ' tcx > > + ' a {
270270 let mut iter = projections
271271 . iter ( )
272272 // Filter out opaque casts, they are unnecessary in the prefix.
@@ -293,7 +293,7 @@ fn strip_prefix<'a, 'tcx>(
293293 base_ty = projection. ty ;
294294 }
295295
296- iter. collect :: < Vec < _ > > ( )
296+ iter
297297}
298298
299299impl < ' tcx > PlaceBuilder < ' tcx > {
@@ -342,10 +342,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
342342
343343 #[ instrument( skip( cx) , level = "debug" ) ]
344344 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)
349353 }
350354 PlaceBuilder :: UpVar ( ..) => {
351355 let dummy_ty = cx. tcx . mk_ty_infer ( ty:: FreshTy ( 0 ) ) ;
@@ -410,13 +414,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
410414 fn compute_field_ty (
411415 cx : & Builder < ' _ , ' tcx > ,
412416 field : Field ,
413- base_place : PlaceBuilder < ' tcx > ,
417+ base_ty : Ty < ' tcx > ,
418+ variant_index : Option < VariantIdx > ,
414419 ) -> Ty < ' tcx > {
415420 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-
420421 let field_ty = match base_ty. kind ( ) {
421422 ty:: Adt ( adt_def, substs) if adt_def. is_enum ( ) => {
422423 let variant_idx = variant_index. unwrap ( ) ;
@@ -479,41 +480,38 @@ impl<'tcx> PlaceBuilder<'tcx> {
479480 /// contains the projections of the captured upvar and `upvar_projection` the
480481 /// projections that are applied to the captured upvar. The main purpose of this
481482 /// 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 ) ) ]
483484 fn construct_local_place_builder (
484485 cx : & Builder < ' _ , ' tcx > ,
485486 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 > > ,
488489 ) -> 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 {
496502 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) ;
500505 debug ! ( ?field_ty) ;
501506
502507 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 ;
511510 }
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) ;
517515 }
518516 }
519517 }
@@ -534,6 +532,81 @@ impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
534532 }
535533}
536534
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+
537610impl < ' a , ' tcx > Builder < ' a , ' tcx > {
538611 /// Compile `expr`, yielding a place that we can move from etc.
539612 ///
0 commit comments