From 77c8ddf10189aff5511dcf60fb427ea6a6e711fb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 30 May 2025 16:49:20 +0100 Subject: [PATCH] [ty] Fix broken property tests for disjointness (#18384) --- .../type_properties/is_disjoint_from.md | 11 ++++++++++ crates/ty_python_semantic/src/types.rs | 21 +++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md b/crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md index 46cf9c9074..a39826671b 100644 --- a/crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md +++ b/crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md @@ -454,15 +454,23 @@ static_assert(is_disjoint_from(bool, Callable[..., Any])) static_assert(is_disjoint_from(C, Callable[..., Any])) static_assert(is_disjoint_from(bool | C, Callable[..., Any])) +static_assert(is_disjoint_from(Callable[..., Any], bool)) +static_assert(is_disjoint_from(Callable[..., Any], C)) +static_assert(is_disjoint_from(Callable[..., Any], bool | C)) + static_assert(not is_disjoint_from(str, Callable[..., Any])) static_assert(not is_disjoint_from(bool | str, Callable[..., Any])) +static_assert(not is_disjoint_from(Callable[..., Any], str)) +static_assert(not is_disjoint_from(Callable[..., Any], bool | str)) + def bound_with_valid_type(): @final class D: def __call__(self, *args: Any, **kwargs: Any) -> Any: ... static_assert(not is_disjoint_from(D, Callable[..., Any])) + static_assert(not is_disjoint_from(Callable[..., Any], D)) def possibly_unbound_with_valid_type(flag: bool): @final @@ -471,6 +479,7 @@ def possibly_unbound_with_valid_type(flag: bool): def __call__(self, *args: Any, **kwargs: Any) -> Any: ... static_assert(not is_disjoint_from(E, Callable[..., Any])) + static_assert(not is_disjoint_from(Callable[..., Any], E)) def bound_with_invalid_type(): @final @@ -478,6 +487,7 @@ def bound_with_invalid_type(): __call__: int = 1 static_assert(is_disjoint_from(F, Callable[..., Any])) + static_assert(is_disjoint_from(Callable[..., Any], F)) def possibly_unbound_with_invalid_type(flag: bool): @final @@ -486,4 +496,5 @@ def possibly_unbound_with_invalid_type(flag: bool): __call__: int = 1 static_assert(is_disjoint_from(G, Callable[..., Any])) + static_assert(is_disjoint_from(Callable[..., Any], G)) ``` diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index f885b45f58..f125540688 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -2180,23 +2180,22 @@ impl<'db> Type<'db> { ( Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_), - Type::NominalInstance(instance), + instance @ Type::NominalInstance(NominalInstanceType { class, .. }), ) | ( - Type::NominalInstance(instance), + instance @ Type::NominalInstance(NominalInstanceType { class, .. }), Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_), - ) if instance.class.is_final(db) => { - let member = self.member_lookup_with_policy( + ) if class.is_final(db) => instance + .member_lookup_with_policy( db, Name::new_static("__call__"), MemberLookupPolicy::NO_INSTANCE_FALLBACK, - ); - match member.symbol { - // TODO: ideally this would check disjointness of the `__call__` signature and the callable signature - Symbol::Type(ty, _) => !ty.is_assignable_to(db, CallableType::unknown(db)), - Symbol::Unbound => true, - } - } + ) + .symbol + .ignore_possibly_unbound() + .is_none_or(|dunder_call| { + !dunder_call.is_assignable_to(db, CallableType::unknown(db)) + }), ( Type::Callable(_) | Type::DataclassDecorator(_) | Type::DataclassTransformer(_),