diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index b7c20041d00..9823f189a26 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -5,7 +5,7 @@ use crate::{ AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, builtins::{PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyTypeRef}, bytecode::ComparisonOperator, - common::hash::PyHash, + common::hash::{PyHash, fix_sentinel, hash_bigint}, convert::ToPyObject, function::{ Either, FromArgs, FuncArgs, OptionalArg, PyComparisonValue, PyMethodDef, PySetterValue, @@ -18,7 +18,6 @@ use crate::{ vm::Context, }; use crossbeam_utils::atomic::AtomicCell; -use malachite_bigint::BigInt; use num_traits::{Signed, ToPrimitive}; use std::{any::Any, any::TypeId, borrow::Borrow, cmp::Ordering, ops::Deref}; @@ -412,9 +411,10 @@ fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { .downcast_ref::() .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer"))?; let big_int = py_int.as_bigint(); - let hash: PyHash = big_int + let hash = big_int .to_i64() - .unwrap_or_else(|| (big_int % BigInt::from(u64::MAX)).to_i64().unwrap()); + .map(fix_sentinel) + .unwrap_or_else(|| hash_bigint(big_int)); Ok(hash) } diff --git a/extra_tests/snippets/builtin_hash.py b/extra_tests/snippets/builtin_hash.py index 96ccc46ba80..9b2c8388790 100644 --- a/extra_tests/snippets/builtin_hash.py +++ b/extra_tests/snippets/builtin_hash.py @@ -12,6 +12,14 @@ class A: assert type(hash(1.1)) is int assert type(hash("")) is int + +class Evil: + def __hash__(self): + return 1 << 63 + + +assert hash(Evil()) == 4 + with assert_raises(TypeError): hash({})