Pyrefly drops the `self` binding of a method whose decorator has a union type.
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 516
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the Bug
SQLAlchemy 2.1 trips it on every `row.status`: its new `_row_cy.py` picks a cython shim with a try/except import, pyrefly unions both branches, and that union decorates `BaseRow.__getattr__`. 2.0 has no such module and is unaffected. Pyrefly 1.1.1, 1.2.0.dev1 and 1.2.0.dev2 all reproduce.
```python
❯ uv run --script repro_pyrefly_union_decorator.py
ERROR Missing argument `x` in function `C.method` [missing-argument]
--> subject.py:16:11
|
16 | C().method(1) # BUG: `Literal[1]` binds to `self`, `x` reported missing
| ^^^
|
ERROR Argument `Literal[1]` is not assignable to parameter `self` with type `C` in function `C.method` [bad-argument-type]
--> subject.py:16:12
|
16 | C().method(1) # BUG: `Literal[1]` binds to `self`, `x` reported missing
| ^
|
INFO 2 errors
```
```python
# /// script
# requires-python = ">=3.12"
# dependencies = ["pyrefly==1.2.0.dev2"]
# ///
import subprocess
import sys
import tempfile
from pathlib import Path
SUBJECT = """
from typing import Any, Callable, TypeVar
_T = TypeVar("_T")
union: Callable[[_T], _T] | Callable[[Any], Any] = lambda f: f
solo: Callable[[_T], _T] = lambda f: f
class C:
@union
def method(self, x: int) -> str: ...
@solo
def control(self, x: int) -> str: ...
C().method(1) # BUG: `Literal[1]` binds to `self`, `x` reported missing
C().control(1) # fine: same decorator, only the annotation differs
"""
if __name__ == "__main__":
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
(root / "pyrefly.toml").touch() # with no config it checks nothing, still says "0 errors"
(root / "subject.py").write_text(SUBJECT)
pyrefly = Path(sys.executable).parent / "pyrefly"
sys.exit(subprocess.run([str(pyrefly), "check", "subject.py"], cwd=root).returncode)
```
### Sandbox Link
_No response_
### (Only applicable for extension issues) IDE Information
_No response_
Contributor guide
Research direction
Start by running repro_pyrefly_union_decorator.py and inspecting subject.py, especially the union and solo decorator cases. Trace how Pyrefly handles method binding when a decorator has a union type; done means C().method(1) no longer reports self or x errors while the control case remains valid.
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
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100