@@ -1212,182 +1212,6 @@ def visitModule(self, mod):
12121212 return result;
12131213}
12141214
1215- /*
1216- * Perform the following validations:
1217- *
1218- * - All keyword arguments are known 'fields' or 'attributes'.
1219- * - No field or attribute would be left unfilled after copy.replace().
1220- *
1221- * On success, this returns 1. Otherwise, set a TypeError
1222- * exception and returns -1 (no exception is set if some
1223- * other internal errors occur).
1224- *
1225- * Parameters
1226- *
1227- * self The AST node instance.
1228- * dict The AST node instance dictionary (self.__dict__).
1229- * fields The list of fields (self._fields).
1230- * attributes The list of attributes (self._attributes).
1231- * kwargs Keyword arguments passed to ast_type_replace().
1232- *
1233- * The 'dict', 'fields', 'attributes' and 'kwargs' arguments can be NULL.
1234- *
1235- * Note: this function can be removed in 3.15 since the verification
1236- * will be done inside the constructor.
1237- */
1238- static inline int
1239- ast_type_replace_check(PyObject *self,
1240- PyObject *dict,
1241- PyObject *fields,
1242- PyObject *attributes,
1243- PyObject *kwargs)
1244- {
1245- // While it is possible to make some fast paths that would avoid
1246- // allocating objects on the stack, this would cost us readability.
1247- // For instance, if 'fields' and 'attributes' are both empty, and
1248- // 'kwargs' is not empty, we could raise a TypeError immediately.
1249- PyObject *expecting = PySet_New(fields);
1250- if (expecting == NULL) {
1251- return -1;
1252- }
1253- if (attributes) {
1254- if (_PySet_Update(expecting, attributes) < 0) {
1255- Py_DECREF(expecting);
1256- return -1;
1257- }
1258- }
1259- // Any keyword argument that is neither a field nor attribute is rejected.
1260- // We first need to check whether a keyword argument is accepted or not.
1261- // If all keyword arguments are accepted, we compute the required fields
1262- // and attributes. A field or attribute is not needed if:
1263- //
1264- // 1) it is given in 'kwargs', or
1265- // 2) it already exists on 'self'.
1266- if (kwargs) {
1267- Py_ssize_t pos = 0;
1268- PyObject *key, *value;
1269- while (PyDict_Next(kwargs, &pos, &key, &value)) {
1270- int rc = PySet_Discard(expecting, key);
1271- if (rc < 0) {
1272- Py_DECREF(expecting);
1273- return -1;
1274- }
1275- if (rc == 0) {
1276- PyErr_Format(PyExc_TypeError,
1277- "%.400s.__replace__ got an unexpected keyword "
1278- "argument '%U'.", Py_TYPE(self)->tp_name, key);
1279- Py_DECREF(expecting);
1280- return -1;
1281- }
1282- }
1283- }
1284- // check that the remaining fields or attributes would be filled
1285- if (dict) {
1286- Py_ssize_t pos = 0;
1287- PyObject *key, *value;
1288- while (PyDict_Next(dict, &pos, &key, &value)) {
1289- // Mark fields or attributes that are found on the instance
1290- // as non-mandatory. If they are not given in 'kwargs', they
1291- // will be shallow-coied; otherwise, they would be replaced
1292- // (not in this function).
1293- if (PySet_Discard(expecting, key) < 0) {
1294- Py_DECREF(expecting);
1295- return -1;
1296- }
1297- }
1298- if (attributes) {
1299- // Some attributes may or may not be present at runtime.
1300- // In particular, now that we checked whether 'kwargs'
1301- // is correct or not, we allow any attribute to be missing.
1302- //
1303- // Note that fields must still be entirely determined when
1304- // calling the constructor later.
1305- PyObject *unused = PyObject_CallMethodOneArg(expecting,
1306- &_Py_ID(difference_update),
1307- attributes);
1308- if (unused == NULL) {
1309- Py_DECREF(expecting);
1310- return -1;
1311- }
1312- Py_DECREF(unused);
1313- }
1314- }
1315-
1316- // Discard fields from 'expecting' that default to None
1317- PyObject *field_types = NULL;
1318- if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self),
1319- &_Py_ID(_field_types),
1320- &field_types) < 0)
1321- {
1322- Py_DECREF(expecting);
1323- return -1;
1324- }
1325- if (field_types != NULL) {
1326- Py_ssize_t pos = 0;
1327- PyObject *field_name, *field_type;
1328- while (PyDict_Next(field_types, &pos, &field_name, &field_type)) {
1329- if (_PyUnion_Check(field_type)) {
1330- // optional field
1331- if (PySet_Discard(expecting, field_name) < 0) {
1332- Py_DECREF(expecting);
1333- Py_DECREF(field_types);
1334- return -1;
1335- }
1336- }
1337- }
1338- Py_DECREF(field_types);
1339- }
1340-
1341- // Now 'expecting' contains the fields or attributes
1342- // that would not be filled inside ast_type_replace().
1343- Py_ssize_t m = PySet_GET_SIZE(expecting);
1344- if (m > 0) {
1345- PyObject *names = PyList_New(m);
1346- if (names == NULL) {
1347- Py_DECREF(expecting);
1348- return -1;
1349- }
1350- Py_ssize_t i = 0, pos = 0;
1351- PyObject *item;
1352- Py_hash_t hash;
1353- while (_PySet_NextEntry(expecting, &pos, &item, &hash)) {
1354- PyObject *name = PyObject_Repr(item);
1355- if (name == NULL) {
1356- Py_DECREF(expecting);
1357- Py_DECREF(names);
1358- return -1;
1359- }
1360- // steal the reference 'name'
1361- PyList_SET_ITEM(names, i++, name);
1362- }
1363- Py_DECREF(expecting);
1364- if (PyList_Sort(names) < 0) {
1365- Py_DECREF(names);
1366- return -1;
1367- }
1368- PyObject *sep = PyUnicode_FromString(", ");
1369- if (sep == NULL) {
1370- Py_DECREF(names);
1371- return -1;
1372- }
1373- PyObject *str_names = PyUnicode_Join(sep, names);
1374- Py_DECREF(sep);
1375- Py_DECREF(names);
1376- if (str_names == NULL) {
1377- return -1;
1378- }
1379- PyErr_Format(PyExc_TypeError,
1380- "%.400s.__replace__ missing %ld keyword argument%s: %U.",
1381- Py_TYPE(self)->tp_name, m, m == 1 ? "" : "s", str_names);
1382- Py_DECREF(str_names);
1383- return -1;
1384- }
1385- else {
1386- Py_DECREF(expecting);
1387- return 1;
1388- }
1389- }
1390-
13911215/*
13921216 * Python equivalent:
13931217 *
@@ -1477,9 +1301,6 @@ def visitModule(self, mod):
14771301 if (PyObject_GetOptionalAttr(self, state->__dict__, &dict) < 0) {
14781302 goto cleanup;
14791303 }
1480- if (ast_type_replace_check(self, dict, fields, attributes, kwargs) < 0) {
1481- goto cleanup;
1482- }
14831304 empty_tuple = PyTuple_New(0);
14841305 if (empty_tuple == NULL) {
14851306 goto cleanup;
0 commit comments