11//! Functionality for statements, operands, places, and things that appear in them.
22
3+ use smallvec:: SmallVec ;
34use tracing:: { debug, instrument} ;
45
56use super :: interpret:: GlobalAlloc ;
@@ -558,7 +559,7 @@ impl From<Local> for PlaceRef<'_> {
558559/// A place possibly containing derefs in the middle of its projection by chaining projection lists.
559560///
560561/// In `AnalysisPhase::PostCleanup` and later, [`Place`] and [`PlaceRef`] cannot represent these
561- /// kinds of places.
562+ /// kinds of places, requiring this struct to be used instead .
562563#[ derive( Copy , Clone , PartialEq , Eq , Hash , TyEncodable , HashStable , TypeFoldable , TypeVisitable ) ]
563564pub struct CompoundPlace < ' tcx > {
564565 pub local : Local ,
@@ -579,6 +580,35 @@ pub struct CompoundPlaceRef<'tcx> {
579580
580581// these impls are bare-bones for now
581582impl < ' tcx > CompoundPlace < ' tcx > {
583+ pub fn from_place ( place : Place < ' tcx > , tcx : TyCtxt < ' tcx > ) -> CompoundPlace < ' tcx > {
584+ let mut segment_start = 0 ;
585+ // size picked from sole user
586+ let mut new_projection_chain = SmallVec :: < [ _ ; 2 ] > :: new ( ) ;
587+
588+ for ( i, elem) in place. projection . iter ( ) . enumerate ( ) {
589+ if elem == PlaceElem :: Deref && i > 0 {
590+ new_projection_chain. push ( tcx. mk_place_elems ( & place. projection [ segment_start..i] ) ) ;
591+ segment_start = i;
592+ }
593+ }
594+
595+ if segment_start == 0 {
596+ new_projection_chain. push ( place. projection ) ;
597+ } else {
598+ new_projection_chain. push ( tcx. mk_place_elems ( & place. projection [ segment_start..] ) ) ;
599+ }
600+
601+ if cfg ! ( debug_assertions) {
602+ let new_projections: Vec < _ > = new_projection_chain. iter ( ) . copied ( ) . flatten ( ) . collect ( ) ;
603+ assert_eq ! ( new_projections. as_slice( ) , place. projection. as_slice( ) ) ;
604+ }
605+
606+ CompoundPlace {
607+ local : place. local ,
608+ projection_chain : tcx. mk_place_elem_chain ( & new_projection_chain) ,
609+ }
610+ }
611+
582612 pub fn as_ref ( & self ) -> CompoundPlaceRef < ' tcx > {
583613 let ( last, base) = self
584614 . projection_chain
@@ -589,21 +619,75 @@ impl<'tcx> CompoundPlace<'tcx> {
589619 CompoundPlaceRef { local : self . local , projection_chain_base : base, last_projection : last }
590620 }
591621
622+ pub fn as_local ( & self ) -> Option < Local > {
623+ if self . projection_chain . is_empty ( ) { Some ( self . local ) } else { None }
624+ }
625+
626+ pub fn local_or_deref_local ( & self ) -> Option < Local > {
627+ self . as_ref ( ) . local_or_deref_local ( )
628+ }
629+
630+ /// Returns a [`Place`] with only the first segment in the projection chain.
631+ pub fn base_place ( & self ) -> Place < ' tcx > {
632+ Place {
633+ local : self . local ,
634+ projection : self . projection_chain . first ( ) . copied ( ) . unwrap_or_default ( ) ,
635+ }
636+ }
637+
638+ /// Replaces the local and first segment of the projection with `new_base`.
639+ pub fn replace_base_place ( & mut self , new_base : Place < ' tcx > , tcx : TyCtxt < ' tcx > ) {
640+ self . local = new_base. local ;
641+ self . projection_chain =
642+ match ( new_base. projection . is_empty ( ) , self . projection_chain . is_empty ( ) ) {
643+ ( false , false ) => {
644+ let mut new_projection_chain = self . projection_chain . to_vec ( ) ;
645+ new_projection_chain[ 0 ] = new_base. projection ;
646+ tcx. mk_place_elem_chain ( & new_projection_chain)
647+ }
648+ ( false , true ) => tcx. mk_place_elem_chain ( & [ new_base. projection ] ) ,
649+
650+ ( true , false ) => tcx. mk_place_elem_chain ( & self . projection_chain [ 1 ..] ) ,
651+ ( true , true ) => List :: empty ( ) ,
652+ }
653+ // FIXME: this logic is a mess
654+ // maybe separate out projection before first deref?
655+ }
656+
657+ /// Replaces the local with `new_base`.
658+ pub fn replace_local_with_place ( & mut self , new_base : Place < ' tcx > , tcx : TyCtxt < ' tcx > ) {
659+ let base_place = self . base_place ( ) ;
660+
661+ if new_base. projection . is_empty ( ) {
662+ self . local = new_base. local ;
663+ } else if base_place. is_indirect_first_projection ( ) {
664+ let mut new_projection_chain = Vec :: with_capacity ( self . projection_chain . len ( ) + 1 ) ;
665+ new_projection_chain. push ( new_base. projection ) ;
666+ new_projection_chain. extend_from_slice ( self . projection_chain ) ;
667+
668+ self . local = new_base. local ;
669+ self . projection_chain = tcx. mk_place_elem_chain ( & new_projection_chain) ;
670+ } else {
671+ self . replace_base_place ( new_base. project_deeper ( base_place. projection , tcx) , tcx) ;
672+ }
673+ }
674+
592675 pub fn iter_projections (
593676 self ,
594677 ) -> impl Iterator < Item = ( CompoundPlaceRef < ' tcx > , PlaceElem < ' tcx > ) > + DoubleEndedIterator {
595678 self . projection_chain . iter ( ) . enumerate ( ) . flat_map ( move |( i, projs) | {
596679 projs. iter ( ) . enumerate ( ) . map ( move |( j, elem) | {
597680 let base = if j == 0 && i > 0 {
598681 // last_projection should only be empty if projection_chain_base is too
599- // otherwise it has to have a deref at least
600-
601682 debug_assert_eq ! ( elem, PlaceElem :: Deref ) ;
602683 CompoundPlaceRef {
603684 local : self . local ,
604685 projection_chain_base : & self . projection_chain [ ..i - 1 ] ,
605- last_projection : & projs [ ..=j ] ,
686+ last_projection : & self . projection_chain [ i - 1 ] ,
606687 }
688+
689+ // FIXME: the fact that i messed up this logic the first time is good evidence that
690+ // the invariants are confusing and difficult to uphold
607691 } else {
608692 CompoundPlaceRef {
609693 local : self . local ,
@@ -612,6 +696,19 @@ impl<'tcx> CompoundPlace<'tcx> {
612696 }
613697 } ;
614698
699+ if cfg ! ( debug_assertions) {
700+ let self_projections: Vec < _ > = self . projection_chain . iter ( ) . flatten ( ) . collect ( ) ;
701+ let base_projections: Vec < _ > = base
702+ . projection_chain_base
703+ . iter ( )
704+ . copied ( )
705+ . flatten ( )
706+ . chain ( base. last_projection . iter ( ) . copied ( ) )
707+ . collect ( ) ;
708+
709+ assert_eq ! ( self_projections[ ..base_projections. len( ) ] , base_projections) ;
710+ }
711+
615712 ( base, elem)
616713 } )
617714 } )
@@ -626,6 +723,13 @@ impl<'tcx> CompoundPlace<'tcx> {
626723 }
627724}
628725
726+ impl From < Local > for CompoundPlace < ' _ > {
727+ #[ inline]
728+ fn from ( local : Local ) -> Self {
729+ CompoundPlace { local, projection_chain : List :: empty ( ) }
730+ }
731+ }
732+
629733impl < ' tcx > CompoundPlaceRef < ' tcx > {
630734 pub fn ty < D : ?Sized > ( & self , local_decls : & D , tcx : TyCtxt < ' tcx > ) -> PlaceTy < ' tcx >
631735 where
@@ -635,6 +739,17 @@ impl<'tcx> CompoundPlaceRef<'tcx> {
635739 . projection_chain_ty ( tcx, self . projection_chain_base )
636740 . multi_projection_ty ( tcx, self . last_projection )
637741 }
742+
743+ pub fn local_or_deref_local ( & self ) -> Option < Local > {
744+ match * self {
745+ CompoundPlaceRef {
746+ local,
747+ projection_chain_base : [ ] ,
748+ last_projection : [ ] | [ ProjectionElem :: Deref ] ,
749+ } => Some ( local) ,
750+ _ => None ,
751+ }
752+ }
638753}
639754
640755///////////////////////////////////////////////////////////////////////////
0 commit comments