mirror of https://github.com/astral-sh/ruff
[ty] Carry generic context through when converting class into `Callable` (#21798)
When converting a class (whether specialized or not) into a `Callable` type, we should carry through any generic context that the constructor has. This includes both the generic context of the class itself (if it's generic) and of the constructor methods (if they are separately generic). To help test this, this also updates the `generic_context` extension function to work on `Callable` types and unions; and adds a new `into_callable` extension function that works just like `CallableTypeOf`, but on value forms instead of type forms. Pulled this out of #21551 for separate review.
This commit is contained in:
parent
71a7a03ad4
commit
e42cdf8495
|
|
@ -301,6 +301,7 @@ consistent with each other.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
@ -308,6 +309,11 @@ class C(Generic[T]):
|
||||||
def __new__(cls, x: T) -> "C[T]":
|
def __new__(cls, x: T) -> "C[T]":
|
||||||
return object.__new__(cls)
|
return object.__new__(cls)
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -318,12 +324,18 @@ wrong_innards: C[int] = C("five")
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
class C(Generic[T]):
|
class C(Generic[T]):
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -334,6 +346,7 @@ wrong_innards: C[int] = C("five")
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
@ -343,6 +356,11 @@ class C(Generic[T]):
|
||||||
|
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -353,6 +371,7 @@ wrong_innards: C[int] = C("five")
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
@ -362,6 +381,11 @@ class C(Generic[T]):
|
||||||
|
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -373,6 +397,11 @@ class D(Generic[T]):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None: ...
|
def __init__(self, *args, **kwargs) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[int]
|
reveal_type(D(1)) # revealed: D[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
||||||
|
|
@ -386,6 +415,7 @@ to specialize the class.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U")
|
U = TypeVar("U")
|
||||||
|
|
@ -398,6 +428,11 @@ class C(Generic[T, U]):
|
||||||
class D(C[V, int]):
|
class D(C[V, int]):
|
||||||
def __init__(self, x: V) -> None: ...
|
def __init__(self, x: V) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[V@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[V@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[int]
|
reveal_type(D(1)) # revealed: D[int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -405,6 +440,7 @@ reveal_type(D(1)) # revealed: D[int]
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U")
|
U = TypeVar("U")
|
||||||
|
|
@ -415,6 +451,11 @@ class C(Generic[T, U]):
|
||||||
class D(C[T, U]):
|
class D(C[T, U]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(C(1, "str")) # revealed: C[int, str]
|
reveal_type(C(1, "str")) # revealed: C[int, str]
|
||||||
reveal_type(D(1, "str")) # revealed: D[int, str]
|
reveal_type(D(1, "str")) # revealed: D[int, str]
|
||||||
```
|
```
|
||||||
|
|
@ -425,6 +466,7 @@ This is a specific example of the above, since it was reported specifically by a
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U")
|
U = TypeVar("U")
|
||||||
|
|
@ -432,6 +474,11 @@ U = TypeVar("U")
|
||||||
class D(dict[T, U]):
|
class D(dict[T, U]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(key=1)) # revealed: D[str, int]
|
reveal_type(D(key=1)) # revealed: D[str, int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -443,12 +490,18 @@ context. But from the user's point of view, this is another example of the above
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U")
|
U = TypeVar("U")
|
||||||
|
|
||||||
class C(tuple[T, U]): ...
|
class C(tuple[T, U]): ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C((1, 2))) # revealed: C[int, int]
|
reveal_type(C((1, 2))) # revealed: C[int, int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -480,6 +533,7 @@ def func8(t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: t
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
S = TypeVar("S")
|
S = TypeVar("S")
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
@ -487,6 +541,11 @@ T = TypeVar("T")
|
||||||
class C(Generic[T]):
|
class C(Generic[T]):
|
||||||
def __init__(self, x: T, y: S) -> None: ...
|
def __init__(self, x: T, y: S) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, S@__init__]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1, 1)) # revealed: C[int]
|
reveal_type(C(1, 1)) # revealed: C[int]
|
||||||
reveal_type(C(1, "string")) # revealed: C[int]
|
reveal_type(C(1, "string")) # revealed: C[int]
|
||||||
reveal_type(C(1, True)) # revealed: C[int]
|
reveal_type(C(1, True)) # revealed: C[int]
|
||||||
|
|
@ -499,6 +558,7 @@ wrong_innards: C[int] = C("five", 1)
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import overload, Generic, TypeVar
|
from typing_extensions import overload, Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U")
|
U = TypeVar("U")
|
||||||
|
|
@ -514,6 +574,11 @@ class C(Generic[T]):
|
||||||
def __init__(self, x: int) -> None: ...
|
def __init__(self, x: int) -> None: ...
|
||||||
def __init__(self, x: str | bytes | int) -> None: ...
|
def __init__(self, x: str | bytes | int) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C("string")) # revealed: C[str]
|
reveal_type(C("string")) # revealed: C[str]
|
||||||
reveal_type(C(b"bytes")) # revealed: C[bytes]
|
reveal_type(C(b"bytes")) # revealed: C[bytes]
|
||||||
reveal_type(C(12)) # revealed: C[Unknown]
|
reveal_type(C(12)) # revealed: C[Unknown]
|
||||||
|
|
@ -541,6 +606,11 @@ class D(Generic[T, U]):
|
||||||
def __init__(self, t: T, u: U) -> None: ...
|
def __init__(self, t: T, u: U) -> None: ...
|
||||||
def __init__(self, *args) -> None: ...
|
def __init__(self, *args) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D("string")) # revealed: D[str, str]
|
reveal_type(D("string")) # revealed: D[str, str]
|
||||||
reveal_type(D(1)) # revealed: D[str, int]
|
reveal_type(D(1)) # revealed: D[str, int]
|
||||||
reveal_type(D(1, "string")) # revealed: D[int, str]
|
reveal_type(D(1, "string")) # revealed: D[int, str]
|
||||||
|
|
@ -551,6 +621,7 @@ reveal_type(D(1, "string")) # revealed: D[int, str]
|
||||||
```py
|
```py
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
@ -558,6 +629,11 @@ T = TypeVar("T")
|
||||||
class A(Generic[T]):
|
class A(Generic[T]):
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@A]
|
||||||
|
reveal_type(generic_context(A))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@A]
|
||||||
|
reveal_type(generic_context(into_callable(A)))
|
||||||
|
|
||||||
reveal_type(A(x=1)) # revealed: A[int]
|
reveal_type(A(x=1)) # revealed: A[int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -565,17 +641,28 @@ reveal_type(A(x=1)) # revealed: A[int]
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import Generic, TypeVar
|
from typing_extensions import Generic, TypeVar
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
U = TypeVar("U", default=T)
|
U = TypeVar("U", default=T)
|
||||||
|
|
||||||
class C(Generic[T, U]): ...
|
class C(Generic[T, U]): ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C()) # revealed: C[Unknown, Unknown]
|
reveal_type(C()) # revealed: C[Unknown, Unknown]
|
||||||
|
|
||||||
class D(Generic[T, U]):
|
class D(Generic[T, U]):
|
||||||
def __init__(self) -> None: ...
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D()) # revealed: D[Unknown, Unknown]
|
reveal_type(D()) # revealed: D[Unknown, Unknown]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,12 +264,19 @@ signatures don't count towards variance).
|
||||||
### `__new__` only
|
### `__new__` only
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
def __new__(cls, x: T) -> "C[T]":
|
def __new__(cls, x: T) -> "C[T]":
|
||||||
return object.__new__(cls)
|
return object.__new__(cls)
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -279,11 +286,18 @@ wrong_innards: C[int] = C("five")
|
||||||
### `__init__` only
|
### `__init__` only
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -293,6 +307,8 @@ wrong_innards: C[int] = C("five")
|
||||||
### Identical `__new__` and `__init__` signatures
|
### Identical `__new__` and `__init__` signatures
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
|
|
@ -301,6 +317,11 @@ class C[T]:
|
||||||
|
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -310,6 +331,8 @@ wrong_innards: C[int] = C("five")
|
||||||
### Compatible `__new__` and `__init__` signatures
|
### Compatible `__new__` and `__init__` signatures
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
|
|
@ -318,6 +341,11 @@ class C[T]:
|
||||||
|
|
||||||
def __init__(self, x: T) -> None: ...
|
def __init__(self, x: T) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
|
|
@ -331,6 +359,11 @@ class D[T]:
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None: ...
|
def __init__(self, *args, **kwargs) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[int]
|
reveal_type(D(1)) # revealed: D[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
||||||
|
|
@ -343,6 +376,8 @@ If either method comes from a generic base class, we don't currently use its inf
|
||||||
to specialize the class.
|
to specialize the class.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T, U]:
|
class C[T, U]:
|
||||||
def __new__(cls, *args, **kwargs) -> "C[T, U]":
|
def __new__(cls, *args, **kwargs) -> "C[T, U]":
|
||||||
return object.__new__(cls)
|
return object.__new__(cls)
|
||||||
|
|
@ -350,18 +385,30 @@ class C[T, U]:
|
||||||
class D[V](C[V, int]):
|
class D[V](C[V, int]):
|
||||||
def __init__(self, x: V) -> None: ...
|
def __init__(self, x: V) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[V@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[V@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[Literal[1]]
|
reveal_type(D(1)) # revealed: D[Literal[1]]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generic class inherits `__init__` from generic base class
|
### Generic class inherits `__init__` from generic base class
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T, U]:
|
class C[T, U]:
|
||||||
def __init__(self, t: T, u: U) -> None: ...
|
def __init__(self, t: T, u: U) -> None: ...
|
||||||
|
|
||||||
class D[T, U](C[T, U]):
|
class D[T, U](C[T, U]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(C(1, "str")) # revealed: C[Literal[1], Literal["str"]]
|
reveal_type(C(1, "str")) # revealed: C[Literal[1], Literal["str"]]
|
||||||
reveal_type(D(1, "str")) # revealed: D[Literal[1], Literal["str"]]
|
reveal_type(D(1, "str")) # revealed: D[Literal[1], Literal["str"]]
|
||||||
```
|
```
|
||||||
|
|
@ -371,9 +418,16 @@ reveal_type(D(1, "str")) # revealed: D[Literal[1], Literal["str"]]
|
||||||
This is a specific example of the above, since it was reported specifically by a user.
|
This is a specific example of the above, since it was reported specifically by a user.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class D[T, U](dict[T, U]):
|
class D[T, U](dict[T, U]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D(key=1)) # revealed: D[str, int]
|
reveal_type(D(key=1)) # revealed: D[str, int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -384,8 +438,15 @@ for `tuple`, so we use a different mechanism to make sure it has the right inher
|
||||||
context. But from the user's point of view, this is another example of the above.)
|
context. But from the user's point of view, this is another example of the above.)
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T, U](tuple[T, U]): ...
|
class C[T, U](tuple[T, U]): ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C((1, 2))) # revealed: C[Literal[1], Literal[2]]
|
reveal_type(C((1, 2))) # revealed: C[Literal[1], Literal[2]]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -409,11 +470,18 @@ def func8(t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: t
|
||||||
### `__init__` is itself generic
|
### `__init__` is itself generic
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
def __init__[S](self, x: T, y: S) -> None: ...
|
def __init__[S](self, x: T, y: S) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, S@__init__]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C(1, 1)) # revealed: C[int]
|
reveal_type(C(1, 1)) # revealed: C[int]
|
||||||
reveal_type(C(1, "string")) # revealed: C[int]
|
reveal_type(C(1, "string")) # revealed: C[int]
|
||||||
reveal_type(C(1, True)) # revealed: C[int]
|
reveal_type(C(1, True)) # revealed: C[int]
|
||||||
|
|
@ -427,6 +495,7 @@ wrong_innards: C[int] = C("five", 1)
|
||||||
```py
|
```py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import overload
|
from typing import overload
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T]:
|
class C[T]:
|
||||||
# we need to use the type variable or else the class is bivariant in T, and
|
# we need to use the type variable or else the class is bivariant in T, and
|
||||||
|
|
@ -443,6 +512,11 @@ class C[T]:
|
||||||
def __init__(self, x: int) -> None: ...
|
def __init__(self, x: int) -> None: ...
|
||||||
def __init__(self, x: str | bytes | int) -> None: ...
|
def __init__(self, x: str | bytes | int) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C("string")) # revealed: C[str]
|
reveal_type(C("string")) # revealed: C[str]
|
||||||
reveal_type(C(b"bytes")) # revealed: C[bytes]
|
reveal_type(C(b"bytes")) # revealed: C[bytes]
|
||||||
reveal_type(C(12)) # revealed: C[Unknown]
|
reveal_type(C(12)) # revealed: C[Unknown]
|
||||||
|
|
@ -470,6 +544,11 @@ class D[T, U]:
|
||||||
def __init__(self, t: T, u: U) -> None: ...
|
def __init__(self, t: T, u: U) -> None: ...
|
||||||
def __init__(self, *args) -> None: ...
|
def __init__(self, *args) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D("string")) # revealed: D[str, Literal["string"]]
|
reveal_type(D("string")) # revealed: D[str, Literal["string"]]
|
||||||
reveal_type(D(1)) # revealed: D[str, Literal[1]]
|
reveal_type(D(1)) # revealed: D[str, Literal[1]]
|
||||||
reveal_type(D(1, "string")) # revealed: D[Literal[1], Literal["string"]]
|
reveal_type(D(1, "string")) # revealed: D[Literal[1], Literal["string"]]
|
||||||
|
|
@ -479,24 +558,42 @@ reveal_type(D(1, "string")) # revealed: D[Literal[1], Literal["string"]]
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class A[T]:
|
class A[T]:
|
||||||
x: T
|
x: T
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@A]
|
||||||
|
reveal_type(generic_context(A))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@A]
|
||||||
|
reveal_type(generic_context(into_callable(A)))
|
||||||
|
|
||||||
reveal_type(A(x=1)) # revealed: A[int]
|
reveal_type(A(x=1)) # revealed: A[int]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Class typevar has another typevar as a default
|
### Class typevar has another typevar as a default
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from ty_extensions import generic_context, into_callable
|
||||||
|
|
||||||
class C[T, U = T]: ...
|
class C[T, U = T]: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(C))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@C, U@C]
|
||||||
|
reveal_type(generic_context(into_callable(C)))
|
||||||
|
|
||||||
reveal_type(C()) # revealed: C[Unknown, Unknown]
|
reveal_type(C()) # revealed: C[Unknown, Unknown]
|
||||||
|
|
||||||
class D[T, U = T]:
|
class D[T, U = T]:
|
||||||
def __init__(self) -> None: ...
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(D))
|
||||||
|
# revealed: ty_extensions.GenericContext[T@D, U@D]
|
||||||
|
reveal_type(generic_context(into_callable(D)))
|
||||||
|
|
||||||
reveal_type(D()) # revealed: D[Unknown, Unknown]
|
reveal_type(D()) # revealed: D[Unknown, Unknown]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,8 @@ class E(A[int]):
|
||||||
def method(self, x: object) -> None: ... # fine
|
def method(self, x: object) -> None: ... # fine
|
||||||
|
|
||||||
class F[T](A[T]):
|
class F[T](A[T]):
|
||||||
# TODO: we should emit `invalid-method-override` on this:
|
|
||||||
# `str` is not necessarily a supertype of `T`!
|
# `str` is not necessarily a supertype of `T`!
|
||||||
|
# error: [invalid-method-override]
|
||||||
def method(self, x: str) -> None: ...
|
def method(self, x: str) -> None: ...
|
||||||
|
|
||||||
class G(A[int]):
|
class G(A[int]):
|
||||||
|
|
|
||||||
|
|
@ -8535,12 +8535,9 @@ impl<'db> TypeMapping<'_, 'db> {
|
||||||
| TypeMapping::Materialize(_)
|
| TypeMapping::Materialize(_)
|
||||||
| TypeMapping::ReplaceParameterDefaults
|
| TypeMapping::ReplaceParameterDefaults
|
||||||
| TypeMapping::EagerExpansion => context,
|
| TypeMapping::EagerExpansion => context,
|
||||||
TypeMapping::BindSelf { .. } => GenericContext::from_typevar_instances(
|
TypeMapping::BindSelf {
|
||||||
db,
|
binding_context, ..
|
||||||
context
|
} => context.remove_self(db, *binding_context),
|
||||||
.variables(db)
|
|
||||||
.filter(|var| !var.typevar(db).is_self(db)),
|
|
||||||
),
|
|
||||||
TypeMapping::ReplaceSelf { new_upper_bound } => GenericContext::from_typevar_instances(
|
TypeMapping::ReplaceSelf { new_upper_bound } => GenericContext::from_typevar_instances(
|
||||||
db,
|
db,
|
||||||
context.variables(db).map(|typevar| {
|
context.variables(db).map(|typevar| {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,9 @@ use crate::types::function::{
|
||||||
use crate::types::generics::{
|
use crate::types::generics::{
|
||||||
InferableTypeVars, Specialization, SpecializationBuilder, SpecializationError,
|
InferableTypeVars, Specialization, SpecializationBuilder, SpecializationError,
|
||||||
};
|
};
|
||||||
use crate::types::signatures::{Parameter, ParameterForm, ParameterKind, Parameters};
|
use crate::types::signatures::{
|
||||||
|
CallableSignature, Parameter, ParameterForm, ParameterKind, Parameters,
|
||||||
|
};
|
||||||
use crate::types::tuple::{TupleLength, TupleType};
|
use crate::types::tuple::{TupleLength, TupleType};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundMethodType, BoundTypeVarIdentity, ClassLiteral, DATACLASS_FLAGS, DataclassFlags,
|
BoundMethodType, BoundTypeVarIdentity, ClassLiteral, DATACLASS_FLAGS, DataclassFlags,
|
||||||
|
|
@ -788,51 +790,67 @@ impl<'db> Bindings<'db> {
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_generic_context = |function: FunctionType<'db>| {
|
let signature_generic_context =
|
||||||
let union = UnionType::from_elements(
|
|signature: &CallableSignature<'db>| {
|
||||||
db,
|
UnionType::try_from_elements(
|
||||||
function
|
db,
|
||||||
.signature(db)
|
signature.overloads.iter().map(|signature| {
|
||||||
.overloads
|
signature.generic_context.map(wrap_generic_context)
|
||||||
.iter()
|
}),
|
||||||
.filter_map(|signature| signature.generic_context)
|
)
|
||||||
.map(wrap_generic_context),
|
};
|
||||||
);
|
|
||||||
if union.is_never() {
|
|
||||||
Type::none(db)
|
|
||||||
} else {
|
|
||||||
union
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Handle generic functions, and unions/intersections of
|
let generic_context_for_simple_type = |ty: Type<'db>| match ty {
|
||||||
// generic types
|
Type::ClassLiteral(class) => {
|
||||||
overload.set_return_type(match ty {
|
class.generic_context(db).map(wrap_generic_context)
|
||||||
Type::ClassLiteral(class) => class
|
}
|
||||||
.generic_context(db)
|
|
||||||
.map(wrap_generic_context)
|
|
||||||
.unwrap_or_else(|| Type::none(db)),
|
|
||||||
|
|
||||||
Type::FunctionLiteral(function) => {
|
Type::FunctionLiteral(function) => {
|
||||||
function_generic_context(*function)
|
signature_generic_context(function.signature(db))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::BoundMethod(bound_method) => {
|
Type::BoundMethod(bound_method) => signature_generic_context(
|
||||||
function_generic_context(bound_method.function(db))
|
bound_method.function(db).signature(db),
|
||||||
|
),
|
||||||
|
|
||||||
|
Type::Callable(callable) => {
|
||||||
|
signature_generic_context(callable.signatures(db))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||||
TypeAliasType::PEP695(alias),
|
TypeAliasType::PEP695(alias),
|
||||||
)) => alias
|
)) => alias.generic_context(db).map(wrap_generic_context),
|
||||||
.generic_context(db)
|
|
||||||
.map(wrap_generic_context)
|
|
||||||
.unwrap_or_else(|| Type::none(db)),
|
|
||||||
|
|
||||||
_ => Type::none(db),
|
_ => None,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let generic_context = match ty {
|
||||||
|
Type::Union(union_type) => UnionType::try_from_elements(
|
||||||
|
db,
|
||||||
|
union_type
|
||||||
|
.elements(db)
|
||||||
|
.iter()
|
||||||
|
.map(|ty| generic_context_for_simple_type(*ty)),
|
||||||
|
),
|
||||||
|
_ => generic_context_for_simple_type(*ty),
|
||||||
|
};
|
||||||
|
|
||||||
|
overload.set_return_type(
|
||||||
|
generic_context.unwrap_or_else(|| Type::none(db)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(KnownFunction::IntoCallable) => {
|
||||||
|
let [Some(ty)] = overload.parameter_types() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(callables) = ty.try_upcast_to_callable(db) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
overload.set_return_type(callables.into_type(db));
|
||||||
|
}
|
||||||
|
|
||||||
Some(KnownFunction::DunderAllNames) => {
|
Some(KnownFunction::DunderAllNames) => {
|
||||||
if let [Some(ty)] = overload.parameter_types() {
|
if let [Some(ty)] = overload.parameter_types() {
|
||||||
overload.set_return_type(match ty {
|
overload.set_return_type(match ty {
|
||||||
|
|
|
||||||
|
|
@ -1133,6 +1133,13 @@ impl<'db> ClassType<'db> {
|
||||||
/// constructor signature of this class.
|
/// constructor signature of this class.
|
||||||
#[salsa::tracked(cycle_initial=into_callable_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
#[salsa::tracked(cycle_initial=into_callable_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||||
pub(super) fn into_callable(self, db: &'db dyn Db) -> CallableTypes<'db> {
|
pub(super) fn into_callable(self, db: &'db dyn Db) -> CallableTypes<'db> {
|
||||||
|
// TODO: This mimics a lot of the logic in Type::try_call_from_constructor. Can we
|
||||||
|
// consolidate the two? Can we invoke a class by upcasting the class into a Callable, and
|
||||||
|
// then relying on the call binding machinery to Just Work™?
|
||||||
|
|
||||||
|
let (class_literal, _) = self.class_literal(db);
|
||||||
|
let class_generic_context = class_literal.generic_context(db);
|
||||||
|
|
||||||
let self_ty = Type::from(self);
|
let self_ty = Type::from(self);
|
||||||
let metaclass_dunder_call_function_symbol = self_ty
|
let metaclass_dunder_call_function_symbol = self_ty
|
||||||
.member_lookup_with_policy(
|
.member_lookup_with_policy(
|
||||||
|
|
@ -1206,39 +1213,58 @@ impl<'db> ClassType<'db> {
|
||||||
// If the class defines an `__init__` method, then we synthesize a callable type with the
|
// If the class defines an `__init__` method, then we synthesize a callable type with the
|
||||||
// same parameters as the `__init__` method after it is bound, and with the return type of
|
// same parameters as the `__init__` method after it is bound, and with the return type of
|
||||||
// the concrete type of `Self`.
|
// the concrete type of `Self`.
|
||||||
let synthesized_dunder_init_callable =
|
let synthesized_dunder_init_callable = if let Place::Defined(ty, _, _) =
|
||||||
if let Place::Defined(ty, _, _) = dunder_init_function_symbol {
|
dunder_init_function_symbol
|
||||||
let signature = match ty {
|
{
|
||||||
Type::FunctionLiteral(dunder_init_function) => {
|
let signature = match ty {
|
||||||
Some(dunder_init_function.signature(db))
|
Type::FunctionLiteral(dunder_init_function) => {
|
||||||
}
|
Some(dunder_init_function.signature(db))
|
||||||
Type::Callable(callable) => Some(callable.signatures(db)),
|
}
|
||||||
_ => None,
|
Type::Callable(callable) => Some(callable.signatures(db)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(signature) = signature {
|
||||||
|
let synthesized_signature = |signature: &Signature<'db>| {
|
||||||
|
let self_annotation = signature
|
||||||
|
.parameters()
|
||||||
|
.get_positional(0)
|
||||||
|
.and_then(Parameter::annotated_type)
|
||||||
|
.filter(|ty| {
|
||||||
|
ty.as_typevar()
|
||||||
|
.is_none_or(|bound_typevar| !bound_typevar.typevar(db).is_self(db))
|
||||||
|
});
|
||||||
|
let return_type = self_annotation.unwrap_or(correct_return_type);
|
||||||
|
let instance_ty = self_annotation.unwrap_or_else(|| Type::instance(db, self));
|
||||||
|
let generic_context = GenericContext::merge_optional(
|
||||||
|
db,
|
||||||
|
class_generic_context,
|
||||||
|
signature.generic_context,
|
||||||
|
);
|
||||||
|
Signature::new_generic(
|
||||||
|
generic_context,
|
||||||
|
signature.parameters().clone(),
|
||||||
|
Some(return_type),
|
||||||
|
)
|
||||||
|
.with_definition(signature.definition())
|
||||||
|
.bind_self(db, Some(instance_ty))
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(signature) = signature {
|
let synthesized_dunder_init_signature = CallableSignature::from_overloads(
|
||||||
let synthesized_signature = |signature: &Signature<'db>| {
|
signature.overloads.iter().map(synthesized_signature),
|
||||||
let instance_ty = Type::instance(db, self);
|
);
|
||||||
Signature::new(signature.parameters().clone(), Some(correct_return_type))
|
|
||||||
.with_definition(signature.definition())
|
|
||||||
.bind_self(db, Some(instance_ty))
|
|
||||||
};
|
|
||||||
|
|
||||||
let synthesized_dunder_init_signature = CallableSignature::from_overloads(
|
Some(CallableType::new(
|
||||||
signature.overloads.iter().map(synthesized_signature),
|
db,
|
||||||
);
|
synthesized_dunder_init_signature,
|
||||||
|
true,
|
||||||
Some(CallableType::new(
|
))
|
||||||
db,
|
|
||||||
synthesized_dunder_init_signature,
|
|
||||||
true,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
match (dunder_new_function, synthesized_dunder_init_callable) {
|
match (dunder_new_function, synthesized_dunder_init_callable) {
|
||||||
(Some(dunder_new_function), Some(synthesized_dunder_init_callable)) => {
|
(Some(dunder_new_function), Some(synthesized_dunder_init_callable)) => {
|
||||||
|
|
@ -1261,9 +1287,13 @@ impl<'db> ClassType<'db> {
|
||||||
)
|
)
|
||||||
.place;
|
.place;
|
||||||
|
|
||||||
if let Place::Defined(Type::FunctionLiteral(new_function), _, _) =
|
if let Place::Defined(Type::FunctionLiteral(mut new_function), _, _) =
|
||||||
new_function_symbol
|
new_function_symbol
|
||||||
{
|
{
|
||||||
|
if let Some(class_generic_context) = class_generic_context {
|
||||||
|
new_function =
|
||||||
|
new_function.with_inherited_generic_context(db, class_generic_context);
|
||||||
|
}
|
||||||
CallableTypes::one(
|
CallableTypes::one(
|
||||||
new_function
|
new_function
|
||||||
.into_bound_method_type(db, correct_return_type)
|
.into_bound_method_type(db, correct_return_type)
|
||||||
|
|
@ -1273,7 +1303,11 @@ impl<'db> ClassType<'db> {
|
||||||
// Fallback if no `object.__new__` is found.
|
// Fallback if no `object.__new__` is found.
|
||||||
CallableTypes::one(CallableType::single(
|
CallableTypes::one(CallableType::single(
|
||||||
db,
|
db,
|
||||||
Signature::new(Parameters::empty(), Some(correct_return_type)),
|
Signature::new_generic(
|
||||||
|
class_generic_context,
|
||||||
|
Parameters::empty(),
|
||||||
|
Some(correct_return_type),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,8 @@ pub enum KnownFunction {
|
||||||
IsSingleValued,
|
IsSingleValued,
|
||||||
/// `ty_extensions.generic_context`
|
/// `ty_extensions.generic_context`
|
||||||
GenericContext,
|
GenericContext,
|
||||||
|
/// `ty_extensions.into_callable`
|
||||||
|
IntoCallable,
|
||||||
/// `ty_extensions.dunder_all_names`
|
/// `ty_extensions.dunder_all_names`
|
||||||
DunderAllNames,
|
DunderAllNames,
|
||||||
/// `ty_extensions.enum_members`
|
/// `ty_extensions.enum_members`
|
||||||
|
|
@ -1411,6 +1413,7 @@ impl KnownFunction {
|
||||||
| Self::IsSingleton
|
| Self::IsSingleton
|
||||||
| Self::IsSubtypeOf
|
| Self::IsSubtypeOf
|
||||||
| Self::GenericContext
|
| Self::GenericContext
|
||||||
|
| Self::IntoCallable
|
||||||
| Self::DunderAllNames
|
| Self::DunderAllNames
|
||||||
| Self::EnumMembers
|
| Self::EnumMembers
|
||||||
| Self::StaticAssert
|
| Self::StaticAssert
|
||||||
|
|
@ -1946,6 +1949,7 @@ pub(crate) mod tests {
|
||||||
KnownFunction::IsSingleton
|
KnownFunction::IsSingleton
|
||||||
| KnownFunction::IsSubtypeOf
|
| KnownFunction::IsSubtypeOf
|
||||||
| KnownFunction::GenericContext
|
| KnownFunction::GenericContext
|
||||||
|
| KnownFunction::IntoCallable
|
||||||
| KnownFunction::DunderAllNames
|
| KnownFunction::DunderAllNames
|
||||||
| KnownFunction::EnumMembers
|
| KnownFunction::EnumMembers
|
||||||
| KnownFunction::StaticAssert
|
| KnownFunction::StaticAssert
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ use crate::types::signatures::Parameters;
|
||||||
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
||||||
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
|
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ApplyTypeMappingVisitor, BoundTypeVarIdentity, BoundTypeVarInstance, ClassLiteral,
|
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarIdentity, BoundTypeVarInstance,
|
||||||
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor,
|
ClassLiteral, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor,
|
||||||
KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, Type, TypeContext,
|
IsEquivalentVisitor, KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor,
|
||||||
TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, TypeVarInstance,
|
Type, TypeContext, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity,
|
||||||
TypeVarKind, TypeVarVariance, UnionType, declaration_type, walk_bound_type_var_type,
|
TypeVarInstance, TypeVarKind, TypeVarVariance, UnionType, declaration_type,
|
||||||
|
walk_bound_type_var_type,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderMap, FxOrderSet};
|
use crate::{Db, FxOrderMap, FxOrderSet};
|
||||||
|
|
||||||
|
|
@ -261,6 +262,34 @@ impl<'db> GenericContext<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn merge_optional(
|
||||||
|
db: &'db dyn Db,
|
||||||
|
left: Option<Self>,
|
||||||
|
right: Option<Self>,
|
||||||
|
) -> Option<Self> {
|
||||||
|
match (left, right) {
|
||||||
|
(None, None) => None,
|
||||||
|
(Some(one), None) | (None, Some(one)) => Some(one),
|
||||||
|
(Some(left), Some(right)) => Some(left.merge(db, right)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_self(
|
||||||
|
self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
binding_context: Option<BindingContext<'db>>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_typevar_instances(
|
||||||
|
db,
|
||||||
|
self.variables(db).filter(|bound_typevar| {
|
||||||
|
!(bound_typevar.typevar(db).is_self(db)
|
||||||
|
&& binding_context.is_none_or(|binding_context| {
|
||||||
|
bound_typevar.binding_context(db) == binding_context
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn inferable_typevars(self, db: &'db dyn Db) -> InferableTypeVars<'db, 'db> {
|
pub(crate) fn inferable_typevars(self, db: &'db dyn Db) -> InferableTypeVars<'db, 'db> {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct CollectTypeVars<'db> {
|
struct CollectTypeVars<'db> {
|
||||||
|
|
|
||||||
|
|
@ -667,10 +667,11 @@ impl<'db> Signature<'db> {
|
||||||
|
|
||||||
let mut parameters = Parameters::new(db, parameters);
|
let mut parameters = Parameters::new(db, parameters);
|
||||||
let mut return_ty = self.return_ty;
|
let mut return_ty = self.return_ty;
|
||||||
|
let binding_context = self.definition.map(BindingContext::Definition);
|
||||||
if let Some(self_type) = self_type {
|
if let Some(self_type) = self_type {
|
||||||
let self_mapping = TypeMapping::BindSelf {
|
let self_mapping = TypeMapping::BindSelf {
|
||||||
self_type,
|
self_type,
|
||||||
binding_context: self.definition.map(BindingContext::Definition),
|
binding_context,
|
||||||
};
|
};
|
||||||
parameters = parameters.apply_type_mapping_impl(
|
parameters = parameters.apply_type_mapping_impl(
|
||||||
db,
|
db,
|
||||||
|
|
@ -682,7 +683,9 @@ impl<'db> Signature<'db> {
|
||||||
.map(|ty| ty.apply_type_mapping(db, &self_mapping, TypeContext::default()));
|
.map(|ty| ty.apply_type_mapping(db, &self_mapping, TypeContext::default()));
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
generic_context: self.generic_context,
|
generic_context: self
|
||||||
|
.generic_context
|
||||||
|
.map(|generic_context| generic_context.remove_self(db, binding_context)),
|
||||||
definition: self.definition,
|
definition: self.definition,
|
||||||
parameters,
|
parameters,
|
||||||
return_ty,
|
return_ty,
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,10 @@ def is_single_valued(ty: Any) -> bool:
|
||||||
# type is not generic.
|
# type is not generic.
|
||||||
def generic_context(ty: Any) -> GenericContext | None: ...
|
def generic_context(ty: Any) -> GenericContext | None: ...
|
||||||
|
|
||||||
|
# Converts a value into a `Callable`, if possible. This is the value equivalent
|
||||||
|
# of `CallableTypeOf`, which operates on types.
|
||||||
|
def into_callable(ty: Any) -> Any: ...
|
||||||
|
|
||||||
# Returns the `__all__` names of a module as a tuple of sorted strings, or `None` if
|
# Returns the `__all__` names of a module as a tuple of sorted strings, or `None` if
|
||||||
# either the module does not have `__all__` or it has invalid elements.
|
# either the module does not have `__all__` or it has invalid elements.
|
||||||
def dunder_all_names(module: Any) -> Any: ...
|
def dunder_all_names(module: Any) -> Any: ...
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue