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;
use crate::types::signatures::{ParameterForm, walk_signature};
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};
use crate::types::variance::{TypeVarVariance, VarianceInferable};
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>> {
match self {
Type::ClassLiteral(class_literal) if class_literal.is_typed_dict(db) => Some(
TypedDictType::from_class(ClassType::NonGeneric(class_literal)),
),
Type::KnownInstance(KnownInstanceType::TypedDictType(typed_dict)) => {
Some(TypedDictType::Synthesized(typed_dict))
Some(TypedDictType::Functional(typed_dict))
}
_ => None,
}
@ -2993,7 +2993,7 @@ impl<'db> Type<'db> {
) -> PlaceAndQualifiers<'db> {
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) =
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"))
.with_annotated_type(Type::any()),
]),
Some(Type::TypedDict(TypedDictType::Synthesized(typed_dict))),
Some(Type::TypedDict(TypedDictType::Functional(typed_dict))),
)],
)
.into()
@ -5685,7 +5685,7 @@ impl<'db> Type<'db> {
.unwrap_or(*self))
}
KnownInstanceType::TypedDictType(typed_dict) => {
Ok(Type::TypedDict(TypedDictType::Synthesized(*typed_dict)))
Ok(Type::TypedDict(TypedDictType::Functional(*typed_dict)))
}
KnownInstanceType::TypedDictSchema(_) => Err(InvalidTypeExpressionError {
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::InvalidType(
@ -6543,8 +6543,9 @@ impl<'db> Type<'db> {
},
Type::TypedDict(typed_dict) => match typed_dict {
TypedDictType::FromClass(class) => Some(TypeDefinition::Class(class.definition(db))),
TypedDictType::Synthesized(_) => None,
TypedDictType::ClassBased(class) => Some(TypeDefinition::Class(class.definition(db))),
// TODO: Support go-to-definition for functional `TypedDict`s.
TypedDictType::Functional(_) => None,
}
Self::Union(_) | Self::Intersection(_) => None,
@ -6893,8 +6894,8 @@ pub enum KnownInstanceType<'db> {
/// A single instance of `typing.TypeAliasType` (PEP 695 type alias)
TypeAliasType(TypeAliasType<'db>),
/// A single instance of `typing.TypedDict`.
TypedDictType(SynthesizedTypedDictType<'db>),
/// A single class object created using the `typing.TypedDict` functional syntax
TypedDictType(FunctionalTypedDictType<'db>),
/// An internal type representing the dictionary literal argument to the functional `TypedDict`
/// constructor.
@ -6928,7 +6929,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
visitor.visit_type_alias_type(db, type_alias);
}
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::ConstraintSet(_)

View File

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

View File

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

View File

@ -512,12 +512,12 @@ impl Display for DisplayRepresentation<'_> {
}
Type::TypedDict(typed_dict) => match typed_dict {
TypedDictType::FromClass(class) => class
TypedDictType::ClassBased(class) => class
.class_literal(self.db)
.0
.display_with(self.db, self.settings.clone())
.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)),

View File

@ -51,21 +51,21 @@ impl Default for TypedDictParams {
pub enum TypedDictType<'db> {
/// A reference to the class (inheriting from `typing.TypedDict`) that specifies the
/// schema of this `TypedDict`.
FromClass(ClassType<'db>),
ClassBased(ClassType<'db>),
/// A `TypedDict` created using the functional syntax.
Synthesized(SynthesizedTypedDictType<'db>),
Functional(FunctionalTypedDictType<'db>),
}
impl<'db> TypedDictType<'db> {
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>>> {
match self {
TypedDictType::Synthesized(synthesized) => Cow::Borrowed(synthesized.items(db)),
TypedDictType::FromClass(class) => {
TypedDictType::Functional(functional) => Cow::Borrowed(functional.items(db)),
TypedDictType::ClassBased(class) => {
let (class_literal, specialization) = class.class_literal(db);
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
// understand a more specific meta type in order to correctly handle `__getitem__`.
match self {
TypedDictType::FromClass(class) => SubclassOfType::from(db, class),
TypedDictType::Synthesized(_) => KnownClass::TypedDictFallback.to_class_literal(db),
TypedDictType::ClassBased(class) => SubclassOfType::from(db, class),
TypedDictType::Functional(_) => KnownClass::TypedDictFallback.to_class_literal(db),
}
}
@ -90,11 +90,11 @@ impl<'db> TypedDictType<'db> {
) -> Self {
// TODO: Materialization of gradual TypedDicts needs more logic
match self {
TypedDictType::FromClass(class) => {
TypedDictType::FromClass(class.apply_type_mapping_impl(db, type_mapping, visitor))
TypedDictType::ClassBased(class) => {
TypedDictType::ClassBased(class.apply_type_mapping_impl(db, type_mapping, visitor))
}
TypedDictType::Synthesized(synthesized) => TypedDictType::Synthesized(
synthesized.apply_type_mapping_impl(db, type_mapping, visitor),
TypedDictType::Functional(functional) => TypedDictType::Functional(
functional.apply_type_mapping_impl(db, type_mapping, visitor),
),
}
}
@ -409,9 +409,9 @@ pub struct TypedDictSchemaField<'db> {
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)]
pub struct SynthesizedTypedDictType<'db> {
pub struct FunctionalTypedDictType<'db> {
pub(crate) name: Name,
pub(crate) params: TypedDictParams,
@ -421,9 +421,9 @@ pub struct SynthesizedTypedDictType<'db> {
}
// 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>(
self,
db: &'db dyn Db,
@ -442,7 +442,7 @@ impl<'db> SynthesizedTypedDictType<'db> {
})
.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(
@ -469,9 +469,9 @@ pub(crate) fn walk_typed_dict_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
visitor: &V,
) {
match typed_dict {
TypedDictType::FromClass(class) => visitor.visit_type(db, class.into()),
TypedDictType::Synthesized(synthesized) => {
for (_, item) in synthesized.items(db) {
TypedDictType::ClassBased(class) => visitor.visit_type(db, class.into()),
TypedDictType::Functional(functional) => {
for (_, item) in functional.items(db) {
visitor.visit_type(db, item.declared_ty);
}
}