Mercurial > cpython-lru_cache-weakref
diff Objects/typeobject.c @ 48475:f4e7ef4329a9
Manual forward port of 64962 - use PyObject_HashNotImplemented as a tp_hash level indicator that the default hash implementation has not been inherited
| author | Nick Coghlan <ncoghlan@gmail.com> |
|---|---|
| date | Tue, 15 Jul 2008 15:46:38 +0000 |
| parents | 98827a21e352 |
| children | 85b67fb5672b |
line wrap: on
line diff
--- a/Objects/typeobject.c Tue Jul 15 15:32:09 2008 +0000 +++ b/Objects/typeobject.c Tue Jul 15 15:46:38 2008 +0000 @@ -3810,13 +3810,15 @@ /* Hack for tp_hash and __hash__. If after all that, tp_hash is still NULL, and __hash__ is not in - tp_dict, set tp_dict['__hash__'] equal to None. + tp_dict, set tp_hash to PyObject_HashNotImplemented and + tp_dict['__hash__'] equal to None. This signals that __hash__ is not inherited. */ if (type->tp_hash == NULL) { if (PyDict_GetItemString(type->tp_dict, "__hash__") == NULL) { if (PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0) goto error; + type->tp_hash = PyObject_HashNotImplemented; } } @@ -4943,9 +4945,7 @@ } if (func == NULL) { - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - Py_TYPE(self)->tp_name); - return -1; + return PyObject_HashNotImplemented(self); } res = PyEval_CallObject(func, NULL); @@ -5676,6 +5676,13 @@ sanity checks. I'll buy the first person to point out a bug in this reasoning a beer. */ } + else if (descr == Py_None && + strcmp(p->name, "__hash__") == 0) { + /* We specifically allow __hash__ to be set to None + to prevent inheritance of the default + implementation from object.__hash__ */ + specific = PyObject_HashNotImplemented; + } else { use_generic = 1; generic = p->function; @@ -5889,12 +5896,21 @@ continue; if (PyDict_GetItem(dict, p->name_strobj)) continue; - descr = PyDescr_NewWrapper(type, p, *ptr); - if (descr == NULL) - return -1; - if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) - return -1; - Py_DECREF(descr); + if (*ptr == PyObject_HashNotImplemented) { + /* Classes may prevent the inheritance of the tp_hash + slot by storing PyObject_HashNotImplemented in it. Make it + visible as a None value for the __hash__ attribute. */ + if (PyDict_SetItem(dict, p->name_strobj, Py_None) < 0) + return -1; + } + else { + descr = PyDescr_NewWrapper(type, p, *ptr); + if (descr == NULL) + return -1; + if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) + return -1; + Py_DECREF(descr); + } } if (type->tp_new != NULL) { if (add_tp_new_wrapper(type) < 0)
