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 ca6727815c893c..d80a2b5b828ebd 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 @@ -616,6 +616,31 @@ class BarNone(Protocol): static_assert(is_disjoint_from(type[Foo], BarNone)) ``` +### `NamedTuple` + +```py +from __future__ import annotations + +from typing import NamedTuple, final +from ty_extensions import is_disjoint_from, static_assert + +@final +class Path(NamedTuple): + prev: Path | None + key: str + +@final +class Path2(NamedTuple): + prev: Path2 | None + key: str + +static_assert(not is_disjoint_from(Path, Path)) +static_assert(not is_disjoint_from(Path, tuple[Path | None, str])) +static_assert(is_disjoint_from(Path, tuple[Path | None])) +static_assert(is_disjoint_from(Path, tuple[Path | None, str, int])) +static_assert(is_disjoint_from(Path, Path2)) +``` + ## 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 c2c11c5820f6b2..ad2488a5c5adb3 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -2553,9 +2553,10 @@ impl<'db> Type<'db> { other.is_disjoint_from_impl(db, KnownClass::ModuleType.to_instance(db), visitor) } - (Type::NominalInstance(left), Type::NominalInstance(right)) => { - left.is_disjoint_from_impl(db, right, visitor) - } + (Type::NominalInstance(left), Type::NominalInstance(right)) => visitor + .visit((self, other), || { + left.is_disjoint_from_impl(db, right, visitor) + }), (Type::PropertyInstance(_), other) | (other, Type::PropertyInstance(_)) => { KnownClass::Property