Skip to main content

DataflowAnalyzer

Trait DataflowAnalyzer 

Source
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_block for coarse-grained analysis
  • Statement-level: Override transfer_stmt; default transfer_block iterates 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§

Source

const DIRECTION: Direction

The direction of this analysis.

Required Associated Types§

Source

type Info: Clone

The analysis state/info type.

Required Methods§

Source

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.

Source

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§

Source

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).

Source

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.

Source

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 transfer
  • edge: 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).

Source

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).

Source

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.

Implementors§

Source§

impl<'db, 'a> DataflowAnalyzer<'db, 'a> for UnsafePanicContext<'db>

Source§

const DIRECTION: Direction = Direction::Backward

Source§

type Info = ReachableSideEffects<'db>

Source§

impl<'db, 'a> DataflowAnalyzer<'db, 'a> for GasRedepositContext<'db>

Source§

const DIRECTION: Direction = Direction::Backward

Source§

type Info = RedepositState

Source§

impl<'db, 'a> DataflowAnalyzer<'db, 'a> for TopSortContext

Source§

const DIRECTION: Direction = Direction::Backward

Source§

type Info = ()

Source§

impl<'db, 'a> DataflowAnalyzer<'db, 'a> for EqualityAnalysis<'a, 'db>

Source§

const DIRECTION: Direction = Direction::Forward

Source§

type Info = EqualityState<'db>