From 897c12bba3df505599615d001cf00c7c472d900b Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 16 Jul 2023 20:53:44 +0300 Subject: [PATCH 1/3] Correctly narrow types for `tuple[type[X], ...]` --- mypy/checker.py | 2 ++ test-data/unit/check-narrowing.test | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index f2873c7d58e4..2e0859dad978 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7118,6 +7118,8 @@ def flatten_types(t: Type) -> list[Type]: t = get_proper_type(t) if isinstance(t, TupleType): return [b for a in t.items for b in flatten_types(a)] + elif is_named_instance(t, "builtins.tuple"): + return [t.args[0]] else: return [t] diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index f06af0057f0f..64d7ff64b642 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1268,3 +1268,21 @@ def g() -> None: def foo(): ... foo() [builtins fixtures/dict.pyi] + + +[case testNarrowingWithTupleOfTypes] +from typing import Tuple, Type + +class Base: ... + +class Impl1(Base): ... +class Impl2(Base): ... + +impls: Tuple[Type[Base], ...] = (Impl1, Impl2) +some: object + +if isinstance(some, impls): + reveal_type(some) # N: Revealed type is "__main__.Base" +else: + reveal_type(some) # N: Revealed type is "builtins.object" +[builtins fixtures/dict.pyi] From bca2caeefbe3b48c55eb07158701b27a511bb0ae Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 16 Jul 2023 21:45:56 +0300 Subject: [PATCH 2/3] More tests --- test-data/unit/check-narrowing.test | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 64d7ff64b642..43e767d89116 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1285,4 +1285,33 @@ if isinstance(some, impls): reveal_type(some) # N: Revealed type is "__main__.Base" else: reveal_type(some) # N: Revealed type is "builtins.object" + +raw: Tuple[type, ...] +if isinstance(some, raw): + reveal_type(some) # N: Revealed type is "builtins.object" +else: + reveal_type(some) # N: Revealed type is "builtins.object" +[builtins fixtures/dict.pyi] + + +[case testNarrowingWithTupleOfTypesPy30Plus] +# flags: --python-version 3.10 +class Base: ... + +class Impl1(Base): ... +class Impl2(Base): ... + +impls: tuple[type[Base], ...] = (Impl1, Impl2) +some: int | Base + +if isinstance(some, impls): + reveal_type(some) # N: Revealed type is "__main__.Base" +else: + reveal_type(some) # N: Revealed type is "Union[builtins.int, __main__.Base]" + +raw: tuple[type, ...] +if isinstance(some, raw): + reveal_type(some) # N: Revealed type is "Union[builtins.int, __main__.Base]" +else: + reveal_type(some) # N: Revealed type is "Union[builtins.int, __main__.Base]" [builtins fixtures/dict.pyi] From 7574423fcb31c9c8f06c289bbdbdeaae6dc98044 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 29 Jul 2023 10:23:30 +0300 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Ilya Priven --- test-data/unit/check-narrowing.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 43e767d89116..d46089a0ac8e 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1294,16 +1294,16 @@ else: [builtins fixtures/dict.pyi] -[case testNarrowingWithTupleOfTypesPy30Plus] +[case testNarrowingWithTupleOfTypesPy310Plus] # flags: --python-version 3.10 class Base: ... class Impl1(Base): ... class Impl2(Base): ... -impls: tuple[type[Base], ...] = (Impl1, Impl2) some: int | Base +impls: tuple[type[Base], ...] = (Impl1, Impl2) if isinstance(some, impls): reveal_type(some) # N: Revealed type is "__main__.Base" else: