forked from M-Labs/nac3
1
0
Fork 0

check type params in class generic base declaration

This commit is contained in:
ychenfo 2021-08-26 11:54:37 +08:00
parent 1a21fb1072
commit 935e7410fd
2 changed files with 35 additions and 7 deletions

View File

@ -466,13 +466,13 @@ impl TopLevelComposer {
let temp_def_list = self.extract_def_list(); let temp_def_list = self.extract_def_list();
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();
let (class_bases, class_ancestors, class_resolver, class_id) = { let (class_bases, class_ancestors, class_resolver, class_id, class_type_vars) = {
if let TopLevelDef::Class { ancestors, resolver, object_id, .. } = class_def.deref_mut() { if let TopLevelDef::Class { ancestors, resolver, object_id, type_vars, .. } = class_def.deref_mut() {
if let Some(ast::Located { if let Some(ast::Located {
node: ast::StmtKind::ClassDef { bases, .. }, .. node: ast::StmtKind::ClassDef { bases, .. }, ..
}) = class_ast }) = class_ast
{ {
(bases, ancestors, resolver, *object_id) (bases, ancestors, resolver, *object_id, type_vars)
} else { } else {
unreachable!("must be both class") unreachable!("must be both class")
} }
@ -519,10 +519,27 @@ impl TopLevelComposer {
if all_base.contains(&class_id) { if all_base.contains(&class_id) {
return Err("cyclic base detected".into()); return Err("cyclic base detected".into());
} }
// find the intersection between type vars occured in the base class type parameter
// and the type vars occured in the class generic declaration
let type_var_occured_in_base = get_type_var_contained_in_type_annotation(&base_ty);
for type_ann in type_var_occured_in_base {
if let TypeAnnotation::TypeVarKind(id, ty) = type_ann {
for (ty_id, class_typvar_ty) in class_type_vars.iter() {
if id == *ty_id {
// if they refer to the same top level defined type var, we unify them together
self.unifier.unify(ty, *class_typvar_ty)?;
}
}
} else {
unreachable!("must be type var annotation")
}
}
class_ancestors.push(base_ty); class_ancestors.push(base_ty);
} else { } else {
return Err( return Err(
"class base declaration can only be concretized custom class".into() "class base declaration can only be custom class".into()
); );
} }
} }

View File

@ -38,7 +38,11 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
x => { x => {
if let Some(obj_id) = resolver.get_identifier_def(x) { if let Some(obj_id) = resolver.get_identifier_def(x) {
let def = top_level_defs[obj_id.0].read(); let def = top_level_defs[obj_id.0].read();
if let TopLevelDef::Class { .. } = &*def { if let TopLevelDef::Class { type_vars, .. } = &*def {
// also check param number here
if !type_vars.is_empty() {
return Err(format!("expect {} type variable parameter but got 0", type_vars.len()))
}
Ok(TypeAnnotation::CustomClassKind { Ok(TypeAnnotation::CustomClassKind {
id: obj_id, id: obj_id,
params: vec![], params: vec![],
@ -67,7 +71,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
} }
}, },
// TODO: subscript or call? // TODO: subscript or call for virtual?
ast::ExprKind::Subscript { value, slice, .. } ast::ExprKind::Subscript { value, slice, .. }
if { matches!(&value.node, ast::ExprKind::Name { id, .. } if id == "virtual") } => if { matches!(&value.node, ast::ExprKind::Name { id, .. } if id == "virtual") } =>
{ {
@ -93,7 +97,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
.get_identifier_def(id) .get_identifier_def(id)
.ok_or_else(|| "unknown class name".to_string())?; .ok_or_else(|| "unknown class name".to_string())?;
let def = top_level_defs[obj_id.0].read(); let def = top_level_defs[obj_id.0].read();
if let TopLevelDef::Class { .. } = &*def { if let TopLevelDef::Class { type_vars, .. } = &*def {
let param_type_infos = if let ast::ExprKind::Tuple { elts, .. } = &slice.node { let param_type_infos = if let ast::ExprKind::Tuple { elts, .. } = &slice.node {
elts.iter() elts.iter()
.map(|v| { .map(|v| {
@ -115,6 +119,13 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
slice, slice,
)?] )?]
}; };
if type_vars.len() != param_type_infos.len() {
return Err(format!(
"expect {} type parameters but got {}",
type_vars.len(),
param_type_infos.len()
))
}
// NOTE: allow type var in class generic application list // NOTE: allow type var in class generic application list
Ok(TypeAnnotation::CustomClassKind { Ok(TypeAnnotation::CustomClassKind {
id: obj_id, id: obj_id,