mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
Issue 1294232: Fix errors in metaclass calculation affecting some cases of metaclass inheritance. Patch by Daniel Urban.
This commit is contained in:
parent
711f87ca7d
commit
de31b191e5
5 changed files with 242 additions and 22 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue