__hash__ may now return long int; the final hash
value is obtained by invoking hash on the long int.
Fixes #1536021.
diff --git a/Doc/ref/ref3.tex b/Doc/ref/ref3.tex
index 8ec9e2b..15fc188 100644
--- a/Doc/ref/ref3.tex
+++ b/Doc/ref/ref3.tex
@@ -1307,6 +1307,11 @@
since the dictionary implementation requires that a key's hash value
is immutable (if the object's hash value changes, it will be in the
wrong hash bucket).
+
+\versionchanged[\method{__hash__()} may now also return a long
+integer object; the 32-bit integer is then derived from the hash
+of that object]{2.5}
+
\withsubitem{(object method)}{\ttindex{__cmp__()}}
\end{methoddesc}
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 70480be..26bfe87 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -640,6 +640,15 @@
def f(): pass
self.assertRaises(TypeError, hash, [])
self.assertRaises(TypeError, hash, {})
+ # Bug 1536021: Allow hash to return long objects
+ class X:
+ def __hash__(self):
+ return 2**100
+ self.assertEquals(type(hash(X())), int)
+ class Y(object):
+ def __hash__(self):
+ return 2**100
+ self.assertEquals(type(hash(Y())), int)
def test_hex(self):
self.assertEqual(hex(16), '0x10')
diff --git a/Misc/NEWS b/Misc/NEWS
index 24b1645..d7f17a4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@
Core and builtins
-----------------
+- Bug #1536021: __hash__ may now return long int; the final hash
+ value is obtained by invoking hash on the long int.
+
- Bug #1536786: buffer comparison could emit a RuntimeWarning.
- Bug #1535165: fixed a segfault in input() and raw_input() when
diff --git a/Objects/classobject.c b/Objects/classobject.c
index c69ba74..56bf29c 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -934,11 +934,9 @@
Py_DECREF(func);
if (res == NULL)
return -1;
- if (PyInt_Check(res)) {
- outcome = PyInt_AsLong(res);
- if (outcome == -1)
- outcome = -2;
- }
+ if (PyInt_Check(res) || PyLong_Check(res))
+ /* This already converts a -1 result to -2. */
+ outcome = res->ob_type->tp_hash(res);
else {
PyErr_SetString(PyExc_TypeError,
"__hash__() should return an int");
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 67e6104..652009b 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4559,7 +4559,10 @@
Py_DECREF(func);
if (res == NULL)
return -1;
- h = PyInt_AsLong(res);
+ if (PyLong_Check(res))
+ h = res->ob_type->tp_hash(res);
+ else
+ h = PyInt_AsLong(res);
Py_DECREF(res);
}
else {