From 7df6183e45218f56722e206acdf067cd73d57db5 Mon Sep 17 00:00:00 2001 From: "Tim D. Smith" Date: Mon, 15 Aug 2022 09:35:19 -0700 Subject: [PATCH 1/3] Allow unpacking from TypeVars by resolving bounds TypeVars aren't iterable, but their bounds might be! Resolve a TypeVar to its bounds before trying to decide how to unpack one of its instances. Fixes #13402. --- mypy/checker.py | 3 +++ test-data/unit/check-bound.test | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 38301f89c815..038cec0fd349 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -3168,6 +3168,9 @@ def check_multi_assignment( # TODO: maybe elsewhere; redundant. rvalue_type = get_proper_type(rv_type or self.expr_checker.accept(rvalue)) + if isinstance(rvalue_type, TypeVarType): + rvalue_type = get_proper_type(rvalue_type.upper_bound) + if isinstance(rvalue_type, UnionType): # If this is an Optional type in non-strict Optional code, unwrap it. relevant_items = rvalue_type.relevant_items() diff --git a/test-data/unit/check-bound.test b/test-data/unit/check-bound.test index bf13ef874579..44d0fede00a9 100644 --- a/test-data/unit/check-bound.test +++ b/test-data/unit/check-bound.test @@ -215,3 +215,11 @@ if int(): b = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "int") twice(a) # E: Value of type variable "T" of "twice" cannot be "int" [builtins fixtures/args.pyi] + + +[case testIterableBoundUnpacking] +from typing import Tuple, TypeVar +TupleT = TypeVar("TupleT", bound=Tuple[int, ...]) +def f(t: TupleT) -> None: + a, *b = t +[builtins fixtures/tuple.pyi] From 2224a5af51bff5c1a7f19045cc53527e867d40d7 Mon Sep 17 00:00:00 2001 From: "Tim D. Smith" Date: Wed, 17 Aug 2022 09:00:37 -0700 Subject: [PATCH 2/3] Reveal types of a and b --- test-data/unit/check-bound.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-data/unit/check-bound.test b/test-data/unit/check-bound.test index 44d0fede00a9..eb97bde32e1f 100644 --- a/test-data/unit/check-bound.test +++ b/test-data/unit/check-bound.test @@ -222,4 +222,6 @@ from typing import Tuple, TypeVar TupleT = TypeVar("TupleT", bound=Tuple[int, ...]) def f(t: TupleT) -> None: a, *b = t + reveal_type(a) # N: Revealed type is "builtins.int" + reveal_type(b) # N: Revealed type is "builtins.list[builtins.int]" [builtins fixtures/tuple.pyi] From 529c571d3bfcae1439fb32f9be6b1a2e8d659c15 Mon Sep 17 00:00:00 2001 From: "Tim D. Smith" Date: Wed, 17 Aug 2022 10:01:38 -0700 Subject: [PATCH 3/3] Add test for unbounded typevar --- test-data/unit/check-typevar-unbound.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-data/unit/check-typevar-unbound.test b/test-data/unit/check-typevar-unbound.test index a233a9c7af13..8761cd94027e 100644 --- a/test-data/unit/check-typevar-unbound.test +++ b/test-data/unit/check-typevar-unbound.test @@ -58,3 +58,9 @@ def h(a: List[Union[Callable[..., T]]]) -> T: def j(a: List[Union[Callable[..., Tuple[T, T]], int]]) -> T: ... [builtins fixtures/tuple.pyi] + +[case testUnboundedTypevarUnpacking] +from typing import TypeVar +T = TypeVar("T") +def f(t: T) -> None: + a, *b = t # E: "object" object is not iterable