forked from M-Labs/nac3
check type params in class generic base declaration
This commit is contained in:
parent
1a21fb1072
commit
935e7410fd
|
@ -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()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue