pub trait DataflowAnalyzer<'db, 'a> {
type Info: Clone;
const DIRECTION: Direction;
// Required methods
fn initial_info(
&mut self,
block_id: BlockId,
block_end: &'a BlockEnd<'db>,
) -> Self::Info;
fn merge(
&mut self,
lowered: &Lowered<'db>,
statement_location: StatementLocation,
info1: Self::Info,
info2: Self::Info,
) -> Self::Info;
// Provided methods
fn transfer_block(
&mut self,
info: &mut Self::Info,
block_id: BlockId,
block: &'a Block<'db>,
) { ... }
fn transfer_stmt(
&mut self,
_info: &mut Self::Info,
_statement_location: StatementLocation,
_stmt: &'a Statement<'db>,
) { ... }
fn transfer_edge(
&mut self,
info: &Self::Info,
_edge: &Edge<'db, 'a>,
) -> Self::Info { ... }
fn visit_block_start(
&mut self,
_info: &mut Self::Info,
_block_id: BlockId,
_block: &Block<'db>,
) { ... }
fn block_entry_location(
&self,
lowered: &Lowered<'db>,
block_id: BlockId,
) -> LocationId<'db> { ... }
}Expand description
Unified analyzer trait for dataflow analysis.
Implementors specify the direction via DIRECTION and implement the core methods.
The framework specifies the “behaviour” of the dataflow (essentially updates to lattice state
for lattice analysis). Running an analysis is done by a runner (backward/forward/etc) which will
handle control flow and dataflow mechanics.
§Transfer Granularity
You can work at either block or statement level:
- Block-level: Override
transfer_blockfor coarse-grained analysis - Statement-level: Override
transfer_stmt; defaulttransfer_blockiterates statements
§Example (block-level analysis)
impl<'db, 'a> DataflowAnalyzer<'db, 'a> for BlockCounter {
type Info = usize;
const DIRECTION: Direction = Direction::Forward;
fn initial_info(&mut self) -> Self::Info { 0 }
fn transfer_block(&mut self, info: &mut Self::Info, block_id: BlockId, block: &Block<'db>) {
*info += 1; // Just count blocks
}
fn merge(&mut self, _loc: StatementLocation, _end_loc: &LocationId, infos: ..) -> Self::Info {
infos.map(|(_, i)| i).max().unwrap_or(0)
}
}Required Associated Constants§
Required Associated Types§
Required Methods§
Sourcefn initial_info(
&mut self,
block_id: BlockId,
block_end: &'a BlockEnd<'db>,
) -> Self::Info
fn initial_info( &mut self, block_id: BlockId, block_end: &'a BlockEnd<'db>, ) -> Self::Info
Create the initial analysis state at a terminal block.
- Backward: called at return/panic blocks (what we know at function exit)
- Forward: called at function entry
For backward analysis, block_end provides access to return variables or panic data.
For forward analysis, this is typically called once at the root block.
Sourcefn merge(
&mut self,
lowered: &Lowered<'db>,
statement_location: StatementLocation,
info1: Self::Info,
info2: Self::Info,
) -> Self::Info
fn merge( &mut self, lowered: &Lowered<'db>, statement_location: StatementLocation, info1: Self::Info, info2: Self::Info, ) -> Self::Info
Merge/join states from multiple control flow paths. Called at join points (match merge for backward, block entry for forward).
statement_location: where the merge occurs in the CFG.info1: first info from an incoming path.info2: second info from another incoming path.
Provided Methods§
Sourcefn transfer_block(
&mut self,
info: &mut Self::Info,
block_id: BlockId,
block: &'a Block<'db>,
)
fn transfer_block( &mut self, info: &mut Self::Info, block_id: BlockId, block: &'a Block<'db>, )
Transfer function for an entire block.
- Backward: transforms post-block state to pre-block state
- Forward: transforms pre-block state to post-block state
Default implementation iterates statements and calls transfer_stmt.
Override this for block-level analysis (ignoring individual statements).
Sourcefn transfer_stmt(
&mut self,
_info: &mut Self::Info,
_statement_location: StatementLocation,
_stmt: &'a Statement<'db>,
)
fn transfer_stmt( &mut self, _info: &mut Self::Info, _statement_location: StatementLocation, _stmt: &'a Statement<'db>, )
Transfer function for a single statement.
- Backward: transforms post-state to pre-state
- Forward: transforms pre-state to post-state
Default is no-op. Override this for statement-level analysis.
Sourcefn transfer_edge(
&mut self,
info: &Self::Info,
_edge: &Edge<'db, 'a>,
) -> Self::Info
fn transfer_edge( &mut self, info: &Self::Info, _edge: &Edge<'db, 'a>, ) -> Self::Info
Transfer state along a CFG edge. Called when traversing between blocks via control flow edges.
info: the state to transferedge: the edge being traversed, containing all relevant information
Default implementation clones the state. Override to modify state based on edge properties (e.g., variable remapping, introduced variables in match arms).
Sourcefn visit_block_start(
&mut self,
_info: &mut Self::Info,
_block_id: BlockId,
_block: &Block<'db>,
)
fn visit_block_start( &mut self, _info: &mut Self::Info, _block_id: BlockId, _block: &Block<'db>, )
Called when entering a block during traversal (before transfer_block).
Sourcefn block_entry_location(
&self,
lowered: &Lowered<'db>,
block_id: BlockId,
) -> LocationId<'db>
fn block_entry_location( &self, lowered: &Lowered<'db>, block_id: BlockId, ) -> LocationId<'db>
Block entry location. For Backward it is the merge location. For Forward it is the block entry location, if there is a statement. If not statement exists it will look at block end. This might recurse to next block if we have a goto with no remappings.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.