use crate::{
containers::{List, Map, Symbol},
typesys::{ConstExpr, Type, Variable},
};
use super::facts::TypeFacts;
#[derive(Debug, Clone, Default)]
pub struct TypecheckState<TVar: Variable, CVar: Variable> {
variable_scope: Map<Symbol, Type<TVar, CVar>>,
type_scope: Map<Symbol, Type<TVar, CVar>>,
cg_scope: Map<Symbol, ConstExpr<CVar>>,
function_scope: Map<Symbol, FunctionType<TVar, CVar>>,
safety: bool,
}
impl<TVar: Variable, CVar: Variable> TypecheckState<TVar, CVar> {
pub fn new() -> Self {
Self {
variable_scope: Map::new(),
type_scope: Map::new(),
cg_scope: Map::new(),
function_scope: Map::new(),
safety: true,
}
}
pub fn bind_var(mut self, s: Symbol, t: Type<TVar, CVar>) -> Self {
self.variable_scope.insert(s, t);
self
}
pub fn bind_vars(mut self, binds: List<(Symbol, Type<TVar, CVar>)>) -> Self {
for (s,t) in binds.into_iter() {
self.variable_scope.insert(s, t);
}
self
}
pub fn bind_cgvar(mut self, s: Symbol, v: ConstExpr<CVar>) -> Self {
self.cg_scope.insert(s, v);
self
}
pub fn bind_type_alias(mut self, alias: Symbol, t: Type<TVar, CVar>) -> Self {
self.type_scope.insert(alias, t);
self
}
pub fn bind_fun(mut self, name: Symbol, funtype: FunctionType<TVar, CVar>) -> Self {
self.function_scope.insert(name, funtype);
self
}
pub fn bind_safety(mut self, safety: bool) -> Self {
self.safety = safety;
self
}
pub fn lookup_safety(&self) -> bool {
self.safety
}
pub fn lookup_var(&self, s: Symbol) -> Option<Type<TVar, CVar>> {
self.variable_scope.get(&s).cloned()
}
pub fn lookup_cgvar(&self, s: Symbol) -> Option<ConstExpr<CVar>> {
self.cg_scope.get(&s).cloned()
}
pub fn lookup_type_alias(&self, alias: Symbol) -> Option<Type<TVar, CVar>> {
self.type_scope.get(&alias).cloned()
}
pub fn lookup_fun(&self, name: Symbol) -> Option<FunctionType<TVar, CVar>> {
self.function_scope.get(&name).cloned()
}
pub fn var_scope(&self) -> Map<Symbol, Type<TVar, CVar>> {
self.variable_scope.clone()
}
pub fn with_facts(mut self, facts: &TypeFacts<TVar, CVar>) -> Self {
log::trace!("with facts {:?}", facts);
for (k, v) in facts.iter() {
if let Some(t) = self.variable_scope.get_mut(k) {
log::trace!("applying fact type {:?} to existing {:?}", v, t);
let new_t = if t.subtype_of(v) {
t.clone()
} else {
v.clone()
};
*t = new_t;
}
}
self
}
}
#[derive(Debug, Clone)]
pub struct FunctionType<TVar: Variable, CVar: Variable> {
pub free_cgvars: List<CVar>,
pub free_vars: List<TVar>,
pub args: List<Type<TVar, CVar>>,
pub result: Type<TVar, CVar>,
}