Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: 
Changeset: r86451:eeb7fd8a6676
Date: 2016-08-23 16:27 +0100
http://bitbucket.org/pypy/pypy/changeset/eeb7fd8a6676/

Log:    Make sure that hash(x) == x.__hash__() for int, long

diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -362,11 +362,10 @@
         return _new_int(space, w_inttype, w_x, w_base)
 
     def descr_hash(self, space):
-        # unlike CPython, we don't special-case the value -1 in most of
-        # our hash functions, so there is not much sense special-casing
-        # it here either.  Make sure this is consistent with the hash of
-        # floats and longs.
-        return self.int(space)
+        # For compatibility with CPython, we special-case -1
+        h = self.intval
+        h -= (h == -1)  # No explicit condition, to avoid JIT bridges
+        return wrapint(space, h)
 
     def _int(self, space):
         return self.int(space)
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -130,7 +130,12 @@
 
     descr_repr = _make_descr_unaryop('repr')
     descr_str = _make_descr_unaryop('str')
-    descr_hash = _make_descr_unaryop('hash')
+
+    def descr_hash(self, space):
+        h = self.asbigint().hash()
+        h -= (h == -1)
+        return space.newint(h)
+
     descr_oct = _make_descr_unaryop('oct')
     descr_hex = _make_descr_unaryop('hex')
 
@@ -387,12 +392,12 @@
     def _make_generic_descr_binop(opname):
         if opname not in COMMUTATIVE_OPS:
             raise Exception("Not supported")
-            
+
         methname = opname + '_' if opname in ('and', 'or') else opname
         descr_rname = 'descr_r' + opname
         op = getattr(rbigint, methname)
         intop = getattr(rbigint, "int_" + methname)
-        
+
         @func_renamer('descr_' + opname)
         def descr_binop(self, space, w_other):
             if isinstance(w_other, W_AbstractIntObject):
@@ -412,7 +417,7 @@
             return W_LongObject(op(w_other.asbigint(), self.num))
 
         return descr_binop, descr_rbinop
-        
+
     descr_add, descr_radd = _make_generic_descr_binop('add')
     descr_sub, descr_rsub = _make_generic_descr_binop_noncommutative('sub')
     descr_mul, descr_rmul = _make_generic_descr_binop('mul')
@@ -454,12 +459,12 @@
         except OverflowError:   # b too big
             raise oefmt(space.w_OverflowError, "shift count too large")
         return W_LongObject(self.num.lshift(shift))
-        
+
     def _int_lshift(self, space, w_other):
         if w_other < 0:
             raise oefmt(space.w_ValueError, "negative shift count")
         return W_LongObject(self.num.lshift(w_other))
-        
+
     descr_lshift, descr_rlshift = _make_descr_binop(_lshift, _int_lshift)
 
     def _rshift(self, space, w_other):
@@ -470,7 +475,7 @@
         except OverflowError:   # b too big # XXX maybe just return 0L instead?
             raise oefmt(space.w_OverflowError, "shift count too large")
         return newlong(space, self.num.rshift(shift))
-        
+
     def _int_rshift(self, space, w_other):
         if w_other < 0:
             raise oefmt(space.w_ValueError, "negative shift count")
@@ -485,7 +490,7 @@
             raise oefmt(space.w_ZeroDivisionError,
                         "long division or modulo by zero")
         return newlong(space, z)
-        
+
     def _floordiv(self, space, w_other):
         try:
             z = self.num.floordiv(w_other.asbigint())
@@ -505,7 +510,7 @@
             raise oefmt(space.w_ZeroDivisionError,
                         "long division or modulo by zero")
         return newlong(space, z)
-        
+
     def _int_mod(self, space, w_other):
         try:
             z = self.num.int_mod(w_other)
diff --git a/pypy/objspace/std/test/test_intobject.py 
b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -295,7 +295,11 @@
         assert self.space.unwrap(result) == hex(x)
 
 
-class AppTestInt:
+class AppTestInt(object):
+    def test_hash(self):
+        assert hash(-1) == (-1).__hash__() == -2
+        assert hash(-2) == (-2).__hash__() == -2
+
     def test_conjugate(self):
         assert (1).conjugate() == 1
         assert (-1).conjugate() == -1
@@ -454,11 +458,11 @@
                 return None
         inst = a()
         raises(TypeError, int, inst)
-        assert inst.ar == True 
+        assert inst.ar == True
 
         class b(object):
-            pass 
-        raises((AttributeError,TypeError), int, b()) 
+            pass
+        raises((AttributeError,TypeError), int, b())
 
     def test_special_long(self):
         class a(object):
diff --git a/pypy/objspace/std/test/test_longobject.py 
b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -228,7 +228,7 @@
     def test_hash(self):
         # ints have the same hash as equal longs
         for i in range(-4, 14):
-            assert hash(i) == hash(long(i))
+            assert hash(i) == hash(long(i)) == long(i).__hash__()
         # might check too much -- it's ok to change the hashing algorithm
         assert hash(123456789L) == 123456789
         assert hash(1234567890123456789L) in (
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to