From 08a9a229a0d9347ec467af4c1a107b7f0f8502e8 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 20 Jun 2025 14:03:49 -0500 Subject: [PATCH 1/4] Only erase instances when checking runtime cover In particular, avoid erasing CallableType that represent type objects Helps with #19159 --- mypy/subtypes.py | 3 ++- test-data/unit/check-python310.test | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index a5e6938615e7..c8f04466b38d 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -2106,7 +2106,8 @@ def covers_at_runtime(item: Type, supertype: Type) -> bool: supertype = get_proper_type(supertype) # Since runtime type checks will ignore type arguments, erase the types. - supertype = erase_type(supertype) + if isinstance(supertype, Instance): + supertype = erase_type(supertype) if is_proper_subtype( erase_type(item), supertype, ignore_promotions=True, erase_instances=True ): diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 0695bd0380cb..f58af98e51fb 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -2601,6 +2601,27 @@ def f(t: T) -> None: reveal_type(k) # N: Revealed type is "tuple[builtins.int, fallback=__main__.K]" [builtins fixtures/tuple.pyi] +[case testMatchTypeObjectTypeVar] +from typing import TypeVar +import b + +T_Choice = TypeVar("T_Choice", bound=b.One | b.Two) + +def switch(choice: type[T_Choice]) -> None: + match choice: + case b.One: + reveal_type(choice) # N: Revealed type is "def () -> b.One" + case b.Two: + reveal_type(choice) # N: Revealed type is "def () -> b.Two" + case _: + reveal_type(choice) # N: Revealed type is "type[T_Choice`-1]" + +[file b.py] +class One: ... +class Two: ... + +[builtins fixtures/tuple.pyi] + [case testNewRedefineMatchBasics] # flags: --allow-redefinition-new --local-partial-types From 59741526c220123581ac2758354a6a46327f3356 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 20 Jun 2025 14:12:13 -0500 Subject: [PATCH 2/4] . --- mypy/subtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index c8f04466b38d..f6bcdf1a86e2 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -2106,7 +2106,7 @@ def covers_at_runtime(item: Type, supertype: Type) -> bool: supertype = get_proper_type(supertype) # Since runtime type checks will ignore type arguments, erase the types. - if isinstance(supertype, Instance): + if not isinstance(supertype, CallableType): supertype = erase_type(supertype) if is_proper_subtype( erase_type(item), supertype, ignore_promotions=True, erase_instances=True From aab250cff3db0dbec85ef2b30825c05d7c51f80d Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 22 Jun 2025 00:15:33 -0500 Subject: [PATCH 3/4] test --- test-data/unit/check-python310.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index f58af98e51fb..bb8f038eb1eb 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -2602,6 +2602,7 @@ def f(t: T) -> None: [builtins fixtures/tuple.pyi] [case testMatchTypeObjectTypeVar] +# flags: --warn-unreachable from typing import TypeVar import b From d477fe7c1aaceff0327af61cf074ef82b6f25d4f Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 22 Jun 2025 00:18:38 -0500 Subject: [PATCH 4/4] erase --- mypy/subtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index f9b9a6f821ab..9219bf1c544b 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -2117,7 +2117,7 @@ def covers_at_runtime(item: Type, supertype: Type) -> bool: supertype = get_proper_type(supertype) # Since runtime type checks will ignore type arguments, erase the types. - if not isinstance(supertype, CallableType): + if not (isinstance(supertype, CallableType) and supertype.is_type_obj()): supertype = erase_type(supertype) if is_proper_subtype( erase_type(item), supertype, ignore_promotions=True, erase_instances=True