diff --git a/Cargo.lock b/Cargo.lock index efe6c395c..f3cce34d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,11 +874,10 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +checksum = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5" dependencies = [ - "autocfg", "num-traits", "serde", ] @@ -1320,6 +1319,7 @@ dependencies = [ "hexf-parse", "lexical-core", "num-bigint", + "num-complex", "num-traits", "parking_lot", "rand", diff --git a/bytecode/Cargo.toml b/bytecode/Cargo.toml index 95206a3bf..2188e8d18 100644 --- a/bytecode/Cargo.toml +++ b/bytecode/Cargo.toml @@ -13,6 +13,6 @@ bincode = "1.1" bitflags = "1.1" lz4-compression = "0.7" num-bigint = { version = "0.3", features = ["serde"] } -num-complex = { version = "0.2", features = ["serde"] } +num-complex = { version = "0.3", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } itertools = "0.9" diff --git a/common/Cargo.toml b/common/Cargo.toml index 951660bfb..986697cc0 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,6 +10,7 @@ threading = ["parking_lot"] [dependencies] parking_lot = { version = "0.11.0", optional = true } num-traits = "0.2" +num-complex = "0.3" num-bigint = "0.3" lexical-core = "0.7" hexf-parse = "0.1.0" diff --git a/common/src/hash.rs b/common/src/hash.rs index 58c554f43..2e683a151 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -1,7 +1,9 @@ use num_bigint::BigInt; +use num_complex::Complex64; use num_traits::ToPrimitive; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; +use std::num::Wrapping; pub type PyHash = i64; pub type PyUHash = u64; @@ -79,6 +81,13 @@ pub fn hash_float(value: f64) -> PyHash { x as PyHash * value.signum() as PyHash } +pub fn hash_complex(value: &Complex64) -> PyHash { + let re_hash = hash_float(value.re); + let im_hash = hash_float(value.im); + let ret = Wrapping(re_hash) + Wrapping(im_hash) * Wrapping(IMAG); + ret.0 +} + pub fn hash_iter<'a, T: 'a, I, F, E>(iter: I, hashf: F) -> Result where I: IntoIterator, diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 6846c4386..9c73674ee 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -12,6 +12,6 @@ indexmap = "1.0" itertools = "0.9" rustpython-bytecode = { path = "../bytecode", version = "0.1.1" } rustpython-parser = { path = "../parser", version = "0.1.1" } -num-complex = { version = "0.2", features = ["serde"] } +num-complex = { version = "0.3", features = ["serde"] } log = "0.4" arrayvec = "0.5" diff --git a/vm/Cargo.toml b/vm/Cargo.toml index f7a9ac5a8..19e2da12e 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -28,7 +28,7 @@ sha3 = "0.8" blake2 = "0.8" volatile = "0.2" -num-complex = { version = "0.2.2", features = ["serde"] } +num-complex = { version = "0.3", features = ["serde"] } num-bigint = { version = "0.3", features = ["serde"] } num-traits = "0.2.8" num-integer = "0.1.41" diff --git a/vm/src/obj/objcomplex.rs b/vm/src/obj/objcomplex.rs index 7da74eb42..ea4327d46 100644 --- a/vm/src/obj/objcomplex.rs +++ b/vm/src/obj/objcomplex.rs @@ -1,6 +1,5 @@ use num_complex::Complex64; use num_traits::Zero; -use std::num::Wrapping; use std::str::FromStr; use super::objfloat::{self, IntoPyFloat, PyFloat}; @@ -9,8 +8,8 @@ use super::objstr::PyString; use super::objtype::PyClassRef; use crate::function::OptionalArg; use crate::pyobject::{ - BorrowValue, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, - TypeProtocol, + BorrowValue, IntoPyObject, Never, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, + PyValue, TypeProtocol, }; use crate::vm::VirtualMachine; use rustpython_common::hash; @@ -89,15 +88,11 @@ impl PyComplex { } #[pymethod(name = "__add__")] + #[pymethod(name = "__radd__")] fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.op(other, |a, b| a + b, vm) } - #[pymethod(name = "__radd__")] - fn radd(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.add(other, vm) - } - #[pymethod(name = "__sub__")] fn sub(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.op(other, |a, b| a - b, vm) @@ -129,25 +124,21 @@ impl PyComplex { } #[pymethod(name = "__float__")] - fn float(&self, vm: &VirtualMachine) -> PyResult<()> { + fn float(&self, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error(String::from("Can't convert complex to float"))) } #[pymethod(name = "__int__")] - fn int(&self, vm: &VirtualMachine) -> PyResult<()> { + fn int(&self, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error(String::from("Can't convert complex to int"))) } #[pymethod(name = "__mul__")] + #[pymethod(name = "__rmul__")] fn mul(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.op(other, |a, b| a * b, vm) } - #[pymethod(name = "__rmul__")] - fn rmul(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.mul(other, vm) - } - #[pymethod(name = "__truediv__")] fn truediv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.op(other, |a, b| a / b, vm) @@ -159,33 +150,21 @@ impl PyComplex { } #[pymethod(name = "__mod__")] - fn mod_(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + #[pymethod(name = "__rmod__")] + fn mod_(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error("can't mod complex numbers.".to_owned())) } - #[pymethod(name = "__rmod__")] - fn rmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.mod_(other, vm) - } - #[pymethod(name = "__floordiv__")] - fn floordiv(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + #[pymethod(name = "__rfloordiv__")] + fn floordiv(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error("can't take floor of complex number.".to_owned())) } - #[pymethod(name = "__rfloordiv__")] - fn rfloordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.floordiv(other, vm) - } - #[pymethod(name = "__divmod__")] - fn divmod(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - Err(vm.new_type_error("can't take floor or mod of complex number.".to_owned())) - } - #[pymethod(name = "__rdivmod__")] - fn rdivmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.divmod(other, vm) + fn divmod(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Err(vm.new_type_error("can't take floor or mod of complex number.".to_owned())) } #[pymethod(name = "__pos__")] @@ -247,7 +226,7 @@ impl PyComplex { } let value = Complex64::from_str(s.borrow_value()) .map_err(|err| vm.new_value_error(err.to_string()))?; - return PyComplex { value }.into_ref_with_type(vm, cls); + return Self::from(value).into_ref_with_type(vm, cls); } obj => { return Err(vm.new_type_error(format!( @@ -264,15 +243,12 @@ impl PyComplex { }; let value = Complex64::new(real, imag); - PyComplex { value }.into_ref_with_type(vm, cls) + Self::from(value).into_ref_with_type(vm, cls) } #[pymethod(name = "__hash__")] fn hash(&self) -> hash::PyHash { - let re_hash = hash::hash_float(self.value.re); - let im_hash = hash::hash_float(self.value.im); - let ret = Wrapping(re_hash) + Wrapping(im_hash) * Wrapping(hash::IMAG); - ret.0 + hash::hash_complex(&self.value) } #[pymethod(name = "__getnewargs__")] diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 41d167e92..9ed0eae4e 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -834,7 +834,7 @@ pub trait IdProtocol { } } -type Never = std::convert::Infallible; +pub type Never = std::convert::Infallible; impl PyValue for Never { fn class(_vm: &VirtualMachine) -> PyClassRef {