[ty] Support constrained TypeVar compatibility across function boundaries#23103
[ty] Support constrained TypeVar compatibility across function boundaries#23103
Conversation
Typing conformance resultsNo changes detected ✅ |
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unsupported-operator |
0 | 89 | 40 |
not-subscriptable |
1 | 96 | 0 |
invalid-argument-type |
13 | 63 | 7 |
possibly-missing-attribute |
22 | 3 | 35 |
no-matching-overload |
27 | 4 | 0 |
invalid-return-type |
1 | 0 | 4 |
invalid-assignment |
0 | 2 | 1 |
not-iterable |
0 | 0 | 2 |
unused-type-ignore-comment |
1 | 0 | 0 |
| Total | 65 | 257 | 89 |
60c6c18 to
3139d4d
Compare
This comment was marked as outdated.
This comment was marked as outdated.
…y each other When a constrained TypeVar is passed to a function expecting another constrained TypeVar, check whether each constraint of the actual TypeVar is assignable to at least one constraint of the formal TypeVar. This fixes false-positive errors when wrapping functions from external packages that define private TypeVars with the same (or compatible) constraint sets. Fixes astral-sh/ty#2728 https://claude.ai/code/session_01FbdSnWQPg9EZgcwbR5Kujp
3139d4d to
cc5ee4b
Compare
| strict subtype would be unsound. For example, a function constrained to `(int, str)` may narrow `T` | ||
| to `int` and return `int(x)`, which would violate a caller's `bool` constraint: |
There was a problem hiding this comment.
Can it, really? It looks like we don't support that. We don't even support return x, which definitely seems wrong.
There was a problem hiding this comment.
Yeah, this analysis of what is sound or not is not based on how we currently narrow constrained typevars, but on how other type checkers do it and how I believe we should do it after fixing astral-sh/ty#1475. I don't want to add behavior here that will become unsound when that issue is fixed. I can add a parenthetical here clarifying that if you think it's needed, although I kind of preferred not to since it's just one more thing we'll have to remember to find and update when fixing that issue (and there's a good chance we won't remember and it'll stay as an obsolete parenthetical.)
I do think it is correct for a type-checker to allow if isinstance(x, int): return int(x) where x is typed as a typevar constrained to (int, something). Constrained typevars must solve to one of the constrained types -- if you verify it is solved to int, the caller may not expect any more precise type than exactly int.
Pyright, pyrefly, and mypy are all fine with that narrowing inside the body of f. Pyright and pyrefly also allow the call from g, which is not sound. Mypy has the behavior I think we want (allow the narrowing in f, disallow the call from g with subtype constraints -- but allow it if the constraints match exactly.)
Summary
Allow passing constrained TypeVars to functions expecting compatible constrained TypeVars.
Fixes astral-sh/ty#2728
Test Plan
Added mdtests.
Ecosystem results look good. After filtering out non-determinism, it's mostly removing the expected false positives, and then revealing some already-known other issues with constrained typevars as fallout. For example the new scrapy diagnostics are astral-sh/ty#1503.