From 592a6744476b122392d87a84c91e7dc710643c00 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 17 Dec 2025 09:21:25 -0600 Subject: [PATCH 1/5] [ty] Cache `ClassType::nearest_disjoint_base` --- crates/ty_python_semantic/src/types/class.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index dd6b192d2d123..7198b8faa9a32 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -716,6 +716,7 @@ impl<'db> ClassType<'db> { /// Return the [`DisjointBase`] that appears first in the MRO of this class. /// /// Returns `None` if this class does not have any disjoint bases in its MRO. + #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] pub(super) fn nearest_disjoint_base(self, db: &'db dyn Db) -> Option> { self.iter_mro(db) .filter_map(ClassBase::into_class) @@ -4124,7 +4125,7 @@ impl InheritanceCycle { /// `TypeError`s resulting from class definitions. /// /// [PEP 800]: https://peps.python.org/pep-0800/ -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, get_size2::GetSize, salsa::Update)] pub(super) struct DisjointBase<'db> { pub(super) class: ClassLiteral<'db>, pub(super) kind: DisjointBaseKind, @@ -4161,7 +4162,7 @@ impl<'db> DisjointBase<'db> { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, get_size2::GetSize, salsa::Update)] pub(super) enum DisjointBaseKind { /// We know the class is a disjoint base because it's either hardcoded in ty /// or has the `@disjoint_base` decorator. From 3c2f5344803b3b2eb26bb423e6fb9cf1cb0fc874 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 17 Dec 2025 09:22:17 -0600 Subject: [PATCH 2/5] [ty] Cache `Type::is_subtype_of` --- crates/ty_python_semantic/src/types.rs | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 40451a0736b30..6e08e6e27730f 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -1952,8 +1952,22 @@ impl<'db> Type<'db> { /// /// See [`TypeRelation::Subtyping`] for more details. pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool { - self.when_subtype_of(db, target, InferableTypeVars::None) - .is_always_satisfied(db) + #[salsa::tracked(cycle_initial=is_subtype_of_cycle_initial, heap_size=ruff_memory_usage::heap_size)] + fn is_subtype_of_impl<'db>( + db: &'db dyn Db, + self_ty: Type<'db>, + target: Type<'db>, + ) -> bool { + self_ty + .when_subtype_of(db, target, InferableTypeVars::None) + .is_always_satisfied(db) + } + + if self == target { + return true; + } + + is_subtype_of_impl(db, self, target) } fn when_subtype_of( @@ -8689,6 +8703,16 @@ impl<'db> VarianceInferable<'db> for Type<'db> { } } +#[allow(clippy::trivially_copy_pass_by_ref)] +fn is_subtype_of_cycle_initial<'db>( + _db: &'db dyn Db, + _id: salsa::Id, + _self_ty: Type<'db>, + _target: Type<'db>, +) -> bool { + false +} + #[allow(clippy::trivially_copy_pass_by_ref)] fn is_redundant_with_cycle_initial<'db>( _db: &'db dyn Db, From 81f39680d2f0b068e70e390c8053c47888eee618 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 17 Dec 2025 09:25:04 -0600 Subject: [PATCH 3/5] [ty] Cache `Type::is_disjoint_from` --- crates/ty_python_semantic/src/types.rs | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 6e08e6e27730f..43aa867fcdd55 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -3238,8 +3238,22 @@ impl<'db> Type<'db> { /// This function aims to have no false positives, but might return wrong /// `false` answers in some cases. pub(crate) fn is_disjoint_from(self, db: &'db dyn Db, other: Type<'db>) -> bool { - self.when_disjoint_from(db, other, InferableTypeVars::None) - .is_always_satisfied(db) + #[salsa::tracked(cycle_initial=is_disjoint_from_cycle_initial, heap_size=ruff_memory_usage::heap_size)] + fn is_disjoint_from_cached<'db>( + db: &'db dyn Db, + self_ty: Type<'db>, + other: Type<'db>, + ) -> bool { + self_ty + .when_disjoint_from(db, other, InferableTypeVars::None) + .is_always_satisfied(db) + } + + if self == other { + return false; + } + + is_disjoint_from_cached(db, self, other) } fn when_disjoint_from( @@ -8713,6 +8727,16 @@ fn is_subtype_of_cycle_initial<'db>( false } +#[allow(clippy::trivially_copy_pass_by_ref)] +fn is_disjoint_from_cycle_initial<'db>( + _db: &'db dyn Db, + _id: salsa::Id, + _self_ty: Type<'db>, + _other: Type<'db>, +) -> bool { + false +} + #[allow(clippy::trivially_copy_pass_by_ref)] fn is_redundant_with_cycle_initial<'db>( _db: &'db dyn Db, From 7d4831597be4eea0214a0f7416af42c59ac42968 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Thu, 18 Dec 2025 08:28:53 -0600 Subject: [PATCH 4/5] Lint --- crates/ty_python_semantic/src/types.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 43aa867fcdd55..2f7d7a6cabc5f 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -1953,11 +1953,7 @@ impl<'db> Type<'db> { /// See [`TypeRelation::Subtyping`] for more details. pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool { #[salsa::tracked(cycle_initial=is_subtype_of_cycle_initial, heap_size=ruff_memory_usage::heap_size)] - fn is_subtype_of_impl<'db>( - db: &'db dyn Db, - self_ty: Type<'db>, - target: Type<'db>, - ) -> bool { + fn is_subtype_of_impl<'db>(db: &'db dyn Db, self_ty: Type<'db>, target: Type<'db>) -> bool { self_ty .when_subtype_of(db, target, InferableTypeVars::None) .is_always_satisfied(db) From 6c2d87ed8076d7fb5f7b6f3bde09cbaaac3b23c5 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Thu, 18 Dec 2025 09:59:00 -0600 Subject: [PATCH 5/5] Invert case --- crates/ty_python_semantic/src/types/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 9e674065b9253..9322edfbfbcc9 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -720,7 +720,7 @@ impl<'db> ProtocolInstanceType<'db> { _value: ProtocolInstanceType<'db>, _: (), ) -> bool { - true + false } is_equivalent_to_object_inner(db, self, ())