Merge pull request #2335 from carbotaniuman/number-reform

Return same object if exact type in int, float, complex and fix pow
This commit is contained in:
Noah
2020-11-23 10:39:00 -06:00
committed by GitHub
7 changed files with 320 additions and 172 deletions

View File

@@ -82,8 +82,6 @@ class ComplexTest(unittest.TestCase):
q = z.__truediv__(y)
self.assertClose(q, x)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_truediv(self):
simple_real = [float(i) for i in range(-5, 6)]
simple_complex = [complex(x, y) for x in simple_real for y in simple_real]
@@ -171,8 +169,6 @@ class ComplexTest(unittest.TestCase):
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
self.assertRaises(TypeError, divmod, 1+1j, 0+0j)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_pow(self):
self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
self.assertAlmostEqual(pow(0+0j, 2+0j), 0.0)
@@ -416,8 +412,6 @@ class ComplexTest(unittest.TestCase):
self.assertEqual(complex(complex1(1j)), 2j)
self.assertRaises(TypeError, complex, complex2(1j))
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.requires_IEEE_754
def test_constructor_special_numbers(self):
class complex2(complex):

View File

@@ -4,8 +4,9 @@ use num_traits::Zero;
use super::float;
use super::pystr::PyStr;
use super::pytype::PyTypeRef;
use crate::function::{OptionalArg, OptionalOption};
use crate::pyobject::{
BorrowValue, IntoPyObject, Never,
BorrowValue, IdProtocol, IntoPyObject, Never,
PyArithmaticValue::{self, *},
PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
@@ -44,27 +45,6 @@ pub fn init(context: &PyContext) {
PyComplex::extend_class(context, &context.types.complex_type);
}
fn try_complex(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Complex64>> {
if let Some(complex) = obj.payload_if_exact::<PyComplex>(vm) {
return Ok(Some(complex.value));
}
if let Some(method) = vm.get_method(obj.clone(), "__complex__") {
let result = vm.invoke(&method?, ())?;
// TODO: returning strict subclasses of complex in __complex__ is deprecated
return match result.payload::<PyComplex>() {
Some(complex_obj) => Ok(Some(complex_obj.value)),
None => Err(vm.new_type_error(format!(
"__complex__ returned non-complex (type '{}')",
result.class().name
))),
};
}
if let Some(float) = float::try_float(obj, vm)? {
return Ok(Some(Complex64::new(float, 0.0)));
}
Ok(None)
}
fn to_op_complex(value: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Complex64>> {
let r = if let Some(complex) = value.payload_if_subclass::<PyComplex>(vm) {
Some(complex.value)
@@ -84,6 +64,26 @@ fn inner_div(v1: Complex64, v2: Complex64, vm: &VirtualMachine) -> PyResult<Comp
Ok(v1.fdiv(v2))
}
fn inner_pow(v1: Complex64, v2: Complex64, vm: &VirtualMachine) -> PyResult<Complex64> {
if v1.is_zero() {
return if v2.im != 0.0 {
let msg = format!("{} cannot be raised to a negative or complex power", v1);
Err(vm.new_zero_division_error(msg))
} else if v2.is_zero() {
Ok(Complex64::new(1.0, 0.0))
} else {
Ok(Complex64::new(0.0, 0.0))
};
}
let ans = v1.powc(v2);
if ans.is_infinite() && !(v1.is_infinite() || v2.is_infinite()) {
Err(vm.new_overflow_error("complex exponentiation overflow".to_owned()))
} else {
Ok(ans)
}
}
#[pyimpl(flags(BASETYPE), with(Comparable, Hashable))]
impl PyComplex {
pub fn to_complex(&self) -> Complex64 {
@@ -235,9 +235,14 @@ impl PyComplex {
fn pow(
&self,
other: PyObjectRef,
mod_val: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyArithmaticValue<Complex64>> {
self.op(other, |a, b| Ok(a.powc(b)), vm)
if mod_val.flatten().is_some() {
Err(vm.new_value_error("complex modulo not allowed".to_owned()))
} else {
self.op(other, |a, b| Ok(inner_pow(a, b, vm)?), vm)
}
}
#[pymethod(name = "__rpow__")]
@@ -246,7 +251,7 @@ impl PyComplex {
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmaticValue<Complex64>> {
self.op(other, |a, b| Ok(b.powc(a)), vm)
self.op(other, |a, b| Ok(inner_pow(b, a, vm)?), vm)
}
#[pymethod(name = "__bool__")]
@@ -256,13 +261,25 @@ impl PyComplex {
#[pyslot]
fn tp_new(cls: PyTypeRef, args: ComplexArgs, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
let real = match args.real {
None => Complex64::new(0.0, 0.0),
Some(obj) => {
if let Some(c) = try_complex(&obj, vm)? {
let imag_missing = args.imag.is_missing();
let (real, real_was_complex) = match args.real {
OptionalArg::Missing => (Complex64::new(0.0, 0.0), false),
OptionalArg::Present(val) => {
let val = if cls.is(&vm.ctx.types.complex_type) && imag_missing {
match val.downcast_exact::<PyComplex>(vm) {
Ok(c) => {
return Ok(c);
}
Err(val) => val,
}
} else {
val
};
if let Some(c) = try_complex(&val, vm)? {
c
} else if let Some(s) = obj.payload_if_subclass::<PyStr>(vm) {
if args.imag.is_some() {
} else if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
if args.imag.is_present() {
return Err(vm.new_type_error(
"complex() can't take second arg if first is a string".to_owned(),
));
@@ -274,15 +291,17 @@ impl PyComplex {
} else {
return Err(vm.new_type_error(format!(
"complex() first argument must be a string or a number, not '{}'",
obj.class().name
val.class().name
)));
}
}
};
let imag = match args.imag {
None => Complex64::new(0.0, 0.0),
Some(obj) => {
let (imag, imag_was_complex) = match args.imag {
// Copy the imaginary from the real to the real of the imaginary
// if an imaginary argument is not passed in
OptionalArg::Missing => (Complex64::new(real.im, 0.0), false),
OptionalArg::Present(obj) => {
if let Some(c) = try_complex(&obj, vm)? {
c
} else if obj.class().issubclass(&vm.ctx.types.str_type) {
@@ -298,7 +317,18 @@ impl PyComplex {
}
};
let value = Complex64::new(real.re - imag.im, real.im + imag.re);
let final_real = if imag_was_complex {
real.re - imag.im
} else {
real.re
};
let final_imag = if real_was_complex && !imag_missing {
imag.re + real.im
} else {
imag.re
};
let value = Complex64::new(final_real, final_imag);
Self::from(value).into_ref_with_type(vm, cls)
}
@@ -340,10 +370,10 @@ impl Hashable for PyComplex {
#[derive(FromArgs)]
struct ComplexArgs {
#[pyarg(any, default)]
real: Option<PyObjectRef>,
#[pyarg(any, default)]
imag: Option<PyObjectRef>,
#[pyarg(any, optional)]
real: OptionalArg<PyObjectRef>,
#[pyarg(any, optional)]
imag: OptionalArg<PyObjectRef>,
}
fn parse_str(s: &str) -> Option<Complex64> {
@@ -382,3 +412,31 @@ fn parse_str(s: &str) -> Option<Complex64> {
};
Some(value)
}
/// Tries converting a python object into a complex, returns an option of whether the complex
/// and whether the object was a complex originally or coereced into one
fn try_complex(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<(Complex64, bool)>> {
if let Some(complex) = obj.payload_if_exact::<PyComplex>(vm) {
return Ok(Some((complex.value, true)));
}
if let Some(method) = vm.get_method(obj.clone(), "__complex__") {
let result = vm.invoke(&method?, ())?;
// TODO: returning strict subclasses of complex in __complex__ is deprecated
return match result.payload::<PyComplex>() {
Some(complex_obj) => Ok(Some((complex_obj.value, true))),
None => Err(vm.new_type_error(format!(
"__complex__ returned non-complex (type '{}')",
result.class().name
))),
};
}
// `complex` does not have a `__complex__` by default, so subclasses might not either,
// use the actual stored value in this case
if let Some(complex) = obj.payload_if_subclass::<PyComplex>(vm) {
return Ok(Some((complex.value, true)));
}
if let Some(float) = float::try_float(obj, vm)? {
return Ok(Some((Complex64::new(float, 0.0), false)));
}
Ok(None)
}

View File

@@ -10,7 +10,7 @@ use super::pytype::PyTypeRef;
use crate::format::FormatSpec;
use crate::function::{OptionalArg, OptionalOption};
use crate::pyobject::{
BorrowValue, IntoPyObject,
BorrowValue, IdProtocol, IntoPyObject,
PyArithmaticValue::{self, *},
PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
TryFromObject, TypeProtocol,
@@ -163,7 +163,19 @@ impl PyFloat {
vm: &VirtualMachine,
) -> PyResult<PyRef<Self>> {
let float_val = match arg {
OptionalArg::Missing => 0.0,
OptionalArg::Present(val) => {
let val = if cls.is(&vm.ctx.types.float_type) {
match val.downcast_exact::<PyFloat>(vm) {
Ok(f) => {
return Ok(f);
}
Err(val) => val,
}
} else {
val
};
if let Some(f) = try_float(&val, vm)? {
f
} else if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
@@ -184,7 +196,6 @@ impl PyFloat {
)));
}
}
OptionalArg::Missing => 0.0,
};
PyFloat::from(float_val).into_ref_with_type(vm, cls)
}
@@ -315,8 +326,17 @@ impl PyFloat {
}
#[pymethod(name = "__pow__")]
fn pow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.complex_op(other, |a, b| float_pow(a, b, vm), vm)
fn pow(
&self,
other: PyObjectRef,
mod_val: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
if mod_val.flatten().is_some() {
Err(vm.new_type_error("floating point pow() does not accept a 3rd argument".to_owned()))
} else {
self.complex_op(other, |a, b| float_pow(a, b, vm), vm)
}
}
#[pymethod(name = "__rpow__")]

View File

@@ -14,7 +14,7 @@ use super::pybool::IntoPyBool;
use super::pystr::{PyStr, PyStrRef};
use super::pytype::PyTypeRef;
use crate::format::FormatSpec;
use crate::function::OptionalArg;
use crate::function::{OptionalArg, OptionalOption};
use crate::pyobject::{
BorrowValue, IdProtocol, IntoPyObject, IntoPyResult, PyArithmaticValue, PyClassImpl,
PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
@@ -262,6 +262,17 @@ impl PyInt {
})?;
try_int_radix(&val, base, vm)
} else {
let val = if cls.is(&vm.ctx.types.int_type) {
match val.downcast_exact::<PyInt>(vm) {
Ok(i) => {
return Ok(i);
}
Err(val) => val,
}
} else {
val
};
try_int(&val, vm)
}
} else if let OptionalArg::Present(_) = options.base {
@@ -397,8 +408,37 @@ impl PyInt {
}
#[pymethod(name = "__pow__")]
fn pow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_pow(a, b, vm), vm)
fn pow(
&self,
other: PyObjectRef,
mod_val: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
match mod_val.flatten() {
Some(int_ref) => {
let int = match int_ref.payload_if_subclass::<PyInt>(vm) {
Some(val) => val,
None => return Ok(vm.ctx.not_implemented()),
};
let modulus = int.borrow_value();
if modulus.is_zero() {
return Err(vm.new_value_error("pow() 3rd argument cannot be 0".to_owned()));
}
self.general_op(
other,
|a, b| {
if b.is_negative() {
Err(vm.new_value_error("modular inverses not supported".to_owned()))
} else {
Ok(vm.ctx.new_int(a.modpow(b, modulus)))
}
},
vm,
)
}
None => self.general_op(other, |a, b| inner_pow(a, b, vm), vm),
}
}
#[pymethod(name = "__rpow__")]
@@ -709,66 +749,6 @@ struct IntToByteArgs {
signed: OptionalArg<IntoPyBool>,
}
// Casting function:
pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt> {
fn try_convert(obj: &PyObjectRef, lit: &[u8], vm: &VirtualMachine) -> PyResult<BigInt> {
let base = 10;
match bytes_to_int(lit, base) {
Some(i) => Ok(i),
None => Err(vm.new_value_error(format!(
"invalid literal for int() with base {}: {}",
base,
vm.to_repr(obj)?,
))),
}
};
// test for strings and bytes
if let Some(s) = obj.downcast_ref::<PyStr>() {
return try_convert(obj, s.borrow_value().as_bytes(), vm);
}
if let Ok(r) = try_bytes_like(vm, &obj, |x| try_convert(obj, x, vm)) {
return r;
}
// strict `int` check
if let Some(int) = obj.payload_if_exact::<PyInt>(vm) {
return Ok(int.borrow_value().clone());
}
// call __int__, then __index__, then __trunc__ (converting the __trunc__ result via __index__ if needed)
// TODO: using __int__ is deprecated and removed in Python 3.10
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
let result = vm.invoke(&method?, ())?;
return match result.payload::<PyInt>() {
Some(int_obj) => Ok(int_obj.borrow_value().clone()),
None => Err(vm.new_type_error(format!(
"__int__ returned non-int (type '{}')",
result.class().name
))),
};
}
// TODO: returning strict subclasses of int in __index__ is deprecated
if let Some(r) = vm.to_index_opt(obj.clone()).transpose()? {
return Ok(r.borrow_value().clone());
}
if let Some(method) = vm.get_method(obj.clone(), "__trunc__") {
let result = vm.invoke(&method?, ())?;
return vm
.to_index_opt(result.clone())
.unwrap_or_else(|| {
Err(vm.new_type_error(format!(
"__trunc__ returned non-Integral (type '{}')",
result.class().name
)))
})
.map(|int_obj| int_obj.borrow_value().clone());
}
Err(vm.new_type_error(format!(
"int() argument must be a string, a bytes-like object or a number, not '{}'",
obj.class().name
)))
}
fn try_int_radix(obj: &PyObjectRef, base: u32, vm: &VirtualMachine) -> PyResult<BigInt> {
debug_assert!(base == 0 || (2..=36).contains(&base));
@@ -917,6 +897,65 @@ pub fn to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {
.ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_owned()))
}
pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt> {
fn try_convert(obj: &PyObjectRef, lit: &[u8], vm: &VirtualMachine) -> PyResult<BigInt> {
let base = 10;
match bytes_to_int(lit, base) {
Some(i) => Ok(i),
None => Err(vm.new_value_error(format!(
"invalid literal for int() with base {}: {}",
base,
vm.to_repr(obj)?,
))),
}
};
// test for strings and bytes
if let Some(s) = obj.downcast_ref::<PyStr>() {
return try_convert(obj, s.borrow_value().as_bytes(), vm);
}
if let Ok(r) = try_bytes_like(vm, &obj, |x| try_convert(obj, x, vm)) {
return r;
}
// strict `int` check
if let Some(int) = obj.payload_if_exact::<PyInt>(vm) {
return Ok(int.borrow_value().clone());
}
// call __int__, then __index__, then __trunc__ (converting the __trunc__ result via __index__ if needed)
// TODO: using __int__ is deprecated and removed in Python 3.10
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
let result = vm.invoke(&method?, ())?;
return match result.payload::<PyInt>() {
Some(int_obj) => Ok(int_obj.borrow_value().clone()),
None => Err(vm.new_type_error(format!(
"__int__ returned non-int (type '{}')",
result.class().name
))),
};
}
// TODO: returning strict subclasses of int in __index__ is deprecated
if let Some(r) = vm.to_index_opt(obj.clone()).transpose()? {
return Ok(r.borrow_value().clone());
}
if let Some(method) = vm.get_method(obj.clone(), "__trunc__") {
let result = vm.invoke(&method?, ())?;
return vm
.to_index_opt(result.clone())
.unwrap_or_else(|| {
Err(vm.new_type_error(format!(
"__trunc__ returned non-Integral (type '{}')",
result.class().name
)))
})
.map(|int_obj| int_obj.borrow_value().clone());
}
Err(vm.new_type_error(format!(
"int() argument must be a string, a bytes-like object or a number, not '{}'",
obj.class().name
)))
}
pub(crate) fn init(context: &PyContext) {
PyInt::extend_class(context, &context.types.int_type);
}

View File

@@ -19,16 +19,19 @@ mod decl {
use crate::builtins::pybool::{self, IntoPyBool};
use crate::builtins::pystr::{PyStr, PyStrRef};
use crate::builtins::pytype::PyTypeRef;
use crate::builtins::PyInt;
use crate::byteslike::PyBytesLike;
use crate::common::{hash::PyHash, str::to_ascii};
#[cfg(feature = "rustpython-compiler")]
use crate::compile;
use crate::exceptions::PyBaseExceptionRef;
use crate::function::{single_or_tuple_any, Args, FuncArgs, KwArgs, OptionalArg};
use crate::function::{
single_or_tuple_any, Args, FuncArgs, KwArgs, OptionalArg, OptionalOption,
};
use crate::iterator;
use crate::pyobject::{
BorrowValue, Either, IdProtocol, ItemProtocol, PyCallable, PyIterable, PyObjectRef,
PyResult, PyValue, TryFromObject, TypeProtocol,
BorrowValue, Either, IdProtocol, ItemProtocol, PyArithmaticValue, PyCallable, PyIterable,
PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol,
};
use crate::readline::{Readline, ReadlineResult};
use crate::scope::Scope;
@@ -177,7 +180,7 @@ mod decl {
#[pyfunction]
fn divmod(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult {
vm.call_or_reflection(&a, &b, "__divmod__", "__rdivmod__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "divmod"))
Err(vm.new_unsupported_binop_error(a, b, "divmod"))
})
}
@@ -582,40 +585,53 @@ mod decl {
}
}
#[allow(clippy::suspicious_else_formatting)]
#[pyfunction]
fn pow(
x: PyObjectRef,
y: PyObjectRef,
mod_value: OptionalArg<PyIntRef>,
mod_value: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
match mod_value {
OptionalArg::Missing => {
vm.call_or_reflection(&x, &y, "__pow__", "__rpow__", |vm, x, y| {
Err(vm.new_unsupported_operand_error(x, y, "pow"))
})
}
OptionalArg::Present(m) => {
// Check if the 3rd argument is defined and perform modulus on the result
if !(x.isinstance(&vm.ctx.types.int_type) && y.isinstance(&vm.ctx.types.int_type)) {
return Err(vm.new_type_error(
"pow() 3rd argument not allowed unless all arguments are integers"
.to_owned(),
));
match mod_value.flatten() {
None => vm.call_or_reflection(&x, &y, "__pow__", "__rpow__", |vm, x, y| {
Err(vm.new_unsupported_binop_error(x, y, "pow"))
}),
Some(z) => {
let try_pow_value = |obj: &PyObjectRef,
args: (PyObjectRef, PyObjectRef, PyObjectRef)|
-> Option<PyResult> {
if let Some(method) = obj.get_class_attr("__pow__") {
let result = match vm.invoke(&method, args) {
Ok(x) => x,
Err(e) => return Some(Err(e)),
};
if let PyArithmaticValue::Implemented(x) =
PyArithmaticValue::from_object(vm, result)
{
return Some(Ok(x));
}
}
None
};
if let Some(val) = try_pow_value(&x, (x.clone(), y.clone(), z.clone())) {
return val;
}
let y = int::get_value(&y);
if y.sign() == Sign::Minus {
return Err(vm.new_value_error(
"pow() 2nd argument cannot be negative when 3rd argument specified"
.to_owned(),
));
if !x.class().is(&y.class()) {
if let Some(val) = try_pow_value(&y, (x.clone(), y.clone(), z.clone())) {
return val;
}
}
let m = m.borrow_value();
if m.is_zero() {
return Err(vm.new_value_error("pow() 3rd argument cannot be 0".to_owned()));
if !x.class().is(&z.class()) && !y.class().is(&z.class()) {
if let Some(val) = try_pow_value(&z, (x.clone(), y.clone(), z.clone())) {
return val;
}
}
let x = int::get_value(&x);
Ok(vm.ctx.new_int(x.modpow(&y, &m)))
Err(vm.new_unsupported_ternop_error(&x, &y, &z, "pow"))
}
}
}

View File

@@ -599,7 +599,7 @@ impl VirtualMachine {
self.new_exception_msg(name_error, msg)
}
pub fn new_unsupported_operand_error(
pub fn new_unsupported_binop_error(
&self,
a: &PyObjectRef,
b: &PyObjectRef,
@@ -613,6 +613,22 @@ impl VirtualMachine {
))
}
pub fn new_unsupported_ternop_error(
&self,
a: &PyObjectRef,
b: &PyObjectRef,
c: &PyObjectRef,
op: &str,
) -> PyBaseExceptionRef {
self.new_type_error(format!(
"Unsupported operand types for '{}': '{}', '{}', and '{}'",
op,
a.class().name,
b.class().name,
c.class().name
))
}
pub fn new_os_error(&self, msg: String) -> PyBaseExceptionRef {
let os_error = self.ctx.exceptions.os_error.clone();
self.new_exception_msg(os_error, msg)
@@ -1153,10 +1169,15 @@ impl VirtualMachine {
// Try to call the default method
self.call_or_unsupported(lhs, rhs, default, move |vm, lhs, rhs| {
// Try to call the reflection method
vm.call_or_unsupported(rhs, lhs, reflection, |_, rhs, lhs| {
// switch them around again
// don't call reflection method if operands are of the same type
if !lhs.class().is(&rhs.class()) {
vm.call_or_unsupported(rhs, lhs, reflection, |_, rhs, lhs| {
// switch them around again
unsupported(vm, lhs, rhs)
})
} else {
unsupported(vm, lhs, rhs)
})
}
})
}
@@ -1289,182 +1310,182 @@ impl VirtualMachine {
pub fn _sub(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "-"))
Err(vm.new_unsupported_binop_error(a, b, "-"))
})
}
pub fn _isub(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__isub__", |vm, a, b| {
vm.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "-="))
Err(vm.new_unsupported_binop_error(a, b, "-="))
})
})
}
pub fn _add(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "+"))
Err(vm.new_unsupported_binop_error(a, b, "+"))
})
}
pub fn _iadd(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__iadd__", |vm, a, b| {
vm.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "+="))
Err(vm.new_unsupported_binop_error(a, b, "+="))
})
})
}
pub fn _mul(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "*"))
Err(vm.new_unsupported_binop_error(a, b, "*"))
})
}
pub fn _imul(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__imul__", |vm, a, b| {
vm.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "*="))
Err(vm.new_unsupported_binop_error(a, b, "*="))
})
})
}
pub fn _matmul(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "@"))
Err(vm.new_unsupported_binop_error(a, b, "@"))
})
}
pub fn _imatmul(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__imatmul__", |vm, a, b| {
vm.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "@="))
Err(vm.new_unsupported_binop_error(a, b, "@="))
})
})
}
pub fn _truediv(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "/"))
Err(vm.new_unsupported_binop_error(a, b, "/"))
})
}
pub fn _itruediv(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__itruediv__", |vm, a, b| {
vm.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "/="))
Err(vm.new_unsupported_binop_error(a, b, "/="))
})
})
}
pub fn _floordiv(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "//"))
Err(vm.new_unsupported_binop_error(a, b, "//"))
})
}
pub fn _ifloordiv(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__ifloordiv__", |vm, a, b| {
vm.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "//="))
Err(vm.new_unsupported_binop_error(a, b, "//="))
})
})
}
pub fn _pow(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "**"))
Err(vm.new_unsupported_binop_error(a, b, "**"))
})
}
pub fn _ipow(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__ipow__", |vm, a, b| {
vm.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "**="))
Err(vm.new_unsupported_binop_error(a, b, "**="))
})
})
}
pub fn _mod(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "%"))
Err(vm.new_unsupported_binop_error(a, b, "%"))
})
}
pub fn _imod(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__imod__", |vm, a, b| {
vm.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "%="))
Err(vm.new_unsupported_binop_error(a, b, "%="))
})
})
}
pub fn _lshift(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "<<"))
Err(vm.new_unsupported_binop_error(a, b, "<<"))
})
}
pub fn _ilshift(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__ilshift__", |vm, a, b| {
vm.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "<<="))
Err(vm.new_unsupported_binop_error(a, b, "<<="))
})
})
}
pub fn _rshift(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, ">>"))
Err(vm.new_unsupported_binop_error(a, b, ">>"))
})
}
pub fn _irshift(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__irshift__", |vm, a, b| {
vm.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, ">>="))
Err(vm.new_unsupported_binop_error(a, b, ">>="))
})
})
}
pub fn _xor(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "^"))
Err(vm.new_unsupported_binop_error(a, b, "^"))
})
}
pub fn _ixor(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__ixor__", |vm, a, b| {
vm.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "^="))
Err(vm.new_unsupported_binop_error(a, b, "^="))
})
})
}
pub fn _or(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "|"))
Err(vm.new_unsupported_binop_error(a, b, "|"))
})
}
pub fn _ior(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__ior__", |vm, a, b| {
vm.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "|="))
Err(vm.new_unsupported_binop_error(a, b, "|="))
})
})
}
pub fn _and(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "&"))
Err(vm.new_unsupported_binop_error(a, b, "&"))
})
}
pub fn _iand(&self, a: &PyObjectRef, b: &PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__iand__", |vm, a, b| {
vm.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
Err(vm.new_unsupported_operand_error(a, b, "&="))
Err(vm.new_unsupported_binop_error(a, b, "&="))
})
})
}
@@ -1517,7 +1538,7 @@ impl VirtualMachine {
match op {
PyComparisonOp::Eq => Ok(Either::B(v.is(&w))),
PyComparisonOp::Ne => Ok(Either::B(!v.is(&w))),
_ => Err(self.new_unsupported_operand_error(v, w, op.operator_token())),
_ => Err(self.new_unsupported_binop_error(v, w, op.operator_token())),
}
// TODO: _Py_LeaveRecursiveCall(tstate);
}