@@ -6,7 +6,7 @@ use crate::{
66 place:: { Place , PlaceAndQualifiers , place_from_bindings, place_from_declarations} ,
77 semantic_index:: { place_table, use_def_map} ,
88 types:: {
9- ClassLiteral , DynamicType , EnumLiteralType , KnownClass , MemberLookupPolicy ,
9+ ClassBase , ClassLiteral , DynamicType , EnumLiteralType , KnownClass , MemberLookupPolicy ,
1010 StringLiteralType , Type , TypeQualifiers ,
1111 } ,
1212} ;
@@ -138,35 +138,45 @@ pub(crate) fn enum_metadata<'db>(
138138 // enum.auto
139139 Some ( KnownClass :: Auto ) => {
140140 auto_counter += 1 ;
141+
142+ // `StrEnum`s have different `auto()` behaviour to enums inheriting from `(str, Enum)`
141143 let auto_value_ty = if Type :: ClassLiteral ( class)
142144 . is_subtype_of ( db, KnownClass :: StrEnum . to_subclass_of ( db) )
143145 {
144146 Type :: StringLiteral ( StringLiteralType :: new (
145147 db,
146148 name. to_lowercase ( ) . as_str ( ) ,
147149 ) )
148- } else if Type :: ClassLiteral ( class)
149- . is_subtype_of ( db, KnownClass :: IntEnum . to_subclass_of ( db) )
150- {
151- Type :: IntLiteral ( auto_counter)
152150 } else {
153- let has_custom_mixin =
154- class. iter_mro ( db, None ) . skip ( 1 ) . any ( |base| {
155- base. into_class ( ) . is_some_and ( |class| {
156- !( class. is_object ( db)
157- || KnownClass :: Enum
158- . to_subclass_of ( db)
159- . to_class_type ( db)
160- . is_some_and ( |enum_class| {
161- class. is_subclass_of ( db, enum_class)
162- } )
163- || class. is_known ( db, KnownClass :: Enum ) )
151+ let custom_mixins: smallvec:: SmallVec < [ Option < KnownClass > ; 1 ] > =
152+ class
153+ . iter_mro ( db, None )
154+ . skip ( 1 )
155+ . filter_map ( ClassBase :: into_class)
156+ . filter ( |class| {
157+ !Type :: from ( * class) . is_subtype_of (
158+ db,
159+ KnownClass :: Enum . to_subclass_of ( db) ,
160+ )
164161 } )
165- } ) ;
166- if has_custom_mixin {
167- Type :: any ( )
168- } else {
162+ . map ( |class| class. known ( db) )
163+ . filter ( |class| {
164+ !matches ! ( class, Some ( KnownClass :: Object ) )
165+ } )
166+ . collect ( ) ;
167+
168+ // `IntEnum`s have the same `auto()` behaviour to enums inheriting from `(int, Enum)`,
169+ // and `IntEnum`s also have `int` in their MROs, so both cases are handled here.
170+ //
171+ // In general, the `auto()` behaviour for enums with non-`int` mixins is hard to predict,
172+ // so we fall back to `Any` in those cases.
173+ if matches ! (
174+ custom_mixins. as_slice( ) ,
175+ [ ] | [ Some ( KnownClass :: Int ) ]
176+ ) {
169177 Type :: IntLiteral ( auto_counter)
178+ } else {
179+ Type :: any ( )
170180 }
171181 } ;
172182 Some ( auto_value_ty)
0 commit comments