mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 21:34:57 +00:00
[ty] Attribute access on top/bottom materializations (#20221)
## Summary Part of astral-sh/ty#994. The goal of this PR was to add correct behavior for attribute access on the top and bottom materializations. This is necessary for the end goal of using the top materialization for narrowing generics (`isinstance(x, list)`): we want methods like `x.append` to work correctly in that case. It turned out to be convenient to represent materialization as a TypeMapping, so it can be stashed in the `type_mappings` list of a function object. This also allowed me to remove most concrete `materialize` methods, since they usually just delegate to the subparts of the type, the same as other type mappings. That is why the net effect of this PR is to remove a few hundred lines. ## Test Plan I added a few more tests. Much of this PR is refactoring and covered by existing tests. ## Followups Assigning to attributes of top materializations is not yet covered. This seems less important so I'd like to defer it. I noticed that the `materialize` implementation of `Parameters` was wrong; it did the same for the top and bottom materializations. This PR makes the bottom materialization slightly more reasonable, but implementing this correctly will require extending the struct.
This commit is contained in:
parent
555b9f78d6
commit
de63f408b9
13 changed files with 263 additions and 399 deletions
|
@ -10,8 +10,9 @@ use crate::semantic_index::{
|
|||
};
|
||||
use crate::semantic_index::{DeclarationWithConstraint, global_scope, use_def_map};
|
||||
use crate::types::{
|
||||
DynamicType, KnownClass, Truthiness, Type, TypeAndQualifiers, TypeQualifiers, UnionBuilder,
|
||||
UnionType, binding_type, declaration_type, todo_type,
|
||||
ApplyTypeMappingVisitor, DynamicType, KnownClass, MaterializationKind, Truthiness, Type,
|
||||
TypeAndQualifiers, TypeQualifiers, UnionBuilder, UnionType, binding_type, declaration_type,
|
||||
todo_type,
|
||||
};
|
||||
use crate::{Db, FxOrderSet, Program, resolve_module};
|
||||
|
||||
|
@ -614,6 +615,15 @@ impl<'db> PlaceAndQualifiers<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> PlaceAndQualifiers<'db> {
|
||||
self.map_type(|ty| ty.materialize(db, materialization_kind, visitor))
|
||||
}
|
||||
|
||||
/// Transform place and qualifiers into a [`LookupResult`],
|
||||
/// a [`Result`] type in which the `Ok` variant represents a definitely bound place
|
||||
/// and the `Err` variant represents a place that is either definitely or possibly unbound.
|
||||
|
|
|
@ -526,16 +526,6 @@ impl<'db> PropertyInstanceType<'db> {
|
|||
ty.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.getter(db)
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
self.setter(db)
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
@ -778,14 +768,22 @@ impl<'db> Type<'db> {
|
|||
/// most general form of the type that is fully static.
|
||||
#[must_use]
|
||||
pub(crate) fn top_materialization(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.materialize(db, MaterializationKind::Top)
|
||||
self.materialize(
|
||||
db,
|
||||
MaterializationKind::Top,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the bottom materialization (or lower bound materialization) of this type, which is
|
||||
/// the most specific form of the type that is fully static.
|
||||
#[must_use]
|
||||
pub(crate) fn bottom_materialization(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.materialize(db, MaterializationKind::Bottom)
|
||||
self.materialize(
|
||||
db,
|
||||
MaterializationKind::Bottom,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// If this type is an instance type where the class has a tuple spec, returns the tuple spec.
|
||||
|
@ -817,103 +815,25 @@ impl<'db> Type<'db> {
|
|||
/// More concretely, `T'`, the materialization of `T`, is the type `T` with all occurrences of
|
||||
/// the dynamic types (`Any`, `Unknown`, `Todo`) replaced as follows:
|
||||
///
|
||||
/// - In covariant position, it's replaced with `object`
|
||||
/// - In covariant position, it's replaced with `object` (TODO: it should be the `TypeVar`'s upper
|
||||
/// bound, if any)
|
||||
/// - In contravariant position, it's replaced with `Never`
|
||||
/// - In invariant position, it's replaced with an unresolved type variable
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Type<'db> {
|
||||
match self {
|
||||
Type::Dynamic(_) => match materialization_kind {
|
||||
MaterializationKind::Top => Type::object(db),
|
||||
MaterializationKind::Bottom => Type::Never,
|
||||
},
|
||||
|
||||
Type::Never
|
||||
| Type::WrapperDescriptor(_)
|
||||
| Type::MethodWrapper(_)
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::EnumLiteral(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::KnownInstance(_)
|
||||
| Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::BoundSuper(_) => *self,
|
||||
|
||||
Type::PropertyInstance(property_instance) => {
|
||||
Type::PropertyInstance(property_instance.materialize(db, materialization_kind))
|
||||
}
|
||||
|
||||
Type::FunctionLiteral(_) | Type::BoundMethod(_) => {
|
||||
// TODO: Subtyping between function / methods with a callable accounts for the
|
||||
// signature (parameters and return type), so we might need to do something here
|
||||
*self
|
||||
}
|
||||
|
||||
Type::NominalInstance(instance) => instance.materialize(db, materialization_kind),
|
||||
Type::GenericAlias(generic_alias) => {
|
||||
Type::GenericAlias(generic_alias.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::Callable(callable_type) => {
|
||||
Type::Callable(callable_type.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::SubclassOf(subclass_of_type) => {
|
||||
subclass_of_type.materialize(db, materialization_kind)
|
||||
}
|
||||
Type::ProtocolInstance(protocol_instance_type) => {
|
||||
// TODO: Add tests for this once subtyping/assignability is implemented for
|
||||
// protocols. It _might_ require changing the logic here because:
|
||||
//
|
||||
// > Subtyping for protocol instances involves taking account of the fact that
|
||||
// > read-only property members, and method members, on protocols act covariantly;
|
||||
// > write-only property members act contravariantly; and read/write attribute
|
||||
// > members on protocols act invariantly
|
||||
Type::ProtocolInstance(protocol_instance_type.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::Union(union_type) => {
|
||||
union_type.map(db, |ty| ty.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::Intersection(intersection_type) => IntersectionBuilder::new(db)
|
||||
.positive_elements(
|
||||
intersection_type
|
||||
.positive(db)
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
)
|
||||
.negative_elements(
|
||||
intersection_type
|
||||
.negative(db)
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind.flip())),
|
||||
)
|
||||
.build(),
|
||||
Type::TypeVar(bound_typevar) => {
|
||||
Type::TypeVar(bound_typevar.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::NonInferableTypeVar(bound_typevar) => {
|
||||
Type::NonInferableTypeVar(bound_typevar.materialize(db, materialization_kind))
|
||||
}
|
||||
Type::TypeIs(type_is) => {
|
||||
// TODO(jelle): this seems wrong, should be invariant?
|
||||
type_is.with_type(
|
||||
db,
|
||||
type_is
|
||||
.return_type(db)
|
||||
.materialize(db, materialization_kind),
|
||||
)
|
||||
}
|
||||
Type::TypedDict(_) => {
|
||||
// TODO: Materialization of gradual TypedDicts
|
||||
*self
|
||||
}
|
||||
Type::TypeAlias(alias) => alias.value_type(db).materialize(db, materialization_kind),
|
||||
}
|
||||
/// - In invariant position, we replace the object with a special form recording that it's the top
|
||||
/// or bottom materialization.
|
||||
///
|
||||
/// This is implemented as a type mapping. Some specific objects have `materialize()` or
|
||||
/// `materialize_impl()` methods. The rule of thumb is:
|
||||
///
|
||||
/// - `materialize()` calls `apply_type_mapping()` (or `apply_type_mapping_impl()`)
|
||||
/// - `materialize_impl()` gets called from `apply_type_mapping()` or from another
|
||||
/// `materialize_impl()`
|
||||
pub(crate) fn materialize(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Type<'db> {
|
||||
self.apply_type_mapping_impl(db, &TypeMapping::Materialize(materialization_kind), visitor)
|
||||
}
|
||||
|
||||
pub(crate) const fn into_class_literal(self) -> Option<ClassLiteral<'db>> {
|
||||
|
@ -2792,7 +2712,17 @@ impl<'db> Type<'db> {
|
|||
}
|
||||
|
||||
Type::GenericAlias(alias) => {
|
||||
Some(ClassType::from(*alias).class_member(db, name, policy))
|
||||
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(
|
||||
db,
|
||||
materialization_kind,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
Type::SubclassOf(subclass_of_ty) => {
|
||||
|
@ -6011,7 +5941,11 @@ impl<'db> Type<'db> {
|
|||
self.apply_type_mapping(db, &TypeMapping::Specialization(specialization));
|
||||
match specialization.materialization_kind(db) {
|
||||
None => new_specialization,
|
||||
Some(materialization_kind) => new_specialization.materialize(db, materialization_kind),
|
||||
Some(materialization_kind) => new_specialization.materialize(
|
||||
db,
|
||||
materialization_kind,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6046,6 +5980,9 @@ impl<'db> Type<'db> {
|
|||
}
|
||||
TypeMapping::PromoteLiterals | TypeMapping::BindLegacyTypevars(_) |
|
||||
TypeMapping::MarkTypeVarsInferable(_) => self,
|
||||
TypeMapping::Materialize(materialization_kind) => {
|
||||
Type::TypeVar(bound_typevar.materialize_impl(db, *materialization_kind, visitor))
|
||||
}
|
||||
}
|
||||
|
||||
Type::NonInferableTypeVar(bound_typevar) => match type_mapping {
|
||||
|
@ -6066,6 +6003,8 @@ impl<'db> Type<'db> {
|
|||
TypeMapping::BindLegacyTypevars(_) |
|
||||
TypeMapping::BindSelf(_)
|
||||
=> self,
|
||||
TypeMapping::Materialize(materialization_kind) => Type::NonInferableTypeVar(bound_typevar.materialize_impl(db, *materialization_kind, visitor))
|
||||
|
||||
}
|
||||
|
||||
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
|
||||
|
@ -6076,7 +6015,8 @@ impl<'db> Type<'db> {
|
|||
TypeMapping::PartialSpecialization(_) |
|
||||
TypeMapping::PromoteLiterals |
|
||||
TypeMapping::BindSelf(_) |
|
||||
TypeMapping::MarkTypeVarsInferable(_) => self,
|
||||
TypeMapping::MarkTypeVarsInferable(_) |
|
||||
TypeMapping::Materialize(_) => self,
|
||||
}
|
||||
|
||||
Type::FunctionLiteral(function) => {
|
||||
|
@ -6093,6 +6033,13 @@ impl<'db> Type<'db> {
|
|||
instance.apply_type_mapping_impl(db, type_mapping, visitor),
|
||||
|
||||
Type::ProtocolInstance(instance) => {
|
||||
// TODO: Add tests for materialization once subtyping/assignability is implemented for
|
||||
// protocols. It _might_ require changing the logic here because:
|
||||
//
|
||||
// > Subtyping for protocol instances involves taking account of the fact that
|
||||
// > read-only property members, and method members, on protocols act covariantly;
|
||||
// > write-only property members act contravariantly; and read/write attribute
|
||||
// > members on protocols act invariantly
|
||||
Type::ProtocolInstance(instance.apply_type_mapping_impl(db, type_mapping, visitor))
|
||||
}
|
||||
|
||||
|
@ -6132,9 +6079,7 @@ impl<'db> Type<'db> {
|
|||
Type::TypedDict(typed_dict.apply_type_mapping_impl(db, type_mapping, visitor))
|
||||
}
|
||||
|
||||
Type::SubclassOf(subclass_of) => Type::SubclassOf(
|
||||
subclass_of.apply_type_mapping_impl(db, type_mapping, visitor),
|
||||
),
|
||||
Type::SubclassOf(subclass_of) => subclass_of.apply_type_mapping_impl(db, type_mapping, visitor),
|
||||
|
||||
Type::PropertyInstance(property) => {
|
||||
Type::PropertyInstance(property.apply_type_mapping_impl(db, type_mapping, visitor))
|
||||
|
@ -6149,13 +6094,18 @@ impl<'db> Type<'db> {
|
|||
builder =
|
||||
builder.add_positive(positive.apply_type_mapping_impl(db, type_mapping, visitor));
|
||||
}
|
||||
let flipped_mapping = match type_mapping {
|
||||
TypeMapping::Materialize(materialization_kind) => &TypeMapping::Materialize(materialization_kind.flip()),
|
||||
_ => type_mapping,
|
||||
};
|
||||
for negative in intersection.negative(db) {
|
||||
builder =
|
||||
builder.add_negative(negative.apply_type_mapping_impl(db, type_mapping, visitor));
|
||||
builder.add_negative(negative.apply_type_mapping_impl(db, flipped_mapping, visitor));
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
// TODO(jelle): Materialize should be handled differently, since TypeIs is invariant
|
||||
Type::TypeIs(type_is) => type_is.with_type(db, type_is.return_type(db).apply_type_mapping(db, type_mapping)),
|
||||
|
||||
Type::TypeAlias(alias) => {
|
||||
|
@ -6173,13 +6123,26 @@ impl<'db> Type<'db> {
|
|||
TypeMapping::PartialSpecialization(_) |
|
||||
TypeMapping::BindLegacyTypevars(_) |
|
||||
TypeMapping::BindSelf(_) |
|
||||
TypeMapping::MarkTypeVarsInferable(_) => self,
|
||||
TypeMapping::MarkTypeVarsInferable(_) |
|
||||
TypeMapping::Materialize(_) => self,
|
||||
TypeMapping::PromoteLiterals => self.literal_fallback_instance(db)
|
||||
.expect("literal type should have fallback instance type"),
|
||||
}
|
||||
|
||||
Type::Dynamic(_)
|
||||
| Type::Never
|
||||
Type::Dynamic(_) => match type_mapping {
|
||||
TypeMapping::Specialization(_) |
|
||||
TypeMapping::PartialSpecialization(_) |
|
||||
TypeMapping::BindLegacyTypevars(_) |
|
||||
TypeMapping::BindSelf(_) |
|
||||
TypeMapping::MarkTypeVarsInferable(_) |
|
||||
TypeMapping::PromoteLiterals => self,
|
||||
TypeMapping::Materialize(materialization_kind) => match materialization_kind {
|
||||
MaterializationKind::Top => Type::object(db),
|
||||
MaterializationKind::Bottom => Type::Never,
|
||||
}
|
||||
}
|
||||
|
||||
Type::Never
|
||||
| Type::AlwaysTruthy
|
||||
| Type::AlwaysFalsy
|
||||
| Type::WrapperDescriptor(_)
|
||||
|
@ -6692,6 +6655,8 @@ pub enum TypeMapping<'a, 'db> {
|
|||
BindSelf(Type<'db>),
|
||||
/// Marks the typevars that are bound by a generic class or function as inferable.
|
||||
MarkTypeVarsInferable(BindingContext<'db>),
|
||||
/// Create the top or bottom materialization of a type.
|
||||
Materialize(MaterializationKind),
|
||||
}
|
||||
|
||||
fn walk_type_mapping<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
|
@ -6711,7 +6676,8 @@ fn walk_type_mapping<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
|||
}
|
||||
TypeMapping::PromoteLiterals
|
||||
| TypeMapping::BindLegacyTypevars(_)
|
||||
| TypeMapping::MarkTypeVarsInferable(_) => {}
|
||||
| TypeMapping::MarkTypeVarsInferable(_)
|
||||
| TypeMapping::Materialize(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6732,6 +6698,9 @@ impl<'db> TypeMapping<'_, 'db> {
|
|||
TypeMapping::MarkTypeVarsInferable(binding_context) => {
|
||||
TypeMapping::MarkTypeVarsInferable(*binding_context)
|
||||
}
|
||||
TypeMapping::Materialize(materialization_kind) => {
|
||||
TypeMapping::Materialize(*materialization_kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6753,6 +6722,9 @@ impl<'db> TypeMapping<'_, 'db> {
|
|||
TypeMapping::MarkTypeVarsInferable(binding_context) => {
|
||||
TypeMapping::MarkTypeVarsInferable(*binding_context)
|
||||
}
|
||||
TypeMapping::Materialize(materialization_kind) => {
|
||||
TypeMapping::Materialize(*materialization_kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7443,7 +7415,12 @@ impl<'db> TypeVarInstance<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
fn materialize_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.name(db),
|
||||
|
@ -7452,26 +7429,32 @@ impl<'db> TypeVarInstance<'db> {
|
|||
.and_then(|bound_or_constraints| match bound_or_constraints {
|
||||
TypeVarBoundOrConstraintsEvaluation::Eager(bound_or_constraints) => Some(
|
||||
bound_or_constraints
|
||||
.materialize(db, materialization_kind)
|
||||
.materialize_impl(db, materialization_kind, visitor)
|
||||
.into(),
|
||||
),
|
||||
TypeVarBoundOrConstraintsEvaluation::LazyUpperBound => self
|
||||
.lazy_bound(db)
|
||||
.map(|bound| bound.materialize(db, materialization_kind).into()),
|
||||
TypeVarBoundOrConstraintsEvaluation::LazyUpperBound => {
|
||||
self.lazy_bound(db).map(|bound| {
|
||||
bound
|
||||
.materialize_impl(db, materialization_kind, visitor)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
TypeVarBoundOrConstraintsEvaluation::LazyConstraints => {
|
||||
self.lazy_constraints(db).map(|constraints| {
|
||||
constraints.materialize(db, materialization_kind).into()
|
||||
constraints
|
||||
.materialize_impl(db, materialization_kind, visitor)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
}),
|
||||
self.explicit_variance(db),
|
||||
self._default(db).and_then(|default| match default {
|
||||
TypeVarDefaultEvaluation::Eager(ty) => {
|
||||
Some(ty.materialize(db, materialization_kind).into())
|
||||
Some(ty.materialize(db, materialization_kind, visitor).into())
|
||||
}
|
||||
TypeVarDefaultEvaluation::Lazy => self
|
||||
.lazy_default(db)
|
||||
.map(|ty| ty.materialize(db, materialization_kind).into()),
|
||||
.map(|ty| ty.materialize(db, materialization_kind, visitor).into()),
|
||||
}),
|
||||
self.kind(db),
|
||||
)
|
||||
|
@ -7655,10 +7638,16 @@ impl<'db> BoundTypeVarInstance<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
fn materialize_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.typevar(db).materialize(db, materialization_kind),
|
||||
self.typevar(db)
|
||||
.materialize_impl(db, materialization_kind, visitor),
|
||||
self.binding_context(db),
|
||||
)
|
||||
}
|
||||
|
@ -7745,18 +7734,23 @@ impl<'db> TypeVarBoundOrConstraints<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
fn materialize_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
||||
TypeVarBoundOrConstraints::UpperBound(bound.materialize(db, materialization_kind))
|
||||
}
|
||||
TypeVarBoundOrConstraints::UpperBound(bound) => TypeVarBoundOrConstraints::UpperBound(
|
||||
bound.materialize(db, materialization_kind, visitor),
|
||||
),
|
||||
TypeVarBoundOrConstraints::Constraints(constraints) => {
|
||||
TypeVarBoundOrConstraints::Constraints(UnionType::new(
|
||||
db,
|
||||
constraints
|
||||
.elements(db)
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind))
|
||||
.map(|ty| ty.materialize(db, materialization_kind, visitor))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice(),
|
||||
))
|
||||
|
@ -8987,14 +8981,6 @@ impl<'db> CallableType<'db> {
|
|||
))
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
CallableType::new(
|
||||
db,
|
||||
self.signatures(db).materialize(db, materialization_kind),
|
||||
self.is_function_like(db),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a callable type which represents a fully-static "bottom" callable.
|
||||
///
|
||||
/// Specifically, this represents a callable type with a single signature:
|
||||
|
|
|
@ -802,17 +802,6 @@ impl<'db> IntersectionBuilder<'db> {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn negative_elements<I, T>(mut self, elements: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<Type<'db>>,
|
||||
{
|
||||
for element in elements {
|
||||
self = self.add_negative(element.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(mut self) -> Type<'db> {
|
||||
// Avoid allocating the UnionBuilder unnecessarily if we have just one intersection:
|
||||
if self.intersections.len() == 1 {
|
||||
|
|
|
@ -29,10 +29,10 @@ use crate::types::typed_dict::typed_dict_params_from_class_def;
|
|||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, Binding, BoundSuperError, BoundSuperType, CallableType,
|
||||
DataclassParams, DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
|
||||
IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind,
|
||||
NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeMapping,
|
||||
TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypedDictParams,
|
||||
UnionBuilder, VarianceInferable, declaration_type, infer_definition_types,
|
||||
IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, NormalizedVisitor,
|
||||
PropertyInstanceType, StringLiteralType, TypeAliasType, TypeMapping, TypeRelation,
|
||||
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypedDictParams, UnionBuilder,
|
||||
VarianceInferable, declaration_type, infer_definition_types,
|
||||
};
|
||||
use crate::{
|
||||
Db, FxIndexMap, FxOrderSet, Program,
|
||||
|
@ -270,19 +270,6 @@ impl<'db> GenericAlias<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.origin(db),
|
||||
self.specialization(db)
|
||||
.materialize(db, materialization_kind),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> {
|
||||
self.origin(db).definition(db)
|
||||
}
|
||||
|
@ -408,17 +395,6 @@ impl<'db> ClassType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
match self {
|
||||
Self::NonGeneric(_) => self,
|
||||
Self::Generic(generic) => Self::Generic(generic.materialize(db, materialization_kind)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn has_pep_695_type_params(self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
Self::NonGeneric(class) => class.has_pep_695_type_params(db),
|
||||
|
@ -769,7 +745,17 @@ impl<'db> ClassType<'db> {
|
|||
let fallback_member_lookup = || {
|
||||
class_literal
|
||||
.own_class_member(db, inherited_generic_context, specialization, name)
|
||||
.map_type(|ty| ty.apply_optional_specialization(db, specialization))
|
||||
.map_type(|ty| {
|
||||
let ty = ty.apply_optional_specialization(db, specialization);
|
||||
match specialization.map(|spec| spec.materialization_kind(db)) {
|
||||
Some(Some(materialization_kind)) => ty.materialize(
|
||||
db,
|
||||
materialization_kind,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
),
|
||||
_ => ty,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let synthesize_simple_tuple_method = |return_type| {
|
||||
|
|
|
@ -302,13 +302,11 @@ impl<'db> ClassBase<'db> {
|
|||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, kind: MaterializationKind) -> Self {
|
||||
match self {
|
||||
ClassBase::Class(class) => Self::Class(class.materialize(db, kind)),
|
||||
ClassBase::Dynamic(_)
|
||||
| ClassBase::Generic
|
||||
| ClassBase::Protocol
|
||||
| ClassBase::TypedDict => self,
|
||||
}
|
||||
self.apply_type_mapping_impl(
|
||||
db,
|
||||
&TypeMapping::Materialize(kind),
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn has_cyclic_mro(self, db: &'db dyn Db) -> bool {
|
||||
|
|
|
@ -590,7 +590,11 @@ impl<'db> Specialization<'db> {
|
|||
let new_specialization = self.apply_type_mapping(db, &TypeMapping::Specialization(other));
|
||||
match other.materialization_kind(db) {
|
||||
None => new_specialization,
|
||||
Some(materialization_kind) => new_specialization.materialize(db, materialization_kind),
|
||||
Some(materialization_kind) => new_specialization.materialize_impl(
|
||||
db,
|
||||
materialization_kind,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,6 +612,9 @@ impl<'db> Specialization<'db> {
|
|||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
if let TypeMapping::Materialize(materialization_kind) = type_mapping {
|
||||
return self.materialize_impl(db, *materialization_kind, visitor);
|
||||
}
|
||||
let types: Box<[_]> = self
|
||||
.types(db)
|
||||
.iter()
|
||||
|
@ -684,10 +691,11 @@ impl<'db> Specialization<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
pub(super) fn materialize_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
// The top and bottom materializations are fully static types already, so materializing them
|
||||
// further does nothing.
|
||||
|
@ -705,14 +713,17 @@ impl<'db> Specialization<'db> {
|
|||
TypeVarVariance::Bivariant => {
|
||||
// With bivariance, all specializations are subtypes of each other,
|
||||
// so any materialization is acceptable.
|
||||
vartype.materialize(db, MaterializationKind::Top)
|
||||
vartype.materialize(db, MaterializationKind::Top, visitor)
|
||||
}
|
||||
TypeVarVariance::Covariant => {
|
||||
vartype.materialize(db, materialization_kind, visitor)
|
||||
}
|
||||
TypeVarVariance::Covariant => vartype.materialize(db, materialization_kind),
|
||||
TypeVarVariance::Contravariant => {
|
||||
vartype.materialize(db, materialization_kind.flip())
|
||||
vartype.materialize(db, materialization_kind.flip(), visitor)
|
||||
}
|
||||
TypeVarVariance::Invariant => {
|
||||
let top_materialization = vartype.materialize(db, MaterializationKind::Top);
|
||||
let top_materialization =
|
||||
vartype.materialize(db, MaterializationKind::Top, visitor);
|
||||
if !vartype.is_equivalent_to(db, top_materialization) {
|
||||
has_dynamic_invariant_typevar = true;
|
||||
}
|
||||
|
@ -723,7 +734,11 @@ impl<'db> Specialization<'db> {
|
|||
.collect();
|
||||
let tuple_inner = self.tuple_inner(db).and_then(|tuple| {
|
||||
// Tuples are immutable, so tuple element types are always in covariant position.
|
||||
tuple.materialize(db, materialization_kind)
|
||||
tuple.apply_type_mapping_impl(
|
||||
db,
|
||||
&TypeMapping::Materialize(materialization_kind),
|
||||
visitor,
|
||||
)
|
||||
});
|
||||
let new_materialization_kind = if has_dynamic_invariant_typevar {
|
||||
Some(materialization_kind)
|
||||
|
|
|
@ -13,8 +13,8 @@ use crate::types::protocol_class::walk_protocol_interface;
|
|||
use crate::types::tuple::{TupleSpec, TupleType};
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, ClassBase, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
|
||||
IsDisjointVisitor, IsEquivalentVisitor, MaterializationKind, NormalizedVisitor, TypeMapping,
|
||||
TypeRelation, VarianceInferable,
|
||||
IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, TypeMapping, TypeRelation,
|
||||
VarianceInferable,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
@ -260,21 +260,6 @@ impl<'db> NominalInstanceType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Type<'db> {
|
||||
match self.0 {
|
||||
NominalInstanceInner::ExactTuple(tuple) => {
|
||||
Type::tuple(tuple.materialize(db, materialization_kind))
|
||||
}
|
||||
NominalInstanceInner::NonTuple(class) => {
|
||||
Type::non_tuple_instance(class.materialize(db, materialization_kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn has_relation_to_impl<C: Constraints<'db>>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -588,20 +573,6 @@ impl<'db> ProtocolInstanceType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
match self.inner {
|
||||
// TODO: This should also materialize via `class.materialize(db, variance)`
|
||||
Protocol::FromClass(class) => Self::from_class(class),
|
||||
Protocol::Synthesized(synthesized) => {
|
||||
Self::synthesized(synthesized.materialize(db, materialization_kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn apply_type_mapping_impl<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -685,7 +656,7 @@ mod synthesized_protocol {
|
|||
use crate::types::protocol_class::ProtocolInterface;
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor,
|
||||
MaterializationKind, NormalizedVisitor, TypeMapping, TypeVarVariance, VarianceInferable,
|
||||
NormalizedVisitor, TypeMapping, TypeVarVariance, VarianceInferable,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
@ -712,14 +683,6 @@ mod synthesized_protocol {
|
|||
Self(interface.normalized_impl(db, visitor))
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
Self(self.0.materialize(db, materialization_kind))
|
||||
}
|
||||
|
||||
pub(super) fn apply_type_mapping_impl<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
|
|
@ -19,8 +19,8 @@ use crate::{
|
|||
types::{
|
||||
ApplyTypeMappingVisitor, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral,
|
||||
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, KnownFunction,
|
||||
MaterializationKind, NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping,
|
||||
TypeQualifiers, TypeRelation, VarianceInferable,
|
||||
NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping, TypeQualifiers,
|
||||
TypeRelation, VarianceInferable,
|
||||
constraints::{Constraints, IteratorConstraintsExtension},
|
||||
signatures::{Parameter, Parameters},
|
||||
},
|
||||
|
@ -256,20 +256,6 @@ impl<'db> ProtocolInterface<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.inner(db)
|
||||
.iter()
|
||||
.map(|(name, data)| (name.clone(), data.materialize(db, materialization_kind)))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn specialized_and_normalized<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -382,13 +368,6 @@ impl<'db> ProtocolMemberData<'db> {
|
|||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
Self {
|
||||
kind: self.kind.materialize(db, materialization_kind),
|
||||
qualifiers: self.qualifiers,
|
||||
}
|
||||
}
|
||||
|
||||
fn display(&self, db: &'db dyn Db) -> impl std::fmt::Display {
|
||||
struct ProtocolMemberDataDisplay<'db> {
|
||||
db: &'db dyn Db,
|
||||
|
@ -492,20 +471,6 @@ impl<'db> ProtocolMemberKind<'db> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn materialize(self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
match self {
|
||||
ProtocolMemberKind::Method(callable) => {
|
||||
ProtocolMemberKind::Method(callable.materialize(db, materialization_kind))
|
||||
}
|
||||
ProtocolMemberKind::Property(property) => {
|
||||
ProtocolMemberKind::Property(property.materialize(db, materialization_kind))
|
||||
}
|
||||
ProtocolMemberKind::Other(ty) => {
|
||||
ProtocolMemberKind::Other(ty.materialize(db, materialization_kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single member of a protocol interface.
|
||||
|
|
|
@ -58,18 +58,6 @@ impl<'db> CallableSignature<'db> {
|
|||
self.overloads.iter()
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
Self::from_overloads(
|
||||
self.overloads
|
||||
.iter()
|
||||
.map(|signature| signature.materialize(db, materialization_kind)),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -414,21 +402,6 @@ impl<'db> Signature<'db> {
|
|||
self
|
||||
}
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
Self {
|
||||
generic_context: self.generic_context,
|
||||
inherited_generic_context: self.inherited_generic_context,
|
||||
definition: self.definition,
|
||||
// Parameters are at contravariant position, so the variance is flipped.
|
||||
parameters: self.parameters.materialize(db, materialization_kind.flip()),
|
||||
return_ty: Some(
|
||||
self.return_ty
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, materialization_kind),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -469,13 +442,19 @@ impl<'db> Signature<'db> {
|
|||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
let flipped_mapping = match type_mapping {
|
||||
TypeMapping::Materialize(materialization_kind) => {
|
||||
&TypeMapping::Materialize(materialization_kind.flip())
|
||||
}
|
||||
_ => type_mapping,
|
||||
};
|
||||
Self {
|
||||
generic_context: self.generic_context,
|
||||
inherited_generic_context: self.inherited_generic_context,
|
||||
definition: self.definition,
|
||||
parameters: self
|
||||
.parameters
|
||||
.apply_type_mapping_impl(db, type_mapping, visitor),
|
||||
.apply_type_mapping_impl(db, flipped_mapping, visitor),
|
||||
return_ty: self
|
||||
.return_ty
|
||||
.map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)),
|
||||
|
@ -1088,17 +1067,6 @@ impl<'db> Parameters<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
if self.is_gradual {
|
||||
Parameters::object(db)
|
||||
} else {
|
||||
Parameters::new(
|
||||
self.iter()
|
||||
.map(|parameter| parameter.materialize(db, materialization_kind)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_slice(&self) -> &[Parameter<'db>] {
|
||||
self.value.as_slice()
|
||||
}
|
||||
|
@ -1254,13 +1222,27 @@ impl<'db> Parameters<'db> {
|
|||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
value: self
|
||||
.value
|
||||
.iter()
|
||||
.map(|param| param.apply_type_mapping_impl(db, type_mapping, visitor))
|
||||
.collect(),
|
||||
is_gradual: self.is_gradual,
|
||||
match type_mapping {
|
||||
// Note that we've already flipped the materialization in Signature.apply_type_mapping_impl(),
|
||||
// so the "top" materialization here is the bottom materialization of the whole Signature.
|
||||
// It might make sense to flip the materialization here instead.
|
||||
TypeMapping::Materialize(MaterializationKind::Top) if self.is_gradual => {
|
||||
Parameters::object(db)
|
||||
}
|
||||
// TODO: This is wrong, the empty Parameters is not a subtype of all materializations.
|
||||
// The bottom materialization is not currently representable and implementing it
|
||||
// properly requires extending the Parameters struct.
|
||||
TypeMapping::Materialize(MaterializationKind::Bottom) if self.is_gradual => {
|
||||
Parameters::empty()
|
||||
}
|
||||
_ => Self {
|
||||
value: self
|
||||
.value
|
||||
.iter()
|
||||
.map(|param| param.apply_type_mapping_impl(db, type_mapping, visitor))
|
||||
.collect(),
|
||||
is_gradual: self.is_gradual,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1425,18 +1407,6 @@ impl<'db> Parameter<'db> {
|
|||
self
|
||||
}
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
Self {
|
||||
annotated_type: Some(
|
||||
self.annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, materialization_kind),
|
||||
),
|
||||
kind: self.kind.clone(),
|
||||
form: self.form,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_type_mapping_impl<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
|
|
@ -80,35 +80,27 @@ impl<'db> SubclassOfType<'db> {
|
|||
subclass_of.is_dynamic()
|
||||
}
|
||||
|
||||
pub(super) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Type<'db> {
|
||||
match self.subclass_of {
|
||||
SubclassOfInner::Dynamic(_) => match materialization_kind {
|
||||
MaterializationKind::Top => KnownClass::Type.to_instance(db),
|
||||
MaterializationKind::Bottom => Type::Never,
|
||||
},
|
||||
SubclassOfInner::Class(_) => Type::SubclassOf(self),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn apply_type_mapping_impl<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
) -> Type<'db> {
|
||||
match self.subclass_of {
|
||||
SubclassOfInner::Class(class) => Self {
|
||||
SubclassOfInner::Class(class) => Type::SubclassOf(Self {
|
||||
subclass_of: SubclassOfInner::Class(class.apply_type_mapping_impl(
|
||||
db,
|
||||
type_mapping,
|
||||
visitor,
|
||||
)),
|
||||
}),
|
||||
SubclassOfInner::Dynamic(_) => match type_mapping {
|
||||
TypeMapping::Materialize(materialization_kind) => match materialization_kind {
|
||||
MaterializationKind::Top => KnownClass::Type.to_instance(db),
|
||||
MaterializationKind::Bottom => Type::Never,
|
||||
},
|
||||
_ => Type::SubclassOf(self),
|
||||
},
|
||||
SubclassOfInner::Dynamic(_) => self,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ use crate::types::class::{ClassType, KnownClass};
|
|||
use crate::types::constraints::{Constraints, IteratorConstraintsExtension};
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
|
||||
IsDisjointVisitor, IsEquivalentVisitor, MaterializationKind, NormalizedVisitor, Type,
|
||||
TypeMapping, TypeRelation, UnionBuilder, UnionType,
|
||||
IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, Type, TypeMapping, TypeRelation,
|
||||
UnionBuilder, UnionType,
|
||||
};
|
||||
use crate::util::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroError};
|
||||
use crate::{Db, FxOrderSet, Program};
|
||||
|
@ -228,14 +228,6 @@ impl<'db> TupleType<'db> {
|
|||
TupleType::new(db, &self.tuple(db).normalized_impl(db, visitor))
|
||||
}
|
||||
|
||||
pub(crate) fn materialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Option<Self> {
|
||||
TupleType::new(db, &self.tuple(db).materialize(db, materialization_kind))
|
||||
}
|
||||
|
||||
pub(crate) fn apply_type_mapping_impl<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -394,14 +386,6 @@ impl<'db> FixedLengthTuple<Type<'db>> {
|
|||
Self::from_elements(self.0.iter().map(|ty| ty.normalized_impl(db, visitor)))
|
||||
}
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, materialization_kind: MaterializationKind) -> Self {
|
||||
Self::from_elements(
|
||||
self.0
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
)
|
||||
}
|
||||
|
||||
fn apply_type_mapping_impl<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -713,22 +697,6 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
|||
})
|
||||
}
|
||||
|
||||
fn materialize(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> TupleSpec<'db> {
|
||||
Self::mixed(
|
||||
self.prefix
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
self.variable.materialize(db, materialization_kind),
|
||||
self.suffix
|
||||
.iter()
|
||||
.map(|ty| ty.materialize(db, materialization_kind)),
|
||||
)
|
||||
}
|
||||
|
||||
fn apply_type_mapping_impl<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -1077,17 +1045,6 @@ impl<'db> Tuple<Type<'db>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn materialize(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
materialization_kind: MaterializationKind,
|
||||
) -> Self {
|
||||
match self {
|
||||
Tuple::Fixed(tuple) => Tuple::Fixed(tuple.materialize(db, materialization_kind)),
|
||||
Tuple::Variable(tuple) => tuple.materialize(db, materialization_kind),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_type_mapping_impl<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
|
|
|
@ -61,6 +61,7 @@ impl<'db> TypedDictType<'db> {
|
|||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||
) -> Self {
|
||||
// TODO: Materialization of gradual TypedDicts needs more logic
|
||||
Self {
|
||||
defining_class: self
|
||||
.defining_class
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue