Summary
ty falls back to TypeVar defaults instead of inferring them from a self argument passed to a module-level generic function.
Playground link: https://play.ty.dev/0147ee60-169a-4d11-b364-ed8e350593a9
Repro (no external deps)
ty_repro_self_typevar_inference.py:
from typing_extensions import TypeVar, Generic
T = TypeVar('T', default=None)
U = TypeVar('U', default=str)
class Stream(Generic[T, U]):
def handle(self, x: int) -> None:
helper(self, x)
def helper(stream: Stream[T, U], x: int) -> None: ...
Run:
uvx ty check ty_repro_self_typevar_inference.py
Actual result
error[invalid-argument-type]: Argument to function `helper` is incorrect
--> ty_repro_self_typevar_inference.py:9:16
|
7 | class Stream(Generic[T, U]):
8 | def handle(self, x: int) -> None:
9 | helper(self, x)
| ^^^^ Expected `Stream[None, str]`, found `Self@handle`
|
info: Function defined here
--> ty_repro_self_typevar_inference.py:12:5
|
12 | def helper(stream: Stream[T, U], x: int) -> None: ...
| ^^^^^^ -------------------- Parameter declared here
|
Expected result
No diagnostic. helper's free TypeVars T and U should be solved from the passed self (whose type is Stream[T@Stream, U@Stream]). Instead ty resolves them to their defaults (None and str) and then reports that Self@handle is not assignable to Stream[None, str]. Pyright accepts this.
Notes
ty 0.0.29 (438a78d 2026-04-05) via uvx ty check. Closed #1977 had the same Self@method / TypeVar-default-fallback symptom but was triggered via Callable[[S], T | None] and fixed by ruff#22495 ("Generalize union-type subtyping fast path"). This repro uses neither Callable nor a union — just a direct helper(self, x) call with class TypeVars that have defaults — so #1977's fix does not cover it.
Summary
ty falls back to
TypeVardefaults instead of inferring them from aselfargument passed to a module-level generic function.Playground link: https://play.ty.dev/0147ee60-169a-4d11-b364-ed8e350593a9
Repro (no external deps)
ty_repro_self_typevar_inference.py:Run:
Actual result
Expected result
No diagnostic.
helper's freeTypeVarsTandUshould be solved from the passedself(whose type isStream[T@Stream, U@Stream]). Instead ty resolves them to their defaults (Noneandstr) and then reports thatSelf@handleis not assignable toStream[None, str]. Pyright accepts this.Notes
ty 0.0.29 (438a78d 2026-04-05) via
uvx ty check. Closed #1977 had the sameSelf@method/TypeVar-default-fallback symptom but was triggered viaCallable[[S], T | None]and fixed by ruff#22495 ("Generalize union-type subtyping fast path"). This repro uses neitherCallablenor a union — just a directhelper(self, x)call with classTypeVars that have defaults — so #1977's fix does not cover it.