From 39b5c696e2c9442163344e7de4b1e709ea3d9f63 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 17 Dec 2025 12:25:01 +0100 Subject: [PATCH] [ty] Experiment --- crates/ty_python_semantic/src/types.rs | 98 ++++++++------ .../ty_python_semantic/src/types/call/bind.rs | 36 +++--- crates/ty_python_semantic/src/types/class.rs | 10 +- .../src/types/constraints.rs | 4 +- .../ty_python_semantic/src/types/function.rs | 4 +- .../ty_python_semantic/src/types/generics.rs | 122 ++++++++++++------ .../src/types/infer/builder.rs | 10 +- .../ty_python_semantic/src/types/instance.rs | 14 +- .../src/types/protocol_class.rs | 6 +- .../src/types/signatures.rs | 36 +++--- .../src/types/subclass_of.rs | 4 +- crates/ty_python_semantic/src/types/tuple.rs | 22 ++-- .../src/types/typed_dict.rs | 4 +- 13 files changed, 216 insertions(+), 154 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index e4a0228cd4..7afe074039 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -615,7 +615,7 @@ impl<'db> PropertyInstanceType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.is_equivalent_to_impl(db, other, inferable, &IsEquivalentVisitor::default()) } @@ -624,7 +624,7 @@ impl<'db> PropertyInstanceType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { let getter_equivalence = if let Some(getter) = self.getter(db) { @@ -1486,7 +1486,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> Type<'db> { self.filter_union(db, |elem| { !elem @@ -1952,7 +1952,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 { - self.when_subtype_of(db, target, InferableTypeVars::None) + self.when_subtype_of(db, target, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -1960,7 +1960,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to(db, target, inferable, TypeRelation::Subtyping) } @@ -1974,7 +1974,7 @@ impl<'db> Type<'db> { db: &'db dyn Db, target: Type<'db>, assuming: ConstraintSet<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to( db, @@ -1988,7 +1988,7 @@ impl<'db> Type<'db> { /// /// See `TypeRelation::Assignability` for more details. pub fn is_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool { - self.when_assignable_to(db, target, InferableTypeVars::None) + self.when_assignable_to(db, target, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -1998,7 +1998,7 @@ impl<'db> Type<'db> { /// a constraint set and lets `satisfied_by_all_typevars` perform existential vs universal /// reasoning depending on inferable typevars. pub fn is_constraint_set_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool { - self.when_constraint_set_assignable_to(db, target, InferableTypeVars::None) + self.when_constraint_set_assignable_to(db, target, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -2006,7 +2006,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to(db, target, inferable, TypeRelation::Assignability) } @@ -2015,7 +2015,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to( db, @@ -2036,7 +2036,7 @@ impl<'db> Type<'db> { other: Type<'db>, ) -> bool { self_ty - .has_relation_to(db, other, InferableTypeVars::None, TypeRelation::Redundancy) + .has_relation_to(db, other, &InferableTypeVars::None, TypeRelation::Redundancy) .is_always_satisfied(db) } @@ -2051,24 +2051,35 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, ) -> ConstraintSet<'db> { - self.has_relation_to_impl( - db, - target, - inferable, - relation, - &HasRelationToVisitor::default(), - &IsDisjointVisitor::default(), - ) + #[salsa::tracked(cycle_initial=has_relation_to_cycle_initial, heap_size=ruff_memory_usage::heap_size)] + fn has_relation_to_tracked<'db>( + db: &'db dyn Db, + source: Type<'db>, + target: Type<'db>, + inferable: InferableTypeVars<'db>, + relation: TypeRelation<'db>, + ) -> ConstraintSet<'db> { + source.has_relation_to_impl( + db, + target, + &inferable, + relation, + &HasRelationToVisitor::default(), + &IsDisjointVisitor::default(), + ) + } + + has_relation_to_tracked(db, self, target, inferable.clone(), relation) } fn has_relation_to_impl( self, db: &'db dyn Db, target: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -3093,7 +3104,7 @@ impl<'db> Type<'db> { /// /// [equivalent to]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent pub(crate) fn is_equivalent_to(self, db: &'db dyn Db, other: Type<'db>) -> bool { - self.when_equivalent_to(db, other, InferableTypeVars::None) + self.when_equivalent_to(db, other, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -3101,7 +3112,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.is_equivalent_to_impl(db, other, inferable, &IsEquivalentVisitor::default()) } @@ -3110,7 +3121,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { @@ -3224,7 +3235,7 @@ 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) + self.when_disjoint_from(db, other, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -3232,7 +3243,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.is_disjoint_from_impl( db, @@ -3247,7 +3258,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -3255,7 +3266,7 @@ impl<'db> Type<'db> { db: &'db dyn Db, protocol: ProtocolInstanceType<'db>, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -8658,6 +8669,19 @@ fn is_redundant_with_cycle_initial<'db>( true } +fn has_relation_to_cycle_initial<'db>( + _db: &'db dyn Db, + _id: salsa::Id, + _source: Type<'db>, + _target: Type<'db>, + _inferable: InferableTypeVars<'db>, + _relation: TypeRelation<'db>, +) -> ConstraintSet<'db> { + // For recursive types, optimistically assume the relation holds. + // This matches the fallback behavior of HasRelationToVisitor::default(). + ConstraintSet::from(true) +} + fn apply_specialization_cycle_recover<'db>( db: &'db dyn Db, cycle: &salsa::Cycle, @@ -12288,7 +12312,7 @@ impl<'db> BoundMethodType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -12322,7 +12346,7 @@ impl<'db> BoundMethodType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { self.function(db) @@ -12538,7 +12562,7 @@ impl<'db> CallableType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -12563,7 +12587,7 @@ impl<'db> CallableType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { @@ -12629,7 +12653,7 @@ impl<'db> CallableTypes<'db> { self, db: &'db dyn Db, other: CallableType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -12718,7 +12742,7 @@ impl<'db> KnownBoundMethodType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -12823,7 +12847,7 @@ impl<'db> KnownBoundMethodType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { match (self, other) { @@ -14072,7 +14096,7 @@ impl<'db> UnionType<'db> { self, db: &'db dyn Db, other: Self, - _inferable: InferableTypeVars<'_, 'db>, + _inferable: &InferableTypeVars<'db>, _visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { @@ -14276,7 +14300,7 @@ impl<'db> IntersectionType<'db> { self, db: &'db dyn Db, other: Self, - _inferable: InferableTypeVars<'_, 'db>, + _inferable: &InferableTypeVars<'db>, _visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 005013e70b..2e22edc886 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -737,7 +737,7 @@ impl<'db> Bindings<'db> { Some(KnownFunction::IsEquivalentTo) => { if let [Some(ty_a), Some(ty_b)] = overload.parameter_types() { let constraints = - ty_a.when_equivalent_to(db, *ty_b, InferableTypeVars::None); + ty_a.when_equivalent_to(db, *ty_b, &InferableTypeVars::None); let tracked = TrackedConstraintSet::new(db, constraints); overload.set_return_type(Type::KnownInstance( KnownInstanceType::ConstraintSet(tracked), @@ -748,7 +748,7 @@ impl<'db> Bindings<'db> { Some(KnownFunction::IsSubtypeOf) => { if let [Some(ty_a), Some(ty_b)] = overload.parameter_types() { let constraints = - ty_a.when_subtype_of(db, *ty_b, InferableTypeVars::None); + ty_a.when_subtype_of(db, *ty_b, &InferableTypeVars::None); let tracked = TrackedConstraintSet::new(db, constraints); overload.set_return_type(Type::KnownInstance( KnownInstanceType::ConstraintSet(tracked), @@ -759,7 +759,7 @@ impl<'db> Bindings<'db> { Some(KnownFunction::IsAssignableTo) => { if let [Some(ty_a), Some(ty_b)] = overload.parameter_types() { let constraints = - ty_a.when_assignable_to(db, *ty_b, InferableTypeVars::None); + ty_a.when_assignable_to(db, *ty_b, &InferableTypeVars::None); let tracked = TrackedConstraintSet::new(db, constraints); overload.set_return_type(Type::KnownInstance( KnownInstanceType::ConstraintSet(tracked), @@ -770,7 +770,7 @@ impl<'db> Bindings<'db> { Some(KnownFunction::IsDisjointFrom) => { if let [Some(ty_a), Some(ty_b)] = overload.parameter_types() { let constraints = - ty_a.when_disjoint_from(db, *ty_b, InferableTypeVars::None); + ty_a.when_disjoint_from(db, *ty_b, &InferableTypeVars::None); let tracked = TrackedConstraintSet::new(db, constraints); overload.set_return_type(Type::KnownInstance( KnownInstanceType::ConstraintSet(tracked), @@ -1254,7 +1254,7 @@ impl<'db> Bindings<'db> { db, *ty_b, tracked.constraints(db), - InferableTypeVars::None, + &InferableTypeVars::None, ); let tracked = TrackedConstraintSet::new(db, result); overload.set_return_type(Type::KnownInstance( @@ -1314,7 +1314,7 @@ impl<'db> Bindings<'db> { let result = tracked .constraints(db) - .satisfied_by_all_typevars(db, InferableTypeVars::One(&inferable)); + .satisfied_by_all_typevars(db, &InferableTypeVars::One(std::sync::Arc::new(inferable.clone()))); overload.set_return_type(Type::BooleanLiteral(result)); } @@ -1732,7 +1732,7 @@ impl<'db> CallableBinding<'db> { .annotated_type() .unwrap_or(Type::unknown()); if argument_type - .when_assignable_to(db, parameter_type, overload.inferable_typevars) + .when_assignable_to(db, parameter_type, &overload.inferable_typevars) .is_always_satisfied(db) { is_argument_assignable_to_any_overload = true; @@ -1986,7 +1986,7 @@ impl<'db> CallableBinding<'db> { .when_equivalent_to( db, current_parameter_type, - overload.inferable_typevars, + &overload.inferable_typevars, ) .is_always_satisfied(db) { @@ -2134,7 +2134,7 @@ impl<'db> CallableBinding<'db> { .when_equivalent_to( db, first_overload_return_type, - overload.inferable_typevars, + &overload.inferable_typevars, ) .is_always_satisfied(db) }) @@ -2925,7 +2925,7 @@ struct ArgumentTypeChecker<'a, 'db> { return_ty: Type<'db>, errors: &'a mut Vec>, - inferable_typevars: InferableTypeVars<'db, 'db>, + inferable_typevars: InferableTypeVars<'db>, specialization: Option>, } @@ -2997,7 +2997,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { .zip(self.call_expression_tcx.annotation); self.inferable_typevars = generic_context.inferable_typevars(self.db); - let mut builder = SpecializationBuilder::new(self.db, self.inferable_typevars); + let mut builder = SpecializationBuilder::new(self.db, self.inferable_typevars.clone()); // Prefer the declared type of generic classes. let preferred_type_mappings = return_with_tcx.and_then(|(return_ty, tcx)| { @@ -3169,7 +3169,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { // constraint set that we get from this assignability check, instead of inferring and // building them in an earlier separate step. if argument_type - .when_assignable_to(self.db, expected_ty, self.inferable_typevars) + .when_assignable_to(self.db, expected_ty, &self.inferable_typevars) .is_never_satisfied(self.db) { let positional = matches!(argument, Argument::Positional | Argument::Synthetic) @@ -3442,7 +3442,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { .when_assignable_to( self.db, KnownClass::Str.to_instance(self.db), - self.inferable_typevars, + &self.inferable_typevars, ) .is_always_satisfied(self.db) { @@ -3507,7 +3507,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { fn finish( self, ) -> ( - InferableTypeVars<'db, 'db>, + InferableTypeVars<'db>, Option>, Type<'db>, ) { @@ -3580,7 +3580,7 @@ pub(crate) struct Binding<'db> { return_ty: Type<'db>, /// The inferable typevars in this signature. - inferable_typevars: InferableTypeVars<'db, 'db>, + inferable_typevars: InferableTypeVars<'db>, /// The specialization that was inferred from the argument types, if the callable is generic. specialization: Option>, @@ -3784,7 +3784,7 @@ impl<'db> Binding<'db> { fn snapshot(&self) -> BindingSnapshot<'db> { BindingSnapshot { return_ty: self.return_ty, - inferable_typevars: self.inferable_typevars, + inferable_typevars: self.inferable_typevars.clone(), specialization: self.specialization, argument_matches: self.argument_matches.clone(), parameter_tys: self.parameter_tys.clone(), @@ -3834,7 +3834,7 @@ impl<'db> Binding<'db> { #[derive(Clone, Debug)] struct BindingSnapshot<'db> { return_ty: Type<'db>, - inferable_typevars: InferableTypeVars<'db, 'db>, + inferable_typevars: InferableTypeVars<'db>, specialization: Option>, argument_matches: Box<[MatchedArgument<'db>]>, parameter_tys: Box<[Option>]>, @@ -3874,7 +3874,7 @@ impl<'db> CallableBindingSnapshot<'db> { // ... and update the snapshot with the current state of the binding. snapshot.return_ty = binding.return_ty; - snapshot.inferable_typevars = binding.inferable_typevars; + snapshot.inferable_typevars = binding.inferable_typevars.clone(); snapshot.specialization = binding.specialization; snapshot .argument_matches diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index a503421713..1466e382d7 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -600,7 +600,7 @@ impl<'db> ClassType<'db> { /// Return `true` if `other` is present in this class's MRO. pub(super) fn is_subclass_of(self, db: &'db dyn Db, other: ClassType<'db>) -> bool { - self.when_subclass_of(db, other, InferableTypeVars::None) + self.when_subclass_of(db, other, &InferableTypeVars::None) .is_always_satisfied(db) } @@ -608,7 +608,7 @@ impl<'db> ClassType<'db> { self, db: &'db dyn Db, other: ClassType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to_impl( db, @@ -624,7 +624,7 @@ impl<'db> ClassType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -676,7 +676,7 @@ impl<'db> ClassType<'db> { self, db: &'db dyn Db, other: ClassType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { @@ -736,7 +736,7 @@ impl<'db> ClassType<'db> { .is_disjoint_from( db, other_alias.specialization(db), - InferableTypeVars::None, + &InferableTypeVars::None, ) .is_always_satisfied(db) } diff --git a/crates/ty_python_semantic/src/types/constraints.rs b/crates/ty_python_semantic/src/types/constraints.rs index 77b96bd74b..031c51520e 100644 --- a/crates/ty_python_semantic/src/types/constraints.rs +++ b/crates/ty_python_semantic/src/types/constraints.rs @@ -346,7 +346,7 @@ impl<'db> ConstraintSet<'db> { pub(crate) fn satisfied_by_all_typevars( self, db: &'db dyn Db, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> bool { self.node.satisfied_by_all_typevars(db, inferable) } @@ -1311,7 +1311,7 @@ impl<'db> Node<'db> { fn satisfied_by_all_typevars( self, db: &'db dyn Db, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> bool { match self { Node::AlwaysTrue => return true, diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index 606b4ff6d3..eb16e8d26d 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -1108,7 +1108,7 @@ impl<'db> FunctionType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1133,7 +1133,7 @@ impl<'db> FunctionType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self.normalized(db) == other.normalized(db) { diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index c012ab09f6..73c18212b1 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fmt::Display; -use itertools::{Either, Itertools}; +use itertools::Itertools; use ruff_python_ast as ast; use rustc_hash::{FxHashMap, FxHashSet}; @@ -119,50 +119,90 @@ pub(crate) fn typing_self<'db>( ) } -#[derive(Clone, Copy, Debug)] -pub(crate) enum InferableTypeVars<'a, 'db> { +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum InferableTypeVars<'db> { None, - One(&'a FxHashSet>), + One(std::sync::Arc>>), Two( - &'a InferableTypeVars<'a, 'db>, - &'a InferableTypeVars<'a, 'db>, + std::sync::Arc>, + std::sync::Arc>, ), } +impl<'db> std::hash::Hash for InferableTypeVars<'db> { + fn hash(&self, state: &mut H) { + match self { + InferableTypeVars::None => { + 0u8.hash(state); + } + InferableTypeVars::One(set) => { + 1u8.hash(state); + // Sort the identities for deterministic hashing. + let mut items: Vec<_> = set.iter().copied().collect(); + items.sort_unstable(); + for item in items { + item.hash(state); + } + } + InferableTypeVars::Two(left, right) => { + 2u8.hash(state); + left.hash(state); + right.hash(state); + } + } + } +} + impl<'db> BoundTypeVarInstance<'db> { pub(crate) fn is_inferable( self, db: &'db dyn Db, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> bool { match inferable { InferableTypeVars::None => false, InferableTypeVars::One(typevars) => typevars.contains(&self.identity(db)), InferableTypeVars::Two(left, right) => { - self.is_inferable(db, *left) || self.is_inferable(db, *right) + self.is_inferable(db, left) || self.is_inferable(db, right) } } } } -impl<'a, 'db> InferableTypeVars<'a, 'db> { - pub(crate) fn merge(&'a self, other: &'a InferableTypeVars<'a, 'db>) -> Self { +impl<'db> InferableTypeVars<'db> { + pub(crate) fn merge(self, other: InferableTypeVars<'db>) -> Self { match (self, other) { - (InferableTypeVars::None, other) | (other, InferableTypeVars::None) => *other, - _ => InferableTypeVars::Two(self, other), + (InferableTypeVars::None, other) | (other, InferableTypeVars::None) => other, + (left, right) => InferableTypeVars::Two(std::sync::Arc::new(left), std::sync::Arc::new(right)), } } // This is not an IntoIterator implementation because I have no desire to try to name the // iterator type. - pub(crate) fn iter(self) -> impl Iterator> { + pub(crate) fn iter(&self) -> impl Iterator> + '_ { + enum Iter<'a, 'db> { + Empty, + One(std::collections::hash_set::Iter<'a, BoundTypeVarIdentity<'db>>), + Two(Box> + 'a>), + } + + impl<'db> Iterator for Iter<'_, 'db> { + type Item = BoundTypeVarIdentity<'db>; + + fn next(&mut self) -> Option { + match self { + Iter::Empty => None, + Iter::One(iter) => iter.next().copied(), + Iter::Two(iter) => iter.next(), + } + } + } + match self { - InferableTypeVars::None => Either::Left(Either::Left(std::iter::empty())), - InferableTypeVars::One(typevars) => Either::Right(typevars.iter().copied()), + InferableTypeVars::None => Iter::Empty, + InferableTypeVars::One(typevars) => Iter::One(typevars.iter()), InferableTypeVars::Two(left, right) => { - let chained: Box>> = - Box::new(left.iter().chain(right.iter())); - Either::Left(Either::Right(chained)) + Iter::Two(Box::new(left.iter().chain(right.iter()))) } } } @@ -172,7 +212,7 @@ impl<'a, 'db> InferableTypeVars<'a, 'db> { pub(crate) fn display(&self, db: &'db dyn Db) -> impl Display { fn find_typevars<'db>( result: &mut FxHashSet>, - inferable: &InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) { match inferable { InferableTypeVars::None => {} @@ -302,7 +342,7 @@ impl<'db> GenericContext<'db> { /// In this example, `method`'s generic context binds `Self` and `T`, but its inferable set /// also includes `A@C`. This is needed because at each call site, we need to infer the /// specialized class instance type whose method is being invoked. - pub(crate) fn inferable_typevars(self, db: &'db dyn Db) -> InferableTypeVars<'db, 'db> { + pub(crate) fn inferable_typevars(self, db: &'db dyn Db) -> InferableTypeVars<'db> { #[derive(Default)] struct CollectTypeVars<'db> { typevars: RefCell>>, @@ -349,10 +389,8 @@ impl<'db> GenericContext<'db> { visitor.typevars.into_inner() } - // This ensures that salsa caches the FxHashSet, not the InferableTypeVars that wraps it. - // (That way InferableTypeVars can contain references, and doesn't need to impl - // salsa::Update.) - InferableTypeVars::One(inferable_typevars_inner(db, self)) + // Wrap the Salsa-cached FxHashSet in an Arc. + InferableTypeVars::One(std::sync::Arc::new(inferable_typevars_inner(db, self).clone())) } pub(crate) fn variables( @@ -769,7 +807,7 @@ fn is_subtype_in_invariant_position<'db>( derived_materialization: MaterializationKind, base_type: &Type<'db>, base_materialization: MaterializationKind, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, ) -> ConstraintSet<'db> { @@ -847,7 +885,7 @@ fn has_relation_in_invariant_position<'db>( derived_materialization: Option, base_type: &Type<'db>, base_materialization: Option, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1233,7 +1271,7 @@ impl<'db> Specialization<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1308,7 +1346,7 @@ impl<'db> Specialization<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.is_disjoint_from_impl( db, @@ -1323,7 +1361,7 @@ impl<'db> Specialization<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -1382,7 +1420,7 @@ impl<'db> Specialization<'db> { self, db: &'db dyn Db, other: Specialization<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self.materialization_kind(db) != other.materialization_kind(db) { @@ -1483,7 +1521,7 @@ impl<'db> PartialSpecialization<'_, 'db> { /// specialization of a generic function. pub(crate) struct SpecializationBuilder<'db> { db: &'db dyn Db, - inferable: InferableTypeVars<'db, 'db>, + inferable: InferableTypeVars<'db>, types: FxHashMap, Type<'db>>, } @@ -1492,7 +1530,7 @@ pub(crate) struct SpecializationBuilder<'db> { pub(crate) type TypeVarAssignment<'db> = (BoundTypeVarIdentity<'db>, TypeVarVariance, Type<'db>); impl<'db> SpecializationBuilder<'db> { - pub(crate) fn new(db: &'db dyn Db, inferable: InferableTypeVars<'db, 'db>) -> Self { + pub(crate) fn new(db: &'db dyn Db, inferable: InferableTypeVars<'db>) -> Self { Self { db, inferable, @@ -1520,7 +1558,7 @@ impl<'db> SpecializationBuilder<'db> { Self { db: self.db, - inferable: self.inferable, + inferable: self.inferable.clone(), types, } } @@ -1687,8 +1725,8 @@ impl<'db> SpecializationBuilder<'db> { // // For example, if `formal` is `list[T]` and `actual` is `list[int] | None`, we want to // specialize `T` to `int`, and so ignore the `None`. - let actual = actual.filter_disjoint_elements(self.db, formal, self.inferable); - let formal = formal.filter_disjoint_elements(self.db, actual, self.inferable); + let actual = actual.filter_disjoint_elements(self.db, formal, &self.inferable); + let formal = formal.filter_disjoint_elements(self.db, actual, &self.inferable); match (formal, actual) { // TODO: We haven't implemented a full unification solver yet. If typevars appear in @@ -1751,7 +1789,7 @@ impl<'db> SpecializationBuilder<'db> { let assignable_elements = (union_formal.elements(self.db).iter()).filter(|ty| { actual - .when_subtype_of(self.db, **ty, self.inferable) + .when_subtype_of(self.db, **ty, &self.inferable) .is_always_satisfied(self.db) }); if assignable_elements.exactly_one().is_ok() { @@ -1786,7 +1824,7 @@ impl<'db> SpecializationBuilder<'db> { // The recursive call to `infer_map_impl` may succeed even if the actual type is // not assignable to the formal element. if !actual - .when_assignable_to(self.db, *formal_element, self.inferable) + .when_assignable_to(self.db, *formal_element, &self.inferable) .is_never_satisfied(self.db) { found_matching_element = true; @@ -1810,12 +1848,12 @@ impl<'db> SpecializationBuilder<'db> { } (Type::TypeVar(bound_typevar), ty) | (ty, Type::TypeVar(bound_typevar)) - if bound_typevar.is_inferable(self.db, self.inferable) => + if bound_typevar.is_inferable(self.db, &self.inferable) => { match bound_typevar.typevar(self.db).bound_or_constraints(self.db) { Some(TypeVarBoundOrConstraints::UpperBound(bound)) => { if !ty - .when_assignable_to(self.db, bound, self.inferable) + .when_assignable_to(self.db, bound, &self.inferable) .is_always_satisfied(self.db) { return Err(SpecializationError::MismatchedBound { @@ -1836,7 +1874,7 @@ impl<'db> SpecializationBuilder<'db> { for constraint in constraints.elements(self.db) { if ty - .when_assignable_to(self.db, *constraint, self.inferable) + .when_assignable_to(self.db, *constraint, &self.inferable) .is_always_satisfied(self.db) { self.add_type_mapping(bound_typevar, *constraint, polarity, f); @@ -1947,7 +1985,7 @@ impl<'db> SpecializationBuilder<'db> { .when_constraint_set_assignable_to( self.db, formal_callable, - self.inferable, + &self.inferable, ); self.add_type_mappings_from_constraint_set(formal, when, &mut f); } else { @@ -1956,7 +1994,7 @@ impl<'db> SpecializationBuilder<'db> { .when_constraint_set_assignable_to_signatures( self.db, formal_callable, - self.inferable, + &self.inferable, ); self.add_type_mappings_from_constraint_set(formal, when, &mut f); } diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index c93269ade2..9d07998341 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -7650,7 +7650,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { annotation.filter_disjoint_elements( self.db(), Type::homogeneous_tuple(self.db(), Type::unknown()), - inferable, + &inferable, ) }); @@ -7835,7 +7835,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // `collection_ty` is `list`. let tcx = tcx.map(|annotation| { let collection_ty = collection_class.to_instance(self.db()); - annotation.filter_disjoint_elements(self.db(), collection_ty, inferable) + annotation.filter_disjoint_elements(self.db(), collection_ty, &inferable) }); // Extract the annotated type of `T`, if provided. @@ -7986,7 +7986,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { annotation.filter_disjoint_elements( self.db(), collection_class.to_instance(self.db()), - InferableTypeVars::None, + &InferableTypeVars::None, ) }); @@ -11851,7 +11851,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { match typevar.typevar(db).bound_or_constraints(db) { Some(TypeVarBoundOrConstraints::UpperBound(bound)) => { if provided_type - .when_assignable_to(db, bound, InferableTypeVars::None) + .when_assignable_to(db, bound, &InferableTypeVars::None) .is_never_satisfied(db) { let node = get_node(index); @@ -11882,7 +11882,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { .when_assignable_to( db, constraints.as_type(db), - InferableTypeVars::None, + &InferableTypeVars::None, ) .is_never_satisfied(db) { diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 9e674065b9..f5a768ef10 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -127,7 +127,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, protocol: ProtocolInstanceType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -405,7 +405,7 @@ impl<'db> NominalInstanceType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -438,7 +438,7 @@ impl<'db> NominalInstanceType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { match (self.0, other.0) { @@ -460,7 +460,7 @@ impl<'db> NominalInstanceType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -706,7 +706,7 @@ impl<'db> ProtocolInstanceType<'db> { .satisfies_protocol( db, protocol, - InferableTypeVars::None, + &InferableTypeVars::None, TypeRelation::Subtyping, &HasRelationToVisitor::default(), &IsDisjointVisitor::default(), @@ -771,7 +771,7 @@ impl<'db> ProtocolInstanceType<'db> { self, db: &'db dyn Db, other: Self, - _inferable: InferableTypeVars<'_, 'db>, + _inferable: &InferableTypeVars<'db>, _visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { if self == other { @@ -793,7 +793,7 @@ impl<'db> ProtocolInstanceType<'db> { self, _db: &'db dyn Db, _other: Self, - _inferable: InferableTypeVars<'_, 'db>, + _inferable: &InferableTypeVars<'db>, _visitor: &IsDisjointVisitor<'db>, ) -> ConstraintSet<'db> { ConstraintSet::from(false) diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 5d3719b8d9..6a239b503b 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -273,7 +273,7 @@ impl<'db> ProtocolInterface<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -694,7 +694,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> { &self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -719,7 +719,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> { &self, db: &'db dyn Db, other: Type<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 33266f8dde..1421392f0b 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -304,7 +304,7 @@ impl<'db> CallableSignature<'db> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to_impl( db, @@ -320,7 +320,7 @@ impl<'db> CallableSignature<'db> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -362,7 +362,7 @@ impl<'db> CallableSignature<'db> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to_impl( db, @@ -380,7 +380,7 @@ impl<'db> CallableSignature<'db> { db: &'db dyn Db, self_signatures: &[Signature<'db>], other_signatures: &[Signature<'db>], - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -551,7 +551,7 @@ impl<'db> CallableSignature<'db> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { match (self.overloads.as_slice(), other.overloads.as_slice()) { @@ -966,7 +966,7 @@ impl<'db> Signature<'db> { } } - fn inferable_typevars(&self, db: &'db dyn Db) -> InferableTypeVars<'db, 'db> { + fn inferable_typevars(&self, db: &'db dyn Db) -> InferableTypeVars<'db> { match self.generic_context { Some(generic_context) => generic_context.inferable_typevars(db), None => InferableTypeVars::None, @@ -980,7 +980,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &Signature<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { // If either signature is generic, their typevars should also be considered inferable when @@ -997,11 +997,11 @@ impl<'db> Signature<'db> { // return t let self_inferable = self.inferable_typevars(db); let other_inferable = other.inferable_typevars(db); - let inferable = inferable.merge(&self_inferable); - let inferable = inferable.merge(&other_inferable); + let inferable = inferable.clone().merge(self_inferable.clone()); + let inferable = inferable.merge(other_inferable.clone()); // `inner` will create a constraint set that references these newly inferable typevars. - let when = self.is_equivalent_to_inner(db, other, inferable, visitor); + let when = self.is_equivalent_to_inner(db, other, &inferable, visitor); // But the caller does not need to consider those extra typevars. Whatever constraint set // we produce, we reduce it back down to the inferable set that the caller asked about. @@ -1014,7 +1014,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &Signature<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { let mut result = ConstraintSet::from(true); @@ -1100,7 +1100,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &CallableSignature<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { // If this signature is a paramspec, bind it to the entire overloaded other callable. if let Some(self_bound_typevar) = self.parameters.as_paramspec() @@ -1143,7 +1143,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, ) -> ConstraintSet<'db> { self.has_relation_to_impl( db, @@ -1160,7 +1160,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &Signature<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1179,14 +1179,14 @@ impl<'db> Signature<'db> { // return t let self_inferable = self.inferable_typevars(db); let other_inferable = other.inferable_typevars(db); - let inferable = inferable.merge(&self_inferable); - let inferable = inferable.merge(&other_inferable); + let inferable = inferable.clone().merge(self_inferable.clone()); + let inferable = inferable.merge(other_inferable.clone()); // `inner` will create a constraint set that references these newly inferable typevars. let when = self.has_relation_to_inner( db, other, - inferable, + &inferable, relation, relation_visitor, disjointness_visitor, @@ -1203,7 +1203,7 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, other: &Signature<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs index eb016199a5..20464b92c9 100644 --- a/crates/ty_python_semantic/src/types/subclass_of.rs +++ b/crates/ty_python_semantic/src/types/subclass_of.rs @@ -205,7 +205,7 @@ impl<'db> SubclassOfType<'db> { self, db: &'db dyn Db, other: SubclassOfType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -247,7 +247,7 @@ impl<'db> SubclassOfType<'db> { self, db: &'db dyn Db, other: Self, - _inferable: InferableTypeVars<'_, 'db>, + _inferable: &InferableTypeVars<'db>, _visitor: &IsDisjointVisitor<'db>, ) -> ConstraintSet<'db> { match (self.subclass_of, other.subclass_of) { diff --git a/crates/ty_python_semantic/src/types/tuple.rs b/crates/ty_python_semantic/src/types/tuple.rs index f0cc3bedc8..3f3e9f3d0d 100644 --- a/crates/ty_python_semantic/src/types/tuple.rs +++ b/crates/ty_python_semantic/src/types/tuple.rs @@ -273,7 +273,7 @@ impl<'db> TupleType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -292,7 +292,7 @@ impl<'db> TupleType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -309,7 +309,7 @@ impl<'db> TupleType<'db> { self, db: &'db dyn Db, other: Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { self.tuple(db) @@ -502,7 +502,7 @@ impl<'db> FixedLengthTuple> { &self, db: &'db dyn Db, other: &Tuple>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -589,7 +589,7 @@ impl<'db> FixedLengthTuple> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { ConstraintSet::from(self.0.len() == other.0.len()).and(db, || { @@ -908,7 +908,7 @@ impl<'db> VariableLengthTuple> { &self, db: &'db dyn Db, other: &Tuple>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1111,7 +1111,7 @@ impl<'db> VariableLengthTuple> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { self.variable @@ -1340,7 +1340,7 @@ impl<'db> Tuple> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -1369,7 +1369,7 @@ impl<'db> Tuple> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { match (self, other) { @@ -1389,7 +1389,7 @@ impl<'db> Tuple> { &self, db: &'db dyn Db, other: &Self, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> { @@ -1409,7 +1409,7 @@ impl<'db> Tuple> { db: &'db dyn Db, a: impl IntoIterator>, b: impl IntoIterator>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, relation_visitor: &HasRelationToVisitor<'db>, ) -> ConstraintSet<'db> diff --git a/crates/ty_python_semantic/src/types/typed_dict.rs b/crates/ty_python_semantic/src/types/typed_dict.rs index dee49a3afe..ee1e2b644f 100644 --- a/crates/ty_python_semantic/src/types/typed_dict.rs +++ b/crates/ty_python_semantic/src/types/typed_dict.rs @@ -129,7 +129,7 @@ impl<'db> TypedDictType<'db> { self, db: &'db dyn Db, target: TypedDictType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, relation: TypeRelation<'db>, relation_visitor: &HasRelationToVisitor<'db>, disjointness_visitor: &IsDisjointVisitor<'db>, @@ -314,7 +314,7 @@ impl<'db> TypedDictType<'db> { self, db: &'db dyn Db, other: TypedDictType<'db>, - inferable: InferableTypeVars<'_, 'db>, + inferable: &InferableTypeVars<'db>, visitor: &IsEquivalentVisitor<'db>, ) -> ConstraintSet<'db> { // TODO: `closed` and `extra_items` support will go here. Until then we don't look at the