From 2b0c7f85f6c4784f5b6e16f403b56faccefb99bb Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Mon, 16 Nov 2020 21:29:20 -0600 Subject: [PATCH 01/10] Return same object if exact type in int, float, complex --- Lib/test/test_complex.py | 2 - vm/src/builtins/complex.rs | 111 ++++++++++++++++++++----------- vm/src/builtins/float.rs | 22 ++++++- vm/src/builtins/int.rs | 132 ++++++++++++++++++++----------------- 4 files changed, 164 insertions(+), 103 deletions(-) diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index d9e77bf14..5fec1dea9 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -416,8 +416,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): diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index de6ed5901..7d0047a2f 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -5,13 +5,14 @@ use super::float; use super::pystr::PyStr; use super::pytype::PyTypeRef; use crate::pyobject::{ - BorrowValue, IntoPyObject, Never, + BorrowValue, IdProtocol, IntoPyObject, Never, PyArithmaticValue::{self, *}, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; use crate::slots::{Comparable, Hashable, PyComparisonOp}; use crate::VirtualMachine; use rustpython_common::{float_ops, hash}; +use crate::function::{OptionalOption, OptionalArg}; /// Create a complex number from a real part and an optional imaginary part. /// @@ -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> { - if let Some(complex) = obj.payload_if_exact::(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::() { - 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> { let r = if let Some(complex) = value.payload_if_subclass::(vm) { Some(complex.value) @@ -256,13 +236,27 @@ impl PyComplex { #[pyslot] fn tp_new(cls: PyTypeRef, args: ComplexArgs, vm: &VirtualMachine) -> PyResult> { - 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::(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::(vm) { - if args.imag.is_some() { + } else if let Some(s) = val.payload_if_subclass::(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 +268,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 +294,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 +347,10 @@ impl Hashable for PyComplex { #[derive(FromArgs)] struct ComplexArgs { - #[pyarg(any, default)] - real: Option, - #[pyarg(any, default)] - imag: Option, + #[pyarg(any, optional)] + real: OptionalArg, + #[pyarg(any, optional)] + imag: OptionalArg, } fn parse_str(s: &str) -> Option { @@ -382,3 +389,31 @@ fn parse_str(s: &str) -> Option { }; 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> { + if let Some(complex) = obj.payload_if_exact::(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::() { + 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::(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) +} diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 5461baf04..8360f7806 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -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,12 +163,29 @@ impl PyFloat { vm: &VirtualMachine, ) -> PyResult> { 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::(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::(vm) { float_ops::parse_str(s.borrow_value().trim()).ok_or_else(|| { - vm.new_value_error(format!("could not convert string to float: '{}'", s)) + vm.new_value_error(format!( + "could not convert string to float: '{}'", + s + )) })? } else if let Some(bytes) = val.payload_if_subclass::(vm) { lexical_core::parse(bytes.borrow_value()).map_err(|_| { @@ -184,7 +201,6 @@ impl PyFloat { ))); } } - OptionalArg::Missing => 0.0, }; PyFloat::from(float_val).into_ref_with_type(vm, cls) } diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 0d685b5db..67507c656 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -262,6 +262,19 @@ impl PyInt { })?; try_int_radix(&val, base, vm) } else { + let val = if cls.is(&vm.ctx.types.int_type) { + match val.downcast_exact::(vm) { + Ok(i) => { + return Ok(i); + } + Err(val) => { + val + } + } + } else { + val + }; + try_int(&val, vm) } } else if let OptionalArg::Present(_) = options.base { @@ -709,66 +722,6 @@ struct IntToByteArgs { signed: OptionalArg, } -// Casting function: -pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult { - fn try_convert(obj: &PyObjectRef, lit: &[u8], vm: &VirtualMachine) -> PyResult { - 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::() { - 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::(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::() { - 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 { debug_assert!(base == 0 || (2..=36).contains(&base)); @@ -917,6 +870,65 @@ pub fn to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult { .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 { + fn try_convert(obj: &PyObjectRef, lit: &[u8], vm: &VirtualMachine) -> PyResult { + 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::() { + 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::(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::() { + 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); } From e572371a460796191b5f274e85b9e6ca7b2d93e3 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Tue, 17 Nov 2020 12:50:22 -0600 Subject: [PATCH 02/10] Fix behavior of pow builtin --- vm/src/builtins/complex.rs | 30 ++++++++- vm/src/builtins/make_module.rs | 64 ++++++++++-------- vm/src/{function.rs => function/mod.rs} | 0 vm/src/vm.rs | 87 +++++++++++++++---------- 4 files changed, 118 insertions(+), 63 deletions(-) rename vm/src/{function.rs => function/mod.rs} (100%) diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 7d0047a2f..963ce7136 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -64,6 +64,26 @@ fn inner_div(v1: Complex64, v2: Complex64, vm: &VirtualMachine) -> PyResult PyResult { + 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 { @@ -215,9 +235,14 @@ impl PyComplex { fn pow( &self, other: PyObjectRef, + mod_val: OptionalOption, vm: &VirtualMachine, ) -> PyResult> { - 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__")] @@ -226,7 +251,7 @@ impl PyComplex { other: PyObjectRef, vm: &VirtualMachine, ) -> PyResult> { - 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__")] @@ -294,6 +319,7 @@ impl PyComplex { } }; + let final_real = if imag_was_complex { real.re - imag.im } else { diff --git a/vm/src/builtins/make_module.rs b/vm/src/builtins/make_module.rs index f45a87c45..d9b573f01 100644 --- a/vm/src/builtins/make_module.rs +++ b/vm/src/builtins/make_module.rs @@ -24,12 +24,9 @@ mod decl { #[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, - }; + use crate::pyobject::{BorrowValue, Either, IdProtocol, ItemProtocol, PyCallable, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol, PyArithmaticValue}; use crate::readline::{Readline, ReadlineResult}; use crate::scope::Scope; use crate::sliceable; @@ -38,6 +35,7 @@ mod decl { use crate::{py_io, sysmodule}; use num_bigint::Sign; use num_traits::{Signed, ToPrimitive, Zero}; + use crate::builtins::PyInt; #[pyfunction] fn abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { @@ -177,7 +175,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")) }) } @@ -586,36 +584,46 @@ mod decl { fn pow( x: PyObjectRef, y: PyObjectRef, - mod_value: OptionalArg, + mod_value: OptionalOption, vm: &VirtualMachine, ) -> PyResult { - match mod_value { - OptionalArg::Missing => { + match mod_value.flatten() { + None => { vm.call_or_reflection(&x, &y, "__pow__", "__rpow__", |vm, x, y| { - Err(vm.new_unsupported_operand_error(x, y, "pow")) + Err(vm.new_unsupported_binop_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(), - )); + Some(z) => { + let try_pow_value = |obj: &PyObjectRef, args: (PyObjectRef, PyObjectRef, PyObjectRef)| -> Option { + 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")) } } } diff --git a/vm/src/function.rs b/vm/src/function/mod.rs similarity index 100% rename from vm/src/function.rs rename to vm/src/function/mod.rs diff --git a/vm/src/vm.rs b/vm/src/vm.rs index fb1656284..77ab0258c 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -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) @@ -1118,8 +1134,8 @@ impl VirtualMachine { method: &str, unsupported: F, ) -> PyResult - where - F: Fn(&VirtualMachine, &PyObjectRef, &PyObjectRef) -> PyResult, + where + F: Fn(&VirtualMachine, &PyObjectRef, &PyObjectRef) -> PyResult, { if let Some(method_or_err) = self.get_method(obj.clone(), method) { let method = method_or_err?; @@ -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); } From 926ac12c513f4f8f74c539d17a65d46d6fe1c78c Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Tue, 17 Nov 2020 21:46:32 -0600 Subject: [PATCH 03/10] Format and move code in `fn pow` to `__pow__` methods --- vm/src/builtins/complex.rs | 13 +++++-------- vm/src/builtins/float.rs | 22 ++++++++++++--------- vm/src/builtins/int.rs | 29 ++++++++++++++++++++++------ vm/src/builtins/make_module.rs | 35 ++++++++++++++++++++-------------- vm/src/vm.rs | 4 ++-- 5 files changed, 64 insertions(+), 39 deletions(-) diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 963ce7136..4c9942ecb 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -4,6 +4,7 @@ use num_traits::Zero; use super::float; use super::pystr::PyStr; use super::pytype::PyTypeRef; +use crate::function::{OptionalArg, OptionalOption}; use crate::pyobject::{ BorrowValue, IdProtocol, IntoPyObject, Never, PyArithmaticValue::{self, *}, @@ -12,7 +13,6 @@ use crate::pyobject::{ use crate::slots::{Comparable, Hashable, PyComparisonOp}; use crate::VirtualMachine; use rustpython_common::{float_ops, hash}; -use crate::function::{OptionalOption, OptionalArg}; /// Create a complex number from a real part and an optional imaginary part. /// @@ -73,13 +73,13 @@ fn inner_pow(v1: Complex64, v2: Complex64, vm: &VirtualMachine) -> PyResult { return Ok(c); } - Err(val) => { - val - } + Err(val) => val, } } else { val @@ -296,7 +294,7 @@ impl PyComplex { val.class().name ))); } - }, + } }; let (imag, imag_was_complex) = match args.imag { @@ -319,7 +317,6 @@ impl PyComplex { } }; - let final_real = if imag_was_complex { real.re - imag.im } else { diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 8360f7806..ccea1c7ad 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -170,9 +170,7 @@ impl PyFloat { Ok(f) => { return Ok(f); } - Err(val) => { - val - } + Err(val) => val, } } else { val @@ -182,10 +180,7 @@ impl PyFloat { f } else if let Some(s) = val.payload_if_subclass::(vm) { float_ops::parse_str(s.borrow_value().trim()).ok_or_else(|| { - vm.new_value_error(format!( - "could not convert string to float: '{}'", - s - )) + vm.new_value_error(format!("could not convert string to float: '{}'", s)) })? } else if let Some(bytes) = val.payload_if_subclass::(vm) { lexical_core::parse(bytes.borrow_value()).map_err(|_| { @@ -331,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, + 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__")] diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 67507c656..6c46f5861 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -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, @@ -267,9 +267,7 @@ impl PyInt { Ok(i) => { return Ok(i); } - Err(val) => { - val - } + Err(val) => val, } } else { val @@ -410,8 +408,27 @@ 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, + vm: &VirtualMachine, + ) -> PyResult { + match mod_val.flatten() { + Some(int_ref) => { + let int = match int_ref.payload_if_subclass::(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| 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__")] diff --git a/vm/src/builtins/make_module.rs b/vm/src/builtins/make_module.rs index d9b573f01..50ee6d5c5 100644 --- a/vm/src/builtins/make_module.rs +++ b/vm/src/builtins/make_module.rs @@ -19,14 +19,20 @@ 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, OptionalOption}; + 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, PyArithmaticValue}; + use crate::pyobject::{ + BorrowValue, Either, IdProtocol, ItemProtocol, PyArithmaticValue, PyCallable, PyIterable, + PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol, + }; use crate::readline::{Readline, ReadlineResult}; use crate::scope::Scope; use crate::sliceable; @@ -35,7 +41,6 @@ mod decl { use crate::{py_io, sysmodule}; use num_bigint::Sign; use num_traits::{Signed, ToPrimitive, Zero}; - use crate::builtins::PyInt; #[pyfunction] fn abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult { @@ -588,38 +593,40 @@ mod decl { vm: &VirtualMachine, ) -> PyResult { 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")) - }) - } + 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 { + let try_pow_value = |obj: &PyObjectRef, + args: (PyObjectRef, PyObjectRef, PyObjectRef)| + -> Option { 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)) + 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 + return val; } if !x.class().is(&y.class()) { if let Some(val) = try_pow_value(&y, (x.clone(), y.clone(), z.clone())) { - return val + return val; } } 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 + return val; } } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 77ab0258c..ce1baf5a8 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -1134,8 +1134,8 @@ impl VirtualMachine { method: &str, unsupported: F, ) -> PyResult - where - F: Fn(&VirtualMachine, &PyObjectRef, &PyObjectRef) -> PyResult, + where + F: Fn(&VirtualMachine, &PyObjectRef, &PyObjectRef) -> PyResult, { if let Some(method_or_err) = self.get_method(obj.clone(), method) { let method = method_or_err?; From b97aa409efb8c0a046fc641660fb0770bf88d9d4 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Tue, 17 Nov 2020 22:46:24 -0600 Subject: [PATCH 04/10] Not implemented --- vm/src/builtins/int.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 6c46f5861..ddf287f64 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -425,6 +425,9 @@ impl PyInt { if modulus.is_zero() { return Err(vm.new_value_error("pow() 3rd argument cannot be 0".to_owned())); } + if modulus.is_negative() { + return Err(vm.new_not_implemented_error("modular inverses".to_owned())); + } self.general_op(other, |a, b| Ok(vm.ctx.new_int(a.modpow(b, modulus))), vm) } None => self.general_op(other, |a, b| inner_pow(a, b, vm), vm), From 2277f4182782a53f33cb3a4ae2bbd9dae987c5cc Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:15:19 -0600 Subject: [PATCH 05/10] Actually fix negative check --- vm/src/builtins/int.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index ddf287f64..4bab115de 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -425,10 +425,13 @@ impl PyInt { if modulus.is_zero() { return Err(vm.new_value_error("pow() 3rd argument cannot be 0".to_owned())); } - if modulus.is_negative() { - return Err(vm.new_not_implemented_error("modular inverses".to_owned())); - } - self.general_op(other, |a, b| Ok(vm.ctx.new_int(a.modpow(b, modulus))), vm) + self.general_op(other, |a, b| { + if b.is_negative() { + Err(vm.new_not_implemented_error("modular inverses".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), } From 27b280b3ca04417ab99bedf4faa71ac6d8d8c225 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:33:54 -0600 Subject: [PATCH 06/10] fix error again --- vm/src/builtins/int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 4bab115de..614fac27f 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -427,7 +427,7 @@ impl PyInt { } self.general_op(other, |a, b| { if b.is_negative() { - Err(vm.new_not_implemented_error("modular inverses".to_owned())) + Err(vm.new_value_error("modular inverses not supported".to_owned())) } else { Ok(vm.ctx.new_int(a.modpow(b, modulus))) } From fa989d0a9b65f6480d48814d8680b4f2c5ab3549 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Thu, 19 Nov 2020 07:52:17 -0600 Subject: [PATCH 07/10] Format --- vm/src/builtins/int.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 614fac27f..7c71e118c 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -425,13 +425,17 @@ impl PyInt { 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) + 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), } From 0388dac94ae43021c6c295b822fafd73d2a1b78a Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Thu, 19 Nov 2020 08:46:09 -0600 Subject: [PATCH 08/10] Remove todos from tests --- Lib/test/test_complex.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 5fec1dea9..b72bd711b 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -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) From 24b36705168831bcebaa951bb7640c0e5c287d37 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sat, 21 Nov 2020 15:58:42 -0600 Subject: [PATCH 09/10] Allow clippy --- vm/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/lib.rs b/vm/src/lib.rs index bcd00bb68..8bb72641d 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -7,6 +7,7 @@ // for methods like vm.to_str(), not the typical use of 'to' as a method prefix #![allow(clippy::wrong_self_convention, clippy::implicit_hasher)] +#![allow(clippy::suspicious_else_formatting)] // to allow `mod foo {}` in foo.rs; clippy thinks this is a mistake/misunderstanding of // how `mod` works, but we want this sometimes for pymodule declarations #![allow(clippy::module_inception)] From 3efa8a4e6501d3f4a866b27fa6c6f4c6a5e03d26 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Sat, 21 Nov 2020 17:36:40 -0600 Subject: [PATCH 10/10] Move allow attribute to specific function --- vm/src/builtins/make_module.rs | 1 + vm/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/builtins/make_module.rs b/vm/src/builtins/make_module.rs index 50ee6d5c5..cf993c99c 100644 --- a/vm/src/builtins/make_module.rs +++ b/vm/src/builtins/make_module.rs @@ -585,6 +585,7 @@ mod decl { } } + #[allow(clippy::suspicious_else_formatting)] #[pyfunction] fn pow( x: PyObjectRef, diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 8bb72641d..bcd00bb68 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -7,7 +7,6 @@ // for methods like vm.to_str(), not the typical use of 'to' as a method prefix #![allow(clippy::wrong_self_convention, clippy::implicit_hasher)] -#![allow(clippy::suspicious_else_formatting)] // to allow `mod foo {}` in foo.rs; clippy thinks this is a mistake/misunderstanding of // how `mod` works, but we want this sometimes for pymodule declarations #![allow(clippy::module_inception)]