use std::collections::HashMap;
use crate::error::Result;
use crate::types::{Type, TypeVar};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Constraint {
Equal(Type, Type),
Subtype(Type, Type),
Occurs(TypeVar, Type),
}
pub struct ConstraintSolver {
next_var: u32,
constraints: Vec<Constraint>,
substitution: HashMap<TypeVar, Type>,
}
impl Default for ConstraintSolver {
fn default() -> Self {
Self::new()
}
}
impl ConstraintSolver {
pub fn new() -> Self {
Self { next_var: 0, constraints: Vec::new(), substitution: HashMap::new() }
}
pub fn fresh_var(&mut self) -> TypeVar {
let var = TypeVar(self.next_var);
self.next_var += 1;
var
}
pub fn add_constraint(&mut self, constraint: Constraint) {
self.constraints.push(constraint);
}
pub fn solve(mut self) -> Result<HashMap<TypeVar, Type>> {
while let Some(constraint) = self.constraints.pop() {
self.solve_constraint(constraint)?;
}
Ok(self.substitution)
}
fn solve_constraint(&mut self, constraint: Constraint) -> Result<()> {
match constraint {
Constraint::Equal(t1, t2) => self.unify(t1, t2)?,
Constraint::Subtype(t1, t2) => self.subtype(t1, t2)?,
Constraint::Occurs(var, ty) => self.occurs_check(var, &ty)?,
}
Ok(())
}
fn unify(&mut self, _t1: Type, _t2: Type) -> Result<()> {
Ok(())
}
fn subtype(&mut self, _t1: Type, _t2: Type) -> Result<()> {
Ok(())
}
fn occurs_check(&self, _var: TypeVar, _ty: &Type) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fresh_var() {
let mut solver = ConstraintSolver::new();
let var1 = solver.fresh_var();
let var2 = solver.fresh_var();
assert_ne!(var1, var2);
}
}