rustc_mir_dataflow/
un_derefer.rs
1use rustc_data_structures::fx::FxHashMap;
2use rustc_middle::mir::*;
3
4#[derive(Default, Debug)]
6pub(crate) struct UnDerefer<'tcx> {
7 deref_chains: FxHashMap<Local, Vec<PlaceRef<'tcx>>>,
8}
9
10impl<'tcx> UnDerefer<'tcx> {
11 #[inline]
12 pub(crate) fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) {
13 let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default();
14 chain.push(reffed);
15 self.deref_chains.insert(local, chain);
16 }
17
18 #[inline]
20 pub(crate) fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] {
21 self.deref_chains.get(&local).map(Vec::as_slice).unwrap_or_default()
22 }
23
24 #[inline]
28 pub(crate) fn iter_projections(
29 &self,
30 place: PlaceRef<'tcx>,
31 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + '_ {
32 ProjectionIter::new(self.deref_chain(place.local), place)
33 }
34}
35
36struct ProjectionIter<'a, 'tcx> {
38 places: SlicePlusOne<'a, PlaceRef<'tcx>>,
39 proj_idx: usize,
40}
41
42impl<'a, 'tcx> ProjectionIter<'a, 'tcx> {
43 #[inline]
44 fn new(deref_chain: &'a [PlaceRef<'tcx>], place: PlaceRef<'tcx>) -> Self {
45 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
57impl<'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 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
80struct SlicePlusOne<'a, T> {
81 slice: &'a [T],
82 last: Option<T>,
83}
84
85impl<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 }
99 }
100}