@@ -157,6 +157,17 @@ impl<'tcx> PlaceTy<'tcx> {
157
157
elems. iter ( ) . fold ( self , |place_ty, & elem| place_ty. projection_ty ( tcx, elem) )
158
158
}
159
159
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
+
160
171
/// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
161
172
/// where we can just use the `Ty` that is already stored inline on
162
173
/// field projection elems.
@@ -544,6 +555,88 @@ impl From<Local> for PlaceRef<'_> {
544
555
}
545
556
}
546
557
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
+
547
640
///////////////////////////////////////////////////////////////////////////
548
641
// Operands
549
642
0 commit comments