From b419634f8a0bcb74a854d7e25086432b7ddfd35a Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sun, 12 Sep 2021 04:34:30 +0800 Subject: [PATCH] nac3core: top level fields inheritance check, more tests --- nac3core/src/toplevel/mod.rs | 33 ++++---- nac3core/src/toplevel/test.rs | 154 ++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 16 deletions(-) diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs index 286e0eed4..83a51f24c 100644 --- a/nac3core/src/toplevel/mod.rs +++ b/nac3core/src/toplevel/mod.rs @@ -1114,25 +1114,26 @@ impl TopLevelComposer { // handle class fields let mut new_child_fields: Vec<(String, Type)> = Vec::new(); - let mut is_override: HashSet = HashSet::new(); + // let mut is_override: HashSet = HashSet::new(); for (anc_field_name, anc_field_ty) in fields { - let mut to_be_added = (anc_field_name.to_string(), *anc_field_ty); + let to_be_added = (anc_field_name.to_string(), *anc_field_ty); // find if there is a fields with the same name in the child class - for (class_field_name, class_field_ty) in class_fields_def.iter() { + for (class_field_name, ..) in class_fields_def.iter() { if class_field_name == anc_field_name { - let ok = Self::check_overload_field_type( - *class_field_ty, - *anc_field_ty, - unifier, - type_var_to_concrete_def, - ); - if !ok { - return Err("fields has same name as ancestors' field, but incompatible type".into()); - } - // mark it as added - is_override.insert(class_field_name.to_string()); - to_be_added = (class_field_name.to_string(), *class_field_ty); - break; + // let ok = Self::check_overload_field_type( + // *class_field_ty, + // *anc_field_ty, + // unifier, + // type_var_to_concrete_def, + // ); + // if !ok { + // return Err("fields has same name as ancestors' field, but incompatible type".into()); + // } + // // mark it as added + // is_override.insert(class_field_name.to_string()); + // to_be_added = (class_field_name.to_string(), *class_field_ty); + // break; + return Err(format!("field `{}` has already declared in the ancestor classes", class_field_name)) } } new_child_fields.push(to_be_added); diff --git a/nac3core/src/toplevel/test.rs b/nac3core/src/toplevel/test.rs index 973888855..a1ac65bc4 100644 --- a/nac3core/src/toplevel/test.rs +++ b/nac3core/src/toplevel/test.rs @@ -496,6 +496,109 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s ]; "self1" )] +#[test_case( + vec![ + indoc! {" + class A(Generic[T]): + a: int32 + b: T + c: A[int64] + def __init__(self, t: T): + self.a = 3 + self.b = T + def fun(self, a: int32, b: T) -> list[virtual[B[bool]]]: + pass + def foo(self, c: C): + pass + "}, + indoc! {" + class B(Generic[V], A[float]): + d: C + def __init__(self): + pass + def fun(self, a: int32, b: T) -> list[virtual[B[bool]]]: + # override + pass + "}, + indoc! {" + class C(B[bool]): + e: int64 + def __init__(self): + pass + "} + ], + vec![ + indoc! {"5: Class { + name: \"A\", + def_id: DefinitionId(5), + ancestors: [CustomClassKind { id: DefinitionId(5), params: [TypeVarKind(UnificationKey(100))] }], + fields: [(\"a\", \"class0\"), (\"b\", \"tvar2\"), (\"c\", \"class5[2->class1]\")], + methods: [(\"__init__\", \"fn[[t=tvar2], class4]\", DefinitionId(6)), (\"fun\", \"fn[[a=class0, b=tvar2], list[virtual[class10[3->class3]]]]\", DefinitionId(7)), (\"foo\", \"fn[[c=class14], class4]\", DefinitionId(8))], + type_vars: [UnificationKey(100)] + }"}, + + indoc! {"6: Function { + name: \"A__init__\", + sig: \"fn[[t=tvar2], class4]\", + var_id: [2] + }"}, + + indoc! {"7: Function { + name: \"Afun\", + sig: \"fn[[a=class0, b=tvar2], list[virtual[class10[3->class3]]]]\", + var_id: [2] + }"}, + + indoc! {"8: Function { + name: \"Afoo\", + sig: \"fn[[c=class14], class4]\", + var_id: [2] + }"}, + + indoc! {"9: Initializer { DefinitionId(5) }"}, + + indoc! {"10: Class { + name: \"B\", + def_id: DefinitionId(10), + ancestors: [CustomClassKind { id: DefinitionId(10), params: [TypeVarKind(UnificationKey(101))] }, CustomClassKind { id: DefinitionId(5), params: [PrimitiveKind(UnificationKey(2))] }], + fields: [(\"a\", \"class0\"), (\"b\", \"tvar2\"), (\"c\", \"class5[2->class1]\"), (\"d\", \"class14\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(11)), (\"fun\", \"fn[[a=class0, b=tvar2], list[virtual[class10[3->class3]]]]\", DefinitionId(12)), (\"foo\", \"fn[[c=class14], class4]\", DefinitionId(8))], + type_vars: [UnificationKey(101)] + }"}, + + indoc! {"11: Function { + name: \"B__init__\", + sig: \"fn[[], class4]\", + var_id: [3] + }"}, + + indoc! {"12: Function { + name: \"Bfun\", + sig: \"fn[[a=class0, b=tvar2], list[virtual[class10[3->class3]]]]\", + var_id: [2, 3] + }"}, + + indoc! {"13: Initializer { DefinitionId(10) }"}, + + indoc! {"14: Class { + name: \"C\", + def_id: DefinitionId(14), + ancestors: [CustomClassKind { id: DefinitionId(14), params: [] }, CustomClassKind { id: DefinitionId(10), params: [PrimitiveKind(UnificationKey(3))] }, CustomClassKind { id: DefinitionId(5), params: [PrimitiveKind(UnificationKey(2))] }], + fields: [(\"a\", \"class0\"), (\"b\", \"tvar2\"), (\"c\", \"class5[2->class1]\"), (\"d\", \"class14\"), (\"e\", \"class1\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(15)), (\"fun\", \"fn[[a=class0, b=tvar2], list[virtual[class10[3->class3]]]]\", DefinitionId(12)), (\"foo\", \"fn[[c=class14], class4]\", DefinitionId(8))], + type_vars: [] + }"}, + + indoc! {"15: Function { + name: \"C__init__\", + sig: \"fn[[], class4]\", + var_id: [] + }"}, + + indoc! {"16: Initializer { DefinitionId(14) }"}, + ]; + "inheritance_override" +)] #[test_case( vec![ indoc! {" @@ -585,6 +688,57 @@ 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" )] +#[test_case( + vec![ + indoc! {" + class A(Generic[T]): + a: int32 + b: T + c: A[int64] + def __init__(self, t: T): + self.a = 3 + self.b = T + def fun(self, a: int32, b: T) -> list[virtual[B[bool]]]: + pass + "}, + indoc! {" + class B(Generic[V], A[float]): + def __init__(self): + pass + def fun(self, a: int32, b: T) -> list[virtual[B[int32]]]: + # override + pass + "} + ], + vec!["method has same name as ancestors' method, but incompatible type"]; + "err_incompatible_inheritance_method" +)] +#[test_case( + vec![ + indoc! {" + class A(Generic[T]): + a: int32 + b: T + c: A[int64] + def __init__(self, t: T): + self.a = 3 + self.b = T + def fun(self, a: int32, b: T) -> list[virtual[B[bool]]]: + pass + "}, + indoc! {" + class B(Generic[V], A[float]): + a: int32 + def __init__(self): + pass + def fun(self, a: int32, b: T) -> list[virtual[B[bool]]]: + # override + pass + "} + ], + vec!["field `a` has already declared in the ancestor classes"]; + "err_incompatible_inheritance_field" +)] fn test_analyze(source: Vec<&str>, res: Vec<&str>) { let print = false; let mut composer = TopLevelComposer::new();