1"""Test cases for the constraint solver used in type inference.""" 2 3from typing import List, Union, Tuple, Optional 4 5from mypy.test.helpers import Suite, assert_equal 6from mypy.constraints import SUPERTYPE_OF, SUBTYPE_OF, Constraint 7from mypy.solve import solve_constraints 8from mypy.test.typefixture import TypeFixture 9from mypy.types import Type, TypeVarType, TypeVarId 10 11 12class SolveSuite(Suite): 13 def setUp(self) -> None: 14 self.fx = TypeFixture() 15 16 def test_empty_input(self) -> None: 17 self.assert_solve([], [], []) 18 19 def test_simple_supertype_constraints(self) -> None: 20 self.assert_solve([self.fx.t.id], 21 [self.supc(self.fx.t, self.fx.a)], 22 [(self.fx.a, self.fx.o)]) 23 self.assert_solve([self.fx.t.id], 24 [self.supc(self.fx.t, self.fx.a), 25 self.supc(self.fx.t, self.fx.b)], 26 [(self.fx.a, self.fx.o)]) 27 28 def test_simple_subtype_constraints(self) -> None: 29 self.assert_solve([self.fx.t.id], 30 [self.subc(self.fx.t, self.fx.a)], 31 [self.fx.a]) 32 self.assert_solve([self.fx.t.id], 33 [self.subc(self.fx.t, self.fx.a), 34 self.subc(self.fx.t, self.fx.b)], 35 [self.fx.b]) 36 37 def test_both_kinds_of_constraints(self) -> None: 38 self.assert_solve([self.fx.t.id], 39 [self.supc(self.fx.t, self.fx.b), 40 self.subc(self.fx.t, self.fx.a)], 41 [(self.fx.b, self.fx.a)]) 42 43 def test_unsatisfiable_constraints(self) -> None: 44 # The constraints are impossible to satisfy. 45 self.assert_solve([self.fx.t.id], 46 [self.supc(self.fx.t, self.fx.a), 47 self.subc(self.fx.t, self.fx.b)], 48 [None]) 49 50 def test_exactly_specified_result(self) -> None: 51 self.assert_solve([self.fx.t.id], 52 [self.supc(self.fx.t, self.fx.b), 53 self.subc(self.fx.t, self.fx.b)], 54 [(self.fx.b, self.fx.b)]) 55 56 def test_multiple_variables(self) -> None: 57 self.assert_solve([self.fx.t.id, self.fx.s.id], 58 [self.supc(self.fx.t, self.fx.b), 59 self.supc(self.fx.s, self.fx.c), 60 self.subc(self.fx.t, self.fx.a)], 61 [(self.fx.b, self.fx.a), (self.fx.c, self.fx.o)]) 62 63 def test_no_constraints_for_var(self) -> None: 64 self.assert_solve([self.fx.t.id], 65 [], 66 [self.fx.uninhabited]) 67 self.assert_solve([self.fx.t.id, self.fx.s.id], 68 [], 69 [self.fx.uninhabited, self.fx.uninhabited]) 70 self.assert_solve([self.fx.t.id, self.fx.s.id], 71 [self.supc(self.fx.s, self.fx.a)], 72 [self.fx.uninhabited, (self.fx.a, self.fx.o)]) 73 74 def test_simple_constraints_with_dynamic_type(self) -> None: 75 self.assert_solve([self.fx.t.id], 76 [self.supc(self.fx.t, self.fx.anyt)], 77 [(self.fx.anyt, self.fx.anyt)]) 78 self.assert_solve([self.fx.t.id], 79 [self.supc(self.fx.t, self.fx.anyt), 80 self.supc(self.fx.t, self.fx.anyt)], 81 [(self.fx.anyt, self.fx.anyt)]) 82 self.assert_solve([self.fx.t.id], 83 [self.supc(self.fx.t, self.fx.anyt), 84 self.supc(self.fx.t, self.fx.a)], 85 [(self.fx.anyt, self.fx.anyt)]) 86 87 self.assert_solve([self.fx.t.id], 88 [self.subc(self.fx.t, self.fx.anyt)], 89 [(self.fx.anyt, self.fx.anyt)]) 90 self.assert_solve([self.fx.t.id], 91 [self.subc(self.fx.t, self.fx.anyt), 92 self.subc(self.fx.t, self.fx.anyt)], 93 [(self.fx.anyt, self.fx.anyt)]) 94 # self.assert_solve([self.fx.t.id], 95 # [self.subc(self.fx.t, self.fx.anyt), 96 # self.subc(self.fx.t, self.fx.a)], 97 # [(self.fx.anyt, self.fx.anyt)]) 98 # TODO: figure out what this should be after changes to meet(any, X) 99 100 def test_both_normal_and_any_types_in_results(self) -> None: 101 # If one of the bounds is any, we promote the other bound to 102 # any as well, since otherwise the type range does not make sense. 103 self.assert_solve([self.fx.t.id], 104 [self.supc(self.fx.t, self.fx.a), 105 self.subc(self.fx.t, self.fx.anyt)], 106 [(self.fx.anyt, self.fx.anyt)]) 107 108 self.assert_solve([self.fx.t.id], 109 [self.supc(self.fx.t, self.fx.anyt), 110 self.subc(self.fx.t, self.fx.a)], 111 [(self.fx.anyt, self.fx.anyt)]) 112 113 def assert_solve(self, 114 vars: List[TypeVarId], 115 constraints: List[Constraint], 116 results: List[Union[None, Type, Tuple[Type, Type]]], 117 ) -> None: 118 res = [] # type: List[Optional[Type]] 119 for r in results: 120 if isinstance(r, tuple): 121 res.append(r[0]) 122 else: 123 res.append(r) 124 actual = solve_constraints(vars, constraints) 125 assert_equal(str(actual), str(res)) 126 127 def supc(self, type_var: TypeVarType, bound: Type) -> Constraint: 128 return Constraint(type_var.id, SUPERTYPE_OF, bound) 129 130 def subc(self, type_var: TypeVarType, bound: Type) -> Constraint: 131 return Constraint(type_var.id, SUBTYPE_OF, bound) 132