def function_definitions_in_statement_lists_can_be_defined_out_of_order(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) _updated_bindings(nodes.module([f, g]))
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 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 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 function_definitions_in_statement_lists_can_be_mutually_recursive(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("f"), [])) ]) _update_context([f, g])
def function_definitions_can_be_mutually_recursive(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("f"), [])) ]) _updated_bindings(nodes.module([f, g]))
def method_can_reference_later_function_if_class_is_not_used_in_the_interim(): g_ref = nodes.ref("g") f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(g_ref, [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) _updated_bindings(nodes.module([ nodes.class_("a", [f]), g, ]))
def names_in_function_are_not_declared_in_outer_scope(): node = nodes.func("f", nodes.arguments([]), [ nodes.assign([nodes.ref("x")], nodes.none()) ], type=None) declarations = find_declarations(node) assert not declarations.is_declared("x")
def exception_handler_targets_cannot_be_accessed_from_nested_function(): target_node = nodes.ref("error") ref_node = nodes.ref("error") body = [nodes.ret(ref_node)] func_node = nodes.func("f", nodes.arguments([]), body, type=None) try_node = nodes.try_( [], handlers=[ nodes.except_(nodes.none(), target_node, [func_node]) ], ) declaration = name_declaration.ExceptionHandlerTargetNode("error") references = References([ (target_node, declaration), (ref_node, declaration), (func_node, name_declaration.VariableDeclarationNode("f")), ]) try: _updated_bindings(try_node, references=references) assert False, "Expected error" except errors.UnboundLocalError as error: assert_equal(ref_node, error.node) assert_is("error", error.name)
def class_cannot_be_referenced_if_method_dependencies_are_not_bound(): g_ref = nodes.ref("g") f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(g_ref, [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) try: _updated_bindings(nodes.module([ nodes.class_("a", [f]), nodes.expression_statement(nodes.ref("a")), g, ])) assert False, "Expected error" except errors.UnboundLocalError as error: assert_equal(g_ref, error.node)
def can_infer_type_of_function_with_explicit_signature_of_aliased_function_type(): args = nodes.arguments([]) node = nodes.func("f", args=args, body=[], type=nodes.ref("Action")) type_bindings = { "Action": types.meta_type(types.func([], types.none_type)) } assert_equal(types.func([], types.none_type), _infer_func_type(node, type_bindings))
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 function_cannot_be_referenced_before_definition_of_dependencies(): g_ref = nodes.ref("g") f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(g_ref, [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) try: _updated_bindings(nodes.module([ f, nodes.expression_statement(nodes.ref("f")), g, ])) assert False, "Expected error" except errors.UnboundLocalError as error: assert_equal(g_ref, error.node)
def declarations_in_function_include_declarations_in_body(): node = nodes.func("f", nodes.arguments([]), [ nodes.assign([nodes.ref("x")], nodes.none()) ], type=None) declarations = _declarations_in(node) assert isinstance(declarations.declaration("x"), name_declaration.VariableDeclarationNode) assert not declarations.is_declared("f")
def break_is_not_valid_in_function_in_while_loop_body(): break_node = nodes.break_() func_node = nodes.func("f", nodes.args([]), [break_node], type=None) node = nodes.while_(nodes.bool_literal(True), [func_node], []) error = assert_raises(errors.TypeCheckError, lambda: check_loop_control(node, False)) assert_equal(break_node, error.node) assert_equal("'break' outside loop", str(error))
def function_definitions_in_statement_lists_are_type_checked_even_if_not_invoked(): node = nodes.func("f", type=None, args=nodes.Arguments([]), body=[nodes.ret(nodes.int_literal(42))]) try: _update_context([node]) assert False, "Expected error" except errors.UnexpectedValueTypeError as error: assert_equal(types.int_type, error.actual) assert_equal(types.none_type, error.expected)
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 test_function_definitions_in_body_are_stored_as_methods(self): _assert_transform( nodes.class_("Blah", [nodes.func("f", nodes.args([]), [], type=None)]), cc.class_( "Blah", methods=[cc.func("f", [], [cc.ret(cc.none)])], body=[cc.declare("f")], ), )
def _create_class_with_init(signature, args, body): return nodes.class_("User", [ nodes.func( name="__init__", args=args, body=body, type=signature ) ])
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 function_can_have_no_signature_if_it_takes_no_args(): source = """ def f(): pass """ module_node = parser.parse(source) expected = nodes.func("f", nodes.args([]), [], type=None) assert_equal(expected, module_node.body[0])
def error_if_type_signature_is_missing_from_function_with_args(): args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=None) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("signature is missing from function definition", str(error))
def type_mismatch_if_return_type_is_incorrect(): return_node = nodes.ret(nodes.str_literal("!")) node = nodes.func( "f", args=nodes.arguments([]), body=[return_node], type=nodes.signature(returns=nodes.ref("int")), ) assert_type_mismatch(lambda: _infer_func_type(node), expected=types.int_type, actual=types.str_type, node=return_node)
def values_can_have_same_name_as_child_module_if_they_are_not_in_module_scope(): value_node = nodes.assign([nodes.ref("x")], nodes.int_literal(1)) node = nodes.module([ nodes.func("f", nodes.args([]), [value_node], type=None) ], is_executable=False) _check_module(LocalModule("root/__init__.py", node), { (".", "x"): module({}), })
def function_definitions_assignments_shadow_variables_of_same_name_in_outer_scope(): args = nodes.arguments([]) ref = nodes.ref("x") body = [nodes.assign([ref], nodes.none())] node = nodes.func("f", args, body, type=None) declarations = _create_declarations(["x", "f"]) references = resolve(node, declarations) assert_is_not(declarations.declaration("x"), references.referenced_declaration(ref))
def function_definitions_bodies_can_access_variables_from_outer_scope(): args = nodes.arguments([]) ref = nodes.ref("x") body = [nodes.ret(ref)] node = nodes.func("f", args, body, type=None) declarations = _create_declarations(["x", "f"]) references = resolve(node, declarations) assert_is(declarations.declaration("x"), references.referenced_declaration(ref))
def can_infer_type_of_function_with_no_args_and_return_annotation(): node = nodes.func( "f", args=nodes.arguments([]), body=[ nodes.ret(nodes.int_literal(4)) ], type=nodes.signature(returns=nodes.ref("int")), ) assert_equal(types.func([], types.int_type), _infer_func_type(node))
def cannot_declare_name_with_two_different_declaration_types(): try: declarations = _declarations_in(nodes.module([ nodes.assign([nodes.ref("f")], nodes.none()), nodes.func("f", nodes.arguments([]), [], type=None) ])) declarations = find_declarations(node) assert False, "Expected error" except errors.InvalidReassignmentError as error: assert_equal("function declaration and variable assignment cannot share the same name", str(error))
def names_in_function_signature_are_not_declared_in_outer_scope(): explicit_type = nodes.signature( type_params=[nodes.formal_type_parameter("T")], args=[], returns=nodes.ref("T"), ) node = nodes.func("f", nodes.arguments([]), [], type=explicit_type) declarations = find_declarations(node) assert not declarations.is_declared("T")
def class_definition_functions_ignore_class_scope_when_resolving_references(): ref = nodes.ref("x") node = nodes.class_("User", [ nodes.assign([nodes.ref("x")], nodes.none()), nodes.func("f", nodes.args([]), [nodes.ret(ref)], type=None), ]) declarations = _create_declarations(["x", "User"]) references = resolve(node, declarations) assert_is(declarations.declaration("x"), references.referenced_declaration(ref))