cairo_lang_lowering/borrow_check/
demand.rsuse cairo_lang_utils::ordered_hash_map::OrderedHashMap;
pub trait DemandReporter<Var, Aux = ()> {
type UsePosition: Copy;
type IntroducePosition: Copy;
fn drop_aux(&mut self, position: Self::IntroducePosition, var: Var, _aux: Aux) {
self.drop(position, var);
}
fn drop(&mut self, _position: Self::IntroducePosition, _var: Var) {}
fn dup(
&mut self,
_position: Self::UsePosition,
_var: Var,
_next_usage_position: Self::UsePosition,
) {
}
fn last_use(&mut self, _position: Self::UsePosition, _var: Var) {}
fn unused_mapped_var(&mut self, _var: Var) {}
}
#[derive(Clone)]
pub struct Demand<Var: std::hash::Hash + Eq + Copy, UsePosition, Aux: Clone + Default = ()> {
pub vars: OrderedHashMap<Var, UsePosition>,
pub aux: Aux,
}
impl<Var: std::hash::Hash + Eq + Copy, UsePosition, Aux: Clone + Default> Default
for Demand<Var, UsePosition, Aux>
{
fn default() -> Self {
Self { vars: Default::default(), aux: Default::default() }
}
}
impl<Var: std::hash::Hash + Eq + Copy, UsePosition: Copy, Aux: Clone + Default + AuxCombine>
Demand<Var, UsePosition, Aux>
{
pub fn finalize(self) -> bool {
self.vars.is_empty()
}
pub fn apply_remapping<
'a,
V: Copy + Into<Var> + 'a,
T: DemandReporter<Var, Aux, UsePosition = UsePosition>,
>(
&mut self,
reporter: &mut T,
remapping: impl std::iter::DoubleEndedIterator<Item = (&'a V, (&'a V, T::UsePosition))>
+ std::iter::ExactSizeIterator,
) {
for (dst, (src, position)) in remapping.rev() {
let src = (*src).into();
let dst = (*dst).into();
if let Some(dest_next_usage_position) = self.vars.swap_remove(&dst) {
if let Some(next_usage_position) = self.vars.insert(src, dest_next_usage_position) {
reporter.dup(position, src, next_usage_position);
} else {
reporter.last_use(position, src);
}
} else {
reporter.unused_mapped_var(dst);
}
}
}
pub fn variables_used<
'a,
V: Copy + Into<Var> + 'a,
T: DemandReporter<Var, Aux, UsePosition = UsePosition>,
>(
&mut self,
reporter: &mut T,
vars: impl std::iter::DoubleEndedIterator<Item = (&'a V, T::UsePosition)>
+ std::iter::ExactSizeIterator,
) {
for (var, position) in vars.rev() {
if let Some(next_usage_position) = self.vars.insert((*var).into(), position) {
reporter.dup(position, (*var).into(), next_usage_position);
} else {
reporter.last_use(position, (*var).into());
}
}
}
pub fn variables_introduced<V: Copy + Into<Var>, T: DemandReporter<Var, Aux>>(
&mut self,
reporter: &mut T,
vars: &[V],
position: T::IntroducePosition,
) {
for var in vars {
if self.vars.swap_remove(&(*var).into()).is_none() {
reporter.drop_aux(position, (*var).into(), self.aux.clone());
}
}
}
pub fn merge_demands<T: DemandReporter<Var, Aux>>(
demands: &[(Self, T::IntroducePosition)],
reporter: &mut T,
) -> Self {
let mut vars = OrderedHashMap::default();
for (arm_demand, _) in demands {
vars.extend(arm_demand.vars.iter().map(|(var, position)| (*var, *position)));
}
let demand = Self { vars, aux: Aux::merge(demands.iter().map(|(d, _)| &d.aux)) };
for var in demand.vars.keys() {
for (arm_demand, position) in demands {
if !arm_demand.vars.contains_key(var) {
reporter.drop_aux(*position, *var, arm_demand.aux.clone());
}
}
}
demand
}
}
pub trait AuxCombine {
fn merge<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self
where
Self: 'a;
}
impl AuxCombine for () {
fn merge<'a, I: Iterator<Item = &'a Self>>(_: I) -> Self {}
}