@@ -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} ;
@@ -68,9 +68,6 @@ pub(crate) fn enum_metadata<'db>(
6868 return None ;
6969 }
7070
71- let is_str_enum =
72- Type :: ClassLiteral ( class) . is_subtype_of ( db, KnownClass :: StrEnum . to_subclass_of ( db) ) ;
73-
7471 let scope_id = class. body_scope ( db) ;
7572 let use_def_map = use_def_map ( db, scope_id) ;
7673 let table = place_table ( db, scope_id) ;
@@ -141,14 +138,48 @@ pub(crate) fn enum_metadata<'db>(
141138 // enum.auto
142139 Some ( KnownClass :: Auto ) => {
143140 auto_counter += 1 ;
144- Some ( if is_str_enum {
141+
142+ // `StrEnum`s have different `auto()` behaviour to enums inheriting from `(str, Enum)`
143+ let auto_value_ty = if Type :: ClassLiteral ( class)
144+ . is_subtype_of ( db, KnownClass :: StrEnum . to_subclass_of ( db) )
145+ {
145146 Type :: StringLiteral ( StringLiteralType :: new (
146147 db,
147148 name. to_lowercase ( ) . as_str ( ) ,
148149 ) )
149150 } else {
150- Type :: IntLiteral ( auto_counter)
151- } )
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+ )
161+ } )
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+ ) {
177+ Type :: IntLiteral ( auto_counter)
178+ } else {
179+ Type :: any ( )
180+ }
181+ } ;
182+ Some ( auto_value_ty)
152183 }
153184
154185 _ => None ,
0 commit comments