From c2706fa720245dcde82eb25c9dfde8466e416dc3 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Tue, 9 Nov 2021 01:15:41 +0800 Subject: [PATCH] nac3core: fix polymorphic class method partial instantiation --- nac3core/src/codegen/concrete_type.rs | 10 +++++-- nac3core/src/toplevel/composer.rs | 33 +++++++++++++++++++++--- nac3core/src/toplevel/type_annotation.rs | 8 +++--- nac3core/src/typecheck/typedef/mod.rs | 16 +++++------- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/nac3core/src/codegen/concrete_type.rs b/nac3core/src/codegen/concrete_type.rs index f4f4518b9..422e4dfc1 100644 --- a/nac3core/src/codegen/concrete_type.rs +++ b/nac3core/src/codegen/concrete_type.rs @@ -147,8 +147,14 @@ impl ConcreteTypeStore { fields: fields .borrow() .iter() - .map(|(name, ty)| { - (*name, (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1)) + .filter_map(|(name, ty)| { + // filter out functions as they can have type vars and + // will not affect codegen + if let TypeEnum::TFunc( .. ) = &*unifier.get_ty(ty.0) { + None + } else { + Some((*name, (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1))) + } }) .collect(), params: params diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index bf9f15612..57ca26434 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1654,7 +1654,7 @@ impl TopLevelComposer { if let TypeEnum::TFunc(func_sig) = self.unifier.get_ty(*signature).as_ref() { let FunSignature { args, ret, vars } = &*func_sig.borrow(); // None if is not class method - let self_type = { + let uninst_self_type = { if let Some(class_id) = self.method_class.get(&DefinitionId(id)) { let class_def = self.definition_ast_list.get(class_id.0).unwrap(); let class_def = class_def.0.read(); @@ -1666,7 +1666,7 @@ impl TopLevelComposer { &self.primitives_ty, &ty_ann, )?; - Some(self_ty) + Some((self_ty, type_vars.clone())) } else { unreachable!("must be class def") } @@ -1717,9 +1717,34 @@ impl TopLevelComposer { }; let self_type = { let unifier = &mut self.unifier; - self_type.map(|x| unifier.subst(x, &subst).unwrap_or(x)) + uninst_self_type + .clone() + .map(|(self_type, type_vars)| { + let subst_for_self = { + let class_ty_var_ids = type_vars + .iter() + .map(|x| { + if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*x) { + *id + } else { + unreachable!("must be type var here"); + } + }) + .collect::>(); + subst + .iter() + .filter_map(|(ty_var_id, ty_var_target)| { + if class_ty_var_ids.contains(ty_var_id) { + Some((*ty_var_id, *ty_var_target)) + } else { + None + } + }) + .collect::>() + }; + unifier.subst(self_type, &subst_for_self).unwrap_or(self_type) + }) }; - let mut identifiers = { // NOTE: none and function args? let mut result: HashSet<_> = HashSet::new(); diff --git a/nac3core/src/toplevel/type_annotation.rs b/nac3core/src/toplevel/type_annotation.rs index 257d582e2..307d87944 100644 --- a/nac3core/src/toplevel/type_annotation.rs +++ b/nac3core/src/toplevel/type_annotation.rs @@ -280,9 +280,11 @@ pub fn get_type_from_type_annotation_kinds( { let ok: bool = { // create a temp type var and unify to check compatibility - let temp = - unifier.get_fresh_var_with_range(range.borrow().as_slice()); - unifier.unify(temp.0, p).is_ok() + p == *tvar || { + let temp = + unifier.get_fresh_var_with_range(range.borrow().as_slice()); + unifier.unify(temp.0, p).is_ok() + } }; if ok { result.insert(*id, p); diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index eb0cf4bc8..85e619c8b 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -719,22 +719,18 @@ impl Unifier { /// Returns Some(T) where T is the instantiated type. /// Returns None if the function is already instantiated. fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type { - let mut instantiated = false; + let mut instantiated = true; let mut vars = Vec::new(); for (k, v) in fun.vars.iter() { if let TypeEnum::TVar { id, range, .. } = self.unification_table.probe_value(*v).as_ref() { - if k != id { - instantiated = true; - break; + // need to do this for partial instantiated function + // (in class methods that contains type vars not in class) + if k == id { + instantiated = false; + vars.push((*k, range.clone())); } - // actually, if the first check succeeded, the function should be uninstatiated. - // The cloned values must be used and would not be wasted. - vars.push((*k, range.clone())); - } else { - instantiated = true; - break; } } if instantiated {