From 5a1a8ecee3d86c2c3db5345f4021797dc494b948 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Wed, 8 Sep 2021 21:53:54 +0800 Subject: [PATCH] nac3core: self is not not allowed to explicitly appear in method type annotations --- nac3core/src/toplevel/mod.rs | 195 +++++++++++++--------------------- nac3core/src/toplevel/test.rs | 170 ++++++++++++++++++++--------- 2 files changed, 190 insertions(+), 175 deletions(-) diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs index 9b26f2ed..d5e70582 100644 --- a/nac3core/src/toplevel/mod.rs +++ b/nac3core/src/toplevel/mod.rs @@ -135,6 +135,7 @@ impl TopLevelComposer { "bool".into(), "none".into(), "None".into(), + "self".into(), ]), defined_class_method_name: Default::default(), defined_class_name: Default::default(), @@ -586,11 +587,9 @@ impl TopLevelComposer { } } - // println!("type_var_to_concrete_def2: {:?}", type_var_to_concrete_def); - - // unification of previously assigned typevar println!("type_var_to_concrete_def3: {:?}\n", type_var_to_concrete_def); - let mut ddddd: Vec<(Type, Type)> = Vec::new(); + + // unification of previously assigned typevar for (ty, def) in type_var_to_concrete_def { println!( "{:?}_{} -> {:?}\n", @@ -604,23 +603,6 @@ impl TopLevelComposer { let target_ty = get_type_from_type_annotation_kinds(&temp_def_list, unifier, primitives, &def)?; unifier.unify(ty, target_ty)?; - ddddd.push((ty, target_ty)); - } - - for (ty, tar_ty) in ddddd { - println!( - "{:?}_{} -> {:?}_{}", - ty, - unifier.stringify(ty, - &mut |id| format!("class{}", id), - &mut |id| format!("tvar{}", id) - ), - tar_ty, - unifier.stringify(tar_ty, - &mut |id| format!("class{}", id), - &mut |id| format!("tvar{}", id) - ), - ) } Ok(()) @@ -793,7 +775,7 @@ impl TopLevelComposer { ) -> Result<(), String> { let mut class_def = class_def.write(); let ( - class_id, + _class_id, _class_name, _class_bases_ast, class_body_ast, @@ -862,126 +844,90 @@ impl TopLevelComposer { and names thould not be the same as the keywords" .into()); } - if name == "__init__" && !defined_paramter_name.contains("self") { - return Err( - "class __init__ function must contain the `self` parameter".into() - ); - } let mut result = Vec::new(); for x in &args.args { let name = x.node.arg.clone(); - if name != "self" { - let type_ann = { - let annotation_expr = x - .node - .annotation - .as_ref() - .ok_or_else(|| "type annotation needed".to_string())? - .as_ref(); - parse_ast_to_type_annotation_kinds( - class_resolver.as_ref(), - temp_def_list, - unifier, - primitives, - annotation_expr, - )? - }; - - // find type vars within this method parameter type annotation - let type_vars_within = - get_type_var_contained_in_type_annotation(&type_ann); - // handle the class type var and the method type var - for type_var_within in type_vars_within { - if let TypeAnnotation::TypeVarKind(ty) = type_var_within { - let id = Self::get_var_id(ty, unifier)?; - if let Some(prev_ty) = method_var_map.insert(id, ty) { - // if already in the list, make sure they are the same? - assert_eq!(prev_ty, ty); - } - } else { - unreachable!("must be type var annotation"); + let type_ann = { + let annotation_expr = x + .node + .annotation + .as_ref() + .ok_or_else(|| "type annotation needed".to_string())? + .as_ref(); + parse_ast_to_type_annotation_kinds( + class_resolver.as_ref(), + temp_def_list, + unifier, + primitives, + annotation_expr, + )? + }; + // find type vars within this method parameter type annotation + let type_vars_within = + get_type_var_contained_in_type_annotation(&type_ann); + // handle the class type var and the method type var + for type_var_within in type_vars_within { + if let TypeAnnotation::TypeVarKind(ty) = type_var_within { + let id = Self::get_var_id(ty, unifier)?; + if let Some(prev_ty) = method_var_map.insert(id, ty) { + // if already in the list, make sure they are the same? + assert_eq!(prev_ty, ty); } + } else { + unreachable!("must be type var annotation"); } - - // finish handling type vars - let dummy_func_arg = FuncArg { - name, - ty: unifier.get_fresh_var().0, - // TODO: symbol default value? - default_value: None, - }; - // push the dummy type and the type annotation - // into the list for later unification - type_var_to_concrete_def.insert(dummy_func_arg.ty, type_ann.clone()); - result.push(dummy_func_arg) - } else { - // if the parameter name is self - // python does not seem to enforce the name - // representing the self class object to be - // `self`??, but we do it here - let dummy_func_arg = FuncArg { - name: "self".into(), - ty: unifier.get_fresh_var().0, - default_value: None, - }; - type_var_to_concrete_def.insert( - dummy_func_arg.ty, - make_self_type_annotation(class_type_vars_def.as_slice(), class_id), - ); - result.push(dummy_func_arg); } + // finish handling type vars + let dummy_func_arg = FuncArg { + name, + ty: unifier.get_fresh_var().0, + // TODO: symbol default value? + default_value: None, + }; + // push the dummy type and the type annotation + // into the list for later unification + type_var_to_concrete_def.insert(dummy_func_arg.ty, type_ann.clone()); + result.push(dummy_func_arg) } result }; let ret_type = { - if name != "__init__" { - if let Some(result) = returns { - let result = result.as_ref(); - let annotation = parse_ast_to_type_annotation_kinds( - class_resolver.as_ref(), - temp_def_list, - unifier, - primitives, - result, - )?; - - // 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(ty) = type_var_within { - let id = Self::get_var_id(ty, unifier)?; - if let Some(prev_ty) = method_var_map.insert(id, ty) { - // if already in the list, make sure they are the same? - assert_eq!(prev_ty, ty); - } - } else { - unreachable!("must be type var annotation"); + if let Some(result) = returns { + let result = result.as_ref(); + let annotation = parse_ast_to_type_annotation_kinds( + class_resolver.as_ref(), + temp_def_list, + unifier, + primitives, + result, + )?; + // 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(ty) = type_var_within { + let id = Self::get_var_id(ty, unifier)?; + if let Some(prev_ty) = method_var_map.insert(id, ty) { + // if already in the list, make sure they are the same? + assert_eq!(prev_ty, ty); } + } else { + unreachable!("must be type var annotation"); } - - let dummy_return_type = unifier.get_fresh_var().0; - type_var_to_concrete_def.insert(dummy_return_type, annotation.clone()); - dummy_return_type - } else { - // if do not have return annotation, return none - // for uniform handling, still use type annoatation - let dummy_return_type = unifier.get_fresh_var().0; - type_var_to_concrete_def.insert( - dummy_return_type, - TypeAnnotation::PrimitiveKind(primitives.none), - ); - dummy_return_type } + let dummy_return_type = unifier.get_fresh_var().0; + type_var_to_concrete_def.insert(dummy_return_type, annotation.clone()); + dummy_return_type } else { - // if is the "__init__" function, the return type is self + // if do not have return annotation, return none + // for uniform handling, still use type annoatation let dummy_return_type = unifier.get_fresh_var().0; type_var_to_concrete_def.insert( dummy_return_type, - make_self_type_annotation(class_type_vars_def.as_slice(), class_id), + TypeAnnotation::PrimitiveKind(primitives.none), ); dummy_return_type } @@ -1041,7 +987,8 @@ impl TopLevelComposer { 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 { diff --git a/nac3core/src/toplevel/test.rs b/nac3core/src/toplevel/test.rs index e4196bbe..5de44838 100644 --- a/nac3core/src/toplevel/test.rs +++ b/nac3core/src/toplevel/test.rs @@ -156,23 +156,23 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s vec![ indoc! {" class A(): - def __init__(self): + def __init__(): self.a: int32 = 3 - def fun(self, b: B): + def fun(b: B): pass - def foo(self, a: T, b: V): + def foo(a: T, b: V): pass "}, indoc! {" class B(C): - def __init__(self): + def __init__(): pass "}, indoc! {" class C(A): - def __init__(self): + def __init__(): pass - def fun(self, b: B): + def fun(b: B): a = 1 pass "}, @@ -190,82 +190,149 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s name: \"A\", def_id: DefinitionId(5), ancestors: [CustomClassKind { id: DefinitionId(5), params: [] }], - fields: [(\"a\", \"0\")], - methods: [(\"__init__\", \"fn[[self=5], 5]\", DefinitionId(6)), (\"fun\", \"fn[[self=5, b=9], 4]\", DefinitionId(7))], + fields: [(\"a\", \"class0\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(6)), (\"fun\", \"fn[[b=class10], class4]\", DefinitionId(7)), (\"foo\", \"fn[[a=tvar2, b=tvar3], class4]\", DefinitionId(8))], type_vars: [] }"}, indoc! {"6: Function { name: \"A__init__\", - sig: \"fn[[self=5], 5]\", + sig: \"fn[[], class4]\", var_id: [] }"}, indoc! {"7: Function { name: \"Afun\", - sig: \"fn[[self=5, b=9], 4]\", + sig: \"fn[[b=class10], class4]\", var_id: [] }"}, - indoc! {"8: Initializer { DefinitionId(5) }"}, + indoc! {"8: Function { + name: \"Afoo\", + sig: \"fn[[a=tvar2, b=tvar3], class4]\", + var_id: [2, 3] + }"}, - indoc! {"9: Class { + indoc! {"9: Initializer { DefinitionId(5) }"}, + + indoc! {"10: Class { name: \"B\", - def_id: DefinitionId(9), - ancestors: [CustomClassKind { id: DefinitionId(9), params: [] }, CustomClassKind { id: DefinitionId(12), params: [] }, CustomClassKind { id: DefinitionId(5), params: [] }], - fields: [(\"a\", \"0\")], - methods: [(\"__init__\", \"fn[[self=9], 9]\", DefinitionId(10)), (\"fun\", \"fn[[self=12, b=9], 4]\", DefinitionId(14))], + def_id: DefinitionId(10), + ancestors: [CustomClassKind { id: DefinitionId(10), params: [] }, CustomClassKind { id: DefinitionId(13), params: [] }, CustomClassKind { id: DefinitionId(5), params: [] }], + fields: [(\"a\", \"class0\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(11)), (\"fun\", \"fn[[b=class10], class4]\", DefinitionId(15)), (\"foo\", \"fn[[a=tvar2, b=tvar3], class4]\", DefinitionId(8))], type_vars: [] }"}, - indoc! {"10: Function { + indoc! {"11: Function { name: \"B__init__\", - sig: \"fn[[self=9], 9]\", + sig: \"fn[[], class4]\", var_id: [] }"}, - indoc! {"11: Initializer { DefinitionId(9) }"}, + indoc! {"12: Initializer { DefinitionId(10) }"}, - indoc! {"12: Class { + indoc! {"13: Class { name: \"C\", - def_id: DefinitionId(12), - ancestors: [CustomClassKind { id: DefinitionId(12), params: [] }, CustomClassKind { id: DefinitionId(5), params: [] }], - fields: [(\"a\", \"0\")], - methods: [(\"__init__\", \"fn[[self=12], 12]\", DefinitionId(13)), (\"fun\", \"fn[[self=12, b=9], 4]\", DefinitionId(14))], + def_id: DefinitionId(13), + ancestors: [CustomClassKind { id: DefinitionId(13), params: [] }, CustomClassKind { id: DefinitionId(5), params: [] }], + fields: [(\"a\", \"class0\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(14)), (\"fun\", \"fn[[b=class10], class4]\", DefinitionId(15)), (\"foo\", \"fn[[a=tvar2, b=tvar3], class4]\", DefinitionId(8))], type_vars: [] }"}, - indoc! {"13: Function { - name: \"C__init__\", - sig: \"fn[[self=12], 12]\", - var_id: [] - }"}, - indoc! {"14: Function { - name: \"Cfun\", - sig: \"fn[[self=12, b=9], 4]\", + name: \"C__init__\", + sig: \"fn[[], class4]\", var_id: [] }"}, - indoc! {"15: Initializer { DefinitionId(12) }"}, - - indoc! {"16: Function { - name: \"foo\", - sig: \"fn[[a=5], 4]\", + indoc! {"15: Function { + name: \"Cfun\", + sig: \"fn[[b=class10], class4]\", var_id: [] }"}, + + indoc! {"16: Initializer { DefinitionId(13) }"}, + + indoc! {"17: Function { + name: \"foo\", + sig: \"fn[[a=class5], class4]\", + var_id: [] + }"}, + + indoc! {"18: Function { + name: \"ff\", + sig: \"fn[[a=tvar2], tvar3]\", + var_id: [2, 3] + }"}, ]; "simple class compose" )] #[test_case( vec![ indoc! {" - class Generic_A(Generic[T, V]): + class Generic_A(Generic[V], B): def __init__(): + self.a: int64 = 123123123123 + def fun(a: int32) -> V: + pass + "}, + indoc! {" + class B: + def __init__(): + self.aa: bool = False + def foo(b: T): pass "} ], - vec![]; + vec![ + indoc! {"5: Class { + name: \"Generic_A\", + def_id: DefinitionId(5), + ancestors: [CustomClassKind { id: DefinitionId(5), params: [TypeVarKind(UnificationKey(101))] }, CustomClassKind { id: DefinitionId(9), params: [] }], + fields: [(\"aa\", \"class3\"), (\"a\", \"class1\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(6)), (\"foo\", \"fn[[b=tvar2], class4]\", DefinitionId(11)), (\"fun\", \"fn[[a=class0], tvar3]\", DefinitionId(7))], + type_vars: [UnificationKey(101)] + }"}, + + indoc! {"6: Function { + name: \"Generic_A__init__\", + sig: \"fn[[], class4]\", + var_id: [3] + }"}, + + indoc! {"7: Function { + name: \"Generic_Afun\", + sig: \"fn[[a=class0], tvar3]\", + var_id: [3] + }"}, + + indoc! {"8: Initializer { DefinitionId(5) }"}, + + indoc! {"9: Class { + name: \"B\", + def_id: DefinitionId(9), + ancestors: [CustomClassKind { id: DefinitionId(9), params: [] }], + fields: [(\"aa\", \"class3\")], + methods: [(\"__init__\", \"fn[[], class4]\", DefinitionId(10)), (\"foo\", \"fn[[b=tvar2], class4]\", DefinitionId(11))], + type_vars: [] + }"}, + + indoc! {"10: Function { + name: \"B__init__\", + sig: \"fn[[], class4]\", + var_id: [] + }"}, + + indoc! {"11: Function { + name: \"Bfoo\", + sig: \"fn[[b=tvar2], class4]\", + var_id: [2] + }"}, + + indoc! {"12: Initializer { DefinitionId(9) }"}, + ]; "generic class" )] fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) { @@ -275,6 +342,7 @@ fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) { let tvar_v = composer .unifier .get_fresh_var_with_range(&[composer.primitives_ty.bool, composer.primitives_ty.int32]); + println!("t: {}, {:?}", tvar_t.1, tvar_t.0); println!("v: {}, {:?}\n", tvar_v.1, tvar_v.0); @@ -311,17 +379,17 @@ fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) { // &mut |id| format!("tvar{}", id) // ) // ); - // assert_eq!( - // format!( - // "{}: {}", - // i + 5, - // def.to_string( - // composer.unifier.borrow_mut(), - // &mut |id| id.to_string(), - // &mut |id| id.to_string() - // ) - // ), - // res[i] - // ) + assert_eq!( + format!( + "{}: {}", + i + 5, + def.to_string( + composer.unifier.borrow_mut(), + &mut |id| format!("class{}", id.to_string()), + &mut |id| format!("tvar{}", id.to_string()), + ) + ), + res[i] + ) } }