From d6acd2ee7d9a4890b3f3b51a7cb7b72383bf467a Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Tue, 21 Mar 2023 21:27:51 +0200 Subject: [PATCH] refactor PyNumberBinaryFunc --- vm/src/builtins/bool.rs | 12 +-- vm/src/builtins/bytearray.rs | 6 +- vm/src/builtins/bytes.rs | 6 +- vm/src/builtins/complex.rs | 24 ++---- vm/src/builtins/dict.rs | 138 ++++++++++---------------------- vm/src/builtins/float.rs | 22 ++--- vm/src/builtins/genericalias.rs | 2 +- vm/src/builtins/int.rs | 32 ++++---- vm/src/builtins/mappingproxy.rs | 12 +-- vm/src/builtins/set.rs | 96 +++++++++------------- vm/src/builtins/str.rs | 7 +- vm/src/builtins/type.rs | 4 +- vm/src/builtins/union.rs | 4 +- vm/src/protocol/number.rs | 81 +++++-------------- vm/src/types/slot.rs | 112 ++++---------------------- vm/src/vm/vm_ops.rs | 47 ++++++----- 16 files changed, 198 insertions(+), 407 deletions(-) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index d5abb3149..d70af0f07 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -164,15 +164,9 @@ impl PyBool { impl AsNumber for PyBool { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - and: Some(|number, other, vm| { - PyBool::and(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) - }), - xor: Some(|number, other, vm| { - PyBool::xor(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) - }), - or: Some(|number, other, vm| { - PyBool::or(number.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) - }), + and: Some(|a, b, vm| PyBool::and(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), + xor: Some(|a, b, vm| PyBool::xor(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), + or: Some(|a, b, vm| PyBool::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyInt::AS_NUMBER }; &AS_NUMBER diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index d0aa435d5..3032b806a 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -843,9 +843,9 @@ impl AsSequence for PyByteArray { impl AsNumber for PyByteArray { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.mod_(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.mod_(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 97b904094..79af94b8a 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -615,9 +615,9 @@ impl AsSequence for PyBytes { impl AsNumber for PyBytes { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.mod_(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.mod_(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 4a15d95c7..ecb19940f 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -8,7 +8,7 @@ use crate::{ PyComparisonValue, }, identifier, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -418,16 +418,10 @@ impl Hashable for PyComplex { impl AsNumber for PyComplex { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a + b, vm) - }), - subtract: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a - b, vm) - }), - multiply: Some(|number, other, vm| { - PyComplex::number_op(number, other, |a, b, _vm| a * b, vm) - }), - power: Some(|number, other, vm| PyComplex::number_op(number, other, inner_pow, vm)), + add: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyComplex::number_op(a, b, |a, b, _vm| a * b, vm)), + power: Some(|a, b, vm| PyComplex::number_op(a, b, inner_pow, vm)), negative: Some(|number, vm| { let value = PyComplex::number_downcast(number).value; (-value).to_pyresult(vm) @@ -440,9 +434,7 @@ impl AsNumber for PyComplex { value.norm().to_pyresult(vm) }), boolean: Some(|number, _vm| Ok(PyComplex::number_downcast(number).value.is_zero())), - true_divide: Some(|number, other, vm| { - PyComplex::number_op(number, other, inner_div, vm) - }), + true_divide: Some(|a, b, vm| PyComplex::number_op(a, b, inner_div, vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -494,12 +486,12 @@ impl Representable for PyComplex { } impl PyComplex { - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(Complex64, Complex64, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (to_op_complex(number.obj, vm)?, to_op_complex(other, vm)?) { + if let (Some(a), Some(b)) = (to_op_complex(a, vm)?, to_op_complex(b, vm)?) { op(a, b, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 237c21876..52092c96f 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -472,16 +472,16 @@ impl AsSequence for PyDict { impl AsNumber for PyDict { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - PyDict::or(num, args.to_pyobject(vm), vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PyDict::or(a, b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - PyDict::ior(num.to_owned(), args.to_pyobject(vm), vm).map(|d| d.into()) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PyDict::ior(a.to_owned(), b.to_pyobject(vm), vm).map(|d| d.into()) } else { Ok(vm.ctx.not_implemented()) } @@ -1169,51 +1169,10 @@ impl AsSequence for PyDictKeys { impl AsNumber for PyDictKeys { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .difference(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - and: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .intersection(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - xor: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.symmetric_difference( - ArgIterable::try_from_object(vm, args.to_owned())?, - vm, - )?, - } - .into_pyobject(vm)) - }), - or: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.union(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), + subtract: Some(set_inner_number_subtract), + and: Some(set_inner_number_and), + xor: Some(set_inner_number_xor), + or: Some(set_inner_number_or), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -1288,51 +1247,10 @@ impl AsSequence for PyDictItems { impl AsNumber for PyDictItems { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .difference(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - and: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num - .intersection(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), - xor: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.symmetric_difference( - ArgIterable::try_from_object(vm, args.to_owned())?, - vm, - )?, - } - .into_pyobject(vm)) - }), - or: Some(|num, args, vm| { - let num = PySetInner::from_iter( - ArgIterable::try_from_object(vm, num.obj.to_owned())?.iter(vm)?, - vm, - )?; - Ok(PySet { - inner: num.union(ArgIterable::try_from_object(vm, args.to_owned())?, vm)?, - } - .into_pyobject(vm)) - }), + subtract: Some(set_inner_number_subtract), + and: Some(set_inner_number_and), + xor: Some(set_inner_number_xor), + or: Some(set_inner_number_or), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -1358,6 +1276,34 @@ impl AsSequence for PyDictValues { } } +fn set_inner_number_op(a: &PyObject, b: &PyObject, f: F, vm: &VirtualMachine) -> PyResult +where + F: FnOnce(PySetInner, ArgIterable) -> PyResult, +{ + let a = PySetInner::from_iter( + ArgIterable::try_from_object(vm, a.to_owned())?.iter(vm)?, + vm, + )?; + let b = ArgIterable::try_from_object(vm, b.to_owned())?; + Ok(PySet { inner: f(a, b)? }.into_pyobject(vm)) +} + +fn set_inner_number_subtract(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + set_inner_number_op(a, b, |a, b| a.difference(b, vm), vm) +} + +fn set_inner_number_and(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + set_inner_number_op(a, b, |a, b| a.intersection(b, vm), vm) +} + +fn set_inner_number_xor(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + set_inner_number_op(a, b, |a, b| a.symmetric_difference(b, vm), vm) +} + +fn set_inner_number_or(a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult { + set_inner_number_op(a, b, |a, b| a.union(b, vm), vm) +} + pub(crate) fn init(context: &Context) { PyDict::extend_class(context, context.types.dict_type); PyDictKeys::extend_class(context, context.types.dict_keys_type); diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index e193f87ff..2d3cfbbf5 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -13,7 +13,7 @@ use crate::{ PyArithmeticValue::{self, *}, PyComparisonValue, }, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Callable, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, @@ -544,12 +544,12 @@ impl Hashable for PyFloat { impl AsNumber for PyFloat { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a + b, vm)), - subtract: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a - b, vm)), - multiply: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a * b, vm)), - remainder: Some(|num, other, vm| PyFloat::number_op(num, other, inner_mod, vm)), - divmod: Some(|num, other, vm| PyFloat::number_op(num, other, inner_divmod, vm)), - power: Some(|num, other, vm| PyFloat::number_op(num, other, float_pow, vm)), + add: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyFloat::number_op(a, b, |a, b, _vm| a * b, vm)), + remainder: Some(|a, b, vm| PyFloat::number_op(a, b, inner_mod, vm)), + divmod: Some(|a, b, vm| PyFloat::number_op(a, b, inner_divmod, vm)), + power: Some(|a, b, vm| PyFloat::number_op(a, b, float_pow, vm)), negative: Some(|num, vm| { let value = PyFloat::number_downcast(num).value; (-value).to_pyresult(vm) @@ -565,8 +565,8 @@ impl AsNumber for PyFloat { try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x)) }), float: Some(|num, vm| Ok(PyFloat::number_downcast_exact(num, vm))), - floor_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_floordiv, vm)), - true_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_div, vm)), + floor_divide: Some(|a, b, vm| PyFloat::number_op(a, b, inner_floordiv, vm)), + true_divide: Some(|a, b, vm| PyFloat::number_op(a, b, inner_div, vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER @@ -586,12 +586,12 @@ impl Representable for PyFloat { } impl PyFloat { - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(f64, f64, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (to_op_float(number.obj, vm)?, to_op_float(other, vm)?) { + if let (Some(a), Some(b)) = (to_op_float(a, vm)?, to_op_float(b, vm)?) { op(a, b, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index 9ed18901f..d17091176 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -345,7 +345,7 @@ impl AsMapping for PyGenericAlias { impl AsNumber for PyGenericAlias { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|a, b, vm| Ok(PyGenericAlias::or(a.obj.to_owned(), b.to_owned(), vm))), + or: Some(|a, b, vm| Ok(PyGenericAlias::or(a.to_owned(), b.to_owned(), vm))), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 6a169cc2f..f46047f67 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -13,7 +13,7 @@ use crate::{ ArgByteOrder, ArgIntoBool, OptionalArg, OptionalOption, PyArithmeticValue, PyComparisonValue, }, - protocol::{PyNumber, PyNumberMethods}, + protocol::PyNumberMethods, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine, @@ -743,39 +743,39 @@ impl AsNumber for PyInt { impl PyInt { pub(super) const AS_NUMBER: PyNumberMethods = PyNumberMethods { - add: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a + b, vm)), - subtract: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a - b, vm)), - multiply: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a * b, vm)), - remainder: Some(|num, other, vm| PyInt::number_op(num, other, inner_mod, vm)), - divmod: Some(|num, other, vm| PyInt::number_op(num, other, inner_divmod, vm)), - power: Some(|num, other, vm| PyInt::number_op(num, other, inner_pow, vm)), + add: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a + b, vm)), + subtract: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a - b, vm)), + multiply: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a * b, vm)), + remainder: Some(|a, b, vm| PyInt::number_op(a, b, inner_mod, vm)), + divmod: Some(|a, b, vm| PyInt::number_op(a, b, inner_divmod, vm)), + power: Some(|a, b, vm| PyInt::number_op(a, b, inner_pow, vm)), negative: Some(|num, vm| (&PyInt::number_downcast(num).value).neg().to_pyresult(vm)), positive: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm).into())), absolute: Some(|num, vm| PyInt::number_downcast(num).value.abs().to_pyresult(vm)), boolean: Some(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())), invert: Some(|num, vm| (&PyInt::number_downcast(num).value).not().to_pyresult(vm)), - lshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_lshift, vm)), - rshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_rshift, vm)), - and: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a & b, vm)), - xor: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a ^ b, vm)), - or: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a | b, vm)), + lshift: Some(|a, b, vm| PyInt::number_op(a, b, inner_lshift, vm)), + rshift: Some(|a, b, vm| PyInt::number_op(a, b, inner_rshift, vm)), + and: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a & b, vm)), + xor: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a ^ b, vm)), + or: Some(|a, b, vm| PyInt::number_op(a, b, |a, b, _vm| a | b, vm)), int: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))), float: Some(|num, vm| { let zelf = PyInt::number_downcast(num); try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x)) }), - floor_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_floordiv, vm)), - true_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_truediv, vm)), + floor_divide: Some(|a, b, vm| PyInt::number_op(a, b, inner_floordiv, vm)), + true_divide: Some(|a, b, vm| PyInt::number_op(a, b, inner_truediv, vm)), index: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))), ..PyNumberMethods::NOT_IMPLEMENTED }; - fn number_op(number: PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_op(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult where F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (number.obj.payload::(), other.payload::()) { + if let (Some(a), Some(b)) = (a.payload::(), b.payload::()) { op(&a.value, &b.value, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 18986d56e..d0659ddf5 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -238,16 +238,16 @@ impl AsSequence for PyMappingProxy { impl AsNumber for PyMappingProxy { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - num.or(args.to_pyobject(vm), vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|num, args, vm| { - if let Some(num) = num.obj.downcast_ref::() { - num.ior(args.to_pyobject(vm), vm) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.ior(b.to_pyobject(vm), vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index a81f8db1d..3e8546cb3 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -794,78 +794,62 @@ impl Iterable for PySet { impl AsNumber for PySet { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.sub(other.to_owned(), vm).to_pyresult(vm) + subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.sub(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.and(other.to_owned(), vm).to_pyresult(vm) + and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.and(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.xor(other.to_owned(), vm).to_pyresult(vm) + xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.xor(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.or(other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::isub( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::isub(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::iand( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::iand(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::ixor( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::ixor(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - inplace_or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - PySet::ior( - number.to_owned(), - AnySet::try_from_object(vm, other.to_owned())?, - vm, - ) - .to_pyresult(vm) + inplace_or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + PySet::ior(a.to_owned(), AnySet::try_from_object(vm, b.to_owned())?, vm) + .to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } @@ -1133,30 +1117,30 @@ impl Iterable for PyFrozenSet { impl AsNumber for PyFrozenSet { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - subtract: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.sub(other.to_owned(), vm).to_pyresult(vm) + subtract: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.sub(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - and: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.and(other.to_owned(), vm).to_pyresult(vm) + and: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.and(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - xor: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.xor(other.to_owned(), vm).to_pyresult(vm) + xor: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.xor(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } }), - or: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.or(other.to_owned(), vm).to_pyresult(vm) + or: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.or(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index efd8e2a49..2539007ca 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -1337,9 +1337,9 @@ impl AsMapping for PyStr { impl AsNumber for PyStr { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - remainder: Some(|number, other, vm| { - if let Some(number) = number.obj.downcast_ref::() { - number.modulo(other.to_owned(), vm).to_pyresult(vm) + remainder: Some(|a, b, vm| { + if let Some(a) = a.downcast_ref::() { + a.modulo(b.to_owned(), vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) } @@ -1577,7 +1577,6 @@ impl AsRef for PyExact { mod tests { use super::*; use crate::Interpreter; - use std::ops::Deref; #[test] fn str_title() { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 133215828..e9feaee7d 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1089,9 +1089,7 @@ impl Callable for PyType { impl AsNumber for PyType { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, other, vm| { - or_(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) - }), + or: Some(|a, b, vm| or_(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER diff --git a/vm/src/builtins/union.rs b/vm/src/builtins/union.rs index 263c6a1f2..fda9d255b 100644 --- a/vm/src/builtins/union.rs +++ b/vm/src/builtins/union.rs @@ -252,9 +252,7 @@ impl AsMapping for PyUnion { impl AsNumber for PyUnion { fn as_number() -> &'static PyNumberMethods { static AS_NUMBER: PyNumberMethods = PyNumberMethods { - or: Some(|num, other, vm| { - PyUnion::or(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm) - }), + or: Some(|a, b, vm| PyUnion::or(a.to_owned(), b.to_owned(), vm).to_pyresult(vm)), ..PyNumberMethods::NOT_IMPLEMENTED }; &AS_NUMBER diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 10b56ce36..981b43945 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -1,7 +1,7 @@ +use std::ops::Deref; + use crate::{ - builtins::{ - int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, - }, + builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr}, common::int::bytes_to_int, function::ArgBytesLike, stdlib::warnings, @@ -10,12 +10,12 @@ use crate::{ }; pub type PyNumberUnaryFunc = fn(PyNumber, &VirtualMachine) -> PyResult; -pub type PyNumberBinaryFunc = fn(PyNumber, &PyObject, &VirtualMachine) -> PyResult; +pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult; impl PyObject { #[inline] - pub fn to_number(&self) -> PyNumber<'_> { - PyNumber::from(self) + pub fn to_number(&self) -> PyNumber { + PyNumber(self) } pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { @@ -197,39 +197,6 @@ impl PyNumberMethods { matrix_multiply: None, inplace_matrix_multiply: None, }; - - pub fn binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { - use PyNumberBinaryOp::*; - match op_slot { - Add => self.add, - Subtract => self.subtract, - Multiply => self.multiply, - Remainder => self.remainder, - Divmod => self.divmod, - Power => self.power, - Lshift => self.lshift, - Rshift => self.rshift, - And => self.and, - Xor => self.xor, - Or => self.or, - InplaceAdd => self.inplace_add, - InplaceSubtract => self.inplace_subtract, - InplaceMultiply => self.inplace_multiply, - InplaceRemainder => self.inplace_remainder, - InplacePower => self.inplace_power, - InplaceLshift => self.inplace_lshift, - InplaceRshift => self.inplace_rshift, - InplaceAnd => self.inplace_and, - InplaceXor => self.inplace_xor, - InplaceOr => self.inplace_or, - FloorDivide => self.floor_divide, - TrueDivide => self.true_divide, - InplaceFloorDivide => self.inplace_floor_divide, - InplaceTrueDivide => self.inplace_true_divide, - MatrixMultiply => self.matrix_multiply, - InplaceMatrixMultiply => self.inplace_matrix_multiply, - } - } } #[derive(Copy, Clone)] @@ -264,25 +231,19 @@ pub enum PyNumberBinaryOp { } #[derive(Copy, Clone)] -pub struct PyNumber<'a> { - pub obj: &'a PyObject, - pub(crate) methods: &'a PyNumberMethods, -} +pub struct PyNumber<'a>(&'a PyObject); -impl<'a> From<&'a PyObject> for PyNumber<'a> { - fn from(obj: &'a PyObject) -> Self { - static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; - Self { - obj, - methods: Self::find_methods(obj) - .map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }), - } +impl<'a> Deref for PyNumber<'a> { + type Target = PyObject; + + fn deref(&self) -> &Self::Target { + self.0 } } -impl PyNumber<'_> { - fn find_methods(obj: &PyObject) -> Option> { - obj.class().mro_find_map(|x| x.slots.as_number.load()) +impl<'a> PyNumber<'a> { + pub(crate) fn obj(self) -> &'a PyObject { + self.0 } // PyNumber_Check @@ -293,15 +254,17 @@ impl PyNumber<'_> { || methods.float.load().is_some() || obj.payload_is::() } +} +impl PyNumber<'_> { // PyIndex_Check - pub fn is_index(&self) -> bool { - self.obj.class().slots.number.index.load().is_some() + pub fn is_index(self) -> bool { + self.class().slots.number.index.load().is_some() } #[inline] pub fn int(self, vm: &VirtualMachine) -> Option> { - self.obj.class().slots.number.int.load().map(|f| { + self.class().slots.number.int.load().map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyInt::class(&vm.ctx)) { warnings::warn( @@ -325,7 +288,7 @@ impl PyNumber<'_> { #[inline] pub fn index(self, vm: &VirtualMachine) -> Option> { - self.obj.class().slots.number.index.load().map(|f| { + self.class().slots.number.index.load().map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyInt::class(&vm.ctx)) { warnings::warn( @@ -349,7 +312,7 @@ impl PyNumber<'_> { #[inline] pub fn float(self, vm: &VirtualMachine) -> Option>> { - self.obj.class().slots.number.float.load().map(|f| { + self.class().slots.number.float.load().map(|f| { let ret = f(self, vm)?; let value = if !ret.class().is(PyFloat::class(&vm.ctx)) { warnings::warn( diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index d1b304d2c..8205c78b8 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -16,7 +16,7 @@ use crate::{ }; use crossbeam_utils::atomic::AtomicCell; use num_traits::{Signed, ToPrimitive}; -use std::{borrow::Borrow, cmp::Ordering}; +use std::{borrow::Borrow, cmp::Ordering, ops::Deref}; #[macro_export] macro_rules! atomic_func { @@ -168,12 +168,9 @@ pub struct PyNumberSlots { } impl PyNumberSlots { - pub fn left_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { + pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { use PyNumberBinaryOp::*; - let binary_op = match op_slot { + match op_slot { Add => self.add.load(), Subtract => self.subtract.load(), Multiply => self.multiply.load(), @@ -201,16 +198,12 @@ impl PyNumberSlots { InplaceTrueDivide => self.inplace_true_divide.load(), MatrixMultiply => self.matrix_multiply.load(), InplaceMatrixMultiply => self.inplace_matrix_multiply.load(), - }; - Ok(binary_op) + } } - pub fn right_binary_op( - &self, - op_slot: PyNumberBinaryOp, - ) -> PyResult> { + pub fn right_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { use PyNumberBinaryOp::*; - let binary_op = match op_slot { + match op_slot { Add => self.right_add.load(), Subtract => self.right_subtract.load(), Multiply => self.right_multiply.load(), @@ -226,8 +219,7 @@ impl PyNumberSlots { TrueDivide => self.right_true_divide.load(), MatrixMultiply => self.right_matrix_multiply.load(), _ => None, - }; - Ok(binary_op) + } } } @@ -321,21 +313,21 @@ pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult PyResult> { - let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?; + let ret = vm.call_special_method(num.deref().to_owned(), 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.obj.to_owned(), identifier!(vm, __index__), ())?; + let ret = vm.call_special_method(num.deref().to_owned(), 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.obj.to_owned(), identifier!(vm, __float__), ())?; + let ret = vm.call_special_method(num.deref().to_owned(), identifier!(vm, __float__), ())?; ret.downcast::().map_err(|obj| { vm.new_type_error(format!( "__float__ returned non-float (type {})", @@ -348,7 +340,7 @@ macro_rules! number_binary_op_wrapper { ($name:ident) => { |num, other, vm| { vm.call_special_method( - num.obj.to_owned(), + num.deref().to_owned(), identifier!(vm, $name), (other.to_owned(),), ) @@ -1314,26 +1306,6 @@ pub trait AsSequence: PyPayload { } } -macro_rules! extend_number_slot { - ($slots:ident, $methods:ident, $method:ident, $right_method:ident, $op_slot:ident) => { - if $methods.$method.is_some() { - $slots.number.$method.store($methods.$method); - $slots.number.$right_method.store(Some(|num, other, vm| { - num.methods.binary_op(PyNumberBinaryOp::$op_slot).unwrap()( - other.to_number(), - num.obj, - vm, - ) - })); - } - }; - ($slots:ident, $methods:ident, $method:ident) => { - if $methods.$method.is_some() { - $slots.number.$method.store($methods.$method); - } - }; -} - #[pyclass] pub trait AsNumber: PyPayload { #[pyslot] @@ -1346,71 +1318,17 @@ pub trait AsNumber: PyPayload { #[inline] fn number_downcast(num: PyNumber) -> &Py { - unsafe { num.obj.downcast_unchecked_ref() } + unsafe { num.obj().downcast_unchecked_ref() } } #[inline] - fn number_downcast_exact(number: PyNumber, vm: &VirtualMachine) -> PyRef { - if let Some(zelf) = number.obj.downcast_ref_if_exact::(vm) { + fn number_downcast_exact(num: PyNumber, vm: &VirtualMachine) -> PyRef { + if let Some(zelf) = num.downcast_ref_if_exact::(vm) { zelf.to_owned() } else { - Self::clone_exact(Self::number_downcast(number), vm) + Self::clone_exact(Self::number_downcast(num), vm) } } - - fn extend_slots(slots: &mut PyTypeSlots) { - let methods = Self::as_number(); - - extend_number_slot!(slots, methods, add, right_add, Add); - extend_number_slot!(slots, methods, subtract, right_subtract, Subtract); - extend_number_slot!(slots, methods, multiply, right_multiply, Multiply); - extend_number_slot!(slots, methods, remainder, right_remainder, Remainder); - extend_number_slot!(slots, methods, divmod, right_divmod, Divmod); - extend_number_slot!(slots, methods, power, right_power, Power); - extend_number_slot!(slots, methods, lshift, right_lshift, Lshift); - extend_number_slot!(slots, methods, rshift, right_rshift, Rshift); - extend_number_slot!(slots, methods, and, right_and, And); - extend_number_slot!(slots, methods, xor, right_xor, Xor); - extend_number_slot!(slots, methods, or, right_or, Or); - extend_number_slot!( - slots, - methods, - floor_divide, - right_floor_divide, - FloorDivide - ); - extend_number_slot!(slots, methods, true_divide, right_true_divide, TrueDivide); - extend_number_slot!( - slots, - methods, - matrix_multiply, - right_matrix_multiply, - MatrixMultiply - ); - - extend_number_slot!(slots, methods, negative); - extend_number_slot!(slots, methods, positive); - extend_number_slot!(slots, methods, absolute); - extend_number_slot!(slots, methods, boolean); - extend_number_slot!(slots, methods, invert); - extend_number_slot!(slots, methods, int); - extend_number_slot!(slots, methods, float); - extend_number_slot!(slots, methods, index); - - extend_number_slot!(slots, methods, inplace_add); - extend_number_slot!(slots, methods, inplace_subtract); - extend_number_slot!(slots, methods, inplace_multiply); - extend_number_slot!(slots, methods, inplace_remainder); - extend_number_slot!(slots, methods, inplace_power); - extend_number_slot!(slots, methods, inplace_lshift); - extend_number_slot!(slots, methods, inplace_rshift); - extend_number_slot!(slots, methods, inplace_and); - extend_number_slot!(slots, methods, inplace_xor); - extend_number_slot!(slots, methods, inplace_or); - extend_number_slot!(slots, methods, inplace_floor_divide); - extend_number_slot!(slots, methods, inplace_true_divide); - extend_number_slot!(slots, methods, inplace_matrix_multiply); - } } #[pyclass] diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index ccc77b440..ab5b59772 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -132,40 +132,39 @@ impl VirtualMachine { /// /// [*] only when Py_TYPE(a) != Py_TYPE(b) && Py_TYPE(b) is a subclass of Py_TYPE(a) pub fn binary_op1(&self, a: &PyObject, b: &PyObject, op_slot: PyNumberBinaryOp) -> PyResult { - let slot_a = a.class().slots.number.left_binary_op(op_slot)?; - let mut slot_b = if b.class().is(a.class()) { - None - } else { - match b.class().slots.number.right_binary_op(op_slot)? { - Some(slot_b) - if slot_b as usize == slot_a.map(|s| s as usize).unwrap_or_default() => - { - None - } - slot_b => slot_b, + let class_a = a.class(); + let class_b = b.class(); + + let slot_a = class_a.slots.number.left_binary_op(op_slot); + let mut slot_b = None; + + if !class_a.is(class_b) { + let slot_bb = class_b.slots.number.right_binary_op(op_slot); + if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) { + slot_b = slot_bb; } - }; + } if let Some(slot_a) = slot_a { if let Some(slot_bb) = slot_b { - if b.fast_isinstance(a.class()) { - let x = slot_bb(b.to_number(), a, self)?; - if !x.is(&self.ctx.not_implemented) { - return Ok(x); + if class_b.fast_issubclass(class_a) { + let ret = slot_bb(a, b, self)?; + if !ret.is(&self.ctx.not_implemented) { + return Ok(ret); } slot_b = None; } } - let x = slot_a(a.to_number(), b, self)?; - if !x.is(&self.ctx.not_implemented) { - return Ok(x); + let ret = slot_a(a, b, self)?; + if !ret.is(&self.ctx.not_implemented) { + return Ok(ret); } } if let Some(slot_b) = slot_b { - let x = slot_b(b.to_number(), a, self)?; - if !x.is(&self.ctx.not_implemented) { - return Ok(x); + let ret = slot_b(a, b, self)?; + if !ret.is(&self.ctx.not_implemented) { + return Ok(ret); } } @@ -206,8 +205,8 @@ impl VirtualMachine { iop_slot: PyNumberBinaryOp, op_slot: PyNumberBinaryOp, ) -> PyResult { - if let Some(slot) = a.class().slots.number.left_binary_op(iop_slot)? { - let x = slot(a.to_number(), b, self)?; + if let Some(slot) = a.class().slots.number.left_binary_op(iop_slot) { + let x = slot(a, b, self)?; if !x.is(&self.ctx.not_implemented) { return Ok(x); }