pytype icon indicating copy to clipboard operation
pytype copied to clipboard

Regression: `@overload` function with `TypeVar` is omitted from generated `pyi` file

Open AdamGleave opened this issue 3 years ago • 0 comments

pytype version 2021.5.11 introduced a regression that is still present in the latest version 2022.01.13: overloaded type annotations that involve a type variable are omitted from the generated pyi file. This causes spurious type errors for source files elsewhere in the project that use the generated pyi type stubs.

Example file with a somewhat tortured example:

from typing import TypeVar, overload

T = TypeVar("T")

class A:
    def __init__(self, x):
        self.x = x

    @overload
    def __getitem__(self, key: int) -> int:
        pass

    @overload
    def __getitem__(self: T, key: slice) -> T:
        pass

    def __getitem__(self, key):
        if isinstance(key, slice):
            return A(self.x[key])
        else:
            return self.x[key]

    @overload
    def f(self, x: int) -> int:
        pass

    @overload
    def f(self, x: float) -> float:
        pass

    def f(self, x):
        return x * self.x[x]

    def g(self: T) -> T:
        return self

The generated pyi file for 2021.5.11 and 2022.01.13 (as well as several versions I tested in between) is:

# (generated with --quick)

from typing import Any, TypeVar, overload

T = TypeVar('T')

class A:
    x: Any
    def __getitem__(self, key: int) -> int: ...
    def __init__(self, x) -> None: ...
    @overload
    def f(self, x: int) -> int: ...
    @overload
    def f(self, x: float) -> float: ...
    def g(self: T) -> T: ...

But 2021.5.6 gets it right with:

# (generated with --quick)

from typing import Any, TypeVar, overload

T = TypeVar('T')

class A:
    x: Any
    @overload
    def __getitem__(self, key: int) -> int: ...
    @overload
    def __getitem__(self: T, key: slice) -> T: ...
    def __init__(self, x) -> None: ...
    @overload
    def f(self, x: int) -> int: ...
    @overload
    def f(self, x: float) -> float: ...
    def g(self: T) -> T: ...

Notably all versions handle the overloaded f without a type variable fine, as well as the non-overloaded g without a type variable. So it seems to be only a combination of the two that causes the problem.

AdamGleave avatar Jan 24 '22 00:01 AdamGleave