mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 14:52:01 +00:00
[red-knot] Disjointness for callable types (#17094)
## Summary Part of #15382, this PR adds support for disjointness between two callable types. They are never disjoint because there exists a callable type that's a subtype of all other callable types: ```py (*args: object, **kwargs: object) -> Never ``` The `Never` is a subtype of every fully static type thus a callable type that has the return type of `Never` means that it is a subtype of every return type. ## Test Plan Add test cases related to mixed parameter kinds, gradual form (`...`) and `Never` type.
This commit is contained in:
parent
d6dcc377f7
commit
6be0a5057d
3 changed files with 55 additions and 6 deletions
|
@ -0,0 +1,15 @@
|
|||
# Tuple
|
||||
|
||||
## `Never`
|
||||
|
||||
If a tuple type contains a `Never` element, then it is eagerly simplified to `Never` which means
|
||||
that a tuple type containing `Never` is disjoint from any other tuple type.
|
||||
|
||||
```py
|
||||
from typing_extensions import Never
|
||||
|
||||
def _(x: tuple[Never], y: tuple[int, Never], z: tuple[Never, int]):
|
||||
reveal_type(x) # revealed: Never
|
||||
reveal_type(y) # revealed: Never
|
||||
reveal_type(z) # revealed: Never
|
||||
```
|
|
@ -61,7 +61,7 @@ static_assert(is_disjoint_from(B2, FinalSubclass))
|
|||
## Tuple types
|
||||
|
||||
```py
|
||||
from typing_extensions import Literal
|
||||
from typing_extensions import Literal, Never
|
||||
from knot_extensions import TypeOf, is_disjoint_from, static_assert
|
||||
|
||||
static_assert(is_disjoint_from(tuple[()], TypeOf[object]))
|
||||
|
@ -353,3 +353,29 @@ class UsesMeta2(metaclass=Meta2): ...
|
|||
|
||||
static_assert(is_disjoint_from(type[UsesMeta1], type[UsesMeta2]))
|
||||
```
|
||||
|
||||
## Callables
|
||||
|
||||
No two callable types are disjoint because there exists a non-empty callable type
|
||||
`(*args: object, **kwargs: object) -> Never` that is a subtype of all fully static callable types.
|
||||
As such, for any two callable types, it is possible to conceive of a runtime callable object that
|
||||
would inhabit both types simultaneously.
|
||||
|
||||
```py
|
||||
from knot_extensions import CallableTypeOf, is_disjoint_from, static_assert
|
||||
from typing_extensions import Callable, Literal, Never
|
||||
|
||||
def mixed(a: int, /, b: str, *args: int, c: int = 2, **kwargs: int) -> None: ...
|
||||
|
||||
static_assert(not is_disjoint_from(Callable[[], Never], CallableTypeOf[mixed]))
|
||||
static_assert(not is_disjoint_from(Callable[[int, str], float], CallableTypeOf[mixed]))
|
||||
|
||||
# Using gradual form
|
||||
static_assert(not is_disjoint_from(Callable[..., None], Callable[[], None]))
|
||||
static_assert(not is_disjoint_from(Callable[..., None], Callable[..., None]))
|
||||
static_assert(not is_disjoint_from(Callable[..., None], Callable[[Literal[1]], None]))
|
||||
|
||||
# Using `Never`
|
||||
static_assert(not is_disjoint_from(Callable[[], Never], Callable[[], Never]))
|
||||
static_assert(not is_disjoint_from(Callable[[Never], str], Callable[[Never], int]))
|
||||
```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue