summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2006-08-21 23:36:26 (GMT)
committerGuido van Rossum <guido@python.org>2006-08-21 23:36:26 (GMT)
commit389381564cfa936c8e50bc51dc53b55cba857652 (patch)
tree7259a38e0d6c06e5519276336ed26a593166de1d /Objects
parent5431ee4a499e173c5638297de30a965ed2206c66 (diff)
downloadcpython-389381564cfa936c8e50bc51dc53b55cba857652.zip
cpython-389381564cfa936c8e50bc51dc53b55cba857652.tar.gz
cpython-389381564cfa936c8e50bc51dc53b55cba857652.tar.bz2
Change the way __hash__ is inherited; when __eq__ or __cmp__ is overridden
but __hash__ is not, set __hash__ explicitly to None (and tp_hash to NULL). All unit tests pass now!
Diffstat (limited to 'Objects')
-rw-r--r--Objects/object.c9
-rw-r--r--Objects/typeobject.c58
2 files changed, 55 insertions, 12 deletions
diff --git a/Objects/object.c b/Objects/object.c
index cb60320..80111b4 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -320,9 +320,16 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
return internal_print(op, fp, flags, 0);
}
+/* For debugging convenience. Set a breakpoint here and call it from your DLL */
+void
+_Py_Break(void)
+{
+}
+
/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */
-void _PyObject_Dump(PyObject* op)
+void
+_PyObject_Dump(PyObject* op)
{
if (op == NULL)
fprintf(stderr, "NULL\n");
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 1578801..f30a826 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2847,6 +2847,33 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
COPYVAL(tp_dictoffset);
}
+/* Map rich comparison operators to their __xx__ namesakes */
+static char *name_op[] = {
+ "__lt__",
+ "__le__",
+ "__eq__",
+ "__ne__",
+ "__gt__",
+ "__ge__",
+ /* These are only for overrides_cmp_or_hash(): */
+ "__cmp__",
+ "__hash__",
+};
+
+static int
+overrides_cmp_or_hash(PyTypeObject *type)
+{
+ int i;
+ PyObject *dict = type->tp_dict;
+
+ assert(dict != NULL);
+ for (i = 0; i < 8; i++) {
+ if (PyDict_GetItemString(dict, name_op[i]) != NULL)
+ return 1;
+ }
+ return 0;
+}
+
static void
inherit_slots(PyTypeObject *type, PyTypeObject *base)
{
@@ -2970,9 +2997,12 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
COPYSLOT(tp_call);
COPYSLOT(tp_str);
{
+ /* Copy comparison-related slots only when
+ not overriding them anywhere */
if (type->tp_compare == NULL &&
type->tp_richcompare == NULL &&
- type->tp_hash == NULL)
+ type->tp_hash == NULL &&
+ !overrides_cmp_or_hash(type))
{
type->tp_compare = base->tp_compare;
type->tp_richcompare = base->tp_richcompare;
@@ -3020,6 +3050,10 @@ PyType_Ready(PyTypeObject *type)
PyTypeObject *base;
Py_ssize_t i, n;
+ if (strcmp(type->tp_name, "C") == 0) {
+ _Py_Break();
+ }
+
if (type->tp_flags & Py_TPFLAGS_READY) {
assert(type->tp_dict != NULL);
return 0;
@@ -3150,6 +3184,18 @@ PyType_Ready(PyTypeObject *type)
}
}
+ /* 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.
+ 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;
+ }
+ }
+
/* Some more special stuff */
base = type->tp_base;
if (base != NULL) {
@@ -4450,16 +4496,6 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
return 0;
}
-/* Map rich comparison operators to their __xx__ namesakes */
-static char *name_op[] = {
- "__lt__",
- "__le__",
- "__eq__",
- "__ne__",
- "__gt__",
- "__ge__",
-};
-
static PyObject *
half_richcompare(PyObject *self, PyObject *other, int op)
{