Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeVar bound not respected in Generic class method overloads #18419

Open
jackmpcollins opened this issue Jan 5, 2025 · 1 comment
Open

TypeVar bound not respected in Generic class method overloads #18419

jackmpcollins opened this issue Jan 5, 2025 · 1 comment
Labels
bug mypy got something wrong topic-overloads

Comments

@jackmpcollins
Copy link

Bug Report

Mypy chooses the wrong overload of a generic class method in the below code. str | Sequence[int] would match Sequence[ItemT] if ItemT was not bounded or constrained, but since it is constrained to non-str the overload for str | Sequence[ItemT] should be matched instead. The issue only affects generic class methods and not regular functions.

To Reproduce

from collections.abc import Sequence
from typing import Generic, TypeVar, overload

from typing_extensions import assert_type


T = TypeVar("T", covariant=True)
ItemT = TypeVar("ItemT", bound=int)  # OR TypeVar("ItemT", int, float)


class MyGeneric(Generic[T]):
    @overload
    def transform(self: "MyGeneric[str]") -> "MyGeneric[str]": ...

    @overload
    def transform(self: "MyGeneric[Sequence[ItemT]]") -> "MyGeneric[Sequence[ItemT]]": ...

    @overload
    def transform(self: "MyGeneric[str | Sequence[ItemT]]") -> "MyGeneric[str | Sequence[ItemT]]": ...

    def transform(self: "MyGeneric[str | Sequence[ItemT]]") -> "MyGeneric[str | Sequence[ItemT]]": ...  # type: ignore


assert_type(MyGeneric[str]().transform(), MyGeneric[str])
assert_type(MyGeneric[Sequence[int]]().transform(), MyGeneric[Sequence[int]])
assert_type(MyGeneric[str | Sequence[int]]().transform(), MyGeneric[str | Sequence[int]])
# error: Expression is of type "MyGeneric[Sequence[object]]", not "MyGeneric[str | Sequence[int]]"

# ---
# The equivalent functions do not have the same issue

@overload
def transform(x: "MyGeneric[str]") -> "MyGeneric[str]": ...

@overload
def transform(x: "MyGeneric[Sequence[ItemT]]") -> "MyGeneric[Sequence[ItemT]]": ...

@overload
def transform(x: "MyGeneric[str | Sequence[ItemT]]") -> "MyGeneric[str | Sequence[ItemT]]": ...

def transform(x: "MyGeneric[str | Sequence[ItemT]]") -> "MyGeneric[str | Sequence[ItemT]]": ...  # type: ignore


assert_type(transform(MyGeneric[str]()), MyGeneric[str])
assert_type(transform(MyGeneric[Sequence[int]]()), MyGeneric[Sequence[int]])
assert_type(transform(MyGeneric[str | Sequence[int]]()), MyGeneric[str | Sequence[int]])

Your Environment

  • Mypy version used: 1.14.1
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.13.0
@jackmpcollins jackmpcollins added the bug mypy got something wrong label Jan 5, 2025
@jackmpcollins
Copy link
Author

jackmpcollins commented Jan 5, 2025

This could be the same issue and is a simpler reproduction, and rules out overload as being the cause. The typevar StrIntT is constrained to str or int, so the Literal input should become a str output, but it remains Literal.

from typing import Generic, Literal, TypeVar

from typing_extensions import assert_type


T = TypeVar("T")
StrIntT = TypeVar("StrIntT", str, int)


class MyGeneric(Generic[T]):
    def transform(self: "MyGeneric[StrIntT]") -> "MyGeneric[StrIntT]":
        return self


assert_type(MyGeneric[str]().transform(), MyGeneric[str])
assert_type(MyGeneric[Literal["x"]]().transform(), MyGeneric[str])
# error: Expression is of type "MyGeneric[Literal['x']]", not "MyGeneric[str]"


# ---
# The equivalent functions do not have the same issue

def transform(x: MyGeneric[StrIntT]) -> MyGeneric[StrIntT]: ...  # type: ignore[empty-body]

assert_type(transform(MyGeneric[str]()), MyGeneric[str])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-overloads
Projects
None yet
Development

No branches or pull requests

2 participants