forked from M-Labs/nac3
nac3core: toplevel all ancestors are put into the def list, disallow generic base class for now
This commit is contained in:
parent
e2a9bdd8bc
commit
40e58d02ed
@ -84,31 +84,36 @@ impl TopLevelComposer {
|
|||||||
Err(format!("no method {} in the current class", method_name))
|
Err(format!("no method {} in the current class", method_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get all base class def id of a class, including itself
|
/// get all base class def id of a class, excluding itself. \
|
||||||
pub fn get_all_base(
|
/// this function should called only after the direct parent is set
|
||||||
child: DefinitionId,
|
/// and before all the ancestors are set
|
||||||
|
/// and when we allow single inheritance \
|
||||||
|
/// the order of the returned list is from the child to the deepest ancestor
|
||||||
|
pub fn get_all_ancestors_helper(
|
||||||
|
child: &TypeAnnotation,
|
||||||
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
||||||
) -> Vec<DefinitionId> {
|
) -> Vec<TypeAnnotation> {
|
||||||
let mut result: Vec<DefinitionId> = Vec::new();
|
let mut result: Vec<TypeAnnotation> = Vec::new();
|
||||||
let child_def = temp_def_list.get(child.0).unwrap();
|
let mut parent = Self::get_parent(child, temp_def_list);
|
||||||
let child_def = child_def.read();
|
while let Some(p) = parent {
|
||||||
let child_def = child_def.deref();
|
parent = Self::get_parent(&p, temp_def_list);
|
||||||
|
result.push(p);
|
||||||
if let TopLevelDef::Class { ancestors, .. } = child_def {
|
|
||||||
for a in ancestors {
|
|
||||||
if let TypeAnnotation::CustomClassKind { id, .. } = a {
|
|
||||||
if *id != child {
|
|
||||||
result.extend(Self::get_all_base(*id, temp_def_list));
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unreachable!("must be class type annotation type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!("this function should only be called with class def id as parameter")
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push(child);
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_parent(
|
||||||
|
child: &TypeAnnotation,
|
||||||
|
temp_def_list: &[Arc<RwLock<TopLevelDef>>],
|
||||||
|
) -> Option<TypeAnnotation> {
|
||||||
|
let child_id =
|
||||||
|
if let TypeAnnotation::CustomClassKind { id, .. } = child { *id } else { return None };
|
||||||
|
let child_def = temp_def_list.get(child_id.0).unwrap();
|
||||||
|
let child_def = child_def.read();
|
||||||
|
if let TopLevelDef::Class { ancestors, .. } = &*child_def {
|
||||||
|
Some(ancestors[0].clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use itertools::{izip, Itertools};
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rustpython_parser::ast::{self, Stmt};
|
use rustpython_parser::ast::{self, Stmt};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||||
pub struct DefinitionId(pub usize);
|
pub struct DefinitionId(pub usize);
|
||||||
|
|
||||||
mod type_annotation;
|
mod type_annotation;
|
||||||
@ -393,6 +393,8 @@ impl TopLevelComposer {
|
|||||||
fn analyze_top_level_class_bases(&mut self) -> Result<(), String> {
|
fn analyze_top_level_class_bases(&mut self) -> Result<(), String> {
|
||||||
let temp_def_list = self.extract_def_list();
|
let temp_def_list = self.extract_def_list();
|
||||||
let unifier = self.unifier.borrow_mut();
|
let unifier = self.unifier.borrow_mut();
|
||||||
|
|
||||||
|
// first, only push direct parent into the 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, class_type_vars) = {
|
let (class_bases, class_ancestors, class_resolver, class_id, class_type_vars) = {
|
||||||
@ -414,7 +416,6 @@ impl TopLevelComposer {
|
|||||||
let class_resolver = class_resolver.as_ref().unwrap();
|
let class_resolver = class_resolver.as_ref().unwrap();
|
||||||
let class_resolver = class_resolver.deref();
|
let class_resolver = class_resolver.deref();
|
||||||
|
|
||||||
// only allow single inheritance
|
|
||||||
let mut has_base = false;
|
let mut has_base = false;
|
||||||
for b in class_bases {
|
for b in class_bases {
|
||||||
// type vars have already been handled, so skip on `Generic[...]`
|
// type vars have already been handled, so skip on `Generic[...]`
|
||||||
@ -436,6 +437,8 @@ impl TopLevelComposer {
|
|||||||
}
|
}
|
||||||
has_base = true;
|
has_base = true;
|
||||||
|
|
||||||
|
// the function parse_ast_to make sure that no type var occured in
|
||||||
|
// bast_ty if it is a CustomClassKind
|
||||||
let base_ty = parse_ast_to_type_annotation_kinds(
|
let base_ty = parse_ast_to_type_annotation_kinds(
|
||||||
class_resolver,
|
class_resolver,
|
||||||
&temp_def_list,
|
&temp_def_list,
|
||||||
@ -444,36 +447,8 @@ impl TopLevelComposer {
|
|||||||
b,
|
b,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let TypeAnnotation::CustomClassKind { id, .. } = &base_ty {
|
if let TypeAnnotation::CustomClassKind { .. } = &base_ty {
|
||||||
// TODO: change a way to check to prevent cyclic base class
|
class_ancestors.push(base_ty);
|
||||||
let all_base = Self::get_all_base(*id, &temp_def_list);
|
|
||||||
if all_base.contains(&class_id) {
|
|
||||||
return Err("cyclic base detected".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: type vars occured in the base type annotation must be
|
|
||||||
// a subset of the class decalred type annotation
|
|
||||||
let base_type_var_ids = get_type_var_contained_in_type_annotation(&base_ty)
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| {
|
|
||||||
if let TypeAnnotation::TypeVarKind(ty) = x {
|
|
||||||
get_var_id(ty, unifier)
|
|
||||||
} else {
|
|
||||||
unreachable!("must be type var")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Result<HashSet<_>, _>>()?;
|
|
||||||
let class_generic_type_var_ids = class_type_vars
|
|
||||||
.iter()
|
|
||||||
.map(|x| get_var_id(*x, unifier))
|
|
||||||
.collect::<Result<HashSet<_>, _>>()?;
|
|
||||||
if class_generic_type_var_ids.is_superset(&base_type_var_ids) {
|
|
||||||
// TODO: this base confirmed
|
|
||||||
// in what order to push all the ancestors?
|
|
||||||
// class_ancestors.push(base_ty);
|
|
||||||
} else {
|
|
||||||
return Err("base class generic type parameter must be declared".into());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err("class base declaration can only be custom class".into());
|
return Err("class base declaration can only be custom class".into());
|
||||||
}
|
}
|
||||||
@ -481,8 +456,57 @@ impl TopLevelComposer {
|
|||||||
|
|
||||||
// TODO: ancestors should include all bases, need to rewrite
|
// TODO: ancestors should include all bases, need to rewrite
|
||||||
// push self to the ancestors
|
// push self to the ancestors
|
||||||
class_ancestors.push(make_self_type_annotation(&temp_def_list, class_id)?)
|
// class_ancestors.push(make_self_type_annotation(&temp_def_list, class_id)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// second get all ancestors
|
||||||
|
let mut ancestors_store: HashMap<DefinitionId, Vec<TypeAnnotation>> = Default::default();
|
||||||
|
for (class_def, class_ast) in self.definition_ast_list.iter_mut() {
|
||||||
|
let mut class_def = class_def.write();
|
||||||
|
let (class_ancestors, class_id) = {
|
||||||
|
if let TopLevelDef::Class { ancestors, object_id, .. } = class_def.deref_mut() {
|
||||||
|
if let Some(ast::Located { node: ast::StmtKind::ClassDef { .. }, .. }) =
|
||||||
|
class_ast
|
||||||
|
{
|
||||||
|
(ancestors, *object_id)
|
||||||
|
} else {
|
||||||
|
unreachable!("must be both class")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ancestors_store.insert(
|
||||||
|
class_id,
|
||||||
|
Self::get_all_ancestors_helper(&class_ancestors[0], temp_def_list.as_slice()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the ancestors to the def list
|
||||||
|
for (class_def, class_ast) in self.definition_ast_list.iter_mut() {
|
||||||
|
let mut class_def = class_def.write();
|
||||||
|
let (class_ancestors, class_id) = {
|
||||||
|
if let TopLevelDef::Class { ancestors, object_id, .. } = class_def.deref_mut() {
|
||||||
|
if let Some(ast::Located { node: ast::StmtKind::ClassDef { .. }, .. }) =
|
||||||
|
class_ast
|
||||||
|
{
|
||||||
|
(ancestors, *object_id)
|
||||||
|
} else {
|
||||||
|
unreachable!("must be both class")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ans = ancestors_store.get_mut(&class_id).unwrap();
|
||||||
|
class_ancestors.append(ans);
|
||||||
|
|
||||||
|
// insert self type annotation
|
||||||
|
class_ancestors
|
||||||
|
.insert(0, make_self_type_annotation(temp_def_list.as_slice(), class_id)?);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
|||||||
params_ast.len()
|
params_ast.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
params_ast
|
let result = params_ast
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
parse_ast_to_type_annotation_kinds(
|
parse_ast_to_type_annotation_kinds(
|
||||||
@ -106,7 +106,19 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
|||||||
x,
|
x,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
// make sure the result do not contain any type vars
|
||||||
|
let no_type_var = result
|
||||||
|
.iter()
|
||||||
|
.all(|x| get_type_var_contained_in_type_annotation(x).is_empty());
|
||||||
|
if no_type_var {
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
return Err("application of type vars to generic class \
|
||||||
|
not currently supported"
|
||||||
|
.into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// allow type var in class generic application list
|
// allow type var in class generic application list
|
||||||
@ -156,9 +168,6 @@ pub fn get_type_from_type_annotation_kinds(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*x).as_ref() {
|
if let TypeEnum::TVar { id, .. } = unifier.get_ty(*x).as_ref() {
|
||||||
// this is for the class generic application,
|
|
||||||
// we only need the information for the copied type var
|
|
||||||
// associated with the class
|
|
||||||
*id
|
*id
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
Loading…
Reference in New Issue
Block a user