Ticket #326, coerce -1 to -2 for __hash__
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 3 Jun 2009 10:17:42 +0000 (03:17 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 3 Jun 2009 10:17:42 +0000 (03:17 -0700)
Cython/Compiler/Nodes.py
tests/run/hash_T326.pyx [new file with mode: 0644]

index 0b572e7eed8d16a06dd4485d089541f7b1e7f832..67d8f2c1ec9143190450869868c377f347d8c5c0 100644 (file)
@@ -1228,6 +1228,11 @@ class FuncDefNode(StatNode, BlockNode):
 
             code.put_finish_refcount_context()
 
+        if self.entry.is_special and self.entry.name == "__hash__":
+            # Returning -1 for __hash__ is supposed to signal an error
+            # We do as Python instances and coerce -1 into -2. 
+            code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (Naming.retval_cname, Naming.retval_cname))
+
         if acquire_gil:
             code.putln("PyGILState_Release(_save);")
 
diff --git a/tests/run/hash_T326.pyx b/tests/run/hash_T326.pyx
new file mode 100644 (file)
index 0000000..bd850e9
--- /dev/null
@@ -0,0 +1,29 @@
+__doc__ = u"""
+
+    >>> hash(A(5))
+    5
+    >>> hash(A(-1))
+    -2
+    >>> hash(A(-2))
+    -2
+    >>> hash(A(100))
+    Traceback (most recent call last):
+    ...
+    TypeError: That's kind of a round number...
+    
+    >>> __hash__(-1)
+    -1
+"""
+
+cdef class A:
+    cdef long a
+    def __init__(self, a):
+        self.a = a
+    def __hash__(self):
+        if self.a == 100:
+            raise TypeError, "That's kind of a round number..."
+        else:
+            return self.a
+
+cpdef long __hash__(long x):
+    return x