Merge pull request #3344 from ChJR/feature/relocate_is_instance

Relocate vm.isinstance to obj.is_instance
This commit is contained in:
Jim Fasarakis-Hilliard
2021-10-20 08:45:06 +03:00
committed by GitHub
4 changed files with 33 additions and 36 deletions

View File

@@ -1783,7 +1783,7 @@ impl ExecutingFrame<'_> {
bytecode::ComparisonOperator::In => vm.ctx.new_bool(self._in(vm, a, b)?).into(),
bytecode::ComparisonOperator::NotIn => vm.ctx.new_bool(self._not_in(vm, a, b)?).into(),
bytecode::ComparisonOperator::ExceptionMatch => {
vm.ctx.new_bool(vm.isinstance(&a, &b)?).into()
vm.ctx.new_bool(a.is_instance(&b, vm)?).into()
}
};

View File

@@ -2,11 +2,12 @@
//! https://docs.python.org/3/c-api/object.html
use crate::{
builtins::{pystr::IntoPyStrRef, PyBytes, PyInt, PyStrRef},
builtins::{pystr::IntoPyStrRef, PyBytes, PyInt, PyStrRef, PyTupleRef},
bytesinner::ByteInnerNewOptions,
common::{hash::PyHash, str::to_ascii},
function::OptionalArg,
protocol::PyIter,
pyobject::IdProtocol,
pyref_type_error,
types::{Constructor, PyComparisonOp},
PyObjectRef, PyResult, TryFromObject, TypeProtocol, VirtualMachine,
@@ -128,8 +129,35 @@ impl PyObjectRef {
vm.issubclass(self, cls)
}
/// Determines if `self` is an instance of `cls`, either directly, indirectly or virtually via
/// the __instancecheck__ magic method.
pub fn is_instance(&self, cls: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
vm.isinstance(self, cls)
// cpython first does an exact check on the type, although documentation doesn't state that
// https://github.com/python/cpython/blob/a24107b04c1277e3c1105f98aff5bfa3a98b33a0/Objects/abstract.c#L2408
if self.class().is(cls) {
return Ok(true);
}
if cls.class().is(&vm.ctx.types.type_type) {
return vm.abstract_isinstance(self, cls);
}
if let Ok(tuple) = PyTupleRef::try_from_object(vm, cls.clone()) {
for typ in tuple.as_slice().iter() {
if vm.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))? {
return Ok(true);
}
}
return Ok(false);
}
if let Ok(meth) = vm.get_special_method(cls.clone(), "__instancecheck__")? {
let ret =
vm.with_recursion("in __instancecheck__", || meth.invoke((self.clone(),), vm))?;
return ret.try_to_bool(vm);
}
vm.abstract_isinstance(self, cls)
}
pub fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {

View File

@@ -397,7 +397,7 @@ mod builtins {
#[pyfunction]
fn isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
vm.isinstance(&obj, &typ)
obj.is_instance(&typ, vm)
}
#[pyfunction]

View File

@@ -1013,7 +1013,7 @@ impl VirtualMachine {
})
}
fn abstract_isinstance(&self, obj: &PyObjectRef, cls: &PyObjectRef) -> PyResult<bool> {
pub fn abstract_isinstance(&self, obj: &PyObjectRef, cls: &PyObjectRef) -> PyResult<bool> {
if let Ok(typ) = PyTypeRef::try_from_object(self, cls.clone()) {
if obj.class().issubclass(typ.clone()) {
Ok(true)
@@ -1046,37 +1046,6 @@ impl VirtualMachine {
}
}
/// Determines if `obj` is an instance of `cls`, either directly, indirectly or virtually via
/// the __instancecheck__ magic method.
pub fn isinstance(&self, obj: &PyObjectRef, cls: &PyObjectRef) -> PyResult<bool> {
// cpython first does an exact check on the type, although documentation doesn't state that
// https://github.com/python/cpython/blob/a24107b04c1277e3c1105f98aff5bfa3a98b33a0/Objects/abstract.c#L2408
if obj.class().is(cls) {
return Ok(true);
}
if cls.class().is(&self.ctx.types.type_type) {
return self.abstract_isinstance(obj, cls);
}
if let Ok(tuple) = PyTupleRef::try_from_object(self, cls.clone()) {
for typ in tuple.as_slice().iter() {
if self.with_recursion("in __instancecheck__", || self.isinstance(obj, typ))? {
return Ok(true);
}
}
return Ok(false);
}
if let Ok(meth) = self.get_special_method(cls.clone(), "__instancecheck__")? {
let ret =
self.with_recursion("in __instancecheck__", || meth.invoke((obj.clone(),), self))?;
return ret.try_to_bool(self);
}
self.abstract_isinstance(obj, cls)
}
fn abstract_issubclass(&self, subclass: PyObjectRef, cls: &PyObjectRef) -> PyResult<bool> {
let mut derived = subclass;
loop {