Regression: specialised self overloads erase container types and suppress attribute errors
- Dominant language
- Python
- Stars
- 15.6k
- Forks
- 1.8k
- Avg merge
- 12h 13m
- Merged PRs (30d)
- 52
Description
## Describe the bug
Starting with Pyright 1.1.412, `Container[Any].copy()` becomes `Any` instead of `Container[Any]`, losing the outer container type and suppressing the nonexistent-member error. Expected: preserve `Container[Any]` and report the invalid attribute, since every overload returns a container.
## Code or Screenshots
```python
from typing import Any, Generic, Never, TypeVar, overload, reveal_type
T = TypeVar("T")
class Container(Generic[T]):
@overload
def copy(self: "Container[Never]") -> "Container[Any]": ...
@overload
def copy(self: "Container[int]") -> "Container[int]": ...
@overload
def copy(self: "Container[float]") -> "Container[float]": ...
def copy(self) -> "Container[Any]":
return self
def example(value: Container[Any], concrete: Container[int]) -> None:
reveal_type(value.copy())
reveal_type(concrete.copy())
value.copy().nonexistent_member()
```
## VS Code extension or command-line
- https://pyright-play.net/?code=GYJw9gtgBALgngBwJYDsDmUkQWEMoCCKcANFAOICmKlISAxmQHKUButZAKopQGoCGIMmHYgANmH4ATMiDaV%2BYgPrwElAFDrOUALxRuagSAAUAIk6mAlJvpj%2BAZ3tQAwmBQx%2BqWsao069AG1OAF1LAC51KCioAAERWglpSOipSmAoejAEOGN7SjFgMKhTV3dPPwCWUWCrKABaAD5i0o8vEACiOBqigDo%2B5Ki40USpAahU9Mzs3PzC5rdWitQYGst6ppKF8toA5e6oPp6xoYTJUejxtIysnLyCos2ytoDgRJXaxvmnitfJd97%2BhcJtdpndgGtPo9FjtOt0xhc5DAAK4gFBQMGaYGUAAe-GwYkoxlYiiRlCKLW27VhZEyKHoiLJLi2zz2EKaTDcZLGcnYihUPCJJMoPSmOUsaygAGIoNk6GgABb4NBIdhOTrc%2BR81SE2n0ygwYWi4ziqLS2VIBVKlWUJwUlnuYJjYliUkim7GnooTnYpD2A3uJQQSgQABG3glZrgcsV4zANqgXvwIE8eSAA
- https://pyrefly.org/sandbox/?project=v2.pVXLDoIwEPyVjRzQS3vnZOIPeOCmxihW5GBrpBr9e6cvpCIk6LXdGXbLzOzYyGxy0SdeE2G9eZSjb181XU_y9cT-Q2fFhZIaU4jr1POu8k2Q4Dwwvp1VqMvT-irDSzTYlW1lA2KjtvYFOsZxRoyxsZxQ0jdGd_wT4xFVXznDRYs1oukbq-NUUxxCRLiQCxkSg7FDlCyAim7MbJ-Gbf1LR8VsW7MZUUKQf1WeNJWQVm3k0cWE7_TDPt72neUewiS6eSDFhdTbszjvIZaI5qDAAss4p3ZdmdDSHZAXuBn-WJU3bD3YFC-eYOEJOml9qTPOA1xdSy4kP6ii5hGCkwmg3X1X2V0a05GyKVKD9p84SF0apENhkJosQMWgv18
Version 1.1.411 exits with status 1; the later versions exit with status 0.
| Pyright | Generic result | Missing-member error |
|---|---|---|
| 1.1.411 | `Container[Any]` | Reported |
| 1.1.412–1.1.414 | `Any` | Missed |
All four versions infer `Container[int]` for the concrete control.
[#11601](https://github.com/microsoft/pyright/pull/11601) intentionally handles ambiguity from nested `Any`/`Unknown` in invariant nominal type arguments, with [specialized-self](https://github.com/microsoft/pyright/blob/6906b0921c6fcda2888035ee1790282fdaf7410b/packages/pyright-internal/src/tests/samples/overloadCall6.py#L335-L362) and [pandas-like tests](https://github.com/microsoft/pyright/blob/6906b0921c6fcda2888035ee1790282fdaf7410b/packages/pyright-internal/src/tests/samples/overloadCall12.py#L14-L58) covering precision loss. This report asks whether the shared outer container can be preserved to retain attribute checking; it does not claim a typing-specification violation.
On unchanged `pandas-stubs` `main` at pandas-dev/pandas-stubs@507243e, Pyright 1.1.414 reports **240 `reportAssertTypeFailure` errors** versus zero in 1.1.411; related work: pandas-dev/pandas-stubs#1941 and temporary pin pandas-dev/pandas-stubs#1942.
Contributor guide
Research direction
Start with the specialized-self cases in packages/pyright-internal/src/tests/samples/overloadCall6.py and the pandas-like cases in overloadCall12.py, then reproduce the 1.1.411–1.1.414 difference from the issue. Trace the overload-resolution regression and add a focused sample or regression test. Done means the generic result remains Container[Any] and the nonexistent-member error is reported without breaking the concrete Container[int] case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100