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
|
fields: fields
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, ty)| {
|
.filter_map(|(name, ty)| {
|
||||||
(*name, (self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1))
|
// 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(),
|
.collect(),
|
||||||
params: params
|
params: params
|
||||||
|
|
|
@ -1654,7 +1654,7 @@ impl TopLevelComposer {
|
||||||
if let TypeEnum::TFunc(func_sig) = self.unifier.get_ty(*signature).as_ref() {
|
if let TypeEnum::TFunc(func_sig) = self.unifier.get_ty(*signature).as_ref() {
|
||||||
let FunSignature { args, ret, vars } = &*func_sig.borrow();
|
let FunSignature { args, ret, vars } = &*func_sig.borrow();
|
||||||
// None if is not class method
|
// None if is not class method
|
||||||
let self_type = {
|
let uninst_self_type = {
|
||||||
if let Some(class_id) = self.method_class.get(&DefinitionId(id)) {
|
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 = self.definition_ast_list.get(class_id.0).unwrap();
|
||||||
let class_def = class_def.0.read();
|
let class_def = class_def.0.read();
|
||||||
|
@ -1666,7 +1666,7 @@ impl TopLevelComposer {
|
||||||
&self.primitives_ty,
|
&self.primitives_ty,
|
||||||
&ty_ann,
|
&ty_ann,
|
||||||
)?;
|
)?;
|
||||||
Some(self_ty)
|
Some((self_ty, type_vars.clone()))
|
||||||
} else {
|
} else {
|
||||||
unreachable!("must be class def")
|
unreachable!("must be class def")
|
||||||
}
|
}
|
||||||
|
@ -1717,9 +1717,34 @@ impl TopLevelComposer {
|
||||||
};
|
};
|
||||||
let self_type = {
|
let self_type = {
|
||||||
let unifier = &mut self.unifier;
|
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 = {
|
let mut identifiers = {
|
||||||
// NOTE: none and function args?
|
// NOTE: none and function args?
|
||||||
let mut result: HashSet<_> = HashSet::new();
|
let mut result: HashSet<_> = HashSet::new();
|
||||||
|
|
|
@ -280,9 +280,11 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
{
|
{
|
||||||
let ok: bool = {
|
let ok: bool = {
|
||||||
// create a temp type var and unify to check compatibility
|
// create a temp type var and unify to check compatibility
|
||||||
let temp =
|
p == *tvar || {
|
||||||
unifier.get_fresh_var_with_range(range.borrow().as_slice());
|
let temp =
|
||||||
unifier.unify(temp.0, p).is_ok()
|
unifier.get_fresh_var_with_range(range.borrow().as_slice());
|
||||||
|
unifier.unify(temp.0, p).is_ok()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if ok {
|
if ok {
|
||||||
result.insert(*id, p);
|
result.insert(*id, p);
|
||||||
|
|
|
@ -719,22 +719,18 @@ impl Unifier {
|
||||||
/// Returns Some(T) where T is the instantiated type.
|
/// Returns Some(T) where T is the instantiated type.
|
||||||
/// Returns None if the function is already instantiated.
|
/// Returns None if the function is already instantiated.
|
||||||
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
||||||
let mut instantiated = false;
|
let mut instantiated = true;
|
||||||
let mut vars = Vec::new();
|
let mut vars = Vec::new();
|
||||||
for (k, v) in fun.vars.iter() {
|
for (k, v) in fun.vars.iter() {
|
||||||
if let TypeEnum::TVar { id, range, .. } =
|
if let TypeEnum::TVar { id, range, .. } =
|
||||||
self.unification_table.probe_value(*v).as_ref()
|
self.unification_table.probe_value(*v).as_ref()
|
||||||
{
|
{
|
||||||
if k != id {
|
// need to do this for partial instantiated function
|
||||||
instantiated = true;
|
// (in class methods that contains type vars not in class)
|
||||||
break;
|
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 {
|
if instantiated {
|
||||||
|
|
Loading…
Reference in New Issue