Author: Carl Friedrich Bolz-Tereick <[email protected]>
Branch: 
Changeset: r93721:14e8d60878c2
Date: 2018-01-30 13:02 +0100
http://bitbucket.org/pypy/pypy/changeset/14e8d60878c2/

Log:    when tp_hash is NULL and either tp_compare or tp_richcompare are
        Null then set __hash__ to None making the type unhashable

        fixes #2740

diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -259,6 +259,11 @@
         cmpr = module.OldCmpType()
         assert cmpr < cmpr
 
+    def test_unhashable_when_tpcompare(self):
+        module = self.import_module("comparisons")
+        cmpr = module.OldCmpType()
+        raises(TypeError, hash, cmpr)
+
     def test_hash(self):
         module = self.import_module("comparisons")
         cmpr = module.CmpType()
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -340,8 +340,12 @@
         if len(slot_names) == 1:
             func = getattr(pto, slot_names[0])
             if slot_names[0] == 'c_tp_hash':
-                if hash_not_impl == func:
-                    # special case for tp_hash == PyObject_HashNotImplemented
+                # two special cases where __hash__ is explicitly set to None
+                # (which leads to an unhashable type):
+                # 1) tp_hash == PyObject_HashNotImplemented
+                # 2) tp_hash == NULL and either of tp_compare or 
tp_richcompare are not NULL
+                if hash_not_impl == func or (
+                        not func and (pto.c_tp_compare or 
pto.c_tp_richcompare)):
                     dict_w[method_name] = space.w_None
                     continue
         else:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to