92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Check winner's C89 declaration and preserve get-bases evaluation order."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nstatic int\ntype_new_get_bases\(type_new_ctx \*ctx, PyObject \*\*type\)\n\{(.*?)\n\}",
|
|
source, re.S,
|
|
)
|
|
assert match, "type_new_get_bases definition missing"
|
|
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
|
|
assert re.match(
|
|
r"\s*Py_ssize_t nbases = PyTuple_GET_SIZE\(ctx->bases\);"
|
|
r"\s*Py_ssize_t i;\s*PyTypeObject \*winner;\s*PyTypeObject \*base;"
|
|
r"\s*if \(nbases == 0\)",
|
|
body,
|
|
), "type_new_get_bases: winner must be declared before statements (C89)"
|
|
assert len(re.findall(r"\bPyTypeObject\s*\*\s*winner\b", body)) == 1, (
|
|
"declare winner exactly once"
|
|
)
|
|
expected = """
|
|
Py_ssize_t nbases = PyTuple_GET_SIZE(ctx->bases);
|
|
Py_ssize_t i;
|
|
PyTypeObject *base;
|
|
if (nbases == 0) {
|
|
PyObject *new_bases;
|
|
|
|
ctx->base = &PyBaseObject_Type;
|
|
new_bases = PyTuple_Pack(1, ctx->base);
|
|
if (new_bases == NULL) {
|
|
return -1;
|
|
}
|
|
ctx->bases = new_bases;
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < nbases; i++) {
|
|
PyObject *base = PyTuple_GET_ITEM(ctx->bases, i);
|
|
PyObject *mro_entries;
|
|
if (PyType_Check(base)) {
|
|
continue;
|
|
}
|
|
if (_PyObject_LookupAttr(base, &_Py_ID(__mro_entries__),
|
|
&mro_entries) < 0) {
|
|
return -1;
|
|
}
|
|
if (mro_entries != NULL) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"type() doesn't support MRO entry resolution; "
|
|
"use types.new_class()");
|
|
Py_DECREF(mro_entries);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
winner = _PyType_CalculateMetaclass(ctx->metatype, ctx->bases);
|
|
if (winner == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (winner != ctx->metatype) {
|
|
if (winner->tp_new != type_new) {
|
|
|
|
*type = winner->tp_new(winner, ctx->args, ctx->kwds);
|
|
if (*type == NULL) {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ctx->metatype = winner;
|
|
}
|
|
|
|
|
|
base = best_base(ctx->bases);
|
|
if (base == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
ctx->base = base;
|
|
ctx->bases = Py_NewRef(ctx->bases);
|
|
return 0;
|
|
"""
|
|
without_winner_declaration = re.sub(r"\bPyTypeObject\s*\*\s*winner;", "", body)
|
|
assert without_winner_declaration.split() == expected.split(), (
|
|
"preserve base validation, metaclass calculation, winner dispatch, best-base "
|
|
"calculation, reference updates, and returns at their original evaluation points"
|
|
)
|
|
print("type_new_get_bases winner C89 declaration and evaluation ordering: PASS")
|