forked from M-Labs/nac3
nac3core: fix polymorphic class method partial instantiation
This commit is contained in:
parent
439cef636f
commit
c2706fa720
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
// actually, if the first check succeeded, the function should be uninstatiated.
|
||||
// The cloned values must be used and would not be wasted.
|
||||
// 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()));
|
||||
} else {
|
||||
instantiated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if instantiated {
|
||||
|
|
Loading…
Reference in New Issue