use core::{convert::AsRef, fmt};
use super::{
AnalysisState, BuildableAnalysisState, ChangeResult, DenseLattice, LatticeAnchor,
LatticeAnchorRef, SparseLattice,
};
pub trait LatticeLike: Default + Clone + Eq + fmt::Debug + 'static {
fn join(&self, other: &Self) -> Self;
fn meet(&self, other: &Self) -> Self;
}
pub struct Lattice<T> {
anchor: LatticeAnchorRef,
value: T,
}
impl<T> Lattice<T> {
pub fn new(anchor: LatticeAnchorRef, value: T) -> Self {
Self { anchor, value }
}
pub fn value(&self) -> &T {
&self.value
}
pub fn value_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for Lattice<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.value, f)
}
}
impl<T: core::fmt::Display> core::fmt::Display for Lattice<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.value, f)
}
}
impl<T: Default + 'static> BuildableAnalysisState for Lattice<T> {
default fn create(anchor: LatticeAnchorRef) -> Self {
Self {
anchor,
value: Default::default(),
}
}
}
impl<T: 'static> AnalysisState for Lattice<T> {
#[inline(always)]
fn as_any(&self) -> &dyn core::any::Any {
self as &dyn core::any::Any
}
#[inline(always)]
fn anchor(&self) -> &dyn LatticeAnchor {
self.anchor.as_ref()
}
}
impl<T: LatticeLike> SparseLattice for Lattice<T> {
type Lattice = T;
#[inline]
fn lattice(&self) -> &Self::Lattice {
&self.value
}
fn join(&mut self, rhs: &Self::Lattice) -> ChangeResult {
let new_value = <T as LatticeLike>::join(&self.value, rhs);
debug_assert_eq!(
<T as LatticeLike>::join(&new_value, &self.value),
new_value,
"expected `join` to be monotonic"
);
debug_assert_eq!(
<T as LatticeLike>::join(&new_value, rhs),
new_value,
"expected `join` to be monotonic"
);
if new_value == self.value {
ChangeResult::Unchanged
} else {
self.value = new_value;
ChangeResult::Changed
}
}
fn meet(&mut self, rhs: &Self::Lattice) -> ChangeResult {
let new_value = <T as LatticeLike>::meet(&self.value, rhs);
debug_assert_eq!(
<T as LatticeLike>::meet(&new_value, &self.value),
new_value,
"expected `meet` to be monotonic"
);
debug_assert_eq!(
<T as LatticeLike>::meet(&new_value, rhs),
new_value,
"expected `meet` to be monotonic"
);
if new_value == self.value {
ChangeResult::Unchanged
} else {
self.value = new_value;
ChangeResult::Changed
}
}
}
impl<T: LatticeLike> DenseLattice for Lattice<T> {
type Lattice = T;
#[inline]
fn lattice(&self) -> &Self::Lattice {
&self.value
}
#[inline]
fn lattice_mut(&mut self) -> &mut Self::Lattice {
&mut self.value
}
fn join(&mut self, rhs: &Self::Lattice) -> ChangeResult {
let new_value = <T as LatticeLike>::join(&self.value, rhs);
debug_assert_eq!(
<T as LatticeLike>::join(&new_value, &self.value),
new_value,
"expected `join` to be monotonic"
);
debug_assert_eq!(
<T as LatticeLike>::join(&new_value, rhs),
new_value,
"expected `join` to be monotonic"
);
if new_value == self.value {
ChangeResult::Unchanged
} else {
self.value = new_value;
ChangeResult::Changed
}
}
fn meet(&mut self, rhs: &Self::Lattice) -> ChangeResult {
let new_value = <T as LatticeLike>::meet(&self.value, rhs);
debug_assert_eq!(
<T as LatticeLike>::meet(&new_value, &self.value),
new_value,
"expected `meet` to be monotonic"
);
debug_assert_eq!(
<T as LatticeLike>::meet(&new_value, rhs),
new_value,
"expected `meet` to be monotonic"
);
if new_value == self.value {
ChangeResult::Unchanged
} else {
self.value = new_value;
ChangeResult::Changed
}
}
}