pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
// Required methods
fn apply_statement_effect(
&mut self,
state: &mut Self::Domain,
statement: &Statement<'tcx>,
location: Location,
);
fn apply_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx>;
fn apply_call_return_effect(
&mut self,
state: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
);
// Provided methods
fn apply_before_statement_effect(
&mut self,
_state: &mut Self::Domain,
_statement: &Statement<'tcx>,
_location: Location,
) { ... }
fn apply_before_terminator_effect(
&mut self,
_state: &mut Self::Domain,
_terminator: &Terminator<'tcx>,
_location: Location,
) { ... }
fn apply_switch_int_edge_effects(
&mut self,
_block: BasicBlock,
_discr: &Operand<'tcx>,
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
) { ... }
fn into_engine<'mir>(
self,
tcx: TyCtxt<'tcx>,
body: &'mir Body<'tcx>,
) -> Engine<'mir, 'tcx, Self>
where Self: Sized { ... }
}
Expand description
A dataflow problem with an arbitrarily complex transfer function.
§Convergence
When implementing this trait directly (not via GenKillAnalysis
), it’s possible to choose a
transfer function such that the analysis does not reach fixpoint. To guarantee convergence,
your transfer functions must maintain the following invariant:
If the dataflow state before some point in the program changes to be greater than the prior state before that point, the dataflow state after that point must also change to be greater than the prior state after that point.
This invariant guarantees that the dataflow state at a given point in the program increases monotonically until fixpoint is reached. Note that this monotonicity requirement only applies to the same point in the program at different points in time. The dataflow state at a given point in the program may or may not be greater than the state at any preceding point.
Required Methods§
sourcefn apply_statement_effect(
&mut self,
state: &mut Self::Domain,
statement: &Statement<'tcx>,
location: Location,
)
fn apply_statement_effect( &mut self, state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, )
Updates the current dataflow state with the effect of evaluating a statement.
sourcefn apply_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx>
fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx>
Updates the current dataflow state with the effect of evaluating a terminator.
The effect of a successful return from a Call
terminator should not be accounted for
in this function. That should go in apply_call_return_effect
. For example, in the
InitializedPlaces
analyses, the return place for a function call is not marked as
initialized here.
sourcefn apply_call_return_effect(
&mut self,
state: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
)
fn apply_call_return_effect( &mut self, state: &mut Self::Domain, block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, )
Updates the current dataflow state with the effect of a successful return from a Call
terminator.
This is separate from apply_terminator_effect
to properly track state across unwind
edges.
Provided Methods§
sourcefn apply_before_statement_effect(
&mut self,
_state: &mut Self::Domain,
_statement: &Statement<'tcx>,
_location: Location,
)
fn apply_before_statement_effect( &mut self, _state: &mut Self::Domain, _statement: &Statement<'tcx>, _location: Location, )
Updates the current dataflow state with an effect that occurs immediately before the given statement.
This method is useful if the consumer of the results of this analysis only needs to observe
part of the effect of a statement (e.g. for two-phase borrows). As a general rule,
analyses should not implement this without also implementing apply_statement_effect
.
sourcefn apply_before_terminator_effect(
&mut self,
_state: &mut Self::Domain,
_terminator: &Terminator<'tcx>,
_location: Location,
)
fn apply_before_terminator_effect( &mut self, _state: &mut Self::Domain, _terminator: &Terminator<'tcx>, _location: Location, )
Updates the current dataflow state with an effect that occurs immediately before the given terminator.
This method is useful if the consumer of the results of this analysis needs only to observe
part of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
analyses should not implement this without also implementing apply_terminator_effect
.
sourcefn apply_switch_int_edge_effects(
&mut self,
_block: BasicBlock,
_discr: &Operand<'tcx>,
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
)
fn apply_switch_int_edge_effects( &mut self, _block: BasicBlock, _discr: &Operand<'tcx>, _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>, )
Updates the current dataflow state with the effect of taking a particular branch in a
SwitchInt
terminator.
Unlike the other edge-specific effects, which are allowed to mutate Self::Domain
directly, overriders of this method must pass a callback to
SwitchIntEdgeEffects::apply
. The callback will be run once for each outgoing edge and
will have access to the dataflow state that will be propagated along that edge.
This interface is somewhat more complex than the other visitor-like “effect” methods.
However, it is both more ergonomic—callers don’t need to recompute or cache information
about a given SwitchInt
terminator for each one of its edges—and more efficient—the
engine doesn’t need to clone the exit state for a block unless
SwitchIntEdgeEffects::apply
is actually called.
sourcefn into_engine<'mir>(
self,
tcx: TyCtxt<'tcx>,
body: &'mir Body<'tcx>,
) -> Engine<'mir, 'tcx, Self>where
Self: Sized,
fn into_engine<'mir>(
self,
tcx: TyCtxt<'tcx>,
body: &'mir Body<'tcx>,
) -> Engine<'mir, 'tcx, Self>where
Self: Sized,
Creates an Engine
to find the fixpoint for this dataflow problem.
You shouldn’t need to override this outside this module, since the combination of the
default impl and the one for all A: GenKillAnalysis
will do the right thing.
Its purpose is to enable method chaining like so:
let results = MyAnalysis::new(tcx, body)
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint()
.into_results_cursor(body);