diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index e3812035fe..17b7e101be 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -45,6 +45,7 @@ use crate::semantic_index::{imported_modules, place_table, semantic_index}; use crate::suppression::check_suppressions; use crate::types::bound_super::BoundSuperType; use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding}; +use crate::types::class::GenericAliasInstance; pub(crate) use crate::types::class_base::ClassBase; use crate::types::constraints::{ ConstraintSet, IteratorConstraintsExtension, OptionConstraintsExtension, @@ -759,7 +760,7 @@ pub enum Type<'db> { /// A specific class object ClassLiteral(ClassLiteral<'db>), /// A specialization of a generic class - GenericAlias(GenericAlias<'db>), + GenericAlias(GenericAliasInstance<'db>), /// The set of all class objects that are subclasses of the given class (C), spelled `type[C]`. SubclassOf(SubclassOfType<'db>), /// The set of Python objects with the given class in their __class__'s method resolution order. @@ -906,7 +907,7 @@ impl<'db> Type<'db> { matches!(self, Type::GenericAlias(_)) } - pub(crate) fn as_generic_alias(&self) -> Option> { + pub(crate) fn as_generic_alias(&self) -> Option> { match self { Type::GenericAlias(alias) => Some(*alias), _ => None, @@ -3822,13 +3823,20 @@ impl<'db> Type<'db> { } } - Type::GenericAlias(alias) if alias.is_typed_dict(db) => { - Some(alias.origin(db).typed_dict_member(db, None, name, policy)) - } + Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => Some( + instance + .alias(db) + .origin(db) + .typed_dict_member(db, None, name, policy), + ), - Type::GenericAlias(alias) => { - let attr = Some(ClassType::from(*alias).class_member(db, name, policy)); - match alias.specialization(db).materialization_kind(db) { + Type::GenericAlias(instance) => { + let attr = Some(ClassType::from(*instance).class_member(db, name, policy)); + match instance + .alias(db) + .specialization(db) + .materialization_kind(db) + { None => attr, Some(materialization_kind) => attr.map(|attr| { attr.materialize( @@ -5039,7 +5047,9 @@ impl<'db> Type<'db> { Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() { SubclassOfInner::Dynamic(_) => Truthiness::Ambiguous, SubclassOfInner::Class(class) => { - Type::from(class).try_bool_impl(db, allow_short_circuit, visitor)? + class + .into_type(db) + .try_bool_impl(db, allow_short_circuit, visitor)? } }, @@ -5770,7 +5780,7 @@ impl<'db> Type<'db> { // getting the signature here. This signature can still be used in some cases (e.g. // evaluating callable subtyping). TODO improve this definition (intersection of // `__new__` and `__init__` signatures? and respect metaclass `__call__`). - SubclassOfInner::Class(class) => Type::from(class).bindings(db), + SubclassOfInner::Class(class) => class.into_type(db).bindings(db), }, Type::NominalInstance(_) | Type::ProtocolInstance(_) | Type::NewTypeInstance(_) => { @@ -5972,7 +5982,7 @@ impl<'db> Type<'db> { match ty { Type::NominalInstance(nominal) => nominal.tuple_spec(db), Type::NewTypeInstance(newtype) => non_async_special_case(db, Type::instance(db, newtype.base_class_type(db))), - Type::GenericAlias(alias) if alias.origin(db).is_tuple(db) => { + Type::GenericAlias(instance) if instance.alias(db).origin(db).is_tuple(db) => { Some(Cow::Owned(TupleSpec::homogeneous(todo_type!( "*tuple[] annotations" )))) @@ -6418,7 +6428,7 @@ impl<'db> Type<'db> { // It is important that identity_specialization specializes the class with // _inferable_ typevars, so that our specialization inference logic will // try to find a specialization for them. - Type::from(class.identity_specialization(db)), + class.identity_specialization(db).into_type(db), ), _ => (None, None, self), }, @@ -6714,8 +6724,10 @@ impl<'db> Type<'db> { }; Ok(ty) } - Type::GenericAlias(alias) if alias.is_typed_dict(db) => Ok(Type::typed_dict(*alias)), - Type::GenericAlias(alias) => Ok(Type::instance(db, ClassType::from(*alias))), + Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => { + Ok(Type::typed_dict(*instance)) + } + Type::GenericAlias(instance) => Ok(Type::instance(db, ClassType::from(*instance))), Type::SubclassOf(_) | Type::BooleanLiteral(_) @@ -7098,7 +7110,7 @@ impl<'db> Type<'db> { // understand a more specific meta type in order to correctly handle `__getitem__`. Type::TypedDict(typed_dict) => SubclassOfType::from(db, typed_dict.defining_class()), Type::TypeAlias(alias) => alias.value_type(db).to_meta_type(db), - Type::NewTypeInstance(newtype) => Type::from(newtype.base_class_type(db)), + Type::NewTypeInstance(newtype) => newtype.base_class_type(db).into_type(db), } } @@ -7116,7 +7128,7 @@ impl<'db> Type<'db> { [KnownClass::Str.to_instance(db), Type::object()], None, ) - .map(Type::from) + .map(|class| class.into_type(db)) // Guard against user-customized typesheds with a broken `dict` class .unwrap_or_else(Type::unknown); } @@ -7874,7 +7886,7 @@ impl<'db> Type<'db> { pub(crate) fn generic_origin(self, db: &'db dyn Db) -> Option> { match self { - Type::GenericAlias(generic) => Some(generic.origin(db)), + Type::GenericAlias(instance) => Some(instance.origin(db)), Type::NominalInstance(instance) => { if let ClassType::Generic(generic) = instance.class(db) { Some(generic.origin(db)) @@ -7934,7 +7946,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> { Type::NominalInstance(nominal_instance_type) => { nominal_instance_type.variance_of(db, typevar) } - Type::GenericAlias(generic_alias) => generic_alias.variance_of(db, typevar), + Type::GenericAlias(instance) => instance.alias(db).variance_of(db, typevar), Type::Callable(callable_type) => callable_type.signatures(db).variance_of(db, typevar), // A type variable is always covariant in itself. Type::TypeVar(other_typevar) if other_typevar == typevar => { @@ -8259,7 +8271,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } KnownInstanceType::NewType(newtype) => { if let ClassType::Generic(generic_alias) = newtype.base_class_type(db) { - visitor.visit_generic_alias_type(db, generic_alias); + visitor.visit_generic_alias_type(db, generic_alias.alias(db)); } } } diff --git a/crates/ty_python_semantic/src/types/bound_super.rs b/crates/ty_python_semantic/src/types/bound_super.rs index 65f9295a5e..7c2d8b14b1 100644 --- a/crates/ty_python_semantic/src/types/bound_super.rs +++ b/crates/ty_python_semantic/src/types/bound_super.rs @@ -76,9 +76,11 @@ impl<'db> BoundSuperError<'db> { BoundSuperError::InvalidPivotClassType { pivot_class } => { if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) { match pivot_class { - Type::GenericAlias(alias) => builder.into_diagnostic(format_args!( + Type::GenericAlias(instance) => builder.into_diagnostic(format_args!( "`types.GenericAlias` instance `{}` is not a valid class", - alias.display_with(context.db(), DisplaySettings::default()), + instance + .alias(context.db()) + .display_with(context.db(), DisplaySettings::default()), )), _ => builder.into_diagnostic(format_args!( "`{pivot_class}` is not a valid class", @@ -209,13 +211,11 @@ impl<'db> SuperOwnerKind<'db> { SuperOwnerKind::Instance(instance) => Some(instance.class(db)), } } -} -impl<'db> From> for Type<'db> { - fn from(owner: SuperOwnerKind<'db>) -> Self { - match owner { + pub fn into_type(self, db: &'db dyn Db) -> Type<'db> { + match self { SuperOwnerKind::Dynamic(dynamic) => Type::Dynamic(dynamic), - SuperOwnerKind::Class(class) => class.into(), + SuperOwnerKind::Class(class) => class.into_type(db), SuperOwnerKind::Instance(instance) => instance.into(), } } @@ -236,8 +236,8 @@ pub(super) fn walk_bound_super_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( bound_super: BoundSuperType<'db>, visitor: &V, ) { - visitor.visit_type(db, Type::from(bound_super.pivot_class(db))); - visitor.visit_type(db, Type::from(bound_super.owner(db))); + visitor.visit_type(db, bound_super.pivot_class(db).into_type(db)); + visitor.visit_type(db, bound_super.owner(db).into_type(db)); } impl<'db> BoundSuperType<'db> { @@ -515,12 +515,12 @@ impl<'db> BoundSuperType<'db> { db, attribute, Type::none(db), - Type::from(owner), + owner.into_type(db), ) .0, ), SuperOwnerKind::Instance(_) => { - let owner = Type::from(owner); + let owner = owner.into_type(db); Some( Type::try_call_dunder_get_on_attribute( db, diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 7f7a87caa0..2504a4757a 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -233,8 +233,6 @@ impl<'db> CodeGeneratorKind<'db> { pub struct GenericAlias<'db> { pub(crate) origin: ClassLiteral<'db>, pub(crate) specialization: Specialization<'db>, - - pub(crate) binding_context: Option>, } pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>( @@ -254,7 +252,6 @@ impl<'db> GenericAlias<'db> { db, self.origin(db), self.specialization(db).normalized_impl(db, visitor), - self.binding_context(db), ) } @@ -280,7 +277,6 @@ impl<'db> GenericAlias<'db> { self.origin(db), self.specialization(db) .apply_type_mapping_impl(db, type_mapping, tcx, visitor), - self.binding_context(db), ) } @@ -300,9 +296,60 @@ impl<'db> GenericAlias<'db> { } } -impl<'db> From> for Type<'db> { - fn from(alias: GenericAlias<'db>) -> Type<'db> { - Type::GenericAlias(alias) +#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)] +#[derive(PartialOrd, Ord)] +pub struct GenericAliasInstance<'db> { + pub alias: GenericAlias<'db>, + pub binding_context: Option>, +} + +impl get_size2::GetSize for GenericAliasInstance<'_> {} + +impl<'db> GenericAliasInstance<'db> { + pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + Self::new( + db, + self.alias(db).normalized_impl(db, visitor), + self.binding_context(db), + ) + } + + pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> { + self.alias(db).definition(db) + } + + pub(crate) fn origin(self, db: &'db dyn Db) -> ClassLiteral<'db> { + self.alias(db).origin(db) + } + + pub(crate) fn specialization(self, db: &'db dyn Db) -> Specialization<'db> { + self.alias(db).specialization(db) + } + + pub(super) fn apply_type_mapping_impl<'a>( + self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + tcx: TypeContext<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { + Self::new( + db, + self.alias(db) + .apply_type_mapping_impl(db, type_mapping, tcx, visitor), + self.binding_context(db), + ) + } + + pub(super) fn find_legacy_typevars_impl( + self, + db: &'db dyn Db, + binding_context: Option>, + typevars: &mut FxOrderSet>, + visitor: &FindLegacyTypeVarsVisitor<'db>, + ) { + self.alias(db) + .find_legacy_typevars_impl(db, binding_context, typevars, visitor); } } @@ -372,7 +419,7 @@ pub enum ClassType<'db> { // should use `ClassLiteral::default_specialization` instead of assuming // `ClassType::NonGeneric`. NonGeneric(ClassLiteral<'db>), - Generic(GenericAlias<'db>), + Generic(GenericAliasInstance<'db>), } #[salsa::tracked] @@ -389,10 +436,17 @@ impl<'db> ClassType<'db> { matches!(self, Self::Generic(_)) } - pub(super) const fn into_generic_alias(self) -> Option> { + pub(super) fn into_generic_alias(self, db: &'db dyn Db) -> Option> { match self { Self::NonGeneric(_) => None, - Self::Generic(generic) => Some(generic), + Self::Generic(instance) => Some(instance.alias(db)), + } + } + + pub(super) fn into_type(self, db: &'db dyn Db) -> Type<'db> { + match self { + Self::NonGeneric(class) => class.into(), + Self::Generic(generic) => Type::GenericAlias(generic), } } @@ -1062,7 +1116,7 @@ impl<'db> ClassType<'db> { /// constructor signature of this class. #[salsa::tracked(cycle_initial=into_callable_cycle_initial, heap_size=ruff_memory_usage::heap_size)] pub(super) fn into_callable(self, db: &'db dyn Db) -> CallableTypes<'db> { - let self_ty = Type::from(self); + let self_ty = self.into_type(db); let metaclass_dunder_call_function_symbol = self_ty .member_lookup_with_policy( db, @@ -1226,26 +1280,17 @@ fn into_callable_cycle_initial<'db>( CallableTypes::one(CallableType::bottom(db)) } -impl<'db> From> for ClassType<'db> { - fn from(generic: GenericAlias<'db>) -> ClassType<'db> { +impl<'db> From> for ClassType<'db> { + fn from(generic: GenericAliasInstance<'db>) -> ClassType<'db> { ClassType::Generic(generic) } } -impl<'db> From> for Type<'db> { - fn from(class: ClassType<'db>) -> Type<'db> { - match class { - ClassType::NonGeneric(non_generic) => non_generic.into(), - ClassType::Generic(generic) => generic.into(), - } - } -} - impl<'db> VarianceInferable<'db> for ClassType<'db> { fn variance_of(self, db: &'db dyn Db, typevar: BoundTypeVarInstance<'db>) -> TypeVarVariance { match self { Self::NonGeneric(class) => class.variance_of(db, typevar), - Self::Generic(generic) => generic.variance_of(db, typevar), + Self::Generic(generic) => generic.alias(db).variance_of(db, typevar), } } } @@ -1550,7 +1595,11 @@ impl<'db> ClassLiteral<'db> { } } - ClassType::Generic(GenericAlias::new(db, self, specialization, binding_context)) + ClassType::Generic(GenericAliasInstance::new( + db, + GenericAlias::new(db, self, specialization), + binding_context, + )) } } } @@ -1646,7 +1695,7 @@ impl<'db> ClassLiteral<'db> { Box::new([ definition_expression_type(db, class_definition, &class_stmt.bases()[0]), - Type::from(tuple_type.to_class_type(db, None)), + tuple_type.to_class_type(db, None).into_type(db), ]) } else { class_stmt @@ -1983,7 +2032,7 @@ impl<'db> ClassLiteral<'db> { let (metaclass_literal, _) = candidate.metaclass.class_literal(db); Ok(( - candidate.metaclass.into(), + candidate.metaclass.into_type(db), metaclass_literal.dataclass_transformer_params(db), )) } @@ -2061,7 +2110,7 @@ impl<'db> ClassLiteral<'db> { // Note: calling `Type::from(superclass).member()` would be incorrect here. // What we'd really want is a `Type::Any.own_class_member()` method, // but adding such a method wouldn't make much sense -- it would always return `Any`! - dynamic_type_to_intersect_with.get_or_insert(Type::from(superclass)); + dynamic_type_to_intersect_with.get_or_insert(superclass.into_type(db)); } ClassBase::Class(class) => { let known = class.known(db); @@ -4855,7 +4904,7 @@ impl KnownClass { "Use `Type::heterogeneous_tuple` or `Type::homogeneous_tuple` to create `tuple` instances" ); self.to_specialized_class_type(db, specialization, None) - .and_then(|class_type| Type::from(class_type).to_instance(db)) + .and_then(|class_type| class_type.into_type(db).to_instance(db)) .unwrap_or_else(Type::unknown) } diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index e392df287f..dd55212c39 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -240,7 +240,7 @@ impl<'db> ClassBase<'db> { fields.values().map(|field| field.declared_ty), )? .to_class_type(db, None) - .into(), + .into_type(db), subclass, ) } @@ -383,7 +383,7 @@ impl<'db> ClassBase<'db> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.base { ClassBase::Dynamic(dynamic) => dynamic.fmt(f), - ClassBase::Class(class) => Type::from(class).display(self.db).fmt(f), + ClassBase::Class(class) => class.into_type(self.db).display(self.db).fmt(f), ClassBase::Protocol => f.write_str("typing.Protocol"), ClassBase::Generic => f.write_str("typing.Generic"), ClassBase::TypedDict => f.write_str("typing.TypedDict"), @@ -393,19 +393,11 @@ impl<'db> ClassBase<'db> { ClassBaseDisplay { db, base: self } } -} -impl<'db> From> for ClassBase<'db> { - fn from(value: ClassType<'db>) -> Self { - ClassBase::Class(value) - } -} - -impl<'db> From> for Type<'db> { - fn from(value: ClassBase<'db>) -> Self { - match value { + pub fn into_type(self, db: &'db dyn Db) -> Type<'db> { + match self { ClassBase::Dynamic(dynamic) => Type::Dynamic(dynamic), - ClassBase::Class(class) => class.into(), + ClassBase::Class(class) => class.into_type(db), ClassBase::Protocol => Type::SpecialForm(SpecialFormType::Protocol), ClassBase::Generic => Type::SpecialForm(SpecialFormType::Generic), ClassBase::TypedDict => Type::SpecialForm(SpecialFormType::TypedDict), @@ -413,9 +405,9 @@ impl<'db> From> for Type<'db> { } } -impl<'db> From<&ClassBase<'db>> for Type<'db> { - fn from(value: &ClassBase<'db>) -> Self { - Self::from(*value) +impl<'db> From> for ClassBase<'db> { + fn from(value: ClassType<'db>) -> Self { + ClassBase::Class(value) } } diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index 050a55fb93..16a5200bec 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -2506,9 +2506,9 @@ pub(super) fn report_possibly_missing_attribute( "Attribute `{attribute}` may be missing on class `{}`", class.name(db), )), - Type::GenericAlias(alias) => builder.into_diagnostic(format_args!( + Type::GenericAlias(instance) => builder.into_diagnostic(format_args!( "Attribute `{attribute}` may be missing on class `{}`", - alias.display(db), + instance.alias(db).display(db), )), _ => builder.into_diagnostic(format_args!( "Attribute `{attribute}` may be missing on object of type `{}`", diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 78bd91b795..d4ddda7601 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -416,11 +416,11 @@ impl<'db> super::visitor::TypeVisitor<'db> for AmbiguousClassCollector<'db> { Type::ProtocolInstance(ProtocolInstanceType { inner: Protocol::FromClass(class), .. - }) => return self.visit_type(db, Type::from(class)), + }) => return self.visit_type(db, class.into_type(db)), _ => {} } - if let visitor::TypeKind::NonAtomic(t) = visitor::TypeKind::from(ty) { + if let visitor::TypeKind::NonAtomic(t) = visitor::TypeKind::from_type(db, ty) { if !self.visited_types.borrow_mut().insert(ty) { // If we have already seen this type, we can skip it. return; @@ -599,7 +599,7 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> { (ClassType::NonGeneric(class), _) => { class.display_with(self.db, self.settings.clone()).fmt_detailed(f) }, - (ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings.clone()).fmt_detailed(f), + (ClassType::Generic(instance), _) => instance.alias(self.db).display_with(self.db, self.settings.clone()).fmt_detailed(f), } } Type::ProtocolInstance(protocol) => match protocol.inner { @@ -607,7 +607,8 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> { ClassType::NonGeneric(class) => class .display_with(self.db, self.settings.clone()) .fmt_detailed(f), - ClassType::Generic(alias) => alias + ClassType::Generic(instance) => instance + .alias(self.db) .display_with(self.db, self.settings.clone()) .fmt_detailed(f), }, @@ -653,6 +654,7 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> { let mut f = f.with_type(self.ty); f.write_str("") @@ -667,11 +669,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> { .fmt_detailed(f)?; f.write_char(']') } - SubclassOfInner::Class(ClassType::Generic(alias)) => { + SubclassOfInner::Class(ClassType::Generic(instance)) => { f.with_type(KnownClass::Type.to_class_literal(self.db)) .write_str("type")?; f.write_char('[')?; - alias + instance + .alias(self.db) .display_with(self.db, self.settings.clone()) .fmt_detailed(f)?; f.write_char(']') @@ -861,11 +864,15 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> { Type::BoundSuper(bound_super) => { f.set_invalid_syntax(); f.write_str("") diff --git a/crates/ty_python_semantic/src/types/enums.rs b/crates/ty_python_semantic/src/types/enums.rs index dbde339221..38cc77de38 100644 --- a/crates/ty_python_semantic/src/types/enums.rs +++ b/crates/ty_python_semantic/src/types/enums.rs @@ -154,7 +154,7 @@ pub(crate) fn enum_metadata<'db>( .skip(1) .filter_map(ClassBase::into_class) .filter(|class| { - !Type::from(*class).is_subtype_of( + !class.into_type(db).is_subtype_of( db, KnownClass::Enum.to_subclass_of(db), ) diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index 0603413396..be0c045409 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -1609,7 +1609,7 @@ impl<'db> SpecializationBuilder<'db> { // Extract formal_alias if this is a generic class let formal_alias = match formal { Type::NominalInstance(formal_nominal) => { - formal_nominal.class(self.db).into_generic_alias() + formal_nominal.class(self.db).into_generic_alias(self.db) } // TODO: This will only handle classes that explicit implement a generic protocol // by listing it as a base class. To handle classes that implicitly implement a @@ -1618,7 +1618,7 @@ impl<'db> SpecializationBuilder<'db> { Type::ProtocolInstance(ProtocolInstanceType { inner: Protocol::FromClass(class), .. - }) => class.into_generic_alias(), + }) => class.into_generic_alias(self.db), _ => None, }; diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs index 779a34b0fe..df0c52ae88 100644 --- a/crates/ty_python_semantic/src/types/ide_support.rs +++ b/crates/ty_python_semantic/src/types/ide_support.rs @@ -150,7 +150,7 @@ impl<'db> AllMembers<'db> { self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db)); } - Type::GenericAlias(generic_alias) if generic_alias.is_typed_dict(db) => { + Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => { self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db)); } diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index c36a797ae8..da28ad4ef5 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -7502,7 +7502,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let class_type = class_literal.apply_specialization(self.db(), |_| builder.build(generic_context), None); - Type::from(class_type).to_instance(self.db()) + class_type.into_type(self.db()).to_instance(self.db()) } /// Infer the type of the `iter` expression of the first comprehension. @@ -9147,9 +9147,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { "Class `{}` has no attribute `{attr_name}`", class.name(db), )), - Type::GenericAlias(alias) => builder.into_diagnostic(format_args!( + Type::GenericAlias(instance) => builder.into_diagnostic(format_args!( "Class `{}` has no attribute `{attr_name}`", - alias.display(db), + instance.alias(db).display(db), )), Type::FunctionLiteral(function) => builder.into_diagnostic(format_args!( "Function `{}` has no attribute `{attr_name}`", @@ -10813,11 +10813,12 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // If we have an implicit type alias like `MyList = list[T]`, and if `MyList` is being // used in another implicit type alias like `Numbers = MyList[int]`, then we infer the // right hand side as a value expression, and need to handle the specialization here. - if let Some(alias) = value_ty.as_generic_alias() { + if let Some(instance) = value_ty.as_generic_alias() { let return_ty = self.infer_explicitly_specialized_type_alias( subscript, value_ty, - alias.binding_context(self.db()), + // alias.binding_context(self.db()), + instance.binding_context(self.db()), false, ); @@ -10864,7 +10865,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let typevar_binding_context = self.typevar_binding_context; let tuple_generic_alias = |tuple: Option>| { let tuple = tuple.unwrap_or_else(|| TupleType::homogeneous(db, Type::unknown())); - Type::from(tuple.to_class_type(db, typevar_binding_context)) + tuple + .to_class_type(db, typevar_binding_context) + .into_type(db) }; match value_ty { @@ -11075,7 +11078,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { [element_ty], self.typevar_binding_context, ) - .map(Type::from) + .map(|class_type| class_type.into_type(self.db())) .unwrap_or_else(Type::unknown); } // `typing` special forms with two generic arguments @@ -11137,7 +11140,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { [first_ty, second_ty], self.typevar_binding_context, ) - .map(Type::from) + .map(|class_type| class_type.into_type(self.db())) .unwrap_or_else(Type::unknown); } Type::KnownInstance(KnownInstanceType::UnionType(instance)) => { @@ -11185,11 +11188,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let db = self.db(); let typevar_binding_context = self.typevar_binding_context; let specialize = |types: &[Option>]| { - Type::from(generic_class.apply_specialization( - db, - |_| generic_context.specialize_partial(db, types.iter().copied()), - typevar_binding_context, - )) + generic_class + .apply_specialization( + db, + |_| generic_context.specialize_partial(db, types.iter().copied()), + typevar_binding_context, + ) + .into_type(db) }; self.infer_explicit_callable_specialization( 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 8801217759..b279e64f53 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 @@ -4,6 +4,7 @@ use ruff_python_ast as ast; use super::{DeferredExpressionState, TypeInferenceBuilder}; use crate::FxOrderSet; use crate::semantic_index::definition::Definition; +use crate::types::class::GenericAliasInstance; use crate::types::diagnostic::{ self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form, report_invalid_arguments_to_callable, @@ -810,10 +811,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> { } else { // Update the binding context match specialized { - Type::GenericAlias(alias) => Type::GenericAlias(GenericAlias::new( + Type::GenericAlias(alias) => Type::GenericAlias(GenericAliasInstance::new( db, - alias.origin(db), - alias.specialization(db), + GenericAlias::new(db, alias.origin(db), alias.specialization(db)), current_typevar_binding_context, )), Type::KnownInstance(KnownInstanceType::TypeGenericAlias(instance)) => { diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index a0218e4276..6c43070dd0 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -207,7 +207,7 @@ pub(super) fn walk_nominal_instance_type<'db, V: super::visitor::TypeVisitor<'db nominal: NominalInstanceType<'db>, visitor: &V, ) { - visitor.visit_type(db, nominal.class(db).into()); + visitor.visit_type(db, nominal.class(db).into_type(db)); } impl<'db> NominalInstanceType<'db> { @@ -279,7 +279,7 @@ impl<'db> NominalInstanceType<'db> { } KnownClass::Tuple => Some( class - .into_generic_alias() + .into_generic_alias(db) .and_then(|alias| { Some(Cow::Borrowed(alias.specialization(db).tuple(db)?)) }) diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 8bfc0525a6..7b2ae858a0 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -144,6 +144,10 @@ impl<'db> ProtocolClass<'db> { .apply_type_mapping_impl(db, type_mapping, tcx, visitor), ) } + + pub(super) fn into_type(self, db: &'db dyn Db) -> Type<'db> { + self.0.into_type(db) + } } impl<'db> Deref for ProtocolClass<'db> { @@ -154,12 +158,6 @@ impl<'db> Deref for ProtocolClass<'db> { } } -impl<'db> From> for Type<'db> { - fn from(value: ProtocolClass<'db>) -> Self { - Self::from(value.0) - } -} - /// The interface of a protocol: the members of that protocol, and the types of those members. /// /// # Ordering diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs index 687d5aaad0..a59675b740 100644 --- a/crates/ty_python_semantic/src/types/subclass_of.rs +++ b/crates/ty_python_semantic/src/types/subclass_of.rs @@ -26,7 +26,7 @@ pub(super) fn walk_subclass_of_type<'db, V: super::visitor::TypeVisitor<'db> + ? subclass_of: SubclassOfType<'db>, visitor: &V, ) { - visitor.visit_type(db, Type::from(subclass_of.subclass_of)); + visitor.visit_type(db, subclass_of.subclass_of.into_type(db)); } impl<'db> SubclassOfType<'db> { @@ -47,7 +47,7 @@ impl<'db> SubclassOfType<'db> { SubclassOfInner::Dynamic(_) => Type::SubclassOf(Self { subclass_of }), SubclassOfInner::Class(class) => { if class.is_final(db) { - Type::from(class) + class.into_type(db) } else if class.is_object(db) { KnownClass::Type.to_instance(db) } else { @@ -129,7 +129,9 @@ impl<'db> SubclassOfType<'db> { name: &str, policy: MemberLookupPolicy, ) -> Option> { - Type::from(self.subclass_of).find_name_in_mro_with_policy(db, name, policy) + self.subclass_of + .into_type(db) + .find_name_in_mro_with_policy(db, name, policy) } /// Return `true` if `self` has a certain relation to `other`. @@ -276,6 +278,13 @@ impl<'db> SubclassOfInner<'db> { _ => None, } } + + pub(crate) fn into_type(self, db: &'db dyn Db) -> Type<'db> { + match self { + SubclassOfInner::Dynamic(dynamic) => Type::Dynamic(dynamic), + SubclassOfInner::Class(class) => class.into_type(db), + } + } } impl<'db> From> for SubclassOfInner<'db> { @@ -295,12 +304,3 @@ impl<'db> From> for SubclassOfInner<'db> { SubclassOfInner::Class(*value) } } - -impl<'db> From> for Type<'db> { - fn from(value: SubclassOfInner<'db>) -> Self { - match value { - SubclassOfInner::Dynamic(dynamic) => Type::Dynamic(dynamic), - SubclassOfInner::Class(class) => class.into(), - } - } -} diff --git a/crates/ty_python_semantic/src/types/typed_dict.rs b/crates/ty_python_semantic/src/types/typed_dict.rs index 7a22f62507..7c9a51835f 100644 --- a/crates/ty_python_semantic/src/types/typed_dict.rs +++ b/crates/ty_python_semantic/src/types/typed_dict.rs @@ -253,7 +253,7 @@ pub(crate) fn walk_typed_dict_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( typed_dict: TypedDictType<'db>, visitor: &V, ) { - visitor.visit_type(db, typed_dict.defining_class.into()); + visitor.visit_type(db, typed_dict.defining_class.into_type(db)); } pub(super) fn typed_dict_params_from_class_def(class_stmt: &StmtClassDef) -> TypedDictParams { diff --git a/crates/ty_python_semantic/src/types/visitor.rs b/crates/ty_python_semantic/src/types/visitor.rs index 7692c205ff..8780987a6e 100644 --- a/crates/ty_python_semantic/src/types/visitor.rs +++ b/crates/ty_python_semantic/src/types/visitor.rs @@ -144,8 +144,8 @@ pub(super) enum TypeKind<'db> { NonAtomic(NonAtomicType<'db>), } -impl<'db> From> for TypeKind<'db> { - fn from(ty: Type<'db>) -> Self { +impl<'db> TypeKind<'db> { + pub(super) fn from_type(db: &'db dyn Db, ty: Type<'db>) -> Self { match ty { Type::AlwaysFalsy | Type::AlwaysTruthy @@ -180,7 +180,9 @@ impl<'db> From> for TypeKind<'db> { TypeKind::NonAtomic(NonAtomicType::MethodWrapper(method_wrapper)) } Type::Callable(callable) => TypeKind::NonAtomic(NonAtomicType::Callable(callable)), - Type::GenericAlias(alias) => TypeKind::NonAtomic(NonAtomicType::GenericAlias(alias)), + Type::GenericAlias(instance) => { + TypeKind::NonAtomic(NonAtomicType::GenericAlias(instance.alias(db))) + } Type::KnownInstance(known_instance) => { TypeKind::NonAtomic(NonAtomicType::KnownInstance(known_instance)) } @@ -260,7 +262,7 @@ pub(crate) fn walk_type_with_recursion_guard<'db>( visitor: &impl TypeVisitor<'db>, recursion_guard: &TypeCollector<'db>, ) { - match TypeKind::from(ty) { + match TypeKind::from_type(db, ty) { TypeKind::Atomic => {} TypeKind::NonAtomic(non_atomic_type) => { if recursion_guard.type_was_already_seen(ty) { @@ -349,7 +351,7 @@ fn specialization_depth(db: &dyn Db, ty: Type<'_>) -> usize { } fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) { - match TypeKind::from(ty) { + match TypeKind::from_type(db, ty) { TypeKind::Atomic => { if ty.is_divergent() { self.max_depth.set(usize::MAX);