@@ -158,6 +158,15 @@ fn downcast_qualname(value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<
158158 }
159159}
160160
161+ fn is_subtype_with_mro ( a_mro : & [ PyTypeRef ] , _a : & Py < PyType > , b : & Py < PyType > ) -> bool {
162+ for item in a_mro {
163+ if item. is ( b) {
164+ return true ;
165+ }
166+ }
167+ false
168+ }
169+
161170impl PyType {
162171 pub fn new_simple_heap (
163172 name : & str ,
@@ -197,6 +206,12 @@ impl PyType {
197206 Self :: new_heap_inner ( base, bases, attrs, slots, heaptype_ext, metaclass, ctx)
198207 }
199208
209+ /// Equivalent to CPython's PyType_Check macro
210+ /// Checks if obj is an instance of type (or its subclass)
211+ pub ( crate ) fn check < ' a > ( obj : & ' a PyObject ) -> Option < & ' a Py < Self > > {
212+ obj. downcast_ref :: < Self > ( )
213+ }
214+
200215 fn resolve_mro ( bases : & [ PyRef < Self > ] ) -> Result < Vec < PyTypeRef > , String > {
201216 // Check for duplicates in bases.
202217 let mut unique_bases = HashSet :: new ( ) ;
@@ -439,10 +454,20 @@ impl PyType {
439454}
440455
441456impl Py < PyType > {
457+ pub ( crate ) fn is_subtype ( & self , other : & Py < PyType > ) -> bool {
458+ is_subtype_with_mro ( & * self . mro . read ( ) , self , other)
459+ }
460+
461+ /// Equivalent to CPython's PyType_CheckExact macro
462+ /// Checks if obj is exactly a type (not a subclass)
463+ pub fn check_exact < ' a > ( obj : & ' a PyObject , vm : & VirtualMachine ) -> Option < & ' a Py < PyType > > {
464+ obj. downcast_ref_if_exact :: < PyType > ( vm)
465+ }
466+
442467 /// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__,
443468 /// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic
444469 /// method.
445- pub fn fast_issubclass ( & self , cls : & impl Borrow < crate :: PyObject > ) -> bool {
470+ pub fn fast_issubclass ( & self , cls : & impl Borrow < PyObject > ) -> bool {
446471 self . as_object ( ) . is ( cls. borrow ( ) ) || self . mro . read ( ) . iter ( ) . any ( |c| c. is ( cls. borrow ( ) ) )
447472 }
448473
@@ -1216,8 +1241,10 @@ impl Py<PyType> {
12161241 }
12171242
12181243 #[ pymethod]
1219- fn __subclasscheck__ ( & self , subclass : PyTypeRef ) -> bool {
1220- subclass. fast_issubclass ( self )
1244+ fn __subclasscheck__ ( & self , subclass : PyObjectRef , vm : & VirtualMachine ) -> PyResult < bool > {
1245+ // Use real_is_subclass to avoid going through __subclasscheck__ recursion
1246+ // This matches CPython's type___subclasscheck___impl which calls _PyObject_RealIsSubclass
1247+ subclass. real_is_subclass ( self . as_object ( ) , vm)
12211248 }
12221249
12231250 #[ pyclassmethod]
0 commit comments