1
0
forked from M-Labs/nac3

nac3core: top level fix class fields as nac3 spec

This commit is contained in:
ychenfo 2021-09-12 03:49:21 +08:00
parent c7cb02b0f3
commit 147298ff40
2 changed files with 60 additions and 57 deletions

View File

@ -136,6 +136,8 @@ impl TopLevelComposer {
"none".into(),
"None".into(),
"self".into(),
"Kernel".into(),
"KernelImmutable".into()
]),
defined_class_method_name: Default::default(),
defined_class_name: Default::default(),
@ -825,9 +827,10 @@ impl TopLevelComposer {
};
let class_resolver = class_resolver.as_ref().unwrap();
let class_resolver = class_resolver.as_ref();
let mut defined_fields: HashSet<String> = HashSet::new();
for b in class_body_ast {
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
if let ast::StmtKind::FunctionDef { args, returns, name, .. } = &b.node {
let (method_dummy_ty, method_id) =
Self::get_class_method_def_info(class_methods_def, name)?;
@ -968,61 +971,54 @@ impl TopLevelComposer {
// NOTE: unify now since function type is not in type annotation define
// which is fine since type within method_type will be subst later
unifier.unify(method_dummy_ty, method_type)?;
} else if let ast::StmtKind::AnnAssign { target, annotation, value: None, .. } = &b.node {
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_fresh_var().0;
class_fields_def.push((attr.to_string(), dummy_field_type));
// class fields
if name == "__init__" {
for b in body {
let mut defined_fields: HashSet<String> = HashSet::new();
// TODO: check the type of value, field instantiation check?
if let ast::StmtKind::AnnAssign { annotation, target, value: _, .. } =
&b.node
{
if let ast::ExprKind::Attribute { value, attr, .. } = &target.node {
if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == "self")
{
if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_fresh_var().0;
class_fields_def.push((attr.to_string(), dummy_field_type));
// handle Kernel[T], KernelImmutable[T]
let annotation = {
match &annotation.as_ref().node {
ast::ExprKind::Subscript { value, slice, .. } if {
matches!(&value.node, ast::ExprKind::Name { id, .. } if id == "Kernel" || id == "KernelImmutable")
} => slice,
_ => annotation
}
};
let annotation = parse_ast_to_type_annotation_kinds(
class_resolver.as_ref(),
&temp_def_list,
unifier,
primitives,
annotation.as_ref(),
vec![(class_id, class_type_vars_def.clone())].into_iter().collect(),
)?;
// find type vars within this return type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&annotation);
// handle the class type var and the method type var
for type_var_within in type_vars_within {
if let TypeAnnotation::TypeVarKind(t) = type_var_within
{
if !class_type_vars_def.contains(&t) {
return Err("class fields can only use type \
vars declared as class generic type vars"
.into());
}
} else {
unreachable!("must be type var annotation");
}
}
// TODO: allow class have field which type refers to Self type?
type_var_to_concrete_def
.insert(dummy_field_type, annotation);
} else {
return Err("same class fields defined twice".into());
}
let annotation = parse_ast_to_type_annotation_kinds(
class_resolver.as_ref(),
&temp_def_list,
unifier,
primitives,
annotation.as_ref(),
vec![(class_id, class_type_vars_def.clone())].into_iter().collect(),
)?;
// find type vars within this return type annotation
let type_vars_within =
get_type_var_contained_in_type_annotation(&annotation);
// handle the class type var and the method type var
for type_var_within in type_vars_within {
if let TypeAnnotation::TypeVarKind(t) = type_var_within
{
if !class_type_vars_def.contains(&t) {
return Err("class fields can only use type \
vars declared as class generic type vars"
.into());
}
} else {
unreachable!("must be type var annotation");
}
}
type_var_to_concrete_def
.insert(dummy_field_type, annotation);
} else {
return Err("same class fields defined twice".into());
}
}
} else {
continue;
return Err("unsupported statement type in class definition body".into())
}
}
Ok(())

View File

@ -156,8 +156,9 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
vec![
indoc! {"
class A():
a: int32
def __init__(self):
self.a: int32 = 3
self.a = 3
def fun(self, b: B):
pass
def foo(self, a: T, b: V):
@ -273,15 +274,17 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
vec![
indoc! {"
class Generic_A(Generic[V], B):
a: int64
def __init__(self):
self.a: int64 = 123123123123
self.a = 123123123123
def fun(self, a: int32) -> V:
pass
"},
indoc! {"
class B:
aa: bool
def __init__(self):
self.aa: bool = False
self.aa = False
def foo(self, b: T):
pass
"}
@ -343,9 +346,11 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
"},
indoc! {"
class A(Generic[T, V]):
a: T
b: V
def __init__(self, v: V):
self.a: T = 1
self.b: V = v
self.a = 1
self.b = v
def fun(self, a: T) -> V:
pass
"},
@ -418,9 +423,11 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
vec![
indoc! {"
class A(Generic[T, V]):
a: A[float, bool]
b: B
def __init__(self, a: A[float, bool], b: B):
self.a: A[float, bool] = a
self.b: B = b
self.a = a
self.b = b
def fun(self, a: A[float, bool]) -> A[bool, int32]:
pass
"},
@ -578,7 +585,7 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
vec!["a class def can only have at most one base class declaration and one generic declaration"];
"err multiple inheritance"
)]
fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) {
fn test_analyze(source: Vec<&str>, res: Vec<&str>) {
let print = false;
let mut composer = TopLevelComposer::new();