Bound TypeVar solved to a type outside its bound
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 55/100
Research direction
Start by running the provided reproduction in t.py or the linked Pyrefly sandbox and confirm that pyrefly reveals Box[int | None] while the other checkers reveal Box[Any]. Trace overload resolution and TypeVar bound handling for this call, then add a regression test showing that the bounded overload is rejected and the untyped overload produces Box[Any].
Written by the indexing model from the issue text.
Description
Describe the Bug
from collections.abc import Mapping
from typing import Any, Generic, overload, reveal_type
from typing_extensions import TypeVar
S1 = TypeVar("S1", bound=int, default=Any)
S2 = TypeVar("S2", bound=int)
class Box(Generic[S1]):
@overload
def map(self, func: Mapping[S1, S2]) -> "Box[S2]": ...
@overload
def map(self, func: Mapping[Any, Any]) -> "Box": ...
def map(self, func: Any) -> Any: ...
b: Box[Any] = Box()
# The dict literal's value type is `int | None`. `None` is not assignable to
# `int` (the bound on S2), so the first overload should not apply, and this
# call should fall through to the second (untyped) overload, giving `Box[Any]`.
reveal_type(b.map({1: 10, 0: 20, None: None})) # revealed: Box[int | None]
The revealed type here is Box[int | None, even though None isn't part of the S2 bound (i.e. int)
mypy / pyright / ty all reveal Box[Any]
(scratch) mgorelli@marcoslaptop:~/scratch$ mypy t.py
t.py:23: note: Revealed type is "t.Box[Any]"
Success: no issues found in 1 source file
(scratch) mgorelli@marcoslaptop:~/scratch$ pyright t.py
/home/mgorelli/scratch/t.py
/home/mgorelli/scratch/t.py:23:13 - information: Type of "b.map({ 1: 10,0: 20,None: None })" is "Box[Any]"
0 errors, 0 warnings, 1 information
(scratch) mgorelli@marcoslaptop:~/scratch$ ty check t.py
info[revealed-type]: Revealed type
--> t.py:23:13
|
23 | reveal_type(b.map({1: 10, 0: 20, None: None}))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Box[Any]`
Found 1 diagnostic
(scratch) mgorelli@marcoslaptop:~/scratch$ pyrefly check t.py
INFO revealed type: Box[int | None] [reveal-type]
--> t.py:23:12
|
23 | reveal_type(b.map({1: 10, 0: 20, None: None}))
| -----------------------------------
INFO 0 errors
Spotted in pandas-stubs
Sandbox Link
(Only applicable for extension issues) IDE Information
No response
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 521
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from facebook/pyrefly
-
Difficulty 2/5 Half a day Newbie friendliness 68/100
-
typechecking
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
False positive `unexpected-keyword` for inherited SQLAlchemy mapped columns in `Update.values()` Opensqlalchemy typechecking
Difficulty 3/5 1-2 days Newbie friendliness 72/100
-
Difficulty 4/5 3-5 days Newbie friendliness 25/100
All issues in facebook/pyrefly
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100