From 6f8f7506b47c928b396bd846be62dd707fa4d020 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama <45118249+mtshiba@users.noreply.github.com> Date: Mon, 12 May 2025 22:44:00 +0900 Subject: [PATCH] [ty] fix infinite recursion bug in `is_disjoint_from` (#18043) ## Summary I found this bug while working on #18041. The following code leads to infinite recursion. ```python from ty_extensions import is_disjoint_from, static_assert, TypeOf class C: @property def prop(self) -> int: return 1 static_assert(not is_disjoint_from(int, TypeOf[C.prop])) ``` The cause is a trivial missing binding in `is_disjoint_from`. This PR fixes the bug and adds a test case (this is a simple fix and may not require a new test case?). ## Test Plan A new test case is added to `mdtest/type_properties/is_disjoint_from.md`. --- .../type_properties/is_disjoint_from.md | 23 +++++++++++++++++++ crates/ty_python_semantic/src/types.rs | 8 ++++--- 2 files changed, 28 insertions(+), 3 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 2671887d95..bc9d2b9c27 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 @@ -375,6 +375,29 @@ class UsesMeta2(metaclass=Meta2): ... static_assert(is_disjoint_from(type[UsesMeta1], type[UsesMeta2])) ``` +### `property` + +```py +from ty_extensions import is_disjoint_from, static_assert, TypeOf +from typing import final + +class C: + @property + def prop(self) -> int: + return 1 + +reveal_type(C.prop) # revealed: property + +@final +class D: + pass + +static_assert(not is_disjoint_from(int, TypeOf[C.prop])) +static_assert(not is_disjoint_from(TypeOf[C.prop], int)) +static_assert(is_disjoint_from(TypeOf[C.prop], D)) +static_assert(is_disjoint_from(D, TypeOf[C.prop])) +``` + ## Callables No two callable types are disjoint because there exists a non-empty callable type diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 9dc4b4cc6d..fdbd76539d 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -2101,9 +2101,11 @@ impl<'db> Type<'db> { instance.is_disjoint_from(db, KnownClass::Tuple.to_instance(db)) } - (Type::PropertyInstance(_), _) | (_, Type::PropertyInstance(_)) => KnownClass::Property - .to_instance(db) - .is_disjoint_from(db, other), + (Type::PropertyInstance(_), other) | (other, Type::PropertyInstance(_)) => { + KnownClass::Property + .to_instance(db) + .is_disjoint_from(db, other) + } (Type::BoundSuper(_), Type::BoundSuper(_)) => !self.is_equivalent_to(db, other), (Type::BoundSuper(_), other) | (other, Type::BoundSuper(_)) => KnownClass::Super