diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 40451a0736b30..2f7d7a6cabc5f 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -1952,8 +1952,18 @@ 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( @@ -3224,8 +3234,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( @@ -8689,6 +8713,26 @@ 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_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, 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. 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, ())