facebook / facebook/pyrefly

`bad-override` ignores a custom `__get__` overload when checking method overrides

Open
#4,494 2 comments 0 reactions 0 assignees View on GitHub
typechecking
Dominant language
Rust
Stars
7k
Forks
519
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

### Summary
When a subclass overrides a method with a decorator that returns a custom
descriptor object (a class implementing `__get__`, correctly overloaded for
the bound vs. unbound access cases), pyrefly's `bad-override` check compares
the *raw, unbound* attribute types of the base and derived methods instead of
resolving `__get__` on each side first. It reports an incompatible override
even when the descriptor's `__get__` is fully and correctly typed, and even
though `reveal_type` on an instance access (e.g. `Derived().method`) shows
pyrefly *does* resolve `__get__` correctly everywhere else — just not inside
this specific check.

### Notes
- We ran into this from JAX's `jax.jit`, which decorates functions and
returns a `JitWrapped[**P, R]` object with correctly-typed `__get__`
overloads for exactly this purpose (binding away `self` when accessed
through an instance). Any method decorated with `@jax.jit` inside a class
body currently trips `bad-override`, even when the wrapper is a fully
correct descriptor. (https://github.com/jax-ml/jax/pull/14688)
- Confirmed this is specific to the override check, not general `__get__`
resolution: `reveal_type(Derived().method)` correctly reports
`(...) -> None` (matching the base's bound `() -> None`), so pyrefly's
attribute-access logic already resolves `__get__` correctly — it's just
not consulted by `bad-override`'s comparison.

### Sandbox Link

https://pyrefly.org/sandbox/?project=v2.pZXBCoJAEIZfZamDIeHeF4LoCaSrdRDdTAIVtXr9_t11HDUSpZO6uv_Mzsz3u8Iy2TycpZEDmZb0QOomqfMKdhL5frgX5-sIswQSPWY-Zh6EhoG54tF_4HBuxd3Z6TkrEQQB8XXkoKyaaWaXZlrZsUOSb_i4MifRY4L2Qlp9c5YuxMoADr8FIahwEaLYknC43_qd7qGn_bIxqSLCVA6EUImcgaQ6KWHpmlqwuxWKd9klqzho1rBVHff81lFHLT7FvQlM3I5p53xoLGqMX7oze8lijpTmAq1v1rYidAuiG1v8ZQBp9oQi4EP0LVqrxb1tq0ZJSdvLOpO6kGmZNHK0QwpjK_Erzm2ZxnKitN7QQPYfyD3HuDeHuGcIxxez1H4A

### (Only applicable for extension issues) IDE Information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start at the bad-override check and compare its behavior with the existing __get__ resolution used for reveal_type on Derived().method. Reproduce the issue with the linked sandbox and a custom descriptor like the JitWrapped case; done means a correctly overloaded descriptor no longer produces an incompatible-override diagnostic while genuine mismatches still do.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.