use super::{Type, TypeVar, Constraint};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeScheme {
pub vars: Vec<TypeVar>,
pub constraints: Vec<Constraint>,
pub type_: Type,
}
impl TypeScheme {
pub fn monomorphic(type_: Type) -> Self {
Self {
vars: Vec::new(),
constraints: Vec::new(),
type_,
}
}
pub fn polymorphic(vars: Vec<TypeVar>, constraints: Vec<Constraint>, type_: Type) -> Self {
Self {
vars,
constraints,
type_,
}
}
pub fn instantiate(&self) -> Type {
if self.vars.is_empty() {
return self.type_.clone();
}
let fresh_vars: HashMap<TypeVar, Type> = self.vars
.iter()
.map(|var| (var.clone(), Type::fresh_var()))
.collect();
Self::substitute_vars(&self.type_, &fresh_vars)
}
fn substitute_vars(type_: &Type, subst: &HashMap<TypeVar, Type>) -> Type {
match type_ {
Type::Variable(var) => {
subst.get(var).cloned().unwrap_or_else(|| type_.clone())
}
Type::Pair(a, b) => {
Type::pair(
Self::substitute_vars(a, subst),
Self::substitute_vars(b, subst),
)
}
Type::List(t) => Type::list(Self::substitute_vars(t, subst)),
Type::Vector(t) => Type::vector(Self::substitute_vars(t, subst)),
Type::Function { params, return_type } => {
Type::function(
params.iter().map(|p| Self::substitute_vars(p, subst)).collect(),
Self::substitute_vars(return_type, subst),
)
}
_ => type_.clone(), }
}
}