From fbf344b4d9411e4a8f3af030795e153d0ddf9747 Mon Sep 17 00:00:00 2001 From: Jared Hance Date: Thu, 11 Aug 2022 09:27:20 -0700 Subject: [PATCH 1/2] Implement tuple cases for typevartuple constraints --- mypy/constraints.py | 17 +++++-- mypy/test/testconstraints.py | 97 +++++++++++++++++++++++++++++++++++- mypy/test/typefixture.py | 1 + 3 files changed, 110 insertions(+), 5 deletions(-) diff --git a/mypy/constraints.py b/mypy/constraints.py index 05bc680230ee..bcbeace1ff2b 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -644,11 +644,20 @@ def visit_instance(self, template: Instance) -> list[Constraint]: isinstance(template_unpack, Instance) and template_unpack.type.fullname == "builtins.tuple" ): - # TODO: check homogenous tuple case - raise NotImplementedError + for item in mapped_middle: + res.extend( + infer_constraints( + template_unpack.args[0], item, self.direction + ) + ) elif isinstance(template_unpack, TupleType): - # TODO: check tuple case - raise NotImplementedError + if len(template_unpack.items) == len(mapped_middle): + for template_arg, item in zip( + template_unpack.items, mapped_middle + ): + res.extend( + infer_constraints(template_arg, item, self.direction) + ) mapped_args = mapped_prefix + mapped_suffix template_args = template_prefix + template_suffix diff --git a/mypy/test/testconstraints.py b/mypy/test/testconstraints.py index 4f5d927f956f..36c26dea71d2 100644 --- a/mypy/test/testconstraints.py +++ b/mypy/test/testconstraints.py @@ -5,7 +5,7 @@ from mypy.constraints import SUBTYPE_OF, SUPERTYPE_OF, Constraint, infer_constraints from mypy.test.helpers import Suite from mypy.test.typefixture import TypeFixture -from mypy.types import Instance, TypeList, UnpackType +from mypy.types import Instance, TupleType, TypeList, UnpackType class ConstraintsSuite(Suite): @@ -48,3 +48,98 @@ def test_type_var_tuple_with_prefix_and_suffix(self) -> None: Constraint(type_var=fx.ts, op=SUPERTYPE_OF, target=TypeList([fx.b, fx.c])), Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.d), } + + def test_unpack_homogenous_tuple(self) -> None: + fx = self.fx + assert set( + infer_constraints( + Instance(fx.gvi, [UnpackType(Instance(fx.std_tuplei, [fx.t]))]), + Instance(fx.gvi, [fx.a, fx.b]), + SUPERTYPE_OF, + ) + ) == { + Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.b), + } + + def test_unpack_homogenous_tuple_with_prefix_and_suffix(self) -> None: + fx = self.fx + assert set( + infer_constraints( + Instance(fx.gv2i, [fx.t, UnpackType(Instance(fx.std_tuplei, [fx.s])), fx.u]), + Instance(fx.gv2i, [fx.a, fx.b, fx.c, fx.d]), + SUPERTYPE_OF, + ) + ) == { + Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.c), + Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + } + + def test_unpack_tuple(self) -> None: + fx = self.fx + assert set( + infer_constraints( + Instance( + fx.gvi, + [ + UnpackType( + TupleType([fx.t, fx.s], fallback=Instance(fx.std_tuplei, [fx.o])) + ) + ], + ), + Instance(fx.gvi, [fx.a, fx.b]), + SUPERTYPE_OF, + ) + ) == { + Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.b), + } + + def test_unpack_with_prefix_and_suffix(self) -> None: + fx = self.fx + assert set( + infer_constraints( + Instance( + fx.gv2i, + [ + fx.u, + UnpackType( + TupleType([fx.t, fx.s], fallback=Instance(fx.std_tuplei, [fx.o])) + ), + fx.u, + ], + ), + Instance(fx.gv2i, [fx.a, fx.b, fx.c, fx.d]), + SUPERTYPE_OF, + ) + ) == { + Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.c), + Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + } + + def test_unpack_tuple_length_non_match(self) -> None: + fx = self.fx + assert set( + infer_constraints( + Instance( + fx.gv2i, + [ + fx.u, + UnpackType( + TupleType([fx.t, fx.s], fallback=Instance(fx.std_tuplei, [fx.o])) + ), + fx.u, + ], + ), + Instance(fx.gv2i, [fx.a, fx.b, fx.d]), + SUPERTYPE_OF, + ) + # We still get constraints on the prefix/suffix in this case. + ) == { + Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + } diff --git a/mypy/test/typefixture.py b/mypy/test/typefixture.py index a78ad6e6f51b..380da909893a 100644 --- a/mypy/test/typefixture.py +++ b/mypy/test/typefixture.py @@ -66,6 +66,7 @@ def make_type_var_tuple(name: str, id: int, upper_bound: Type) -> TypeVarTupleTy self.s1 = make_type_var("S", 1, [], self.o, variance) # S`1 (type variable) self.sf = make_type_var("S", -2, [], self.o, variance) # S`-2 (type variable) self.sf1 = make_type_var("S", -1, [], self.o, variance) # S`-1 (type variable) + self.u = make_type_var("U", 3, [], self.o, variance) # U`3 (type variable) self.ts = make_type_var_tuple("Ts", 1, self.o) # Ts`1 (type var tuple) self.ss = make_type_var_tuple("Ss", 2, self.o) # Ss`2 (type var tuple) From 4f8880fcd3a8eee9b9c4d8e477ed0f261ca9108b Mon Sep 17 00:00:00 2001 From: Jared Hance Date: Thu, 8 Sep 2022 07:56:02 -0700 Subject: [PATCH 2/2] Clean up broken rebase --- mypy/test/testconstraints.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mypy/test/testconstraints.py b/mypy/test/testconstraints.py index 36c26dea71d2..6b8f596dd605 100644 --- a/mypy/test/testconstraints.py +++ b/mypy/test/testconstraints.py @@ -58,8 +58,8 @@ def test_unpack_homogenous_tuple(self) -> None: SUPERTYPE_OF, ) ) == { - Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), - Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.b), } def test_unpack_homogenous_tuple_with_prefix_and_suffix(self) -> None: @@ -71,10 +71,10 @@ def test_unpack_homogenous_tuple_with_prefix_and_suffix(self) -> None: SUPERTYPE_OF, ) ) == { - Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), - Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.b), - Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.c), - Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.c), + Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.d), } def test_unpack_tuple(self) -> None: @@ -93,8 +93,8 @@ def test_unpack_tuple(self) -> None: SUPERTYPE_OF, ) ) == { - Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.a), - Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.b), } def test_unpack_with_prefix_and_suffix(self) -> None: @@ -115,10 +115,10 @@ def test_unpack_with_prefix_and_suffix(self) -> None: SUPERTYPE_OF, ) ) == { - Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.a), - Constraint(type_var=fx.t.id, op=SUPERTYPE_OF, target=fx.b), - Constraint(type_var=fx.s.id, op=SUPERTYPE_OF, target=fx.c), - Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.b), + Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.c), + Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.d), } def test_unpack_tuple_length_non_match(self) -> None: @@ -140,6 +140,6 @@ def test_unpack_tuple_length_non_match(self) -> None: ) # We still get constraints on the prefix/suffix in this case. ) == { - Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.a), - Constraint(type_var=fx.u.id, op=SUPERTYPE_OF, target=fx.d), + Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.a), + Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.d), }