class TypeOpsSuite(Suite): def set_up(self): self.fx = TypeFixture(INVARIANT) self.fx_co = TypeFixture(COVARIANT) self.fx_contra = TypeFixture(CONTRAVARIANT) # expand_type def test_trivial_expand(self): for t in (self.fx.a, self.fx.o, self.fx.t, self.fx.void, self.fx.nonet, self.tuple(self.fx.a), self.callable([], self.fx.a, self.fx.a), self.fx.anyt): self.assert_expand(t, [], t) self.assert_expand(t, [], t) self.assert_expand(t, [], t) def test_expand_naked_type_var(self): self.assert_expand(self.fx.t, [(1, self.fx.a)], self.fx.a) self.assert_expand(self.fx.t, [(2, self.fx.a)], self.fx.t) def test_expand_basic_generic_types(self): self.assert_expand(self.fx.gt, [(1, self.fx.a)], self.fx.ga) # IDEA: Add test cases for # tuple types # callable types # multiple arguments def assert_expand(self, orig, map_items, result): lower_bounds = {} for id, t in map_items: lower_bounds[id] = t exp = expand_type(orig, lower_bounds) # Remove erased tags (asterisks). assert_equal(str(exp).replace('*', ''), str(result)) # replace_type_vars def test_trivial_replace(self): for t in (self.fx.a, self.fx.o, self.fx.void, self.fx.nonet, self.tuple(self.fx.a), self.callable([], self.fx.a, self.fx.a), self.fx.anyt, self.fx.err): self.assert_replace(t, t) def test_replace_type_var(self): self.assert_replace(self.fx.t, self.fx.anyt) def test_replace_generic_instance(self): self.assert_replace(self.fx.ga, self.fx.ga) self.assert_replace(self.fx.gt, self.fx.gdyn) def assert_replace(self, orig, result): assert_equal(str(replace_type_vars(orig)), str(result)) # erase_type def test_trivial_erase(self): for t in (self.fx.a, self.fx.o, self.fx.void, self.fx.nonet, self.fx.anyt, self.fx.err): self.assert_erase(t, t) def test_erase_with_type_variable(self): self.assert_erase(self.fx.t, self.fx.anyt) def test_erase_with_generic_type(self): self.assert_erase(self.fx.ga, self.fx.gdyn) self.assert_erase(self.fx.hab, Instance(self.fx.hi, [self.fx.anyt, self.fx.anyt])) def test_erase_with_tuple_type(self): self.assert_erase(self.tuple(self.fx.a), self.fx.std_tuple) def test_erase_with_function_type(self): self.assert_erase(self.fx.callable(self.fx.a, self.fx.b), self.fx.callable_type(self.fx.void)) def test_erase_with_type_object(self): self.assert_erase(self.fx.callable_type(self.fx.a, self.fx.b), self.fx.callable_type(self.fx.void)) def assert_erase(self, orig, result): assert_equal(str(erase_type(orig)), str(result)) # is_more_precise def test_is_more_precise(self): fx = self.fx assert_true(is_more_precise(fx.b, fx.a)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.anyt)) assert_true(is_more_precise(self.tuple(fx.b, fx.a), self.tuple(fx.b, fx.a))) assert_false(is_more_precise(fx.a, fx.b)) assert_false(is_more_precise(fx.anyt, fx.b)) assert_false(is_more_precise(self.tuple(fx.b, fx.b), self.tuple(fx.b, fx.a))) # is_proper_subtype def test_is_proper_subtype(self): fx = self.fx assert_true(is_proper_subtype(fx.a, fx.a)) assert_true(is_proper_subtype(fx.b, fx.a)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_false(is_proper_subtype(fx.a, fx.b)) assert_false(is_proper_subtype(fx.o, fx.b)) assert_true(is_proper_subtype(fx.anyt, fx.anyt)) assert_false(is_proper_subtype(fx.a, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, fx.a)) assert_true(is_proper_subtype(fx.ga, fx.ga)) assert_true(is_proper_subtype(fx.gdyn, fx.gdyn)) assert_false(is_proper_subtype(fx.ga, fx.gdyn)) assert_false(is_proper_subtype(fx.gdyn, fx.ga)) assert_true(is_proper_subtype(fx.t, fx.t)) assert_false(is_proper_subtype(fx.t, fx.s)) def test_is_proper_subtype_covariance(self): fx_co = self.fx_co assert_true(is_proper_subtype(fx_co.gsab, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gsab, fx_co.ga)) assert_false(is_proper_subtype(fx_co.gsaa, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gb, fx_co.ga)) assert_false(is_proper_subtype(fx_co.ga, fx_co.gb)) def test_is_proper_subtype_contravariance(self): fx_contra = self.fx_contra assert_true(is_proper_subtype(fx_contra.gsab, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gsab, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.gsaa, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gb, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.ga, fx_contra.gb)) def test_is_proper_subtype_invariance(self): fx = self.fx assert_true(is_proper_subtype(fx.gsab, fx.gb)) assert_false(is_proper_subtype(fx.gsab, fx.ga)) assert_false(is_proper_subtype(fx.gsaa, fx.gb)) assert_false(is_proper_subtype(fx.gb, fx.ga)) assert_false(is_proper_subtype(fx.ga, fx.gb)) # Helpers def tuple(self, *a): return TupleType(a, self.fx.std_tuple) def callable(self, vars, *a) -> CallableType: """callable(args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r and type arguments vars. """ tv = [] # type: List[TypeVarDef] n = -1 for v in vars: tv.append(TypeVarDef(v, n, None, self.fx.o)) n -= 1 return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1), [None] * (len(a) - 1), a[-1], self.fx.function, None, tv)
class TypeOpsSuite(Suite): def setUp(self) -> None: self.fx = TypeFixture(INVARIANT) self.fx_co = TypeFixture(COVARIANT) self.fx_contra = TypeFixture(CONTRAVARIANT) # expand_type def test_trivial_expand(self) -> None: for t in (self.fx.a, self.fx.o, self.fx.t, self.fx.nonet, self.tuple(self.fx.a), self.callable([], self.fx.a, self.fx.a), self.fx.anyt): self.assert_expand(t, [], t) self.assert_expand(t, [], t) self.assert_expand(t, [], t) def test_expand_naked_type_var(self) -> None: self.assert_expand(self.fx.t, [(self.fx.t.id, self.fx.a)], self.fx.a) self.assert_expand(self.fx.t, [(self.fx.s.id, self.fx.a)], self.fx.t) def test_expand_basic_generic_types(self) -> None: self.assert_expand(self.fx.gt, [(self.fx.t.id, self.fx.a)], self.fx.ga) # IDEA: Add test cases for # tuple types # callable types # multiple arguments def assert_expand(self, orig: Type, map_items: List[Tuple[TypeVarId, Type]], result: Type, ) -> None: lower_bounds = {} for id, t in map_items: lower_bounds[id] = t exp = expand_type(orig, lower_bounds) # Remove erased tags (asterisks). assert_equal(str(exp).replace('*', ''), str(result)) # erase_type def test_trivial_erase(self) -> None: for t in (self.fx.a, self.fx.o, self.fx.nonet, self.fx.anyt): self.assert_erase(t, t) def test_erase_with_type_variable(self) -> None: self.assert_erase(self.fx.t, self.fx.anyt) def test_erase_with_generic_type(self) -> None: self.assert_erase(self.fx.ga, self.fx.gdyn) self.assert_erase(self.fx.hab, Instance(self.fx.hi, [self.fx.anyt, self.fx.anyt])) def test_erase_with_tuple_type(self) -> None: self.assert_erase(self.tuple(self.fx.a), self.fx.std_tuple) def test_erase_with_function_type(self) -> None: self.assert_erase(self.fx.callable(self.fx.a, self.fx.b), CallableType(arg_types=[self.fx.anyt, self.fx.anyt], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=[None, None], ret_type=self.fx.anyt, fallback=self.fx.function)) def test_erase_with_type_object(self) -> None: self.assert_erase(self.fx.callable_type(self.fx.a, self.fx.b), CallableType(arg_types=[self.fx.anyt, self.fx.anyt], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=[None, None], ret_type=self.fx.anyt, fallback=self.fx.type_type)) def test_erase_with_type_type(self) -> None: self.assert_erase(self.fx.type_a, self.fx.type_a) self.assert_erase(self.fx.type_t, self.fx.type_any) def assert_erase(self, orig: Type, result: Type) -> None: assert_equal(str(erase_type(orig)), str(result)) # is_more_precise def test_is_more_precise(self) -> None: fx = self.fx assert_true(is_more_precise(fx.b, fx.a)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.anyt)) assert_true(is_more_precise(self.tuple(fx.b, fx.a), self.tuple(fx.b, fx.a))) assert_true(is_more_precise(self.tuple(fx.b, fx.b), self.tuple(fx.b, fx.a))) assert_false(is_more_precise(fx.a, fx.b)) assert_false(is_more_precise(fx.anyt, fx.b)) # is_proper_subtype def test_is_proper_subtype(self) -> None: fx = self.fx assert_true(is_proper_subtype(fx.a, fx.a)) assert_true(is_proper_subtype(fx.b, fx.a)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_false(is_proper_subtype(fx.a, fx.b)) assert_false(is_proper_subtype(fx.o, fx.b)) assert_true(is_proper_subtype(fx.anyt, fx.anyt)) assert_false(is_proper_subtype(fx.a, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, fx.a)) assert_true(is_proper_subtype(fx.ga, fx.ga)) assert_true(is_proper_subtype(fx.gdyn, fx.gdyn)) assert_false(is_proper_subtype(fx.ga, fx.gdyn)) assert_false(is_proper_subtype(fx.gdyn, fx.ga)) assert_true(is_proper_subtype(fx.t, fx.t)) assert_false(is_proper_subtype(fx.t, fx.s)) assert_true(is_proper_subtype(fx.a, UnionType([fx.a, fx.b]))) assert_true(is_proper_subtype(UnionType([fx.a, fx.b]), UnionType([fx.a, fx.b, fx.c]))) assert_false(is_proper_subtype(UnionType([fx.a, fx.b]), UnionType([fx.b, fx.c]))) def test_is_proper_subtype_covariance(self) -> None: fx_co = self.fx_co assert_true(is_proper_subtype(fx_co.gsab, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gsab, fx_co.ga)) assert_false(is_proper_subtype(fx_co.gsaa, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gb, fx_co.ga)) assert_false(is_proper_subtype(fx_co.ga, fx_co.gb)) def test_is_proper_subtype_contravariance(self) -> None: fx_contra = self.fx_contra assert_true(is_proper_subtype(fx_contra.gsab, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gsab, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.gsaa, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gb, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.ga, fx_contra.gb)) def test_is_proper_subtype_invariance(self) -> None: fx = self.fx assert_true(is_proper_subtype(fx.gsab, fx.gb)) assert_false(is_proper_subtype(fx.gsab, fx.ga)) assert_false(is_proper_subtype(fx.gsaa, fx.gb)) assert_false(is_proper_subtype(fx.gb, fx.ga)) assert_false(is_proper_subtype(fx.ga, fx.gb)) def test_is_proper_subtype_and_subtype_literal_types(self) -> None: fx = self.fx lit1 = LiteralType(1, fx.a) lit2 = LiteralType("foo", fx.d) lit3 = LiteralType("bar", fx.d) assert_true(is_proper_subtype(lit1, fx.a)) assert_false(is_proper_subtype(lit1, fx.d)) assert_false(is_proper_subtype(fx.a, lit1)) assert_true(is_proper_subtype(fx.uninhabited, lit1)) assert_false(is_proper_subtype(lit1, fx.uninhabited)) assert_true(is_proper_subtype(lit1, lit1)) assert_false(is_proper_subtype(lit1, lit2)) assert_false(is_proper_subtype(lit2, lit3)) assert_true(is_subtype(lit1, fx.a)) assert_false(is_subtype(lit1, fx.d)) assert_false(is_subtype(fx.a, lit1)) assert_true(is_subtype(fx.uninhabited, lit1)) assert_false(is_subtype(lit1, fx.uninhabited)) assert_true(is_subtype(lit1, lit1)) assert_false(is_subtype(lit1, lit2)) assert_false(is_subtype(lit2, lit3)) assert_false(is_proper_subtype(lit1, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, lit1)) assert_true(is_subtype(lit1, fx.anyt)) assert_true(is_subtype(fx.anyt, lit1)) # can_be_true / can_be_false def test_empty_tuple_always_false(self) -> None: tuple_type = self.tuple() assert_true(tuple_type.can_be_false) assert_false(tuple_type.can_be_true) def test_nonempty_tuple_always_true(self) -> None: tuple_type = self.tuple(AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)) assert_true(tuple_type.can_be_true) assert_false(tuple_type.can_be_false) def test_union_can_be_true_if_any_true(self) -> None: union_type = UnionType([self.fx.a, self.tuple()]) assert_true(union_type.can_be_true) def test_union_can_not_be_true_if_none_true(self) -> None: union_type = UnionType([self.tuple(), self.tuple()]) assert_false(union_type.can_be_true) def test_union_can_be_false_if_any_false(self) -> None: union_type = UnionType([self.fx.a, self.tuple()]) assert_true(union_type.can_be_false) def test_union_can_not_be_false_if_none_false(self) -> None: union_type = UnionType([self.tuple(self.fx.a), self.tuple(self.fx.d)]) assert_false(union_type.can_be_false) # true_only / false_only def test_true_only_of_false_type_is_uninhabited(self) -> None: to = true_only(NoneType()) assert_type(UninhabitedType, to) def test_true_only_of_true_type_is_idempotent(self) -> None: always_true = self.tuple(AnyType(TypeOfAny.special_form)) to = true_only(always_true) assert_true(always_true is to) def test_true_only_of_instance(self) -> None: to = true_only(self.fx.a) assert_equal(str(to), "A") assert_true(to.can_be_true) assert_false(to.can_be_false) assert_type(Instance, to) # The original class still can be false assert_true(self.fx.a.can_be_false) def test_true_only_of_union(self) -> None: tup_type = self.tuple(AnyType(TypeOfAny.special_form)) # Union of something that is unknown, something that is always true, something # that is always false union_type = UnionType([self.fx.a, tup_type, self.tuple()]) to = true_only(union_type) assert isinstance(to, UnionType) assert_equal(len(to.items), 2) assert_true(to.items[0].can_be_true) assert_false(to.items[0].can_be_false) assert_true(to.items[1] is tup_type) def test_false_only_of_true_type_is_uninhabited(self) -> None: fo = false_only(self.tuple(AnyType(TypeOfAny.special_form))) assert_type(UninhabitedType, fo) def test_false_only_of_false_type_is_idempotent(self) -> None: always_false = NoneType() fo = false_only(always_false) assert_true(always_false is fo) def test_false_only_of_instance(self) -> None: fo = false_only(self.fx.a) assert_equal(str(fo), "A") assert_false(fo.can_be_true) assert_true(fo.can_be_false) assert_type(Instance, fo) # The original class still can be true assert_true(self.fx.a.can_be_true) def test_false_only_of_union(self) -> None: tup_type = self.tuple() # Union of something that is unknown, something that is always true, something # that is always false union_type = UnionType([self.fx.a, self.tuple(AnyType(TypeOfAny.special_form)), tup_type]) assert_equal(len(union_type.items), 3) fo = false_only(union_type) assert isinstance(fo, UnionType) assert_equal(len(fo.items), 2) assert_false(fo.items[0].can_be_true) assert_true(fo.items[0].can_be_false) assert_true(fo.items[1] is tup_type) # Helpers def tuple(self, *a: Type) -> TupleType: return TupleType(list(a), self.fx.std_tuple) def callable(self, vars: List[str], *a: Type) -> CallableType: """callable(args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r and type arguments vars. """ tv = [] # type: List[TypeVarDef] n = -1 for v in vars: tv.append(TypeVarDef(v, v, n, [], self.fx.o)) n -= 1 return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1), [None] * (len(a) - 1), a[-1], self.fx.function, name=None, variables=tv)
class SubtypingSuite(Suite): def setUp(self) -> None: self.fx = TypeFixture(INVARIANT) self.fx_contra = TypeFixture(CONTRAVARIANT) self.fx_co = TypeFixture(COVARIANT) def test_trivial_cases(self) -> None: for simple in self.fx_co.a, self.fx_co.o, self.fx_co.b: self.assert_subtype(simple, simple) def test_instance_subtyping(self) -> None: self.assert_strict_subtype(self.fx.a, self.fx.o) self.assert_strict_subtype(self.fx.b, self.fx.o) self.assert_strict_subtype(self.fx.b, self.fx.a) self.assert_not_subtype(self.fx.a, self.fx.d) self.assert_not_subtype(self.fx.b, self.fx.c) def test_simple_generic_instance_subtyping_invariant(self) -> None: self.assert_subtype(self.fx.ga, self.fx.ga) self.assert_subtype(self.fx.hab, self.fx.hab) self.assert_not_subtype(self.fx.ga, self.fx.g2a) self.assert_not_subtype(self.fx.ga, self.fx.gb) self.assert_not_subtype(self.fx.gb, self.fx.ga) def test_simple_generic_instance_subtyping_covariant(self) -> None: self.assert_subtype(self.fx_co.ga, self.fx_co.ga) self.assert_subtype(self.fx_co.hab, self.fx_co.hab) self.assert_not_subtype(self.fx_co.ga, self.fx_co.g2a) self.assert_not_subtype(self.fx_co.ga, self.fx_co.gb) self.assert_subtype(self.fx_co.gb, self.fx_co.ga) def test_simple_generic_instance_subtyping_contravariant(self) -> None: self.assert_subtype(self.fx_contra.ga, self.fx_contra.ga) self.assert_subtype(self.fx_contra.hab, self.fx_contra.hab) self.assert_not_subtype(self.fx_contra.ga, self.fx_contra.g2a) self.assert_subtype(self.fx_contra.ga, self.fx_contra.gb) self.assert_not_subtype(self.fx_contra.gb, self.fx_contra.ga) def test_generic_subtyping_with_inheritance_invariant(self) -> None: self.assert_subtype(self.fx.gsab, self.fx.gb) self.assert_not_subtype(self.fx.gsab, self.fx.ga) self.assert_not_subtype(self.fx.gsaa, self.fx.gb) def test_generic_subtyping_with_inheritance_covariant(self) -> None: self.assert_subtype(self.fx_co.gsab, self.fx_co.gb) self.assert_subtype(self.fx_co.gsab, self.fx_co.ga) self.assert_not_subtype(self.fx_co.gsaa, self.fx_co.gb) def test_generic_subtyping_with_inheritance_contravariant(self) -> None: self.assert_subtype(self.fx_contra.gsab, self.fx_contra.gb) self.assert_not_subtype(self.fx_contra.gsab, self.fx_contra.ga) self.assert_subtype(self.fx_contra.gsaa, self.fx_contra.gb) def test_interface_subtyping(self) -> None: self.assert_subtype(self.fx.e, self.fx.f) self.assert_equivalent(self.fx.f, self.fx.f) self.assert_not_subtype(self.fx.a, self.fx.f) @skip def test_generic_interface_subtyping(self) -> None: # TODO make this work fx2 = InterfaceTypeFixture() self.assert_subtype(fx2.m1, fx2.gfa) self.assert_not_subtype(fx2.m1, fx2.gfb) self.assert_equivalent(fx2.gfa, fx2.gfa) def test_basic_callable_subtyping(self) -> None: self.assert_strict_subtype(self.fx.callable(self.fx.o, self.fx.d), self.fx.callable(self.fx.a, self.fx.d)) self.assert_strict_subtype(self.fx.callable(self.fx.d, self.fx.b), self.fx.callable(self.fx.d, self.fx.a)) self.assert_strict_subtype(self.fx.callable(self.fx.a, self.fx.nonet), self.fx.callable(self.fx.a, self.fx.a)) self.assert_unrelated( self.fx.callable(self.fx.a, self.fx.a, self.fx.a), self.fx.callable(self.fx.a, self.fx.a)) def test_default_arg_callable_subtyping(self) -> None: self.assert_strict_subtype( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.a, self.fx.d, self.fx.a)) self.assert_strict_subtype( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.a, self.fx.a)) self.assert_strict_subtype( self.fx.callable_default(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a)) self.assert_unrelated( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.d, self.fx.d, self.fx.a)) self.assert_unrelated( self.fx.callable_default(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable_default(1, self.fx.a, self.fx.a, self.fx.a)) self.assert_unrelated( self.fx.callable_default(1, self.fx.a, self.fx.a), self.fx.callable(self.fx.a, self.fx.a, self.fx.a)) def test_var_arg_callable_subtyping_1(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable_var_arg(0, self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_2(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_3(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable(self.fx.a)) def test_var_arg_callable_subtyping_4(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_5(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_6(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.f, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.e, self.fx.d)) def test_var_arg_callable_subtyping_7(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.d), self.fx.callable(self.fx.a, self.fx.d)) def test_var_arg_callable_subtyping_8(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.d), self.fx.callable_var_arg(0, self.fx.a, self.fx.a, self.fx.d)) self.assert_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.b, self.fx.d)) def test_var_arg_callable_subtyping_9(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.b, self.fx.d), self.fx.callable_var_arg(0, self.fx.a, self.fx.d)) self.assert_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.d)) def test_type_callable_subtyping(self) -> None: self.assert_subtype( self.fx.callable_type(self.fx.d, self.fx.a), self.fx.type_type) self.assert_strict_subtype( self.fx.callable_type(self.fx.d, self.fx.b), self.fx.callable(self.fx.d, self.fx.a)) self.assert_strict_subtype(self.fx.callable_type(self.fx.a, self.fx.b), self.fx.callable(self.fx.a, self.fx.b)) # IDEA: Maybe add these test cases (they are tested pretty well in type # checker tests already): # * more interface subtyping test cases # * more generic interface subtyping test cases # * type variables # * tuple types # * None type # * any type # * generic function types def assert_subtype(self, s: Type, t: Type) -> None: assert_true(is_subtype(s, t), '{} not subtype of {}'.format(s, t)) def assert_not_subtype(self, s: Type, t: Type) -> None: assert_true(not is_subtype(s, t), '{} subtype of {}'.format(s, t)) def assert_strict_subtype(self, s: Type, t: Type) -> None: self.assert_subtype(s, t) self.assert_not_subtype(t, s) def assert_equivalent(self, s: Type, t: Type) -> None: self.assert_subtype(s, t) self.assert_subtype(t, s) def assert_unrelated(self, s: Type, t: Type) -> None: self.assert_not_subtype(s, t) self.assert_not_subtype(t, s)
class TypeOpsSuite(Suite): def setUp(self) -> None: self.fx = TypeFixture(INVARIANT) self.fx_co = TypeFixture(COVARIANT) self.fx_contra = TypeFixture(CONTRAVARIANT) # expand_type def test_trivial_expand(self) -> None: for t in (self.fx.a, self.fx.o, self.fx.t, self.fx.nonet, self.tuple(self.fx.a), self.callable([], self.fx.a, self.fx.a), self.fx.anyt): self.assert_expand(t, [], t) self.assert_expand(t, [], t) self.assert_expand(t, [], t) def test_trivial_expand_recursive(self) -> None: A, _ = self.fx.def_alias_1(self.fx.a) self.assert_expand(A, [], A) A, _ = self.fx.def_alias_2(self.fx.a) self.assert_expand(A, [], A) def test_expand_naked_type_var(self) -> None: self.assert_expand(self.fx.t, [(self.fx.t.id, self.fx.a)], self.fx.a) self.assert_expand(self.fx.t, [(self.fx.s.id, self.fx.a)], self.fx.t) def test_expand_basic_generic_types(self) -> None: self.assert_expand(self.fx.gt, [(self.fx.t.id, self.fx.a)], self.fx.ga) # IDEA: Add test cases for # tuple types # callable types # multiple arguments def assert_expand( self, orig: Type, map_items: List[Tuple[TypeVarId, Type]], result: Type, ) -> None: lower_bounds = {} for id, t in map_items: lower_bounds[id] = t exp = expand_type(orig, lower_bounds) # Remove erased tags (asterisks). assert_equal(str(exp).replace('*', ''), str(result)) # erase_type def test_trivial_erase(self) -> None: for t in (self.fx.a, self.fx.o, self.fx.nonet, self.fx.anyt): self.assert_erase(t, t) def test_erase_with_type_variable(self) -> None: self.assert_erase(self.fx.t, self.fx.anyt) def test_erase_with_generic_type(self) -> None: self.assert_erase(self.fx.ga, self.fx.gdyn) self.assert_erase(self.fx.hab, Instance(self.fx.hi, [self.fx.anyt, self.fx.anyt])) def test_erase_with_generic_type_recursive(self) -> None: tuple_any = Instance(self.fx.std_tuplei, [AnyType(TypeOfAny.explicit)]) A, _ = self.fx.def_alias_1(self.fx.a) self.assert_erase(A, tuple_any) A, _ = self.fx.def_alias_2(self.fx.a) self.assert_erase(A, UnionType([self.fx.a, tuple_any])) def test_erase_with_tuple_type(self) -> None: self.assert_erase(self.tuple(self.fx.a), self.fx.std_tuple) def test_erase_with_function_type(self) -> None: self.assert_erase( self.fx.callable(self.fx.a, self.fx.b), CallableType(arg_types=[self.fx.anyt, self.fx.anyt], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=[None, None], ret_type=self.fx.anyt, fallback=self.fx.function)) def test_erase_with_type_object(self) -> None: self.assert_erase( self.fx.callable_type(self.fx.a, self.fx.b), CallableType(arg_types=[self.fx.anyt, self.fx.anyt], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=[None, None], ret_type=self.fx.anyt, fallback=self.fx.type_type)) def test_erase_with_type_type(self) -> None: self.assert_erase(self.fx.type_a, self.fx.type_a) self.assert_erase(self.fx.type_t, self.fx.type_any) def assert_erase(self, orig: Type, result: Type) -> None: assert_equal(str(erase_type(orig)), str(result)) # is_more_precise def test_is_more_precise(self) -> None: fx = self.fx assert_true(is_more_precise(fx.b, fx.a)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.b)) assert_true(is_more_precise(fx.b, fx.anyt)) assert_true( is_more_precise(self.tuple(fx.b, fx.a), self.tuple(fx.b, fx.a))) assert_true( is_more_precise(self.tuple(fx.b, fx.b), self.tuple(fx.b, fx.a))) assert_false(is_more_precise(fx.a, fx.b)) assert_false(is_more_precise(fx.anyt, fx.b)) # is_proper_subtype def test_is_proper_subtype(self) -> None: fx = self.fx assert_true(is_proper_subtype(fx.a, fx.a)) assert_true(is_proper_subtype(fx.b, fx.a)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_true(is_proper_subtype(fx.b, fx.o)) assert_false(is_proper_subtype(fx.a, fx.b)) assert_false(is_proper_subtype(fx.o, fx.b)) assert_true(is_proper_subtype(fx.anyt, fx.anyt)) assert_false(is_proper_subtype(fx.a, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, fx.a)) assert_true(is_proper_subtype(fx.ga, fx.ga)) assert_true(is_proper_subtype(fx.gdyn, fx.gdyn)) assert_false(is_proper_subtype(fx.ga, fx.gdyn)) assert_false(is_proper_subtype(fx.gdyn, fx.ga)) assert_true(is_proper_subtype(fx.t, fx.t)) assert_false(is_proper_subtype(fx.t, fx.s)) assert_true(is_proper_subtype(fx.a, UnionType([fx.a, fx.b]))) assert_true( is_proper_subtype(UnionType([fx.a, fx.b]), UnionType([fx.a, fx.b, fx.c]))) assert_false( is_proper_subtype(UnionType([fx.a, fx.b]), UnionType([fx.b, fx.c]))) def test_is_proper_subtype_covariance(self) -> None: fx_co = self.fx_co assert_true(is_proper_subtype(fx_co.gsab, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gsab, fx_co.ga)) assert_false(is_proper_subtype(fx_co.gsaa, fx_co.gb)) assert_true(is_proper_subtype(fx_co.gb, fx_co.ga)) assert_false(is_proper_subtype(fx_co.ga, fx_co.gb)) def test_is_proper_subtype_contravariance(self) -> None: fx_contra = self.fx_contra assert_true(is_proper_subtype(fx_contra.gsab, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gsab, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.gsaa, fx_contra.gb)) assert_false(is_proper_subtype(fx_contra.gb, fx_contra.ga)) assert_true(is_proper_subtype(fx_contra.ga, fx_contra.gb)) def test_is_proper_subtype_invariance(self) -> None: fx = self.fx assert_true(is_proper_subtype(fx.gsab, fx.gb)) assert_false(is_proper_subtype(fx.gsab, fx.ga)) assert_false(is_proper_subtype(fx.gsaa, fx.gb)) assert_false(is_proper_subtype(fx.gb, fx.ga)) assert_false(is_proper_subtype(fx.ga, fx.gb)) def test_is_proper_subtype_and_subtype_literal_types(self) -> None: fx = self.fx lit1 = LiteralType(1, fx.a) lit2 = LiteralType("foo", fx.d) lit3 = LiteralType("bar", fx.d) assert_true(is_proper_subtype(lit1, fx.a)) assert_false(is_proper_subtype(lit1, fx.d)) assert_false(is_proper_subtype(fx.a, lit1)) assert_true(is_proper_subtype(fx.uninhabited, lit1)) assert_false(is_proper_subtype(lit1, fx.uninhabited)) assert_true(is_proper_subtype(lit1, lit1)) assert_false(is_proper_subtype(lit1, lit2)) assert_false(is_proper_subtype(lit2, lit3)) assert_true(is_subtype(lit1, fx.a)) assert_false(is_subtype(lit1, fx.d)) assert_false(is_subtype(fx.a, lit1)) assert_true(is_subtype(fx.uninhabited, lit1)) assert_false(is_subtype(lit1, fx.uninhabited)) assert_true(is_subtype(lit1, lit1)) assert_false(is_subtype(lit1, lit2)) assert_false(is_subtype(lit2, lit3)) assert_false(is_proper_subtype(lit1, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, lit1)) assert_true(is_subtype(lit1, fx.anyt)) assert_true(is_subtype(fx.anyt, lit1)) def test_subtype_aliases(self) -> None: A1, _ = self.fx.def_alias_1(self.fx.a) AA1, _ = self.fx.def_alias_1(self.fx.a) assert_true(is_subtype(A1, AA1)) assert_true(is_subtype(AA1, A1)) A2, _ = self.fx.def_alias_2(self.fx.a) AA2, _ = self.fx.def_alias_2(self.fx.a) assert_true(is_subtype(A2, AA2)) assert_true(is_subtype(AA2, A2)) B1, _ = self.fx.def_alias_1(self.fx.b) B2, _ = self.fx.def_alias_2(self.fx.b) assert_true(is_subtype(B1, A1)) assert_true(is_subtype(B2, A2)) assert_false(is_subtype(A1, B1)) assert_false(is_subtype(A2, B2)) assert_false(is_subtype(A2, A1)) assert_true(is_subtype(A1, A2)) # can_be_true / can_be_false def test_empty_tuple_always_false(self) -> None: tuple_type = self.tuple() assert_true(tuple_type.can_be_false) assert_false(tuple_type.can_be_true) def test_nonempty_tuple_always_true(self) -> None: tuple_type = self.tuple(AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)) assert_true(tuple_type.can_be_true) assert_false(tuple_type.can_be_false) def test_union_can_be_true_if_any_true(self) -> None: union_type = UnionType([self.fx.a, self.tuple()]) assert_true(union_type.can_be_true) def test_union_can_not_be_true_if_none_true(self) -> None: union_type = UnionType([self.tuple(), self.tuple()]) assert_false(union_type.can_be_true) def test_union_can_be_false_if_any_false(self) -> None: union_type = UnionType([self.fx.a, self.tuple()]) assert_true(union_type.can_be_false) def test_union_can_not_be_false_if_none_false(self) -> None: union_type = UnionType([self.tuple(self.fx.a), self.tuple(self.fx.d)]) assert_false(union_type.can_be_false) # true_only / false_only def test_true_only_of_false_type_is_uninhabited(self) -> None: to = true_only(NoneType()) assert_type(UninhabitedType, to) def test_true_only_of_true_type_is_idempotent(self) -> None: always_true = self.tuple(AnyType(TypeOfAny.special_form)) to = true_only(always_true) assert_true(always_true is to) def test_true_only_of_instance(self) -> None: to = true_only(self.fx.a) assert_equal(str(to), "A") assert_true(to.can_be_true) assert_false(to.can_be_false) assert_type(Instance, to) # The original class still can be false assert_true(self.fx.a.can_be_false) def test_true_only_of_union(self) -> None: tup_type = self.tuple(AnyType(TypeOfAny.special_form)) # Union of something that is unknown, something that is always true, something # that is always false union_type = UnionType([self.fx.a, tup_type, self.tuple()]) to = true_only(union_type) assert isinstance(to, UnionType) assert_equal(len(to.items), 2) assert_true(to.items[0].can_be_true) assert_false(to.items[0].can_be_false) assert_true(to.items[1] is tup_type) def test_false_only_of_true_type_is_uninhabited(self) -> None: with strict_optional_set(True): fo = false_only(self.tuple(AnyType(TypeOfAny.special_form))) assert_type(UninhabitedType, fo) def test_false_only_tuple(self) -> None: with strict_optional_set(False): fo = false_only(self.tuple(self.fx.a)) assert_equal(fo, NoneType()) with strict_optional_set(True): fo = false_only(self.tuple(self.fx.a)) assert_equal(fo, UninhabitedType()) def test_false_only_of_false_type_is_idempotent(self) -> None: always_false = NoneType() fo = false_only(always_false) assert_true(always_false is fo) def test_false_only_of_instance(self) -> None: fo = false_only(self.fx.a) assert_equal(str(fo), "A") assert_false(fo.can_be_true) assert_true(fo.can_be_false) assert_type(Instance, fo) # The original class still can be true assert_true(self.fx.a.can_be_true) def test_false_only_of_union(self) -> None: with strict_optional_set(True): tup_type = self.tuple() # Union of something that is unknown, something that is always true, something # that is always false union_type = UnionType([ self.fx.a, self.tuple(AnyType(TypeOfAny.special_form)), tup_type ]) assert_equal(len(union_type.items), 3) fo = false_only(union_type) assert isinstance(fo, UnionType) assert_equal(len(fo.items), 2) assert_false(fo.items[0].can_be_true) assert_true(fo.items[0].can_be_false) assert_true(fo.items[1] is tup_type) # Helpers def tuple(self, *a: Type) -> TupleType: return TupleType(list(a), self.fx.std_tuple) def callable(self, vars: List[str], *a: Type) -> CallableType: """callable(args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r and type arguments vars. """ tv = [] # type: List[TypeVarDef] n = -1 for v in vars: tv.append(TypeVarDef(v, v, n, [], self.fx.o)) n -= 1 return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1), [None] * (len(a) - 1), a[-1], self.fx.function, name=None, variables=tv)
class SubtypingSuite(Suite): def setUp(self) -> None: self.fx = TypeFixture(INVARIANT) self.fx_contra = TypeFixture(CONTRAVARIANT) self.fx_co = TypeFixture(COVARIANT) def test_trivial_cases(self) -> None: for simple in self.fx_co.a, self.fx_co.o, self.fx_co.b: self.assert_subtype(simple, simple) def test_instance_subtyping(self) -> None: self.assert_strict_subtype(self.fx.a, self.fx.o) self.assert_strict_subtype(self.fx.b, self.fx.o) self.assert_strict_subtype(self.fx.b, self.fx.a) self.assert_not_subtype(self.fx.a, self.fx.d) self.assert_not_subtype(self.fx.b, self.fx.c) def test_simple_generic_instance_subtyping_invariant(self) -> None: self.assert_subtype(self.fx.ga, self.fx.ga) self.assert_subtype(self.fx.hab, self.fx.hab) self.assert_not_subtype(self.fx.ga, self.fx.g2a) self.assert_not_subtype(self.fx.ga, self.fx.gb) self.assert_not_subtype(self.fx.gb, self.fx.ga) def test_simple_generic_instance_subtyping_covariant(self) -> None: self.assert_subtype(self.fx_co.ga, self.fx_co.ga) self.assert_subtype(self.fx_co.hab, self.fx_co.hab) self.assert_not_subtype(self.fx_co.ga, self.fx_co.g2a) self.assert_not_subtype(self.fx_co.ga, self.fx_co.gb) self.assert_subtype(self.fx_co.gb, self.fx_co.ga) def test_simple_generic_instance_subtyping_contravariant(self) -> None: self.assert_subtype(self.fx_contra.ga, self.fx_contra.ga) self.assert_subtype(self.fx_contra.hab, self.fx_contra.hab) self.assert_not_subtype(self.fx_contra.ga, self.fx_contra.g2a) self.assert_subtype(self.fx_contra.ga, self.fx_contra.gb) self.assert_not_subtype(self.fx_contra.gb, self.fx_contra.ga) def test_generic_subtyping_with_inheritance_invariant(self) -> None: self.assert_subtype(self.fx.gsab, self.fx.gb) self.assert_not_subtype(self.fx.gsab, self.fx.ga) self.assert_not_subtype(self.fx.gsaa, self.fx.gb) def test_generic_subtyping_with_inheritance_covariant(self) -> None: self.assert_subtype(self.fx_co.gsab, self.fx_co.gb) self.assert_subtype(self.fx_co.gsab, self.fx_co.ga) self.assert_not_subtype(self.fx_co.gsaa, self.fx_co.gb) def test_generic_subtyping_with_inheritance_contravariant(self) -> None: self.assert_subtype(self.fx_contra.gsab, self.fx_contra.gb) self.assert_not_subtype(self.fx_contra.gsab, self.fx_contra.ga) self.assert_subtype(self.fx_contra.gsaa, self.fx_contra.gb) def test_interface_subtyping(self) -> None: self.assert_subtype(self.fx.e, self.fx.f) self.assert_equivalent(self.fx.f, self.fx.f) self.assert_not_subtype(self.fx.a, self.fx.f) @skip def test_generic_interface_subtyping(self) -> None: # TODO make this work fx2 = InterfaceTypeFixture() self.assert_subtype(fx2.m1, fx2.gfa) self.assert_not_subtype(fx2.m1, fx2.gfb) self.assert_equivalent(fx2.gfa, fx2.gfa) def test_basic_callable_subtyping(self) -> None: self.assert_strict_subtype(self.fx.callable(self.fx.o, self.fx.d), self.fx.callable(self.fx.a, self.fx.d)) self.assert_strict_subtype(self.fx.callable(self.fx.d, self.fx.b), self.fx.callable(self.fx.d, self.fx.a)) self.assert_strict_subtype(self.fx.callable(self.fx.a, self.fx.nonet), self.fx.callable(self.fx.a, self.fx.a)) self.assert_unrelated( self.fx.callable(self.fx.a, self.fx.a, self.fx.a), self.fx.callable(self.fx.a, self.fx.a)) def test_default_arg_callable_subtyping(self) -> None: self.assert_strict_subtype( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.a, self.fx.d, self.fx.a)) self.assert_strict_subtype( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.a, self.fx.a)) self.assert_strict_subtype( self.fx.callable_default(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a)) self.assert_unrelated( self.fx.callable_default(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.d, self.fx.d, self.fx.a)) self.assert_unrelated( self.fx.callable_default(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable_default(1, self.fx.a, self.fx.a, self.fx.a)) self.assert_unrelated( self.fx.callable_default(1, self.fx.a, self.fx.a), self.fx.callable(self.fx.a, self.fx.a, self.fx.a)) def test_var_arg_callable_subtyping_1(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable_var_arg(0, self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_2(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_3(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a), self.fx.callable(self.fx.a)) def test_var_arg_callable_subtyping_4(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(1, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_5(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.d, self.fx.a), self.fx.callable(self.fx.b, self.fx.a)) def test_var_arg_callable_subtyping_6(self) -> None: self.assert_strict_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.f, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.e, self.fx.d)) def test_var_arg_callable_subtyping_7(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.d), self.fx.callable(self.fx.a, self.fx.d)) def test_var_arg_callable_subtyping_8(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.d), self.fx.callable_var_arg(0, self.fx.a, self.fx.a, self.fx.d)) self.assert_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.b, self.fx.d)) def test_var_arg_callable_subtyping_9(self) -> None: self.assert_not_subtype( self.fx.callable_var_arg(0, self.fx.b, self.fx.b, self.fx.d), self.fx.callable_var_arg(0, self.fx.a, self.fx.d)) self.assert_subtype( self.fx.callable_var_arg(0, self.fx.a, self.fx.a, self.fx.d), self.fx.callable_var_arg(0, self.fx.b, self.fx.d)) def test_type_callable_subtyping(self) -> None: self.assert_subtype(self.fx.callable_type(self.fx.d, self.fx.a), self.fx.type_type) self.assert_strict_subtype(self.fx.callable_type(self.fx.d, self.fx.b), self.fx.callable(self.fx.d, self.fx.a)) self.assert_strict_subtype(self.fx.callable_type(self.fx.a, self.fx.b), self.fx.callable(self.fx.a, self.fx.b)) # IDEA: Maybe add these test cases (they are tested pretty well in type # checker tests already): # * more interface subtyping test cases # * more generic interface subtyping test cases # * type variables # * tuple types # * None type # * any type # * generic function types def assert_subtype(self, s: Type, t: Type) -> None: assert is_subtype(s, t), f'{s} not subtype of {t}' def assert_not_subtype(self, s: Type, t: Type) -> None: assert not is_subtype(s, t), f'{s} subtype of {t}' def assert_strict_subtype(self, s: Type, t: Type) -> None: self.assert_subtype(s, t) self.assert_not_subtype(t, s) def assert_equivalent(self, s: Type, t: Type) -> None: self.assert_subtype(s, t) self.assert_subtype(t, s) def assert_unrelated(self, s: Type, t: Type) -> None: self.assert_not_subtype(s, t) self.assert_not_subtype(t, s)