Skip to content

1.1 regression: false positive bad-assignment for overload with generic self type #3974

Description

@jorenham

Describe the Bug

After bumping Pyrefly from 1.0 to 1.1 in optype, a bunch of type-tests started failing for the numpy<2.2 jobs (see e.g. https://github.com/jorenham/optype/actions/runs/27886459886/job/82522566360). This also broadly affects scipy-stubs, which heavily depends on these relevant optype types. But I'm guessing that this also causes issues for other projects that support these older NumPy versions.

When an overloaded method has an overload whose self is annotated with a TypeVar, Pyrefly 1.1 drops that overload when the method is bound on an instance. With it gone, the type no longer satisfies any Protocol that structurally needs it:

from typing import Any, Protocol, Self, overload

class C1:
    @overload
    def f[S](self, /) -> Self: ...
    @overload
    def f(self, x: int, /) -> int: ...

class C2:
    @overload
    def f[S](self: S, /) -> S: ...
    @overload
    def f(self, x: int, /) -> int: ...

class P(Protocol):
    def f(self, /) -> object: ...

x: P = C1()  # ✔️ 
x: P = C2()  # ❌ `C2` is not assignable to `P` [bad-assignment]

The error message shows that first overload disappeared:

ERROR sandbox.pyi:19:8-12: `C2` is not assignable to `P` [[bad-assignment](https://pyrefly.org/en/docs/error-kinds/#bad-assignment)]
  `C2.f` has type `Overload[
  (self: C2, x: int, /) -> int
]`, which is not assignable to `(self: C2, /) -> object`, the type of `P.f`

And indeed, without that overload, C2 would be assignable to P.

This doesn't apply to non-overloaded methods, so e.g. def f[S](self: S) -> S is fine.
It also seems to be order-independent, so swapping the overloads doesn't change anything.

I verified that this is still the case on main.

Oh and the reason this only affects numpy<2.2 is because, starting from 2.2, numpy.generic.__array__ uses Self instead of a self-bound TypeVar.

Related (but verified to be different) issues:

Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeSIIANCGQE4xhSmEAuuAtlBQMQAEABVIMmpPmix58fAMa50kAOYBXOqlYR5hADrp%2BAZRgw%2BAC1aticRAHpr9Rs0K46i6zHTXMuGXGtyFECpqGvLWfGDOfKgAbqjQqNiwsvJKquqa6Hy4xCHocDroZKwm8gC00TB0cBl8ALx82iAAzIQAjABMjboA2pV0znAAurrK6BAcxM6sMJilmBAMMhoVdXwA5IHozjBruluspQwAjsoLM6UA1jCkpagyMvBwq2sA7qh06Lvo1CASOAQkUgQChgfocPisUjECDoRR8caTOisPgAQXQpCogn67DkUExhigYExuAqdCguFQmF0uhkUFQcCeAGFWohdHx2XwAAIkyrkylsjmYRjhbr6QYACjgMEJmOsAEo%2BKUAHx8AlgRB8QhagXs7mkvlUzKC4VgSXSol8fAamGsWUK5Xw9CsDVago0ukMviM9qso26nlkimGjl8IVgEVis2EjX6O2KlX6F3av1cgMGnWhk1Ri1Wx22vjy%2BN5pNu9C0%2BlPATigTY7y4KBy30hsPhbNxh24bAAKxgSxL1PQuYEq2Z4rluiHI-aY90IAAvjQ7ssYAAxaAwCh-KSA4FzoA

(Only applicable for extension issues) IDE Information

No response

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions