Skip to content

Commit ce725c5

Browse files
committed
[red-knot] Disjointness for callable types
1 parent 8396d7c commit ce725c5

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

crates/red_knot_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static_assert(is_disjoint_from(B2, FinalSubclass))
6161
## Tuple types
6262

6363
```py
64-
from typing_extensions import Literal
64+
from typing_extensions import Literal, Never
6565
from knot_extensions import TypeOf, is_disjoint_from, static_assert
6666

6767
static_assert(is_disjoint_from(tuple[()], TypeOf[object]))
@@ -80,6 +80,16 @@ static_assert(is_disjoint_from(tuple[Literal[1], Literal[2]], tuple[Literal[1],
8080
static_assert(not is_disjoint_from(tuple[Literal[1], Literal[2]], tuple[Literal[1], int]))
8181
```
8282

83+
If a tuple type contains a `Never` element, it is considered similar to `Never` itself and is
84+
disjoint from any other type.
85+
86+
```py
87+
static_assert(is_disjoint_from(tuple[Never], tuple[Never]))
88+
static_assert(is_disjoint_from(tuple[int, Never], tuple[int, Never]))
89+
static_assert(is_disjoint_from(tuple[int, Never], tuple[Never, int]))
90+
static_assert(is_disjoint_from(tuple[int, Never], tuple[int, int]))
91+
```
92+
8393
## Unions
8494

8595
```py
@@ -353,3 +363,27 @@ class UsesMeta2(metaclass=Meta2): ...
353363

354364
static_assert(is_disjoint_from(type[UsesMeta1], type[UsesMeta2]))
355365
```
366+
367+
## Callables
368+
369+
No two callable types are disjoint because there exists a callable type
370+
`(*args: object, **kwargs: object) -> Never` that is a subtype of all fully static callable types.
371+
372+
```py
373+
from knot_extensions import CallableTypeOf, is_disjoint_from, static_assert
374+
from typing_extensions import Callable, Literal, Never
375+
376+
def mixed(a: int, /, b: str, *args: int, c: int = 2, **kwargs: int) -> Never: ...
377+
378+
static_assert(not is_disjoint_from(Callable[[], Never], CallableTypeOf[mixed]))
379+
static_assert(not is_disjoint_from(Callable[[int, str], float], CallableTypeOf[mixed]))
380+
381+
# Using gradual form
382+
static_assert(not is_disjoint_from(Callable[..., None], Callable[[], None]))
383+
static_assert(not is_disjoint_from(Callable[..., None], Callable[..., None]))
384+
static_assert(not is_disjoint_from(Callable[..., None], Callable[[Literal[1]], None]))
385+
386+
# Using `Never`
387+
static_assert(not is_disjoint_from(Callable[[], Never], Callable[[], Never]))
388+
static_assert(not is_disjoint_from(Callable[[Never], str], Callable[[Never], int]))
389+
```

crates/red_knot_python_semantic/src/types.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,22 @@ impl<'db> Type<'db> {
12621262
Type::Callable(CallableType::WrapperDescriptorDunderGet),
12631263
) => !KnownClass::WrapperDescriptorType.is_subclass_of(db, class),
12641264

1265+
(
1266+
Type::Callable(CallableType::General(self_callable)),
1267+
Type::Callable(CallableType::General(other_callable)),
1268+
) => {
1269+
// No two callable types are ever disjoint because
1270+
// `(*args: object, **kwargs: object) -> Never` is a subtype of all fully static
1271+
// callable types.
1272+
false
1273+
}
1274+
1275+
(Type::Callable(CallableType::General(_)), _)
1276+
| (_, Type::Callable(CallableType::General(_))) => {
1277+
// TODO: Implement disjointness for general callable types
1278+
false
1279+
}
1280+
12651281
(Type::ModuleLiteral(..), other @ Type::Instance(..))
12661282
| (other @ Type::Instance(..), Type::ModuleLiteral(..)) => {
12671283
// Modules *can* actually be instances of `ModuleType` subclasses
@@ -1298,12 +1314,6 @@ impl<'db> Type<'db> {
12981314
// TODO: add checks for the above cases once we support them
12991315
instance.is_disjoint_from(db, KnownClass::Tuple.to_instance(db))
13001316
}
1301-
1302-
(Type::Callable(CallableType::General(_)), _)
1303-
| (_, Type::Callable(CallableType::General(_))) => {
1304-
// TODO: Implement disjointedness for general callable types
1305-
false
1306-
}
13071317
}
13081318
}
13091319

0 commit comments

Comments
 (0)