From 234b1613f81429d17a8345874182563d39583e82 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Sun, 14 Aug 2022 18:51:34 +0100 Subject: [PATCH] Fix type inference for tuples in iterable context (#13406) It is a minor change to fix the example in https://github.com/python/typeshed/issues/7904 --- mypy/checkexpr.py | 5 +++-- test-data/unit/check-inference.test | 16 ++++++++++++++++ test-data/unit/pythoneval.test | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 598fe952fafa..7f72a21ebc18 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -132,6 +132,7 @@ ) from mypy.types import ( LITERAL_TYPE_NAMES, + TUPLE_LIKE_INSTANCE_NAMES, AnyType, CallableType, DeletedType, @@ -3848,7 +3849,7 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: t for t in get_proper_types(type_context.items) if (isinstance(t, TupleType) and len(t.items) == len(e.items)) - or is_named_instance(t, "builtins.tuple") + or is_named_instance(t, TUPLE_LIKE_INSTANCE_NAMES) ] if len(tuples_in_context) == 1: type_context = tuples_in_context[0] @@ -3859,7 +3860,7 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: if isinstance(type_context, TupleType): type_context_items = type_context.items - elif type_context and is_named_instance(type_context, "builtins.tuple"): + elif type_context and is_named_instance(type_context, TUPLE_LIKE_INSTANCE_NAMES): assert isinstance(type_context, Instance) if type_context.args: type_context_items = [type_context.args[0]] * len(e.items) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index f094bf36b8c5..04c710af10d1 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -3248,3 +3248,19 @@ reveal_type(x) # N: Revealed type is "builtins.bytes" if x: reveal_type(x) # N: Revealed type is "builtins.bytes" [builtins fixtures/dict.pyi] + +[case testTupleContextFromIterable] +from typing import TypeVar, Iterable, List, Union + +T = TypeVar("T") + +def foo(x: List[T]) -> List[T]: ... +x: Iterable[List[Union[int, str]]] = (foo([1]), foo(["a"])) +[builtins fixtures/tuple.pyi] + +[case testTupleContextFromIterable2] +from typing import Dict, Iterable, Tuple, Union + +def foo(x: Union[Tuple[str, Dict[str, int], str], Iterable[object]]) -> None: ... +foo(("a", {"a": "b"}, "b")) +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index a79e8743fb97..7991ee75d03e 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1612,3 +1612,21 @@ class Foo(Enum): _testEnumValueWithPlaceholderNodeType.py:5: error: Incompatible types in assignment (expression has type "object", variable has type "Foo") _testEnumValueWithPlaceholderNodeType.py:6: error: Incompatible types in assignment (expression has type "object", variable has type "Foo") _testEnumValueWithPlaceholderNodeType.py:6: error: Name "Missing" is not defined + +[case testTypeshedRecursiveTypesExample] +# flags: --enable-recursive-aliases +from typing import List, Union + +Recursive = Union[str, List["Recursive"]] + +def foo(r: Recursive) -> None: + if not isinstance(r, str): + if r: + foo(r[0]) + if not isinstance(r, list): + r.casefold() + +foo("") +foo(list("")) +foo(list((list(""), ""))) +[out]