diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 16a6e2891..cc0535707 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -16,8 +16,8 @@ use crate::{ scope::Scope, stdlib::builtins, types::PyComparisonOp, - AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, - VirtualMachine, + vm::PyMethod, + AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, }; use indexmap::IndexMap; use itertools::Itertools; diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 4fd9abd71..e7b60b6cb 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -78,7 +78,7 @@ pub mod vm; pub use self::convert::{TryFromBorrowedObject, TryFromObject}; // pyobject items -pub use self::object::{AsObject, PyMethod, PyPayload, PyRefExact, PyResult}; +pub use self::object::{AsObject, PyPayload, PyRefExact, PyResult}; // pyobjectrc items pub use self::object::{Py, PyObject, PyObjectRef, PyRef, PyWeakRef}; pub use self::types::PyStructSequence; diff --git a/vm/src/object/ext.rs b/vm/src/object/ext.rs index 6c3c6b4f6..762e72869 100644 --- a/vm/src/object/ext.rs +++ b/vm/src/object/ext.rs @@ -4,10 +4,8 @@ use super::{ }; use crate::common::lock::PyRwLockReadGuard; use crate::{ - builtins::{object, pystr, PyBaseExceptionRef, PyType}, + builtins::{PyBaseExceptionRef, PyType}, convert::{ToPyObject, ToPyResult, TryFromObject}, - function::IntoFuncArgs, - types::PyTypeFlags, VirtualMachine, }; use std::{borrow::Borrow, fmt, ops::Deref}; @@ -276,151 +274,3 @@ where self.map(|res| T::to_pyobject(res, vm)) } } - -pub trait PyObjectWrap -where - Self: AsObject, -{ - fn into_object(self) -> PyObjectRef; -} - -impl From for PyObjectRef -where - T: PyObjectWrap, -{ - #[inline(always)] - fn from(py_ref: T) -> Self { - py_ref.into_object() - } -} - -#[derive(Debug)] -pub enum PyMethod { - Function { - target: PyObjectRef, - func: PyObjectRef, - }, - Attribute(PyObjectRef), -} - -impl PyMethod { - pub fn get(obj: PyObjectRef, name: pystr::PyStrRef, vm: &VirtualMachine) -> PyResult { - let cls = obj.class(); - let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap(); - if getattro as usize != object::PyBaseObject::getattro as usize { - drop(cls); - return obj.get_attr(name, vm).map(Self::Attribute); - } - - let mut is_method = false; - - let cls_attr = match cls.get_attr(name.as_str()) { - Some(descr) => { - let descr_cls = descr.class(); - let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) { - is_method = true; - None - } else { - let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load()); - if let Some(descr_get) = descr_get { - if descr_cls - .mro_find_map(|cls| cls.slots.descr_set.load()) - .is_some() - { - drop(descr_cls); - let cls = cls.into_owned().into(); - return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute); - } - } - descr_get - }; - drop(descr_cls); - Some((descr, descr_get)) - } - None => None, - }; - - if let Some(dict) = obj.dict() { - if let Some(attr) = dict.get_item_opt(name.clone(), vm)? { - return Ok(Self::Attribute(attr)); - } - } - - if let Some((attr, descr_get)) = cls_attr { - match descr_get { - None if is_method => { - drop(cls); - Ok(Self::Function { - target: obj, - func: attr, - }) - } - Some(descr_get) => { - let cls = cls.into_owned().into(); - descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute) - } - None => Ok(Self::Attribute(attr)), - } - } else if let Some(getter) = cls.get_attr("__getattr__") { - drop(cls); - vm.invoke(&getter, (obj, name)).map(Self::Attribute) - } else { - let exc = vm.new_attribute_error(format!( - "'{}' object has no attribute '{}'", - cls.name(), - name - )); - vm.set_attribute_error_context(&exc, obj.clone(), name); - Err(exc) - } - } - - pub(crate) fn get_special( - obj: PyObjectRef, - name: &str, - vm: &VirtualMachine, - ) -> PyResult> { - let obj_cls = obj.class(); - let func = match obj_cls.get_attr(name) { - Some(f) => f, - None => { - drop(obj_cls); - return Ok(Err(obj)); - } - }; - let meth = if func - .class() - .slots - .flags - .has_feature(PyTypeFlags::METHOD_DESCR) - { - drop(obj_cls); - Self::Function { target: obj, func } - } else { - let obj_cls = obj_cls.into_owned().into(); - let attr = vm - .call_get_descriptor_specific(func, Some(obj), Some(obj_cls)) - .unwrap_or_else(Ok)?; - Self::Attribute(attr) - }; - Ok(Ok(meth)) - } - - pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { - let (func, args) = match self { - PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)), - PyMethod::Attribute(func) => (func, args.into_args(vm)), - }; - vm.invoke(&func, args) - } - - pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { - let (func, args) = match self { - PyMethod::Function { target, func } => { - (func, args.into_method_args(target.clone(), vm)) - } - PyMethod::Attribute(func) => (func, args.into_args(vm)), - }; - vm.invoke(func, args) - } -} diff --git a/vm/src/vm/method.rs b/vm/src/vm/method.rs new file mode 100644 index 000000000..1a0fc4415 --- /dev/null +++ b/vm/src/vm/method.rs @@ -0,0 +1,142 @@ +//! This module will be replaced once #3100 is done +//! Do not expose this type to outside of this crate + +use super::VirtualMachine; +use crate::{ + builtins::{PyBaseObject, PyStrRef}, + function::IntoFuncArgs, + object::{AsObject, PyObjectRef, PyResult}, + types::PyTypeFlags, +}; + +#[derive(Debug)] +pub enum PyMethod { + Function { + target: PyObjectRef, + func: PyObjectRef, + }, + Attribute(PyObjectRef), +} + +impl PyMethod { + pub fn get(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult { + let cls = obj.class(); + let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap(); + if getattro as usize != PyBaseObject::getattro as usize { + drop(cls); + return obj.get_attr(name, vm).map(Self::Attribute); + } + + let mut is_method = false; + + let cls_attr = match cls.get_attr(name.as_str()) { + Some(descr) => { + let descr_cls = descr.class(); + let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) { + is_method = true; + None + } else { + let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load()); + if let Some(descr_get) = descr_get { + if descr_cls + .mro_find_map(|cls| cls.slots.descr_set.load()) + .is_some() + { + drop(descr_cls); + let cls = cls.into_owned().into(); + return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute); + } + } + descr_get + }; + drop(descr_cls); + Some((descr, descr_get)) + } + None => None, + }; + + if let Some(dict) = obj.dict() { + if let Some(attr) = dict.get_item_opt(name.clone(), vm)? { + return Ok(Self::Attribute(attr)); + } + } + + if let Some((attr, descr_get)) = cls_attr { + match descr_get { + None if is_method => { + drop(cls); + Ok(Self::Function { + target: obj, + func: attr, + }) + } + Some(descr_get) => { + let cls = cls.into_owned().into(); + descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute) + } + None => Ok(Self::Attribute(attr)), + } + } else if let Some(getter) = cls.get_attr("__getattr__") { + drop(cls); + vm.invoke(&getter, (obj, name)).map(Self::Attribute) + } else { + let exc = vm.new_attribute_error(format!( + "'{}' object has no attribute '{}'", + cls.name(), + name + )); + vm.set_attribute_error_context(&exc, obj.clone(), name); + Err(exc) + } + } + + pub(crate) fn get_special( + obj: PyObjectRef, + name: &str, + vm: &VirtualMachine, + ) -> PyResult> { + let obj_cls = obj.class(); + let func = match obj_cls.get_attr(name) { + Some(f) => f, + None => { + drop(obj_cls); + return Ok(Err(obj)); + } + }; + let meth = if func + .class() + .slots + .flags + .has_feature(PyTypeFlags::METHOD_DESCR) + { + drop(obj_cls); + Self::Function { target: obj, func } + } else { + let obj_cls = obj_cls.into_owned().into(); + let attr = vm + .call_get_descriptor_specific(func, Some(obj), Some(obj_cls)) + .unwrap_or_else(Ok)?; + Self::Attribute(attr) + }; + Ok(Ok(meth)) + } + + pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { + let (func, args) = match self { + PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)), + PyMethod::Attribute(func) => (func, args.into_args(vm)), + }; + vm.invoke(&func, args) + } + + #[allow(dead_code)] + pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { + let (func, args) = match self { + PyMethod::Function { target, func } => { + (func, args.into_method_args(target.clone(), vm)) + } + PyMethod::Attribute(func) => (func, args.into_args(vm)), + }; + vm.invoke(func, args) + } +} diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index a07dbae8b..f9daf77a4 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -7,6 +7,7 @@ mod compile; mod context; mod interpreter; +mod method; mod setting; pub mod thread; mod vm_new; @@ -42,6 +43,7 @@ use std::{ pub use context::Context; pub use interpreter::Interpreter; +pub(crate) use method::PyMethod; pub use setting::Settings; // Objects are live when they are on stack, or referenced by a name (for now) diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index 02849e9ed..4c98a4c08 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -1,8 +1,9 @@ +use super::PyMethod; use crate::{ builtins::{PyBaseExceptionRef, PyList, PyStr}, function::{FuncArgs, IntoFuncArgs}, + object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult}, vm::VirtualMachine, - AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyResult, }; /// Trace events for sys.settrace and sys.setprofile. diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 0a3d9738b..dc10479a2 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -1,10 +1,10 @@ +use super::{PyMethod, VirtualMachine}; use crate::{ builtins::{PyInt, PyIntRef}, function::PyArithmeticValue, + object::{AsObject, PyObject, PyObjectRef, PyResult}, protocol::PyIterReturn, types::PyComparisonOp, - vm::VirtualMachine, - AsObject, PyMethod, PyObject, PyObjectRef, PyResult, }; /// Collection of operators