rustc_borrowck/polonius/legacy/
location.rs
1use rustc_index::IndexVec;
2use rustc_middle::mir::{BasicBlock, Body, Location};
3use tracing::debug;
4
5pub struct PoloniusLocationTable {
17 num_points: usize,
18 statements_before_block: IndexVec<BasicBlock, usize>,
19}
20
21rustc_index::newtype_index! {
22 #[orderable]
23 #[debug_format = "LocationIndex({})"]
24 pub struct LocationIndex {}
25}
26
27#[derive(Copy, Clone, Debug)]
28pub enum RichLocation {
29 Start(Location),
30 Mid(Location),
31}
32
33impl PoloniusLocationTable {
34 pub(crate) fn new(body: &Body<'_>) -> Self {
35 let mut num_points = 0;
36 let statements_before_block = body
37 .basic_blocks
38 .iter()
39 .map(|block_data| {
40 let v = num_points;
41 num_points += (block_data.statements.len() + 1) * 2;
42 v
43 })
44 .collect();
45
46 debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block);
47 debug!("PoloniusLocationTable: num_points={:#?}", num_points);
48
49 Self { num_points, statements_before_block }
50 }
51
52 pub fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
53 (0..self.num_points).map(LocationIndex::from_usize)
54 }
55
56 pub fn start_index(&self, location: Location) -> LocationIndex {
57 let Location { block, statement_index } = location;
58 let start_index = self.statements_before_block[block];
59 LocationIndex::from_usize(start_index + statement_index * 2)
60 }
61
62 pub fn mid_index(&self, location: Location) -> LocationIndex {
63 let Location { block, statement_index } = location;
64 let start_index = self.statements_before_block[block];
65 LocationIndex::from_usize(start_index + statement_index * 2 + 1)
66 }
67
68 pub fn to_rich_location(&self, index: LocationIndex) -> RichLocation {
69 let point_index = index.index();
70
71 let (block, &first_index) = self
88 .statements_before_block
89 .iter_enumerated()
90 .rfind(|&(_, &first_index)| first_index <= point_index)
91 .unwrap();
92
93 let statement_index = (point_index - first_index) / 2;
94 if index.is_start() {
95 RichLocation::Start(Location { block, statement_index })
96 } else {
97 RichLocation::Mid(Location { block, statement_index })
98 }
99 }
100
101 pub fn to_location(&self, index: LocationIndex) -> Location {
102 match self.to_rich_location(index) {
103 RichLocation::Start(location) => location,
104 RichLocation::Mid(location) => location,
105 }
106 }
107}
108
109impl LocationIndex {
110 fn is_start(self) -> bool {
111 (self.index() % 2) == 0
113 }
114}