From b1a070acc2468a9a66cb69c026e1d80f85e9ca5d Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 4 Mar 2019 19:55:58 +1300 Subject: [PATCH] Only use real isinstance/issubclass for builtins and move the real versions to the vm. --- vm/src/builtins.rs | 6 +++--- vm/src/macros.rs | 2 +- vm/src/obj/objsuper.rs | 4 +--- vm/src/obj/objtype.rs | 30 ------------------------------ vm/src/pyobject.rs | 10 ++-------- vm/src/vm.rs | 20 ++++++++++++++++++++ 6 files changed, 27 insertions(+), 45 deletions(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 0e48315e98..e7a3bbb448 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -347,7 +347,7 @@ fn builtin_isinstance(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(obj, None), (typ, Some(vm.get_type()))] ); - let isinstance = objtype::real_isinstance(vm, obj, typ)?; + let isinstance = vm.isinstance(obj, typ)?; Ok(vm.new_bool(isinstance)) } @@ -358,7 +358,7 @@ fn builtin_issubclass(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(subclass, Some(vm.get_type())), (cls, Some(vm.get_type()))] ); - let issubclass = objtype::real_issubclass(vm, subclass, cls)?; + let issubclass = vm.issubclass(subclass, cls)?; Ok(vm.context().new_bool(issubclass)) } @@ -814,7 +814,7 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> Py let mut metaclass = args.get_kwarg("metaclass", vm.get_type()); for base in bases.clone() { - if objtype::real_issubclass(vm, &base.typ(), &metaclass)? { + if objtype::issubclass(&base.typ(), &metaclass) { metaclass = base.typ(); } else if !objtype::issubclass(&metaclass, &base.typ()) { return Err(vm.new_type_error("metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases".to_string())); diff --git a/vm/src/macros.rs b/vm/src/macros.rs index f228b6a7fb..f91cd7c614 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -19,7 +19,7 @@ macro_rules! type_check { if let Some(expected_type) = $arg_type { let arg = &$args.args[$arg_count]; - if !$crate::obj::objtype::real_isinstance($vm, arg, &expected_type)? { + if !$crate::obj::objtype::isinstance(arg, &expected_type) { let arg_typ = arg.typ(); let expected_type_name = $vm.to_pystr(&expected_type)?; let actual_type = $vm.to_pystr(&arg_typ)?; diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index b3d2184300..79c516d4c0 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -72,9 +72,7 @@ fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; // Check obj type: - if !(objtype::real_isinstance(vm, &py_obj, &py_type)? - || objtype::real_issubclass(vm, &py_obj, &py_type)?) - { + if !(objtype::isinstance(&py_obj, &py_type) || objtype::issubclass(&py_obj, &py_type)) { return Err(vm.new_type_error( "super(type, obj): obj must be an instance or subtype of type".to_string(), )); diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 785ca1b87b..c800b7f522 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -1,4 +1,3 @@ -use super::objbool; use super::objdict; use super::objstr; use super::objtype; // Required for arg_check! to use isinstance @@ -9,7 +8,6 @@ use crate::pyobject::{ use crate::vm::VirtualMachine; use std::cell::RefCell; use std::collections::HashMap; -use std::rc::Rc; /* * The magical type type @@ -108,23 +106,6 @@ pub fn isinstance(obj: &PyObjectRef, cls: &PyObjectRef) -> bool { mro.into_iter().any(|c| c.is(&cls)) } -/// Determines if `obj` is an instance of `cls`, either directly, indirectly or virtually via the -/// __instancecheck__ magic method. -pub fn real_isinstance( - vm: &mut VirtualMachine, - obj: &PyObjectRef, - cls: &PyObjectRef, -) -> PyResult { - // 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 Rc::ptr_eq(&obj.typ(), cls) { - Ok(true) - } else { - let ret = vm.call_method(cls, "__instancecheck__", vec![obj.clone()])?; - objbool::boolval(vm, ret) - } -} - fn type_instance_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -142,17 +123,6 @@ pub fn issubclass(subclass: &PyObjectRef, cls: &PyObjectRef) -> bool { mro.into_iter().any(|c| c.is(&cls)) } -/// Determines if `subclass` is a subclass of `cls`, either directly, indirectly or virtually via -/// the __subclasscheck__ magic method. -pub fn real_issubclass( - vm: &mut VirtualMachine, - subclass: &PyObjectRef, - cls: &PyObjectRef, -) -> PyResult { - let ret = vm.call_method(cls, "__subclasscheck__", vec![subclass.clone()])?; - objbool::boolval(vm, ret) -} - fn type_subclass_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index c39aa71ae6..e3900627fc 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -922,7 +922,7 @@ impl PyFuncArgs { ) -> Result, PyObjectRef> { match self.get_optional_kwarg(key) { Some(kwarg) => { - if objtype::real_isinstance(vm, &kwarg, &ty)? { + if objtype::isinstance(&kwarg, &ty) { Ok(Some(kwarg)) } else { let expected_ty_name = vm.to_pystr(&ty)?; @@ -1003,13 +1003,7 @@ where Ok(value) => Some(T::try_from_object(self.vm, value)), Err(err) => { let stop_ex = self.vm.ctx.exceptions.stop_iteration.clone(); - let stop = match objtype::real_isinstance(self.vm, &err, &stop_ex) { - Ok(stop) => stop, - Err(e) => { - return Some(Err(e)); - } - }; - if stop { + if objtype::isinstance(&err, &stop_ex) { None } else { Some(Err(err)) diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 9d91abf9e9..c4b6c14ce8 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -242,6 +242,26 @@ impl VirtualMachine { self.call_method(obj, "__repr__", vec![]) } + /// Determines if `obj` is an instance of `cls`, either directly, indirectly or virtually via + /// the __instancecheck__ magic method. + pub fn isinstance(&mut self, obj: &PyObjectRef, cls: &PyObjectRef) -> PyResult { + // 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 Rc::ptr_eq(&obj.typ(), cls) { + Ok(true) + } else { + let ret = self.call_method(cls, "__instancecheck__", vec![obj.clone()])?; + objbool::boolval(self, ret) + } + } + + /// Determines if `subclass` is a subclass of `cls`, either directly, indirectly or virtually + /// via the __subclasscheck__ magic method. + pub fn issubclass(&mut self, subclass: &PyObjectRef, cls: &PyObjectRef) -> PyResult { + let ret = self.call_method(cls, "__subclasscheck__", vec![subclass.clone()])?; + objbool::boolval(self, ret) + } + pub fn call_get_descriptor(&mut self, attr: PyObjectRef, obj: PyObjectRef) -> PyResult { let attr_class = attr.typ(); if let Some(descriptor) = attr_class.get_attr("__get__") {