Skip to content

Commit 6a0657e

Browse files
authored
[mypyc] Don't rely on _PyType_CalculateMetaclass on 3.13 (#17525)
Copy the implementation from CPython (with minor changes), as it's no longer exported. Work on mypyc/mypyc#1056.
1 parent 42337a0 commit 6a0657e

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

mypyc/lib-rt/CPy.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -846,10 +846,7 @@ static inline bool CPy_TypeCheck(PyObject *o, PyObject *type) {
846846
return PyObject_TypeCheck(o, (PyTypeObject *)type);
847847
}
848848

849-
static inline PyObject *CPy_CalculateMetaclass(PyObject *type, PyObject *o) {
850-
return (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)type, o);
851-
}
852-
849+
PyObject *CPy_CalculateMetaclass(PyObject *type, PyObject *o);
853850
PyObject *CPy_GetCoro(PyObject *obj);
854851
PyObject *CPyIter_Send(PyObject *iter, PyObject *val);
855852
int CPy_YieldFromErrorHandle(PyObject *iter, PyObject **outp);

mypyc/lib-rt/misc_ops.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,52 @@ static bool _CPy_IsSafeMetaClass(PyTypeObject *metaclass) {
131131
return matches;
132132
}
133133

134+
#if CPY_3_13_FEATURES
135+
136+
// Adapted from CPython 3.13.0b3
137+
/* Determine the most derived metatype. */
138+
PyObject *CPy_CalculateMetaclass(PyObject *metatype, PyObject *bases)
139+
{
140+
Py_ssize_t i, nbases;
141+
PyTypeObject *winner;
142+
PyObject *tmp;
143+
PyTypeObject *tmptype;
144+
145+
/* Determine the proper metatype to deal with this,
146+
and check for metatype conflicts while we're at it.
147+
Note that if some other metatype wins to contract,
148+
it's possible that its instances are not types. */
149+
150+
nbases = PyTuple_GET_SIZE(bases);
151+
winner = (PyTypeObject *)metatype;
152+
for (i = 0; i < nbases; i++) {
153+
tmp = PyTuple_GET_ITEM(bases, i);
154+
tmptype = Py_TYPE(tmp);
155+
if (PyType_IsSubtype(winner, tmptype))
156+
continue;
157+
if (PyType_IsSubtype(tmptype, winner)) {
158+
winner = tmptype;
159+
continue;
160+
}
161+
/* else: */
162+
PyErr_SetString(PyExc_TypeError,
163+
"metaclass conflict: "
164+
"the metaclass of a derived class "
165+
"must be a (non-strict) subclass "
166+
"of the metaclasses of all its bases");
167+
return NULL;
168+
}
169+
return (PyObject *)winner;
170+
}
171+
172+
#else
173+
174+
PyObject *CPy_CalculateMetaclass(PyObject *metatype, PyObject *bases) {
175+
return (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)metatype, bases);
176+
}
177+
178+
#endif
179+
134180
// Create a heap type based on a template non-heap type.
135181
// This is super hacky and maybe we should suck it up and use PyType_FromSpec instead.
136182
// We allow bases to be NULL to represent just inheriting from object.
@@ -163,7 +209,7 @@ PyObject *CPyType_FromTemplate(PyObject *template,
163209
// Find the appropriate metaclass from our base classes. We
164210
// care about this because Generic uses a metaclass prior to
165211
// Python 3.7.
166-
metaclass = _PyType_CalculateMetaclass(metaclass, bases);
212+
metaclass = (PyTypeObject *)CPy_CalculateMetaclass((PyObject *)metaclass, bases);
167213
if (!metaclass)
168214
goto error;
169215

0 commit comments

Comments
 (0)