@@ -881,6 +881,13 @@ impl MethodDecorator {
881881 }
882882}
883883
884+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
885+ pub ( crate ) struct DataclassField < ' db > {
886+ pub ( crate ) field_ty : Type < ' db > ,
887+ pub ( crate ) default_ty : Option < Type < ' db > > ,
888+ pub ( crate ) init_only : bool ,
889+ }
890+
884891/// Representation of a class definition statement in the AST: either a non-generic class, or a
885892/// generic class that has not been specialized.
886893///
@@ -1473,6 +1480,10 @@ impl<'db> ClassLiteral<'db> {
14731480 }
14741481 }
14751482
1483+ if lookup_result. is_ok_and ( |r| r. qualifiers . contains ( TypeQualifiers :: INIT_VAR ) ) {
1484+ return Place :: Unbound . into ( ) ;
1485+ }
1486+
14761487 match (
14771488 PlaceAndQualifiers :: from ( lookup_result) ,
14781489 dynamic_type_to_intersect_with,
@@ -1580,10 +1591,16 @@ impl<'db> ClassLiteral<'db> {
15801591
15811592 let signature_from_fields = |mut parameters : Vec < _ > | {
15821593 let mut kw_only_field_seen = false ;
1583- for ( name, ( mut attr_ty, mut default_ty) ) in
1584- self . fields ( db, specialization, field_policy)
1594+ for (
1595+ field_name,
1596+ DataclassField {
1597+ mut field_ty,
1598+ mut default_ty,
1599+ init_only : _,
1600+ } ,
1601+ ) in self . fields ( db, specialization, field_policy)
15851602 {
1586- if attr_ty
1603+ if field_ty
15871604 . into_nominal_instance ( )
15881605 . is_some_and ( |instance| instance. class . is_known ( db, KnownClass :: KwOnly ) )
15891606 {
@@ -1594,7 +1611,7 @@ impl<'db> ClassLiteral<'db> {
15941611 continue ;
15951612 }
15961613
1597- let dunder_set = attr_ty . class_member ( db, "__set__" . into ( ) ) ;
1614+ let dunder_set = field_ty . class_member ( db, "__set__" . into ( ) ) ;
15981615 if let Place :: Type ( dunder_set, Boundness :: Bound ) = dunder_set. place {
15991616 // The descriptor handling below is guarded by this not-dynamic check, because
16001617 // dynamic types like `Any` are valid (data) descriptors: since they have all
@@ -1623,7 +1640,7 @@ impl<'db> ClassLiteral<'db> {
16231640 }
16241641 }
16251642 }
1626- attr_ty = value_types. build ( ) ;
1643+ field_ty = value_types. build ( ) ;
16271644
16281645 // The default value of the attribute is *not* determined by the right hand side
16291646 // of the class-body assignment. Instead, the runtime invokes `__get__` on the
@@ -1640,11 +1657,11 @@ impl<'db> ClassLiteral<'db> {
16401657 }
16411658
16421659 let mut parameter = if kw_only_field_seen {
1643- Parameter :: keyword_only ( name )
1660+ Parameter :: keyword_only ( field_name )
16441661 } else {
1645- Parameter :: positional_or_keyword ( name )
1662+ Parameter :: positional_or_keyword ( field_name )
16461663 }
1647- . with_annotated_type ( attr_ty ) ;
1664+ . with_annotated_type ( field_ty ) ;
16481665
16491666 if let Some ( default_ty) = default_ty {
16501667 parameter = parameter. with_default_type ( default_ty) ;
@@ -1746,7 +1763,7 @@ impl<'db> ClassLiteral<'db> {
17461763 db : & ' db dyn Db ,
17471764 specialization : Option < Specialization < ' db > > ,
17481765 field_policy : CodeGeneratorKind ,
1749- ) -> FxOrderMap < Name , ( Type < ' db > , Option < Type < ' db > > ) > {
1766+ ) -> FxOrderMap < Name , DataclassField < ' db > > {
17501767 if field_policy == CodeGeneratorKind :: NamedTuple {
17511768 // NamedTuples do not allow multiple inheritance, so it is sufficient to enumerate the
17521769 // fields of this class only.
@@ -1793,7 +1810,7 @@ impl<'db> ClassLiteral<'db> {
17931810 self ,
17941811 db : & ' db dyn Db ,
17951812 specialization : Option < Specialization < ' db > > ,
1796- ) -> FxOrderMap < Name , ( Type < ' db > , Option < Type < ' db > > ) > {
1813+ ) -> FxOrderMap < Name , DataclassField < ' db > > {
17971814 let mut attributes = FxOrderMap :: default ( ) ;
17981815
17991816 let class_body_scope = self . body_scope ( db) ;
@@ -1835,11 +1852,12 @@ impl<'db> ClassLiteral<'db> {
18351852
18361853 attributes. insert (
18371854 place_expr. expect_name ( ) . clone ( ) ,
1838- (
1839- attr_ty. apply_optional_specialization ( db, specialization) ,
1840- default_ty
1855+ DataclassField {
1856+ field_ty : attr_ty. apply_optional_specialization ( db, specialization) ,
1857+ default_ty : default_ty
18411858 . map ( |ty| ty. apply_optional_specialization ( db, specialization) ) ,
1842- ) ,
1859+ init_only : attr. is_init_var ( ) ,
1860+ } ,
18431861 ) ;
18441862 }
18451863 }
@@ -1876,6 +1894,10 @@ impl<'db> ClassLiteral<'db> {
18761894 qualifiers,
18771895 } = class. own_instance_member ( db, name)
18781896 {
1897+ if qualifiers. contains ( TypeQualifiers :: INIT_VAR ) {
1898+ continue ;
1899+ }
1900+
18791901 // TODO: We could raise a diagnostic here if there are conflicting type qualifiers
18801902 union_qualifiers |= qualifiers;
18811903
@@ -2592,6 +2614,7 @@ pub enum KnownClass {
25922614 // dataclasses
25932615 Field ,
25942616 KwOnly ,
2617+ InitVar ,
25952618 // _typeshed._type_checker_internals
25962619 NamedTupleFallback ,
25972620}
@@ -2686,6 +2709,7 @@ impl KnownClass {
26862709 | Self :: Deprecated
26872710 | Self :: Field
26882711 | Self :: KwOnly
2712+ | Self :: InitVar
26892713 | Self :: NamedTupleFallback => Truthiness :: Ambiguous ,
26902714 }
26912715 }
@@ -2744,6 +2768,7 @@ impl KnownClass {
27442768 | Self :: EllipsisType
27452769 | Self :: NotImplementedType
27462770 | Self :: KwOnly
2771+ | Self :: InitVar
27472772 | Self :: VersionInfo
27482773 | Self :: Bool
27492774 | Self :: NoneType => false ,
@@ -2843,6 +2868,7 @@ impl KnownClass {
28432868 | KnownClass :: NotImplementedType
28442869 | KnownClass :: Field
28452870 | KnownClass :: KwOnly
2871+ | KnownClass :: InitVar
28462872 | KnownClass :: NamedTupleFallback => false ,
28472873 }
28482874 }
@@ -2925,6 +2951,7 @@ impl KnownClass {
29252951 | Self :: UnionType
29262952 | Self :: Field
29272953 | Self :: KwOnly
2954+ | Self :: InitVar
29282955 | Self :: NamedTupleFallback => false ,
29292956 }
29302957 }
@@ -3016,6 +3043,7 @@ impl KnownClass {
30163043 Self :: NotImplementedType => "_NotImplementedType" ,
30173044 Self :: Field => "Field" ,
30183045 Self :: KwOnly => "KW_ONLY" ,
3046+ Self :: InitVar => "InitVar" ,
30193047 Self :: NamedTupleFallback => "NamedTupleFallback" ,
30203048 }
30213049 }
@@ -3269,8 +3297,7 @@ impl KnownClass {
32693297 | Self :: DefaultDict
32703298 | Self :: Deque
32713299 | Self :: OrderedDict => KnownModule :: Collections ,
3272- Self :: Field => KnownModule :: Dataclasses ,
3273- Self :: KwOnly => KnownModule :: Dataclasses ,
3300+ Self :: Field | Self :: KwOnly | Self :: InitVar => KnownModule :: Dataclasses ,
32743301 Self :: NamedTupleFallback => KnownModule :: TypeCheckerInternals ,
32753302 }
32763303 }
@@ -3342,6 +3369,7 @@ impl KnownClass {
33423369 | Self :: NewType
33433370 | Self :: Field
33443371 | Self :: KwOnly
3372+ | Self :: InitVar
33453373 | Self :: Iterable
33463374 | Self :: Iterator
33473375 | Self :: NamedTupleFallback => false ,
@@ -3417,6 +3445,7 @@ impl KnownClass {
34173445 | Self :: NewType
34183446 | Self :: Field
34193447 | Self :: KwOnly
3448+ | Self :: InitVar
34203449 | Self :: Iterable
34213450 | Self :: Iterator
34223451 | Self :: NamedTupleFallback => false ,
@@ -3504,6 +3533,7 @@ impl KnownClass {
35043533 "_NotImplementedType" => Self :: NotImplementedType ,
35053534 "Field" => Self :: Field ,
35063535 "KW_ONLY" => Self :: KwOnly ,
3536+ "InitVar" => Self :: InitVar ,
35073537 "NamedTupleFallback" => Self :: NamedTupleFallback ,
35083538 _ => return None ,
35093539 } ;
@@ -3566,6 +3596,7 @@ impl KnownClass {
35663596 | Self :: WrapperDescriptorType
35673597 | Self :: Field
35683598 | Self :: KwOnly
3599+ | Self :: InitVar
35693600 | Self :: NamedTupleFallback => module == self . canonical_module ( db) ,
35703601 Self :: NoneType => matches ! ( module, KnownModule :: Typeshed | KnownModule :: Types ) ,
35713602 Self :: SpecialForm
0 commit comments