Skip to content

Commit 5efda1b

Browse files
committed
compatibility utility
1 parent 2a1a48a commit 5efda1b

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

vm/src/builtins/type.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
161170
impl 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

441456
impl 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]

vm/src/builtins/union.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ impl PyUnion {
4040
Self { args, parameters }
4141
}
4242

43+
/// Direct access to args field, matching CPython's _Py_union_args
44+
pub(crate) fn get_args(&self) -> &PyTupleRef {
45+
&self.args
46+
}
47+
4348
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
4449
fn repr_item(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
4550
if obj.is(vm.ctx.types.none_type) {

0 commit comments

Comments
 (0)