mirror of https://github.com/astral-sh/ruff
New KnownInstanceType
This commit is contained in:
parent
54c88b599d
commit
96e7ebb588
|
|
@ -906,12 +906,12 @@ impl<'db> Type<'db> {
|
||||||
matches!(self, Type::GenericAlias(_))
|
matches!(self, Type::GenericAlias(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn as_generic_alias(&self) -> Option<GenericAlias<'db>> {
|
// pub(crate) fn as_generic_alias(&self) -> Option<GenericAlias<'db>> {
|
||||||
match self {
|
// match self {
|
||||||
Type::GenericAlias(alias) => Some(*alias),
|
// Type::GenericAlias(alias) => Some(*alias),
|
||||||
_ => None,
|
// _ => None,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const fn is_dynamic(&self) -> bool {
|
const fn is_dynamic(&self) -> bool {
|
||||||
matches!(self, Type::Dynamic(_))
|
matches!(self, Type::Dynamic(_))
|
||||||
|
|
@ -6599,7 +6599,7 @@ impl<'db> Type<'db> {
|
||||||
.map(|specialization| {
|
.map(|specialization| {
|
||||||
Type::instance(
|
Type::instance(
|
||||||
db,
|
db,
|
||||||
generic_origin.apply_specialization(db, |_| specialization, None),
|
generic_origin.apply_specialization(db, |_| specialization),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or(instance_ty);
|
.unwrap_or(instance_ty);
|
||||||
|
|
@ -6824,6 +6824,7 @@ impl<'db> Type<'db> {
|
||||||
Ok(ty.to_meta_type(db))
|
Ok(ty.to_meta_type(db))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
KnownInstanceType::GenericAlias(instance) => Ok(instance.inner(db)),
|
||||||
KnownInstanceType::Callable(instance) => {
|
KnownInstanceType::Callable(instance) => {
|
||||||
Ok(Type::Callable(instance.callable_type(db)))
|
Ok(Type::Callable(instance.callable_type(db)))
|
||||||
}
|
}
|
||||||
|
|
@ -7111,11 +7112,7 @@ impl<'db> Type<'db> {
|
||||||
pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
|
pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
|
||||||
if self.is_typed_dict() {
|
if self.is_typed_dict() {
|
||||||
return KnownClass::Dict
|
return KnownClass::Dict
|
||||||
.to_specialized_class_type(
|
.to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object()])
|
||||||
db,
|
|
||||||
[KnownClass::Str.to_instance(db), Type::object()],
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.map(Type::from)
|
.map(Type::from)
|
||||||
// Guard against user-customized typesheds with a broken `dict` class
|
// Guard against user-customized typesheds with a broken `dict` class
|
||||||
.unwrap_or_else(Type::unknown);
|
.unwrap_or_else(Type::unknown);
|
||||||
|
|
@ -7272,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) => {
|
KnownInstanceType::Callable(instance) => {
|
||||||
Type::KnownInstance(KnownInstanceType::Callable(CallableTypeInstance::new(
|
Type::KnownInstance(KnownInstanceType::Callable(CallableTypeInstance::new(
|
||||||
db,
|
db,
|
||||||
|
|
@ -7617,6 +7623,10 @@ impl<'db> Type<'db> {
|
||||||
ty.inner(db)
|
ty.inner(db)
|
||||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
.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::SubscriptedProtocol(_)
|
||||||
| KnownInstanceType::SubscriptedGeneric(_)
|
| KnownInstanceType::SubscriptedGeneric(_)
|
||||||
| KnownInstanceType::TypeVar(_)
|
| KnownInstanceType::TypeVar(_)
|
||||||
|
|
@ -8205,6 +8215,8 @@ pub enum KnownInstanceType<'db> {
|
||||||
/// An instance of `typing.GenericAlias` representing a `type[...]` expression.
|
/// An instance of `typing.GenericAlias` representing a `type[...]` expression.
|
||||||
TypeGenericAlias(TypeInContext<'db>),
|
TypeGenericAlias(TypeInContext<'db>),
|
||||||
|
|
||||||
|
GenericAlias(TypeInContext<'db>),
|
||||||
|
|
||||||
/// An instance of `typing.GenericAlias` representing a `Callable[...]` expression.
|
/// An instance of `typing.GenericAlias` representing a `Callable[...]` expression.
|
||||||
Callable(CallableTypeInstance<'db>),
|
Callable(CallableTypeInstance<'db>),
|
||||||
|
|
||||||
|
|
@ -8248,7 +8260,9 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
visitor.visit_type(db, *union_type);
|
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));
|
visitor.visit_type(db, instance.inner(db));
|
||||||
}
|
}
|
||||||
KnownInstanceType::Literal(ty) | KnownInstanceType::LiteralStringAlias(ty) => {
|
KnownInstanceType::Literal(ty) | KnownInstanceType::LiteralStringAlias(ty) => {
|
||||||
|
|
@ -8294,6 +8308,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)),
|
Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)),
|
||||||
Self::Annotated(ty) => Self::Annotated(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::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::Callable(callable) => Self::Callable(callable.normalized_impl(db, visitor)),
|
||||||
Self::LiteralStringAlias(ty) => {
|
Self::LiteralStringAlias(ty) => {
|
||||||
Self::LiteralStringAlias(ty.normalized_impl(db, visitor))
|
Self::LiteralStringAlias(ty.normalized_impl(db, visitor))
|
||||||
|
|
@ -8332,6 +8347,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
Self::Literal(_)
|
Self::Literal(_)
|
||||||
| Self::Annotated(_)
|
| Self::Annotated(_)
|
||||||
| Self::TypeGenericAlias(_)
|
| Self::TypeGenericAlias(_)
|
||||||
|
| Self::GenericAlias(_)
|
||||||
| Self::Callable(_) => KnownClass::GenericAlias,
|
| Self::Callable(_) => KnownClass::GenericAlias,
|
||||||
Self::LiteralStringAlias(_) => KnownClass::Str,
|
Self::LiteralStringAlias(_) => KnownClass::Str,
|
||||||
Self::NewType(_) => KnownClass::NewType,
|
Self::NewType(_) => KnownClass::NewType,
|
||||||
|
|
@ -8437,6 +8453,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
KnownInstanceType::TypeGenericAlias(_) | KnownInstanceType::Callable(_) => {
|
KnownInstanceType::TypeGenericAlias(_) | KnownInstanceType::Callable(_) => {
|
||||||
f.write_str("GenericAlias")
|
f.write_str("GenericAlias")
|
||||||
}
|
}
|
||||||
|
KnownInstanceType::GenericAlias(_) => f.write_str("GenericAlias(…)"), //TODO
|
||||||
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
||||||
KnownInstanceType::NewType(declaration) => {
|
KnownInstanceType::NewType(declaration) => {
|
||||||
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ fn try_mro_cycle_initial<'db>(
|
||||||
) -> Result<Mro<'db>, MroError<'db>> {
|
) -> Result<Mro<'db>, MroError<'db>> {
|
||||||
Err(MroError::cycle(
|
Err(MroError::cycle(
|
||||||
db,
|
db,
|
||||||
self_.apply_optional_specialization(db, specialization, None),
|
self_.apply_optional_specialization(db, specialization),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,8 +233,6 @@ impl<'db> CodeGeneratorKind<'db> {
|
||||||
pub struct GenericAlias<'db> {
|
pub struct GenericAlias<'db> {
|
||||||
pub(crate) origin: ClassLiteral<'db>,
|
pub(crate) origin: ClassLiteral<'db>,
|
||||||
pub(crate) specialization: Specialization<'db>,
|
pub(crate) specialization: Specialization<'db>,
|
||||||
|
|
||||||
pub(crate) binding_context: Option<Definition<'db>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
|
|
@ -254,7 +252,6 @@ impl<'db> GenericAlias<'db> {
|
||||||
db,
|
db,
|
||||||
self.origin(db),
|
self.origin(db),
|
||||||
self.specialization(db).normalized_impl(db, visitor),
|
self.specialization(db).normalized_impl(db, visitor),
|
||||||
self.binding_context(db),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,7 +277,6 @@ impl<'db> GenericAlias<'db> {
|
||||||
self.origin(db),
|
self.origin(db),
|
||||||
self.specialization(db)
|
self.specialization(db)
|
||||||
.apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
.apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||||
self.binding_context(db),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1533,7 +1529,6 @@ impl<'db> ClassLiteral<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
||||||
binding_context: Option<Definition<'db>>,
|
|
||||||
) -> ClassType<'db> {
|
) -> ClassType<'db> {
|
||||||
match self.generic_context(db) {
|
match self.generic_context(db) {
|
||||||
None => ClassType::NonGeneric(self),
|
None => ClassType::NonGeneric(self),
|
||||||
|
|
@ -1550,7 +1545,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassType::Generic(GenericAlias::new(db, self, specialization, binding_context))
|
ClassType::Generic(GenericAlias::new(db, self, specialization))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1559,22 +1554,15 @@ impl<'db> ClassLiteral<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
specialization: Option<Specialization<'db>>,
|
specialization: Option<Specialization<'db>>,
|
||||||
binding_context: Option<Definition<'db>>,
|
|
||||||
) -> ClassType<'db> {
|
) -> ClassType<'db> {
|
||||||
self.apply_specialization(
|
self.apply_specialization(db, |generic_context| {
|
||||||
db,
|
|
||||||
|generic_context| {
|
|
||||||
specialization
|
specialization
|
||||||
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
||||||
},
|
})
|
||||||
binding_context,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn top_materialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
pub(crate) fn top_materialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
self.apply_specialization(
|
self.apply_specialization(db, |generic_context| {
|
||||||
db,
|
|
||||||
|generic_context| {
|
|
||||||
generic_context
|
generic_context
|
||||||
.default_specialization(db, self.known(db))
|
.default_specialization(db, self.known(db))
|
||||||
.materialize_impl(
|
.materialize_impl(
|
||||||
|
|
@ -1582,40 +1570,32 @@ impl<'db> ClassLiteral<'db> {
|
||||||
MaterializationKind::Top,
|
MaterializationKind::Top,
|
||||||
&ApplyTypeMappingVisitor::default(),
|
&ApplyTypeMappingVisitor::default(),
|
||||||
)
|
)
|
||||||
},
|
})
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the default specialization of this class. For non-generic classes, the class is
|
/// 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
|
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||||
/// applies the default specialization to the class's typevars.
|
/// applies the default specialization to the class's typevars.
|
||||||
pub(crate) fn default_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
pub(crate) fn default_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
self.apply_specialization(
|
self.apply_specialization(db, |generic_context| {
|
||||||
db,
|
generic_context.default_specialization(db, self.known(db))
|
||||||
|generic_context| generic_context.default_specialization(db, self.known(db)),
|
})
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the unknown specialization of this class. For non-generic classes, the class is
|
/// 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
|
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||||
/// maps each of the class's typevars to `Unknown`.
|
/// maps each of the class's typevars to `Unknown`.
|
||||||
pub(crate) fn unknown_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
pub(crate) fn unknown_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
self.apply_specialization(
|
self.apply_specialization(db, |generic_context| {
|
||||||
db,
|
generic_context.unknown_specialization(db)
|
||||||
|generic_context| generic_context.unknown_specialization(db),
|
})
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a specialization of this class where each typevar is mapped to itself.
|
/// 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> {
|
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
self.apply_specialization(
|
self.apply_specialization(db, |generic_context| {
|
||||||
db,
|
generic_context.identity_specialization(db)
|
||||||
|generic_context| generic_context.identity_specialization(db),
|
})
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the inferred types of this class's *explicit* bases.
|
/// Return an iterator over the inferred types of this class's *explicit* bases.
|
||||||
|
|
@ -1646,7 +1626,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
|
|
||||||
Box::new([
|
Box::new([
|
||||||
definition_expression_type(db, class_definition, &class_stmt.bases()[0]),
|
definition_expression_type(db, class_definition, &class_stmt.bases()[0]),
|
||||||
Type::from(tuple_type.to_class_type(db, None)),
|
Type::from(tuple_type.to_class_type(db)),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
class_stmt
|
class_stmt
|
||||||
|
|
@ -2291,10 +2271,8 @@ impl<'db> ClassLiteral<'db> {
|
||||||
|| transformer_params.is_some_and(|params| params.flags(db).contains(param))
|
|| transformer_params.is_some_and(|params| params.flags(db).contains(param))
|
||||||
};
|
};
|
||||||
|
|
||||||
let instance_ty = Type::instance(
|
let instance_ty =
|
||||||
db,
|
Type::instance(db, self.apply_optional_specialization(db, specialization));
|
||||||
self.apply_optional_specialization(db, specialization, None),
|
|
||||||
);
|
|
||||||
|
|
||||||
let signature_from_fields = |mut parameters: Vec<_>, return_ty: Option<Type<'db>>| {
|
let signature_from_fields = |mut parameters: Vec<_>, return_ty: Option<Type<'db>>| {
|
||||||
for (field_name, field) in self.fields(db, specialization, field_policy) {
|
for (field_name, field) in self.fields(db, specialization, field_policy) {
|
||||||
|
|
@ -4809,7 +4787,6 @@ impl KnownClass {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
specialization: impl IntoIterator<Item = Type<'db>>,
|
specialization: impl IntoIterator<Item = Type<'db>>,
|
||||||
binding_context: Option<Definition<'db>>,
|
|
||||||
) -> Option<ClassType<'db>> {
|
) -> Option<ClassType<'db>> {
|
||||||
let Type::ClassLiteral(class_literal) = self.to_class_literal(db) else {
|
let Type::ClassLiteral(class_literal) = self.to_class_literal(db) else {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -4831,11 +4808,7 @@ impl KnownClass {
|
||||||
return Some(class_literal.default_specialization(db));
|
return Some(class_literal.default_specialization(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(class_literal.apply_specialization(
|
Some(class_literal.apply_specialization(db, |_| generic_context.specialize(db, types)))
|
||||||
db,
|
|
||||||
|_| generic_context.specialize(db, types),
|
|
||||||
binding_context,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup a [`KnownClass`] in typeshed and return a [`Type`]
|
/// Lookup a [`KnownClass`] in typeshed and return a [`Type`]
|
||||||
|
|
@ -4854,7 +4827,7 @@ impl KnownClass {
|
||||||
KnownClass::Tuple,
|
KnownClass::Tuple,
|
||||||
"Use `Type::heterogeneous_tuple` or `Type::homogeneous_tuple` to create `tuple` instances"
|
"Use `Type::heterogeneous_tuple` or `Type::homogeneous_tuple` to create `tuple` instances"
|
||||||
);
|
);
|
||||||
self.to_specialized_class_type(db, specialization, None)
|
self.to_specialized_class_type(db, specialization)
|
||||||
.and_then(|class_type| Type::from(class_type).to_instance(db))
|
.and_then(|class_type| Type::from(class_type).to_instance(db))
|
||||||
.unwrap_or_else(Type::unknown)
|
.unwrap_or_else(Type::unknown)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,9 @@ impl<'db> ClassBase<'db> {
|
||||||
KnownInstanceType::TypeGenericAlias(_) => {
|
KnownInstanceType::TypeGenericAlias(_) => {
|
||||||
Self::try_from_type(db, KnownClass::Type.to_class_literal(db), subclass)
|
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) => {
|
KnownInstanceType::Annotated(ty) => {
|
||||||
// Unions are not supported in this position, so we only need to support
|
// Unions are not supported in this position, so we only need to support
|
||||||
// something like `class C(Annotated[Base, "metadata"]): ...`, which we
|
// something like `class C(Annotated[Base, "metadata"]): ...`, which we
|
||||||
|
|
@ -239,7 +242,7 @@ impl<'db> ClassBase<'db> {
|
||||||
db,
|
db,
|
||||||
fields.values().map(|field| field.declared_ty),
|
fields.values().map(|field| field.declared_ty),
|
||||||
)?
|
)?
|
||||||
.to_class_type(db, None)
|
.to_class_type(db)
|
||||||
.into(),
|
.into(),
|
||||||
subclass,
|
subclass,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7500,7 +7500,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_type =
|
let class_type =
|
||||||
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context), None);
|
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context));
|
||||||
|
|
||||||
Type::from(class_type).to_instance(self.db())
|
Type::from(class_type).to_instance(self.db())
|
||||||
}
|
}
|
||||||
|
|
@ -10813,18 +10813,48 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
// If we have an implicit type alias like `MyList = list[T]`, and if `MyList` is being
|
// 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
|
// 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.
|
// 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 Type::KnownInstance(KnownInstanceType::GenericAlias(alias)) = value_ty {
|
||||||
let return_ty = self.infer_explicitly_specialized_type_alias(
|
return Type::KnownInstance(KnownInstanceType::GenericAlias(TypeInContext::new(
|
||||||
|
self.db(),
|
||||||
|
self.infer_explicitly_specialized_type_alias(
|
||||||
subscript,
|
subscript,
|
||||||
value_ty,
|
value_ty,
|
||||||
alias.binding_context(self.db()),
|
alias.binding_context(self.db()),
|
||||||
false,
|
false,
|
||||||
);
|
),
|
||||||
|
self.typevar_binding_context,
|
||||||
return return_ty;
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
fn infer_subscript_load_impl(
|
||||||
|
|
@ -10860,11 +10890,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let db = self.db();
|
let tuple_generic_alias = |db: &'db dyn Db, tuple: Option<TupleType<'db>>| {
|
||||||
let typevar_binding_context = self.typevar_binding_context;
|
|
||||||
let tuple_generic_alias = |tuple: Option<TupleType<'db>>| {
|
|
||||||
let tuple = tuple.unwrap_or_else(|| TupleType::homogeneous(db, Type::unknown()));
|
let tuple = tuple.unwrap_or_else(|| TupleType::homogeneous(db, Type::unknown()));
|
||||||
Type::from(tuple.to_class_type(db, typevar_binding_context))
|
Type::from(tuple.to_class_type(db))
|
||||||
};
|
};
|
||||||
|
|
||||||
match value_ty {
|
match value_ty {
|
||||||
|
|
@ -10876,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_
|
// updating all of the subscript logic below to use custom callables for all of the _other_
|
||||||
// special cases, too.
|
// special cases, too.
|
||||||
if class.is_tuple(self.db()) {
|
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) {
|
} else if class.is_known(self.db(), KnownClass::Type) {
|
||||||
let argument_ty = self.infer_type_expression(slice);
|
let argument_ty = self.infer_type_expression(slice);
|
||||||
return Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
return Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||||
|
|
@ -10904,7 +10932,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::SpecialForm(SpecialFormType::Tuple) => {
|
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) => {
|
Type::SpecialForm(SpecialFormType::Literal) => {
|
||||||
match self.infer_literal_parameter_type(slice) {
|
match self.infer_literal_parameter_type(slice) {
|
||||||
|
|
@ -11070,11 +11098,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
.expect("A known stdlib class is available");
|
.expect("A known stdlib class is available");
|
||||||
|
|
||||||
return class
|
return class
|
||||||
.to_specialized_class_type(
|
.to_specialized_class_type(self.db(), [element_ty])
|
||||||
self.db(),
|
|
||||||
[element_ty],
|
|
||||||
self.typevar_binding_context,
|
|
||||||
)
|
|
||||||
.map(Type::from)
|
.map(Type::from)
|
||||||
.unwrap_or_else(Type::unknown);
|
.unwrap_or_else(Type::unknown);
|
||||||
}
|
}
|
||||||
|
|
@ -11132,11 +11156,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
.expect("Stdlib class available");
|
.expect("Stdlib class available");
|
||||||
|
|
||||||
return class
|
return class
|
||||||
.to_specialized_class_type(
|
.to_specialized_class_type(self.db(), [first_ty, second_ty])
|
||||||
self.db(),
|
|
||||||
[first_ty, second_ty],
|
|
||||||
self.typevar_binding_context,
|
|
||||||
)
|
|
||||||
.map(Type::from)
|
.map(Type::from)
|
||||||
.unwrap_or_else(Type::unknown);
|
.unwrap_or_else(Type::unknown);
|
||||||
}
|
}
|
||||||
|
|
@ -11183,13 +11203,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
generic_context: GenericContext<'db>,
|
generic_context: GenericContext<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
let db = self.db();
|
let db = self.db();
|
||||||
let typevar_binding_context = self.typevar_binding_context;
|
|
||||||
let specialize = |types: &[Option<Type<'db>>]| {
|
let specialize = |types: &[Option<Type<'db>>]| {
|
||||||
Type::from(generic_class.apply_specialization(
|
Type::from(generic_class.apply_specialization(db, |_| {
|
||||||
db,
|
generic_context.specialize_partial(db, types.iter().copied())
|
||||||
|_| generic_context.specialize_partial(db, types.iter().copied()),
|
}))
|
||||||
typevar_binding_context,
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.infer_explicit_callable_specialization(
|
self.infer_explicit_callable_specialization(
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ use crate::types::string_annotation::parse_string_annotation;
|
||||||
use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
||||||
use crate::types::visitor::any_over_type;
|
use crate::types::visitor::any_over_type;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BindingContext, CallableType, DynamicType, GenericAlias, GenericContext, IntersectionBuilder,
|
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||||
KnownClass, KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType,
|
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||||
SubclassOfType, Type, TypeAliasType, TypeContext, TypeInContext, TypeIsType, TypeMapping,
|
Type, TypeAliasType, TypeContext, TypeInContext, TypeIsType, TypeMapping, UnionBuilder,
|
||||||
UnionBuilder, UnionType, todo_type,
|
UnionType, todo_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type expressions
|
/// Type expressions
|
||||||
|
|
@ -713,20 +713,13 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
match class_literal.generic_context(self.db()) {
|
match class_literal.generic_context(self.db()) {
|
||||||
Some(generic_context) => {
|
Some(generic_context) => {
|
||||||
let db = self.db();
|
let db = self.db();
|
||||||
let typevar_binding_context = self.typevar_binding_context;
|
|
||||||
let specialize = |types: &[Option<Type<'db>>]| {
|
let specialize = |types: &[Option<Type<'db>>]| {
|
||||||
SubclassOfType::from(
|
SubclassOfType::from(
|
||||||
db,
|
db,
|
||||||
class_literal.apply_specialization(
|
class_literal.apply_specialization(db, |_| {
|
||||||
db,
|
generic_context
|
||||||
|_| {
|
.specialize_partial(db, types.iter().copied())
|
||||||
generic_context.specialize_partial(
|
}),
|
||||||
db,
|
|
||||||
types.iter().copied(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
typevar_binding_context,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.infer_explicit_callable_specialization(
|
self.infer_explicit_callable_specialization(
|
||||||
|
|
@ -810,12 +803,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
} else {
|
} else {
|
||||||
// Update the binding context
|
// Update the binding context
|
||||||
match specialized {
|
match specialized {
|
||||||
Type::GenericAlias(alias) => Type::GenericAlias(GenericAlias::new(
|
// Type::GenericAlias(alias) => Type::GenericAlias(GenericAlias::new(
|
||||||
db,
|
// db,
|
||||||
alias.origin(db),
|
// alias.origin(db),
|
||||||
alias.specialization(db),
|
// alias.specialization(db),
|
||||||
current_typevar_binding_context,
|
// current_typevar_binding_context,
|
||||||
)),
|
// )),
|
||||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(instance)) => {
|
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(instance)) => {
|
||||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||||
TypeInContext::new(
|
TypeInContext::new(
|
||||||
|
|
@ -995,7 +988,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
KnownInstanceType::Annotated(instance)
|
KnownInstanceType::Annotated(instance)
|
||||||
| KnownInstanceType::TypeGenericAlias(instance) => self
|
| KnownInstanceType::TypeGenericAlias(instance)
|
||||||
|
| KnownInstanceType::GenericAlias(instance) => self
|
||||||
.infer_explicitly_specialized_type_alias(
|
.infer_explicitly_specialized_type_alias(
|
||||||
subscript,
|
subscript,
|
||||||
value_ty,
|
value_ty,
|
||||||
|
|
@ -1049,12 +1043,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::GenericAlias(alias) => self.infer_explicitly_specialized_type_alias(
|
// Type::GenericAlias(alias) => {
|
||||||
subscript,
|
// self.infer_explicitly_specialized_type_alias(subscript, value_ty, None, true)
|
||||||
value_ty,
|
// }
|
||||||
alias.binding_context(self.db()),
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
Type::StringLiteral(_) => {
|
Type::StringLiteral(_) => {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
// For stringified TypeAlias; remove once properly supported
|
// For stringified TypeAlias; remove once properly supported
|
||||||
|
|
@ -1063,6 +1054,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
_ => {
|
_ => {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||||
|
dbg!(&value_ty);
|
||||||
builder.into_diagnostic(format_args!(
|
builder.into_diagnostic(format_args!(
|
||||||
"Invalid subscript of object of type `{}` in type expression",
|
"Invalid subscript of object of type `{}` in type expression",
|
||||||
value_ty.display(self.db())
|
value_ty.display(self.db())
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ pub(super) fn walk_nominal_instance_type<'db, V: super::visitor::TypeVisitor<'db
|
||||||
impl<'db> NominalInstanceType<'db> {
|
impl<'db> NominalInstanceType<'db> {
|
||||||
pub(super) fn class(&self, db: &'db dyn Db) -> ClassType<'db> {
|
pub(super) fn class(&self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
match self.0 {
|
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::NonTuple(class) => class,
|
||||||
NominalInstanceInner::Object => KnownClass::Object
|
NominalInstanceInner::Object => KnownClass::Object
|
||||||
.try_to_class_literal(db)
|
.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> {
|
pub(super) fn class_literal(&self, db: &'db dyn Db) -> ClassLiteral<'db> {
|
||||||
let class = match self.0 {
|
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::NonTuple(class) => class,
|
||||||
NominalInstanceInner::Object => {
|
NominalInstanceInner::Object => {
|
||||||
return KnownClass::Object
|
return KnownClass::Object
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl<'db> Mro<'db> {
|
||||||
class_literal: ClassLiteral<'db>,
|
class_literal: ClassLiteral<'db>,
|
||||||
specialization: Option<Specialization<'db>>,
|
specialization: Option<Specialization<'db>>,
|
||||||
) -> Result<Self, MroError<'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`,
|
// Special-case `NotImplementedType`: typeshed says that it inherits from `Any`,
|
||||||
// but this causes more problems than it fixes.
|
// but this causes more problems than it fixes.
|
||||||
if class_literal.is_known(db, KnownClass::NotImplementedType) {
|
if class_literal.is_known(db, KnownClass::NotImplementedType) {
|
||||||
|
|
@ -100,7 +100,13 @@ impl<'db> Mro<'db> {
|
||||||
if original_bases.contains(&Type::SpecialForm(SpecialFormType::Protocol)) {
|
if original_bases.contains(&Type::SpecialForm(SpecialFormType::Protocol)) {
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
resolved_bases.push(ClassBase::Generic);
|
resolved_bases.push(ClassBase::Generic);
|
||||||
|
|
@ -412,11 +418,10 @@ impl<'db> Iterator for MroIterator<'db> {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if !self.first_element_yielded {
|
if !self.first_element_yielded {
|
||||||
self.first_element_yielded = true;
|
self.first_element_yielded = true;
|
||||||
return Some(ClassBase::Class(self.class.apply_optional_specialization(
|
return Some(ClassBase::Class(
|
||||||
self.db,
|
self.class
|
||||||
self.specialization,
|
.apply_optional_specialization(self.db, self.specialization),
|
||||||
None,
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
self.full_mro_except_first_element().next()
|
self.full_mro_except_first_element().next()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -202,27 +202,19 @@ impl<'db> TupleType<'db> {
|
||||||
// `static-frame` as part of a mypy_primer run! This is because it's called
|
// `static-frame` as part of a mypy_primer run! This is because it's called
|
||||||
// from `NominalInstanceType::class()`, which is a very hot method.
|
// 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)]
|
#[salsa::tracked(cycle_initial=to_class_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||||
pub(crate) fn to_class_type(
|
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||||
self,
|
|
||||||
db: &'db dyn Db,
|
|
||||||
binding_context: Option<Definition<'db>>,
|
|
||||||
) -> ClassType<'db> {
|
|
||||||
let tuple_class = KnownClass::Tuple
|
let tuple_class = KnownClass::Tuple
|
||||||
.try_to_class_literal(db)
|
.try_to_class_literal(db)
|
||||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||||
|
|
||||||
tuple_class.apply_specialization(
|
tuple_class.apply_specialization(db, |generic_context| {
|
||||||
db,
|
|
||||||
|generic_context| {
|
|
||||||
if generic_context.variables(db).len() == 1 {
|
if generic_context.variables(db).len() == 1 {
|
||||||
let element_type = self.tuple(db).homogeneous_element_type(db);
|
let element_type = self.tuple(db).homogeneous_element_type(db);
|
||||||
generic_context.specialize_tuple(db, element_type, self)
|
generic_context.specialize_tuple(db, element_type, self)
|
||||||
} else {
|
} else {
|
||||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
binding_context,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a normalized version of `self`.
|
/// Return a normalized version of `self`.
|
||||||
|
|
@ -302,23 +294,18 @@ fn to_class_type_cycle_initial<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
_id: salsa::Id,
|
_id: salsa::Id,
|
||||||
self_: TupleType<'db>,
|
self_: TupleType<'db>,
|
||||||
binding_context: Option<Definition<'db>>,
|
|
||||||
) -> ClassType<'db> {
|
) -> ClassType<'db> {
|
||||||
let tuple_class = KnownClass::Tuple
|
let tuple_class = KnownClass::Tuple
|
||||||
.try_to_class_literal(db)
|
.try_to_class_literal(db)
|
||||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||||
|
|
||||||
tuple_class.apply_specialization(
|
tuple_class.apply_specialization(db, |generic_context| {
|
||||||
db,
|
|
||||||
|generic_context| {
|
|
||||||
if generic_context.variables(db).len() == 1 {
|
if generic_context.variables(db).len() == 1 {
|
||||||
generic_context.specialize_tuple(db, Type::Never, self_)
|
generic_context.specialize_tuple(db, Type::Never, self_)
|
||||||
} else {
|
} else {
|
||||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
binding_context,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tuple spec describes the contents of a tuple type, which might be fixed- or variable-length.
|
/// A tuple spec describes the contents of a tuple type, which might be fixed- or variable-length.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue