def for_statement_target_can_be_supertype_of_iterable_element_type(): ref_node = nodes.ref("xs") node = nodes.for_(nodes.subscript(nodes.ref("ys"), nodes.int_literal(0)), ref_node, []) update_context(node, type_bindings={ "xs": types.list_type(types.int_type), "ys": types.list_type(types.object_type), })
def target_of_comprehension_is_available_in_element(): type_bindings = {"xs": types.list_type(types.str_type)} node = nodes.list_comprehension( nodes.ref("x"), nodes.ref("x"), nodes.ref("xs"), ) assert_equal( types.list_type(types.str_type), infer(node, type_bindings=type_bindings) )
def can_infer_type_of_list_comprehension_over_list(): type_bindings = {"xs": types.list_type(types.str_type)} node = nodes.list_comprehension( nodes.int_literal(1), nodes.ref("x"), nodes.ref("xs"), ) assert_equal( types.list_type(types.int_type), infer(node, type_bindings=type_bindings) )
def for_statement_target_can_be_variable(): node = nodes.for_(nodes.ref("x"), nodes.ref("xs"), []) # Unassigned case update_context(node, type_bindings={ "xs": types.list_type(types.str_type), }) # Assigned case update_context(node, type_bindings={ "x": types.str_type, "xs": types.list_type(types.str_type), })
def else_body_of_for_loop_is_type_checked(): assert_statement_is_type_checked( lambda bad_statement: nodes.for_(nodes.ref("x"), nodes.ref("xs"), [], [ bad_statement ]), type_bindings={ "xs": types.list_type(types.str_type), } )
def for_statement_target_cannot_be_strict_subtype_of_iterable_element_type(): target_sequence_node = nodes.ref("ys") target_node = nodes.subscript(target_sequence_node, nodes.int_literal(0)) iterable_node = nodes.ref("xs") node = nodes.for_(target_node, iterable_node, []) try: update_context(node, type_bindings={ "xs": types.list_type(types.object_type), "ys": types.list_type(types.int_type), }) assert False, "Expected error" except errors.UnexpectedTargetTypeError as error: assert_equal(target_sequence_node, ephemeral.root_node(error.node)) assert_equal( ephemeral.FormalArg(ephemeral.attr(target_sequence_node, "__setitem__"), 1), ephemeral.underlying_node(error.node) ) assert_equal(types.object_type, error.value_type) assert_equal(types.int_type, error.target_type)
def when_target_has_explicit_type_that_type_is_used_as_type_hint(): node = nodes.assign( [nodes.ref("x")], nodes.list_literal([nodes.str_literal("Hello")]), type=nodes.type_apply(nodes.ref("list"), [nodes.ref("object")]) ) context = update_context(node, type_bindings={ "list": types.meta_type(types.list_type), "object": types.meta_type(types.object_type), }) assert_equal(types.list_type(types.object_type), context.lookup_name("x"))
def assignment_to_tuple_must_have_tuple_value(): tuple_node = nodes.tuple_literal([nodes.ref("x")]) node = nodes.assign( [tuple_node], nodes.ref("value") ) try: update_context(node, type_bindings={ "value": types.list_type(types.int_type), }) assert False, "Expected error" except errors.CanOnlyUnpackTuplesError as error: assert_equal(tuple_node, error.node) assert_equal("only tuples can be unpacked" , str(error))
def assignment_to_list_does_not_allow_supertype(): target_sequence_node = nodes.ref("x") value_node = nodes.ref("y") node = nodes.assign([nodes.subscript(target_sequence_node, nodes.int_literal(0))], value_node) type_bindings = { "x": types.list_type(types.str_type), "y": types.object_type, } try: update_context(node, type_bindings=type_bindings) assert False, "Expected error" except errors.UnexpectedTargetTypeError as error: assert_equal(target_sequence_node, ephemeral.root_node(error.node)) assert_equal( ephemeral.FormalArg(ephemeral.attr(target_sequence_node, "__setitem__"), 1), ephemeral.underlying_node(error.node) ) assert_equal(types.object_type, error.value_type) assert_equal(types.str_type, error.target_type)
def when_target_already_has_type_that_type_is_used_as_type_hint(): node = nodes.assign([nodes.ref("x")], nodes.list_literal([nodes.str_literal("Hello")])) type_bindings = {"x": types.list_type(types.object_type)} context = update_context(node, type_bindings=type_bindings) assert_equal(types.list_type(types.object_type), context.lookup_name("x"))
def assignment_to_list_allows_subtype(): node = nodes.assign([nodes.subscript(nodes.ref("x"), nodes.int_literal(0))], nodes.str_literal("Hello")) type_bindings = {"x": types.list_type(types.object_type)} update_context(node, type_bindings=type_bindings)
def empty_list_can_be_typed_using_type_hint(): assert_equal( types.list_type(types.int_type), infer(nodes.list_literal([]), hint=types.list_type(types.int_type)) )
def empty_list_type_hint_is_ignored_if_type_hint_is_not_list(): assert_equal( types.list_type(types.bottom_type), infer(nodes.list_literal([]), hint=types.int_type) )
def empty_list_has_elements_of_type_bottom(): assert_equal(types.list_type(types.bottom_type), infer(nodes.list_literal([])))
def can_infer_type_of_subscript_of_list(): type_bindings = {"x": types.list_type(types.str_type)} node = nodes.subscript(nodes.ref("x"), nodes.int_literal(4)) assert_equal(types.str_type, infer(node, type_bindings=type_bindings))
def non_empty_list_can_be_typed_using_type_hint(): assert_equal( types.list_type(types.object_type), infer(nodes.list_literal([nodes.int_literal(1)]), hint=types.list_type(types.object_type)) )
def list_type_hint_is_ignored_if_not_super_type_of_elements(): assert_equal( types.list_type(types.int_type), infer(nodes.list_literal([nodes.int_literal(1)]), hint=types.list_type(types.none_type)) )
def formal_type_of_argument_is_used_as_type_hint_for_actual_argument(): type_bindings = {"f": types.func([types.list_type(types.str_type)], types.int_type)} node = nodes.call(nodes.ref("f"), [nodes.list_literal([])]) assert_equal(types.int_type, infer(node, type_bindings=type_bindings))
def can_infer_type_of_list_of_ints(): assert_equal(types.list_type(types.int_type), infer(nodes.list_literal([nodes.int_literal(1), nodes.int_literal(42)])))