nac3core: fix polymorphic class method partial instantiation

This commit is contained in:
ychenfo 2021-11-09 01:15:41 +08:00
parent 439cef636f
commit c2706fa720
4 changed files with 48 additions and 19 deletions

View File

@ -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

View File

@ -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::<HashSet<_>>();
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::<HashMap<_, _>>()
};
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();

View File

@ -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);

View File

@ -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 {