1010//! 2. **Transfer granularity** (choose one):
1111//! - Block-level: override `transfer_block` for coarse-grained analysis
1212//! - Statement-level: override `transfer_stmt` (default `transfer_block` iterates statements)
13- //! 3. **Variable tracking** (optional): `apply_remapping` - override if tracking per-variable state
14- //! 4. **Advanced hooks** (optional): `merge_match`, `split_match`, etc. - override for special
15- //! cases
13+ //! 3. **Variable tracking** (optional): `transfer_edge` - override if tracking per-variable state
1614//!
17- //! The framework handles control flow mechanics automatically:
18- //! - Goto with remapping: calls `apply_remapping`
19- //! - Match (backward): calls `merge_match` which defaults to `merge`
20- //! - Match (forward): calls `split_match` which defaults to cloning
15+ //! The Runner's (backward/forward/etc) should handle control flow mechanics automatically:
16+ //! - Goto with remapping/Match split: calls `transfer_edge`
17+ //! - Call transfer block for each block in need of processing
2118
22- use crate :: { Block , BlockEnd , BlockId , MatchInfo , Statement , VarRemapping } ;
19+ use crate :: ids:: LocationId ;
20+ use crate :: { Block , BlockEnd , BlockId , MatchArm , MatchInfo , Statement , VarRemapping , VarUsage } ;
2321
2422/// Location of a lowering statement inside a block.
2523pub type StatementLocation = ( BlockId , usize ) ;
2624
2725/// The direction of dataflow analysis.
28- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
2926#[ expect( dead_code) ]
27+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
3028pub enum Direction {
3129 Forward ,
3230 Backward ,
3331}
3432
33+ /// Represents an edge in the control flow graph.
34+ ///
35+ /// Each variant captures the specific information needed for that edge type,
36+ /// enabling analyzers to handle variable introductions and remappings.
37+ #[ derive( Debug ) ]
38+ #[ expect( dead_code) ]
39+ pub enum Edge < ' db , ' a > {
40+ /// A goto edge with variable remapping.
41+ Goto { target : BlockId , remapping : & ' a VarRemapping < ' db > } ,
42+ /// A match arm edge with the arm's introduced variables.
43+ MatchArm { arm : & ' a MatchArm < ' db > , match_info : & ' a MatchInfo < ' db > } ,
44+ /// A return edge (terminal).
45+ Return { vars : & ' a [ VarUsage < ' db > ] , location : & ' a LocationId < ' db > } ,
46+ /// A panic edge (terminal).
47+ Panic { var : & ' a VarUsage < ' db > } ,
48+ }
49+
3550/// Unified analyzer trait for dataflow analysis.
3651///
3752/// Implementors specify the direction via `DIRECTION` and implement the core methods.
38- /// The framework handles control flow mechanics (remapping, match arms) automatically,
39- /// with sensible defaults that can be overridden for complex analyses.
53+ /// The framework specifies the "behaviour" of the dataflow (essentially updates to lattice state
54+ /// for lattice analysis). Running an analysis is done by a runner (backward/forward/etc) which will
55+ /// handle control flow and dataflow mechanics.
4056///
4157/// # Transfer Granularity
4258///
4359/// You can work at either block or statement level:
4460/// - **Block-level**: Override `transfer_block` for coarse-grained analysis
4561/// - **Statement-level**: Override `transfer_stmt`; default `transfer_block` iterates statements
4662///
47- /// # Lifetime parameters
48- /// - `'db`: The database lifetime (for interned types).
49- /// - `'a`: The lifetime of borrowed lowering data.
50- ///
51- /// # Example (statement-level forward analysis)
52- /// ```ignore
53- /// impl<'db, 'a> DataflowAnalyzer<'db, 'a> for MyAnalyzer {
54- /// type Info = HashSet<VariableId>;
55- /// const DIRECTION: Direction = Direction::Forward;
56- ///
57- /// fn initial_info(&mut self) -> Self::Info { HashSet::new() }
58- /// fn transfer_stmt(&mut self, info: &mut Self::Info, ..) { /* update info */ }
59- /// fn merge(&mut self, infos: impl Iterator<Item = Self::Info>) -> Self::Info {
60- /// infos.fold(HashSet::new(), |mut acc, i| { acc.extend(i); acc })
61- /// }
62- /// }
63- /// ```
64- ///
6563/// # Example (block-level analysis)
6664/// ```ignore
6765/// impl<'db, 'a> DataflowAnalyzer<'db, 'a> for BlockCounter {
@@ -72,8 +70,8 @@ pub enum Direction {
7270/// fn transfer_block(&mut self, info: &mut Self::Info, block_id: BlockId, block: &Block<'db>) {
7371/// *info += 1; // Just count blocks
7472/// }
75- /// fn merge(&mut self, infos: impl Iterator<Item = Self::Info> ) -> Self::Info {
76- /// infos.max().unwrap_or(0)
73+ /// fn merge(&mut self, _loc: StatementLocation, _end_loc: &LocationId, infos: .. ) -> Self::Info {
74+ /// infos.map(|(_, i)| i). max().unwrap_or(0)
7775/// }
7876/// }
7977/// ```
@@ -85,10 +83,6 @@ pub trait DataflowAnalyzer<'db, 'a> {
8583 /// The direction of this analysis.
8684 const DIRECTION : Direction ;
8785
88- // ========================================================================
89- // Core methods (must implement)
90- // ========================================================================
91-
9286 /// Create the initial analysis state at a terminal block.
9387 ///
9488 /// - Backward: called at return/panic blocks (what we know at function exit)
@@ -101,18 +95,16 @@ pub trait DataflowAnalyzer<'db, 'a> {
10195 /// Merge/join states from multiple control flow paths.
10296 /// Called at join points (match merge for backward, block entry for forward).
10397 ///
104- /// - `statement_location`: where the merge occurs in the CFG
105- /// - `infos`: iterator of (source_block_id, info) pairs from each incoming path
98+ /// - `statement_location`: where the merge occurs in the CFG.
99+ /// - `location`: source location of the merge.
100+ /// - `infos`: iterator of (source_block_id, info) pairs from each incoming path.
106101 fn merge (
107102 & mut self ,
108103 statement_location : StatementLocation ,
104+ location : & ' a LocationId < ' db > ,
109105 infos : impl Iterator < Item = ( BlockId , Self :: Info ) > ,
110106 ) -> Self :: Info ;
111107
112- // ========================================================================
113- // Transfer functions (choose granularity)
114- // ========================================================================
115-
116108 /// Transfer function for an entire block.
117109 /// - Backward: transforms post-block state to pre-block state
118110 /// - Forward: transforms pre-block state to post-block state
@@ -147,30 +139,19 @@ pub trait DataflowAnalyzer<'db, 'a> {
147139 ) {
148140 }
149141
150- // ========================================================================
151- // Variable tracking (optional - override if tracking per-variable state)
152- // ========================================================================
153-
154- /// Apply variable remapping to the state.
155- /// Called by the framework when crossing a goto with remapping.
142+ /// Transfer state along a CFG edge.
143+ /// Called when traversing between blocks via control flow edges.
156144 ///
157- /// - Backward: translates demands on destination vars to demands on source vars
158- /// - Forward: translates state of source vars to state of destination vars
145+ /// - `info`: the state to transfer
146+ /// - `edge`: the edge being traversed, containing all relevant information
159147 ///
160- /// Default is no-op (fine for analyses that don't track per-variable state).
161- fn apply_remapping (
162- & mut self ,
163- _info : & mut Self :: Info ,
164- _statement_location : StatementLocation ,
165- _target_block_id : BlockId ,
166- _remapping : & ' a VarRemapping < ' db > ,
167- ) {
148+ /// Default implementation clones the state.
149+ /// Override to modify state based on edge properties (e.g., variable remapping,
150+ /// introduced variables in match arms).
151+ fn transfer_edge ( & mut self , info : & Self :: Info , _edge : & Edge < ' db , ' a > ) -> Self :: Info {
152+ info. clone ( )
168153 }
169154
170- // ========================================================================
171- // Block boundary hooks (optional)
172- // ========================================================================
173-
174155 /// Called when entering a block during traversal (before transfer_block).
175156 fn visit_block_start (
176157 & mut self ,
@@ -179,33 +160,4 @@ pub trait DataflowAnalyzer<'db, 'a> {
179160 _block : & Block < ' db > ,
180161 ) {
181162 }
182-
183- // ========================================================================
184- // Match handling (optional - have sensible defaults)
185- // ========================================================================
186-
187- /// Backward: merge states from match arms.
188- /// Default implementation calls `merge` with arm block IDs.
189- /// Override for special handling (e.g., tracking arm-specific metadata).
190- fn merge_match (
191- & mut self ,
192- statement_location : StatementLocation ,
193- match_info : & ' a MatchInfo < ' db > ,
194- arm_infos : impl Iterator < Item = Self :: Info > ,
195- ) -> Self :: Info {
196- let infos_with_blocks = match_info. arms ( ) . iter ( ) . map ( |arm| arm. block_id ) . zip ( arm_infos) ;
197- self . merge ( statement_location, infos_with_blocks)
198- }
199-
200- /// Forward: split state for match arms.
201- /// Default implementation clones state for each arm.
202- /// Override to refine state based on match conditions.
203- fn split_match (
204- & mut self ,
205- info : & Self :: Info ,
206- _statement_location : StatementLocation ,
207- match_info : & ' a MatchInfo < ' db > ,
208- ) -> Vec < Self :: Info > {
209- match_info. arms ( ) . iter ( ) . map ( |_| info. clone ( ) ) . collect ( )
210- }
211163}
0 commit comments