Update isintance (#5868)

* PyUnion::get_args

* issubclass

* isinstance
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2025-06-29 15:15:09 +09:00
1 parent 4cca8b0d32
commit 7c6d0632cc
2 files changed
+33 -28

No files matched your search

+6
View File
@@ -40,6 +40,12 @@ impl PyUnion {
Self { args, parameters }
}
/// Direct access to args field, matching CPython's _Py_union_args
#[inline]
pub fn args(&self) -> &PyTupleRef {
&self.args
}
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
fn repr_item(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
if obj.is(vm.ctx.types.none_type) {
+27 -28
View File
@@ -497,30 +497,31 @@ impl PyObject {
/// via the __subclasscheck__ magic method.
/// PyObject_IsSubclass/object_issubclass
pub fn is_subclass(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
let derived = self;
// PyType_CheckExact(cls)
if cls.class().is(vm.ctx.types.type_type) {
if self.is(cls) {
if derived.is(cls) {
return Ok(true);
}
return self.recursive_issubclass(cls, vm);
return derived.recursive_issubclass(cls, vm);
}
// Check for Union type - CPython handles this before tuple
let cls_to_check = if cls.class().is(vm.ctx.types.union_type) {
let cls = if cls.class().is(vm.ctx.types.union_type) {
// Get the __args__ attribute which contains the union members
if let Ok(args) = cls.get_attr(identifier!(vm, __args__), vm) {
args
} else {
cls.to_owned()
}
// Match CPython's _Py_union_args which directly accesses the args field
let union = cls
.downcast_ref::<crate::builtins::PyUnion>()
.expect("union is already checked");
union.args().as_object()
} else {
cls.to_owned()
cls
};
// Check if cls_to_check is a tuple
if let Ok(tuple) = cls_to_check.try_to_value::<&Py<PyTuple>>(vm) {
for typ in tuple {
if vm.with_recursion("in __subclasscheck__", || self.is_subclass(typ, vm))? {
// Check if cls is a tuple
if let Some(tuple) = cls.downcast_ref::<PyTuple>() {
for item in tuple {
if vm.with_recursion("in __subclasscheck__", || derived.is_subclass(item, vm))? {
return Ok(true);
}
}
@@ -528,14 +529,14 @@ impl PyObject {
}
// Check for __subclasscheck__ method
if let Some(meth) = vm.get_special_method(cls, identifier!(vm, __subclasscheck__))? {
let ret = vm.with_recursion("in __subclasscheck__", || {
meth.invoke((self.to_owned(),), vm)
if let Some(checker) = vm.get_special_method(cls, identifier!(vm, __subclasscheck__))? {
let res = vm.with_recursion("in __subclasscheck__", || {
checker.invoke((derived.to_owned(),), vm)
})?;
return ret.try_to_bool(vm);
return res.try_to_bool(vm);
}
self.recursive_issubclass(cls, vm)
derived.recursive_issubclass(cls, vm)
}
/// Real isinstance check without going through __instancecheck__
@@ -601,16 +602,14 @@ impl PyObject {
// Check for Union type (e.g., int | str) - CPython checks this before tuple
if cls.class().is(vm.ctx.types.union_type) {
if let Ok(args) = cls.get_attr(identifier!(vm, __args__), vm) {
if let Ok(tuple) = args.try_to_ref::<PyTuple>(vm) {
for typ in tuple {
if vm
.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))?
{
return Ok(true);
}
}
return Ok(false);
// Match CPython's _Py_union_args which directly accesses the args field
let union = cls
.try_to_ref::<crate::builtins::PyUnion>(vm)
.expect("checked by is");
let tuple = union.args();
for typ in tuple.iter() {
if vm.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))? {
return Ok(true);
}
}
}