From 177afabe18ea9b067ecaf0419c87f968b4aa8176 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 3 Apr 2025 03:38:13 +0530 Subject: [PATCH] [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. --- .../mdtest/type_properties/is_disjoint_from.md | 12 ++++++++++++ crates/red_knot_python_semantic/src/types.rs | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md index 479bf0efb2..fb5fe478cf 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md @@ -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], 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])) +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 2bed15f04b..1a2017a618 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -1393,6 +1393,20 @@ impl<'db> Type<'db> { 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(_)) => { // TODO: Implement disjointness for general callable type with other types false