summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-08-10 21:24:08 (GMT)
committerGuido van Rossum <guido@python.org>2001-08-10 21:24:08 (GMT)
commit13d52f0b3289e34298fbf5d3912cb642f3d2fbd9 (patch)
treeddccff20e1c079a0c40b1cb7751fe357cd5f64cf
parentf24b2f32850625dc56d510e2a5d019641bd06b4e (diff)
downloadcpython-13d52f0b3289e34298fbf5d3912cb642f3d2fbd9.zip
cpython-13d52f0b3289e34298fbf5d3912cb642f3d2fbd9.tar.gz
cpython-13d52f0b3289e34298fbf5d3912cb642f3d2fbd9.tar.bz2
- Big changes to fix SF bug #442833 (a nasty multiple inheritance
problem). inherit_slots() is split in two parts: inherit_special() which inherits the flags and a few very special members from the dominant base; inherit_slots() which inherits only regular slots, and is now called for each base in the MRO in turn. These are now both void functions since they don't have error returns. - Added object.__setitem__() back -- for the same reason as object.__new__(): a subclass of object should be able to call object.__new__(). - add_wrappers() was moved around to be closer to where it is used (it was defined together with add_methods() etc., but has nothing to do with these).
-rw-r--r--Objects/typeobject.c213
1 files changed, 122 insertions, 91 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 926d151..37d9491 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4,8 +4,6 @@
#include "Python.h"
#include "structmember.h"
-staticforward int add_members(PyTypeObject *, struct memberlist *);
-
static struct memberlist type_members[] = {
{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
@@ -647,7 +645,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
slotoffset += sizeof(PyObject *);
}
type->tp_basicsize = slotoffset;
- add_members(type, et->members);
+ type->tp_members = et->members;
/* Special case some slots */
if (type->tp_dictoffset != 0 || nslots > 0) {
@@ -882,7 +880,7 @@ PyTypeObject PyBaseObject_Type = {
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
"The most base type", /* tp_doc */
@@ -929,25 +927,6 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
}
static int
-add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
-{
- PyObject *dict = type->tp_defined;
-
- for (; wraps->name != NULL; wraps++) {
- PyObject *descr;
- if (PyDict_GetItemString(dict, wraps->name))
- continue;
- descr = PyDescr_NewWrapper(type, wraps, wrapped);
- if (descr == NULL)
- return -1;
- if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
- return -1;
- Py_DECREF(descr);
- }
- return 0;
-}
-
-static int
add_members(PyTypeObject *type, struct memberlist *memb)
{
PyObject *dict = type->tp_defined;
@@ -986,27 +965,90 @@ add_getset(PyTypeObject *type, struct getsetlist *gsp)
return 0;
}
-staticforward int add_operators(PyTypeObject *);
+static void
+inherit_special(PyTypeObject *type, PyTypeObject *base)
+{
+ int oldsize, newsize;
-static int
+ /* Special flag magic */
+ if (!type->tp_as_buffer && base->tp_as_buffer) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ type->tp_flags |=
+ base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ }
+ if (!type->tp_as_sequence && base->tp_as_sequence) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ }
+ if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
+ (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
+ if ((!type->tp_as_number && base->tp_as_number) ||
+ (!type->tp_as_sequence && base->tp_as_sequence)) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
+ if (!type->tp_as_number && !type->tp_as_sequence) {
+ type->tp_flags |= base->tp_flags &
+ Py_TPFLAGS_HAVE_INPLACEOPS;
+ }
+ }
+ /* Wow */
+ }
+ if (!type->tp_as_number && base->tp_as_number) {
+ type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
+ }
+
+ /* Copying basicsize is connected to the GC flags */
+ oldsize = PyType_BASICSIZE(base);
+ newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
+ if (!(type->tp_flags & Py_TPFLAGS_GC) &&
+ (base->tp_flags & Py_TPFLAGS_GC) &&
+ (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
+ (!type->tp_traverse && !type->tp_clear)) {
+ type->tp_flags |= Py_TPFLAGS_GC;
+ if (type->tp_traverse == NULL)
+ type->tp_traverse = base->tp_traverse;
+ if (type->tp_clear == NULL)
+ type->tp_clear = base->tp_clear;
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ if (base != &PyBaseObject_Type ||
+ (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ if (type->tp_new == NULL)
+ type->tp_new = base->tp_new;
+ }
+ }
+ PyType_SET_BASICSIZE(type, newsize);
+}
+
+static void
inherit_slots(PyTypeObject *type, PyTypeObject *base)
{
- int oldsize, newsize;
+ PyTypeObject *basebase;
+#undef SLOTDEFINED
#undef COPYSLOT
#undef COPYNUM
#undef COPYSEQ
#undef COPYMAP
+
+#define SLOTDEFINED(SLOT) \
+ (base->SLOT != 0 && \
+ (basebase == NULL || base->SLOT != basebase->SLOT))
+
#define COPYSLOT(SLOT) \
- if (!type->SLOT) type->SLOT = base->SLOT
+ if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT
#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
- if (type->tp_as_number == NULL)
- type->tp_as_number = base->tp_as_number;
- else if (base->tp_as_number) {
+ /* This won't inherit indirect slots (from tp_as_number etc.)
+ if type doesn't provide the space. */
+
+ if (type->tp_as_number != NULL && base->tp_as_number != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_number == NULL)
+ basebase = NULL;
COPYNUM(nb_add);
COPYNUM(nb_subtract);
COPYNUM(nb_multiply);
@@ -1049,9 +1091,10 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
}
}
- if (type->tp_as_sequence == NULL)
- type->tp_as_sequence = base->tp_as_sequence;
- else if (base->tp_as_sequence) {
+ if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_sequence == NULL)
+ basebase = NULL;
COPYSEQ(sq_length);
COPYSEQ(sq_concat);
COPYSEQ(sq_repeat);
@@ -1064,53 +1107,16 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
COPYSEQ(sq_inplace_repeat);
}
- if (type->tp_as_mapping == NULL)
- type->tp_as_mapping = base->tp_as_mapping;
- else if (base->tp_as_mapping) {
+ if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_mapping == NULL)
+ basebase = NULL;
COPYMAP(mp_length);
COPYMAP(mp_subscript);
COPYMAP(mp_ass_subscript);
}
- /* Special flag magic */
- if (!type->tp_as_buffer && base->tp_as_buffer) {
- type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
- type->tp_flags |=
- base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
- }
- if (!type->tp_as_sequence && base->tp_as_sequence) {
- type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
- type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
- }
- if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
- (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
- if ((!type->tp_as_number && base->tp_as_number) ||
- (!type->tp_as_sequence && base->tp_as_sequence)) {
- type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
- if (!type->tp_as_number && !type->tp_as_sequence) {
- type->tp_flags |= base->tp_flags &
- Py_TPFLAGS_HAVE_INPLACEOPS;
- }
- }
- /* Wow */
- }
- if (!type->tp_as_number && base->tp_as_number) {
- type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
- type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
- }
-
- /* Copying basicsize is connected to the GC flags */
- oldsize = PyType_BASICSIZE(base);
- newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
- if (!(type->tp_flags & Py_TPFLAGS_GC) &&
- (base->tp_flags & Py_TPFLAGS_GC) &&
- (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
- (!type->tp_traverse && !type->tp_clear)) {
- type->tp_flags |= Py_TPFLAGS_GC;
- COPYSLOT(tp_traverse);
- COPYSLOT(tp_clear);
- }
- PyType_SET_BASICSIZE(type, newsize);
+ basebase = base->tp_base;
COPYSLOT(tp_itemsize);
COPYSLOT(tp_dealloc);
@@ -1152,16 +1158,12 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
COPYSLOT(tp_dictoffset);
COPYSLOT(tp_init);
COPYSLOT(tp_alloc);
- if (base != &PyBaseObject_Type ||
- (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
- COPYSLOT(tp_new);
- }
COPYSLOT(tp_free);
}
-
- return 0;
}
+staticforward int add_operators(PyTypeObject *);
+
int
PyType_Ready(PyTypeObject *type)
{
@@ -1237,34 +1239,44 @@ PyType_Ready(PyTypeObject *type)
goto error;
}
+ /* Inherit special flags from dominant base */
+ if (type->tp_base != NULL)
+ inherit_special(type, type->tp_base);
+
/* Initialize tp_dict properly */
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
/* For a static type, tp_dict is the consolidation
- of the tp_defined of its bases in MRO. Earlier
- bases override later bases; since d.update() works
- the other way, we walk the MRO sequence backwards. */
+ of the tp_defined of its bases in MRO. */
Py_DECREF(type->tp_dict);
- type->tp_dict = PyDict_New();
+ type->tp_dict = PyDict_Copy(type->tp_defined);
if (type->tp_dict == NULL)
goto error;
bases = type->tp_mro;
assert(bases != NULL);
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
- for (i = n; --i >= 0; ) {
+ for (i = 1; i < n; i++) {
base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
assert(PyType_Check(base));
x = base->tp_defined;
- if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
+ if (x != NULL && PyDict_Merge(type->tp_dict, x, 0) < 0)
goto error;
+ inherit_slots(type, base);
}
}
- /* Inherit slots from direct base */
- if (type->tp_base != NULL)
- if (inherit_slots(type, type->tp_base) < 0)
- goto error;
+ /* Some more special stuff */
+ base = type->tp_base;
+ if (base != NULL) {
+ if (type->tp_as_number == NULL)
+ type->tp_as_number = base->tp_as_number;
+ if (type->tp_as_sequence == NULL)
+ type->tp_as_sequence = base->tp_as_sequence;
+ if (type->tp_as_mapping == NULL)
+ type->tp_as_mapping = base->tp_as_mapping;
+ }
+ /* All done -- set the ready flag */
assert(type->tp_dict != NULL);
type->tp_flags =
(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
@@ -1911,6 +1923,25 @@ add_tp_new_wrapper(PyTypeObject *type)
return PyDict_SetItemString(type->tp_defined, "__new__", func);
}
+static int
+add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
+{
+ PyObject *dict = type->tp_defined;
+
+ for (; wraps->name != NULL; wraps++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, wraps->name))
+ continue;
+ descr = PyDescr_NewWrapper(type, wraps, wrapped);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
/* This function is called by PyType_Ready() to populate the type's
dictionary with method descriptors for function slots. For each
function slot (like tp_repr) that's defined in the type, one or