use crate::allocator::SortAllocator;
use crate::ast::{HasArenaAlt, Sort, Str, TC};
use crate::traits::Repr;
use std::collections::HashMap;
pub(crate) type SortSubst = HashMap<Str, Option<Sort>>;
pub fn sort_unification(subst: &mut SortSubst, expected: &Sort, ground: &Sort) -> TC<bool> {
if expected.1.is_empty() {
let esymb = &expected.repr().0.symbol;
if let Some(v) = subst.get(esymb) {
match v {
None => {
subst.insert(esymb.clone(), Some(ground.clone()));
Ok(true)
}
Some(v) => Ok(*v == *ground), }
} else {
Ok(*expected == *ground)
}
} else if expected.1.len() != ground.1.len() {
Err(format!(
"TC: sort mismatch: {} and {} cannot be unified!",
ground, expected,
))
} else {
for (e, g) in expected.1.iter().zip(ground.1.iter()) {
if !sort_unification(subst, e, g)? {
return Ok(false);
}
}
Ok(true)
}
}
pub fn empty_subst(vs: &[Str]) -> SortSubst {
vs.iter().map(|s| (s.clone(), None)).collect()
}
pub fn subst_missed_vars(subst: &SortSubst) -> Vec<Str> {
subst
.iter()
.filter_map(|(k, v)| if v.is_none() { Some(k.clone()) } else { None })
.collect()
}
pub(crate) fn apply_subst<A: HasArenaAlt>(arena: &mut A, subst: &SortSubst, s: &Sort) -> Sort {
if s.1.is_empty() {
let sym = &s.repr().0.symbol;
if let Some(Some(v)) = subst.get(sym) {
v.clone()
} else {
s.clone()
}
} else {
let ss = s.1.iter().map(|s| apply_subst(arena, subst, s)).collect();
arena.arena_alt().sort(s.repr().0.clone(), ss)
}
}
pub fn instantiate_subst<'a, 'b>(
subst: &mut SortSubst,
eg_pairs: impl IntoIterator<Item = (&'a Sort, &'b Sort)>,
) -> TC<bool> {
for (expected, ground) in eg_pairs {
if !sort_unification(subst, expected, ground)? {
return Ok(false);
}
}
Ok(true)
}
pub fn format_subst(subst: &SortSubst) -> String {
subst
.iter()
.map(|(k, v)| match v {
None => {
format!("?/{}", k)
}
Some(v) => {
format!("{}/{}", v, k)
}
})
.collect::<Vec<_>>()
.join(", ")
}