diff --git a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs index 037e9d5014..0d646ca626 100644 --- a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs +++ b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs @@ -344,7 +344,7 @@ fn pattern_kind_to_type<'db>(db: &'db dyn Db, kind: &PatternPredicateKind<'db>) PatternPredicateKind::As(pattern, _) => pattern .as_deref() .map(|p| pattern_kind_to_type(db, p)) - .unwrap_or_else(|| Type::object(db)), + .unwrap_or_else(Type::object), PatternPredicateKind::Unsupported => Type::Never, } } diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 62bbac6051..42e42eb5fd 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -766,10 +766,6 @@ impl<'db> Type<'db> { Self::Dynamic(DynamicType::Divergent(DivergentType { scope })) } - pub(crate) fn object(db: &'db dyn Db) -> Self { - KnownClass::Object.to_instance(db) - } - pub const fn is_unknown(&self) -> bool { matches!(self, Type::Dynamic(DynamicType::Unknown)) } @@ -785,18 +781,18 @@ impl<'db> Type<'db> { fn is_none(&self, db: &'db dyn Db) -> bool { self.into_nominal_instance() - .is_some_and(|instance| instance.class(db).is_known(db, KnownClass::NoneType)) + .is_some_and(|instance| instance.has_known_class(db, KnownClass::NoneType)) } fn is_bool(&self, db: &'db dyn Db) -> bool { self.into_nominal_instance() - .is_some_and(|instance| instance.class(db).is_known(db, KnownClass::Bool)) + .is_some_and(|instance| instance.has_known_class(db, KnownClass::Bool)) } fn is_enum(&self, db: &'db dyn Db) -> bool { - self.into_nominal_instance().is_some_and(|instance| { - crate::types::enums::enum_metadata(db, instance.class(db).class_literal(db).0).is_some() - }) + self.into_nominal_instance() + .and_then(|instance| crate::types::enums::enum_metadata(db, instance.class_literal(db))) + .is_some() } /// Return true if this type overrides __eq__ or __ne__ methods @@ -823,16 +819,8 @@ impl<'db> Type<'db> { } pub(crate) fn is_notimplemented(&self, db: &'db dyn Db) -> bool { - self.into_nominal_instance().is_some_and(|instance| { - instance - .class(db) - .is_known(db, KnownClass::NotImplementedType) - }) - } - - pub(crate) fn is_object(&self, db: &'db dyn Db) -> bool { self.into_nominal_instance() - .is_some_and(|instance| instance.is_object(db)) + .is_some_and(|instance| instance.has_known_class(db, KnownClass::NotImplementedType)) } pub(crate) const fn is_todo(&self) -> bool { @@ -1455,7 +1443,7 @@ impl<'db> Type<'db> { match (self, target) { // Everything is a subtype of `object`. - (_, Type::NominalInstance(instance)) if instance.is_object(db) => { + (_, Type::NominalInstance(instance)) if instance.is_object() => { C::always_satisfiable(db) } (_, Type::ProtocolInstance(target)) if target.is_equivalent_to_object(db) => { @@ -1627,7 +1615,7 @@ impl<'db> Type<'db> { (left, Type::AlwaysTruthy) => C::from_bool(db, left.bool(db).is_always_true()), // Currently, the only supertype of `AlwaysFalsy` and `AlwaysTruthy` is the universal set (object instance). (Type::AlwaysFalsy | Type::AlwaysTruthy, _) => { - target.when_equivalent_to(db, Type::object(db)) + target.when_equivalent_to(db, Type::object()) } // These clauses handle type variants that include function literals. A function @@ -1979,7 +1967,7 @@ impl<'db> Type<'db> { } (Type::ProtocolInstance(protocol), nominal @ Type::NominalInstance(n)) | (nominal @ Type::NominalInstance(n), Type::ProtocolInstance(protocol)) => { - C::from_bool(db, n.is_object(db) && protocol.normalized(db) == nominal) + C::from_bool(db, n.is_object() && protocol.normalized(db) == nominal) } // An instance of an enum class is equivalent to an enum literal of that class, // if that enum has only has one member. @@ -1988,9 +1976,7 @@ impl<'db> Type<'db> { if literal.enum_class_instance(db) != Type::NominalInstance(instance) { return C::unsatisfiable(db); } - - let class_literal = instance.class(db).class_literal(db).0; - C::from_bool(db, is_single_member_enum(db, class_literal)) + C::from_bool(db, is_single_member_enum(db, instance.class_literal(db))) } (Type::PropertyInstance(left), Type::PropertyInstance(right)) => { @@ -2840,9 +2826,7 @@ impl<'db> Type<'db> { // i.e. Type::NominalInstance(type). So looking up a name in the MRO of // `Type::NominalInstance(type)` is equivalent to looking up the name in the // MRO of the class `object`. - Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::Type) => - { + Type::NominalInstance(instance) if instance.has_known_class(db, KnownClass::Type) => { if policy.mro_no_object_fallback() { Some(Place::Unbound.into()) } else { @@ -2982,12 +2966,12 @@ impl<'db> Type<'db> { .to_instance(db) .instance_member(db, name), Type::Callable(_) | Type::DataclassTransformer(_) => { - Type::object(db).instance_member(db, name) + Type::object().instance_member(db, name) } Type::NonInferableTypeVar(bound_typevar) => { match bound_typevar.typevar(db).bound_or_constraints(db) { - None => Type::object(db).instance_member(db, name), + None => Type::object().instance_member(db, name), Some(TypeVarBoundOrConstraints::UpperBound(bound)) => { bound.instance_member(db, name) } @@ -3020,7 +3004,7 @@ impl<'db> Type<'db> { .enum_class_instance(db) .instance_member(db, name), - Type::AlwaysTruthy | Type::AlwaysFalsy => Type::object(db).instance_member(db, name), + Type::AlwaysTruthy | Type::AlwaysFalsy => Type::object().instance_member(db, name), Type::ModuleLiteral(_) => KnownClass::ModuleType .to_instance(db) .instance_member(db, name), @@ -3477,12 +3461,12 @@ impl<'db> Type<'db> { .member_lookup_with_policy(db, name, policy), Type::Callable(_) | Type::DataclassTransformer(_) => { - Type::object(db).member_lookup_with_policy(db, name, policy) + Type::object().member_lookup_with_policy(db, name, policy) } Type::NominalInstance(instance) if matches!(name.as_str(), "major" | "minor") - && instance.class(db).is_known(db, KnownClass::VersionInfo) => + && instance.has_known_class(db, KnownClass::VersionInfo) => { let python_version = Program::get(db).python_version(db); let segment = if name == "major" { @@ -3577,7 +3561,7 @@ impl<'db> Type<'db> { // resolve the attribute. if matches!( self.into_nominal_instance() - .and_then(|instance| instance.class(db).known(db)), + .and_then(|instance| instance.known_class(db)), Some(KnownClass::ModuleType | KnownClass::GenericAlias) ) { return Place::Unbound.into(); @@ -3906,8 +3890,7 @@ impl<'db> Type<'db> { Type::TypeVar(_) => Truthiness::Ambiguous, Type::NominalInstance(instance) => instance - .class(db) - .known(db) + .known_class(db) .and_then(KnownClass::bool) .map(Ok) .unwrap_or_else(try_dunder_bool)?, @@ -4042,7 +4025,7 @@ impl<'db> Type<'db> { self, Signature::new( Parameters::new([Parameter::positional_only(Some(Name::new_static("func"))) - .with_annotated_type(Type::object(db))]), + .with_annotated_type(Type::object())]), None, ), ) @@ -4307,7 +4290,7 @@ impl<'db> Type<'db> { Parameters::new([Parameter::positional_or_keyword( Name::new_static("object"), ) - .with_annotated_type(Type::object(db)) + .with_annotated_type(Type::object()) .with_default_type(Type::string_literal(db, ""))]), Some(KnownClass::Str.to_instance(db)), ), @@ -4390,7 +4373,7 @@ impl<'db> Type<'db> { // ``` Binding::single( self, - Signature::new(Parameters::empty(), Some(Type::object(db))), + Signature::new(Parameters::empty(), Some(Type::object())), ) .into() } @@ -4631,7 +4614,7 @@ impl<'db> Type<'db> { } Some(KnownClass::Tuple) => { - let object = Type::object(db); + let object = Type::object(); // ```py // class tuple: @@ -5648,7 +5631,7 @@ impl<'db> Type<'db> { // See conversation in https://github.com/astral-sh/ruff/pull/19915. SpecialFormType::NamedTuple => Ok(IntersectionBuilder::new(db) .positive_elements([ - Type::homogeneous_tuple(db, Type::object(db)), + Type::homogeneous_tuple(db, Type::object()), KnownClass::NamedTupleLike.to_instance(db), ]) .build()), @@ -5787,7 +5770,7 @@ impl<'db> Type<'db> { Type::Dynamic(_) => Ok(*self), - Type::NominalInstance(instance) => match instance.class(db).known(db) { + Type::NominalInstance(instance) => match instance.known_class(db) { Some(KnownClass::TypeVar) => Ok(todo_type!( "Support for `typing.TypeVar` instances in type expressions" )), @@ -5908,7 +5891,7 @@ impl<'db> Type<'db> { pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> { if self.is_typed_dict() { return KnownClass::Dict - .to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object(db)]) + .to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object()]) .map(Type::from) // Guard against user-customized typesheds with a broken `dict` class .unwrap_or_else(Type::unknown); @@ -6142,7 +6125,7 @@ impl<'db> Type<'db> { TypeMapping::MarkTypeVarsInferable(_) | TypeMapping::PromoteLiterals => self, TypeMapping::Materialize(materialization_kind) => match materialization_kind { - MaterializationKind::Top => Type::object(db), + MaterializationKind::Top => Type::object(), MaterializationKind::Bottom => Type::Never, } } @@ -9096,7 +9079,7 @@ impl<'db> CallableType<'db> { /// `(*args: object, **kwargs: object) -> Never`. #[cfg(test)] pub(crate) fn bottom(db: &'db dyn Db) -> Type<'db> { - Self::single(db, Signature::bottom(db)) + Self::single(db, Signature::bottom()) } /// Return a "normalized" version of this `Callable` type. @@ -9380,7 +9363,7 @@ impl<'db> KnownBoundMethodType<'db> { Signature::new( Parameters::new([ Parameter::positional_only(Some(Name::new_static("instance"))) - .with_annotated_type(Type::object(db)), + .with_annotated_type(Type::object()), Parameter::positional_only(Some(Name::new_static("owner"))) .with_annotated_type(UnionType::from_elements( db, @@ -9400,9 +9383,9 @@ impl<'db> KnownBoundMethodType<'db> { Either::Right(std::iter::once(Signature::new( Parameters::new([ Parameter::positional_only(Some(Name::new_static("instance"))) - .with_annotated_type(Type::object(db)), + .with_annotated_type(Type::object()), Parameter::positional_only(Some(Name::new_static("value"))) - .with_annotated_type(Type::object(db)), + .with_annotated_type(Type::object()), ]), None, ))) @@ -9482,7 +9465,7 @@ impl WrapperDescriptorKind { Parameter::positional_only(Some(Name::new_static("self"))) .with_annotated_type(descriptor), Parameter::positional_only(Some(Name::new_static("instance"))) - .with_annotated_type(Type::object(db)), + .with_annotated_type(Type::object()), Parameter::positional_only(Some(Name::new_static("owner"))) .with_annotated_type(UnionType::from_elements( db, @@ -9503,7 +9486,7 @@ impl WrapperDescriptorKind { Either::Left(dunder_get_signatures(db, KnownClass::Property).into_iter()) } WrapperDescriptorKind::PropertyDunderSet => { - let object = Type::object(db); + let object = Type::object(); Either::Right(std::iter::once(Signature::new( Parameters::new([ Parameter::positional_only(Some(Name::new_static("self"))) @@ -10257,7 +10240,7 @@ impl<'db> IntersectionType<'db> { /// there are no positive elements, returns a single `object` type. fn positive_elements_or_object(self, db: &'db dyn Db) -> impl Iterator> { if self.positive(db).is_empty() { - Either::Left(std::iter::once(Type::object(db))) + Either::Left(std::iter::once(Type::object())) } else { Either::Right(self.positive(db).iter().copied()) } diff --git a/crates/ty_python_semantic/src/types/builder.rs b/crates/ty_python_semantic/src/types/builder.rs index 16b28e5fe8..a729191e00 100644 --- a/crates/ty_python_semantic/src/types/builder.rs +++ b/crates/ty_python_semantic/src/types/builder.rs @@ -242,8 +242,7 @@ impl<'db> UnionBuilder<'db> { /// Collapse the union to a single type: `object`. fn collapse_to_object(&mut self) { self.elements.clear(); - self.elements - .push(UnionElement::Type(Type::object(self.db))); + self.elements.push(UnionElement::Type(Type::object())); } /// Adds a type to this union. @@ -448,7 +447,7 @@ impl<'db> UnionBuilder<'db> { } } // Adding `object` to a union results in `object`. - ty if ty.is_object(self.db) => { + ty if ty.is_object() => { self.collapse_to_object(); } _ => { @@ -648,8 +647,7 @@ impl<'db> IntersectionBuilder<'db> { self } Type::NominalInstance(instance) - if enum_metadata(self.db, instance.class(self.db).class_literal(self.db).0) - .is_some() => + if enum_metadata(self.db, instance.class_literal(self.db)).is_some() => { let mut contains_enum_literal_as_negative_element = false; for intersection in &self.intersections { @@ -674,7 +672,7 @@ impl<'db> IntersectionBuilder<'db> { self.add_positive_impl( Type::Union(UnionType::new( db, - enum_member_literals(db, instance.class(db).class_literal(db).0, None) + enum_member_literals(db, instance.class_literal(db), None) .expect("Calling `enum_member_literals` on an enum class") .collect::>(), )), @@ -860,7 +858,7 @@ impl<'db> InnerIntersectionBuilder<'db> { _ => { let known_instance = new_positive .into_nominal_instance() - .and_then(|instance| instance.class(db).known(db)); + .and_then(|instance| instance.known_class(db)); if known_instance == Some(KnownClass::Object) { // `object & T` -> `T`; it is always redundant to add `object` to an intersection @@ -880,7 +878,7 @@ impl<'db> InnerIntersectionBuilder<'db> { new_positive = Type::BooleanLiteral(false); } Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::Bool) => + if instance.has_known_class(db, KnownClass::Bool) => { match new_positive { // `bool & AlwaysTruthy` -> `Literal[True]` @@ -974,7 +972,7 @@ impl<'db> InnerIntersectionBuilder<'db> { self.positive .iter() .filter_map(|ty| ty.into_nominal_instance()) - .filter_map(|instance| instance.class(db).known(db)) + .filter_map(|instance| instance.known_class(db)) .any(KnownClass::is_bool) }; @@ -990,7 +988,7 @@ impl<'db> InnerIntersectionBuilder<'db> { Type::Never => { // Adding ~Never to an intersection is a no-op. } - Type::NominalInstance(instance) if instance.is_object(db) => { + Type::NominalInstance(instance) if instance.is_object() => { // Adding ~object to an intersection results in Never. *self = Self::default(); self.positive.insert(Type::Never); @@ -1152,7 +1150,7 @@ impl<'db> InnerIntersectionBuilder<'db> { fn build(mut self, db: &'db dyn Db) -> Type<'db> { self.simplify_constrained_typevars(db); match (self.positive.len(), self.negative.len()) { - (0, 0) => Type::object(db), + (0, 0) => Type::object(), (1, 0) => self.positive[0], _ => { self.positive.shrink_to_fit(); @@ -1208,7 +1206,7 @@ mod tests { let db = setup_db(); let intersection = IntersectionBuilder::new(&db).build(); - assert_eq!(intersection, Type::object(&db)); + assert_eq!(intersection, Type::object()); } #[test_case(Type::BooleanLiteral(true))] @@ -1222,7 +1220,7 @@ mod tests { // We add t_object in various orders (in first or second position) in // the tests below to ensure that the boolean simplification eliminates // everything from the intersection, not just `bool`. - let t_object = Type::object(&db); + let t_object = Type::object(); let t_bool = KnownClass::Bool.to_instance(&db); let ty = IntersectionBuilder::new(&db) diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 8284f5b7c7..9a43c78c73 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -1313,7 +1313,7 @@ impl<'db> Field<'db> { pub(crate) fn is_kw_only_sentinel(&self, db: &'db dyn Db) -> bool { self.declared_ty .into_nominal_instance() - .is_some_and(|instance| instance.class(db).is_known(db, KnownClass::KwOnly)) + .is_some_and(|instance| instance.has_known_class(db, KnownClass::KwOnly)) } } diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index 1306651c5c..d8aa0aa2df 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -82,7 +82,7 @@ impl<'db> ClassBase<'db> { Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))), Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))), Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::GenericAlias) => + if instance.has_known_class(db, KnownClass::GenericAlias) => { Self::try_from_type(db, todo_type!("GenericAlias instance"), subclass) } diff --git a/crates/ty_python_semantic/src/types/constraints.rs b/crates/ty_python_semantic/src/types/constraints.rs index 22a6183200..546d77e4f5 100644 --- a/crates/ty_python_semantic/src/types/constraints.rs +++ b/crates/ty_python_semantic/src/types/constraints.rs @@ -1042,7 +1042,7 @@ impl<'db> Constraint<'db> { // If the requested constraint is `Never ≤ T ≤ object`, then the typevar can be specialized // to _any_ type, and the constraint does nothing. - if lower.is_never() && upper.is_object(db) { + if lower.is_never() && upper.is_object() { return Satisfiable::Always; } @@ -1189,7 +1189,7 @@ impl<'db> RangeConstraint<'db> { ConstraintClause::from_constraints( db, [ - Constraint::range(db, self.upper, Type::object(db)).constrain(typevar), + Constraint::range(db, self.upper, Type::object()).constrain(typevar), Constraint::not_equivalent(db, self.upper).constrain(typevar), ], ), @@ -1214,7 +1214,7 @@ impl<'db> RangeConstraint<'db> { write!(f, "{} ≤ ", self.constraint.lower.display(self.db))?; } self.typevar.fmt(f)?; - if !self.constraint.upper.is_object(self.db) { + if !self.constraint.upper.is_object() { write!(f, " ≤ {}", self.constraint.upper.display(self.db))?; } f.write_str(")") @@ -1356,7 +1356,7 @@ impl<'db> Constraint<'db> { debug_assert_eq!(ty, ty.top_materialization(db)); // Every type is comparable to Never and to object. - if ty.is_never() || ty.is_object(db) { + if ty.is_never() || ty.is_object() { return Satisfiable::Never; } @@ -1407,7 +1407,7 @@ impl<'db> IncomparableConstraint<'db> { ); set.union_constraint( db, - Constraint::range(db, self.ty, Type::object(db)).constrain(typevar), + Constraint::range(db, self.ty, Type::object()).constrain(typevar), ); } diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 744474564c..92b86c406b 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -90,9 +90,7 @@ impl DisplaySettings { fn type_to_class_literal<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option> { match ty { Type::ClassLiteral(class) => Some(class), - Type::NominalInstance(instance) => { - type_to_class_literal(db, Type::from(instance.class(db))) - } + Type::NominalInstance(instance) => Some(instance.class_literal(db)), Type::EnumLiteral(enum_literal) => Some(enum_literal.enum_class(db)), Type::GenericAlias(alias) => Some(alias.origin(db)), Type::ProtocolInstance(ProtocolInstanceType { @@ -1648,7 +1646,7 @@ mod tests { .with_annotated_type(KnownClass::Int.to_instance(&db)) .with_default_type(Type::IntLiteral(4)), Parameter::variadic(Name::new_static("args")) - .with_annotated_type(Type::object(&db)), + .with_annotated_type(Type::object()), Parameter::keyword_only(Name::new_static("g")) .with_default_type(Type::IntLiteral(5)), Parameter::keyword_only(Name::new_static("h")) @@ -1804,7 +1802,7 @@ mod tests { .with_annotated_type(KnownClass::Int.to_instance(&db)) .with_default_type(Type::IntLiteral(4)), Parameter::variadic(Name::new_static("args")) - .with_annotated_type(Type::object(&db)), + .with_annotated_type(Type::object()), Parameter::keyword_only(Name::new_static("g")) .with_default_type(Type::IntLiteral(5)), Parameter::keyword_only(Name::new_static("h")) diff --git a/crates/ty_python_semantic/src/types/enums.rs b/crates/ty_python_semantic/src/types/enums.rs index fb6f5b0c33..c62851fe8d 100644 --- a/crates/ty_python_semantic/src/types/enums.rs +++ b/crates/ty_python_semantic/src/types/enums.rs @@ -130,7 +130,7 @@ pub(crate) fn enum_metadata<'db>( // Some types are specifically disallowed for enum members. return None; } - Type::NominalInstance(instance) => match instance.class(db).known(db) { + Type::NominalInstance(instance) => match instance.known_class(db) { // enum.nonmember Some(KnownClass::Nonmember) => return None, @@ -208,7 +208,7 @@ pub(crate) fn enum_metadata<'db>( PlaceAndQualifiers { place: Place::Type(Type::NominalInstance(instance), _), .. - } if instance.class(db).is_known(db, KnownClass::Member) => { + } if instance.has_known_class(db, KnownClass::Member) => { // If the attribute is specifically declared with `enum.member`, it is considered a member } _ => { diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index 4d8bf36e58..be9976fe6f 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -1133,10 +1133,10 @@ fn signature_cycle_recover<'db>( } fn signature_cycle_initial<'db>( - db: &'db dyn Db, + _db: &'db dyn Db, _function: FunctionType<'db>, ) -> CallableSignature<'db> { - CallableSignature::single(Signature::bottom(db)) + CallableSignature::single(Signature::bottom()) } fn last_definition_signature_cycle_recover<'db>( @@ -1149,10 +1149,10 @@ fn last_definition_signature_cycle_recover<'db>( } fn last_definition_signature_cycle_initial<'db>( - db: &'db dyn Db, + _db: &'db dyn Db, _function: FunctionType<'db>, ) -> Signature<'db> { - Signature::bottom(db) + Signature::bottom() } /// Non-exhaustive enumeration of known functions (e.g. `builtins.reveal_type`, ...) that might diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs index 17b0c72f52..95e404bde3 100644 --- a/crates/ty_python_semantic/src/types/ide_support.rs +++ b/crates/ty_python_semantic/src/types/ide_support.rs @@ -95,8 +95,7 @@ impl<'db> AllMembers<'db> { ), Type::NominalInstance(instance) => { - let (class_literal, _specialization) = instance.class(db).class_literal(db); - self.extend_with_instance_members(db, ty, class_literal); + self.extend_with_instance_members(db, ty, instance.class_literal(db)); } Type::ClassLiteral(class_literal) if class_literal.is_typed_dict(db) => { @@ -211,7 +210,7 @@ impl<'db> AllMembers<'db> { match ty { Type::NominalInstance(instance) if matches!( - instance.class(db).known(db), + instance.known_class(db), Some( KnownClass::TypeVar | KnownClass::TypeVarTuple diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 1264aa21fd..0a5561dc6d 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -1245,7 +1245,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { Type::BooleanLiteral(_) | Type::IntLiteral(_) => {} Type::NominalInstance(instance) if matches!( - instance.class(self.db()).known(self.db()), + instance.known_class(self.db()), Some(KnownClass::Float | KnownClass::Int | KnownClass::Bool) ) => {} _ => return false, @@ -3411,9 +3411,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { ), // Super instances do not allow attribute assignment - Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::Super) => - { + Type::NominalInstance(instance) if instance.has_known_class(db, KnownClass::Super) => { if emit_diagnostics { if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target) { builder.into_diagnostic(format_args!( @@ -7559,10 +7557,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // We didn't see any positive elements, check if the operation is supported on `object`: match intersection_on { IntersectionOn::Left => { - self.infer_binary_type_comparison(Type::object(self.db()), op, other, range) + self.infer_binary_type_comparison(Type::object(), op, other, range) } IntersectionOn::Right => { - self.infer_binary_type_comparison(other, op, Type::object(self.db()), range) + self.infer_binary_type_comparison(other, op, Type::object(), range) } } } @@ -8733,7 +8731,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } else if any_over_type(self.db(), *typevar, &|ty| match ty { Type::Dynamic(DynamicType::TodoUnpack) => true, Type::NominalInstance(nominal) => matches!( - nominal.class(self.db()).known(self.db()), + nominal.known_class(self.db()), Some(KnownClass::TypeVarTuple | KnownClass::ParamSpec) ), _ => false, @@ -8776,9 +8774,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let type_to_slice_argument = |ty: Option>| match ty { Some(ty @ (Type::IntLiteral(_) | Type::BooleanLiteral(_))) => SliceArg::Arg(ty), Some(ty @ Type::NominalInstance(instance)) - if instance - .class(self.db()) - .is_known(self.db(), KnownClass::NoneType) => + if instance.has_known_class(self.db(), KnownClass::NoneType) => { SliceArg::Arg(ty) } diff --git a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs index a841a2d361..7ff6fb2279 100644 --- a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs +++ b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs @@ -1521,9 +1521,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> { } if any_over_type(self.db(), self.infer_name_load(name), &|ty| match ty { Type::Dynamic(DynamicType::TodoPEP695ParamSpec) => true, - Type::NominalInstance(nominal) => nominal - .class(self.db()) - .is_known(self.db(), KnownClass::ParamSpec), + Type::NominalInstance(nominal) => { + nominal.has_known_class(self.db(), KnownClass::ParamSpec) + } _ => false, }) { return Some(Parameters::todo()); diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 194d047788..414d5d92e4 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -12,32 +12,44 @@ use crate::types::enums::is_single_member_enum; use crate::types::protocol_class::walk_protocol_interface; use crate::types::tuple::{TupleSpec, TupleType}; use crate::types::{ - ApplyTypeMappingVisitor, ClassBase, FindLegacyTypeVarsVisitor, HasRelationToVisitor, - IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, TypeMapping, TypeRelation, - VarianceInferable, + ApplyTypeMappingVisitor, ClassBase, ClassLiteral, FindLegacyTypeVarsVisitor, + HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, TypeMapping, + TypeRelation, VarianceInferable, }; use crate::{Db, FxOrderSet}; pub(super) use synthesized_protocol::SynthesizedProtocolType; impl<'db> Type<'db> { + pub(crate) const fn object() -> Self { + Type::NominalInstance(NominalInstanceType(NominalInstanceInner::Object)) + } + + pub(crate) const fn is_object(&self) -> bool { + matches!( + self, + Type::NominalInstance(NominalInstanceType(NominalInstanceInner::Object)) + ) + } + pub(crate) fn instance(db: &'db dyn Db, class: ClassType<'db>) -> Self { let (class_literal, specialization) = class.class_literal(db); - - if class_literal.is_known(db, KnownClass::Tuple) { - Type::tuple(TupleType::new( + match class_literal.known(db) { + Some(KnownClass::Tuple) => Type::tuple(TupleType::new( db, specialization .and_then(|spec| Some(Cow::Borrowed(spec.tuple(db)?))) .unwrap_or_else(|| Cow::Owned(TupleSpec::homogeneous(Type::unknown()))) .as_ref(), - )) - } else if class_literal.is_protocol(db) { - Self::ProtocolInstance(ProtocolInstanceType::from_class(class)) - } else if class_literal.is_typed_dict(db) { - Type::typed_dict(class) - } else { - Type::non_tuple_instance(class) + )), + Some(KnownClass::Object) => Type::object(), + _ if class_literal.is_protocol(db) => { + Self::ProtocolInstance(ProtocolInstanceType::from_class(class)) + } + _ if class_literal.is_typed_dict(db) => Type::typed_dict(class), + // We don't call non_tuple_instance here because we've already checked that the class + // is not `object` + _ => Type::NominalInstance(NominalInstanceType(NominalInstanceInner::NonTuple(class))), } } @@ -74,8 +86,12 @@ impl<'db> Type<'db> { /// **Private** helper function to create a `Type::NominalInstance` from a class that /// is known not to be `Any`, a protocol class, or a typed dict class. - fn non_tuple_instance(class: ClassType<'db>) -> Self { - Type::NominalInstance(NominalInstanceType(NominalInstanceInner::NonTuple(class))) + fn non_tuple_instance(db: &'db dyn Db, class: ClassType<'db>) -> Self { + if class.is_known(db, KnownClass::Object) { + Type::NominalInstance(NominalInstanceType(NominalInstanceInner::Object)) + } else { + Type::NominalInstance(NominalInstanceType(NominalInstanceInner::NonTuple(class))) + } } pub(crate) const fn into_nominal_instance(self) -> Option> { @@ -132,7 +148,12 @@ impl<'db> Type<'db> { // recognise `str` as a subtype of `Container[str]`. structurally_satisfied.or(db, || { if let Protocol::FromClass(class) = protocol.inner { - self.has_relation_to_impl(db, Type::non_tuple_instance(class), relation, visitor) + self.has_relation_to_impl( + db, + Type::non_tuple_instance(db, class), + relation, + visitor, + ) } else { C::unsatisfiable(db) } @@ -161,9 +182,42 @@ impl<'db> NominalInstanceType<'db> { match self.0 { NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db), NominalInstanceInner::NonTuple(class) => class, + NominalInstanceInner::Object => KnownClass::Object + .try_to_class_literal(db) + .expect("Typeshed should always have a `object` class in `builtins.pyi`") + .default_specialization(db), } } + pub(super) fn class_literal(&self, db: &'db dyn Db) -> ClassLiteral<'db> { + let class = match self.0 { + NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db), + NominalInstanceInner::NonTuple(class) => class, + NominalInstanceInner::Object => { + return KnownClass::Object + .try_to_class_literal(db) + .expect("Typeshed should always have a `object` class in `builtins.pyi`"); + } + }; + let (class_literal, _) = class.class_literal(db); + class_literal + } + + /// Returns the [`KnownClass`] that this is a nominal instance of, or `None` if it is not an + /// instance of a known class. + pub(super) fn known_class(&self, db: &'db dyn Db) -> Option { + match self.0 { + NominalInstanceInner::ExactTuple(_) => Some(KnownClass::Tuple), + NominalInstanceInner::NonTuple(class) => class.known(db), + NominalInstanceInner::Object => Some(KnownClass::Object), + } + } + + /// Returns whether this is a nominal instance of a particular [`KnownClass`]. + pub(super) fn has_known_class(&self, db: &'db dyn Db, known_class: KnownClass) -> bool { + self.known_class(db) == Some(known_class) + } + /// If this is an instance type where the class has a tuple spec, returns the tuple spec. /// /// I.e., for the type `tuple[int, str]`, this will return the tuple spec `[int, str]`. @@ -203,15 +257,13 @@ impl<'db> NominalInstanceType<'db> { _ => None, }) } + NominalInstanceInner::Object => None, } } /// Return `true` if this type represents instances of the class `builtins.object`. - pub(super) fn is_object(self, db: &'db dyn Db) -> bool { - match self.0 { - NominalInstanceInner::ExactTuple(_) => false, - NominalInstanceInner::NonTuple(class) => class.is_object(db), - } + pub(super) const fn is_object(self) -> bool { + matches!(self.0, NominalInstanceInner::Object) } /// If this type is an *exact* tuple type (*not* a subclass of `tuple`), returns the @@ -227,7 +279,7 @@ impl<'db> NominalInstanceType<'db> { pub(super) fn own_tuple_spec(&self, db: &'db dyn Db) -> Option>> { match self.0 { NominalInstanceInner::ExactTuple(tuple) => Some(Cow::Borrowed(tuple.tuple(db))), - NominalInstanceInner::NonTuple(_) => None, + NominalInstanceInner::NonTuple(_) | NominalInstanceInner::Object => None, } } @@ -238,7 +290,7 @@ impl<'db> NominalInstanceType<'db> { /// integers or `None`. pub(crate) fn slice_literal(self, db: &'db dyn Db) -> Option { let class = match self.0 { - NominalInstanceInner::ExactTuple(_) => return None, + NominalInstanceInner::ExactTuple(_) | NominalInstanceInner::Object => return None, NominalInstanceInner::NonTuple(class) => class, }; let (class, Some(specialization)) = class.class_literal(db) else { @@ -255,7 +307,7 @@ impl<'db> NominalInstanceType<'db> { Type::IntLiteral(n) => i32::try_from(*n).map(Some).ok(), Type::BooleanLiteral(b) => Some(Some(i32::from(*b))), Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::NoneType) => + if instance.has_known_class(db, KnownClass::NoneType) => { Some(None) } @@ -278,8 +330,9 @@ impl<'db> NominalInstanceType<'db> { Type::tuple(tuple.normalized_impl(db, visitor)) } NominalInstanceInner::NonTuple(class) => { - Type::non_tuple_instance(class.normalized_impl(db, visitor)) + Type::non_tuple_instance(db, class.normalized_impl(db, visitor)) } + NominalInstanceInner::Object => Type::object(), } } @@ -291,6 +344,7 @@ impl<'db> NominalInstanceType<'db> { visitor: &HasRelationToVisitor<'db, C>, ) -> C { match (self.0, other.0) { + (_, NominalInstanceInner::Object) => C::always_satisfiable(db), ( NominalInstanceInner::ExactTuple(tuple1), NominalInstanceInner::ExactTuple(tuple2), @@ -312,6 +366,9 @@ impl<'db> NominalInstanceType<'db> { NominalInstanceInner::ExactTuple(tuple1), NominalInstanceInner::ExactTuple(tuple2), ) => tuple1.is_equivalent_to_impl(db, tuple2, visitor), + (NominalInstanceInner::Object, NominalInstanceInner::Object) => { + C::always_satisfiable(db) + } (NominalInstanceInner::NonTuple(class1), NominalInstanceInner::NonTuple(class2)) => { class1.is_equivalent_to_impl(db, class2, visitor) } @@ -325,6 +382,9 @@ impl<'db> NominalInstanceType<'db> { other: Self, visitor: &IsDisjointVisitor<'db, C>, ) -> C { + if self.is_object() || other.is_object() { + return C::unsatisfiable(db); + } let mut result = C::unsatisfiable(db); if let Some(self_spec) = self.tuple_spec(db) { if let Some(other_spec) = other.tuple_spec(db) { @@ -349,7 +409,7 @@ impl<'db> NominalInstanceType<'db> { // should not be relied on for type narrowing, so we do not treat it as one. // See: // https://docs.python.org/3/reference/expressions.html#parenthesized-forms - NominalInstanceInner::ExactTuple(_) => false, + NominalInstanceInner::ExactTuple(_) | NominalInstanceInner::Object => false, NominalInstanceInner::NonTuple(class) => class .known(db) .map(KnownClass::is_singleton) @@ -360,6 +420,7 @@ impl<'db> NominalInstanceType<'db> { pub(super) fn is_single_valued(self, db: &'db dyn Db) -> bool { match self.0 { NominalInstanceInner::ExactTuple(tuple) => tuple.is_single_valued(db), + NominalInstanceInner::Object => false, NominalInstanceInner::NonTuple(class) => class .known(db) .and_then(KnownClass::is_single_valued) @@ -382,9 +443,11 @@ impl<'db> NominalInstanceType<'db> { NominalInstanceInner::ExactTuple(tuple) => { Type::tuple(tuple.apply_type_mapping_impl(db, type_mapping, visitor)) } - NominalInstanceInner::NonTuple(class) => { - Type::non_tuple_instance(class.apply_type_mapping_impl(db, type_mapping, visitor)) - } + NominalInstanceInner::NonTuple(class) => Type::non_tuple_instance( + db, + class.apply_type_mapping_impl(db, type_mapping, visitor), + ), + NominalInstanceInner::Object => Type::object(), } } @@ -402,6 +465,7 @@ impl<'db> NominalInstanceType<'db> { NominalInstanceInner::NonTuple(class) => { class.find_legacy_typevars_impl(db, binding_context, typevars, visitor); } + NominalInstanceInner::Object => {} } } } @@ -417,6 +481,12 @@ impl<'db> From> for Type<'db> { /// instances where it would be unnecessary (this is somewhat expensive!). #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, salsa::Update, get_size2::GetSize)] enum NominalInstanceInner<'db> { + /// An instance of `object`. + /// + /// We model it with a dedicated enum variant since its use as "the type of all values" is so + /// prevalent and foundational, and it's useful to be able to instantiate this without having + /// to load the definition of `object` from the typeshed. + Object, /// A tuple type, e.g. `tuple[int, str]`. /// /// Note that the type `tuple[int, str]` includes subtypes of `tuple[int, str]`, @@ -514,7 +584,7 @@ impl<'db> ProtocolInstanceType<'db> { pub(super) fn is_equivalent_to_object(self, db: &'db dyn Db) -> bool { #[salsa::tracked(cycle_fn=recover, cycle_initial=initial, heap_size=ruff_memory_usage::heap_size)] fn inner<'db>(db: &'db dyn Db, protocol: ProtocolInstanceType<'db>, _: ()) -> bool { - Type::object(db) + Type::object() .satisfies_protocol( db, protocol, @@ -558,7 +628,7 @@ impl<'db> ProtocolInstanceType<'db> { visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { if self.is_equivalent_to_object(db) { - return Type::object(db); + return Type::object(); } match self.inner { Protocol::FromClass(_) => Type::ProtocolInstance(Self::synthesized( diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index b81ef61d7c..b1ba138c65 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -292,13 +292,13 @@ fn merge_constraints_or<'db>( *entry.get_mut() = UnionBuilder::new(db).add(*entry.get()).add(*value).build(); } Entry::Vacant(entry) => { - entry.insert(Type::object(db)); + entry.insert(Type::object()); } } } for (key, value) in into.iter_mut() { if !from.contains_key(key) { - *value = Type::object(db); + *value = Type::object(); } } } @@ -554,7 +554,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { } // Treat `bool` as `Literal[True, False]`. Type::NominalInstance(instance) - if instance.class(db).is_known(db, KnownClass::Bool) => + if instance.has_known_class(db, KnownClass::Bool) => { UnionType::from_elements( db, @@ -565,11 +565,11 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { } // Treat enums as a union of their members. Type::NominalInstance(instance) - if enum_metadata(db, instance.class(db).class_literal(db).0).is_some() => + if enum_metadata(db, instance.class_literal(db)).is_some() => { UnionType::from_elements( db, - enum_member_literals(db, instance.class(db).class_literal(db).0, None) + enum_member_literals(db, instance.class_literal(db), None) .expect("Calling `enum_member_literals` on an enum class") .map(|ty| filter_to_cannot_be_equal(db, ty, rhs_ty)), ) @@ -596,7 +596,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { fn evaluate_expr_ne(&mut self, lhs_ty: Type<'db>, rhs_ty: Type<'db>) -> Option> { match (lhs_ty, rhs_ty) { (Type::NominalInstance(instance), Type::IntLiteral(i)) - if instance.class(self.db).is_known(self.db, KnownClass::Bool) => + if instance.has_known_class(self.db, KnownClass::Bool) => { if i == 0 { Some(Type::BooleanLiteral(false).negate(self.db)) @@ -912,10 +912,8 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { // Since `hasattr` only checks if an attribute is readable, // the type of the protocol member should be a read-only property that returns `object`. - let constraint = Type::protocol_with_readonly_members( - self.db, - [(attr, Type::object(self.db))], - ); + let constraint = + Type::protocol_with_readonly_members(self.db, [(attr, Type::object())]); return Some(NarrowingConstraints::from_iter([( place, diff --git a/crates/ty_python_semantic/src/types/property_tests.rs b/crates/ty_python_semantic/src/types/property_tests.rs index f5a47001de..5c998fec42 100644 --- a/crates/ty_python_semantic/src/types/property_tests.rs +++ b/crates/ty_python_semantic/src/types/property_tests.rs @@ -133,13 +133,13 @@ mod stable { // All types should be assignable to `object` type_property_test!( all_types_assignable_to_object, db, - forall types t. t.is_assignable_to(db, Type::object(db)) + forall types t. t.is_assignable_to(db, Type::object()) ); // And all types should be subtypes of `object` type_property_test!( all_types_subtype_of_object, db, - forall types t. t.is_subtype_of(db, Type::object(db)) + forall types t. t.is_subtype_of(db, Type::object()) ); // Never should be assignable to every type @@ -182,7 +182,7 @@ mod stable { // Only `object` is a supertype of `Any`. type_property_test!( only_object_is_supertype_of_any, db, - forall types t. !t.is_equivalent_to(db, Type::object(db)) => !Type::any().is_subtype_of(db, t) + forall types t. !t.is_equivalent_to(db, Type::object()) => !Type::any().is_subtype_of(db, t) ); // Equivalence is commutative. @@ -332,6 +332,6 @@ mod flaky { // Currently flaky due to type_property_test!( all_type_assignable_to_iterable_are_iterable, db, - forall types t. t.is_assignable_to(db, KnownClass::Iterable.to_specialized_instance(db, [Type::object(db)])) => t.try_iterate(db).is_ok() + forall types t. t.is_assignable_to(db, KnownClass::Iterable.to_specialized_instance(db, [Type::object()])) => t.try_iterate(db).is_ok() ); } diff --git a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs index 0a296088ff..f46a1cb345 100644 --- a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs +++ b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs @@ -153,7 +153,7 @@ impl Ty { .place .expect_type(); debug_assert!( - matches!(ty, Type::NominalInstance(instance) if is_single_member_enum(db, instance.class(db).class_literal(db).0)) + matches!(ty, Type::NominalInstance(instance) if is_single_member_enum(db, instance.class_literal(db))) ); ty } diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 3705990d1c..3b8cea026d 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -227,7 +227,7 @@ impl<'db> ProtocolInterface<'db> { place: Place::bound(member.ty()), qualifiers: member.qualifiers(), }) - .unwrap_or_else(|| Type::object(db).member(db, name)) + .unwrap_or_else(|| Type::object().member(db, name)) } /// Return `true` if `self` extends the interface of `other`, i.e., diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 1159b0556d..f8f0fcb2f5 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -408,8 +408,8 @@ impl<'db> Signature<'db> { } /// Return the "bottom" signature, subtype of all other fully-static signatures. - pub(crate) fn bottom(db: &'db dyn Db) -> Self { - Self::new(Parameters::object(db), Some(Type::Never)) + pub(crate) fn bottom() -> Self { + Self::new(Parameters::object(), Some(Type::Never)) } pub(crate) fn with_inherited_generic_context( @@ -704,11 +704,11 @@ impl<'db> Signature<'db> { && self .parameters .variadic() - .is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object(db))) + .is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object())) && self .parameters .keyword_variadic() - .is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object(db))) + .is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object())) { return C::always_satisfiable(db); } @@ -1142,12 +1142,12 @@ impl<'db> Parameters<'db> { } /// Return parameters that represents `(*args: object, **kwargs: object)`. - pub(crate) fn object(db: &'db dyn Db) -> Self { + pub(crate) fn object() -> Self { Self { value: vec![ - Parameter::variadic(Name::new_static("args")).with_annotated_type(Type::object(db)), + Parameter::variadic(Name::new_static("args")).with_annotated_type(Type::object()), Parameter::keyword_variadic(Name::new_static("kwargs")) - .with_annotated_type(Type::object(db)), + .with_annotated_type(Type::object()), ], is_gradual: false, } @@ -1274,7 +1274,7 @@ impl<'db> Parameters<'db> { // so the "top" materialization here is the bottom materialization of the whole Signature. // It might make sense to flip the materialization here instead. TypeMapping::Materialize(MaterializationKind::Top) if self.is_gradual => { - Parameters::object(db) + Parameters::object() } // TODO: This is wrong, the empty Parameters is not a subtype of all materializations. // The bottom materialization is not currently representable and implementing it @@ -1779,8 +1779,7 @@ mod tests { Parameter::positional_or_keyword(Name::new_static("f")) .with_annotated_type(Type::IntLiteral(4)) .with_default_type(Type::IntLiteral(4)), - Parameter::variadic(Name::new_static("args")) - .with_annotated_type(Type::object(&db)), + Parameter::variadic(Name::new_static("args")).with_annotated_type(Type::object()), Parameter::keyword_only(Name::new_static("g")) .with_default_type(Type::IntLiteral(5)), Parameter::keyword_only(Name::new_static("h"))