@@ -18,6 +18,7 @@ use ruff_python_stdlib::typing::as_pep_585_generic;
1818use ruff_text_size:: { Ranged , TextRange } ;
1919use rustc_hash:: { FxHashMap , FxHashSet } ;
2020use smallvec:: SmallVec ;
21+ use strum:: IntoEnumIterator ;
2122use ty_module_resolver:: { KnownModule , ModuleName , resolve_module} ;
2223
2324use super :: deferred;
@@ -100,6 +101,7 @@ use crate::types::mro::DynamicMroErrorKind;
100101use crate :: types:: newtype:: NewType ;
101102use crate :: types:: set_theoretic:: RecursivelyDefined ;
102103use crate :: types:: signatures:: CallableSignature ;
104+ use crate :: types:: special_form:: TypeQualifier ;
103105use crate :: types:: subclass_of:: SubclassOfInner ;
104106use crate :: types:: tuple:: { Tuple , TupleLength , TupleSpecBuilder , TupleType } ;
105107use crate :: types:: type_alias:: { ManualPEP695TypeAliasType , PEP695TypeAliasType } ;
@@ -3864,8 +3866,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
38643866 ) ;
38653867
38663868 if !annotated. qualifiers . is_empty ( ) {
3867- for qualifier in [ TypeQualifiers :: CLASS_VAR , TypeQualifiers :: INIT_VAR ] {
3868- if annotated. qualifiers . contains ( qualifier)
3869+ for qualifier in TypeQualifier :: iter ( ) {
3870+ if !qualifier. is_valid_for_non_name_targets ( )
3871+ && annotated
3872+ . qualifiers
3873+ . contains ( TypeQualifiers :: from ( qualifier) )
38693874 && let Some ( builder) = self
38703875 . context
38713876 . report_lint ( & INVALID_TYPE_FORM , annotation. as_ref ( ) )
@@ -4141,45 +4146,117 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
41414146 }
41424147
41434148 if !declared. qualifiers . is_empty ( ) {
4144- let current_scope_id = self . scope ( ) . file_scope_id ( self . db ( ) ) ;
4145- let current_scope = self . index . scope ( current_scope_id) ;
4146- if current_scope. kind ( ) != ScopeKind :: Class {
4147- for qualifier in [ TypeQualifiers :: CLASS_VAR , TypeQualifiers :: INIT_VAR ] {
4148- if declared. qualifiers . contains ( qualifier)
4149- && let Some ( builder) =
4150- self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4151- {
4152- builder. into_diagnostic ( format_args ! (
4153- "`{name}` annotations are only allowed in class-body scopes" ,
4154- name = qualifier. name( )
4155- ) ) ;
4149+ for qualifier in TypeQualifier :: iter ( ) {
4150+ if !declared
4151+ . qualifiers
4152+ . contains ( TypeQualifiers :: from ( qualifier) )
4153+ {
4154+ continue ;
4155+ }
4156+ let current_scope_id = self . scope ( ) . file_scope_id ( self . db ( ) ) ;
4157+
4158+ if self . index . scope ( current_scope_id) . kind ( ) != ScopeKind :: Class {
4159+ match qualifier {
4160+ TypeQualifier :: Final => { }
4161+ TypeQualifier :: ClassVar => {
4162+ if let Some ( builder) =
4163+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4164+ {
4165+ builder
4166+ . into_diagnostic ( "`ClassVar` is only allowed in class bodies" ) ;
4167+ }
4168+ }
4169+ TypeQualifier :: InitVar => {
4170+ if let Some ( builder) =
4171+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4172+ {
4173+ builder. into_diagnostic (
4174+ "`InitVar` is only allowed in dataclass fields" ,
4175+ ) ;
4176+ }
4177+ }
4178+ TypeQualifier :: NotRequired
4179+ | TypeQualifier :: ReadOnly
4180+ | TypeQualifier :: Required => {
4181+ if let Some ( builder) =
4182+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4183+ {
4184+ builder. into_diagnostic ( format_args ! (
4185+ "`{name}` is only allowed in TypedDict fields" ,
4186+ name = qualifier. name( )
4187+ ) ) ;
4188+ }
4189+ }
41564190 }
4191+
4192+ continue ;
41574193 }
4158- }
41594194
4160- // `Required`, `NotRequired`, and `ReadOnly` are only valid inside TypedDict classes.
4161- if declared. qualifiers . intersects (
4162- TypeQualifiers :: REQUIRED | TypeQualifiers :: NOT_REQUIRED | TypeQualifiers :: READ_ONLY ,
4163- ) {
4164- let in_typed_dict = current_scope. kind ( ) == ScopeKind :: Class
4165- && nearest_enclosing_class ( self . db ( ) , self . index , self . scope ( ) )
4166- . is_some_and ( |class| class. is_typed_dict ( self . db ( ) ) ) ;
4167- if !in_typed_dict {
4168- for qualifier in [
4169- TypeQualifiers :: REQUIRED ,
4170- TypeQualifiers :: NOT_REQUIRED ,
4171- TypeQualifiers :: READ_ONLY ,
4172- ] {
4173- if declared. qualifiers . contains ( qualifier)
4174- && let Some ( builder) =
4195+ let nearest_enclosing_class =
4196+ nearest_enclosing_class ( self . db ( ) , self . index , self . scope ( ) ) ;
4197+ let class_kind = nearest_enclosing_class. and_then ( |class| {
4198+ CodeGeneratorKind :: from_class ( self . db ( ) , ClassLiteral :: Static ( class) , None )
4199+ } ) ;
4200+
4201+ match class_kind {
4202+ Some ( CodeGeneratorKind :: TypedDict ) => match qualifier {
4203+ TypeQualifier :: ClassVar | TypeQualifier :: Final | TypeQualifier :: InitVar => {
4204+ let Some ( builder) =
41754205 self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4176- {
4206+ else {
4207+ continue ;
4208+ } ;
4209+ builder. into_diagnostic ( format_args ! (
4210+ "`{name}` is not allowed in TypedDict fields" ,
4211+ name = qualifier. name( )
4212+ ) ) ;
4213+ }
4214+ TypeQualifier :: NotRequired
4215+ | TypeQualifier :: ReadOnly
4216+ | TypeQualifier :: Required => { }
4217+ } ,
4218+ Some ( CodeGeneratorKind :: DataclassLike ( _) ) => match qualifier {
4219+ TypeQualifier :: NotRequired
4220+ | TypeQualifier :: ReadOnly
4221+ | TypeQualifier :: Required => {
4222+ let Some ( builder) =
4223+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4224+ else {
4225+ continue ;
4226+ } ;
4227+ builder. into_diagnostic ( format_args ! (
4228+ "`{name}` is not allowed in dataclass fields" ,
4229+ name = qualifier. name( )
4230+ ) ) ;
4231+ }
4232+ TypeQualifier :: ClassVar | TypeQualifier :: Final | TypeQualifier :: InitVar => {
4233+ }
4234+ } ,
4235+ Some ( CodeGeneratorKind :: NamedTuple ) | None => match qualifier {
4236+ TypeQualifier :: NotRequired
4237+ | TypeQualifier :: Required
4238+ | TypeQualifier :: ReadOnly => {
4239+ let Some ( builder) =
4240+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4241+ else {
4242+ continue ;
4243+ } ;
41774244 builder. into_diagnostic ( format_args ! (
41784245 "`{name}` is only allowed in TypedDict fields" ,
41794246 name = qualifier. name( )
41804247 ) ) ;
41814248 }
4182- }
4249+ TypeQualifier :: InitVar => {
4250+ let Some ( builder) =
4251+ self . context . report_lint ( & INVALID_TYPE_FORM , annotation)
4252+ else {
4253+ continue ;
4254+ } ;
4255+ builder
4256+ . into_diagnostic ( "`InitVar` is only allowed in dataclass fields" ) ;
4257+ }
4258+ TypeQualifier :: ClassVar | TypeQualifier :: Final => { }
4259+ } ,
41834260 }
41844261 }
41854262 }
0 commit comments