Okay I am figuring things out about hindley-milner again
This commit is contained in:
parent
4928fc0019
commit
f79dc0b1e3
@ -115,7 +115,7 @@ impl TypeContext {
|
|||||||
let spec = PathSpecifier(name.clone());
|
let spec = PathSpecifier(name.clone());
|
||||||
let ty = expr.1.as_ref()
|
let ty = expr.1.as_ref()
|
||||||
.map(|ty| self.from_anno(ty))
|
.map(|ty| self.from_anno(ty))
|
||||||
.unwrap_or_else(|| { self.get_existential_type() });
|
.unwrap_or_else(|| { self.alloc_existential_type() }); // this call to alloc_existential is OK b/c a binding only ever has one type, so if the annotation is absent, it's fine to just make one de novo
|
||||||
let entry = TypeContextEntry { ty, constant: *constant };
|
let entry = TypeContextEntry { ty, constant: *constant };
|
||||||
self.symbol_table.insert(spec, entry);
|
self.symbol_table.insert(spec, entry);
|
||||||
},
|
},
|
||||||
@ -137,7 +137,7 @@ impl TypeContext {
|
|||||||
pub fn debug_symbol_table(&self) -> String {
|
pub fn debug_symbol_table(&self) -> String {
|
||||||
format!("Symbol table:\n {:?}", self.symbol_table)
|
format!("Symbol table:\n {:?}", self.symbol_table)
|
||||||
}
|
}
|
||||||
fn get_existential_type(&mut self) -> Type {
|
fn alloc_existential_type(&mut self) -> Type {
|
||||||
let ret = Type::TVar(TypeVar::Exist(self.existential_type_label_count));
|
let ret = Type::TVar(TypeVar::Exist(self.existential_type_label_count));
|
||||||
self.existential_type_label_count += 1;
|
self.existential_type_label_count += 1;
|
||||||
ret
|
ret
|
||||||
@ -153,7 +153,7 @@ impl TypeContext {
|
|||||||
"Int" => TConst(Integer),
|
"Int" => TConst(Integer),
|
||||||
"Bool" => TConst(Boolean),
|
"Bool" => TConst(Boolean),
|
||||||
"String" => TConst(StringT),
|
"String" => TConst(StringT),
|
||||||
_ => self.get_existential_type()
|
s => TVar(TypeVar::Univ(Rc::new(format!("{}",s)))),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&TypeName::Tuple(ref items) => {
|
&TypeName::Tuple(ref items) => {
|
||||||
@ -170,13 +170,22 @@ impl TypeContext {
|
|||||||
use self::Type::*;
|
use self::Type::*;
|
||||||
use self::TypeConst::*;
|
use self::TypeConst::*;
|
||||||
|
|
||||||
let return_type = sig.type_anno.as_ref().map(|anno| self.from_anno(&anno)).unwrap_or_else(|| { self.get_existential_type() });
|
//TODO this won't work properly until you make sure that all (universal) type vars in the function have the same existential type var
|
||||||
|
// actually this should never even put existential types into the symbol table at all
|
||||||
|
|
||||||
|
//this will crash if more than 5 arg function is used
|
||||||
|
let names = vec!["a", "b", "c", "d", "e", "f"];
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
let mut get_type = || { let q = TVar(TypeVar::Univ(Rc::new(format!("{}", names.get(idx).unwrap())))); idx += 1; q };
|
||||||
|
|
||||||
|
let return_type = sig.type_anno.as_ref().map(|anno| self.from_anno(&anno)).unwrap_or_else(|| { get_type() });
|
||||||
if sig.params.len() == 0 {
|
if sig.params.len() == 0 {
|
||||||
TConst(FunctionT(Box::new(TConst(Unit)), Box::new(return_type)))
|
TConst(FunctionT(Box::new(TConst(Unit)), Box::new(return_type)))
|
||||||
} else {
|
} else {
|
||||||
let mut output_type = return_type;
|
let mut output_type = return_type;
|
||||||
for p in sig.params.iter() {
|
for p in sig.params.iter() {
|
||||||
let p_type = p.1.as_ref().map(|anno| self.from_anno(anno)).unwrap_or_else(|| { self.get_existential_type() });
|
let p_type = p.1.as_ref().map(|anno| self.from_anno(anno)).unwrap_or_else(|| { get_type() });
|
||||||
output_type = TConst(FunctionT(Box::new(p_type), Box::new(output_type)));
|
output_type = TConst(FunctionT(Box::new(p_type), Box::new(output_type)));
|
||||||
}
|
}
|
||||||
output_type
|
output_type
|
||||||
@ -202,6 +211,7 @@ impl TypeContext {
|
|||||||
Ok(last)
|
Ok(last)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn infer(&mut self, expr: &Expression) -> TypeCheckResult {
|
fn infer(&mut self, expr: &Expression) -> TypeCheckResult {
|
||||||
use self::ExpressionType::*;
|
use self::ExpressionType::*;
|
||||||
use self::Type::*;
|
use self::Type::*;
|
||||||
@ -298,6 +308,39 @@ impl TypeContext {
|
|||||||
))
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
fn infer(&mut self, expr: &Expression) -> TypeCheckResult {
|
||||||
|
use self::ExpressionType::*;
|
||||||
|
use self::Type::*;
|
||||||
|
use self::TypeConst::*;
|
||||||
|
|
||||||
|
Ok(match (&expr.0, &expr.1) {
|
||||||
|
(ex, &Some(ref anno)) => {
|
||||||
|
let tx = self.infer(&Expression(ex.clone(), None))?; //TODO rewrite this to call into a function that takes just an ExprType, to avoid this cloning
|
||||||
|
let ty = self.from_anno(anno);
|
||||||
|
self.unify(tx, ty)?
|
||||||
|
},
|
||||||
|
(&IntLiteral(_), _) => TConst(Integer),
|
||||||
|
(&BoolLiteral(_), _) => TConst(Boolean),
|
||||||
|
(&Value(ref name), _) => {
|
||||||
|
self.lookup(name)
|
||||||
|
.map(|entry| entry.ty)
|
||||||
|
.ok_or(format!("Couldn't find {}", name))?
|
||||||
|
},
|
||||||
|
(&Call { ref f, ref arguments }, _) => {
|
||||||
|
let tf = self.infer(f)?;
|
||||||
|
let targ = self.infer(arguments.get(0).unwrap())?;
|
||||||
|
match tf {
|
||||||
|
TConst(FunctionT(box t1, box t2)) => {
|
||||||
|
let _ = self.unify(t1, targ);
|
||||||
|
t2
|
||||||
|
},
|
||||||
|
_ => return Err(format!("Not a function!")),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => TConst(Bottom),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn unify(&mut self, t1: Type, t2: Type) -> TypeCheckResult {
|
fn unify(&mut self, t1: Type, t2: Type) -> TypeCheckResult {
|
||||||
use self::Type::*;
|
use self::Type::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user