@@ -5473,11 +5473,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
54735473 items,
54745474 } = dict;
54755475
5476- // Validate `TypedDict` dictionary literal assignments.
5476+ // Infer `TypedDict` dictionary literal assignments.
54775477 if let Some ( ty) = self . infer_typed_dict_expression ( dict, tcx) {
54785478 return ty;
54795479 }
54805480
5481+ // Infer the dictionary literal passed to the `TypedDict` constructor.
5482+ if let Some ( ty) = self . infer_typed_dict_constructor_literal ( dict, tcx) {
5483+ return ty;
5484+ }
5485+
54815486 // Avoid false positives for the functional `TypedDict` form, which is currently
54825487 // unsupported.
54835488 if let Some ( Type :: Dynamic ( DynamicType :: Todo ( _) ) ) = tcx. annotation {
@@ -5603,52 +5608,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
56035608 items,
56045609 } = dict;
56055610
5606- // Evaluate the dictionary literal passed to the `TypedDict` constructor.
5607- if let Some ( Type :: SpecialForm ( SpecialFormType :: TypedDict ) ) = tcx. annotation {
5608- let mut typed_dict_items = FxOrderMap :: default ( ) ;
5609-
5610- for item in items {
5611- let Some ( Type :: StringLiteral ( key) ) =
5612- self . infer_optional_expression ( item. key . as_ref ( ) , TypeContext :: default ( ) )
5613- else {
5614- // Emit a diagnostic here? We seem to support non-string literals.
5615- unimplemented ! ( )
5616- } ;
5617-
5618- let field_ty = self . infer_typed_dict_field_type_expression ( & item. value ) ;
5619-
5620- let is_required = if field_ty. qualifiers . contains ( TypeQualifiers :: REQUIRED ) {
5621- // Explicit Required[T] annotation - always required
5622- Truthiness :: AlwaysTrue
5623- } else if field_ty. qualifiers . contains ( TypeQualifiers :: NOT_REQUIRED ) {
5624- // Explicit NotRequired[T] annotation - never required
5625- Truthiness :: AlwaysFalse
5626- } else {
5627- // No explicit qualifier - we don't have access to the `total` qualifier here,
5628- // so we leave this to be filled in by the `TypedDict` constructor.
5629- Truthiness :: Ambiguous
5630- } ;
5631-
5632- let field = Field {
5633- single_declaration : None ,
5634- declared_ty : field_ty. inner_type ( ) ,
5635- kind : FieldKind :: TypedDict {
5636- is_required,
5637- is_read_only : field_ty. qualifiers . contains ( TypeQualifiers :: READ_ONLY ) ,
5638- } ,
5639- } ;
5640-
5641- typed_dict_items. insert ( ast:: name:: Name :: new ( key. value ( self . db ( ) ) ) , field) ;
5642- }
5643-
5644- // Create an incomplete synthesized `TypedDictType`, to be completed by the `TypedDict`
5645- // constructor binding.
5646- return Some ( Type :: TypedDict ( TypedDictType :: from_items (
5647- self . db ( ) ,
5648- typed_dict_items,
5649- ) ) ) ;
5650- }
5651-
56525611 let typed_dict = tcx. annotation . and_then ( Type :: into_typed_dict) ?;
56535612 let typed_dict_items = typed_dict. items ( self . db ( ) ) ;
56545613
@@ -5672,6 +5631,64 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
56725631 . map ( |_| Type :: TypedDict ( typed_dict) )
56735632 }
56745633
5634+ // Infer the dictionary literal passed to the `TypedDict` constructor.
5635+ fn infer_typed_dict_constructor_literal (
5636+ & mut self ,
5637+ dict : & ast:: ExprDict ,
5638+ tcx : TypeContext < ' db > ,
5639+ ) -> Option < Type < ' db > > {
5640+ let ast:: ExprDict {
5641+ range : _,
5642+ node_index : _,
5643+ items,
5644+ } = dict;
5645+
5646+ let Some ( Type :: SpecialForm ( SpecialFormType :: TypedDict ) ) = tcx. annotation else {
5647+ return None ;
5648+ } ;
5649+
5650+ let mut typed_dict_items = FxOrderMap :: default ( ) ;
5651+
5652+ for item in items {
5653+ let Some ( Type :: StringLiteral ( key) ) =
5654+ self . infer_optional_expression ( item. key . as_ref ( ) , TypeContext :: default ( ) )
5655+ else {
5656+ continue ;
5657+ } ;
5658+
5659+ let field_ty = self . infer_typed_dict_field_type_expression ( & item. value ) ;
5660+
5661+ let is_required = if field_ty. qualifiers . contains ( TypeQualifiers :: REQUIRED ) {
5662+ // Explicit Required[T] annotation - always required
5663+ Truthiness :: AlwaysTrue
5664+ } else if field_ty. qualifiers . contains ( TypeQualifiers :: NOT_REQUIRED ) {
5665+ // Explicit NotRequired[T] annotation - never required
5666+ Truthiness :: AlwaysFalse
5667+ } else {
5668+ // No explicit qualifier - we don't have access to the `total` qualifier here,
5669+ // so we leave this to be filled in by the `TypedDict` constructor.
5670+ Truthiness :: Ambiguous
5671+ } ;
5672+
5673+ let field = Field {
5674+ single_declaration : None ,
5675+ declared_ty : field_ty. inner_type ( ) ,
5676+ kind : FieldKind :: TypedDict {
5677+ is_required,
5678+ is_read_only : field_ty. qualifiers . contains ( TypeQualifiers :: READ_ONLY ) ,
5679+ } ,
5680+ } ;
5681+
5682+ typed_dict_items. insert ( ast:: name:: Name :: new ( key. value ( self . db ( ) ) ) , field) ;
5683+ }
5684+
5685+ // Create an anonymous `TypedDict` from the items, to be completed by the `TypedDict` constructor binding.
5686+ Some ( Type :: TypedDict ( TypedDictType :: from_items (
5687+ self . db ( ) ,
5688+ typed_dict_items,
5689+ ) ) )
5690+ }
5691+
56755692 fn infer_typed_dict_field_type_expression (
56765693 & mut self ,
56775694 expr : & ast:: Expr ,
0 commit comments