ruff
d2479057 - [ty] Materialize only substituted typevars during specialization (#23725)

Commit
18 days ago
[ty] Materialize only substituted typevars during specialization (#23725) ## Summary See https://github.com/astral-sh/ty/issues/2955#issuecomment-4000172171 for a comprehensive write-up of the underlying issue. Here's a Claude-generated example: ```python from typing import Any class InvariantWithAny[T: int]: a: T b: Any def _(x: object): if isinstance(x, InvariantWithAny): # x is narrowed to InvariantWithAny[Unknown], then materialized. # T was substituted (T → Unknown → object), so `a` becomes `object`. # But `b` was annotated as `Any` by the user — it has nothing to do with T. reveal_type(x.a) # revealed: object ← correct either way reveal_type(x.b) # revealed: Any ← fixed (was: object) ``` On main, the second pass materializes every gradual type, so `Any` on `b` was turned into `object`. Now, only the types that come from substituting `T` gets materialized, so the explicit `Any` on `b` is left alone. IIUC, this is a bit worse in the contravariant case (again, with Claude's help): ```python class Handler[T]: def handle(self, event: T, context: Any) -> None: ... def _(x: object): if isinstance(x, Handler): # handle(event: Never, context: Never) ← bug # handle(event: Never, context: Any) ← fixed x.handle(42, {"key": "value"}) ``` Closes https://github.com/astral-sh/ty/issues/2955.
Author
Parents
Loading