forked from M-Labs/nac3
nac3core: top level fields inheritance check, more tests
This commit is contained in:
parent
147298ff40
commit
b419634f8a
|
@ -1114,25 +1114,26 @@ impl TopLevelComposer {
|
|||
|
||||
// handle class fields
|
||||
let mut new_child_fields: Vec<(String, Type)> = Vec::new();
|
||||
let mut is_override: HashSet<String> = HashSet::new();
|
||||
// let mut is_override: HashSet<String> = 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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue