Compare commits
1 Commits
david/gene
...
david/gene
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96e7ebb588 |
@@ -45,7 +45,6 @@ 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,
|
||||
@@ -760,7 +759,7 @@ pub enum Type<'db> {
|
||||
/// A specific class object
|
||||
ClassLiteral(ClassLiteral<'db>),
|
||||
/// A specialization of a generic class
|
||||
GenericAlias(GenericAliasInstance<'db>),
|
||||
GenericAlias(GenericAlias<'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.
|
||||
@@ -907,12 +906,12 @@ impl<'db> Type<'db> {
|
||||
matches!(self, Type::GenericAlias(_))
|
||||
}
|
||||
|
||||
pub(crate) fn as_generic_alias(&self) -> Option<GenericAliasInstance<'db>> {
|
||||
match self {
|
||||
Type::GenericAlias(alias) => Some(*alias),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
// pub(crate) fn as_generic_alias(&self) -> Option<GenericAlias<'db>> {
|
||||
// match self {
|
||||
// Type::GenericAlias(alias) => Some(*alias),
|
||||
// _ => None,
|
||||
// }
|
||||
// }
|
||||
|
||||
const fn is_dynamic(&self) -> bool {
|
||||
matches!(self, Type::Dynamic(_))
|
||||
@@ -1160,7 +1159,7 @@ impl<'db> Type<'db> {
|
||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> Option<ClassType<'db>> {
|
||||
match self {
|
||||
Type::ClassLiteral(class_literal) => Some(class_literal.default_specialization(db)),
|
||||
Type::GenericAlias(instance) => Some(ClassType::Generic(instance.alias(db))),
|
||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1284,8 +1283,8 @@ impl<'db> Type<'db> {
|
||||
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
|
||||
}
|
||||
|
||||
pub(crate) fn typed_dict(defining_class: ClassType<'db>) -> Self {
|
||||
Self::TypedDict(TypedDictType::new(defining_class))
|
||||
pub(crate) fn typed_dict(defining_class: impl Into<ClassType<'db>>) -> Self {
|
||||
Self::TypedDict(TypedDictType::new(defining_class.into()))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -1570,9 +1569,7 @@ impl<'db> Type<'db> {
|
||||
Some(class_literal.default_specialization(db).into_callable(db))
|
||||
}
|
||||
|
||||
Type::GenericAlias(instance) => {
|
||||
Some(ClassType::Generic(instance.alias(db)).into_callable(db))
|
||||
}
|
||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias).into_callable(db)),
|
||||
|
||||
Type::NewTypeInstance(newtype) => {
|
||||
Type::instance(db, newtype.base_class_type(db)).try_upcast_to_callable(db)
|
||||
@@ -2419,22 +2416,20 @@ impl<'db> Type<'db> {
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability())),
|
||||
(Type::GenericAlias(instance), Type::SubclassOf(target_subclass_ty)) => {
|
||||
target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
.map(|subclass_of_class| {
|
||||
ClassType::Generic(instance.alias(db)).has_relation_to_impl(
|
||||
db,
|
||||
subclass_of_class,
|
||||
inferable,
|
||||
relation,
|
||||
relation_visitor,
|
||||
disjointness_visitor,
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability()))
|
||||
}
|
||||
(Type::GenericAlias(alias), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
.map(|subclass_of_class| {
|
||||
ClassType::Generic(alias).has_relation_to_impl(
|
||||
db,
|
||||
subclass_of_class,
|
||||
inferable,
|
||||
relation,
|
||||
relation_visitor,
|
||||
disjointness_visitor,
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability())),
|
||||
|
||||
// This branch asks: given two types `type[T]` and `type[S]`, is `type[T]` a subtype of `type[S]`?
|
||||
(Type::SubclassOf(self_subclass_ty), Type::SubclassOf(target_subclass_ty)) => {
|
||||
@@ -2461,7 +2456,7 @@ impl<'db> Type<'db> {
|
||||
disjointness_visitor,
|
||||
)
|
||||
}
|
||||
(Type::GenericAlias(instance), _) => ClassType::Generic(instance.alias(db))
|
||||
(Type::GenericAlias(alias), _) => ClassType::from(alias)
|
||||
.metaclass_instance_type(db)
|
||||
.has_relation_to_impl(
|
||||
db,
|
||||
@@ -3185,7 +3180,7 @@ impl<'db> Type<'db> {
|
||||
| (Type::GenericAlias(alias_b), Type::SubclassOf(subclass_of_ty)) => {
|
||||
match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Dynamic(_) => ConstraintSet::from(false),
|
||||
SubclassOfInner::Class(class_a) => ClassType::Generic(alias_b.alias(db))
|
||||
SubclassOfInner::Class(class_a) => ClassType::from(alias_b)
|
||||
.when_subclass_of(db, class_a, inferable)
|
||||
.negate(db),
|
||||
}
|
||||
@@ -3300,9 +3295,9 @@ impl<'db> Type<'db> {
|
||||
.metaclass_instance_type(db)
|
||||
.when_subtype_of(db, instance, inferable)
|
||||
.negate(db),
|
||||
(Type::GenericAlias(generic), instance @ Type::NominalInstance(_))
|
||||
| (instance @ Type::NominalInstance(_), Type::GenericAlias(generic)) => {
|
||||
ClassType::Generic(generic.alias(db))
|
||||
(Type::GenericAlias(alias), instance @ Type::NominalInstance(_))
|
||||
| (instance @ Type::NominalInstance(_), Type::GenericAlias(alias)) => {
|
||||
ClassType::from(alias)
|
||||
.metaclass_instance_type(db)
|
||||
.has_relation_to_impl(
|
||||
db,
|
||||
@@ -3827,21 +3822,13 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
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) if alias.is_typed_dict(db) => {
|
||||
Some(alias.origin(db).typed_dict_member(db, None, name, policy))
|
||||
}
|
||||
|
||||
Type::GenericAlias(instance) => {
|
||||
let attr =
|
||||
Some(ClassType::Generic(instance.alias(db)).class_member(db, name, policy));
|
||||
match instance
|
||||
.alias(db)
|
||||
.specialization(db)
|
||||
.materialization_kind(db)
|
||||
{
|
||||
Type::GenericAlias(alias) => {
|
||||
let attr = Some(ClassType::from(*alias).class_member(db, name, policy));
|
||||
match alias.specialization(db).materialization_kind(db) {
|
||||
None => attr,
|
||||
Some(materialization_kind) => attr.map(|attr| {
|
||||
attr.materialize(
|
||||
@@ -5045,16 +5032,14 @@ impl<'db> Type<'db> {
|
||||
.metaclass_instance_type(db)
|
||||
.try_bool_impl(db, allow_short_circuit, visitor)?
|
||||
}
|
||||
Type::GenericAlias(generic) => ClassType::Generic(generic.alias(db))
|
||||
Type::GenericAlias(alias) => ClassType::from(*alias)
|
||||
.metaclass_instance_type(db)
|
||||
.try_bool_impl(db, allow_short_circuit, visitor)?,
|
||||
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Dynamic(_) => Truthiness::Ambiguous,
|
||||
SubclassOfInner::Class(class) => {
|
||||
class
|
||||
.into_type(db)
|
||||
.try_bool_impl(db, allow_short_circuit, visitor)?
|
||||
Type::from(class).try_bool_impl(db, allow_short_circuit, visitor)?
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5785,7 +5770,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) => class.into_type(db).bindings(db),
|
||||
SubclassOfInner::Class(class) => Type::from(class).bindings(db),
|
||||
},
|
||||
|
||||
Type::NominalInstance(_) | Type::ProtocolInstance(_) | Type::NewTypeInstance(_) => {
|
||||
@@ -5987,7 +5972,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(instance) if instance.alias(db).origin(db).is_tuple(db) => {
|
||||
Type::GenericAlias(alias) if alias.origin(db).is_tuple(db) => {
|
||||
Some(Cow::Owned(TupleSpec::homogeneous(todo_type!(
|
||||
"*tuple[] annotations"
|
||||
))))
|
||||
@@ -6433,7 +6418,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.
|
||||
class.identity_specialization(db).into_type(db),
|
||||
Type::from(class.identity_specialization(db)),
|
||||
),
|
||||
_ => (None, None, self),
|
||||
},
|
||||
@@ -6614,7 +6599,7 @@ impl<'db> Type<'db> {
|
||||
.map(|specialization| {
|
||||
Type::instance(
|
||||
db,
|
||||
generic_origin.apply_specialization(db, |_| specialization, None),
|
||||
generic_origin.apply_specialization(db, |_| specialization),
|
||||
)
|
||||
})
|
||||
.unwrap_or(instance_ty);
|
||||
@@ -6647,9 +6632,7 @@ impl<'db> Type<'db> {
|
||||
match self {
|
||||
Type::Dynamic(_) | Type::Never => Some(self),
|
||||
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
|
||||
Type::GenericAlias(instance) => {
|
||||
Some(Type::instance(db, ClassType::Generic(instance.alias(db))))
|
||||
}
|
||||
Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(alias))),
|
||||
Type::SubclassOf(subclass_of_ty) => Some(subclass_of_ty.to_instance(db)),
|
||||
Type::KnownInstance(KnownInstanceType::NewType(newtype)) => {
|
||||
Some(Type::NewTypeInstance(newtype))
|
||||
@@ -6731,12 +6714,8 @@ impl<'db> Type<'db> {
|
||||
};
|
||||
Ok(ty)
|
||||
}
|
||||
Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => {
|
||||
Ok(Type::typed_dict(ClassType::Generic(instance.alias(db))))
|
||||
}
|
||||
Type::GenericAlias(instance) => {
|
||||
Ok(Type::instance(db, ClassType::Generic(instance.alias(db))))
|
||||
}
|
||||
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::SubclassOf(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
@@ -6845,6 +6824,7 @@ impl<'db> Type<'db> {
|
||||
Ok(ty.to_meta_type(db))
|
||||
}
|
||||
}
|
||||
KnownInstanceType::GenericAlias(instance) => Ok(instance.inner(db)),
|
||||
KnownInstanceType::Callable(instance) => {
|
||||
Ok(Type::Callable(instance.callable_type(db)))
|
||||
}
|
||||
@@ -7094,7 +7074,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
Type::ClassLiteral(class) => class.metaclass(db),
|
||||
Type::GenericAlias(instance) => ClassType::Generic(instance.alias(db)).metaclass(db),
|
||||
Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Dynamic(_) => self,
|
||||
SubclassOfInner::Class(class) => SubclassOfType::from(
|
||||
@@ -7119,7 +7099,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) => newtype.base_class_type(db).into_type(db),
|
||||
Type::NewTypeInstance(newtype) => Type::from(newtype.base_class_type(db)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7132,12 +7112,8 @@ 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()],
|
||||
None,
|
||||
)
|
||||
.map(|class| class.into_type(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);
|
||||
}
|
||||
@@ -7293,6 +7269,15 @@ impl<'db> Type<'db> {
|
||||
)
|
||||
))
|
||||
},
|
||||
KnownInstanceType::GenericAlias(instance) => {
|
||||
Type::KnownInstance(KnownInstanceType::GenericAlias(
|
||||
TypeInContext::new(
|
||||
db,
|
||||
instance.inner(db).apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||
instance.binding_context(db),
|
||||
)
|
||||
))
|
||||
},
|
||||
KnownInstanceType::Callable(instance) => {
|
||||
Type::KnownInstance(KnownInstanceType::Callable(CallableTypeInstance::new(
|
||||
db,
|
||||
@@ -7638,6 +7623,10 @@ impl<'db> Type<'db> {
|
||||
ty.inner(db)
|
||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
KnownInstanceType::GenericAlias(ty) => {
|
||||
ty.inner(db)
|
||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
KnownInstanceType::SubscriptedProtocol(_)
|
||||
| KnownInstanceType::SubscriptedGeneric(_)
|
||||
| KnownInstanceType::TypeVar(_)
|
||||
@@ -7895,7 +7884,7 @@ impl<'db> Type<'db> {
|
||||
|
||||
pub(crate) fn generic_origin(self, db: &'db dyn Db) -> Option<ClassLiteral<'db>> {
|
||||
match self {
|
||||
Type::GenericAlias(instance) => Some(instance.origin(db)),
|
||||
Type::GenericAlias(generic) => Some(generic.origin(db)),
|
||||
Type::NominalInstance(instance) => {
|
||||
if let ClassType::Generic(generic) = instance.class(db) {
|
||||
Some(generic.origin(db))
|
||||
@@ -7955,7 +7944,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
|
||||
Type::NominalInstance(nominal_instance_type) => {
|
||||
nominal_instance_type.variance_of(db, typevar)
|
||||
}
|
||||
Type::GenericAlias(instance) => instance.alias(db).variance_of(db, typevar),
|
||||
Type::GenericAlias(generic_alias) => generic_alias.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 => {
|
||||
@@ -8226,6 +8215,8 @@ pub enum KnownInstanceType<'db> {
|
||||
/// An instance of `typing.GenericAlias` representing a `type[...]` expression.
|
||||
TypeGenericAlias(TypeInContext<'db>),
|
||||
|
||||
GenericAlias(TypeInContext<'db>),
|
||||
|
||||
/// An instance of `typing.GenericAlias` representing a `Callable[...]` expression.
|
||||
Callable(CallableTypeInstance<'db>),
|
||||
|
||||
@@ -8269,7 +8260,9 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
visitor.visit_type(db, *union_type);
|
||||
}
|
||||
}
|
||||
KnownInstanceType::Annotated(instance) | KnownInstanceType::TypeGenericAlias(instance) => {
|
||||
KnownInstanceType::Annotated(instance)
|
||||
| KnownInstanceType::TypeGenericAlias(instance)
|
||||
| KnownInstanceType::GenericAlias(instance) => {
|
||||
visitor.visit_type(db, instance.inner(db));
|
||||
}
|
||||
KnownInstanceType::Literal(ty) | KnownInstanceType::LiteralStringAlias(ty) => {
|
||||
@@ -8315,6 +8308,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)),
|
||||
Self::Annotated(ty) => Self::Annotated(ty.normalized_impl(db, visitor)),
|
||||
Self::TypeGenericAlias(ty) => Self::TypeGenericAlias(ty.normalized_impl(db, visitor)),
|
||||
Self::GenericAlias(ty) => Self::GenericAlias(ty.normalized_impl(db, visitor)),
|
||||
Self::Callable(callable) => Self::Callable(callable.normalized_impl(db, visitor)),
|
||||
Self::LiteralStringAlias(ty) => {
|
||||
Self::LiteralStringAlias(ty.normalized_impl(db, visitor))
|
||||
@@ -8353,6 +8347,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
Self::Literal(_)
|
||||
| Self::Annotated(_)
|
||||
| Self::TypeGenericAlias(_)
|
||||
| Self::GenericAlias(_)
|
||||
| Self::Callable(_) => KnownClass::GenericAlias,
|
||||
Self::LiteralStringAlias(_) => KnownClass::Str,
|
||||
Self::NewType(_) => KnownClass::NewType,
|
||||
@@ -8458,6 +8453,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
KnownInstanceType::TypeGenericAlias(_) | KnownInstanceType::Callable(_) => {
|
||||
f.write_str("GenericAlias")
|
||||
}
|
||||
KnownInstanceType::GenericAlias(_) => f.write_str("GenericAlias(…)"), //TODO
|
||||
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
||||
KnownInstanceType::NewType(declaration) => {
|
||||
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
||||
|
||||
@@ -76,11 +76,9 @@ impl<'db> BoundSuperError<'db> {
|
||||
BoundSuperError::InvalidPivotClassType { pivot_class } => {
|
||||
if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) {
|
||||
match pivot_class {
|
||||
Type::GenericAlias(instance) => builder.into_diagnostic(format_args!(
|
||||
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
||||
"`types.GenericAlias` instance `{}` is not a valid class",
|
||||
instance
|
||||
.alias(context.db())
|
||||
.display_with(context.db(), DisplaySettings::default()),
|
||||
alias.display_with(context.db(), DisplaySettings::default()),
|
||||
)),
|
||||
_ => builder.into_diagnostic(format_args!(
|
||||
"`{pivot_class}` is not a valid class",
|
||||
@@ -211,11 +209,13 @@ impl<'db> SuperOwnerKind<'db> {
|
||||
SuperOwnerKind::Instance(instance) => Some(instance.class(db)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
impl<'db> From<SuperOwnerKind<'db>> for Type<'db> {
|
||||
fn from(owner: SuperOwnerKind<'db>) -> Self {
|
||||
match owner {
|
||||
SuperOwnerKind::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
||||
SuperOwnerKind::Class(class) => class.into_type(db),
|
||||
SuperOwnerKind::Class(class) => class.into(),
|
||||
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, bound_super.pivot_class(db).into_type(db));
|
||||
visitor.visit_type(db, bound_super.owner(db).into_type(db));
|
||||
visitor.visit_type(db, Type::from(bound_super.pivot_class(db)));
|
||||
visitor.visit_type(db, Type::from(bound_super.owner(db)));
|
||||
}
|
||||
|
||||
impl<'db> BoundSuperType<'db> {
|
||||
@@ -515,12 +515,12 @@ impl<'db> BoundSuperType<'db> {
|
||||
db,
|
||||
attribute,
|
||||
Type::none(db),
|
||||
owner.into_type(db),
|
||||
Type::from(owner),
|
||||
)
|
||||
.0,
|
||||
),
|
||||
SuperOwnerKind::Instance(_) => {
|
||||
let owner = owner.into_type(db);
|
||||
let owner = Type::from(owner);
|
||||
Some(
|
||||
Type::try_call_dunder_get_on_attribute(
|
||||
db,
|
||||
|
||||
@@ -103,7 +103,7 @@ fn try_mro_cycle_initial<'db>(
|
||||
) -> Result<Mro<'db>, MroError<'db>> {
|
||||
Err(MroError::cycle(
|
||||
db,
|
||||
self_.apply_optional_specialization(db, specialization, None),
|
||||
self_.apply_optional_specialization(db, specialization),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -296,60 +296,9 @@ impl<'db> GenericAlias<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
#[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<Definition<'db>>,
|
||||
}
|
||||
|
||||
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<Definition<'db>>,
|
||||
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
|
||||
visitor: &FindLegacyTypeVarsVisitor<'db>,
|
||||
) {
|
||||
self.alias(db)
|
||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
impl<'db> From<GenericAlias<'db>> for Type<'db> {
|
||||
fn from(alias: GenericAlias<'db>) -> Type<'db> {
|
||||
Type::GenericAlias(alias)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,19 +385,10 @@ impl<'db> ClassType<'db> {
|
||||
matches!(self, Self::Generic(_))
|
||||
}
|
||||
|
||||
pub(super) fn into_generic_alias(self, db: &'db dyn Db) -> Option<GenericAlias<'db>> {
|
||||
pub(super) const fn into_generic_alias(self) -> Option<GenericAlias<'db>> {
|
||||
match self {
|
||||
Self::NonGeneric(_) => None,
|
||||
Self::Generic(alias) => Some(alias),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn into_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
Self::NonGeneric(class) => class.into(),
|
||||
Self::Generic(instance) => {
|
||||
Type::GenericAlias(GenericAliasInstance::new(db, instance, None))
|
||||
}
|
||||
Self::Generic(generic) => Some(generic),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1118,7 +1058,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 = self.into_type(db);
|
||||
let self_ty = Type::from(self);
|
||||
let metaclass_dunder_call_function_symbol = self_ty
|
||||
.member_lookup_with_policy(
|
||||
db,
|
||||
@@ -1282,11 +1222,26 @@ fn into_callable_cycle_initial<'db>(
|
||||
CallableTypes::one(CallableType::bottom(db))
|
||||
}
|
||||
|
||||
impl<'db> From<GenericAlias<'db>> for ClassType<'db> {
|
||||
fn from(generic: GenericAlias<'db>) -> ClassType<'db> {
|
||||
ClassType::Generic(generic)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> From<ClassType<'db>> 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(alias) => alias.variance_of(db, typevar),
|
||||
Self::Generic(generic) => generic.variance_of(db, typevar),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1574,7 +1529,6 @@ impl<'db> ClassLiteral<'db> {
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
match self.generic_context(db) {
|
||||
None => ClassType::NonGeneric(self),
|
||||
@@ -1600,63 +1554,48 @@ impl<'db> ClassLiteral<'db> {
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Option<Specialization<'db>>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
specialization
|
||||
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
specialization
|
||||
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn top_materialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
generic_context
|
||||
.default_specialization(db, self.known(db))
|
||||
.materialize_impl(
|
||||
db,
|
||||
MaterializationKind::Top,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
},
|
||||
None,
|
||||
)
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context
|
||||
.default_specialization(db, self.known(db))
|
||||
.materialize_impl(
|
||||
db,
|
||||
MaterializationKind::Top,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the default specialization of this class. For non-generic classes, the class is
|
||||
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||
/// applies the default specialization to the class's typevars.
|
||||
pub(crate) fn default_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.default_specialization(db, self.known(db)),
|
||||
None,
|
||||
)
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.default_specialization(db, self.known(db))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the unknown specialization of this class. For non-generic classes, the class is
|
||||
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||
/// maps each of the class's typevars to `Unknown`.
|
||||
pub(crate) fn unknown_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.unknown_specialization(db),
|
||||
None,
|
||||
)
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.unknown_specialization(db)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a specialization of this class where each typevar is mapped to itself.
|
||||
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.identity_specialization(db),
|
||||
None,
|
||||
)
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.identity_specialization(db)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return an iterator over the inferred types of this class's *explicit* bases.
|
||||
@@ -1687,7 +1626,7 @@ impl<'db> ClassLiteral<'db> {
|
||||
|
||||
Box::new([
|
||||
definition_expression_type(db, class_definition, &class_stmt.bases()[0]),
|
||||
tuple_type.to_class_type(db, None).into_type(db),
|
||||
Type::from(tuple_type.to_class_type(db)),
|
||||
])
|
||||
} else {
|
||||
class_stmt
|
||||
@@ -2024,7 +1963,7 @@ impl<'db> ClassLiteral<'db> {
|
||||
|
||||
let (metaclass_literal, _) = candidate.metaclass.class_literal(db);
|
||||
Ok((
|
||||
candidate.metaclass.into_type(db),
|
||||
candidate.metaclass.into(),
|
||||
metaclass_literal.dataclass_transformer_params(db),
|
||||
))
|
||||
}
|
||||
@@ -2102,7 +2041,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(superclass.into_type(db));
|
||||
dynamic_type_to_intersect_with.get_or_insert(Type::from(superclass));
|
||||
}
|
||||
ClassBase::Class(class) => {
|
||||
let known = class.known(db);
|
||||
@@ -2332,10 +2271,8 @@ impl<'db> ClassLiteral<'db> {
|
||||
|| transformer_params.is_some_and(|params| params.flags(db).contains(param))
|
||||
};
|
||||
|
||||
let instance_ty = Type::instance(
|
||||
db,
|
||||
self.apply_optional_specialization(db, specialization, None),
|
||||
);
|
||||
let instance_ty =
|
||||
Type::instance(db, self.apply_optional_specialization(db, specialization));
|
||||
|
||||
let signature_from_fields = |mut parameters: Vec<_>, return_ty: Option<Type<'db>>| {
|
||||
for (field_name, field) in self.fields(db, specialization, field_policy) {
|
||||
@@ -4850,7 +4787,6 @@ impl KnownClass {
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: impl IntoIterator<Item = Type<'db>>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> Option<ClassType<'db>> {
|
||||
let Type::ClassLiteral(class_literal) = self.to_class_literal(db) else {
|
||||
return None;
|
||||
@@ -4872,11 +4808,7 @@ impl KnownClass {
|
||||
return Some(class_literal.default_specialization(db));
|
||||
}
|
||||
|
||||
Some(class_literal.apply_specialization(
|
||||
db,
|
||||
|_| generic_context.specialize(db, types),
|
||||
binding_context,
|
||||
))
|
||||
Some(class_literal.apply_specialization(db, |_| generic_context.specialize(db, types)))
|
||||
}
|
||||
|
||||
/// Lookup a [`KnownClass`] in typeshed and return a [`Type`]
|
||||
@@ -4895,8 +4827,8 @@ impl KnownClass {
|
||||
KnownClass::Tuple,
|
||||
"Use `Type::heterogeneous_tuple` or `Type::homogeneous_tuple` to create `tuple` instances"
|
||||
);
|
||||
self.to_specialized_class_type(db, specialization, None)
|
||||
.and_then(|class_type| class_type.into_type(db).to_instance(db))
|
||||
self.to_specialized_class_type(db, specialization)
|
||||
.and_then(|class_type| Type::from(class_type).to_instance(db))
|
||||
.unwrap_or_else(Type::unknown)
|
||||
}
|
||||
|
||||
|
||||
@@ -79,9 +79,7 @@ impl<'db> ClassBase<'db> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||
Type::GenericAlias(instance) => {
|
||||
Some(Self::Class(ClassType::Generic(instance.alias(db))))
|
||||
}
|
||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
||||
Type::NominalInstance(instance)
|
||||
if instance.has_known_class(db, KnownClass::GenericAlias) =>
|
||||
{
|
||||
@@ -187,6 +185,9 @@ impl<'db> ClassBase<'db> {
|
||||
KnownInstanceType::TypeGenericAlias(_) => {
|
||||
Self::try_from_type(db, KnownClass::Type.to_class_literal(db), subclass)
|
||||
}
|
||||
KnownInstanceType::GenericAlias(instance) => {
|
||||
Self::try_from_type(db, instance.inner(db), subclass)
|
||||
}
|
||||
KnownInstanceType::Annotated(ty) => {
|
||||
// Unions are not supported in this position, so we only need to support
|
||||
// something like `class C(Annotated[Base, "metadata"]): ...`, which we
|
||||
@@ -241,8 +242,8 @@ impl<'db> ClassBase<'db> {
|
||||
db,
|
||||
fields.values().map(|field| field.declared_ty),
|
||||
)?
|
||||
.to_class_type(db, None)
|
||||
.into_type(db),
|
||||
.to_class_type(db)
|
||||
.into(),
|
||||
subclass,
|
||||
)
|
||||
}
|
||||
@@ -385,7 +386,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) => class.into_type(self.db).display(self.db).fmt(f),
|
||||
ClassBase::Class(class) => Type::from(class).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"),
|
||||
@@ -395,11 +396,19 @@ impl<'db> ClassBase<'db> {
|
||||
|
||||
ClassBaseDisplay { db, base: self }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
impl<'db> From<ClassType<'db>> for ClassBase<'db> {
|
||||
fn from(value: ClassType<'db>) -> Self {
|
||||
ClassBase::Class(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> From<ClassBase<'db>> for Type<'db> {
|
||||
fn from(value: ClassBase<'db>) -> Self {
|
||||
match value {
|
||||
ClassBase::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
||||
ClassBase::Class(class) => class.into_type(db),
|
||||
ClassBase::Class(class) => class.into(),
|
||||
ClassBase::Protocol => Type::SpecialForm(SpecialFormType::Protocol),
|
||||
ClassBase::Generic => Type::SpecialForm(SpecialFormType::Generic),
|
||||
ClassBase::TypedDict => Type::SpecialForm(SpecialFormType::TypedDict),
|
||||
@@ -407,9 +416,9 @@ impl<'db> ClassBase<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> From<ClassType<'db>> for ClassBase<'db> {
|
||||
fn from(value: ClassType<'db>) -> Self {
|
||||
ClassBase::Class(value)
|
||||
impl<'db> From<&ClassBase<'db>> for Type<'db> {
|
||||
fn from(value: &ClassBase<'db>) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2506,9 +2506,9 @@ pub(super) fn report_possibly_missing_attribute(
|
||||
"Attribute `{attribute}` may be missing on class `{}`",
|
||||
class.name(db),
|
||||
)),
|
||||
Type::GenericAlias(instance) => builder.into_diagnostic(format_args!(
|
||||
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
||||
"Attribute `{attribute}` may be missing on class `{}`",
|
||||
instance.alias(db).display(db),
|
||||
alias.display(db),
|
||||
)),
|
||||
_ => builder.into_diagnostic(format_args!(
|
||||
"Attribute `{attribute}` may be missing on object of type `{}`",
|
||||
|
||||
@@ -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, class.into_type(db)),
|
||||
}) => return self.visit_type(db, Type::from(class)),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let visitor::TypeKind::NonAtomic(t) = visitor::TypeKind::from_type(db, ty) {
|
||||
if let visitor::TypeKind::NonAtomic(t) = visitor::TypeKind::from(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(instance), _) => instance.display_with(self.db, self.settings.clone()).fmt_detailed(f),
|
||||
(ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings.clone()).fmt_detailed(f),
|
||||
}
|
||||
}
|
||||
Type::ProtocolInstance(protocol) => match protocol.inner {
|
||||
@@ -607,7 +607,7 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
ClassType::NonGeneric(class) => class
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f),
|
||||
ClassType::Generic(instance) => instance
|
||||
ClassType::Generic(alias) => alias
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f),
|
||||
},
|
||||
@@ -653,7 +653,6 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
let mut f = f.with_type(self.ty);
|
||||
f.write_str("<class '")?;
|
||||
generic
|
||||
.alias(self.db)
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(&mut f)?;
|
||||
f.write_str("'>")
|
||||
@@ -668,11 +667,11 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
.fmt_detailed(f)?;
|
||||
f.write_char(']')
|
||||
}
|
||||
SubclassOfInner::Class(ClassType::Generic(instance)) => {
|
||||
SubclassOfInner::Class(ClassType::Generic(alias)) => {
|
||||
f.with_type(KnownClass::Type.to_class_literal(self.db))
|
||||
.write_str("type")?;
|
||||
f.write_char('[')?;
|
||||
instance
|
||||
alias
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_char(']')
|
||||
@@ -862,15 +861,11 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
Type::BoundSuper(bound_super) => {
|
||||
f.set_invalid_syntax();
|
||||
f.write_str("<super: ")?;
|
||||
bound_super
|
||||
.pivot_class(self.db)
|
||||
.into_type(self.db)
|
||||
Type::from(bound_super.pivot_class(self.db))
|
||||
.display_with(self.db, self.settings.singleline())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_str(", ")?;
|
||||
bound_super
|
||||
.owner(self.db)
|
||||
.into_type(self.db)
|
||||
Type::from(bound_super.owner(self.db))
|
||||
.display_with(self.db, self.settings.singleline())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_str(">")
|
||||
|
||||
@@ -154,7 +154,7 @@ pub(crate) fn enum_metadata<'db>(
|
||||
.skip(1)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.filter(|class| {
|
||||
!class.into_type(db).is_subtype_of(
|
||||
!Type::from(*class).is_subtype_of(
|
||||
db,
|
||||
KnownClass::Enum.to_subclass_of(db),
|
||||
)
|
||||
|
||||
@@ -1578,7 +1578,7 @@ impl KnownFunction {
|
||||
let mut good_argument = true;
|
||||
let classes = match param_type {
|
||||
Type::ClassLiteral(class) => vec![ClassType::NonGeneric(*class)],
|
||||
Type::GenericAlias(generic) => vec![ClassType::Generic(generic.alias(db))],
|
||||
Type::GenericAlias(generic_alias) => vec![ClassType::Generic(*generic_alias)],
|
||||
Type::Union(union) => {
|
||||
let elements = union.elements(db);
|
||||
let mut classes = Vec::with_capacity(elements.len());
|
||||
@@ -1587,8 +1587,8 @@ impl KnownFunction {
|
||||
Type::ClassLiteral(class) => {
|
||||
classes.push(ClassType::NonGeneric(*class));
|
||||
}
|
||||
Type::GenericAlias(generic) => {
|
||||
classes.push(ClassType::Generic(generic.alias(db)));
|
||||
Type::GenericAlias(generic_alias) => {
|
||||
classes.push(ClassType::Generic(*generic_alias));
|
||||
}
|
||||
_ => {
|
||||
good_argument = false;
|
||||
|
||||
@@ -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(self.db)
|
||||
formal_nominal.class(self.db).into_generic_alias()
|
||||
}
|
||||
// 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(self.db),
|
||||
}) => class.into_generic_alias(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ impl<'db> AllMembers<'db> {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db));
|
||||
}
|
||||
|
||||
Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => {
|
||||
Type::GenericAlias(generic_alias) if generic_alias.is_typed_dict(db) => {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db));
|
||||
}
|
||||
|
||||
|
||||
@@ -686,7 +686,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
continue;
|
||||
}
|
||||
Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
|
||||
Type::GenericAlias(generic) => ClassType::Generic(generic.alias(self.db())),
|
||||
Type::GenericAlias(class) => ClassType::Generic(*class),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
@@ -7500,9 +7500,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
|
||||
let class_type =
|
||||
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context), None);
|
||||
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context));
|
||||
|
||||
class_type.into_type(self.db()).to_instance(self.db())
|
||||
Type::from(class_type).to_instance(self.db())
|
||||
}
|
||||
|
||||
/// Infer the type of the `iter` expression of the first comprehension.
|
||||
@@ -8085,7 +8085,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
|
||||
let class = match callable_type {
|
||||
Type::ClassLiteral(class) => Some(ClassType::NonGeneric(class)),
|
||||
Type::GenericAlias(generic) => Some(ClassType::Generic(generic.alias(self.db()))),
|
||||
Type::GenericAlias(generic) => Some(ClassType::Generic(generic)),
|
||||
Type::SubclassOf(subclass) => subclass.subclass_of().into_class(),
|
||||
_ => None,
|
||||
};
|
||||
@@ -9147,9 +9147,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
"Class `{}` has no attribute `{attr_name}`",
|
||||
class.name(db),
|
||||
)),
|
||||
Type::GenericAlias(instance) => builder.into_diagnostic(format_args!(
|
||||
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
||||
"Class `{}` has no attribute `{attr_name}`",
|
||||
instance.alias(db).display(db),
|
||||
alias.display(db),
|
||||
)),
|
||||
Type::FunctionLiteral(function) => builder.into_diagnostic(format_args!(
|
||||
"Function `{}` has no attribute `{attr_name}`",
|
||||
@@ -10813,19 +10813,48 @@ 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(instance) = value_ty.as_generic_alias() {
|
||||
let return_ty = self.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
// alias.binding_context(self.db()),
|
||||
instance.binding_context(self.db()),
|
||||
false,
|
||||
);
|
||||
|
||||
return return_ty;
|
||||
if let Type::KnownInstance(KnownInstanceType::GenericAlias(alias)) = value_ty {
|
||||
return Type::KnownInstance(KnownInstanceType::GenericAlias(TypeInContext::new(
|
||||
self.db(),
|
||||
self.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
alias.binding_context(self.db()),
|
||||
false,
|
||||
),
|
||||
self.typevar_binding_context,
|
||||
)));
|
||||
}
|
||||
|
||||
self.infer_subscript_load_impl(value_ty, subscript)
|
||||
// if let Type::GenericAlias(alias) = value_ty {
|
||||
// return Type::KnownInstance(KnownInstanceType::GenericAlias(TypeInContext::new(
|
||||
// self.db(),
|
||||
// self.infer_explicitly_specialized_type_alias(
|
||||
// subscript,
|
||||
// value_ty,
|
||||
// Some(alias.definition(self.db())),
|
||||
// false,
|
||||
// ),
|
||||
// self.typevar_binding_context,
|
||||
// )));
|
||||
// }
|
||||
|
||||
let result_ty = self.infer_subscript_load_impl(value_ty, subscript);
|
||||
|
||||
// let result_ty = if result_ty.is_generic_alias() {
|
||||
// Type::KnownInstance(KnownInstanceType::GenericAlias(TypeInContext::new(
|
||||
// self.db(),
|
||||
// result_ty,
|
||||
// self.typevar_binding_context,
|
||||
// )))
|
||||
// } else {
|
||||
// result_ty
|
||||
// };
|
||||
|
||||
// eprintln!("Subscripting type: {}", value_ty.display(self.db()));
|
||||
// eprintln!("Inferred subscript type: {}", result_ty.display(self.db()));
|
||||
|
||||
result_ty
|
||||
}
|
||||
|
||||
fn infer_subscript_load_impl(
|
||||
@@ -10861,13 +10890,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let tuple_generic_alias = |tuple: Option<TupleType<'db>>| {
|
||||
let tuple_generic_alias = |db: &'db dyn Db, tuple: Option<TupleType<'db>>| {
|
||||
let tuple = tuple.unwrap_or_else(|| TupleType::homogeneous(db, Type::unknown()));
|
||||
tuple
|
||||
.to_class_type(db, typevar_binding_context)
|
||||
.into_type(db)
|
||||
Type::from(tuple.to_class_type(db))
|
||||
};
|
||||
|
||||
match value_ty {
|
||||
@@ -10879,7 +10904,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// updating all of the subscript logic below to use custom callables for all of the _other_
|
||||
// special cases, too.
|
||||
if class.is_tuple(self.db()) {
|
||||
return tuple_generic_alias(self.infer_tuple_type_expression(slice));
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
} else if class.is_known(self.db(), KnownClass::Type) {
|
||||
let argument_ty = self.infer_type_expression(slice);
|
||||
return Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||
@@ -10907,7 +10932,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Tuple) => {
|
||||
return tuple_generic_alias(self.infer_tuple_type_expression(slice));
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Literal) => {
|
||||
match self.infer_literal_parameter_type(slice) {
|
||||
@@ -11073,12 +11098,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
.expect("A known stdlib class is available");
|
||||
|
||||
return class
|
||||
.to_specialized_class_type(
|
||||
self.db(),
|
||||
[element_ty],
|
||||
self.typevar_binding_context,
|
||||
)
|
||||
.map(|class_type| class_type.into_type(self.db()))
|
||||
.to_specialized_class_type(self.db(), [element_ty])
|
||||
.map(Type::from)
|
||||
.unwrap_or_else(Type::unknown);
|
||||
}
|
||||
// `typing` special forms with two generic arguments
|
||||
@@ -11135,12 +11156,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
.expect("Stdlib class available");
|
||||
|
||||
return class
|
||||
.to_specialized_class_type(
|
||||
self.db(),
|
||||
[first_ty, second_ty],
|
||||
self.typevar_binding_context,
|
||||
)
|
||||
.map(|class_type| class_type.into_type(self.db()))
|
||||
.to_specialized_class_type(self.db(), [first_ty, second_ty])
|
||||
.map(Type::from)
|
||||
.unwrap_or_else(Type::unknown);
|
||||
}
|
||||
Type::KnownInstance(KnownInstanceType::UnionType(instance)) => {
|
||||
@@ -11186,15 +11203,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
generic_context: GenericContext<'db>,
|
||||
) -> Type<'db> {
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let specialize = |types: &[Option<Type<'db>>]| {
|
||||
generic_class
|
||||
.apply_specialization(
|
||||
db,
|
||||
|_| generic_context.specialize_partial(db, types.iter().copied()),
|
||||
typevar_binding_context,
|
||||
)
|
||||
.into_type(db)
|
||||
Type::from(generic_class.apply_specialization(db, |_| {
|
||||
generic_context.specialize_partial(db, types.iter().copied())
|
||||
}))
|
||||
};
|
||||
|
||||
self.infer_explicit_callable_specialization(
|
||||
|
||||
@@ -4,7 +4,6 @@ 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,
|
||||
@@ -14,10 +13,10 @@ use crate::types::string_annotation::parse_string_annotation;
|
||||
use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
||||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
BindingContext, CallableType, DynamicType, GenericAlias, GenericContext, IntersectionBuilder,
|
||||
KnownClass, KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType,
|
||||
SubclassOfType, Type, TypeAliasType, TypeContext, TypeInContext, TypeIsType, TypeMapping,
|
||||
UnionBuilder, UnionType, todo_type,
|
||||
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||
Type, TypeAliasType, TypeContext, TypeInContext, TypeIsType, TypeMapping, UnionBuilder,
|
||||
UnionType, todo_type,
|
||||
};
|
||||
|
||||
/// Type expressions
|
||||
@@ -714,20 +713,13 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
match class_literal.generic_context(self.db()) {
|
||||
Some(generic_context) => {
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let specialize = |types: &[Option<Type<'db>>]| {
|
||||
SubclassOfType::from(
|
||||
db,
|
||||
class_literal.apply_specialization(
|
||||
db,
|
||||
|_| {
|
||||
generic_context.specialize_partial(
|
||||
db,
|
||||
types.iter().copied(),
|
||||
)
|
||||
},
|
||||
typevar_binding_context,
|
||||
),
|
||||
class_literal.apply_specialization(db, |_| {
|
||||
generic_context
|
||||
.specialize_partial(db, types.iter().copied())
|
||||
}),
|
||||
)
|
||||
};
|
||||
self.infer_explicit_callable_specialization(
|
||||
@@ -811,11 +803,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
} else {
|
||||
// Update the binding context
|
||||
match specialized {
|
||||
Type::GenericAlias(alias) => Type::GenericAlias(GenericAliasInstance::new(
|
||||
db,
|
||||
GenericAlias::new(db, alias.origin(db), alias.specialization(db)),
|
||||
current_typevar_binding_context,
|
||||
)),
|
||||
// Type::GenericAlias(alias) => Type::GenericAlias(GenericAlias::new(
|
||||
// db,
|
||||
// alias.origin(db),
|
||||
// alias.specialization(db),
|
||||
// current_typevar_binding_context,
|
||||
// )),
|
||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(instance)) => {
|
||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||
TypeInContext::new(
|
||||
@@ -995,7 +988,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
true,
|
||||
),
|
||||
KnownInstanceType::Annotated(instance)
|
||||
| KnownInstanceType::TypeGenericAlias(instance) => self
|
||||
| KnownInstanceType::TypeGenericAlias(instance)
|
||||
| KnownInstanceType::GenericAlias(instance) => self
|
||||
.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
@@ -1049,12 +1043,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::GenericAlias(instance) => self.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
instance.binding_context(self.db()),
|
||||
true,
|
||||
),
|
||||
// Type::GenericAlias(alias) => {
|
||||
// self.infer_explicitly_specialized_type_alias(subscript, value_ty, None, true)
|
||||
// }
|
||||
Type::StringLiteral(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
// For stringified TypeAlias; remove once properly supported
|
||||
@@ -1063,6 +1054,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
_ => {
|
||||
self.infer_type_expression(slice);
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||
dbg!(&value_ty);
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Invalid subscript of object of type `{}` in type expression",
|
||||
value_ty.display(self.db())
|
||||
|
||||
@@ -207,13 +207,13 @@ 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_type(db));
|
||||
visitor.visit_type(db, nominal.class(db).into());
|
||||
}
|
||||
|
||||
impl<'db> NominalInstanceType<'db> {
|
||||
pub(super) fn class(&self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
match self.0 {
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db, None),
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db),
|
||||
NominalInstanceInner::NonTuple(class) => class,
|
||||
NominalInstanceInner::Object => KnownClass::Object
|
||||
.try_to_class_literal(db)
|
||||
@@ -224,7 +224,7 @@ impl<'db> NominalInstanceType<'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, None),
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db),
|
||||
NominalInstanceInner::NonTuple(class) => class,
|
||||
NominalInstanceInner::Object => {
|
||||
return KnownClass::Object
|
||||
@@ -279,7 +279,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||
}
|
||||
KnownClass::Tuple => Some(
|
||||
class
|
||||
.into_generic_alias(db)
|
||||
.into_generic_alias()
|
||||
.and_then(|alias| {
|
||||
Some(Cow::Borrowed(alias.specialization(db).tuple(db)?))
|
||||
})
|
||||
|
||||
@@ -51,7 +51,7 @@ impl<'db> Mro<'db> {
|
||||
class_literal: ClassLiteral<'db>,
|
||||
specialization: Option<Specialization<'db>>,
|
||||
) -> Result<Self, MroError<'db>> {
|
||||
let class = class_literal.apply_optional_specialization(db, specialization, None);
|
||||
let class = class_literal.apply_optional_specialization(db, specialization);
|
||||
// Special-case `NotImplementedType`: typeshed says that it inherits from `Any`,
|
||||
// but this causes more problems than it fixes.
|
||||
if class_literal.is_known(db, KnownClass::NotImplementedType) {
|
||||
@@ -100,7 +100,13 @@ impl<'db> Mro<'db> {
|
||||
if original_bases.contains(&Type::SpecialForm(SpecialFormType::Protocol)) {
|
||||
return;
|
||||
}
|
||||
if remaining_bases.iter().any(Type::is_generic_alias) {
|
||||
if remaining_bases.iter().any(|ty| {
|
||||
matches!(
|
||||
ty,
|
||||
Type::GenericAlias(..)
|
||||
| Type::KnownInstance(KnownInstanceType::GenericAlias(_))
|
||||
)
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
resolved_bases.push(ClassBase::Generic);
|
||||
@@ -412,11 +418,10 @@ impl<'db> Iterator for MroIterator<'db> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if !self.first_element_yielded {
|
||||
self.first_element_yielded = true;
|
||||
return Some(ClassBase::Class(self.class.apply_optional_specialization(
|
||||
self.db,
|
||||
self.specialization,
|
||||
None,
|
||||
)));
|
||||
return Some(ClassBase::Class(
|
||||
self.class
|
||||
.apply_optional_specialization(self.db, self.specialization),
|
||||
));
|
||||
}
|
||||
self.full_mro_except_first_element().next()
|
||||
}
|
||||
|
||||
@@ -144,10 +144,6 @@ 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> {
|
||||
@@ -158,6 +154,12 @@ impl<'db> Deref for ProtocolClass<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> From<ProtocolClass<'db>> 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
|
||||
|
||||
@@ -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, subclass_of.subclass_of.into_type(db));
|
||||
visitor.visit_type(db, Type::from(subclass_of.subclass_of));
|
||||
}
|
||||
|
||||
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) {
|
||||
class.into_type(db)
|
||||
Type::from(class)
|
||||
} else if class.is_object(db) {
|
||||
KnownClass::Type.to_instance(db)
|
||||
} else {
|
||||
@@ -129,9 +129,7 @@ impl<'db> SubclassOfType<'db> {
|
||||
name: &str,
|
||||
policy: MemberLookupPolicy,
|
||||
) -> Option<PlaceAndQualifiers<'db>> {
|
||||
self.subclass_of
|
||||
.into_type(db)
|
||||
.find_name_in_mro_with_policy(db, name, policy)
|
||||
Type::from(self.subclass_of).find_name_in_mro_with_policy(db, name, policy)
|
||||
}
|
||||
|
||||
/// Return `true` if `self` has a certain relation to `other`.
|
||||
@@ -273,18 +271,11 @@ impl<'db> SubclassOfInner<'db> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic.alias(db)))),
|
||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
||||
Type::SpecialForm(SpecialFormType::Any) => Some(Self::Dynamic(DynamicType::Any)),
|
||||
_ => 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<ClassType<'db>> for SubclassOfInner<'db> {
|
||||
@@ -304,3 +295,12 @@ impl<'db> From<ProtocolClass<'db>> for SubclassOfInner<'db> {
|
||||
SubclassOfInner::Class(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> From<SubclassOfInner<'db>> for Type<'db> {
|
||||
fn from(value: SubclassOfInner<'db>) -> Self {
|
||||
match value {
|
||||
SubclassOfInner::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
||||
SubclassOfInner::Class(class) => class.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,27 +202,19 @@ impl<'db> TupleType<'db> {
|
||||
// `static-frame` as part of a mypy_primer run! This is because it's called
|
||||
// from `NominalInstanceType::class()`, which is a very hot method.
|
||||
#[salsa::tracked(cycle_initial=to_class_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn to_class_type(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
let element_type = self.tuple(db).homogeneous_element_type(db);
|
||||
generic_context.specialize_tuple(db, element_type, self)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
let element_type = self.tuple(db).homogeneous_element_type(db);
|
||||
generic_context.specialize_tuple(db, element_type, self)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a normalized version of `self`.
|
||||
@@ -302,23 +294,18 @@ fn to_class_type_cycle_initial<'db>(
|
||||
db: &'db dyn Db,
|
||||
_id: salsa::Id,
|
||||
self_: TupleType<'db>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
generic_context.specialize_tuple(db, Type::Never, self_)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
generic_context.specialize_tuple(db, Type::Never, self_)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A tuple spec describes the contents of a tuple type, which might be fixed- or variable-length.
|
||||
|
||||
@@ -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_type(db));
|
||||
visitor.visit_type(db, typed_dict.defining_class.into());
|
||||
}
|
||||
|
||||
pub(super) fn typed_dict_params_from_class_def(class_stmt: &StmtClassDef) -> TypedDictParams {
|
||||
|
||||
@@ -144,8 +144,8 @@ pub(super) enum TypeKind<'db> {
|
||||
NonAtomic(NonAtomicType<'db>),
|
||||
}
|
||||
|
||||
impl<'db> TypeKind<'db> {
|
||||
pub(super) fn from_type(db: &'db dyn Db, ty: Type<'db>) -> Self {
|
||||
impl<'db> From<Type<'db>> for TypeKind<'db> {
|
||||
fn from(ty: Type<'db>) -> Self {
|
||||
match ty {
|
||||
Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
@@ -180,9 +180,7 @@ impl<'db> TypeKind<'db> {
|
||||
TypeKind::NonAtomic(NonAtomicType::MethodWrapper(method_wrapper))
|
||||
}
|
||||
Type::Callable(callable) => TypeKind::NonAtomic(NonAtomicType::Callable(callable)),
|
||||
Type::GenericAlias(instance) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::GenericAlias(instance.alias(db)))
|
||||
}
|
||||
Type::GenericAlias(alias) => TypeKind::NonAtomic(NonAtomicType::GenericAlias(alias)),
|
||||
Type::KnownInstance(known_instance) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::KnownInstance(known_instance))
|
||||
}
|
||||
@@ -262,7 +260,7 @@ pub(crate) fn walk_type_with_recursion_guard<'db>(
|
||||
visitor: &impl TypeVisitor<'db>,
|
||||
recursion_guard: &TypeCollector<'db>,
|
||||
) {
|
||||
match TypeKind::from_type(db, ty) {
|
||||
match TypeKind::from(ty) {
|
||||
TypeKind::Atomic => {}
|
||||
TypeKind::NonAtomic(non_atomic_type) => {
|
||||
if recursion_guard.type_was_already_seen(ty) {
|
||||
@@ -351,7 +349,7 @@ fn specialization_depth(db: &dyn Db, ty: Type<'_>) -> usize {
|
||||
}
|
||||
|
||||
fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
match TypeKind::from_type(db, ty) {
|
||||
match TypeKind::from(ty) {
|
||||
TypeKind::Atomic => {
|
||||
if ty.is_divergent() {
|
||||
self.max_depth.set(usize::MAX);
|
||||
|
||||
Reference in New Issue
Block a user