summaryrefslogtreecommitdiffstats
path: root/Objects/typeobject.c
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2011-10-23 12:04:16 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2011-10-23 12:04:16 (GMT)
commitde31b191e570d00ed7917c7f9ea28af3e770c16d (patch)
tree1139df0a3f75762d2acc5e6a5d964f62893fd68c /Objects/typeobject.c
parent711f87ca7d8b455feb450b2fb66a3d264fd603ce (diff)
downloadcpython-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.c61
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)