forked from M-Labs/nac3
nac3core: top level check inheritance method overload
This commit is contained in:
parent
82c2edcf8d
commit
098bd1e6e6
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::typecheck::typedef::TypeVarMeta;
|
||||||
|
|
||||||
impl TopLevelComposer {
|
impl TopLevelComposer {
|
||||||
pub fn make_primitives() -> (PrimitiveStore, Unifier) {
|
pub fn make_primitives() -> (PrimitiveStore, Unifier) {
|
||||||
@ -116,4 +117,49 @@ impl TopLevelComposer {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_overload_type_compatible(unifier: &mut Unifier, ty: Type, other: Type) -> bool {
|
||||||
|
let ty = unifier.get_ty(ty);
|
||||||
|
let ty = ty.as_ref();
|
||||||
|
let other = unifier.get_ty(other);
|
||||||
|
let other = other.as_ref();
|
||||||
|
|
||||||
|
match (ty, other) {
|
||||||
|
(TypeEnum::TList { ty }, TypeEnum::TList { ty: other })
|
||||||
|
| (TypeEnum::TVirtual { ty }, TypeEnum::TVirtual { ty: other }) => {
|
||||||
|
Self::check_overload_type_compatible(unifier, *ty, *other)
|
||||||
|
}
|
||||||
|
|
||||||
|
(TypeEnum::TTuple { ty }, TypeEnum::TTuple { ty: other }) => ty
|
||||||
|
.iter()
|
||||||
|
.zip(other)
|
||||||
|
.all(|(ty, other)| Self::check_overload_type_compatible(unifier, *ty, *other)),
|
||||||
|
|
||||||
|
(
|
||||||
|
TypeEnum::TObj { obj_id, params, .. },
|
||||||
|
TypeEnum::TObj { obj_id: other_obj_id, params: other_params, .. },
|
||||||
|
) => {
|
||||||
|
let params = &*params.borrow();
|
||||||
|
let other_params = &*other_params.borrow();
|
||||||
|
obj_id.0 == other_obj_id.0
|
||||||
|
&& (params.iter().all(|(var_id, ty)| {
|
||||||
|
if let Some(other_ty) = other_params.get(var_id) {
|
||||||
|
Self::check_overload_type_compatible(unifier, *ty, *other_ty)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
TypeEnum::TVar { id, meta: TypeVarMeta::Generic, .. },
|
||||||
|
TypeEnum::TVar { id: other_id, meta: TypeVarMeta::Generic, .. },
|
||||||
|
) => {
|
||||||
|
// NOTE: directly compare var_id?
|
||||||
|
*id == *other_id
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,7 +452,7 @@ impl TopLevelComposer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// second get all ancestors
|
// second, get all ancestors
|
||||||
let mut ancestors_store: HashMap<DefinitionId, Vec<TypeAnnotation>> = Default::default();
|
let mut ancestors_store: HashMap<DefinitionId, Vec<TypeAnnotation>> = Default::default();
|
||||||
for (class_def, class_ast) in self.definition_ast_list.iter_mut() {
|
for (class_def, class_ast) in self.definition_ast_list.iter_mut() {
|
||||||
let mut class_def = class_def.write();
|
let mut class_def = class_def.write();
|
||||||
@ -513,7 +513,7 @@ impl TopLevelComposer {
|
|||||||
let mut type_var_to_concrete_def: HashMap<Type, TypeAnnotation> = HashMap::new();
|
let mut type_var_to_concrete_def: HashMap<Type, TypeAnnotation> = HashMap::new();
|
||||||
|
|
||||||
for (class_def, class_ast) in def_ast_list {
|
for (class_def, class_ast) in def_ast_list {
|
||||||
Self::analyze_single_class(
|
Self::analyze_single_class_methods_fields(
|
||||||
class_def.clone(),
|
class_def.clone(),
|
||||||
&class_ast.as_ref().unwrap().node,
|
&class_ast.as_ref().unwrap().node,
|
||||||
&temp_def_list,
|
&temp_def_list,
|
||||||
@ -531,10 +531,20 @@ impl TopLevelComposer {
|
|||||||
unifier.unify(ty, target_ty)?;
|
unifier.unify(ty, target_ty)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle the inheritanced methods and fields
|
||||||
|
for (class_def, _) in def_ast_list {
|
||||||
|
Self::analyze_single_class_ancestors(
|
||||||
|
class_def.clone(),
|
||||||
|
&temp_def_list,
|
||||||
|
unifier,
|
||||||
|
primitives,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 4, after class methods are done
|
/// step 4, after class methods are done, top level functions have nothing unknown
|
||||||
fn analyze_top_level_function(&mut self) -> Result<(), String> {
|
fn analyze_top_level_function(&mut self) -> Result<(), String> {
|
||||||
let def_list = &self.definition_ast_list;
|
let def_list = &self.definition_ast_list;
|
||||||
let keyword_list = &self.keyword_list;
|
let keyword_list = &self.keyword_list;
|
||||||
@ -682,13 +692,7 @@ impl TopLevelComposer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 5, field instantiation?
|
fn analyze_single_class_methods_fields(
|
||||||
fn analyze_top_level_field_instantiation(&mut self) -> Result<(), String> {
|
|
||||||
// TODO:
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn analyze_single_class(
|
|
||||||
class_def: Arc<RwLock<TopLevelDef>>,
|
class_def: Arc<RwLock<TopLevelDef>>,
|
||||||
class_ast: &ast::StmtKind<()>,
|
class_ast: &ast::StmtKind<()>,
|
||||||
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
||||||
@ -720,7 +724,7 @@ impl TopLevelComposer {
|
|||||||
{
|
{
|
||||||
if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast {
|
if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast {
|
||||||
(
|
(
|
||||||
object_id,
|
*object_id,
|
||||||
name.clone(),
|
name.clone(),
|
||||||
bases,
|
bases,
|
||||||
body,
|
body,
|
||||||
@ -828,7 +832,7 @@ impl TopLevelComposer {
|
|||||||
};
|
};
|
||||||
type_var_to_concrete_def.insert(
|
type_var_to_concrete_def.insert(
|
||||||
dummy_func_arg.ty,
|
dummy_func_arg.ty,
|
||||||
make_self_type_annotation(temp_def_list, *class_id)?,
|
make_self_type_annotation(temp_def_list, class_id)?,
|
||||||
);
|
);
|
||||||
result.push(dummy_func_arg);
|
result.push(dummy_func_arg);
|
||||||
}
|
}
|
||||||
@ -874,7 +878,7 @@ impl TopLevelComposer {
|
|||||||
let dummy_return_type = unifier.get_fresh_var().0;
|
let dummy_return_type = unifier.get_fresh_var().0;
|
||||||
type_var_to_concrete_def.insert(
|
type_var_to_concrete_def.insert(
|
||||||
dummy_return_type,
|
dummy_return_type,
|
||||||
make_self_type_annotation(temp_def_list, *class_id)?,
|
make_self_type_annotation(temp_def_list, class_id)?,
|
||||||
);
|
);
|
||||||
dummy_return_type
|
dummy_return_type
|
||||||
}
|
}
|
||||||
@ -943,4 +947,122 @@ impl TopLevelComposer {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn analyze_single_class_ancestors(
|
||||||
|
class_def: Arc<RwLock<TopLevelDef>>,
|
||||||
|
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
||||||
|
unifier: &mut Unifier,
|
||||||
|
primitives: &PrimitiveStore,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let mut class_def = class_def.write();
|
||||||
|
let (
|
||||||
|
_class_id,
|
||||||
|
class_ancestor_def,
|
||||||
|
_class_fields_def,
|
||||||
|
class_methods_def,
|
||||||
|
_class_type_vars_def,
|
||||||
|
_class_resolver,
|
||||||
|
) = if let TopLevelDef::Class {
|
||||||
|
object_id,
|
||||||
|
ancestors,
|
||||||
|
fields,
|
||||||
|
methods,
|
||||||
|
resolver,
|
||||||
|
type_vars,
|
||||||
|
..
|
||||||
|
} = class_def.deref_mut()
|
||||||
|
{
|
||||||
|
(*object_id, ancestors, fields, methods, type_vars, resolver)
|
||||||
|
} else {
|
||||||
|
unreachable!("here must be class def ast");
|
||||||
|
};
|
||||||
|
|
||||||
|
for (method_name, method_ty, ..) in class_methods_def {
|
||||||
|
if method_name == "__init__" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// search the ancestors from the nearest to the deepest to find overload and check
|
||||||
|
'search_for_overload: for anc in class_ancestor_def.iter().skip(1) {
|
||||||
|
if let TypeAnnotation::CustomClassKind { id, params } = anc {
|
||||||
|
let anc_class_def = temp_def_list.get(id.0).unwrap().read();
|
||||||
|
let anc_class_def = anc_class_def.deref();
|
||||||
|
|
||||||
|
if let TopLevelDef::Class { methods, type_vars, .. } = anc_class_def {
|
||||||
|
for (anc_method_name, anc_method_ty, ..) in methods {
|
||||||
|
// if same name, then is overload, needs check
|
||||||
|
if anc_method_name == method_name {
|
||||||
|
let param_ty = params
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
get_type_from_type_annotation_kinds(
|
||||||
|
temp_def_list,
|
||||||
|
unifier,
|
||||||
|
primitives,
|
||||||
|
x,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let subst = type_vars
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
if let TypeEnum::TVar { id, .. } =
|
||||||
|
unifier.get_ty(*x).as_ref()
|
||||||
|
{
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.zip(param_ty.into_iter())
|
||||||
|
.collect::<HashMap<u32, Type>>();
|
||||||
|
|
||||||
|
let anc_method_ty = unifier.subst(*anc_method_ty, &subst).unwrap();
|
||||||
|
|
||||||
|
if let (
|
||||||
|
TypeEnum::TFunc(child_method_sig),
|
||||||
|
TypeEnum::TFunc(parent_method_sig),
|
||||||
|
) = (
|
||||||
|
unifier.get_ty(*method_ty).as_ref(),
|
||||||
|
unifier.get_ty(anc_method_ty).as_ref(),
|
||||||
|
) {
|
||||||
|
let (
|
||||||
|
FunSignature { args: c_as, ret: c_r, .. },
|
||||||
|
FunSignature { args: p_as, ret: p_r, .. },
|
||||||
|
) = (&*child_method_sig.borrow(), &*parent_method_sig.borrow());
|
||||||
|
|
||||||
|
// arguments
|
||||||
|
for (
|
||||||
|
FuncArg { name: c_name, ty: c_ty, .. },
|
||||||
|
FuncArg { name: p_name, ty: p_ty, .. },
|
||||||
|
) in c_as.iter().zip(p_as)
|
||||||
|
{
|
||||||
|
if c_name == "self" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if c_name != p_name
|
||||||
|
|| !Self::check_overload_type_compatible(
|
||||||
|
unifier, *c_ty, *p_ty,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Err("incompatible parameter".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the compatibility of c_r and p_r
|
||||||
|
if !Self::check_overload_type_compatible(unifier, *c_r, *p_r) {
|
||||||
|
return Err("incompatible parameter".into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!("must be function type")
|
||||||
|
}
|
||||||
|
break 'search_for_overload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
|||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
return Err("application of type vars to generic class \
|
return Err("application of type vars to generic class \
|
||||||
not currently supported"
|
is not currently supported"
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user