@@ -462,26 +462,26 @@ impl PyObject {
462
462
}
463
463
464
464
fn recursive_issubclass ( & self , cls : & PyObject , vm : & VirtualMachine ) -> PyResult < bool > {
465
- if let ( Ok ( obj) , Ok ( cls) ) = ( self . try_to_ref :: < PyType > ( vm) , cls. try_to_ref :: < PyType > ( vm) ) {
466
- Ok ( obj. fast_issubclass ( cls) )
467
- } else {
468
- // Check if derived is a class
469
- self . check_class ( vm, || {
470
- format ! ( "issubclass() arg 1 must be a class, not {}" , self . class( ) )
471
- } ) ?;
472
-
473
- // Check if cls is a class, tuple, or union
474
- if !cls. class ( ) . is ( vm. ctx . types . union_type ) {
475
- cls. check_class ( vm, || {
476
- format ! (
477
- "issubclass() arg 2 must be a class, a tuple of classes, or a union, not {}" ,
478
- cls. class( )
479
- )
480
- } ) ?;
481
- }
465
+ // Fast path for both being types (matches CPython's PyType_Check)
466
+ if let Some ( cls) = PyType :: check ( cls)
467
+ && let Some ( derived) = PyType :: check ( self )
468
+ {
469
+ // PyType_IsSubtype equivalent
470
+ return Ok ( derived. is_subtype ( cls) ) ;
471
+ }
472
+ // Check if derived is a class
473
+ self . check_class ( vm, || {
474
+ format ! ( "issubclass() arg 1 must be a class, not {}" , self . class( ) )
475
+ } ) ?;
482
476
483
- self . abstract_issubclass ( cls, vm)
477
+ // Check if cls is a class, tuple, or union (matches CPython's order and message)
478
+ if !cls. class ( ) . is ( vm. ctx . types . union_type ) {
479
+ cls. check_class ( vm, || {
480
+ "issubclass() arg 2 must be a class, a tuple of classes, or a union" . to_string ( )
481
+ } ) ?;
484
482
}
483
+
484
+ self . abstract_issubclass ( cls, vm)
485
485
}
486
486
487
487
/// Real issubclass check without going through __subclasscheck__
0 commit comments