use crate::TcKey;
use std::collections::HashMap;
use std::{fmt::Debug, ops::Index};
pub trait Abstract: Eq + Sized + Clone + Debug {
type Err: Debug;
fn unconstrained() -> Self;
fn is_unconstrained(&self) -> bool {
self == &Self::unconstrained()
}
fn meet(&self, other: &Self) -> Result<Self, Self::Err>;
fn arity(&self) -> Option<usize>;
fn nth_child(&self, n: usize) -> &Self;
fn with_children<I>(&self, children: I) -> Self
where
I: IntoIterator<Item = Self>;
}
#[derive(Debug, Clone)]
pub enum ReificationErr {
TooGeneral(String),
Conflicting(String),
}
pub trait Reifiable {
type Reified;
fn reify(&self) -> Self::Reified;
}
pub trait TryReifiable {
type Reified;
fn try_reify(&self) -> Result<Self::Reified, ReificationErr>;
}
pub trait Generalizable {
type Generalized;
fn generalize(&self) -> Self::Generalized;
}
pub trait TypeTable: Index<TcKey> {
type Type;
fn as_hashmap(self) -> HashMap<TcKey, Self::Type>;
}
#[derive(Debug, Clone)]
pub struct AbstractTypeTable<AbsTy: Abstract> {
table: HashMap<TcKey, AbsTy>,
}
impl<AbsTy: Abstract> Index<TcKey> for AbstractTypeTable<AbsTy> {
type Output = AbsTy;
fn index(&self, index: TcKey) -> &Self::Output {
&self.table[&index]
}
}
impl<AbsTy: Abstract> From<HashMap<TcKey, AbsTy>> for AbstractTypeTable<AbsTy> {
fn from(map: HashMap<TcKey, AbsTy>) -> Self {
AbstractTypeTable { table: map }
}
}
#[derive(Debug, Clone)]
pub struct ReifiedTypeTable<Concrete> {
table: HashMap<TcKey, Concrete>,
}
impl<Concrete> Index<TcKey> for ReifiedTypeTable<Concrete> {
type Output = Concrete;
fn index(&self, index: TcKey) -> &Self::Output {
&self.table[&index]
}
}
impl<Concrete> From<HashMap<TcKey, Concrete>> for ReifiedTypeTable<Concrete> {
fn from(map: HashMap<TcKey, Concrete>) -> Self {
ReifiedTypeTable { table: map }
}
}
impl<AbsTy: Abstract> TypeTable for AbstractTypeTable<AbsTy> {
type Type = AbsTy;
fn as_hashmap(self) -> HashMap<TcKey, Self::Type> {
self.table
}
}
impl<Concrete> TypeTable for ReifiedTypeTable<Concrete> {
type Type = Concrete;
fn as_hashmap(self) -> HashMap<TcKey, Self::Type> {
self.table
}
}
impl<AbsTy> AbstractTypeTable<AbsTy>
where
AbsTy: Abstract + Reifiable,
{
pub fn reified(self) -> ReifiedTypeTable<AbsTy::Reified> {
ReifiedTypeTable { table: self.table.into_iter().map(|(key, ty)| (key, ty.reify())).collect() }
}
}
impl<AbsTy> AbstractTypeTable<AbsTy>
where
AbsTy: Abstract + TryReifiable,
{
pub fn try_reified(self) -> Result<ReifiedTypeTable<AbsTy::Reified>, ()> {
self.table
.into_iter()
.map(|(key, ty)| ty.try_reify().map(|re| (key, re)))
.collect::<Result<HashMap<TcKey, AbsTy::Reified>, ReificationErr>>()
.map_err(|_| ())
.map(|table| ReifiedTypeTable { table })
}
}