This commit is contained in:
Ibraheem Ahmed 2025-10-07 20:05:42 -04:00
parent 26c25bec82
commit b22cc1aa2b
5 changed files with 36 additions and 35 deletions

View File

@ -66,7 +66,7 @@ use crate::types::mro::{Mro, MroError, MroIterator};
pub(crate) use crate::types::narrow::infer_narrowing_constraint; pub(crate) use crate::types::narrow::infer_narrowing_constraint;
use crate::types::signatures::{ParameterForm, walk_signature}; use crate::types::signatures::{ParameterForm, walk_signature};
use crate::types::tuple::TupleSpec; use crate::types::tuple::TupleSpec;
use crate::types::typed_dict::{SynthesizedTypedDictType, TypedDictSchema}; use crate::types::typed_dict::{FunctionalTypedDictType, TypedDictSchema};
pub(crate) use crate::types::typed_dict::{TypedDictParams, TypedDictType, walk_typed_dict_type}; pub(crate) use crate::types::typed_dict::{TypedDictParams, TypedDictType, walk_typed_dict_type};
use crate::types::variance::{TypeVarVariance, VarianceInferable}; use crate::types::variance::{TypeVarVariance, VarianceInferable};
use crate::types::visitor::any_over_type; use crate::types::visitor::any_over_type;
@ -1010,14 +1010,14 @@ impl<'db> Type<'db> {
} }
} }
/// Turn a typed dict class literal or synthesized type dict type into a `TypedDictType`. /// Turn a typed dict class literal or functional type dict type into a `TypedDictType`.
pub(crate) fn to_typed_dict_type(self, db: &'db dyn Db) -> Option<TypedDictType<'db>> { pub(crate) fn to_typed_dict_type(self, db: &'db dyn Db) -> Option<TypedDictType<'db>> {
match self { match self {
Type::ClassLiteral(class_literal) if class_literal.is_typed_dict(db) => Some( Type::ClassLiteral(class_literal) if class_literal.is_typed_dict(db) => Some(
TypedDictType::from_class(ClassType::NonGeneric(class_literal)), TypedDictType::from_class(ClassType::NonGeneric(class_literal)),
), ),
Type::KnownInstance(KnownInstanceType::TypedDictType(typed_dict)) => { Type::KnownInstance(KnownInstanceType::TypedDictType(typed_dict)) => {
Some(TypedDictType::Synthesized(typed_dict)) Some(TypedDictType::Functional(typed_dict))
} }
_ => None, _ => None,
} }
@ -2993,7 +2993,7 @@ impl<'db> Type<'db> {
) -> PlaceAndQualifiers<'db> { ) -> PlaceAndQualifiers<'db> {
tracing::trace!("class_member: {}.{}", self.display(db), name); tracing::trace!("class_member: {}.{}", self.display(db), name);
if let Type::TypedDict(TypedDictType::Synthesized(typed_dict)) = self if let Type::TypedDict(TypedDictType::Functional(typed_dict)) = self
&& let Some(member) = && let Some(member) =
TypedDictType::synthesized_member(db, self, typed_dict.items(db), &name) TypedDictType::synthesized_member(db, self, typed_dict.items(db), &name)
{ {
@ -4875,7 +4875,7 @@ impl<'db> Type<'db> {
Parameter::keyword_variadic(Name::new_static("kwargs")) Parameter::keyword_variadic(Name::new_static("kwargs"))
.with_annotated_type(Type::any()), .with_annotated_type(Type::any()),
]), ]),
Some(Type::TypedDict(TypedDictType::Synthesized(typed_dict))), Some(Type::TypedDict(TypedDictType::Functional(typed_dict))),
)], )],
) )
.into() .into()
@ -5685,7 +5685,7 @@ impl<'db> Type<'db> {
.unwrap_or(*self)) .unwrap_or(*self))
} }
KnownInstanceType::TypedDictType(typed_dict) => { KnownInstanceType::TypedDictType(typed_dict) => {
Ok(Type::TypedDict(TypedDictType::Synthesized(*typed_dict))) Ok(Type::TypedDict(TypedDictType::Functional(*typed_dict)))
} }
KnownInstanceType::TypedDictSchema(_) => Err(InvalidTypeExpressionError { KnownInstanceType::TypedDictSchema(_) => Err(InvalidTypeExpressionError {
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::InvalidType( invalid_expressions: smallvec::smallvec![InvalidTypeExpression::InvalidType(
@ -6543,8 +6543,9 @@ impl<'db> Type<'db> {
}, },
Type::TypedDict(typed_dict) => match typed_dict { Type::TypedDict(typed_dict) => match typed_dict {
TypedDictType::FromClass(class) => Some(TypeDefinition::Class(class.definition(db))), TypedDictType::ClassBased(class) => Some(TypeDefinition::Class(class.definition(db))),
TypedDictType::Synthesized(_) => None, // TODO: Support go-to-definition for functional `TypedDict`s.
TypedDictType::Functional(_) => None,
} }
Self::Union(_) | Self::Intersection(_) => None, Self::Union(_) | Self::Intersection(_) => None,
@ -6893,8 +6894,8 @@ pub enum KnownInstanceType<'db> {
/// A single instance of `typing.TypeAliasType` (PEP 695 type alias) /// A single instance of `typing.TypeAliasType` (PEP 695 type alias)
TypeAliasType(TypeAliasType<'db>), TypeAliasType(TypeAliasType<'db>),
/// A single instance of `typing.TypedDict`. /// A single class object created using the `typing.TypedDict` functional syntax
TypedDictType(SynthesizedTypedDictType<'db>), TypedDictType(FunctionalTypedDictType<'db>),
/// An internal type representing the dictionary literal argument to the functional `TypedDict` /// An internal type representing the dictionary literal argument to the functional `TypedDict`
/// constructor. /// constructor.
@ -6928,7 +6929,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
visitor.visit_type_alias_type(db, type_alias); visitor.visit_type_alias_type(db, type_alias);
} }
KnownInstanceType::TypedDictType(typed_dict) => { KnownInstanceType::TypedDictType(typed_dict) => {
visitor.visit_typed_dict_type(db, TypedDictType::Synthesized(typed_dict)); visitor.visit_typed_dict_type(db, TypedDictType::Functional(typed_dict));
} }
KnownInstanceType::Deprecated(_) KnownInstanceType::Deprecated(_)
| KnownInstanceType::ConstraintSet(_) | KnownInstanceType::ConstraintSet(_)

View File

@ -29,7 +29,7 @@ use crate::types::function::{
use crate::types::generics::{Specialization, SpecializationBuilder, SpecializationError}; use crate::types::generics::{Specialization, SpecializationBuilder, SpecializationError};
use crate::types::signatures::{Parameter, ParameterForm, ParameterKind, Parameters}; use crate::types::signatures::{Parameter, ParameterForm, ParameterKind, Parameters};
use crate::types::tuple::{TupleLength, TupleType}; use crate::types::tuple::{TupleLength, TupleType};
use crate::types::typed_dict::SynthesizedTypedDictType; use crate::types::typed_dict::FunctionalTypedDictType;
use crate::types::{ use crate::types::{
BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownBoundMethodType, BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownBoundMethodType,
KnownClass, KnownInstanceType, MemberLookupPolicy, PropertyInstanceType, SpecialFormType, KnownClass, KnownInstanceType, MemberLookupPolicy, PropertyInstanceType, SpecialFormType,
@ -1137,7 +1137,7 @@ impl<'db> Bindings<'db> {
.collect::<FxOrderMap<_, _>>(); .collect::<FxOrderMap<_, _>>();
overload.set_return_type(Type::KnownInstance( overload.set_return_type(Type::KnownInstance(
KnownInstanceType::TypedDictType(SynthesizedTypedDictType::new( KnownInstanceType::TypedDictType(FunctionalTypedDictType::new(
db, db,
Name::new(name.value(db)), Name::new(name.value(db)),
params, params,

View File

@ -173,7 +173,7 @@ impl<'db> ClassBase<'db> {
| KnownInstanceType::Deprecated(_) | KnownInstanceType::Deprecated(_)
| KnownInstanceType::Field(_) | KnownInstanceType::Field(_)
| KnownInstanceType::ConstraintSet(_) => None, | KnownInstanceType::ConstraintSet(_) => None,
// TODO: Inherit the fields of synthesized `TypedDict`s. // TODO: Inherit the fields of functional `TypedDict`s.
KnownInstanceType::TypedDictType(_) => Some(Self::TypedDict), KnownInstanceType::TypedDictType(_) => Some(Self::TypedDict),
}, },

View File

@ -512,12 +512,12 @@ impl Display for DisplayRepresentation<'_> {
} }
Type::TypedDict(typed_dict) => match typed_dict { Type::TypedDict(typed_dict) => match typed_dict {
TypedDictType::FromClass(class) => class TypedDictType::ClassBased(class) => class
.class_literal(self.db) .class_literal(self.db)
.0 .0
.display_with(self.db, self.settings.clone()) .display_with(self.db, self.settings.clone())
.fmt(f), .fmt(f),
TypedDictType::Synthesized(synthesized) => synthesized.name(self.db).fmt(f), TypedDictType::Functional(synthesized) => synthesized.name(self.db).fmt(f),
}, },
Type::TypeAlias(alias) => f.write_str(alias.name(self.db)), Type::TypeAlias(alias) => f.write_str(alias.name(self.db)),

View File

@ -51,21 +51,21 @@ impl Default for TypedDictParams {
pub enum TypedDictType<'db> { pub enum TypedDictType<'db> {
/// A reference to the class (inheriting from `typing.TypedDict`) that specifies the /// A reference to the class (inheriting from `typing.TypedDict`) that specifies the
/// schema of this `TypedDict`. /// schema of this `TypedDict`.
FromClass(ClassType<'db>), ClassBased(ClassType<'db>),
/// A `TypedDict` created using the functional syntax. /// A `TypedDict` created using the functional syntax.
Synthesized(SynthesizedTypedDictType<'db>), Functional(FunctionalTypedDictType<'db>),
} }
impl<'db> TypedDictType<'db> { impl<'db> TypedDictType<'db> {
pub(crate) fn from_class(class: ClassType<'db>) -> Self { pub(crate) fn from_class(class: ClassType<'db>) -> Self {
TypedDictType::FromClass(class) TypedDictType::ClassBased(class)
} }
pub(crate) fn items(&self, db: &'db dyn Db) -> Cow<'db, FxOrderMap<Name, Field<'db>>> { pub(crate) fn items(&self, db: &'db dyn Db) -> Cow<'db, FxOrderMap<Name, Field<'db>>> {
match self { match self {
TypedDictType::Synthesized(synthesized) => Cow::Borrowed(synthesized.items(db)), TypedDictType::Functional(functional) => Cow::Borrowed(functional.items(db)),
TypedDictType::FromClass(class) => { TypedDictType::ClassBased(class) => {
let (class_literal, specialization) = class.class_literal(db); let (class_literal, specialization) = class.class_literal(db);
Cow::Owned(class_literal.fields(db, specialization, CodeGeneratorKind::TypedDict)) Cow::Owned(class_literal.fields(db, specialization, CodeGeneratorKind::TypedDict))
} }
@ -77,8 +77,8 @@ impl<'db> TypedDictType<'db> {
// `TypedDict` instances are instances of `dict` at runtime, but its important that we // `TypedDict` instances are instances of `dict` at runtime, but its important that we
// understand a more specific meta type in order to correctly handle `__getitem__`. // understand a more specific meta type in order to correctly handle `__getitem__`.
match self { match self {
TypedDictType::FromClass(class) => SubclassOfType::from(db, class), TypedDictType::ClassBased(class) => SubclassOfType::from(db, class),
TypedDictType::Synthesized(_) => KnownClass::TypedDictFallback.to_class_literal(db), TypedDictType::Functional(_) => KnownClass::TypedDictFallback.to_class_literal(db),
} }
} }
@ -90,11 +90,11 @@ impl<'db> TypedDictType<'db> {
) -> Self { ) -> Self {
// TODO: Materialization of gradual TypedDicts needs more logic // TODO: Materialization of gradual TypedDicts needs more logic
match self { match self {
TypedDictType::FromClass(class) => { TypedDictType::ClassBased(class) => {
TypedDictType::FromClass(class.apply_type_mapping_impl(db, type_mapping, visitor)) TypedDictType::ClassBased(class.apply_type_mapping_impl(db, type_mapping, visitor))
} }
TypedDictType::Synthesized(synthesized) => TypedDictType::Synthesized( TypedDictType::Functional(functional) => TypedDictType::Functional(
synthesized.apply_type_mapping_impl(db, type_mapping, visitor), functional.apply_type_mapping_impl(db, type_mapping, visitor),
), ),
} }
} }
@ -409,9 +409,9 @@ pub struct TypedDictSchemaField<'db> {
pub(crate) is_read_only: bool, pub(crate) is_read_only: bool,
} }
#[salsa::interned(debug, heap_size=SynthesizedTypedDictType::heap_size)] #[salsa::interned(debug, heap_size=FunctionalTypedDictType::heap_size)]
#[derive(PartialOrd, Ord)] #[derive(PartialOrd, Ord)]
pub struct SynthesizedTypedDictType<'db> { pub struct FunctionalTypedDictType<'db> {
pub(crate) name: Name, pub(crate) name: Name,
pub(crate) params: TypedDictParams, pub(crate) params: TypedDictParams,
@ -421,9 +421,9 @@ pub struct SynthesizedTypedDictType<'db> {
} }
// The Salsa heap is tracked separately. // The Salsa heap is tracked separately.
impl get_size2::GetSize for SynthesizedTypedDictType<'_> {} impl get_size2::GetSize for FunctionalTypedDictType<'_> {}
impl<'db> SynthesizedTypedDictType<'db> { impl<'db> FunctionalTypedDictType<'db> {
pub(super) fn apply_type_mapping_impl<'a>( pub(super) fn apply_type_mapping_impl<'a>(
self, self,
db: &'db dyn Db, db: &'db dyn Db,
@ -442,7 +442,7 @@ impl<'db> SynthesizedTypedDictType<'db> {
}) })
.collect::<FxOrderMap<_, _>>(); .collect::<FxOrderMap<_, _>>();
SynthesizedTypedDictType::new(db, self.name(db), self.params(db), items) FunctionalTypedDictType::new(db, self.name(db), self.params(db), items)
} }
pub(crate) fn normalized_impl( pub(crate) fn normalized_impl(
@ -469,9 +469,9 @@ pub(crate) fn walk_typed_dict_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
visitor: &V, visitor: &V,
) { ) {
match typed_dict { match typed_dict {
TypedDictType::FromClass(class) => visitor.visit_type(db, class.into()), TypedDictType::ClassBased(class) => visitor.visit_type(db, class.into()),
TypedDictType::Synthesized(synthesized) => { TypedDictType::Functional(functional) => {
for (_, item) in synthesized.items(db) { for (_, item) in functional.items(db) {
visitor.visit_type(db, item.declared_ty); visitor.visit_type(db, item.declared_ty);
} }
} }