#!/usr/bin/env python3 """Check the C89 rollback index and reverse MRO restoration order.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nstatic int\ntype_set_bases\(PyTypeObject \*type, PyObject \*new_bases, void \*context\)\n\{(.*?)\n\}", source, re.S, ) assert match, "type_set_bases definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert not re.search(r"for\s*\(\s*Py_ssize_t\s+i\b", body), ( "type_set_bases: C99 rollback loop index declaration remains" ) assert re.match(r"\s*Py_ssize_t n;\s*Py_ssize_t i;", body), ( "type_set_bases: reuse i from the opening declarations" ) assert len(re.findall(r"\bPy_ssize_t\s+i\b", body)) == 1, ( "type_set_bases: declare i exactly once" ) rollback = body.split("undo:", 1)[1].split("bail:", 1)[0] expected = ''' n = PyList_GET_SIZE(temp); for (i = n - 1; i >= 0; i--) { PyTypeObject *cls; PyObject *new_mro, *old_mro = NULL; PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), "", 2, 3, &cls, &new_mro, &old_mro); if (cls->tp_mro == new_mro) { Py_XINCREF(old_mro); cls->tp_mro = old_mro; Py_DECREF(new_mro); } } Py_DECREF(temp); ''' assert rollback.split() == expected.split(), ( "type_set_bases: preserve rollback size evaluation, reverse iteration, " "newer-MRO guard, reference operations, and temp cleanup order" ) print("type_set_bases rollback index C89 and unchanged restoration order: PASS")