@@ -62,13 +62,28 @@ impl<'db> Type<'db> {
6262 //
6363 // [1] https://docs.python.org/3/reference/datamodel.html#object.__radd__
6464
65- // Technically we don't have to check left_ty != right_ty here, since if the types
66- // are the same, they will trivially have the same implementation of the reflected
67- // dunder, and so we'll fail the inner check. But the type equality check will be
68- // faster for the common case, and allow us to skip the (two) class member lookups.
65+ // Reflected-method precedence is based on the operands' runtime classes, not on whether
66+ // one value type is a subtype of the other. This matters for literals: an enum literal can
67+ // have a class that is a strict subclass of `int` even though it is not a subtype of a
68+ // specific integer literal.
69+ //
70+ // Technically, the type equality check is not required for correctness: equal value types
71+ // have the same runtime class and reflected implementation. It provides a fast path for
72+ // the common case and avoids the runtime-class checks and two class member lookups below.
73+ let right_is_strict_subclass = left_ty != right_ty
74+ && match ( left_ty. nominal_class ( db) , right_ty. nominal_class ( db) ) {
75+ ( Some ( left_class) , Some ( right_class) )
76+ if !left_ty. is_type_var ( ) && !right_ty. is_type_var ( ) =>
77+ {
78+ left_class. class_literal ( db) != right_class. class_literal ( db)
79+ && right_class. is_subclass_of ( db, left_class)
80+ }
81+ _ => right_ty. is_subtype_of ( db, left_ty) ,
82+ } ;
83+
6984 let left_class = left_ty. to_meta_type ( db) ;
7085 let right_class = right_ty. to_meta_type ( db) ;
71- if left_ty != right_ty && right_ty . is_subtype_of ( db , left_ty ) {
86+ if right_is_strict_subclass {
7287 let reflected_dunder = op. reflected_dunder ( ) ;
7388 let rhs_reflected = right_class. member ( db, reflected_dunder) . place ;
7489 // TODO: if `rhs_reflected` is possibly unbound, we should union the two possible
0 commit comments