diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index f06e66408..bc0869c14 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -345,8 +345,10 @@ where match slot_name.as_str() { "call" => quote! { slots.#slot_ident.store(Some( - |vm: &::rustpython_vm::VirtualMachine, args: ::rustpython_vm::function::PyFuncArgs| -> ::rustpython_vm::pyobject::PyResult { - ::rustpython_vm::function::IntoPyNativeFunc::call(&Self::#ident, vm, args) + |zelf: ::rustpython_vm::pyobject::PyObjectRef, args: ::rustpython_vm::function::PyFuncArgs, vm: &::rustpython_vm::VirtualMachine| -> ::rustpython_vm::pyobject::PyResult { + use ::rustpython_vm::pyobject::TryFromObject; + let zelf = PyRef::::try_from_object(vm, zelf)?; + Self::#ident(zelf, args, vm) } as _ )); }, diff --git a/vm/src/obj/objbuiltinfunc.rs b/vm/src/obj/objbuiltinfunc.rs index 2c7206f81..acc46aab9 100644 --- a/vm/src/obj/objbuiltinfunc.rs +++ b/vm/src/obj/objbuiltinfunc.rs @@ -1,7 +1,7 @@ use std::fmt; use super::objclassmethod::PyClassMethod; -use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc}; +use crate::function::{PyFuncArgs, PyNativeFunc}; use crate::obj::objstr::PyStringRef; use crate::obj::objtype::PyClassRef; use crate::pyobject::{ @@ -169,10 +169,10 @@ impl PyBuiltinMethod { impl SlotDescriptor for PyBuiltinMethod { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - cls: OptionalArg, + cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = match Self::_check(zelf, obj, vm) { Ok(obj) => obj, diff --git a/vm/src/obj/objclassmethod.rs b/vm/src/obj/objclassmethod.rs index d69b85a96..3c9d8e6e4 100644 --- a/vm/src/obj/objclassmethod.rs +++ b/vm/src/obj/objclassmethod.rs @@ -1,5 +1,4 @@ use super::objtype::PyClassRef; -use crate::function::OptionalArg; use crate::pyobject::{ PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; @@ -47,10 +46,10 @@ impl PyValue for PyClassMethod { impl SlotDescriptor for PyClassMethod { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - cls: OptionalArg, + cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; let cls = cls.unwrap_or_else(|| obj.class().into_object()); diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index a7ecdb9ee..646f2d411 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -8,7 +8,7 @@ use super::objtuple::PyTupleRef; use super::objtype::PyClassRef; use crate::bytecode; use crate::frame::Frame; -use crate::function::{OptionalArg, PyFuncArgs}; +use crate::function::PyFuncArgs; use crate::obj::objasyncgenerator::PyAsyncGen; use crate::obj::objcoroutine::PyCoroutine; use crate::obj::objgenerator::PyGenerator; @@ -306,10 +306,10 @@ impl PyFunction { impl SlotDescriptor for PyFunction { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - cls: OptionalArg, + cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; if vm.is_none(&obj) && !Self::_cls_is(&cls, &obj.class()) { diff --git a/vm/src/obj/objgetset.rs b/vm/src/obj/objgetset.rs index a3986efcb..c575434af 100644 --- a/vm/src/obj/objgetset.rs +++ b/vm/src/obj/objgetset.rs @@ -2,7 +2,7 @@ */ use super::objtype::PyClassRef; -use crate::function::{OptionalArg, OwnedParam, RefParam}; +use crate::function::{OwnedParam, RefParam}; use crate::pyobject::{ IntoPyResult, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -182,10 +182,10 @@ pub type PyGetSetRef = PyRef; impl SlotDescriptor for PyGetSet { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - _cls: OptionalArg, + _cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = match Self::_check(zelf, obj, vm) { Ok(obj) => obj, diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 5af26b89d..03768f1e7 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -4,7 +4,6 @@ use crate::common::cell::PyRwLock; use super::objtype::PyClassRef; -use crate::function::OptionalArg; use crate::pyobject::{ PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; @@ -74,10 +73,10 @@ struct PropertyArgs { impl SlotDescriptor for PyProperty { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - _cls: OptionalArg, + _cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; if vm.is_none(&obj) { diff --git a/vm/src/obj/objstaticmethod.rs b/vm/src/obj/objstaticmethod.rs index b8fbedf25..7d32e37a6 100644 --- a/vm/src/obj/objstaticmethod.rs +++ b/vm/src/obj/objstaticmethod.rs @@ -1,5 +1,4 @@ use super::objtype::PyClassRef; -use crate::function::OptionalArg; use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; use crate::slots::SlotDescriptor; use crate::vm::VirtualMachine; @@ -19,10 +18,10 @@ impl PyValue for PyStaticMethod { impl SlotDescriptor for PyStaticMethod { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, _obj: Option, - _cls: OptionalArg, + _cls: Option, + vm: &VirtualMachine, ) -> PyResult { let zelf = Self::_zelf(zelf, vm)?; Ok(zelf.callable.clone()) diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index 5438f2dcb..441cc5612 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -132,10 +132,10 @@ impl PySuper { impl SlotDescriptor for PySuper { fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - _cls: OptionalArg, + _cls: Option, + vm: &VirtualMachine, ) -> PyResult { let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; if vm.is_none(&obj) || zelf.obj.is_some() { diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index e50d22dd3..6731352bc 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -11,7 +11,7 @@ use super::objstaticmethod::PyStaticMethod; use super::objstr::PyStringRef; use super::objtuple::PyTuple; use super::objweakref::PyWeak; -use crate::function::{KwArgs, OptionalArg, PyFuncArgs}; +use crate::function::{KwArgs, PyFuncArgs}; use crate::pyobject::{ BorrowValue, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyLease, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -214,12 +214,7 @@ impl PyClass { PyLease::into_pyref(attr_class).first_in_mro(|cls| cls.slots.descr_get.load()) { let mcl = PyLease::into_pyref(mcl).into_object(); - return descr_get( - vm, - attr, - Some(zelf.into_object()), - OptionalArg::Present(mcl), - ); + return descr_get(attr, Some(zelf.into_object()), Some(mcl), vm); } } } @@ -228,7 +223,7 @@ impl PyClass { let attr_class = attr.class(); if let Some(ref descr_get) = attr_class.first_in_mro(|cls| cls.slots.descr_get.load()) { drop(mcl); - return descr_get(vm, attr, None, OptionalArg::Present(zelf.into_object())); + return descr_get(attr, None, Some(zelf.into_object()), vm); } } diff --git a/vm/src/slots.rs b/vm/src/slots.rs index cd2297f9d..c8b59e05f 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use crate::common::cell::PyRwLock; use crate::common::hash::PyHash; -use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs, PyNativeFunc}; +use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc}; use crate::pyobject::{ IdProtocol, PyComparisonValue, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -41,9 +41,9 @@ impl Default for PyTpFlags { } } -type GenericFunc = fn(&VirtualMachine, PyFuncArgs) -> PyResult; +type GenericMethod = fn(PyObjectRef, PyFuncArgs, &VirtualMachine) -> PyResult; type DescrGetFunc = - fn(&VirtualMachine, PyObjectRef, Option, OptionalArg) -> PyResult; + fn(PyObjectRef, Option, Option, &VirtualMachine) -> PyResult; type HashFunc = Box PyResult)>; #[derive(Default)] @@ -51,7 +51,7 @@ pub struct PyClassSlots { pub flags: PyTpFlags, pub name: PyRwLock>, // tp_name, not class name pub new: Option, - pub call: AtomicCell>, + pub call: AtomicCell>, pub descr_get: AtomicCell>, pub hash: Option, pub cmp: Option, @@ -80,13 +80,21 @@ impl PyClassSlots { pub(crate) fn update_slot_func(&self, name: &str) { match name { "__call__" => { - let func: GenericFunc = - |vm, args| { IntoPyNativeFunc::call(&call_magic_call, vm, args) } as _; + let func: GenericMethod = |zelf, args, vm| { + let magic = get_class_magic(&zelf, "__call__"); + let magic = vm.call_if_get_descriptor(magic, zelf.clone())?; + vm.invoke(&magic, args) + } as _; self.call.store(Some(func)) } "__get__" => { - let func: DescrGetFunc = - |vm, zelf, obj, cls| { call_magic_descr_get(vm, zelf, obj, cls) } as _; + let func: DescrGetFunc = |zelf, obj, cls, vm| { + let magic = get_class_magic(&zelf, "__get__"); + vm.invoke( + &magic, + vec![zelf, vm.unwrap_or_none(obj), vm.unwrap_or_none(cls)], + ) + } as _; self.descr_get.store(Some(func)) } _ => (), @@ -94,6 +102,16 @@ impl PyClassSlots { } } +#[inline] +fn get_class_magic(zelf: &PyObjectRef, name: &str) -> PyObjectRef { + zelf.get_class_attr(name).unwrap() + + // TODO: we already looked up the matching class but lost the information here + // let cls = zelf.lease_class(); + // let attrs = cls.attributes.read(); + // attrs.get(name).unwrap().clone() +} + impl std::fmt::Debug for PyClassSlots { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("PyClassSlots") @@ -107,53 +125,14 @@ pub trait SlotCall: PyValue { fn call(zelf: PyRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult; } -#[inline] -fn get_class_magic(zelf: &PyObjectRef, name: &str) -> PyObjectRef { - zelf.get_class_attr(name).unwrap() - // let cls = zelf.lease_class(); - // let attrs = cls.attributes.read(); - // let attr = attrs.get(name); - // attr.unwrap().clone() -} - -fn call_magic_call(zelf: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { - let magic = get_class_magic(&zelf, "__call__"); - let magic = vm.call_if_get_descriptor(magic, zelf.clone())?; - args.insert(zelf); - vm.invoke(&magic, args) -} - -fn call_magic_descr_get( - vm: &VirtualMachine, - zelf: PyObjectRef, - obj: Option, - cls: OptionalArg, -) -> PyResult { - let magic = get_class_magic(&zelf, "__get__"); - vm.invoke( - &magic, - vec![ - zelf, - vm.unwrap_or_none(obj), - vm.unwrap_or_none(cls.into_option()), - ], - ) -} - -pub type PyDescrGetFunc = Box< - dyn Fn(&VirtualMachine, PyObjectRef, Option, OptionalArg) -> PyResult - + Send - + Sync, ->; - #[pyimpl] pub trait SlotDescriptor: PyValue { #[pyslot] fn descr_get( - vm: &VirtualMachine, zelf: PyObjectRef, obj: Option, - cls: OptionalArg, + cls: Option, + vm: &VirtualMachine, ) -> PyResult; #[pymethod(magic)] @@ -163,7 +142,7 @@ pub trait SlotDescriptor: PyValue { cls: OptionalArg, vm: &VirtualMachine, ) -> PyResult { - Self::descr_get(vm, zelf, Some(obj), cls) + Self::descr_get(zelf, Some(obj), cls.into_option(), vm) } fn _zelf(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult> { @@ -204,14 +183,11 @@ pub trait SlotDescriptor: PyValue { } } - fn _cls_is(cls: &OptionalArg, other: &T) -> bool + fn _cls_is(cls: &Option, other: &T) -> bool where T: IdProtocol, { - match cls { - OptionalArg::Present(cls) => cls.is(other), - OptionalArg::Missing => false, - } + cls.as_ref().map_or(false, |cls| cls.is(other)) } } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index b84b06555..bcf2157fe 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -23,7 +23,7 @@ use crate::common::{cell::PyMutex, hash::HashSecret, rc::PyRc}; use crate::exceptions::{self, PyBaseException, PyBaseExceptionRef}; use crate::frame::{ExecutionResult, Frame, FrameRef}; use crate::frozen; -use crate::function::{OptionalArg, PyFuncArgs}; +use crate::function::PyFuncArgs; use crate::import; use crate::obj::objbool; use crate::obj::objcode::{PyCode, PyCodeRef}; @@ -844,7 +844,7 @@ impl VirtualMachine { descr .class() .first_in_mro(|cls| cls.slots.descr_get.load()) - .map(|descr_get| descr_get(self, descr, obj, OptionalArg::from_option(cls))) + .map(|descr_get| descr_get(descr, obj, cls, self)) } pub fn call_get_descriptor(&self, descr: PyObjectRef, obj: PyObjectRef) -> Option { @@ -882,21 +882,19 @@ impl VirtualMachine { fn _invoke(&self, callable: &PyObjectRef, args: PyFuncArgs) -> PyResult { vm_trace!("Invoke: {:?} {:?}", callable, args); - let invoked = callable.class().first_in_mro(|cls| { - cls.slots.call.load().map(|slot_call| { + let slot_call = callable.class().first_in_mro(|cls| cls.slots.call.load()); + match slot_call { + Some(slot_call) => { self.trace_event(TraceEvent::Call)?; - let args = args.insert(callable.clone()); - let result = slot_call(self, args); + let result = slot_call(callable.clone(), args, self); self.trace_event(TraceEvent::Return)?; result - }) - }); - invoked.unwrap_or_else(|| { - Err(self.new_type_error(format!( + } + None => Err(self.new_type_error(format!( "'{}' object is not callable", callable.lease_class().name - ))) - }) + ))), + } } #[inline]