From bc2bb1023d8931bc98881497d6971d52aecc611c Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 22 Sep 2021 02:40:22 +0900 Subject: [PATCH 1/3] try to types utility functions to PyObjectRef methods --- vm/src/builtins/complex.rs | 2 +- vm/src/builtins/float.rs | 56 ++++++++++++++++++++------------------ vm/src/builtins/int.rs | 12 ++++---- vm/src/builtins/mod.rs | 3 ++ vm/src/builtins/pybool.rs | 8 +++++- vm/src/bytesinner.rs | 10 +++---- vm/src/byteslike.rs | 46 +++++++++++++++++-------------- vm/src/cformat.rs | 18 ++++++------ vm/src/stdlib/array.rs | 6 ++-- vm/src/stdlib/math.rs | 17 ++++++------ 10 files changed, 96 insertions(+), 82 deletions(-) diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 203c7075fb..d56bfad0c2 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -446,7 +446,7 @@ fn try_complex(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult(vm) { return Ok(Some((complex.value, true))); } - if let Some(float) = float::try_float_opt(obj, vm)? { + if let Some(float) = obj.try_to_f64(vm)? { return Ok(Some((Complex64::new(float, 0.0), false))); } Ok(None) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 3e9f37ae50..72c70e937c 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -1,4 +1,4 @@ -use super::{int, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef}; +use super::{try_bigint_to_f64, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef}; use crate::common::{float_ops, hash}; use crate::format::FormatSpec; use crate::function::{OptionalArg, OptionalOption}; @@ -51,29 +51,31 @@ impl From for PyFloat { } } -pub fn try_float_opt(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult> { - if let Some(float) = obj.payload_if_exact::(vm) { - return Ok(Some(float.value)); - } - if let Some(method) = vm.get_method(obj.clone(), "__float__") { - let result = vm.invoke(&method?, ())?; - // TODO: returning strict subclasses of float in __float__ is deprecated - return match result.payload::() { - Some(float_obj) => Ok(Some(float_obj.value)), - None => Err(vm.new_type_error(format!( - "__float__ returned non-float (type '{}')", - result.class().name() - ))), - }; - } - if let Some(r) = vm.to_index_opt(obj.clone()).transpose()? { - return Ok(Some(int::to_float(r.as_bigint(), vm)?)); +impl PyObjectRef { + pub fn try_to_f64(&self, vm: &VirtualMachine) -> PyResult> { + if let Some(float) = self.payload_if_exact::(vm) { + return Ok(Some(float.value)); + } + if let Some(method) = vm.get_method(self.clone(), "__float__") { + let result = vm.invoke(&method?, ())?; + // TODO: returning strict subclasses of float in __float__ is deprecated + return match result.payload::() { + Some(float_obj) => Ok(Some(float_obj.value)), + None => Err(vm.new_type_error(format!( + "__float__ returned non-float (type '{}')", + result.class().name() + ))), + }; + } + if let Some(r) = vm.to_index_opt(self.clone()).transpose()? { + return Ok(Some(try_bigint_to_f64(r.as_bigint(), vm)?)); + } + Ok(None) } - Ok(None) } pub fn try_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult { - try_float_opt(obj, vm)?.ok_or_else(|| { + obj.try_to_f64(vm)?.ok_or_else(|| { vm.new_type_error(format!("must be real number, not {}", obj.class().name())) }) } @@ -82,7 +84,7 @@ pub(crate) fn to_op_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult(vm) { Some(float.value) } else if let Some(int) = obj.payload_if_subclass::(vm) { - Some(int::to_float(int.as_bigint(), vm)?) + Some(try_bigint_to_f64(int.as_bigint(), vm)?) } else { None }; @@ -111,7 +113,7 @@ fn inner_mod(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult { .ok_or_else(|| vm.new_zero_division_error("float mod by zero".to_owned())) } -pub fn try_bigint(value: f64, vm: &VirtualMachine) -> PyResult { +pub fn try_to_bigint(value: f64, vm: &VirtualMachine) -> PyResult { match value.to_bigint() { Some(int) => Ok(int), None => { @@ -171,7 +173,7 @@ impl SlotConstructor for PyFloat { val }; - if let Some(f) = try_float_opt(&val, vm)? { + if let Some(f) = val.try_to_f64(vm)? { f } else if let Some(s) = val.payload_if_subclass::(vm) { float_ops::parse_str(s.as_str().trim()).ok_or_else(|| { @@ -379,17 +381,17 @@ impl PyFloat { #[pymethod(magic)] fn trunc(&self, vm: &VirtualMachine) -> PyResult { - try_bigint(self.value, vm) + try_to_bigint(self.value, vm) } #[pymethod(magic)] fn floor(&self, vm: &VirtualMachine) -> PyResult { - try_bigint(self.value.floor(), vm) + try_to_bigint(self.value.floor(), vm) } #[pymethod(magic)] fn ceil(&self, vm: &VirtualMachine) -> PyResult { - try_bigint(self.value.ceil(), vm) + try_to_bigint(self.value.ceil(), vm) } #[pymethod(magic)] @@ -417,7 +419,7 @@ impl PyFloat { } else { self.value.round() }; - let int = try_bigint(value, vm)?; + let int = try_to_bigint(value, vm)?; vm.ctx.new_int(int) }; Ok(value) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 54724bcd8a..230877f8b2 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -1,10 +1,10 @@ use super::{float, IntoPyBool, PyByteArray, PyBytes, PyStr, PyStrRef, PyTypeRef}; +use crate::bytesinner::PyBytesInner; use crate::common::hash; use crate::format::FormatSpec; use crate::function::{OptionalArg, OptionalOption}; use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::VirtualMachine; -use crate::{bytesinner::PyBytesInner, byteslike::try_bytes_like}; use crate::{ try_value_from_borrowed_object, IdProtocol, IntoPyObject, IntoPyResult, PyArithmaticValue, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, @@ -142,8 +142,8 @@ pub fn bigint_unsigned_mask(v: &BigInt) -> u32 { fn inner_pow(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult { if int2.is_negative() { - let v1 = to_float(int1, vm)?; - let v2 = to_float(int2, vm)?; + let v1 = try_to_float(int1, vm)?; + let v2 = try_to_float(int2, vm)?; float::float_pow(v1, v2, vm).into_pyresult(vm) } else { Ok(if let Some(v2) = int2.to_u64() { @@ -541,7 +541,7 @@ impl PyInt { #[pymethod(magic)] fn float(&self, vm: &VirtualMachine) -> PyResult { - to_float(&self.value, vm) + try_to_float(&self.value, vm) } #[pymethod(magic)] @@ -914,7 +914,7 @@ pub(crate) fn get_value(obj: &PyObjectRef) -> &BigInt { &obj.payload::().unwrap().value } -pub fn to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult { +pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult { i2f(int).ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_owned())) } // num-bigint now returns Some(inf) for to_f64() in some cases, so just keep that the same for now @@ -939,7 +939,7 @@ pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult() { return try_convert(obj, s.as_str().as_bytes(), vm); } - if let Ok(r) = try_bytes_like(vm, obj, |x| try_convert(obj, x, vm)) { + if let Ok(r) = obj.try_bytes_like(vm, |x| try_convert(obj, x, vm)) { return r; } // strict `int` check diff --git a/vm/src/builtins/mod.rs b/vm/src/builtins/mod.rs index 07f0d66141..06dae4a56c 100644 --- a/vm/src/builtins/mod.rs +++ b/vm/src/builtins/mod.rs @@ -80,5 +80,8 @@ pub(crate) mod zip; pub use zip::PyZip; pub(crate) mod genericalias; +pub use float::try_to_bigint as try_f64_to_bigint; +pub use int::try_to_float as try_bigint_to_f64; + mod make_module; pub use make_module::{ascii, make_module, print}; diff --git a/vm/src/builtins/pybool.rs b/vm/src/builtins/pybool.rs index 5d7f07bdb1..6249238b8d 100644 --- a/vm/src/builtins/pybool.rs +++ b/vm/src/builtins/pybool.rs @@ -29,8 +29,14 @@ impl TryFromBorrowedObject for bool { } } +impl PyObjectRef { + pub fn try_into_bool(self, vm: &VirtualMachine) -> PyResult { + boolval(vm, self) + } +} + /// Convert Python bool into Rust bool. -pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { +pub(crate) fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { if obj.is(&vm.ctx.true_value) { return Ok(true); } diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index c414fd882e..a88215b29a 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -4,7 +4,6 @@ use crate::builtins::bytes::{PyBytes, PyBytesRef}; use crate::builtins::int::{PyInt, PyIntRef}; use crate::builtins::pystr::{self, PyStr, PyStrRef}; use crate::builtins::PyTypeRef; -use crate::byteslike::try_bytes_like; use crate::cformat::CFormatBytes; use crate::function::{OptionalArg, OptionalOption}; use crate::sliceable::PySliceableSequence; @@ -320,10 +319,9 @@ impl PyBytesInner { // TODO: bytes can compare with any object implemented buffer protocol // but not memoryview, and not equal if compare with unicode str(PyStr) PyComparisonValue::from_option( - try_bytes_like(vm, other, |other| { - op.eval_ord(self.elements.as_slice().cmp(other)) - }) - .ok(), + other + .try_bytes_like(vm, |other| op.eval_ord(self.elements.as_slice().cmp(other))) + .ok(), ) } @@ -1238,7 +1236,7 @@ pub const fn is_py_ascii_whitespace(b: u8) -> bool { } pub fn bytes_from_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult> { - if let Ok(elements) = try_bytes_like(vm, obj, |bytes| bytes.to_vec()) { + if let Ok(elements) = obj.try_bytes_like(vm, |bytes| bytes.to_vec()) { return Ok(elements); } diff --git a/vm/src/byteslike.rs b/vm/src/byteslike.rs index b5caa945b7..ef574468f4 100644 --- a/vm/src/byteslike.rs +++ b/vm/src/byteslike.rs @@ -77,27 +77,31 @@ impl TryFromBorrowedObject for ArgBytesLike { } } -pub fn try_bytes_like( - vm: &VirtualMachine, - obj: &PyObjectRef, - f: impl FnOnce(&[u8]) -> R, -) -> PyResult { - let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?; - buffer.as_contiguous().map(|x| f(&*x)).ok_or_else(|| { - vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()) - }) -} - -pub fn try_rw_bytes_like( - vm: &VirtualMachine, - obj: &PyObjectRef, - f: impl FnOnce(&mut [u8]) -> R, -) -> PyResult { - let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?; - buffer - .as_contiguous_mut() - .map(|mut x| f(&mut *x)) - .ok_or_else(|| vm.new_type_error("buffer is not a read-write bytes-like object".to_owned())) +impl PyObjectRef { + pub fn try_bytes_like( + &self, + vm: &VirtualMachine, + f: impl FnOnce(&[u8]) -> R, + ) -> PyResult { + let buffer = PyBuffer::try_from_borrowed_object(vm, self)?; + buffer.as_contiguous().map(|x| f(&*x)).ok_or_else(|| { + vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()) + }) + } + + pub fn try_rw_bytes_like( + &self, + vm: &VirtualMachine, + f: impl FnOnce(&mut [u8]) -> R, + ) -> PyResult { + let buffer = PyBuffer::try_from_borrowed_object(vm, self)?; + buffer + .as_contiguous_mut() + .map(|mut x| f(&mut *x)) + .ok_or_else(|| { + vm.new_type_error("buffer is not a read-write bytes-like object".to_owned()) + }) + } } impl ArgMemoryBuffer { diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index d7744a0c1a..ff12da0ce0 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -1,14 +1,14 @@ +//! Implementation of Printf-Style string formatting +//! [https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting] + use crate::buffer::PyBuffer; -/// Implementation of Printf-Style string formatting -/// [https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting] -use crate::builtins::float::{try_bigint, IntoPyFloat, PyFloat}; -use crate::builtins::int::{self, PyInt}; -use crate::builtins::pystr::PyStr; -use crate::builtins::{tuple, PyBytes}; +use crate::builtins::{ + float::IntoPyFloat, int, try_f64_to_bigint, tuple, PyBytes, PyFloat, PyInt, PyStr, +}; use crate::common::float_ops; -use crate::vm::VirtualMachine; use crate::{ ItemProtocol, PyObjectRef, PyResult, TryFromBorrowedObject, TryFromObject, TypeProtocol, + VirtualMachine, }; use itertools::Itertools; use num_bigint::{BigInt, Sign}; @@ -403,7 +403,7 @@ impl CFormatSpec { } ref f @ PyFloat => { Ok(self - .format_number(&try_bigint(f.to_f64(), vm)?) + .format_number(&try_f64_to_bigint(f.to_f64(), vm)?) .into_bytes()) } obj => { @@ -477,7 +477,7 @@ impl CFormatSpec { Ok(self.format_number(i.as_bigint())) } ref f @ PyFloat => { - Ok(self.format_number(&try_bigint(f.to_f64(), vm)?)) + Ok(self.format_number(&try_f64_to_bigint(f.to_f64(), vm)?)) } obj => { if let Some(method) = vm.get_method(obj.clone(), "__int__") { diff --git a/vm/src/stdlib/array.rs b/vm/src/stdlib/array.rs index ac0f9fd58b..153b51980e 100644 --- a/vm/src/stdlib/array.rs +++ b/vm/src/stdlib/array.rs @@ -16,7 +16,7 @@ mod array { use crate::builtins::pytype::PyTypeRef; use crate::builtins::slice::PySliceRef; use crate::builtins::{PyByteArray, PyBytes, PyBytesRef, PyIntRef}; - use crate::byteslike::{try_bytes_like, ArgBytesLike}; + use crate::byteslike::ArgBytesLike; use crate::common::borrow::{BorrowedValue, BorrowedValueMut}; use crate::common::lock::{ PyMappedRwLockReadGuard, PyMappedRwLockWriteGuard, PyRwLock, PyRwLockReadGuard, @@ -657,13 +657,13 @@ mod array { ))); } } else if init.payload_is::() || init.payload_is::() { - try_bytes_like(vm, &init, |x| array.frombytes(x))?; + init.try_bytes_like(vm, |x| array.frombytes(x))?; } else if let Ok(iter) = PyIterable::try_from_object(vm, init.clone()) { for obj in iter.iter(vm)? { array.push(obj?, vm)?; } } else { - try_bytes_like(vm, &init, |x| array.frombytes(x))?; + init.try_bytes_like(vm, |x| array.frombytes(x))?; } } diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index 36cb40a042..409938ce11 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -7,8 +7,9 @@ use num_bigint::BigInt; use num_traits::{One, Signed, Zero}; use puruspe::{erf, erfc, gamma, ln_gamma}; -use crate::builtins::float::{self, IntoPyFloat, PyFloatRef}; -use crate::builtins::int::{self, PyInt, PyIntRef}; +use crate::builtins::{ + float::IntoPyFloat, try_bigint_to_f64, try_f64_to_bigint, PyFloatRef, PyInt, PyIntRef, +}; use crate::function::{Args, OptionalArg}; use crate::utils::Either; use crate::vm::VirtualMachine; @@ -359,8 +360,8 @@ fn math_trunc(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { fn math_ceil(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method("__ceil__", vm, &value); if result_or_err.is_err() { - if let Ok(Some(v)) = float::try_float_opt(&value, vm) { - let v = float::try_bigint(v.ceil(), vm)?; + if let Ok(Some(v)) = value.try_to_f64(vm) { + let v = try_f64_to_bigint(v.ceil(), vm)?; return Ok(vm.ctx.new_int(v)); } } @@ -376,8 +377,8 @@ fn math_ceil(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { fn math_floor(value: PyObjectRef, vm: &VirtualMachine) -> PyResult { let result_or_err = try_magic_method("__floor__", vm, &value); if result_or_err.is_err() { - if let Ok(Some(v)) = float::try_float_opt(&value, vm) { - let v = float::try_bigint(v.floor(), vm)?; + if let Ok(Some(v)) = value.try_to_f64(vm) { + let v = try_f64_to_bigint(v.floor(), vm)?; return Ok(vm.ctx.new_int(v)); } } @@ -401,14 +402,14 @@ fn math_ldexp( ) -> PyResult { let value = match value { Either::A(f) => f.to_f64(), - Either::B(z) => int::to_float(z.as_bigint(), vm)?, + Either::B(z) => try_bigint_to_f64(z.as_bigint(), vm)?, }; if value == 0_f64 || !value.is_finite() { // NaNs, zeros and infinities are returned unchanged Ok(value) } else { - let result = value * (2_f64).powf(int::to_float(i.as_bigint(), vm)?); + let result = value * (2_f64).powf(try_bigint_to_f64(i.as_bigint(), vm)?); result_or_overflow(value, result, vm) } } From 540b9c316a6f6419a4b6dd0ba4bf38bc3d750fc6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 22 Sep 2021 02:46:52 +0900 Subject: [PATCH 2/3] Export common conversion parameter type IntoPy* --- vm/src/builtins/mod.rs | 6 +++--- vm/src/cformat.rs | 4 +--- vm/src/stdlib/array.rs | 2 +- vm/src/stdlib/cmath.rs | 2 +- vm/src/stdlib/math.rs | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/vm/src/builtins/mod.rs b/vm/src/builtins/mod.rs index 06dae4a56c..f4631cd1e3 100644 --- a/vm/src/builtins/mod.rs +++ b/vm/src/builtins/mod.rs @@ -12,7 +12,7 @@ pub use classmethod::PyClassMethod; pub(crate) mod code; pub use code::PyCode; pub(crate) mod complex; -pub use complex::PyComplex; +pub use complex::{IntoPyComplex, PyComplex}; pub(crate) mod coroutine; pub use coroutine::PyCoroutine; pub mod dict; @@ -22,7 +22,7 @@ pub use enumerate::PyEnumerate; pub(crate) mod filter; pub use filter::PyFilter; pub(crate) mod float; -pub use float::{PyFloat, PyFloatRef}; +pub use float::{IntoPyFloat, PyFloat, PyFloatRef}; pub(crate) mod frame; pub(crate) mod function; pub use function::PyFunction; @@ -65,7 +65,7 @@ pub use set::PySet; pub(crate) mod singletons; pub use singletons::{PyNone, PyNotImplemented}; pub(crate) mod slice; -pub use slice::PySlice; +pub use slice::{PySlice, PySliceRef}; pub(crate) mod staticmethod; pub use staticmethod::PyStaticMethod; pub(crate) mod traceback; diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index ff12da0ce0..11750e6f48 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -2,9 +2,7 @@ //! [https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting] use crate::buffer::PyBuffer; -use crate::builtins::{ - float::IntoPyFloat, int, try_f64_to_bigint, tuple, PyBytes, PyFloat, PyInt, PyStr, -}; +use crate::builtins::{int, try_f64_to_bigint, tuple, IntoPyFloat, PyBytes, PyFloat, PyInt, PyStr}; use crate::common::float_ops; use crate::{ ItemProtocol, PyObjectRef, PyResult, TryFromBorrowedObject, TryFromObject, TypeProtocol, diff --git a/vm/src/stdlib/array.rs b/vm/src/stdlib/array.rs index 153b51980e..c4114daf0d 100644 --- a/vm/src/stdlib/array.rs +++ b/vm/src/stdlib/array.rs @@ -10,11 +10,11 @@ pub type wchar_t = u32; #[pymodule(name = "array")] mod array { use crate::buffer::{BufferOptions, PyBuffer, PyBufferInternal, ResizeGuard}; - use crate::builtins::float::IntoPyFloat; use crate::builtins::list::{PyList, PyListRef}; use crate::builtins::pystr::{PyStr, PyStrRef}; use crate::builtins::pytype::PyTypeRef; use crate::builtins::slice::PySliceRef; + use crate::builtins::IntoPyFloat; use crate::builtins::{PyByteArray, PyBytes, PyBytesRef, PyIntRef}; use crate::byteslike::ArgBytesLike; use crate::common::borrow::{BorrowedValue, BorrowedValueMut}; diff --git a/vm/src/stdlib/cmath.rs b/vm/src/stdlib/cmath.rs index 0d3dd9ceea..d0b7dbf79d 100644 --- a/vm/src/stdlib/cmath.rs +++ b/vm/src/stdlib/cmath.rs @@ -22,7 +22,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { /// This module provides access to mathematical functions for complex numbers. #[pymodule] mod cmath { - use crate::builtins::{complex::IntoPyComplex, float::IntoPyFloat}; + use crate::builtins::{IntoPyComplex, IntoPyFloat}; use crate::function::OptionalArg; use crate::{PyResult, VirtualMachine}; use num_complex::Complex64; diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index 409938ce11..c8be7b7a73 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -8,7 +8,7 @@ use num_traits::{One, Signed, Zero}; use puruspe::{erf, erfc, gamma, ln_gamma}; use crate::builtins::{ - float::IntoPyFloat, try_bigint_to_f64, try_f64_to_bigint, PyFloatRef, PyInt, PyIntRef, + try_bigint_to_f64, try_f64_to_bigint, IntoPyFloat, PyFloatRef, PyInt, PyIntRef, }; use crate::function::{Args, OptionalArg}; use crate::utils::Either; From 09bc4d3cae2e21dd4d0e7e14f5214c59b8a02292 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 22 Sep 2021 02:08:30 +0900 Subject: [PATCH 3/3] pybool::boolval -> PyObjectRef::try_into_bool --- vm/src/builtins/filter.rs | 3 +- vm/src/builtins/object.rs | 3 +- vm/src/builtins/pybool.rs | 82 ++++++++++++++++++-------------------- vm/src/codecs.rs | 4 +- vm/src/frame.rs | 18 ++++----- vm/src/stdlib/io.rs | 22 +++++----- vm/src/stdlib/itertools.rs | 9 ++--- vm/src/stdlib/json.rs | 4 +- vm/src/stdlib/operator.rs | 5 +-- vm/src/vm.rs | 7 ++-- 10 files changed, 74 insertions(+), 83 deletions(-) diff --git a/vm/src/builtins/filter.rs b/vm/src/builtins/filter.rs index e9bbde7dcf..251fa0c81c 100644 --- a/vm/src/builtins/filter.rs +++ b/vm/src/builtins/filter.rs @@ -1,4 +1,3 @@ -use super::pybool; use super::pytype::PyTypeRef; use crate::iterator; use crate::slots::{PyIter, SlotConstructor}; @@ -64,7 +63,7 @@ impl PyIter for PyFilter { // iteration vm.invoke(predicate, vec![next_obj.clone()])? }; - if pybool::boolval(vm, predicate_value)? { + if predicate_value.try_to_bool(vm)? { return Ok(next_obj); } } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 80d412ab5e..6df2fcb578 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -1,6 +1,5 @@ use super::dict::{PyDict, PyDictRef}; use super::list::PyList; -use super::pybool; use super::pystr::{PyStr, PyStrRef}; use super::pytype::PyTypeRef; use crate::builtins::pytype::PyType; @@ -77,7 +76,7 @@ impl PyBaseObject { .unwrap(); let value = match cmp(zelf, other, PyComparisonOp::Eq, vm)? { Either::A(obj) => PyArithmaticValue::from_object(vm, obj) - .map(|obj| pybool::boolval(vm, obj)) + .map(|obj| obj.try_to_bool(vm)) .transpose()?, Either::B(value) => value, }; diff --git a/vm/src/builtins/pybool.rs b/vm/src/builtins/pybool.rs index 6249238b8d..8f88f4a54c 100644 --- a/vm/src/builtins/pybool.rs +++ b/vm/src/builtins/pybool.rs @@ -30,54 +30,50 @@ impl TryFromBorrowedObject for bool { } impl PyObjectRef { - pub fn try_into_bool(self, vm: &VirtualMachine) -> PyResult { - boolval(vm, self) - } -} - -/// Convert Python bool into Rust bool. -pub(crate) fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - if obj.is(&vm.ctx.true_value) { - return Ok(true); - } - if obj.is(&vm.ctx.false_value) { - return Ok(false); - } - let rs_bool = match vm.get_method(obj.clone(), "__bool__") { - Some(method_or_err) => { - // If descriptor returns Error, propagate it further - let method = method_or_err?; - let bool_obj = vm.invoke(&method, ())?; - if !bool_obj.isinstance(&vm.ctx.types.bool_type) { - return Err(vm.new_type_error(format!( - "__bool__ should return bool, returned type {}", - bool_obj.class().name() - ))); - } - - get_value(&bool_obj) + /// Convert Python bool into Rust bool. + pub fn try_to_bool(self, vm: &VirtualMachine) -> PyResult { + if self.is(&vm.ctx.true_value) { + return Ok(true); + } + if self.is(&vm.ctx.false_value) { + return Ok(false); } - None => match vm.get_method(obj, "__len__") { + let rs_bool = match vm.get_method(self.clone(), "__bool__") { Some(method_or_err) => { + // If descriptor returns Error, propagate it further let method = method_or_err?; let bool_obj = vm.invoke(&method, ())?; - let int_obj = bool_obj.payload::().ok_or_else(|| { - vm.new_type_error(format!( - "'{}' object cannot be interpreted as an integer", + if !bool_obj.isinstance(&vm.ctx.types.bool_type) { + return Err(vm.new_type_error(format!( + "__bool__ should return bool, returned type {}", bool_obj.class().name() - )) - })?; - - let len_val = int_obj.as_bigint(); - if len_val.sign() == Sign::Minus { - return Err(vm.new_value_error("__len__() should return >= 0".to_owned())); + ))); } - !len_val.is_zero() + + get_value(&bool_obj) } - None => true, - }, - }; - Ok(rs_bool) + None => match vm.get_method(self, "__len__") { + Some(method_or_err) => { + let method = method_or_err?; + let bool_obj = vm.invoke(&method, ())?; + let int_obj = bool_obj.payload::().ok_or_else(|| { + vm.new_type_error(format!( + "'{}' object cannot be interpreted as an integer", + bool_obj.class().name() + )) + })?; + + let len_val = int_obj.as_bigint(); + if len_val.sign() == Sign::Minus { + return Err(vm.new_value_error("__len__() should return >= 0".to_owned())); + } + !len_val.is_zero() + } + None => true, + }, + }; + Ok(rs_bool) + } } /// bool(x) -> bool @@ -111,7 +107,7 @@ impl SlotConstructor for PyBool { actual_type ))); } - let val = x.map_or(Ok(false), |val| boolval(vm, val))?; + let val = x.map_or(Ok(false), |val| val.try_to_bool(vm))?; Ok(vm.ctx.new_bool(val)) } } @@ -208,7 +204,7 @@ impl IntoPyBool { impl TryFromObject for IntoPyBool { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { Ok(IntoPyBool { - value: boolval(vm, obj)?, + value: obj.try_to_bool(vm)?, }) } } diff --git a/vm/src/codecs.rs b/vm/src/codecs.rs index 86edea55a9..bf51356a20 100644 --- a/vm/src/codecs.rs +++ b/vm/src/codecs.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::ops::Range; -use crate::builtins::{pybool, PyBytesRef, PyStr, PyStrRef, PyTuple, PyTupleRef}; +use crate::builtins::{PyBytesRef, PyStr, PyStrRef, PyTuple, PyTupleRef}; use crate::common::lock::PyRwLock; use crate::exceptions::PyBaseExceptionRef; use crate::VirtualMachine; @@ -52,7 +52,7 @@ impl PyCodec { pub fn is_text_codec(&self, vm: &VirtualMachine) -> PyResult { let is_text = vm.get_attribute_opt(self.0.clone().into_object(), "_is_text_encoding")?; - is_text.map_or(Ok(true), |is_text| pybool::boolval(vm, is_text)) + is_text.map_or(Ok(true), |is_text| is_text.try_to_bool(vm)) } pub fn encode( diff --git a/vm/src/frame.rs b/vm/src/frame.rs index bd790f76d6..05f64bc712 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -17,7 +17,7 @@ use crate::builtins::pytype::PyTypeRef; use crate::builtins::slice::PySlice; use crate::builtins::traceback::PyTraceback; use crate::builtins::tuple::{PyTuple, PyTupleTyped}; -use crate::builtins::{list, pybool, set}; +use crate::builtins::{list, set}; use crate::bytecode; use crate::common::boxvec::BoxVec; use crate::common::lock::PyMutex; @@ -844,7 +844,7 @@ impl ExecutingFrame<'_> { _ => self.fatal("WithCleanupFinish expects a FinallyHandler block on stack"), }; - let suppress_exception = pybool::boolval(vm, self.pop_value())?; + let suppress_exception = self.pop_value().try_to_bool(vm)?; vm.set_exception(prev_exc); @@ -957,7 +957,7 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::JumpIfTrue { target } => { let obj = self.pop_value(); - let value = pybool::boolval(vm, obj)?; + let value = obj.try_to_bool(vm)?; if value { self.jump(*target); } @@ -966,7 +966,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::JumpIfFalse { target } => { let obj = self.pop_value(); - let value = pybool::boolval(vm, obj)?; + let value = obj.try_to_bool(vm)?; if !value { self.jump(*target); } @@ -975,7 +975,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::JumpIfTrueOrPop { target } => { let obj = self.last_value(); - let value = pybool::boolval(vm, obj)?; + let value = obj.try_to_bool(vm)?; if value { self.jump(*target); } else { @@ -986,7 +986,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::JumpIfFalseOrPop { target } => { let obj = self.last_value(); - let value = pybool::boolval(vm, obj)?; + let value = obj.try_to_bool(vm)?; if !value { self.jump(*target); } else { @@ -1670,7 +1670,7 @@ impl ExecutingFrame<'_> { bytecode::UnaryOperator::Plus => vm._pos(&a)?, bytecode::UnaryOperator::Invert => vm._invert(&a)?, bytecode::UnaryOperator::Not => { - let value = pybool::boolval(vm, a)?; + let value = a.try_to_bool(vm)?; vm.ctx.new_bool(!value) } }; @@ -1689,7 +1689,7 @@ impl ExecutingFrame<'_> { haystack: PyObjectRef, ) -> PyResult { let found = vm._membership(haystack, needle)?; - pybool::boolval(vm, found) + found.try_to_bool(vm) } fn _not_in( @@ -1699,7 +1699,7 @@ impl ExecutingFrame<'_> { haystack: PyObjectRef, ) -> PyResult { let found = vm._membership(haystack, needle)?; - Ok(!pybool::boolval(vm, found)?) + Ok(!found.try_to_bool(vm)?) } fn _is(&self, a: PyObjectRef, b: PyObjectRef) -> bool { diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index c90c5bad82..90e95d6329 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -81,7 +81,7 @@ mod _io { use crate::builtins::memory::PyMemoryView; use crate::builtins::{ bytes::{PyBytes, PyBytesRef}, - pybool, pytype, PyByteArray, PyStr, PyStrRef, PyTypeRef, + pytype, PyByteArray, PyStr, PyStrRef, PyTypeRef, }; use crate::byteslike::{ArgBytesLike, ArgMemoryBuffer}; use crate::common::borrow::{BorrowedValue, BorrowedValueMut}; @@ -113,7 +113,7 @@ mod _io { } fn ensure_unclosed(file: &PyObjectRef, msg: &str, vm: &VirtualMachine) -> PyResult<()> { - if pybool::boolval(vm, vm.get_attribute(file.clone(), "closed")?)? { + if vm.get_attribute(file.clone(), "closed")?.try_to_bool(vm)? { Err(vm.new_value_error(msg.to_owned())) } else { Ok(()) @@ -288,7 +288,7 @@ mod _io { } fn file_closed(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult { - pybool::boolval(vm, vm.get_attribute(file.clone(), "closed")?) + vm.get_attribute(file.clone(), "closed")?.try_to_bool(vm) } fn check_closed(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { if file_closed(file, vm)? { @@ -299,7 +299,7 @@ mod _io { } fn check_readable(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - if pybool::boolval(vm, vm.call_method(file, "readable", ())?)? { + if vm.call_method(file, "readable", ())?.try_to_bool(vm)? { Ok(()) } else { Err(new_unsupported_operation( @@ -310,7 +310,7 @@ mod _io { } fn check_writable(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - if pybool::boolval(vm, vm.call_method(file, "writable", ())?)? { + if vm.call_method(file, "writable", ())?.try_to_bool(vm)? { Ok(()) } else { Err(new_unsupported_operation( @@ -321,7 +321,7 @@ mod _io { } fn check_seekable(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - if pybool::boolval(vm, vm.call_method(file, "seekable", ())?)? { + if vm.call_method(file, "seekable", ())?.try_to_bool(vm)? { Ok(()) } else { Err(new_unsupported_operation( @@ -520,7 +520,7 @@ mod _io { #[pyslot] fn tp_iternext(instance: &PyObjectRef, vm: &VirtualMachine) -> PyResult { let line = vm.call_method(instance, "readline", ())?; - if !pybool::boolval(vm, line.clone())? { + if !line.clone().try_to_bool(vm)? { Err(vm.new_stop_iteration()) } else { Ok(line) @@ -1812,7 +1812,7 @@ mod _io { fn isatty(&self, vm: &VirtualMachine) -> PyResult { // read.isatty() or write.isatty() let res = self.read.isatty(vm)?; - if pybool::boolval(vm, res.clone())? { + if res.clone().try_to_bool(vm)? { Ok(res) } else { self.write.isatty(vm) @@ -2208,11 +2208,11 @@ mod _io { let buffer = args.buffer; let has_read1 = vm.get_attribute_opt(buffer.clone(), "read1")?.is_some(); - let seekable = pybool::boolval(vm, vm.call_method(&buffer, "seekable", ())?)?; + let seekable = vm.call_method(&buffer, "seekable", ())?.try_to_bool(vm)?; let codec = vm.state.codec_registry.lookup(encoding.as_str(), vm)?; - let encoder = if pybool::boolval(vm, vm.call_method(&buffer, "writable", ())?)? { + let encoder = if vm.call_method(&buffer, "writable", ())?.try_to_bool(vm)? { let incremental_encoder = codec.get_incremental_encoder(Some(errors.clone()), vm)?; let encoding_name = vm.get_attribute_opt(incremental_encoder.clone(), "name")?; @@ -2228,7 +2228,7 @@ mod _io { None }; - let decoder = if pybool::boolval(vm, vm.call_method(&buffer, "readable", ())?)? { + let decoder = if vm.call_method(&buffer, "readable", ())?.try_to_bool(vm)? { let incremental_decoder = codec.get_incremental_decoder(Some(errors.clone()), vm)?; // TODO: wrap in IncrementalNewlineDecoder if newlines == Universal | Passthrough diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index 3a7d01d9cd..a45a80deb8 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -8,7 +8,6 @@ mod decl { use std::fmt; use crate::builtins::int::{self, PyInt, PyIntRef}; - use crate::builtins::pybool; use crate::builtins::pytype::PyTypeRef; use crate::builtins::tuple::PyTupleRef; use crate::common::lock::{PyMutex, PyRwLock, PyRwLockWriteGuard}; @@ -136,7 +135,7 @@ mod decl { fn next(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { loop { let sel_obj = call_next(vm, &zelf.selector)?; - let verdict = pybool::boolval(vm, sel_obj.clone())?; + let verdict = sel_obj.clone().try_to_bool(vm)?; let data_obj = call_next(vm, &zelf.data)?; if verdict { @@ -432,7 +431,7 @@ mod decl { let predicate = &zelf.predicate; let verdict = vm.invoke(predicate, (obj.clone(),))?; - let verdict = pybool::boolval(vm, verdict)?; + let verdict = verdict.try_to_bool(vm)?; if verdict { Ok(obj) } else { @@ -493,7 +492,7 @@ mod decl { let obj = call_next(vm, iterable)?; let pred = predicate.clone(); let pred_value = vm.invoke(&pred.into_object(), (obj.clone(),))?; - if !pybool::boolval(vm, pred_value)? { + if !pred_value.try_to_bool(vm)? { zelf.start_flag.store(true); return Ok(obj); } @@ -841,7 +840,7 @@ mod decl { vm.invoke(predicate, vec![obj.clone()])? }; - if !pybool::boolval(vm, pred_value)? { + if !pred_value.try_to_bool(vm)? { return Ok(obj); } } diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index 16ab99c8d6..5b0cf6fa07 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -5,7 +5,7 @@ mod machinery; mod _json { use super::*; use crate::builtins::pystr::PyStrRef; - use crate::builtins::{pybool, pytype::PyTypeRef}; + use crate::builtins::pytype::PyTypeRef; use crate::exceptions::PyBaseExceptionRef; use crate::function::{FuncArgs, OptionalArg}; use crate::iterator; @@ -35,7 +35,7 @@ mod _json { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { - let strict = pybool::boolval(vm, vm.get_attribute(ctx.clone(), "strict")?)?; + let strict = vm.get_attribute(ctx.clone(), "strict")?.try_to_bool(vm)?; let object_hook = vm.option_if_none(vm.get_attribute(ctx.clone(), "object_hook")?); let object_pairs_hook = vm.option_if_none(vm.get_attribute(ctx.clone(), "object_pairs_hook")?); diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 8fd62ed545..91e79530e5 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -11,7 +11,6 @@ pub(crate) use _operator::make_module; mod _operator { use crate::builtins::int; use crate::builtins::int::PyIntRef; - use crate::builtins::pybool; use crate::builtins::pystr::PyStrRef; use crate::builtins::PyInt; use crate::builtins::PyTypeRef; @@ -73,13 +72,13 @@ mod _operator { /// Same as not a. #[pyfunction] fn not_(a: PyObjectRef, vm: &VirtualMachine) -> PyResult { - pybool::boolval(vm, a).map(|r| !r) + a.try_to_bool(vm).map(|r| !r) } /// Return True if a is true, False otherwise. #[pyfunction] fn truth(a: PyObjectRef, vm: &VirtualMachine) -> PyResult { - pybool::boolval(vm, a) + a.try_to_bool(vm) } /// Same as a is b. diff --git a/vm/src/vm.rs b/vm/src/vm.rs index c661117ab8..eb120dc993 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -18,7 +18,6 @@ use crate::builtins::int::{PyInt, PyIntRef}; use crate::builtins::list::PyList; use crate::builtins::module::{self, PyModule}; use crate::builtins::object; -use crate::builtins::pybool; use crate::builtins::pystr::{PyStr, PyStrRef}; use crate::builtins::pytype::PyTypeRef; use crate::builtins::tuple::{PyTuple, PyTupleRef, PyTupleTyped}; @@ -1030,7 +1029,7 @@ impl VirtualMachine { if let Ok(meth) = self.get_special_method(cls.clone(), "__instancecheck__")? { let ret = meth.invoke((obj.clone(),), self)?; - return pybool::boolval(self, ret); + return ret.try_to_bool(self); } self.abstract_isinstance(obj, cls) @@ -1112,7 +1111,7 @@ impl VirtualMachine { if let Ok(meth) = self.get_special_method(cls.clone(), "__subclasscheck__")? { let ret = meth.invoke((subclass.clone(),), self)?; - return pybool::boolval(self, ret); + return ret.try_to_bool(self); } self.recursive_issubclass(subclass, cls) @@ -1857,7 +1856,7 @@ impl VirtualMachine { pub fn bool_cmp(&self, a: &PyObjectRef, b: &PyObjectRef, op: PyComparisonOp) -> PyResult { match self._cmp(a, b, op)? { - Either::A(obj) => pybool::boolval(self, obj), + Either::A(obj) => obj.try_to_bool(self), Either::B(b) => Ok(b), } }