use rustc_hir::def_id::DefId;
use rustc_middle::{
mir::BasicBlock,
ty::{EarlyBinder, Instance, TyCtxt, TypingEnv},
};
use crate::analysis::path::{
PathTree,
graph::{PathEnumerator, PathGraph},
};
use crate::verify::checkpoint::CheckpointLocation;
pub(crate) struct PathExtractor<'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
allow_repeat: usize,
instance: Option<Instance<'tcx>>,
}
impl<'tcx> PathExtractor<'tcx> {
pub(crate) fn new_with_instance(
tcx: TyCtxt<'tcx>,
def_id: DefId,
allow_repeat: usize,
instance: Option<Instance<'tcx>>,
) -> Self {
Self {
tcx,
def_id,
allow_repeat,
instance,
}
}
pub(crate) fn run(self) -> PathTree {
let body = match self.instance {
Some(inst) => {
let mir = self.tcx.optimized_mir(self.def_id);
inst.instantiate_mir_and_normalize_erasing_regions(
self.tcx,
TypingEnv::post_analysis(self.tcx, self.def_id),
EarlyBinder::bind(self.tcx, mir.clone()),
)
}
None => self.tcx.optimized_mir(self.def_id).clone(),
};
let mut graph = PathGraph::new_with_body(self.tcx, self.def_id, &body);
graph.inline_callees();
graph.find_scc();
let mut tree = {
let mut enumerator = PathEnumerator::new(&graph);
enumerator.enumerate_paths_repeat(self.allow_repeat)
};
tree.set_block_fn(
graph
.cfg
.blocks
.iter()
.map(|b| (b.def_id, b.local_index))
.collect(),
graph.inline_bindings.clone(),
graph.inline_parents.clone(),
graph.inlined_call_blocks.clone(),
);
tree
}
}
#[derive(Clone, Debug)]
pub(crate) struct Path {
pub target: CheckpointLocation,
pub steps: Vec<PathStep>,
}
impl Path {
pub(crate) fn describe_indices(&self) -> String {
let mut indices: Vec<usize> = Vec::new();
for step in &self.steps {
match step {
PathStep::Block(b) => indices.push(b.as_usize()),
PathStep::Checkpoint(l) => {
let bb = l.block.as_usize();
if indices.last() != Some(&bb) {
indices.push(bb);
}
}
}
}
format!("{:?}", indices)
}
}
#[derive(Clone, Debug)]
pub(crate) enum PathStep {
Block(BasicBlock),
Checkpoint(CheckpointLocation),
}