diff --git a/schala-lang/language/Cargo.toml b/schala-lang/language/Cargo.toml index ea09ac1..a210754 100644 --- a/schala-lang/language/Cargo.toml +++ b/schala-lang/language/Cargo.toml @@ -10,6 +10,7 @@ take_mut = "0.1.3" maplit = "*" lazy_static = "0.2.8" failure = "0.1.2" +ena = "0.11.0" schala-lang-codegen = { path = "../codegen" } diff --git a/schala-lang/language/src/lib.rs b/schala-lang/language/src/lib.rs index aaa26dc..24d75ef 100644 --- a/schala-lang/language/src/lib.rs +++ b/schala-lang/language/src/lib.rs @@ -17,6 +17,7 @@ extern crate schala_repl; extern crate schala_repl_codegen; #[macro_use] extern crate schala_lang_codegen; +extern crate ena; use std::cell::RefCell; use std::rc::Rc; diff --git a/schala-lang/language/src/typechecking.rs b/schala-lang/language/src/typechecking.rs index e64ad05..d3edbb0 100644 --- a/schala-lang/language/src/typechecking.rs +++ b/schala-lang/language/src/typechecking.rs @@ -4,10 +4,16 @@ use std::rc::Rc; // -nope, ghc deliberately does typechecking before desugaring to core // cf. a history of haskell, peyton-jones +use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable}; + use crate::ast::*; use crate::util::ScopeStack; use crate::builtin::{PrefixOp, BinOp}; +use std::collections::HashMap; +use std::hash::Hash; + + #[derive(Debug, Clone, PartialEq)] pub struct TypeData { ty: Option @@ -23,6 +29,7 @@ pub type TypeName = Rc; pub struct TypeContext<'a> { variable_map: ScopeStack<'a, Rc, Type>, + unification_table: InPlaceUnificationTable, //evar_count: u32 } @@ -49,8 +56,15 @@ pub enum Type { } } -#[derive(Debug, Clone, PartialEq)] -pub struct TypeVar(String); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TypeVar(usize); + +impl UnifyKey for TypeVar { + type Value = (); + fn index(&self) -> u32 { self.0 as u32 } + fn from_index(u: u32) -> TypeVar { TypeVar(u as usize) } + fn tag() -> &'static str { "TypeVar" } +} #[derive(Debug, Clone, PartialEq)] pub enum TypeConst { @@ -190,6 +204,7 @@ impl<'a> TypeContext<'a> { pub fn new() -> TypeContext<'a> { TypeContext { variable_map: ScopeStack::new(None), + unification_table: UnificationTable::new(), //evar_count: 0 } } @@ -315,6 +330,7 @@ impl<'a> TypeContext<'a> { } fn lambda(&mut self, params: &Vec, type_anno: &Option, body: &Block) -> InferResult { + Ok(ty!(Unit)) } @@ -336,10 +352,20 @@ impl<'a> TypeContext<'a> { fn unify(&mut self, t1: Type, t2: Type) -> InferResult { use self::Type::*; - Ok(match (t1, t2) { - (Const(ref c1), Const(ref c2)) if c1 == c2 => Const(c1.clone()), //choice of c1 is arbitrary I *think* - (a, b) => return TypeError::new(format!("{:?} and {:?} do not unify", a, b)), - }) + use std::collections::hash_map::Entry; + + match (t1, t2) { + (Const(ref c1), Const(ref c2)) if c1 == c2 => Ok(Const(c1.clone())), //choice of c1 is arbitrary I *think* + (Const(ref c1), Var(ref v2)) => { + //TODO flesh this out! + Ok(Const(c1.clone())) + }, + (a @ Var(_), b @ Const(_)) => self.unify(b, a), + (Var(v1), Var(v2)) => { + panic!() + }, + (a, b) => TypeError::new(format!("{:?} and {:?} do not unify", a, b)), + } } }