use std::fmt;
use crate::analysis::DefLocation;
use crate::analysis::core::{DataflowAnalyzer, Direction, Edge, StatementLocation};
use crate::analysis::forward::ForwardDataflowAnalysis;
use crate::{BlockEnd, BlockId, Lowered, Statement};
pub struct DefSites(pub Vec<Option<DefLocation>>);
impl std::ops::Deref for DefSites {
type Target = [Option<DefLocation>];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Debug for DefSites {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for (idx, def) in self.0.iter().enumerate() {
match def {
Some(loc) => list.entry(&format_args!("v{idx}: {loc:?}")),
None => list.entry(&format_args!("v{idx}: undefined")),
};
}
list.finish()
}
}
pub struct DefSiteAnalysis<'db, 'a> {
lowered: &'a Lowered<'db>,
def_sites: Vec<Option<DefLocation>>,
}
impl DefSiteAnalysis<'_, '_> {
pub fn analyze(lowered: &Lowered<'_>) -> DefSites {
let analyzer = DefSiteAnalysis { lowered, def_sites: vec![None; lowered.variables.len()] };
let mut fwd = ForwardDataflowAnalysis::new(lowered, analyzer);
fwd.run();
DefSites(fwd.analyzer.def_sites)
}
}
impl<'db, 'a> DataflowAnalyzer<'db, 'a> for DefSiteAnalysis<'db, 'a> {
type Info = ();
const DIRECTION: Direction = Direction::Forward;
fn initial_info(&mut self, _block_id: BlockId, _block_end: &'a BlockEnd<'db>) -> Self::Info {
for ¶m in &self.lowered.parameters {
self.def_sites[param.index()] = Some(DefLocation::BlockEntry(BlockId::root()));
}
}
fn merge(
&mut self,
_lowered: &Lowered<'db>,
_statement_location: StatementLocation,
_info1: Self::Info,
_info2: Self::Info,
) -> Self::Info {
}
fn transfer_stmt(
&mut self,
_info: &mut Self::Info,
statement_location: StatementLocation,
stmt: &'a Statement<'db>,
) {
for &output in stmt.outputs() {
self.def_sites[output.index()] = Some(DefLocation::Statement(statement_location));
}
}
fn transfer_edge(&mut self, _info: &Self::Info, edge: &Edge<'db, 'a>) -> Self::Info {
match edge {
Edge::Goto { target, remapping } => {
for (&dst, _) in remapping.iter() {
self.def_sites[dst.index()] = Some(DefLocation::BlockEntry(*target));
}
}
Edge::MatchArm { arm, .. } => {
for &var in &arm.var_ids {
self.def_sites[var.index()] = Some(DefLocation::BlockEntry(arm.block_id));
}
}
Edge::Return { .. } | Edge::Panic { .. } => {}
}
}
}