[red-knot] Callable types are disjoint from literals (#17160)

## Summary

A callable type is disjoint from other literal types. For example,
`Type::StringLiteral` must be an instance of exactly `str`, not a
subclass of `str`, and `str` is not callable. The same applies to other
literal types.

This should hopefully fix #17144, I couldn't produce any failures after
running property tests multiple times.

## Test Plan

Add test cases for disjointness check between callable and other literal
types.

Run property tests multiple times.
This commit is contained in:
Dhruv Manilawala 2025-04-03 03:38:13 +05:30 committed by GitHub
parent 28c68934a4
commit 177afabe18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 0 deletions

View File

@ -379,3 +379,15 @@ static_assert(not is_disjoint_from(Callable[..., None], Callable[[Literal[1]], N
static_assert(not is_disjoint_from(Callable[[], Never], Callable[[], Never])) static_assert(not is_disjoint_from(Callable[[], Never], Callable[[], Never]))
static_assert(not is_disjoint_from(Callable[[Never], str], Callable[[Never], int])) static_assert(not is_disjoint_from(Callable[[Never], str], Callable[[Never], int]))
``` ```
A callable type is disjoint from all literal types.
```py
from knot_extensions import CallableTypeOf, is_disjoint_from, static_assert
from typing_extensions import Callable, Literal, Never
static_assert(is_disjoint_from(Callable[[], None], Literal[""]))
static_assert(is_disjoint_from(Callable[[], None], Literal[b""]))
static_assert(is_disjoint_from(Callable[[], None], Literal[1]))
static_assert(is_disjoint_from(Callable[[], None], Literal[True]))
```

View File

@ -1393,6 +1393,20 @@ impl<'db> Type<'db> {
false false
} }
(
Type::Callable(_),
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
)
| (
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
Type::Callable(_),
) => {
// A callable type is disjoint from other literal types. For example,
// `Type::StringLiteral` must be an instance of exactly `str`, not a subclass
// of `str`, and `str` is not callable. The same applies to other literal types.
true
}
(Type::Callable(_), _) | (_, Type::Callable(_)) => { (Type::Callable(_), _) | (_, Type::Callable(_)) => {
// TODO: Implement disjointness for general callable type with other types // TODO: Implement disjointness for general callable type with other types
false false