diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2011-10-23 12:04:16 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2011-10-23 12:04:16 (GMT) |
commit | de31b191e570d00ed7917c7f9ea28af3e770c16d (patch) | |
tree | 1139df0a3f75762d2acc5e6a5d964f62893fd68c /Objects/typeobject.c | |
parent | 711f87ca7d8b455feb450b2fb66a3d264fd603ce (diff) | |
download | cpython-de31b191e570d00ed7917c7f9ea28af3e770c16d.zip cpython-de31b191e570d00ed7917c7f9ea28af3e770c16d.tar.gz cpython-de31b191e570d00ed7917c7f9ea28af3e770c16d.tar.bz2 |
Issue 1294232: Fix errors in metaclass calculation affecting some cases of metaclass inheritance. Patch by Daniel Urban.
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r-- | Objects/typeobject.c | 61 |
1 files changed, 41 insertions, 20 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 856a4a5..9f62401 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1912,6 +1912,42 @@ PyType_GetFlags(PyTypeObject *type) return type->tp_flags; } +/* Determine the most derived metatype. */ +PyTypeObject * +_PyType_CalculateMetaclass(PyTypeObject *metatype, PyObject *bases) +{ + Py_ssize_t i, nbases; + PyTypeObject *winner; + PyObject *tmp; + PyTypeObject *tmptype; + + /* Determine the proper metatype to deal with this, + and check for metatype conflicts while we're at it. + Note that if some other metatype wins to contract, + it's possible that its instances are not types. */ + + nbases = PyTuple_GET_SIZE(bases); + winner = metatype; + for (i = 0; i < nbases; i++) { + tmp = PyTuple_GET_ITEM(bases, i); + tmptype = Py_TYPE(tmp); + if (PyType_IsSubtype(winner, tmptype)) + continue; + if (PyType_IsSubtype(tmptype, winner)) { + winner = tmptype; + continue; + } + /* else: */ + PyErr_SetString(PyExc_TypeError, + "metaclass conflict: " + "the metaclass of a derived class " + "must be a (non-strict) subclass " + "of the metaclasses of all its bases"); + return NULL; + } + return winner; +} + static PyObject * type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { @@ -1955,28 +1991,12 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) &PyDict_Type, &dict)) return NULL; - /* Determine the proper metatype to deal with this, - and check for metatype conflicts while we're at it. - Note that if some other metatype wins to contract, - it's possible that its instances are not types. */ - nbases = PyTuple_GET_SIZE(bases); - winner = metatype; - for (i = 0; i < nbases; i++) { - tmp = PyTuple_GET_ITEM(bases, i); - tmptype = Py_TYPE(tmp); - if (PyType_IsSubtype(winner, tmptype)) - continue; - if (PyType_IsSubtype(tmptype, winner)) { - winner = tmptype; - continue; - } - PyErr_SetString(PyExc_TypeError, - "metaclass conflict: " - "the metaclass of a derived class " - "must be a (non-strict) subclass " - "of the metaclasses of all its bases"); + /* Determine the proper metatype to deal with this: */ + winner = _PyType_CalculateMetaclass(metatype, bases); + if (winner == NULL) { return NULL; } + if (winner != metatype) { if (winner->tp_new != type_new) /* Pass it to the winner */ return winner->tp_new(winner, args, kwds); @@ -1984,6 +2004,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } /* Adjust for empty tuple bases */ + nbases = PyTuple_GET_SIZE(bases); if (nbases == 0) { bases = PyTuple_Pack(1, &PyBaseObject_Type); if (bases == NULL) |