False positive on `__init_subclass__` keyword validation in diamond inheritance
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 516
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the Bug
Pyrefly reports a spurious "Missing argument" error on a **valid** class header
when `__init_subclass__` is overridden in a diamond hierarchy. The inherited
`__init_subclass__` is resolved by a depth-first walk over base classes, which
diverges from Python's actual C3 MRO.
**Steps to reproduce** :
```python
class D:
def __init_subclass__(cls, kw: str) -> None: ...
class B(D): ...
class C(D):
def __init_subclass__(cls, **kwargs) -> None: ...
class A(B, C): ...
```
**What I see:** an error on `class A(B, C)` on a missing required argument `kw`.
**Expected:** no error. At runtime `MRO(A) == [A, B, C, D]`, so
`C.__init_subclass__` (which accepts `**kwargs`) is what runs, and `class A(B, C)`
is valid. Pyrefly's base walk visits `B → D` first, finds `D`'s stricter
signature, and stops before reaching `C`, producing the false positive.
The linear (non-diamond) case is handled correctly; only diamonds where an
intermediate base overrides `__init_subclass__` more permissively than a deeper
shared base are affected.
---
_Note for maintainers:_ `find_inherited_init_subclass` in
`pyrefly/lib/alt/class/class_metadata.rs` walks bases pre-order DFS and takes the
first `__init_subclass__` found. It deliberately avoids the class's own MRO
(still being computed during metadata, unsafe on cyclic hierarchies), so a fix
should linearize from the bases' already-computed MROs rather than a raw
pre-order walk. Introduced alongside the `__init_subclass__` keyword validation.
### Sandbox Link
_No response_
### (Only applicable for extension issues) IDE Information
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.