cairo_lang_lowering/borrow_check/
analysis.rs1use std::collections::HashMap;
5
6use crate::{
7 BlockId, FlatBlock, FlatBlockEnd, FlatLowered, MatchInfo, Statement, VarRemapping, VarUsage,
8};
9
10pub type StatementLocation = (BlockId, usize);
12
13#[allow(unused_variables)]
15pub trait Analyzer<'a> {
16 type Info: Clone;
17 fn visit_block_start(&mut self, info: &mut Self::Info, block_id: BlockId, block: &FlatBlock) {}
18 fn visit_stmt(
19 &mut self,
20 info: &mut Self::Info,
21 statement_location: StatementLocation,
22 stmt: &'a Statement,
23 ) {
24 }
25 fn visit_goto(
26 &mut self,
27 info: &mut Self::Info,
28 statement_location: StatementLocation,
29 target_block_id: BlockId,
30 remapping: &VarRemapping,
31 ) {
32 }
33 fn merge_match(
34 &mut self,
35 statement_location: StatementLocation,
36 match_info: &'a MatchInfo,
37 infos: impl Iterator<Item = Self::Info>,
38 ) -> Self::Info;
39 fn info_from_return(
40 &mut self,
41 statement_location: StatementLocation,
42 vars: &'a [VarUsage],
43 ) -> Self::Info;
44
45 fn info_from_panic(
48 &mut self,
49 statement_location: StatementLocation,
50 var: &VarUsage,
51 ) -> Self::Info {
52 unreachable!("Panics should have been stripped in the `lower_panics` phase.");
53 }
54}
55
56pub struct BackAnalysis<'a, TAnalyzer: Analyzer<'a>> {
58 lowered: &'a FlatLowered,
59 pub analyzer: TAnalyzer,
60 block_info: HashMap<BlockId, TAnalyzer::Info>,
61}
62impl<'a, TAnalyzer: Analyzer<'a>> BackAnalysis<'a, TAnalyzer> {
63 pub fn new(lowered: &'a FlatLowered, analyzer: TAnalyzer) -> Self {
65 Self { lowered, analyzer, block_info: Default::default() }
66 }
67 pub fn get_root_info(&mut self) -> TAnalyzer::Info {
69 let mut dfs_stack = vec![BlockId::root()];
70 while let Some(block_id) = dfs_stack.last() {
71 let end = &self.lowered.blocks[*block_id].end;
72 if !self.add_missing_dependency_blocks(&mut dfs_stack, end) {
73 self.calc_block_info(dfs_stack.pop().unwrap());
74 }
75 }
76 self.block_info.remove(&BlockId::root()).unwrap()
77 }
78
79 fn calc_block_info(&mut self, block_id: BlockId) {
81 let mut info = self.get_end_info(block_id);
82
83 for (i, stmt) in self.lowered.blocks[block_id].statements.iter().enumerate().rev() {
85 let statement_location = (block_id, i);
86 self.analyzer.visit_stmt(&mut info, statement_location, stmt);
87 }
88
89 self.analyzer.visit_block_start(&mut info, block_id, &self.lowered.blocks[block_id]);
90
91 self.block_info.insert(block_id, info);
93 }
94
95 fn add_missing_dependency_blocks(
98 &self,
99 dfs_stack: &mut Vec<BlockId>,
100 block_end: &'a FlatBlockEnd,
101 ) -> bool {
102 match block_end {
103 FlatBlockEnd::NotSet => unreachable!(),
104 FlatBlockEnd::Goto(target_block_id, _)
105 if !self.block_info.contains_key(target_block_id) =>
106 {
107 dfs_stack.push(*target_block_id);
108 true
109 }
110 FlatBlockEnd::Goto(_, _) | FlatBlockEnd::Return(..) | FlatBlockEnd::Panic(_) => false,
111 FlatBlockEnd::Match { info } => {
112 let mut missing_cache = false;
113 for arm in info.arms() {
114 if !self.block_info.contains_key(&arm.block_id) {
115 dfs_stack.push(arm.block_id);
116 missing_cache = true;
117 }
118 }
119 missing_cache
120 }
121 }
122 }
123
124 fn get_end_info(&mut self, block_id: BlockId) -> TAnalyzer::Info {
126 let block_end = &self.lowered.blocks[block_id].end;
127 let statement_location = (block_id, self.lowered.blocks[block_id].statements.len());
128 match block_end {
129 FlatBlockEnd::NotSet => unreachable!(),
130 FlatBlockEnd::Goto(target_block_id, remapping) => {
131 let mut info = self.block_info[target_block_id].clone();
132 self.analyzer.visit_goto(
133 &mut info,
134 statement_location,
135 *target_block_id,
136 remapping,
137 );
138 info
139 }
140 FlatBlockEnd::Return(vars, _location) => {
141 self.analyzer.info_from_return(statement_location, vars)
142 }
143 FlatBlockEnd::Panic(data) => self.analyzer.info_from_panic(statement_location, data),
144 FlatBlockEnd::Match { info } => {
145 let arm_infos =
147 info.arms().iter().map(|arm| self.block_info.remove(&arm.block_id).unwrap());
148 self.analyzer.merge_match(statement_location, info, arm_infos)
149 }
150 }
151 }
152}