mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-02 21:03:11 +00:00
[ty] typing.Self is bound by the method, not the class (#19784)
This fixes our logic for binding a legacy typevar with its binding context. (To recap, a legacy typevar starts out "unbound" when it is first created, and each time it's used in a generic class or function, we "bind" it with the corresponding `Definition`.) We treat `typing.Self` the same as a legacy typevar, and so we apply this binding logic to it too. Before, we were using the enclosing class as its binding context. But that's not correct — it's the method where `typing.Self` is used that binds the typevar. (Each invocation of the method will find a new specialization of `Self` based on the specific instance type containing the invoked method.) This required plumbing through some additional state to the `in_type_expression` method. This also revealed that we weren't handling `Self`-typed instance attributes correctly (but were coincidentally not getting the expected false positive diagnostics).
This commit is contained in:
parent
21ac16db85
commit
585ce12ace
9 changed files with 216 additions and 69 deletions
|
|
@ -365,3 +365,33 @@ def g(x: T) -> T | None:
|
|||
reveal_type(f(g("a"))) # revealed: tuple[Literal["a"] | None, int]
|
||||
reveal_type(g(f("a"))) # revealed: tuple[Literal["a"], int] | None
|
||||
```
|
||||
|
||||
## Opaque decorators don't affect typevar binding
|
||||
|
||||
Inside the body of a generic function, we should be able to see that the typevars bound by that
|
||||
function are in fact bound by that function. This requires being able to see the enclosing
|
||||
function's _undecorated_ type and signature, especially in the case where a gradually typed
|
||||
decorator "hides" the function type from outside callers.
|
||||
|
||||
```py
|
||||
from typing import cast, Any, Callable, TypeVar
|
||||
|
||||
F = TypeVar("F", bound=Callable[..., Any])
|
||||
T = TypeVar("T")
|
||||
|
||||
def opaque_decorator(f: Any) -> Any:
|
||||
return f
|
||||
|
||||
def transparent_decorator(f: F) -> F:
|
||||
return f
|
||||
|
||||
@opaque_decorator
|
||||
def decorated(t: T) -> None:
|
||||
# error: [redundant-cast]
|
||||
reveal_type(cast(T, t)) # revealed: T@decorated
|
||||
|
||||
@transparent_decorator
|
||||
def decorated(t: T) -> None:
|
||||
# error: [redundant-cast]
|
||||
reveal_type(cast(T, t)) # revealed: T@decorated
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue