1
1
//! Functionality for statements, operands, places, and things that appear in them.
2
2
3
+ use smallvec:: SmallVec ;
3
4
use tracing:: { debug, instrument} ;
4
5
5
6
use super :: interpret:: GlobalAlloc ;
@@ -558,7 +559,7 @@ impl From<Local> for PlaceRef<'_> {
558
559
/// A place possibly containing derefs in the middle of its projection by chaining projection lists.
559
560
///
560
561
/// 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 .
562
563
#[ derive( Copy , Clone , PartialEq , Eq , Hash , TyEncodable , HashStable , TypeFoldable , TypeVisitable ) ]
563
564
pub struct CompoundPlace < ' tcx > {
564
565
pub local : Local ,
@@ -579,6 +580,35 @@ pub struct CompoundPlaceRef<'tcx> {
579
580
580
581
// these impls are bare-bones for now
581
582
impl < ' 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
+
582
612
pub fn as_ref ( & self ) -> CompoundPlaceRef < ' tcx > {
583
613
let ( last, base) = self
584
614
. projection_chain
@@ -589,21 +619,75 @@ impl<'tcx> CompoundPlace<'tcx> {
589
619
CompoundPlaceRef { local : self . local , projection_chain_base : base, last_projection : last }
590
620
}
591
621
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 seperate 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
+
592
675
pub fn iter_projections (
593
676
self ,
594
677
) -> impl Iterator < Item = ( CompoundPlaceRef < ' tcx > , PlaceElem < ' tcx > ) > + DoubleEndedIterator {
595
678
self . projection_chain . iter ( ) . enumerate ( ) . flat_map ( move |( i, projs) | {
596
679
projs. iter ( ) . enumerate ( ) . map ( move |( j, elem) | {
597
680
let base = if j == 0 && i > 0 {
598
681
// last_projection should only be empty if projection_chain_base is too
599
- // otherwise it has to have a deref at least
600
-
601
682
debug_assert_eq ! ( elem, PlaceElem :: Deref ) ;
602
683
CompoundPlaceRef {
603
684
local : self . local ,
604
685
projection_chain_base : & self . projection_chain [ ..i - 1 ] ,
605
- last_projection : & projs [ ..=j ] ,
686
+ last_projection : & self . projection_chain [ i - 1 ] ,
606
687
}
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
607
691
} else {
608
692
CompoundPlaceRef {
609
693
local : self . local ,
@@ -612,6 +696,19 @@ impl<'tcx> CompoundPlace<'tcx> {
612
696
}
613
697
} ;
614
698
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
+
615
712
( base, elem)
616
713
} )
617
714
} )
@@ -626,6 +723,13 @@ impl<'tcx> CompoundPlace<'tcx> {
626
723
}
627
724
}
628
725
726
+ impl From < Local > for CompoundPlace < ' _ > {
727
+ #[ inline]
728
+ fn from ( local : Local ) -> Self {
729
+ CompoundPlace { local, projection_chain : List :: empty ( ) }
730
+ }
731
+ }
732
+
629
733
impl < ' tcx > CompoundPlaceRef < ' tcx > {
630
734
pub fn ty < D : ?Sized > ( & self , local_decls : & D , tcx : TyCtxt < ' tcx > ) -> PlaceTy < ' tcx >
631
735
where
@@ -635,6 +739,17 @@ impl<'tcx> CompoundPlaceRef<'tcx> {
635
739
. projection_chain_ty ( tcx, self . projection_chain_base )
636
740
. multi_projection_ty ( tcx, self . last_projection )
637
741
}
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
+ }
638
753
}
639
754
640
755
///////////////////////////////////////////////////////////////////////////
0 commit comments