Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 not isinstance(supertype, CallableType):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we only skip erase if the callable type represents a type object? What about overloaded callable types?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how we would get here with other CallableType's (and we don't anywhere in the test suite). isinstance(item, CallableType) isn't really a thing that can happen at runtime.

I went ahead and restricted it to just type objects though!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC it can be triggered (at least in theory) by if callable(x): ... checks. Also as @JukkaL said you should really use FunctionLike instead of CallableType, otherwise things will weirdly behave differently for classes with overloaded constructors (unfortunately this already happens in a bunch of other places, but it is not an excuse to add more of it).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh lol right, I even made an issue about this a few years ago #12320 (and tried to fix it in several places)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

supertype = erase_type(supertype)
if is_proper_subtype(
erase_type(item), supertype, ignore_promotions=True, erase_instances=True
):
Expand Down
21 changes: 21 additions & 0 deletions test-data/unit/check-python310.test
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down