@@ -157,6 +157,17 @@ impl<'tcx> PlaceTy<'tcx> {
157157 elems. iter ( ) . fold ( self , |place_ty, & elem| place_ty. projection_ty ( tcx, elem) )
158158 }
159159
160+ pub fn projection_chain_ty (
161+ self ,
162+ tcx : TyCtxt < ' tcx > ,
163+ chain : & [ & List < PlaceElem < ' tcx > > ] ,
164+ ) -> PlaceTy < ' tcx > {
165+ chain
166+ . iter ( )
167+ . flat_map ( |& elems| elems)
168+ . fold ( self , |place_ty, elem| place_ty. projection_ty ( tcx, elem) )
169+ }
170+
160171 /// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
161172 /// where we can just use the `Ty` that is already stored inline on
162173 /// field projection elems.
@@ -544,6 +555,88 @@ impl From<Local> for PlaceRef<'_> {
544555 }
545556}
546557
558+ /// A place possibly containing derefs in the middle of its projection by chaining projection lists.
559+ ///
560+ /// In `AnalysisPhase::PostCleanup` and later, [`Place`] and [`PlaceRef`] cannot represent these
561+ /// kinds of places.
562+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , TyEncodable , HashStable , TypeFoldable , TypeVisitable ) ]
563+ pub struct CompoundPlace < ' tcx > {
564+ pub local : Local ,
565+ /// Invariants:
566+ /// - All segments in the chain other than the first must start with a deref.
567+ /// - Derefs may only appear at the start of a segment.
568+ /// - No segment may be empty.
569+ pub projection_chain : & ' tcx List < & ' tcx List < PlaceElem < ' tcx > > > ,
570+ }
571+
572+ /// Borrowed form of [`CompoundPlace`].
573+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
574+ pub struct CompoundPlaceRef < ' tcx > {
575+ pub local : Local ,
576+ pub projection_chain_base : & ' tcx [ & ' tcx List < PlaceElem < ' tcx > > ] ,
577+ pub last_projection : & ' tcx [ PlaceElem < ' tcx > ] ,
578+ }
579+
580+ // these impls are bare-bones for now
581+ impl < ' tcx > CompoundPlace < ' tcx > {
582+ pub fn as_ref ( & self ) -> CompoundPlaceRef < ' tcx > {
583+ let ( last, base) = self
584+ . projection_chain
585+ . split_last ( )
586+ . map ( |( & last, base) | ( last, base) )
587+ . unwrap_or_default ( ) ;
588+
589+ CompoundPlaceRef { local : self . local , projection_chain_base : base, last_projection : last }
590+ }
591+
592+ pub fn ty < D : ?Sized > ( & self , local_decls : & D , tcx : TyCtxt < ' tcx > ) -> PlaceTy < ' tcx >
593+ where
594+ D : HasLocalDecls < ' tcx > ,
595+ {
596+ PlaceTy :: from_ty ( local_decls. local_decls ( ) [ self . local ] . ty )
597+ . projection_chain_ty ( tcx, self . projection_chain )
598+ }
599+
600+ pub fn iter_projections (
601+ self ,
602+ ) -> impl Iterator < Item = ( CompoundPlaceRef < ' tcx > , PlaceElem < ' tcx > ) > + DoubleEndedIterator {
603+ self . projection_chain . iter ( ) . enumerate ( ) . flat_map ( move |( i, projs) | {
604+ projs. iter ( ) . enumerate ( ) . map ( move |( j, elem) | {
605+ let base = if j == 0 && i > 0 {
606+ // last_projection should only be empty if projection_chain_base is too
607+ // otherwise it has to have a deref at least
608+
609+ debug_assert_eq ! ( elem, PlaceElem :: Deref ) ;
610+ CompoundPlaceRef {
611+ local : self . local ,
612+ projection_chain_base : & self . projection_chain [ ..i - 1 ] ,
613+ last_projection : & projs[ ..=j] ,
614+ }
615+ } else {
616+ CompoundPlaceRef {
617+ local : self . local ,
618+ projection_chain_base : & self . projection_chain [ ..i] ,
619+ last_projection : & projs[ ..j] ,
620+ }
621+ } ;
622+
623+ ( base, elem)
624+ } )
625+ } )
626+ }
627+ }
628+
629+ impl < ' tcx > CompoundPlaceRef < ' tcx > {
630+ pub fn ty < D : ?Sized > ( & self , local_decls : & D , tcx : TyCtxt < ' tcx > ) -> PlaceTy < ' tcx >
631+ where
632+ D : HasLocalDecls < ' tcx > ,
633+ {
634+ PlaceTy :: from_ty ( local_decls. local_decls ( ) [ self . local ] . ty )
635+ . projection_chain_ty ( tcx, self . projection_chain_base )
636+ . multi_projection_ty ( tcx, self . last_projection )
637+ }
638+ }
639+
547640///////////////////////////////////////////////////////////////////////////
548641// Operands
549642
0 commit comments