Add ena crate for unification

This commit is contained in:
greg 2019-02-23 00:34:44 -08:00
parent f041cc17d2
commit 00a0de4431
3 changed files with 34 additions and 6 deletions

View File

@ -10,6 +10,7 @@ take_mut = "0.1.3"
maplit = "*" maplit = "*"
lazy_static = "0.2.8" lazy_static = "0.2.8"
failure = "0.1.2" failure = "0.1.2"
ena = "0.11.0"
schala-lang-codegen = { path = "../codegen" } schala-lang-codegen = { path = "../codegen" }

View File

@ -17,6 +17,7 @@ extern crate schala_repl;
extern crate schala_repl_codegen; extern crate schala_repl_codegen;
#[macro_use] #[macro_use]
extern crate schala_lang_codegen; extern crate schala_lang_codegen;
extern crate ena;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;

View File

@ -4,10 +4,16 @@ use std::rc::Rc;
// -nope, ghc deliberately does typechecking before desugaring to core // -nope, ghc deliberately does typechecking before desugaring to core
// cf. a history of haskell, peyton-jones // cf. a history of haskell, peyton-jones
use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable};
use crate::ast::*; use crate::ast::*;
use crate::util::ScopeStack; use crate::util::ScopeStack;
use crate::builtin::{PrefixOp, BinOp}; use crate::builtin::{PrefixOp, BinOp};
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct TypeData { pub struct TypeData {
ty: Option<Type> ty: Option<Type>
@ -23,6 +29,7 @@ pub type TypeName = Rc<String>;
pub struct TypeContext<'a> { pub struct TypeContext<'a> {
variable_map: ScopeStack<'a, Rc<String>, Type>, variable_map: ScopeStack<'a, Rc<String>, Type>,
unification_table: InPlaceUnificationTable<TypeVar>,
//evar_count: u32 //evar_count: u32
} }
@ -49,8 +56,15 @@ pub enum Type {
} }
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeVar(String); 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)] #[derive(Debug, Clone, PartialEq)]
pub enum TypeConst { pub enum TypeConst {
@ -190,6 +204,7 @@ impl<'a> TypeContext<'a> {
pub fn new() -> TypeContext<'a> { pub fn new() -> TypeContext<'a> {
TypeContext { TypeContext {
variable_map: ScopeStack::new(None), variable_map: ScopeStack::new(None),
unification_table: UnificationTable::new(),
//evar_count: 0 //evar_count: 0
} }
} }
@ -315,6 +330,7 @@ impl<'a> TypeContext<'a> {
} }
fn lambda(&mut self, params: &Vec<FormalParam>, type_anno: &Option<TypeIdentifier>, body: &Block) -> InferResult<Type> { fn lambda(&mut self, params: &Vec<FormalParam>, type_anno: &Option<TypeIdentifier>, body: &Block) -> InferResult<Type> {
Ok(ty!(Unit)) Ok(ty!(Unit))
} }
@ -336,10 +352,20 @@ impl<'a> TypeContext<'a> {
fn unify(&mut self, t1: Type, t2: Type) -> InferResult<Type> { fn unify(&mut self, t1: Type, t2: Type) -> InferResult<Type> {
use self::Type::*; use self::Type::*;
Ok(match (t1, t2) { use std::collections::hash_map::Entry;
(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)), 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)),
}
} }
} }