facebook / facebook/pyrefly

Pyrefly drops the `self` binding of a method whose decorator has a union type.

Open
#4,181 0 comments 0 reactions 0 assignees View on GitHub
sqlalchemy typechecking
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.