def attributes_assigned_in_init_can_be_used_in_methods_when_init_method_is_defined_after_other_method(): init_func = nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign( [nodes.attr(nodes.ref("self_init"), "message")], nodes.str_literal("Hello"), type=nodes.ref("str"), ) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ) node = nodes.class_("User", [ nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[nodes.ret(nodes.attr(nodes.ref("self_g"), "message"))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("str") ), ), init_func, ]) _infer_class_type(node, ["__init__", "g"], [(init_func, ["self_init"])])
def method_can_call_method_on_same_instance_defined_later_in_body(): node = nodes.class_("User", [ nodes.func( name="f", args=nodes.args([nodes.arg("self_f")]), body=[ nodes.ret(nodes.call(nodes.attr(nodes.ref("self_f"), "g"), [])) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ), nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[ nodes.ret(nodes.call(nodes.attr(nodes.ref("self_g"), "f"), [])) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ) ]) _infer_class_type(node, ["f", "g"])
def init_method_cannot_call_other_methods(): node = nodes.class_("User", [ nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign([nodes.ref("x")], nodes.call(nodes.attr(nodes.ref("self_init"), "g"), [])) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ), nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ), ]) try: _infer_class_type(node, ["__init__", "g"]) assert False, "Expected error" except errors.InitMethodCannotGetSelfAttributes as error: assert_equal("__init__ methods cannot get attributes of self", str(error))
def can_parse_signature_with_multiple_args(): expected_signature = nodes.signature( args=[ nodes.signature_arg(nodes.ref("int")), nodes.signature_arg(nodes.ref("str")) ], returns=nodes.ref("str") ) assert_equal(expected_signature, parse_explicit_type("int, str -> str"))
def init_method_is_used_as_call_method_on_meta_type(): node = _create_class_with_init( signature=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self")), nodes.signature_arg(nodes.ref("str"))], returns=nodes.ref("none") ), args=nodes.args([nodes.arg("self"), nodes.arg("name")]), body=[], ) meta_type = _infer_meta_type(node, ["__init__"]) assert_equal(types.func([types.str_type], meta_type.type), meta_type.attrs.type_of("__call__"))
def can_parse_signature_with_function_type_as_argument(): sub_signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("str") ) expected_signature = nodes.signature( args=[ nodes.signature_arg(sub_signature) ], returns=nodes.ref("none") ) assert_equal(expected_signature, parse_explicit_type("(int -> str) -> none"))
def error_if_type_signature_has_different_number_of_args_from_def(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int")), nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("args length mismatch: def has 1, signature has 2", str(error))
def can_infer_type_of_function_with_args_and_no_return(): signature = nodes.signature( args=[ nodes.signature_arg(nodes.ref("int")), nodes.signature_arg(nodes.ref("str")), ], returns=nodes.ref("none"), ) args = nodes.arguments([ nodes.argument("x"), nodes.argument("y"), ]) node = nodes.func("f", args=args, body=[], type=signature) assert_equal(types.func([types.int_type, types.str_type], types.none_type), _infer_func_type(node))
def attributes_assigned_in_init_can_be_used_outside_of_class(): init_func = nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign( [nodes.attr(nodes.ref("self_init"), "message")], nodes.str_literal("Hello"), type=nodes.ref("str"), ) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ) ) class_node = nodes.class_("User", [init_func]) node = [ class_node, nodes.assign([nodes.ref("x")], nodes.attr(nodes.call(nodes.ref("User"), []), "message")), ] context = _update_context(node, declared_names_in_node=NodeDict([ (class_node, ["Self", "__init__"]), (init_func, ["self_init"]), ])) assert_equal(types.str_type, context.lookup_name("x"))
def can_parse_signature_comment_with_one_formal_type_parameter(): expected_signature = nodes.signature( type_params=[nodes.formal_type_parameter("T")], args=[nodes.signature_arg(nodes.ref("T"))], returns=nodes.ref("T") ) assert_equal(expected_signature, parse_explicit_type("T => T -> T"))
def type_parameters_of_function_are_definitely_bound(): param = nodes.formal_type_parameter("T") arg_ref = nodes.ref("T") returns_ref = nodes.ref("T") explicit_type = nodes.signature(type_params=[param], args=[nodes.signature_arg(arg_ref)], returns=returns_ref) func_node = nodes.func("f", nodes.arguments([]), [], type=explicit_type) _updated_bindings(func_node)
def function_adds_arguments_to_context(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) assert_equal(types.func([types.int_type], types.int_type), _infer_func_type(node))
def init_method_is_not_present_on_instance(): node = _create_class_with_init( signature=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), args=nodes.args([nodes.arg("self")]), body=[], ) meta_type = _infer_meta_type(node, ["__init__"]) assert not "__init__" in meta_type.type.attrs
def type_of_function_signature_is_metatype_of_function(): type_bindings = { "str": types.meta_type(types.str_type), "int": types.meta_type(types.int_type), } node = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("str") ) inferred_type = infer(node, type_bindings=type_bindings) assert types.is_meta_type(inferred_type) assert_equal(types.func([types.int_type], types.str_type), inferred_type.type)
def error_if_name_of_argument_does_not_match_name_in_signature(): signature = nodes.signature( args=[nodes.signature_arg("y", nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("argument 'x' has name 'y' in signature", str(error))
def can_type_check_generic_function_with_type_parameters(): signature = nodes.signature( type_params=[nodes.formal_type_parameter("T")], args=[ nodes.signature_arg(nodes.ref("T")), ], returns=nodes.ref("T"), ) args = nodes.arguments([ nodes.argument("value"), ]) node = nodes.func("f", args=args, body=[nodes.ret(nodes.ref("value"))], type=signature) assert_equal(types.func([types.int_type], types.int_type), _infer_func_type(node).instantiate([types.int_type]))
def error_if_type_signature_argument_is_optional_but_def_argument_is_not_optional(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"), optional=True)], returns=nodes.type_union([nodes.ref("int"), nodes.ref("none")]) ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("optional argument 'x' must have default value", str(error))
def type_of_generic_function_signature_is_metatype_of_function(): node = nodes.signature( type_params=[nodes.formal_type_parameter("T")], args=[nodes.signature_arg(nodes.ref("T"))], returns=nodes.ref("T") ) inferred_type = infer(node) assert types.is_meta_type(inferred_type) assert types.is_generic_func(inferred_type.type) formal_type_param, = inferred_type.type.formal_type_params assert_equal( types.func([formal_type_param], formal_type_param), inferred_type.type.instantiate([formal_type_param]), )
def first_argument_in_method_signature_can_be_strict_supertype_of_class(): node = nodes.class_("User", [ nodes.func( name="is_person", args=nodes.args([nodes.arg("self")]), body=[nodes.ret(nodes.bool_literal(True))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("object"))], returns=nodes.ref("bool") ), ) ]) class_type = _infer_class_type(node, ["is_person"]) assert_equal(types.func([], types.bool_type), class_type.attrs.type_of("is_person"))
def init_method_must_return_none(): node = _create_class_with_init( signature=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("str") ), args=nodes.args([nodes.arg("self")]), body=[nodes.ret(nodes.str_literal(""))], ) try: _infer_meta_type(node, ["__init__"]) assert False, "Expected error" except errors.InitMethodsMustReturnNoneError as error: assert_equal(node.body[0], error.node)
def attributes_with_function_type_defined_in_class_definition_body_are_bound_to_class_type(): node = nodes.class_("User", [ nodes.func( name="is_person", args=nodes.args([nodes.arg("self")]), body=[nodes.ret(nodes.bool_literal(True))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("bool") ), ), ]) class_type = _infer_class_type(node, ["is_person"]) assert_equal(types.func([], types.bool_type), class_type.attrs.type_of("is_person"))
def argument_type_in_signature_is_unioned_with_none_if_argument_is_optional(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x", optional=True)]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.UnexpectedValueTypeError as error: assert_equal(types.int_type, error.expected) assert_equal(types.union(types.int_type, types.none_type), error.actual)
def function_definition_signature_has_names_resolved(): int_ref = nodes.ref("int") str_ref = nodes.ref("str") signature = nodes.signature( args=[nodes.signature_arg(int_ref)], returns=str_ref, ) node = nodes.func("f", nodes.arguments([]), [], type=signature) declarations = _create_declarations(["f", "int", "str"]) references = resolve(node, declarations) assert_is(declarations.declaration("int"), references.referenced_declaration(int_ref)) assert_is(declarations.declaration("str"), references.referenced_declaration(str_ref))
def can_infer_type_of_function_with_optional_arg(): signature = nodes.signature( args=[ nodes.signature_arg(nodes.ref("int"), optional=True), ], returns=nodes.ref("none") ) args = nodes.arguments([ nodes.argument("x", optional=True), ]) node = nodes.func("f", args=args, body=[], type=signature) assert_equal( types.func([types.func_arg(None, types.int_type, optional=True)], types.none_type), _infer_func_type(node) )
def can_infer_type_of_function_with_named_arg(): signature = nodes.signature( args=[ nodes.signature_arg("message", nodes.ref("int")), ], returns=nodes.ref("none") ) args = nodes.arguments([ nodes.argument("message"), ]) node = nodes.func("f", args=args, body=[], type=signature) assert_equal( types.func([types.func_arg("message", types.int_type)], types.none_type), _infer_func_type(node) )
def generic_function_definition_signature_has_names_resolved(): param = nodes.formal_type_parameter("T") arg_ref = nodes.ref("T") return_ref = nodes.ref("T") signature = nodes.signature( type_params=[param], args=[nodes.signature_arg(arg_ref)], returns=return_ref, ) node = nodes.func("f", nodes.arguments([]), [], type=signature) declarations = _create_declarations(["f"]) references = resolve(node, declarations) assert not declarations.is_declared("T") assert_is(references.referenced_declaration(param), references.referenced_declaration(arg_ref)) assert_is(references.referenced_declaration(param), references.referenced_declaration(return_ref))
def self_argument_in_method_signature_cannot_be_unrelated_type(): func_node = nodes.func( name="is_person", args=nodes.args([nodes.arg("self")]), body=[nodes.ret(nodes.bool_literal(True))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("bool"))], returns=nodes.ref("bool") ), ) node = nodes.class_("User", [func_node]) try: _infer_class_type(node, ["is_person"]) assert False, "Expected error" except errors.UnexpectedReceiverTypeError as error: assert_equal(func_node, error.node) assert_equal(types.bool_type, error.receiver_type) assert_equal("first argument of methods should have Self type but was 'bool'", str(error))
def _infer_meta_type(class_node, names, names_in_nodes=None, type_bindings=None): if type_bindings is None: type_bindings = {} else: type_bindings = type_bindings.copy() if names_in_nodes is None: names_in_nodes = [] type_bindings["bool"] = types.meta_type(types.bool_type) type_bindings["object"] = types.meta_type(types.object_type) type_bindings["none"] = types.meta_type(types.none_type) type_bindings["str"] = types.meta_type(types.str_type) context = update_context( class_node, declared_names_in_node=NodeDict(names_in_nodes + [(class_node, names + ["Self"])]), type_bindings=type_bindings, ) meta_type = context.lookup(class_node) assert isinstance(meta_type, types.MetaType) assert types.is_class_type(meta_type.type) or types.is_generic_type(meta_type.type) return meta_type def _infer_class_type(class_node, names, names_in_nodes=None, type_bindings=None): return _infer_meta_type(class_node, names, names_in_nodes, type_bindings=type_bindings).type _no_arg_init_signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") )
def can_parse_signature_with_named_arg(): expected_signature = nodes.signature( args=[nodes.signature_arg("x", nodes.ref("int"))], returns=nodes.ref("str"), ) assert_equal(expected_signature, parse_explicit_type("x: int -> str"))
def can_parse_signature_with_optional_arg(): expected_signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"), optional=True)], returns=nodes.ref("str") ) assert_equal(expected_signature, parse_explicit_type("?int -> str"))