diff --git a/src/shell/helper.rs b/src/shell/helper.rs index f6ec941ea8..83d72907bd 100644 --- a/src/shell/helper.rs +++ b/src/shell/helper.rs @@ -2,7 +2,7 @@ use rustpython_vm::{ builtins::{PyDictRef, PyStrRef}, function::ArgIterable, - identifier, PyResult, TryFromObject, VirtualMachine, + identifier, AsObject, PyResult, TryFromObject, VirtualMachine, }; pub struct ShellHelper<'vm> { @@ -82,19 +82,17 @@ impl<'vm> ShellHelper<'vm> { current = current.get_attr(&attr, self.vm).ok()?; } - let current_iter = str_iter_method(current, identifier!(self.vm, __dir__)).ok()?; + let current_iter = str_iter_method(¤t, identifier!(self.vm, __dir__)).ok()?; (last, current_iter, None) } else { // we need to get a variable based off of globals/builtins let globals = - str_iter_method(self.globals.clone().into(), identifier!(self.vm, keys)).ok()?; - let builtins = str_iter_method( - self.vm.builtins.clone().into(), - identifier!(self.vm, __dir__), - ) - .ok()?; + str_iter_method(self.globals.as_object(), identifier!(self.vm, keys)).ok()?; + let builtins = + str_iter_method(self.vm.builtins.as_object(), identifier!(self.vm, __dir__)) + .ok()?; (first, globals, Some(builtins)) }; Some((word_start, iter1.chain(iter2.into_iter().flatten()))) diff --git a/vm/src/builtins/builtin_func.rs b/vm/src/builtins/builtin_func.rs index 96c97f8aa7..47479fd344 100644 --- a/vm/src/builtins/builtin_func.rs +++ b/vm/src/builtins/builtin_func.rs @@ -194,14 +194,14 @@ impl GetDescriptor for PyBuiltinMethod { cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, obj) = match Self::_check(zelf, obj, vm) { - Ok(obj) => obj, - Err(result) => return result, + let (_zelf, obj) = match Self::_check(&zelf, obj, vm) { + Some(obj) => obj, + None => return Ok(zelf), }; let r = if vm.is_none(&obj) && !Self::_cls_is(&cls, obj.class()) { - zelf.into() + zelf } else { - PyBoundMethod::new_ref(obj, zelf.into(), &vm.ctx).into() + PyBoundMethod::new_ref(obj, zelf, &vm.ctx).into() }; Ok(r) } diff --git a/vm/src/builtins/classmethod.rs b/vm/src/builtins/classmethod.rs index 960cb0c8ba..02f836199e 100644 --- a/vm/src/builtins/classmethod.rs +++ b/vm/src/builtins/classmethod.rs @@ -53,7 +53,7 @@ impl GetDescriptor for PyClassMethod { cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, _obj) = Self::_unwrap(zelf, obj, vm)?; + let (zelf, _obj) = Self::_unwrap(&zelf, obj, vm)?; let cls = cls.unwrap_or_else(|| _obj.class().to_owned().into()); let call_descr_get: PyResult = zelf.callable.lock().get_attr("__get__", vm); match call_descr_get { diff --git a/vm/src/builtins/descriptor.rs b/vm/src/builtins/descriptor.rs index 4735350b9a..a0995e1472 100644 --- a/vm/src/builtins/descriptor.rs +++ b/vm/src/builtins/descriptor.rs @@ -3,7 +3,7 @@ use crate::{ class::PyClassImpl, function::PySetterValue, types::{Constructor, GetDescriptor, Representable, Unconstructible}, - AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, + AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; use rustpython_common::lock::PyRwLock; @@ -122,12 +122,12 @@ impl MemberDescrObject { #[pyslot] fn descr_set( - zelf: PyObjectRef, + zelf: &PyObject, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { - let zelf = Self::_zelf(zelf, vm)?; + let zelf = Self::_as_pyref(zelf, vm)?; zelf.member.set(obj, value, vm) } } @@ -208,7 +208,7 @@ impl GetDescriptor for MemberDescrObject { ) -> PyResult { match obj { Some(x) => { - let zelf = Self::_zelf(zelf, vm)?; + let zelf = Self::_as_pyref(&zelf, vm)?; zelf.member.get(x, vm) } None => Ok(zelf), diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index db68994a86..bf8fb46d29 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -374,13 +374,13 @@ impl PyFunction { // {"__builtins__", T_OBJECT, OFF(func_builtins), READONLY}, #[pymember(magic)] fn globals(vm: &VirtualMachine, zelf: PyObjectRef) -> PyResult { - let zelf = Self::_zelf(zelf, vm)?; + let zelf = Self::_as_pyref(&zelf, vm)?; Ok(zelf.globals.clone().into()) } #[pymember(magic)] fn closure(vm: &VirtualMachine, zelf: PyObjectRef) -> PyResult { - let zelf = Self::_zelf(zelf, vm)?; + let zelf = Self::_as_pyref(&zelf, vm)?; Ok(vm.unwrap_or_none(zelf.closure.clone().map(|x| x.to_pyobject(vm)))) } @@ -439,11 +439,11 @@ impl GetDescriptor for PyFunction { cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; + let (_zelf, obj) = Self::_unwrap(&zelf, obj, vm)?; let obj = if vm.is_none(&obj) && !Self::_cls_is(&cls, obj.class()) { - zelf.into() + zelf } else { - PyBoundMethod::new_ref(obj, zelf.into(), &vm.ctx).into() + PyBoundMethod::new_ref(obj, zelf, &vm.ctx).into() }; Ok(obj) } @@ -507,7 +507,7 @@ impl GetAttr for PyBoundMethod { .interned_str(name) .and_then(|attr_name| zelf.get_class_attr(attr_name)); if let Some(obj) = class_attr { - return vm.call_if_get_descriptor(obj, zelf.to_owned().into()); + return vm.call_if_get_descriptor(&obj, zelf.to_owned().into()); } zelf.function.get_attr(name, vm) } diff --git a/vm/src/builtins/getset.rs b/vm/src/builtins/getset.rs index 766fec2d77..2516fcd566 100644 --- a/vm/src/builtins/getset.rs +++ b/vm/src/builtins/getset.rs @@ -6,7 +6,7 @@ use crate::{ class::PyClassImpl, function::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc, PySetterValue}, types::{Constructor, GetDescriptor, Unconstructible}, - AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, + AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; #[pyclass(module = false, name = "getset_descriptor")] @@ -51,9 +51,9 @@ impl GetDescriptor for PyGetSet { _cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, obj) = match Self::_check(zelf, obj, vm) { - Ok(obj) => obj, - Err(result) => return result, + let (zelf, obj) = match Self::_check(&zelf, obj, vm) { + Some(obj) => obj, + None => return Ok(zelf), }; if let Some(ref f) = zelf.getter { f(vm, obj) @@ -100,12 +100,12 @@ impl PyGetSet { #[pyslot] fn descr_set( - zelf: PyObjectRef, + zelf: &PyObject, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { - let zelf = PyRef::::try_from_object(vm, zelf)?; + let zelf = zelf.try_to_ref::(vm)?; if let Some(ref f) = zelf.setter { f(vm, obj, value) } else { @@ -123,11 +123,11 @@ impl PyGetSet { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - Self::descr_set(zelf, obj, PySetterValue::Assign(value), vm) + Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) } #[pymethod] fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - Self::descr_set(zelf, obj, PySetterValue::Delete, vm) + Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) } #[pygetset(magic)] diff --git a/vm/src/builtins/property.rs b/vm/src/builtins/property.rs index 5357d3a986..7322ba7d08 100644 --- a/vm/src/builtins/property.rs +++ b/vm/src/builtins/property.rs @@ -8,7 +8,7 @@ use crate::{ class::PyClassImpl, function::{FuncArgs, PySetterValue}, types::{Constructor, GetDescriptor, Initializer}, - AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, + AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; #[pyclass(module = false, name = "property")] @@ -40,14 +40,14 @@ pub struct PropertyArgs { impl GetDescriptor for PyProperty { fn descr_get( - zelf: PyObjectRef, + zelf_obj: PyObjectRef, obj: Option, _cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; + let (zelf, obj) = Self::_unwrap(&zelf_obj, obj, vm)?; if vm.is_none(&obj) { - Ok(zelf.into()) + Ok(zelf_obj) } else if let Some(getter) = zelf.getter.read().as_ref() { getter.call((obj,), vm) } else { @@ -62,12 +62,12 @@ impl PyProperty { #[pyslot] fn descr_set( - zelf: PyObjectRef, + zelf: &PyObject, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { - let zelf = PyRef::::try_from_object(vm, zelf)?; + let zelf = zelf.try_to_ref::(vm)?; match value { PySetterValue::Assign(value) => { if let Some(setter) = zelf.setter.read().as_ref() { @@ -92,11 +92,11 @@ impl PyProperty { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - Self::descr_set(zelf, obj, PySetterValue::Assign(value), vm) + Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) } #[pymethod] fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - Self::descr_set(zelf, obj, PySetterValue::Delete, vm) + Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) } // Access functions diff --git a/vm/src/builtins/staticmethod.rs b/vm/src/builtins/staticmethod.rs index 36e72ba520..187648e2c0 100644 --- a/vm/src/builtins/staticmethod.rs +++ b/vm/src/builtins/staticmethod.rs @@ -27,7 +27,7 @@ impl GetDescriptor for PyStaticMethod { _cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, _obj) = Self::_unwrap(zelf, obj, vm)?; + let (zelf, _obj) = Self::_unwrap(&zelf, obj, vm)?; let x = Ok(zelf.callable.lock().clone()); x } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 2539007cad..dad7f08402 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -48,6 +48,13 @@ impl<'a> TryFromBorrowedObject<'a> for String { } } +impl<'a> TryFromBorrowedObject<'a> for &'a str { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult { + let pystr: &Py = TryFromBorrowedObject::try_from_borrowed_object(vm, obj)?; + Ok(pystr.as_str()) + } +} + #[pyclass(module = false, name = "str")] pub struct PyStr { bytes: Box<[u8]>, diff --git a/vm/src/builtins/super.rs b/vm/src/builtins/super.rs index 6cdaa76134..be8c0ed192 100644 --- a/vm/src/builtins/super.rs +++ b/vm/src/builtins/super.rs @@ -150,7 +150,7 @@ impl GetAttr for PySuper { if let Some(descr) = cls.get_direct_attr(name) { return vm .call_get_descriptor_specific( - descr.clone(), + &descr, // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267) if obj.is(&start_type) { None } else { Some(obj) }, Some(start_type.as_object().to_owned()), @@ -165,14 +165,14 @@ impl GetAttr for PySuper { impl GetDescriptor for PySuper { fn descr_get( - zelf: PyObjectRef, + zelf_obj: PyObjectRef, obj: Option, _cls: Option, vm: &VirtualMachine, ) -> PyResult { - let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; + let (zelf, obj) = Self::_unwrap(&zelf_obj, obj, vm)?; if vm.is_none(&obj) || zelf.obj.is_some() { - return Ok(zelf.into()); + return Ok(zelf_obj); } let zelf_class = zelf.as_object().class(); if zelf_class.is(vm.ctx.types.super_type) { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 22e0dc29a5..933d097158 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -17,7 +17,7 @@ use crate::{ borrow::BorrowedValue, lock::{PyRwLock, PyRwLockReadGuard}, }, - convert::{ToPyObject, ToPyResult}, + convert::ToPyResult, function::{FuncArgs, KwArgs, OptionalArg, PySetterValue}, identifier, protocol::{PyIterReturn, PyMappingMethods, PyNumberMethods, PySequenceMethods}, @@ -816,7 +816,7 @@ impl PyType { cell.class().name() )) })?; - cell.set(Some(typ.clone().to_pyobject(vm))); + cell.set(Some(typ.clone().into())); }; // avoid deadlock @@ -844,7 +844,7 @@ impl PyType { if let Some(init_subclass) = typ.get_super_attr(identifier!(vm, __init_subclass__)) { let init_subclass = vm - .call_get_descriptor_specific(init_subclass.clone(), None, Some(typ.clone().into())) + .call_get_descriptor_specific(&init_subclass, None, Some(typ.clone().into())) .unwrap_or(Ok(init_subclass))?; init_subclass.call(kwargs, vm)?; }; @@ -1008,19 +1008,17 @@ impl GetAttr for PyType { let zelf_attr = zelf.get_attr(name); - if let Some(ref attr) = zelf_attr { + if let Some(attr) = zelf_attr { let descr_get = attr.class().mro_find_map(|cls| cls.slots.descr_get.load()); if let Some(descr_get) = descr_get { - return descr_get(attr.clone(), None, Some(zelf.to_owned().into()), vm); + descr_get(attr, None, Some(zelf.to_owned().into()), vm) + } else { + Ok(attr) } - } - - if let Some(cls_attr) = zelf_attr { - Ok(cls_attr) } else if let Some(attr) = mcl_attr { - vm.call_if_get_descriptor(attr, zelf.to_owned().into()) + vm.call_if_get_descriptor(&attr, zelf.to_owned().into()) } else { - return Err(attribute_error(zelf, name_str.as_str(), vm)); + Err(attribute_error(zelf, name_str.as_str(), vm)) } } } @@ -1037,7 +1035,7 @@ impl SetAttr for PyType { if let Some(attr) = zelf.get_class_attr(attr_name) { let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load()); if let Some(descriptor) = descr_set { - return descriptor(attr, zelf.to_owned().into(), value, vm); + return descriptor(&attr, zelf.to_owned().into(), value, vm); } } let assign = value.is_assign(); @@ -1132,10 +1130,10 @@ fn find_base_dict_descr(cls: &Py, vm: &VirtualMachine) -> Option PyResult { // TODO: obj.class().as_pyref() need to be supported let ret = match find_base_dict_descr(obj.class(), vm) { - Some(descr) => vm.call_get_descriptor(descr, obj).unwrap_or_else(|obj| { + Some(descr) => vm.call_get_descriptor(&descr, obj).unwrap_or_else(|| { Err(vm.new_type_error(format!( "this __dict__ descriptor does not support '{}' objects", - obj.class() + descr.class() ))) })?, None => object::object_get_dict(obj, vm)?.into(), @@ -1156,7 +1154,7 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) - cls.name() )) })?; - descr_set(descr, obj, PySetterValue::Assign(value), vm) + descr_set(&descr, obj, PySetterValue::Assign(value), vm) } None => { object::object_set_dict(obj, value.try_into_value(vm)?, vm)?; diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index a0e4c8c2f6..2b8dd4b0b9 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -33,8 +33,8 @@ fn spec_format_bytes( Ok(buffer.contiguous_or_collect(|bytes| spec.format_bytes(bytes))) } else { let bytes = vm - .get_special_method(obj, identifier!(vm, __bytes__))? - .map_err(|obj| { + .get_special_method(&obj, identifier!(vm, __bytes__))? + .ok_or_else(|| { vm.new_type_error(format!( "%b requires a bytes-like object, or an object that \ implements __bytes__, not '{}'", diff --git a/vm/src/convert/try_from.rs b/vm/src/convert/try_from.rs index 070c127458..028cc91033 100644 --- a/vm/src/convert/try_from.rs +++ b/vm/src/convert/try_from.rs @@ -38,6 +38,13 @@ impl PyObject { T::try_from_borrowed_object(vm, self) } + pub fn try_to_ref<'a, T: 'a>(&'a self, vm: &VirtualMachine) -> PyResult<&'a Py> + where + T: PyPayload, + { + self.try_to_value::<&Py>(vm) + } + pub fn try_value_with(&self, f: F, vm: &VirtualMachine) -> PyResult where T: PyPayload, diff --git a/vm/src/frame.rs b/vm/src/frame.rs index ad12ec15b5..80deeff213 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -851,8 +851,8 @@ impl ExecutingFrame<'_> { ) }; let enter_res = vm - .get_special_method(context_manager.clone(), identifier!(vm, __enter__))? - .map_err(|_obj| vm.new_type_error(error_string()))? + .get_special_method(&context_manager, identifier!(vm, __enter__))? + .ok_or_else(|| vm.new_type_error(error_string()))? .invoke((), vm)?; let exit = context_manager @@ -879,8 +879,8 @@ impl ExecutingFrame<'_> { }; let aenter_res = vm - .get_special_method(mgr.clone(), identifier!(vm, __aenter__))? - .map_err(|_obj| vm.new_type_error(error_string()))? + .get_special_method(&mgr, identifier!(vm, __aenter__))? + .ok_or_else(|| vm.new_type_error(error_string()))? .invoke((), vm)?; let aexit = mgr .get_attr(identifier!(vm, __aexit__), vm) @@ -976,17 +976,17 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::GetAIter => { let aiterable = self.pop_value(); - let aiter = vm.call_special_method(aiterable, identifier!(vm, __aiter__), ())?; + let aiter = vm.call_special_method(&aiterable, identifier!(vm, __aiter__), ())?; self.push_value(aiter); Ok(None) } bytecode::Instruction::GetANext => { let aiter = self.last_value(); - let awaitable = vm.call_special_method(aiter, identifier!(vm, __anext__), ())?; + let awaitable = vm.call_special_method(&aiter, identifier!(vm, __anext__), ())?; let awaitable = if awaitable.payload_is::() { awaitable } else { - vm.call_special_method(awaitable, identifier!(vm, __await__), ())? + vm.call_special_method(&awaitable, identifier!(vm, __await__), ())? }; self.push_value(awaitable); Ok(None) @@ -1728,7 +1728,7 @@ impl ExecutingFrame<'_> { Ok(d) => d.contains_key(__annotations__, vm), Err(o) => { let needle = __annotations__.to_object(); - self._in(vm, needle, o)? + self._in(vm, needle, &o)? } }; if !has_annotations { @@ -1801,12 +1801,7 @@ impl ExecutingFrame<'_> { Ok(None) } - fn _in( - &self, - vm: &VirtualMachine, - needle: PyObjectRef, - haystack: PyObjectRef, - ) -> PyResult { + fn _in(&self, vm: &VirtualMachine, needle: PyObjectRef, haystack: &PyObject) -> PyResult { let found = vm._contains(haystack, needle)?; found.try_to_bool(vm) } @@ -1816,7 +1811,7 @@ impl ExecutingFrame<'_> { &self, vm: &VirtualMachine, needle: PyObjectRef, - haystack: PyObjectRef, + haystack: &PyObject, ) -> PyResult { Ok(!self._in(vm, needle, haystack)?) } @@ -1828,8 +1823,8 @@ impl ExecutingFrame<'_> { let value = match op { bytecode::TestOperator::Is => a.is(&b), bytecode::TestOperator::IsNot => !a.is(&b), - bytecode::TestOperator::In => self._in(vm, a, b)?, - bytecode::TestOperator::NotIn => self._not_in(vm, a, b)?, + bytecode::TestOperator::In => self._in(vm, a, &b)?, + bytecode::TestOperator::NotIn => self._not_in(vm, a, &b)?, bytecode::TestOperator::ExceptionMatch => a.is_instance(&b, vm)?, }; diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs index 9de7a37303..c0a0720099 100644 --- a/vm/src/protocol/mapping.rs +++ b/vm/src/protocol/mapping.rs @@ -178,7 +178,7 @@ impl PyMapping<'_> { return Ok(meth_output); } - let iter = meth_output.clone().get_iter(vm).map_err(|_| { + let iter = meth_output.get_iter(vm).map_err(|_| { vm.new_type_error(format!( "{}.{}() returned a non-iterable (type {})", self.obj.class(), diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index a08ef3bbff..63bffcb68e 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -60,8 +60,7 @@ impl PyObject { Ok(i.to_owned()) } else if let Some(i) = self.to_number().int(vm).or_else(|| self.try_index_opt(vm)) { i - } else if let Ok(Ok(f)) = vm.get_special_method(self.to_owned(), identifier!(vm, __trunc__)) - { + } else if let Ok(Some(f)) = vm.get_special_method(self, identifier!(vm, __trunc__)) { // TODO: Deprecate in 3.11 // warnings::warn( // vm.ctx.exceptions.deprecation_warning.clone(), diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index d398154260..d47b20f25d 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -62,19 +62,19 @@ impl PyObjectRef { } // PyObject *PyObject_Dir(PyObject *o) +} +impl PyObject { /// Takes an object and returns an iterator for it. /// This is typically a new iterator but if the argument is an iterator, this /// returns itself. - pub fn get_iter(self, vm: &VirtualMachine) -> PyResult { + pub fn get_iter(&self, vm: &VirtualMachine) -> PyResult { // PyObject_GetIter - PyIter::try_from_object(vm, self) + PyIter::try_from_object(vm, self.to_owned()) } // PyObject *PyObject_GetAIter(PyObject *o) -} -impl PyObject { pub fn has_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult { self.get_attr(attr_name, vm).map(|o| !vm.is_none(&o)) } @@ -152,7 +152,7 @@ impl PyObject { { let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load()); if let Some(descriptor) = descr_set { - return descriptor(attr, self.to_owned(), value, vm); + return descriptor(&attr, self.to_owned(), value, vm); } } @@ -319,7 +319,7 @@ impl PyObject { match self.class().slots.repr.load() { Some(slot) => slot(self, vm), None => vm - .call_special_method(self.to_owned(), identifier!(vm, __repr__), ())? + .call_special_method(self, identifier!(vm, __repr__), ())? .try_into_value(vm), // TODO: remove magic method call once __repr__ is fully ported to slot } }) @@ -338,9 +338,9 @@ impl PyObject { Err(obj) => obj, }; // TODO: replace to obj.class().slots.str - let str_method = match vm.get_special_method(obj, identifier!(vm, __str__))? { - Ok(str_method) => str_method, - Err(obj) => return obj.repr(vm), + let str_method = match vm.get_special_method(&obj, identifier!(vm, __str__))? { + Some(str_method) => str_method, + None => return obj.repr(vm), }; let s = str_method.invoke((), vm)?; s.downcast::().map_err(|obj| { @@ -447,9 +447,7 @@ impl PyObject { return Ok(false); } - if let Ok(meth) = - vm.get_special_method(cls.to_owned(), identifier!(vm, __subclasscheck__))? - { + 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) })?; @@ -514,9 +512,7 @@ impl PyObject { return Ok(false); } - if let Ok(meth) = - vm.get_special_method(cls.to_owned(), identifier!(vm, __instancecheck__))? - { + if let Some(meth) = vm.get_special_method(cls, identifier!(vm, __instancecheck__))? { let ret = vm.with_recursion("in __instancecheck__", || { meth.invoke((self.to_owned(),), vm) })?; diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index c0591d8cf9..2b9da7de5c 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -438,7 +438,7 @@ mod builtins { #[pyfunction] fn aiter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult { if iter_target.payload_is::() { - vm.call_special_method(iter_target, identifier!(vm, __aiter__), ()) + vm.call_special_method(&iter_target, identifier!(vm, __aiter__), ()) } else { Err(vm.new_type_error("wrong argument type".to_owned())) } @@ -720,8 +720,8 @@ mod builtins { #[pyfunction] fn round(RoundArgs { number, ndigits }: RoundArgs, vm: &VirtualMachine) -> PyResult { let meth = vm - .get_special_method(number, identifier!(vm, __round__))? - .map_err(|number| { + .get_special_method(&number, identifier!(vm, __round__))? + .ok_or_else(|| { vm.new_type_error(format!( "type {} doesn't define __round__", number.class().name() diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index e551d0295b..24d7998840 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -1181,18 +1181,14 @@ mod decl { let n = n.unwrap_or(2); let copyable = if iterable.class().has_attr(identifier!(vm, __copy__)) { - vm.call_special_method(iterable.into(), identifier!(vm, __copy__), ())? + vm.call_special_method(iterable.as_object(), identifier!(vm, __copy__), ())? } else { PyItertoolsTee::from_iter(iterable, vm)? }; let mut tee_vec: Vec = Vec::with_capacity(n); for _ in 0..n { - tee_vec.push(vm.call_special_method( - copyable.clone(), - identifier!(vm, __copy__), - (), - )?); + tee_vec.push(vm.call_special_method(©able, identifier!(vm, __copy__), ())?); } Ok(PyTuple::new_ref(tee_vec, &vm.ctx).into()) @@ -1204,7 +1200,7 @@ mod decl { fn from_iter(iterator: PyIter, vm: &VirtualMachine) -> PyResult { let class = PyItertoolsTee::class(&vm.ctx); if iterator.class().is(PyItertoolsTee::class(&vm.ctx)) { - return vm.call_special_method(iterator.into(), identifier!(vm, __copy__), ()); + return vm.call_special_method(&iterator, identifier!(vm, __copy__), ()); } Ok(PyItertoolsTee { tee_data: PyItertoolsTeeData::new(iterator, vm)?, diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 93a4173101..32131d795c 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -173,7 +173,7 @@ mod _operator { #[pyfunction] fn contains(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult { - vm._contains(a, b) + vm._contains(&a, b) } #[pyfunction(name = "countOf")] diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index 4e3e213861..493e1d7651 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -429,7 +429,7 @@ mod sys { #[pyfunction] fn getsizeof(args: GetsizeofArgs, vm: &VirtualMachine) -> PyResult { let sizeof = || -> PyResult { - let res = vm.call_special_method(args.obj, identifier!(vm, __sizeof__), ())?; + let res = vm.call_special_method(&args.obj, identifier!(vm, __sizeof__), ())?; let res = res.try_index(vm)?.try_to_primitive::(vm)?; Ok(res + std::mem::size_of::()) }; diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index dba2194a69..12eb324c6b 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -173,14 +173,14 @@ pub(crate) type IterNextFunc = fn(&PyObject, &VirtualMachine) -> PyResult, Option, &VirtualMachine) -> PyResult; pub(crate) type DescrSetFunc = - fn(PyObjectRef, PyObjectRef, PySetterValue, &VirtualMachine) -> PyResult<()>; + fn(&PyObject, PyObjectRef, PySetterValue, &VirtualMachine) -> PyResult<()>; pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult; pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult<()>; pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>; // slot_sq_length pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult { - let ret = vm.call_special_method(obj.to_owned(), identifier!(vm, __len__), ())?; + let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?; let len = ret.payload::().ok_or_else(|| { vm.new_type_error(format!( "'{}' object cannot be interpreted as an integer", @@ -198,21 +198,21 @@ pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult PyResult> { - let ret = vm.call_special_method(num.deref().to_owned(), identifier!(vm, __int__), ())?; + let ret = vm.call_special_method(num.deref(), identifier!(vm, __int__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class())) }) } fn index_wrapper(num: PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.deref().to_owned(), identifier!(vm, __index__), ())?; + let ret = vm.call_special_method(num.deref(), identifier!(vm, __index__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class())) }) } fn float_wrapper(num: PyNumber, vm: &VirtualMachine) -> PyResult> { - let ret = vm.call_special_method(num.deref().to_owned(), identifier!(vm, __float__), ())?; + let ret = vm.call_special_method(num.deref(), identifier!(vm, __float__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!( "__float__ returned non-float (type {})", @@ -223,17 +223,17 @@ fn float_wrapper(num: PyNumber, vm: &VirtualMachine) -> PyResult> macro_rules! number_binary_op_wrapper { ($name:ident) => { - |a, b, vm| vm.call_special_method(a.to_owned(), identifier!(vm, $name), (b.to_owned(),)) + |a, b, vm| vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),)) }; } macro_rules! number_binary_right_op_wrapper { ($name:ident) => { - |a, b, vm| vm.call_special_method(b.to_owned(), identifier!(vm, $name), (a.to_owned(),)) + |a, b, vm| vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),)) }; } fn getitem_wrapper(obj: &PyObject, needle: K, vm: &VirtualMachine) -> PyResult { - vm.call_special_method(obj.to_owned(), identifier!(vm, __getitem__), (needle,)) + vm.call_special_method(obj, identifier!(vm, __getitem__), (needle,)) } fn setitem_wrapper( @@ -243,18 +243,14 @@ fn setitem_wrapper( vm: &VirtualMachine, ) -> PyResult<()> { match value { - Some(value) => vm.call_special_method( - obj.to_owned(), - identifier!(vm, __setitem__), - (needle, value), - ), - None => vm.call_special_method(obj.to_owned(), identifier!(vm, __delitem__), (needle,)), + Some(value) => vm.call_special_method(obj, identifier!(vm, __setitem__), (needle, value)), + None => vm.call_special_method(obj, identifier!(vm, __delitem__), (needle,)), } .map(drop) } fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { - let ret = vm.call_special_method(zelf.to_owned(), identifier!(vm, __repr__), ())?; + let ret = vm.call_special_method(zelf, identifier!(vm, __repr__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!( "__repr__ returned non-string (type {})", @@ -264,7 +260,7 @@ fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { } fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { - let hash_obj = vm.call_special_method(zelf.to_owned(), identifier!(vm, __hash__), ())?; + let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?; let py_int = hash_obj .payload_if_subclass::(vm) .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer".to_owned()))?; @@ -277,16 +273,16 @@ pub fn hash_not_implemented(zelf: &PyObject, vm: &VirtualMachine) -> PyResult PyResult { - vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args) + vm.call_special_method(zelf, identifier!(vm, __call__), args) } fn getattro_wrapper(zelf: &PyObject, name: &Py, vm: &VirtualMachine) -> PyResult { let __getattribute__ = identifier!(vm, __getattribute__); let __getattr__ = identifier!(vm, __getattr__); - match vm.call_special_method(zelf.to_owned(), __getattribute__, (name.to_owned(),)) { + match vm.call_special_method(zelf, __getattribute__, (name.to_owned(),)) { Ok(r) => Ok(r), Err(_) if zelf.class().has_attr(__getattr__) => { - vm.call_special_method(zelf.to_owned(), __getattr__, (name.to_owned(),)) + vm.call_special_method(zelf, __getattr__, (name.to_owned(),)) } Err(e) => Err(e), } @@ -298,7 +294,6 @@ fn setattro_wrapper( value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { - let zelf = zelf.to_owned(); let name = name.to_owned(); match value { PySetterValue::Assign(value) => { @@ -317,21 +312,17 @@ pub(crate) fn richcompare_wrapper( op: PyComparisonOp, vm: &VirtualMachine, ) -> PyResult> { - vm.call_special_method( - zelf.to_owned(), - op.method_name(&vm.ctx), - (other.to_owned(),), - ) - .map(Either::A) + vm.call_special_method(zelf, op.method_name(&vm.ctx), (other.to_owned(),)) + .map(Either::A) } fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { - vm.call_special_method(zelf, identifier!(vm, __iter__), ()) + vm.call_special_method(&zelf, identifier!(vm, __iter__), ()) } fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { PyIterReturn::from_pyresult( - vm.call_special_method(zelf.to_owned(), identifier!(vm, __next__), ()), + vm.call_special_method(zelf, identifier!(vm, __next__), ()), vm, ) } @@ -342,11 +333,11 @@ fn descr_get_wrapper( cls: Option, vm: &VirtualMachine, ) -> PyResult { - vm.call_special_method(zelf, identifier!(vm, __get__), (obj, cls)) + vm.call_special_method(&zelf, identifier!(vm, __get__), (obj, cls)) } fn descr_set_wrapper( - zelf: PyObjectRef, + zelf: &PyObject, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine, @@ -361,7 +352,7 @@ fn descr_set_wrapper( } fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { - let res = vm.call_special_method(obj, identifier!(vm, __init__), args)?; + let res = vm.call_special_method(&obj, identifier!(vm, __init__), args)?; if !vm.is_none(&res) { return Err(vm.new_type_error("__init__ must return None".to_owned())); } @@ -375,7 +366,7 @@ fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyRes } fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> { - vm.call_special_method(zelf.to_owned(), identifier!(vm, __del__), ())?; + vm.call_special_method(zelf, identifier!(vm, __del__), ())?; Ok(()) } @@ -874,44 +865,40 @@ pub trait GetDescriptor: PyPayload { } #[inline] - fn _zelf(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - zelf.try_into_value(vm) + fn _as_pyref<'a>(zelf: &'a PyObject, vm: &VirtualMachine) -> PyResult<&'a Py> { + zelf.try_to_value(vm) } #[inline] - fn _unwrap( - zelf: PyObjectRef, + fn _unwrap<'a>( + zelf: &'a PyObject, obj: Option, vm: &VirtualMachine, - ) -> PyResult<(PyRef, PyObjectRef)> { - let zelf = Self::_zelf(zelf, vm)?; + ) -> PyResult<(&'a Py, PyObjectRef)> { + let zelf = Self::_as_pyref(zelf, vm)?; let obj = vm.unwrap_or_none(obj); Ok((zelf, obj)) } #[inline] - fn _check( - zelf: PyObjectRef, + fn _check<'a>( + zelf: &'a PyObject, obj: Option, vm: &VirtualMachine, - ) -> Result<(PyRef, PyObjectRef), PyResult> { + ) -> Option<(&'a Py, PyObjectRef)> { // CPython descr_check - if let Some(obj) = obj { - // if (!PyObject_TypeCheck(obj, descr->d_type)) { - // PyErr_Format(PyExc_TypeError, - // "descriptor '%V' for '%.100s' objects " - // "doesn't apply to a '%.100s' object", - // descr_name((PyDescrObject *)descr), "?", - // descr->d_type->slot_name, - // obj->ob_type->slot_name); - // *pres = NULL; - // return 1; - // } else { - Ok((Self::_zelf(zelf, vm).unwrap(), obj)) - // } - } else { - Err(Ok(zelf)) - } + let obj = obj?; + // if (!PyObject_TypeCheck(obj, descr->d_type)) { + // PyErr_Format(PyExc_TypeError, + // "descriptor '%V' for '%.100s' objects " + // "doesn't apply to a '%.100s' object", + // descr_name((PyDescrObject *)descr), "?", + // descr->d_type->slot_name, + // obj->ob_type->slot_name); + // *pres = NULL; + // return 1; + // } else { + Some((Self::_as_pyref(zelf, vm).unwrap(), obj)) } #[inline] diff --git a/vm/src/vm/method.rs b/vm/src/vm/method.rs index c2bf741cdb..9f55e28f86 100644 --- a/vm/src/vm/method.rs +++ b/vm/src/vm/method.rs @@ -5,7 +5,7 @@ use super::VirtualMachine; use crate::{ builtins::{PyBaseObject, PyStr, PyStrInterned}, function::IntoFuncArgs, - object::{AsObject, Py, PyObjectRef, PyResult}, + object::{AsObject, Py, PyObject, PyObjectRef, PyResult}, types::PyTypeFlags, }; @@ -86,15 +86,15 @@ impl PyMethod { } pub(crate) fn get_special( - obj: PyObjectRef, + obj: &PyObject, name: &'static PyStrInterned, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult> { let obj_cls = obj.class(); let func = match obj_cls.get_attr(name) { Some(f) => f, None => { - return Ok(Err(obj)); + return Ok(None); } }; let meth = if func @@ -103,15 +103,18 @@ impl PyMethod { .flags .has_feature(PyTypeFlags::METHOD_DESCR) { - Self::Function { target: obj, func } + Self::Function { + target: obj.to_owned(), + func, + } } else { let obj_cls = obj_cls.to_owned().into(); let attr = vm - .call_get_descriptor_specific(func, Some(obj), Some(obj_cls)) - .unwrap_or_else(Ok)?; + .call_get_descriptor_specific(&func, Some(obj.to_owned()), Some(obj_cls)) + .unwrap_or(Ok(func))?; Self::Attribute(attr) }; - Ok(Ok(meth)) + Ok(Some(meth)) } pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 3a0eb57b4f..57e916b4a6 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -650,7 +650,7 @@ impl VirtualMachine { .class() .get_attr(method_name) .ok_or_else(|| self.new_type_error(err_msg()))?; - self.call_if_get_descriptor(method, obj) + self.call_if_get_descriptor(&method, obj) } // TODO: remove + transfer over to get_special_method @@ -660,7 +660,7 @@ impl VirtualMachine { method_name: &'static PyStrInterned, ) -> Option { let method = obj.get_class_attr(method_name)?; - Some(self.call_if_get_descriptor(method, obj)) + Some(self.call_if_get_descriptor(&method, obj)) } pub(crate) fn get_str_method(&self, obj: PyObjectRef, method_name: &str) -> Option { diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index bcc8487d6a..056ded9bfd 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -73,28 +73,24 @@ impl VirtualMachine { pub fn call_get_descriptor_specific( &self, - descr: PyObjectRef, + descr: &PyObject, obj: Option, cls: Option, - ) -> Result { - let descr_get = descr.class().mro_find_map(|cls| cls.slots.descr_get.load()); - match descr_get { - Some(descr_get) => Ok(descr_get(descr, obj, cls, self)), - None => Err(descr), - } + ) -> Option { + let descr_get = descr + .class() + .mro_find_map(|cls| cls.slots.descr_get.load())?; + Some(descr_get(descr.to_owned(), obj, cls, self)) } - pub fn call_get_descriptor( - &self, - descr: PyObjectRef, - obj: PyObjectRef, - ) -> Result { + pub fn call_get_descriptor(&self, descr: &PyObject, obj: PyObjectRef) -> Option { let cls = obj.class().to_owned().into(); self.call_get_descriptor_specific(descr, Some(obj), Some(cls)) } - pub fn call_if_get_descriptor(&self, attr: PyObjectRef, obj: PyObjectRef) -> PyResult { - self.call_get_descriptor(attr, obj).unwrap_or_else(Ok) + pub fn call_if_get_descriptor(&self, attr: &PyObject, obj: PyObjectRef) -> PyResult { + self.call_get_descriptor(attr, obj) + .unwrap_or_else(|| Ok(attr.to_owned())) } #[inline] @@ -118,8 +114,8 @@ impl VirtualMachine { pub fn dir(&self, obj: Option) -> PyResult { let seq = match obj { Some(obj) => self - .get_special_method(obj, identifier!(self, __dir__))? - .map_err(|_obj| self.new_type_error("object does not provide __dir__".to_owned()))? + .get_special_method(&obj, identifier!(self, __dir__))? + .ok_or_else(|| self.new_type_error("object does not provide __dir__".to_owned()))? .invoke((), self)?, None => self.call_method( self.current_locals()?.as_object(), @@ -136,9 +132,9 @@ impl VirtualMachine { #[inline] pub(crate) fn get_special_method( &self, - obj: PyObjectRef, + obj: &PyObject, method: &'static PyStrInterned, - ) -> PyResult> { + ) -> PyResult> { PyMethod::get_special(obj, method, self) } @@ -146,12 +142,12 @@ impl VirtualMachine { #[doc(hidden)] pub fn call_special_method( &self, - obj: PyObjectRef, + obj: &PyObject, method: &'static PyStrInterned, args: impl IntoFuncArgs, ) -> PyResult { self.get_special_method(obj, method)? - .map_err(|_obj| self.new_attribute_error(method.as_str().to_owned()))? + .ok_or_else(|| self.new_attribute_error(method.as_str().to_owned()))? .invoke(args, self) } diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 343354703a..7858b576ff 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -333,26 +333,26 @@ impl VirtualMachine { } pub fn _abs(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), identifier!(self, __abs__))? - .map_err(|_| self.new_unsupported_unary_error(a, "abs()"))? + self.get_special_method(a, identifier!(self, __abs__))? + .ok_or_else(|| self.new_unsupported_unary_error(a, "abs()"))? .invoke((), self) } pub fn _pos(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), identifier!(self, __pos__))? - .map_err(|_| self.new_unsupported_unary_error(a, "unary +"))? + self.get_special_method(a, identifier!(self, __pos__))? + .ok_or_else(|| self.new_unsupported_unary_error(a, "unary +"))? .invoke((), self) } pub fn _neg(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), identifier!(self, __neg__))? - .map_err(|_| self.new_unsupported_unary_error(a, "unary -"))? + self.get_special_method(a, identifier!(self, __neg__))? + .ok_or_else(|| self.new_unsupported_unary_error(a, "unary -"))? .invoke((), self) } pub fn _invert(&self, a: &PyObject) -> PyResult { - self.get_special_method(a.to_owned(), identifier!(self, __invert__))? - .map_err(|_| self.new_unsupported_unary_error(a, "unary ~"))? + self.get_special_method(a, identifier!(self, __invert__))? + .ok_or_else(|| self.new_unsupported_unary_error(a, "unary ~"))? .invoke((), self) } @@ -368,8 +368,8 @@ impl VirtualMachine { } } let bound_format = self - .get_special_method(obj.to_owned(), identifier!(self, __format__))? - .map_err(|_| { + .get_special_method(obj, identifier!(self, __format__))? + .ok_or_else(|| { self.new_type_error(format!( "Type {} doesn't define __format__", obj.class().name() @@ -387,7 +387,7 @@ impl VirtualMachine { // https://docs.python.org/3/reference/expressions.html#membership-test-operations fn _membership_iter_search( &self, - haystack: PyObjectRef, + haystack: &PyObject, needle: PyObjectRef, ) -> PyResult { let iter = haystack.get_iter(self)?; @@ -404,10 +404,10 @@ impl VirtualMachine { } } - pub fn _contains(&self, haystack: PyObjectRef, needle: PyObjectRef) -> PyResult { + pub fn _contains(&self, haystack: &PyObject, needle: PyObjectRef) -> PyResult { match PyMethod::get_special(haystack, identifier!(self, __contains__), self)? { - Ok(method) => method.invoke((needle,), self), - Err(haystack) => self + Some(method) => method.invoke((needle,), self), + None => self ._membership_iter_search(haystack, needle) .map(Into::into), }