|  | 
| 1 | 1 | use rustc_data_structures::fx::FxHashMap; | 
| 2 | 2 | use rustc_middle::mir::*; | 
| 3 | 3 | 
 | 
| 4 |  | -use std::iter::once; | 
| 5 |  | - | 
| 6 | 4 | /// Used for reverting changes made by `DerefSeparator` | 
| 7 | 5 | #[derive(Default, Debug)] | 
| 8 | 6 | pub struct UnDerefer<'tcx> { | 
| 9 |  | -    deref_chains: FxHashMap<Local, Vec<Place<'tcx>>>, | 
|  | 7 | +    deref_chains: FxHashMap<Local, Vec<PlaceRef<'tcx>>>, | 
| 10 | 8 | } | 
| 11 | 9 | 
 | 
| 12 | 10 | impl<'tcx> UnDerefer<'tcx> { | 
| 13 |  | -    pub fn insert(&mut self, local: Local, reffed: Place<'tcx>) { | 
|  | 11 | +    #[inline] | 
|  | 12 | +    pub fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) { | 
| 14 | 13 |         let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default(); | 
| 15 | 14 |         chain.push(reffed); | 
| 16 | 15 |         self.deref_chains.insert(local, chain); | 
| 17 | 16 |     } | 
| 18 | 17 | 
 | 
| 19 | 18 |     /// Returns the chain of places behind `DerefTemp` locals | 
| 20 |  | -    pub fn deref_chain(&self, local: Local) -> &[Place<'tcx>] { | 
|  | 19 | +    #[inline] | 
|  | 20 | +    pub fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] { | 
| 21 | 21 |         self.deref_chains.get(&local).map(Vec::as_slice).unwrap_or_default() | 
| 22 | 22 |     } | 
| 23 | 23 | 
 | 
|  | 24 | +    /// Iterates over the projections of a place and its deref chain. | 
|  | 25 | +    /// | 
|  | 26 | +    /// See [`PlaceRef::iter_projections`] | 
|  | 27 | +    #[inline] | 
| 24 | 28 |     pub fn iter_projections( | 
| 25 | 29 |         &self, | 
| 26 | 30 |         place: PlaceRef<'tcx>, | 
| 27 |  | -    ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator + '_ { | 
| 28 |  | -        let deref_chain = self.deref_chain(place.local); | 
| 29 |  | - | 
| 30 |  | -        deref_chain | 
| 31 |  | -            .iter() | 
| 32 |  | -            .map(Place::as_ref) | 
| 33 |  | -            .chain(once(place)) | 
| 34 |  | -            .flat_map(|place| place.iter_projections()) | 
|  | 31 | +    ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + '_ { | 
|  | 32 | +        ProjectionIter::new(self.deref_chain(place.local), place) | 
|  | 33 | +    } | 
|  | 34 | +} | 
|  | 35 | + | 
|  | 36 | +/// The iterator returned by [`UnDerefer::iter_projections`]. | 
|  | 37 | +struct ProjectionIter<'a, 'tcx> { | 
|  | 38 | +    places: SlicePlusOne<'a, PlaceRef<'tcx>>, | 
|  | 39 | +    proj_idx: usize, | 
|  | 40 | +} | 
|  | 41 | + | 
|  | 42 | +impl<'a, 'tcx> ProjectionIter<'a, 'tcx> { | 
|  | 43 | +    #[inline] | 
|  | 44 | +    fn new(deref_chain: &'a [PlaceRef<'tcx>], place: PlaceRef<'tcx>) -> Self { | 
|  | 45 | +        // just return an empty iterator for a bare local | 
|  | 46 | +        let last = if place.as_local().is_none() { | 
|  | 47 | +            Some(place) | 
|  | 48 | +        } else { | 
|  | 49 | +            debug_assert!(deref_chain.is_empty()); | 
|  | 50 | +            None | 
|  | 51 | +        }; | 
|  | 52 | + | 
|  | 53 | +        ProjectionIter { places: SlicePlusOne { slice: deref_chain, last }, proj_idx: 0 } | 
|  | 54 | +    } | 
|  | 55 | +} | 
|  | 56 | + | 
|  | 57 | +impl<'tcx> Iterator for ProjectionIter<'_, 'tcx> { | 
|  | 58 | +    type Item = (PlaceRef<'tcx>, PlaceElem<'tcx>); | 
|  | 59 | + | 
|  | 60 | +    #[inline] | 
|  | 61 | +    fn next(&mut self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { | 
|  | 62 | +        let place = self.places.read()?; | 
|  | 63 | + | 
|  | 64 | +        // the projection should never be empty except for a bare local which is handled in new | 
|  | 65 | +        let partial_place = | 
|  | 66 | +            PlaceRef { local: place.local, projection: &place.projection[..self.proj_idx] }; | 
|  | 67 | +        let elem = place.projection[self.proj_idx]; | 
|  | 68 | + | 
|  | 69 | +        if self.proj_idx == place.projection.len() - 1 { | 
|  | 70 | +            self.proj_idx = 0; | 
|  | 71 | +            self.places.advance(); | 
|  | 72 | +        } else { | 
|  | 73 | +            self.proj_idx += 1; | 
|  | 74 | +        } | 
|  | 75 | + | 
|  | 76 | +        Some((partial_place, elem)) | 
|  | 77 | +    } | 
|  | 78 | +} | 
|  | 79 | + | 
|  | 80 | +struct SlicePlusOne<'a, T> { | 
|  | 81 | +    slice: &'a [T], | 
|  | 82 | +    last: Option<T>, | 
|  | 83 | +} | 
|  | 84 | + | 
|  | 85 | +impl<T: Copy> SlicePlusOne<'_, T> { | 
|  | 86 | +    #[inline] | 
|  | 87 | +    fn read(&self) -> Option<T> { | 
|  | 88 | +        self.slice.first().copied().or(self.last) | 
|  | 89 | +    } | 
|  | 90 | + | 
|  | 91 | +    #[inline] | 
|  | 92 | +    fn advance(&mut self) { | 
|  | 93 | +        match self.slice { | 
|  | 94 | +            [_, ref remainder @ ..] => { | 
|  | 95 | +                self.slice = remainder; | 
|  | 96 | +            } | 
|  | 97 | +            [] => self.last = None, | 
|  | 98 | +        } | 
| 35 | 99 |     } | 
| 36 | 100 | } | 
0 commit comments