mirror of https://github.com/astral-sh/ruff
use internal `TypedDictSchema` type for functional `TypedDict` constructor
This commit is contained in:
parent
f2a25b0fd7
commit
b753851379
|
|
@ -97,10 +97,18 @@ from typing import TypedDict
|
|||
from typing_extensions import Required, NotRequired
|
||||
|
||||
Person = TypedDict("Person", {"name": Required[str], "age": int | None})
|
||||
|
||||
reveal_type(Person) # revealed: typing.TypedDict
|
||||
```
|
||||
|
||||
The `TypedDict` schema must be passed directly as the second argument:
|
||||
|
||||
```py
|
||||
fields = {"name": str}
|
||||
|
||||
# error: [invalid-argument-type] "Argument is incorrect: Expected `_TypedDictSchema`, found `dict[Unknown | str, Unknown | <class 'str'>]`"
|
||||
Other = TypedDict("Other", fields)
|
||||
```
|
||||
|
||||
New inhabitants can be created from dict literals. When accessing keys, the correct types should be
|
||||
inferred based on the `TypedDict` definition:
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ use crate::types::mro::{Mro, MroError, MroIterator};
|
|||
pub(crate) use crate::types::narrow::infer_narrowing_constraint;
|
||||
use crate::types::signatures::{ParameterForm, walk_signature};
|
||||
use crate::types::tuple::TupleSpec;
|
||||
use crate::types::typed_dict::SynthesizedTypedDictType;
|
||||
use crate::types::typed_dict::{SynthesizedTypedDictType, TypedDictSchema};
|
||||
pub(crate) use crate::types::typed_dict::{TypedDictParams, TypedDictType, walk_typed_dict_type};
|
||||
use crate::types::variance::{TypeVarVariance, VarianceInferable};
|
||||
use crate::types::visitor::any_over_type;
|
||||
|
|
@ -1523,6 +1523,11 @@ impl<'db> Type<'db> {
|
|||
.has_relation_to_impl(db, right, relation, visitor)
|
||||
}
|
||||
|
||||
(
|
||||
Type::KnownInstance(KnownInstanceType::TypedDictSchema(_)),
|
||||
Type::SpecialForm(SpecialFormType::TypedDictSchema),
|
||||
) => ConstraintSet::from(true),
|
||||
|
||||
// Dynamic is only a subtype of `object` and only a supertype of `Never`; both were
|
||||
// handled above. It's always assignable, though.
|
||||
//
|
||||
|
|
@ -4767,10 +4772,9 @@ impl<'db> Type<'db> {
|
|||
Parameter::positional_only(Some(Name::new_static("typename")))
|
||||
.with_annotated_type(KnownClass::Str.to_instance(db)),
|
||||
Parameter::positional_only(Some(Name::new_static("fields")))
|
||||
// We infer this type as an anonymous `TypedDict` instance, such that the
|
||||
// complete `TypeDict` instance can be constructed from it after. Note that
|
||||
// `typing.TypedDict` is not otherwise allowed in type-form expressions.
|
||||
.with_annotated_type(Type::SpecialForm(SpecialFormType::TypedDict))
|
||||
.with_annotated_type(Type::SpecialForm(
|
||||
SpecialFormType::TypedDictSchema,
|
||||
))
|
||||
.with_default_type(Type::any()),
|
||||
Parameter::keyword_only(Name::new_static("total"))
|
||||
.with_annotated_type(KnownClass::Bool.to_instance(db))
|
||||
|
|
@ -5678,6 +5682,12 @@ impl<'db> Type<'db> {
|
|||
KnownInstanceType::TypedDictType(typed_dict) => {
|
||||
Ok(Type::TypedDict(TypedDictType::Synthesized(*typed_dict)))
|
||||
}
|
||||
KnownInstanceType::TypedDictSchema(_) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::InvalidType(
|
||||
*self, scope_id
|
||||
)],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
KnownInstanceType::Deprecated(_) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::Deprecated],
|
||||
fallback_type: Type::unknown(),
|
||||
|
|
@ -5768,6 +5778,12 @@ impl<'db> Type<'db> {
|
|||
],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
SpecialFormType::TypedDictSchema => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec_inline![
|
||||
InvalidTypeExpression::InvalidType(*self, scope_id)
|
||||
],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
|
||||
SpecialFormType::Literal
|
||||
| SpecialFormType::Union
|
||||
|
|
@ -6875,6 +6891,10 @@ pub enum KnownInstanceType<'db> {
|
|||
/// A single instance of `typing.TypedDict`.
|
||||
TypedDictType(SynthesizedTypedDictType<'db>),
|
||||
|
||||
/// An internal type representing the dictionary literal argument to the functional `TypedDict`
|
||||
/// constructor.
|
||||
TypedDictSchema(TypedDictSchema<'db>),
|
||||
|
||||
/// A single instance of `warnings.deprecated` or `typing_extensions.deprecated`
|
||||
Deprecated(DeprecatedInstance<'db>),
|
||||
|
||||
|
|
@ -6905,7 +6925,9 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
|||
KnownInstanceType::TypedDictType(typed_dict) => {
|
||||
visitor.visit_typed_dict_type(db, TypedDictType::Synthesized(typed_dict));
|
||||
}
|
||||
KnownInstanceType::Deprecated(_) | KnownInstanceType::ConstraintSet(_) => {
|
||||
KnownInstanceType::Deprecated(_)
|
||||
| KnownInstanceType::ConstraintSet(_)
|
||||
| KnownInstanceType::TypedDictSchema(_) => {
|
||||
// Nothing to visit
|
||||
}
|
||||
KnownInstanceType::Field(field) => {
|
||||
|
|
@ -6930,15 +6952,8 @@ impl<'db> KnownInstanceType<'db> {
|
|||
Self::TypedDictType(typed_dict) => {
|
||||
Self::TypedDictType(typed_dict.normalized_impl(db, visitor))
|
||||
}
|
||||
Self::Deprecated(deprecated) => {
|
||||
// Nothing to normalize
|
||||
Self::Deprecated(deprecated)
|
||||
}
|
||||
Self::Field(field) => Self::Field(field.normalized_impl(db, visitor)),
|
||||
Self::ConstraintSet(set) => {
|
||||
// Nothing to normalize
|
||||
Self::ConstraintSet(set)
|
||||
}
|
||||
Self::Deprecated(_) | Self::TypedDictSchema(_) | Self::ConstraintSet(_) => self,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6951,6 +6966,7 @@ impl<'db> KnownInstanceType<'db> {
|
|||
}
|
||||
Self::TypeAliasType(_) => KnownClass::TypeAliasType,
|
||||
Self::TypedDictType(_) => KnownClass::TypedDictFallback,
|
||||
Self::TypedDictSchema(_) => KnownClass::Object,
|
||||
Self::Deprecated(_) => KnownClass::Deprecated,
|
||||
Self::Field(_) => KnownClass::Field,
|
||||
Self::ConstraintSet(_) => KnownClass::ConstraintSet,
|
||||
|
|
@ -7008,6 +7024,7 @@ impl<'db> KnownInstanceType<'db> {
|
|||
}
|
||||
}
|
||||
KnownInstanceType::TypedDictType(_) => f.write_str("typing.TypedDict"),
|
||||
KnownInstanceType::TypedDictSchema(_) => f.write_str("_TypedDictSchema"),
|
||||
// This is a legacy `TypeVar` _outside_ of any generic class or function, so we render
|
||||
// it as an instance of `typing.TypeVar`. Inside of a generic class or function, we'll
|
||||
// have a `Type::TypeVar(_)`, which is rendered as the typevar's name.
|
||||
|
|
|
|||
|
|
@ -1098,8 +1098,12 @@ impl<'db> Bindings<'db> {
|
|||
},
|
||||
|
||||
Type::SpecialForm(SpecialFormType::TypedDict) => {
|
||||
let [Some(name), Some(Type::TypedDict(typed_dict)), total, ..] =
|
||||
overload.parameter_types()
|
||||
let [
|
||||
Some(name),
|
||||
Some(Type::KnownInstance(KnownInstanceType::TypedDictSchema(schema))),
|
||||
total,
|
||||
..,
|
||||
] = overload.parameter_types()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -1113,26 +1117,19 @@ impl<'db> Bindings<'db> {
|
|||
let is_total = to_bool(total, true);
|
||||
params.set(TypedDictParams::TOTAL, is_total);
|
||||
|
||||
let items = typed_dict.items(db);
|
||||
let items = items
|
||||
let items = schema
|
||||
.items(db)
|
||||
.iter()
|
||||
.map(|(name, field)| {
|
||||
let FieldKind::TypedDict {
|
||||
is_required,
|
||||
is_read_only,
|
||||
} = field.kind
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let field = Field {
|
||||
single_declaration: None,
|
||||
declared_ty: field.declared_ty,
|
||||
kind: FieldKind::TypedDict {
|
||||
is_read_only,
|
||||
// If there is no explicit `Required`/`NotRequired` qualifier, use
|
||||
is_read_only: field.is_read_only,
|
||||
// If there is no explicit `Required` or `NotRequired` qualifier, use
|
||||
// the `total` parameter.
|
||||
is_required: is_required.unwrap_or(is_total).into(),
|
||||
is_required: field.is_required.unwrap_or(is_total),
|
||||
},
|
||||
..field.clone()
|
||||
};
|
||||
|
||||
(name.clone(), field)
|
||||
|
|
@ -1142,7 +1139,7 @@ impl<'db> Bindings<'db> {
|
|||
overload.set_return_type(Type::KnownInstance(
|
||||
KnownInstanceType::TypedDictType(SynthesizedTypedDictType::new(
|
||||
db,
|
||||
Some(Name::new(name.value(db))),
|
||||
Name::new(name.value(db)),
|
||||
params,
|
||||
items,
|
||||
)),
|
||||
|
|
|
|||
|
|
@ -1286,7 +1286,7 @@ pub(crate) enum FieldKind<'db> {
|
|||
/// `TypedDict` field metadata
|
||||
TypedDict {
|
||||
/// Whether this field is required
|
||||
is_required: Truthiness,
|
||||
is_required: bool,
|
||||
/// Whether this field is marked read-only
|
||||
is_read_only: bool,
|
||||
},
|
||||
|
|
@ -1313,7 +1313,7 @@ impl<'db> Field<'db> {
|
|||
FieldKind::Dataclass {
|
||||
init, default_ty, ..
|
||||
} => default_ty.is_none() && *init,
|
||||
FieldKind::TypedDict { is_required, .. } => is_required.is_always_true(),
|
||||
FieldKind::TypedDict { is_required, .. } => *is_required,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2566,7 +2566,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
};
|
||||
|
||||
FieldKind::TypedDict {
|
||||
is_required: Truthiness::from(is_required),
|
||||
is_required,
|
||||
is_read_only: attr.is_read_only(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ impl<'db> ClassBase<'db> {
|
|||
KnownInstanceType::TypeAliasType(_)
|
||||
| KnownInstanceType::TypeVar(_)
|
||||
| KnownInstanceType::TypedDictType(_)
|
||||
| KnownInstanceType::TypedDictSchema(_)
|
||||
| KnownInstanceType::Deprecated(_)
|
||||
| KnownInstanceType::Field(_)
|
||||
| KnownInstanceType::ConstraintSet(_) => None,
|
||||
|
|
@ -201,7 +202,8 @@ impl<'db> ClassBase<'db> {
|
|||
| SpecialFormType::TypeOf
|
||||
| SpecialFormType::CallableTypeOf
|
||||
| SpecialFormType::AlwaysTruthy
|
||||
| SpecialFormType::AlwaysFalsy => None,
|
||||
| SpecialFormType::AlwaysFalsy
|
||||
| SpecialFormType::TypedDictSchema => None,
|
||||
|
||||
SpecialFormType::Any => Some(Self::Dynamic(DynamicType::Any)),
|
||||
SpecialFormType::Unknown => Some(Self::unknown()),
|
||||
|
|
|
|||
|
|
@ -517,13 +517,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
.0
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt(f),
|
||||
TypedDictType::Synthesized(synthesized) => {
|
||||
let name = synthesized
|
||||
.name(self.db)
|
||||
.expect("cannot have incomplete `TypedDict` in type expression");
|
||||
|
||||
write!(f, "{name}")
|
||||
}
|
||||
TypedDictType::Synthesized(synthesized) => synthesized.name(self.db).fmt(f),
|
||||
},
|
||||
|
||||
Type::TypeAlias(alias) => f.write_str(alias.name(self.db)),
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ use crate::semantic_index::{
|
|||
};
|
||||
use crate::types::call::bind::MatchingOverloadIndex;
|
||||
use crate::types::call::{Binding, Bindings, CallArguments, CallError, CallErrorKind};
|
||||
use crate::types::class::{
|
||||
CodeGeneratorKind, Field, FieldKind, MetaclassErrorKind, MethodDecorator,
|
||||
};
|
||||
use crate::types::class::{CodeGeneratorKind, FieldKind, MetaclassErrorKind, MethodDecorator};
|
||||
use crate::types::context::{InNoTypeCheck, InferContext};
|
||||
use crate::types::cyclic::CycleDetector;
|
||||
use crate::types::diagnostic::{
|
||||
|
|
@ -86,7 +84,8 @@ use crate::types::signatures::Signature;
|
|||
use crate::types::subclass_of::SubclassOfInner;
|
||||
use crate::types::tuple::{Tuple, TupleLength, TupleSpec, TupleType};
|
||||
use crate::types::typed_dict::{
|
||||
TypedDictAssignmentKind, validate_typed_dict_constructor, validate_typed_dict_dict_literal,
|
||||
TypedDictAssignmentKind, TypedDictSchema, TypedDictSchemaField,
|
||||
validate_typed_dict_constructor, validate_typed_dict_dict_literal,
|
||||
validate_typed_dict_key_assignment,
|
||||
};
|
||||
use crate::types::visitor::any_over_type;
|
||||
|
|
@ -97,7 +96,7 @@ use crate::types::{
|
|||
Parameters, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness, Type,
|
||||
TypeAliasType, TypeAndQualifiers, TypeContext, TypeQualifiers,
|
||||
TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarInstance, TypeVarKind,
|
||||
TypedDictType, UnionBuilder, UnionType, binding_type, todo_type,
|
||||
UnionBuilder, UnionType, binding_type, todo_type,
|
||||
};
|
||||
use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
|
||||
use crate::unpack::{EvaluationMode, UnpackPosition};
|
||||
|
|
@ -5478,8 +5477,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
return ty;
|
||||
}
|
||||
|
||||
// Infer the dictionary literal passed to the `TypedDict` constructor.
|
||||
if let Some(ty) = self.infer_typed_dict_constructor_literal(dict, tcx) {
|
||||
// Infer the dictionary literal passed to the functional `TypedDict` constructor.
|
||||
if let Some(ty) = self.infer_typed_dict_schema(dict, tcx) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
|
|
@ -5631,8 +5630,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
.map(|_| Type::TypedDict(typed_dict))
|
||||
}
|
||||
|
||||
// Infer the dictionary literal passed to the `TypedDict` constructor.
|
||||
fn infer_typed_dict_constructor_literal(
|
||||
// Infer the dictionary literal passed to the functional `TypedDict` constructor.
|
||||
fn infer_typed_dict_schema(
|
||||
&mut self,
|
||||
dict: &ast::ExprDict,
|
||||
tcx: TypeContext<'db>,
|
||||
|
|
@ -5643,7 +5642,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
items,
|
||||
} = dict;
|
||||
|
||||
let Some(Type::SpecialForm(SpecialFormType::TypedDict)) = tcx.annotation else {
|
||||
let Some(Type::SpecialForm(SpecialFormType::TypedDictSchema)) = tcx.annotation else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -5673,22 +5672,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
Truthiness::Ambiguous
|
||||
};
|
||||
|
||||
let field = Field {
|
||||
single_declaration: None,
|
||||
declared_ty: field_ty.inner_type(),
|
||||
kind: FieldKind::TypedDict {
|
||||
let field = TypedDictSchemaField {
|
||||
is_required,
|
||||
declared_ty: field_ty.inner_type(),
|
||||
is_read_only: field_ty.qualifiers.contains(TypeQualifiers::READ_ONLY),
|
||||
},
|
||||
};
|
||||
|
||||
typed_dict_items.insert(ast::name::Name::new(key.value(self.db())), field);
|
||||
}
|
||||
|
||||
// Create an anonymous `TypedDict` from the items, to be completed by the `TypedDict` constructor binding.
|
||||
Some(Type::TypedDict(TypedDictType::from_items(
|
||||
self.db(),
|
||||
typed_dict_items,
|
||||
Some(Type::KnownInstance(KnownInstanceType::TypedDictSchema(
|
||||
TypedDictSchema::new(self.db(), typed_dict_items),
|
||||
)))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -769,6 +769,15 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::TypedDictSchema(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"`_TypedDictSchema` is not allowed in type expressions",
|
||||
));
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::TypeVar(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("TypeVar annotations")
|
||||
|
|
@ -1383,7 +1392,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
SpecialFormType::Tuple => {
|
||||
Type::tuple(self.infer_tuple_type_expression(arguments_slice))
|
||||
}
|
||||
SpecialFormType::Generic | SpecialFormType::Protocol => {
|
||||
SpecialFormType::Generic
|
||||
| SpecialFormType::Protocol
|
||||
| SpecialFormType::TypedDictSchema => {
|
||||
self.infer_expression(arguments_slice, TypeContext::default());
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
|
|
|
|||
|
|
@ -127,6 +127,10 @@ pub enum SpecialFormType {
|
|||
/// Typeshed defines this symbol as a class, but this isn't accurate: it's actually a factory function
|
||||
/// at runtime. We therefore represent it as a special form internally.
|
||||
NamedTuple,
|
||||
|
||||
/// An internal type representing the dictionary literal argument to the functional `TypedDict`
|
||||
/// constructor.
|
||||
TypedDictSchema,
|
||||
}
|
||||
|
||||
impl SpecialFormType {
|
||||
|
|
@ -179,7 +183,9 @@ impl SpecialFormType {
|
|||
| Self::ChainMap
|
||||
| Self::OrderedDict => KnownClass::StdlibAlias,
|
||||
|
||||
Self::Unknown | Self::AlwaysTruthy | Self::AlwaysFalsy => KnownClass::Object,
|
||||
Self::Unknown | Self::AlwaysTruthy | Self::AlwaysFalsy | Self::TypedDictSchema => {
|
||||
KnownClass::Object
|
||||
}
|
||||
|
||||
Self::NamedTuple => KnownClass::FunctionType,
|
||||
}
|
||||
|
|
@ -264,6 +270,8 @@ impl SpecialFormType {
|
|||
| Self::Intersection
|
||||
| Self::TypeOf
|
||||
| Self::CallableTypeOf => module.is_ty_extensions(),
|
||||
|
||||
Self::TypedDictSchema => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +332,8 @@ impl SpecialFormType {
|
|||
| Self::ReadOnly
|
||||
| Self::Protocol
|
||||
| Self::Any
|
||||
| Self::Generic => false,
|
||||
| Self::Generic
|
||||
| Self::TypedDictSchema => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +384,7 @@ impl SpecialFormType {
|
|||
SpecialFormType::Protocol => "typing.Protocol",
|
||||
SpecialFormType::Generic => "typing.Generic",
|
||||
SpecialFormType::NamedTuple => "typing.NamedTuple",
|
||||
SpecialFormType::TypedDictSchema => "_TypedDictSchema",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::types::generics::GenericContext;
|
|||
use crate::types::variance::TypeVarVariance;
|
||||
use crate::types::{
|
||||
BoundTypeVarInstance, CallableSignature, CallableType, KnownClass, NormalizedVisitor,
|
||||
Parameter, Parameters, Signature, StringLiteralType, SubclassOfType, UnionType,
|
||||
Parameter, Parameters, Signature, StringLiteralType, SubclassOfType, Truthiness, UnionType,
|
||||
};
|
||||
use crate::{Db, FxOrderMap};
|
||||
|
||||
|
|
@ -62,19 +62,6 @@ impl<'db> TypedDictType<'db> {
|
|||
TypedDictType::FromClass(class)
|
||||
}
|
||||
|
||||
/// Returns an anonymous (incomplete) `TypedDictType` from its items.
|
||||
///
|
||||
/// This is used to instantiate a `TypedDictType` from the dictionary literal passed to a
|
||||
/// `typing.TypedDict` constructor (functional form for creating `TypedDict`s).
|
||||
pub(crate) fn from_items(db: &'db dyn Db, items: FxOrderMap<Name, Field<'db>>) -> Self {
|
||||
TypedDictType::Synthesized(SynthesizedTypedDictType::new(
|
||||
db,
|
||||
None,
|
||||
TypedDictParams::default(),
|
||||
items,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn items(&self, db: &'db dyn Db) -> Cow<'db, FxOrderMap<Name, Field<'db>>> {
|
||||
match self {
|
||||
TypedDictType::Synthesized(synthesized) => Cow::Borrowed(synthesized.items(db)),
|
||||
|
|
@ -393,12 +380,39 @@ impl<'db> TypedDictType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An internal type representing the dictionary literal argument to the functional `TypedDict`
|
||||
/// constructor.
|
||||
#[salsa::interned(debug, heap_size=TypedDictSchema::heap_size)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct TypedDictSchema<'db> {
|
||||
pub(crate) items: FxOrderMap<Name, TypedDictSchemaField<'db>>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for TypedDictSchema<'_> {}
|
||||
|
||||
impl<'db> TypedDictSchema<'db> {
|
||||
fn heap_size((items,): &(FxOrderMap<Name, TypedDictSchemaField<'db>>,)) -> usize {
|
||||
ruff_memory_usage::order_map_heap_size(items)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub struct TypedDictSchemaField<'db> {
|
||||
/// The declared type of the field
|
||||
pub(crate) declared_ty: Type<'db>,
|
||||
|
||||
/// Whether this field is required.
|
||||
pub(crate) is_required: Truthiness,
|
||||
|
||||
/// Whether this field is marked read-only.
|
||||
pub(crate) is_read_only: bool,
|
||||
}
|
||||
|
||||
#[salsa::interned(debug, heap_size=SynthesizedTypedDictType::heap_size)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct SynthesizedTypedDictType<'db> {
|
||||
// The dictionary literal passed to the `TypedDict` constructor is inferred as
|
||||
// an anonymous (incomplete) `SynthesizedTypedDictType`.
|
||||
pub(crate) name: Option<Name>,
|
||||
pub(crate) name: Name,
|
||||
|
||||
pub(crate) params: TypedDictParams,
|
||||
|
||||
|
|
@ -441,7 +455,7 @@ impl<'db> SynthesizedTypedDictType<'db> {
|
|||
}
|
||||
|
||||
fn heap_size(
|
||||
(name, params, items): &(Option<Name>, TypedDictParams, FxOrderMap<Name, Field<'db>>),
|
||||
(name, params, items): &(Name, TypedDictParams, FxOrderMap<Name, Field<'db>>),
|
||||
) -> usize {
|
||||
ruff_memory_usage::heap_size(name)
|
||||
+ ruff_memory_usage::heap_size(params)
|
||||
|
|
|
|||
Loading…
Reference in New Issue