Skip to content

Commit

Permalink
Merge AnalysisDomain into Analysis.
Browse files Browse the repository at this point in the history
With `GenKillAnalysis` gone, there is no need for them to be separate.
  • Loading branch information
nnethercote committed Oct 10, 2024
1 parent 9b34f19 commit fd0b5ae
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 105 deletions.
30 changes: 14 additions & 16 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_middle::mir::{
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable};
use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
use tracing::debug;

use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
Expand All @@ -22,9 +22,9 @@ pub(crate) struct BorrowckResults<'a, 'tcx> {
/// The transient state of the dataflow analyses used by the borrow checker.
#[derive(Debug)]
pub(crate) struct BorrowckDomain<'a, 'tcx> {
pub(crate) borrows: <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
}

impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
Expand Down Expand Up @@ -427,7 +427,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// That means they went out of a nonlexical scope
fn kill_loans_out_of_scope_at_location(
&self,
trans: &mut <Self as AnalysisDomain<'tcx>>::Domain,
trans: &mut <Self as Analysis<'tcx>>::Domain,
location: Location,
) {
// NOTE: The state associated with a given `location`
Expand All @@ -449,7 +449,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// Kill any borrows that conflict with `place`.
fn kill_borrows_on_place(
&self,
trans: &mut <Self as AnalysisDomain<'tcx>>::Domain,
trans: &mut <Self as Analysis<'tcx>>::Domain,
place: Place<'tcx>,
) {
debug!("kill_borrows_on_place: place={:?}", place);
Expand Down Expand Up @@ -490,7 +490,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
}
}

impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
/// - we gen the introduced loans
/// - we kill loans on locals going out of (regular) scope
/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a
/// region stops containing the CFG points reachable from the issuing location.
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
/// `a.b.c` when `a` is overwritten.
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
type Domain = BitSet<BorrowIndex>;

const NAME: &'static str = "borrows";
Expand All @@ -504,16 +511,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
// no borrows of code region_scopes have been taken prior to
// function execution, so this method has no effect.
}
}

/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
/// - we gen the introduced loans
/// - we kill loans on locals going out of (regular) scope
/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a
/// region stops containing the CFG points reachable from the issuing location.
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
/// `a.b.c` when `a` is overwritten.
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
fn apply_before_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_const_eval/src/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_middle::mir::{
self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges,
};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::{Analysis, AnalysisDomain, JoinSemiLattice};
use rustc_mir_dataflow::{Analysis, JoinSemiLattice};

use super::{ConstCx, Qualif, qualifs};

Expand Down Expand Up @@ -310,7 +310,7 @@ impl JoinSemiLattice for State {
}
}

impl<'tcx, Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
Expand All @@ -328,12 +328,7 @@ where
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
self.transfer_function(state).initialize_state();
}
}

impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
fn apply_statement_effect(
&mut self,
state: &mut Self::Domain,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_mir_dataflow/src/framework/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ use {rustc_ast as ast, rustc_graphviz as dot};

use super::fmt::DebugWithContext;
use super::{
Analysis, AnalysisDomain, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz,
visit_results,
Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results,
};
use crate::errors::{
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
};

type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;

/// A dataflow analysis that has converged to fixpoint.
#[derive(Clone)]
Expand Down
41 changes: 19 additions & 22 deletions compiler/rustc_mir_dataflow/src/framework/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,26 @@ impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> {
}
}

/// Defines the domain of a dataflow problem.
/// A dataflow problem with an arbitrarily complex transfer function.
///
/// This trait specifies the lattice on which this analysis operates (the domain), its
/// initial value at the entry point of each basic block, and various operations.
///
/// This trait specifies the lattice on which this analysis operates (the domain) as well as its
/// initial value at the entry point of each basic block.
pub trait AnalysisDomain<'tcx> {
/// # Convergence
///
/// When implementing this trait 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.
pub trait Analysis<'tcx> {
/// The type that holds the dataflow state at any given point in the program.
type Domain: Clone + JoinSemiLattice;

Expand All @@ -115,25 +130,7 @@ pub trait AnalysisDomain<'tcx> {
// block where control flow could exit the MIR body (e.g., those terminated with `return` or
// `resume`). It's not obvious how to handle `yield` points in coroutines, however.
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
}

/// A dataflow problem with an arbitrarily complex transfer function.
///
/// # Convergence
///
/// When implementing this trait 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.
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// Updates the current dataflow state with the effect of evaluating a statement.
fn apply_statement_effect(
&mut self,
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_mir_dataflow/src/framework/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
}
}

impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
type Domain = BitSet<usize>;
type Direction = D;

Expand All @@ -167,9 +167,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint");
}
}

impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
fn apply_statement_effect(
&mut self,
state: &mut Self::Domain,
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;

use crate::{Analysis, AnalysisDomain, GenKill};
use crate::{Analysis, GenKill};

/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
/// to a given local. This analysis ignores fake borrows, so it should not be used by
Expand All @@ -20,7 +20,7 @@ impl MaybeBorrowedLocals {
}
}

impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals {
impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_borrowed_locals";

Expand All @@ -32,9 +32,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals {
fn initialize_start_block(&self, _: &Body<'tcx>, _: &mut Self::Domain) {
// No locals are aliased on function entry
}
}

impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down
27 changes: 9 additions & 18 deletions compiler/rustc_mir_dataflow/src/impls/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use crate::elaborate_drops::DropFlagState;
use crate::framework::SwitchIntEdgeEffects;
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::{
Analysis, AnalysisDomain, GenKill, MaybeReachable, drop_flag_effects,
drop_flag_effects_for_function_entry, drop_flag_effects_for_location, lattice,
on_all_children_bits, on_lookup_result_bits,
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits,
};

/// `MaybeInitializedPlaces` tracks all places that might be
Expand Down Expand Up @@ -270,7 +269,7 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {

impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
fn update_bits(
trans: &mut <Self as AnalysisDomain<'tcx>>::Domain,
trans: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
) {
Expand All @@ -283,7 +282,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {

impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
fn update_bits(
trans: &mut <Self as AnalysisDomain<'tcx>>::Domain,
trans: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
) {
Expand All @@ -296,7 +295,7 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {

impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
fn update_bits(
trans: &mut <Self as AnalysisDomain<'tcx>>::Domain,
trans: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
) {
Expand All @@ -307,7 +306,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
}
}

impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
type Domain = MaybeReachable<ChunkedBitSet<MovePathIndex>>;
Expand All @@ -327,9 +326,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
state.gen_(path);
});
}
}

impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down Expand Up @@ -436,7 +433,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}
}

impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
type Domain = ChunkedBitSet<MovePathIndex>;
Expand All @@ -458,9 +455,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
state.remove(path);
});
}
}

impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down Expand Up @@ -559,7 +554,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
}

impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
/// Use set intersection as the join operator.
type Domain = lattice::Dual<BitSet<MovePathIndex>>;

Expand All @@ -579,9 +574,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
state.0.insert(path);
});
}
}

impl<'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down Expand Up @@ -625,7 +618,7 @@ impl<'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
}
}

impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
type Domain = ChunkedBitSet<InitIndex>;
Expand All @@ -642,9 +635,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
state.insert(InitIndex::new(arg_init));
}
}
}

impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
#[instrument(skip(self, trans), level = "debug")]
fn apply_statement_effect(
&mut self,
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_mir_dataflow/src/impls/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_middle::mir::{
self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges,
};

use crate::{Analysis, AnalysisDomain, Backward, GenKill};
use crate::{Analysis, Backward, GenKill};

/// A [live-variable dataflow analysis][liveness].
///
Expand All @@ -25,7 +25,7 @@ use crate::{Analysis, AnalysisDomain, Backward, GenKill};
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
pub struct MaybeLiveLocals;

impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
type Domain = BitSet<Local>;
type Direction = Backward;

Expand All @@ -39,9 +39,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// No variables are live until we observe a use
}
}

impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down Expand Up @@ -219,7 +217,7 @@ impl<'a> MaybeTransitiveLiveLocals<'a> {
}
}

impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
type Domain = BitSet<Local>;
type Direction = Backward;

Expand All @@ -233,9 +231,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// No variables are live until we observe a use
}
}

impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
Expand Down
Loading

0 comments on commit fd0b5ae

Please sign in to comment.