diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 53d760cc8..3250bef80 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -303,8 +303,7 @@ fn builtin_hasattr(obj: PyObjectRef, attr: PyStringRef, vm: &VirtualMachine) -> fn builtin_hash(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, None)]); - - vm.call_method(obj, "__hash__", vec![]) + vm._hash(obj).and_then(|v| Ok(vm.new_int(v))) } // builtin_help diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 814631015..eab6fca8c 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -23,6 +23,7 @@ use crate::obj::objcode::PyCodeRef; use crate::obj::objdict::PyDictRef; use crate::obj::objfunction::{PyFunction, PyMethod}; use crate::obj::objgenerator::PyGenerator; +use crate::obj::objint; use crate::obj::objiter; use crate::obj::objsequence; use crate::obj::objstr::{PyString, PyStringRef}; @@ -36,6 +37,7 @@ use crate::pyobject::{ use crate::stdlib; use crate::sysmodule; use num_bigint::BigInt; +use num_traits::ToPrimitive; // use objects::objects; @@ -912,6 +914,19 @@ impl VirtualMachine { }) } + pub fn _hash(&self, obj: &PyObjectRef) -> PyResult { + const PRIME: usize = 0x1fff_ffff_ffff_ffff; + let hash_obj = self.call_method(obj, "__hash__", vec![])?; + if objtype::isinstance(&hash_obj, &self.ctx.int_type()) { + let hash_int = objint::get_value(&hash_obj); + Ok(hash_int + .to_usize() + .unwrap_or_else(|| (hash_int % PRIME).to_usize().unwrap())) + } else { + Err(self.new_type_error("__hash__ method should return an integer".to_string())) + } + } + // https://docs.python.org/3/reference/expressions.html#membership-test-operations fn _membership_iter_search(&self, haystack: PyObjectRef, needle: PyObjectRef) -> PyResult { let iter = objiter::get_iter(self, &haystack)?;