refactored using constrain

to allow easier modification later with subtyping
This commit is contained in:
pca006132 2021-07-19 17:05:48 +08:00
parent e732f7e089
commit eb4b2bb7f6
2 changed files with 22 additions and 20 deletions

View File

@ -38,6 +38,12 @@ impl<'a> Fold<()> for Inferencer<'a> {
type InferenceResult = Result<Type, String>; type InferenceResult = Result<Type, String>;
impl<'a> Inferencer<'a> { impl<'a> Inferencer<'a> {
/// Constrain a <: b
/// Currently implemented as unification
fn constrain(&mut self, a: Type, b: Type) -> Result<(), String> {
self.unifier.unify(a, b)
}
fn build_method_call( fn build_method_call(
&mut self, &mut self,
method: String, method: String,
@ -55,7 +61,7 @@ impl<'a> Inferencer<'a> {
let call = self.unifier.add_ty(TypeEnum::TCall { calls: vec![call] }); let call = self.unifier.add_ty(TypeEnum::TCall { calls: vec![call] });
let fields = once((method, call)).collect(); let fields = once((method, call)).collect();
let record = self.unifier.add_ty(TypeEnum::TRecord { fields }); let record = self.unifier.add_ty(TypeEnum::TRecord { fields });
self.unifier.unify(obj, record)?; self.constrain(obj, record)?;
Ok(ret) Ok(ret)
} }
@ -114,15 +120,15 @@ impl<'a> Inferencer<'a> {
fn infer_attribute(&mut self, value: &ast::Expr<Option<Type>>, attr: &str) -> InferenceResult { fn infer_attribute(&mut self, value: &ast::Expr<Option<Type>>, attr: &str) -> InferenceResult {
let (attr_ty, _) = self.unifier.get_fresh_var(); let (attr_ty, _) = self.unifier.get_fresh_var();
let fields = once((attr.to_string(), attr_ty)).collect(); let fields = once((attr.to_string(), attr_ty)).collect();
let parent = self.unifier.add_ty(TypeEnum::TRecord { fields }); let record = self.unifier.add_ty(TypeEnum::TRecord { fields });
self.unifier.unify(value.custom.unwrap(), parent)?; self.constrain(value.custom.unwrap(), record)?;
Ok(attr_ty) Ok(attr_ty)
} }
fn infer_bool_ops(&mut self, values: &[ast::Expr<Option<Type>>]) -> InferenceResult { fn infer_bool_ops(&mut self, values: &[ast::Expr<Option<Type>>]) -> InferenceResult {
let b = self.primitives.bool; let b = self.primitives.bool;
for v in values { for v in values {
self.unifier.unify(v.custom.unwrap(), b)?; self.constrain(v.custom.unwrap(), b)?;
} }
Ok(b) Ok(b)
} }
@ -181,32 +187,30 @@ impl<'a> Inferencer<'a> {
.iter() .iter()
.flatten() .flatten()
{ {
self.unifier self.constrain(v.custom.unwrap(), self.primitives.int32)?;
.unify(self.primitives.int32, v.custom.unwrap())?;
} }
let list = self.unifier.add_ty(TypeEnum::TList { ty }); let list = self.unifier.add_ty(TypeEnum::TList { ty });
self.unifier.unify(value.custom.unwrap(), list)?; self.constrain(value.custom.unwrap(), list)?;
Ok(list) Ok(list)
} }
ast::ExprKind::Constant { ast::ExprKind::Constant {
value: ast::Constant::Int(val), value: ast::Constant::Int(val),
.. ..
} => { } => {
// the index is a constant, so value can be a sequence (either list/tuple) // the index is a constant, so value can be a sequence.
let ind: i32 = val let ind: i32 = val
.try_into() .try_into()
.map_err(|_| "Index must be int32".to_string())?; .map_err(|_| "Index must be int32".to_string())?;
let map = once((ind, ty)).collect(); let map = once((ind, ty)).collect();
let seq = self.unifier.add_ty(TypeEnum::TSeq { map }); let seq = self.unifier.add_ty(TypeEnum::TSeq { map });
self.unifier.unify(value.custom.unwrap(), seq)?; self.constrain(value.custom.unwrap(), seq)?;
Ok(ty) Ok(ty)
} }
_ => { _ => {
// the index is not a constant, so value can only be a list // the index is not a constant, so value can only be a list
self.unifier self.constrain(slice.custom.unwrap(), self.primitives.int32)?;
.unify(slice.custom.unwrap(), self.primitives.int32)?;
let list = self.unifier.add_ty(TypeEnum::TList { ty }); let list = self.unifier.add_ty(TypeEnum::TList { ty });
self.unifier.unify(value.custom.unwrap(), list)?; self.constrain(value.custom.unwrap(), list)?;
Ok(ty) Ok(ty)
} }
} }
@ -218,10 +222,10 @@ impl<'a> Inferencer<'a> {
body: ast::Expr<Option<Type>>, body: ast::Expr<Option<Type>>,
orelse: ast::Expr<Option<Type>>, orelse: ast::Expr<Option<Type>>,
) -> InferenceResult { ) -> InferenceResult {
self.unifier self.constrain(test.custom.unwrap(), self.primitives.bool)?;
.unify(test.custom.unwrap(), self.primitives.bool)?; let ty = self.unifier.get_fresh_var().0;
self.unifier self.constrain(body.custom.unwrap(), ty)?;
.unify(body.custom.unwrap(), orelse.custom.unwrap())?; self.constrain(orelse.custom.unwrap(), ty)?;
Ok(body.custom.unwrap()) Ok(ty)
} }
} }

View File

@ -188,9 +188,7 @@ impl Unifier {
) )
}; };
let (ty_a, ty_b) = { let (ty_a, ty_b) = { (ty_a_cell.borrow(), ty_b_cell.borrow()) };
(ty_a_cell.borrow(), ty_b_cell.borrow())
};
self.occur_check(a, b)?; self.occur_check(a, b)?;
match (&*ty_a, &*ty_b) { match (&*ty_a, &*ty_b) {