8000 gh-126835: Move const folding of lists & sets from ast_opt.c to flowg… · python/cpython@140e69c · GitHub
[go: up one dir, main page]

Skip to content

Commit 140e69c

Browse files
authored
gh-126835: Move const folding of lists & sets from ast_opt.c to flowgraph.c (#130032)
1 parent c7a9d06 commit 140e69c

File tree

5 files changed

+231
-120
lines changed

5 files changed

+231
-120
lines changed

Lib/test/test_ast/test_ast.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3239,46 +3239,6 @@ def test_folding_tuple(self):
32393239

32403240
self.assert_ast(code, non_optimized_target, optimized_target)
32413241

3242-
def test_folding_comparator(self):
3243-
code = "1 %s %s1%s"
3244-
operators = [("in", ast.In()), ("not in", ast.NotIn())]
3245-
braces = [
3246-
("[", "]", ast.List, (1,)),
3247-
("{", "}", ast.Set, frozenset({1})),
3248-
]
3249-
for left, right, non_optimized_comparator, optimized_comparator in braces:
3250-
for op, node in operators:
3251-
non_optimized_target = self.wrap_expr(ast.Compare(
3252-
left=ast.Constant(1), ops=[node],
3253-
comparators=[non_optimized_comparator(elts=[ast.Constant(1)])]
3254-
))
3255-
optimized_target = self.wrap_expr(ast.Compare(
3256-
left=ast.Constant(1), ops=[node],
3257-
comparators=[ast.Constant(value=optimized_comparator)]
3258-
))
3259-
self.assert_ast(code % (op, left, right), non_optimized_target, optimized_target)
3260-
3261-
def test_folding_iter(self):
3262-
code = "for _ in %s1%s: pass"
3263-
braces = [
3264-
("[", "]", ast.List, (1,)),
3265-
("{", "}", ast.Set, frozenset({1})),
3266-
]
3267-
3268-
for left, right, ast_cls, optimized_iter in braces:
3269-
non_optimized_target = self.wrap_statement(ast.For(
3270-
target=ast.Name(id="_", ctx=ast.Store()),
3271-
iter=ast_cls(elts=[ast.Constant(1)]),
3272-
body=[ast.Pass()]
3273-
))
3274-
optimized_target = self.wrap_statement(ast.For(
3275-
target=ast.Name(id="_", ctx=ast.Store()),
3276-
iter=ast.Constant(value=optimized_iter),
3277-
body=[ast.Pass()]
3278-
))
3279-
3280-
self.assert_ast(code % (left, right), non_optimized_target, optimized_target)
3281-
32823242
def test_folding_type_param_in_function_def(self):
32833243
code = "def foo[%s = 1 + 1](): pass"
32843244

Lib/test/test_compile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ def check_same_constant(const):
798798
f3 = lambda x: x in {("not a name",)}
799799
self.assertIs(f1.__code__.co_consts[0],
800800
f2.__code__.co_consts[0][0])
801-
self.assertIs(next(iter(f3.__code__.co_consts[0])),
801+
self.assertIs(next(iter(f3.__code__.co_consts[1])),
802802
f2.__code__.co_consts[0])
803803

804804
# {0} is converted to a constant frozenset({0}) by the peephole

Lib/test/test_peepholer.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,202 @@ def test_optimize_if_const_set(self):
12611261
]
12621262
self.cfg_optimization_test(same, same, consts=[])
12631263

1264+
def test_optimize_literal_list_for_iter(self):
1265+
# for _ in [1, 2]: pass ==> for _ in (1, 2): pass
1266+
before = [
1267+
('LOAD_SMALL_INT', 1, 0),
1268+
('LOAD_SMALL_INT', 2, 0),
1269+
('BUILD_LIST', 2, 0),
1270+
('GET_ITER', None, 0),
1271+
start := self.Label(),
1272+
('FOR_ITER', end := self.Label(), 0),
1273+
('STORE_FAST', 0, 0),
1274+
('JUMP', start, 0),
1275+
end,
1276+
('END_FOR', None, 0),
1277+
('POP_ITER', None, 0),
1278+
('LOAD_CONST', 0, 0),
1279+
('RETURN_VALUE', None, 0),
1280+
]
1281+
after = [
1282+
('LOAD_CONST', 1, 0),
1283+
('GET_ITER', None, 0),
1284+
start := self.Label(),
1285+
('FOR_ITER', end := self.Label(), 0),
1286+
('STORE_FAST', 0, 0),
1287+
('JUMP', start, 0),
1288+
end,
1289+
('END_FOR', None, 0),
1290+
('POP_ITER', None, 0),
1291+
('LOAD_CONST', 0, 0),
1292+
('RETURN_VALUE', None, 0),
1293+
]
1294+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)])
1295+
1296+
# for _ in [1, x]: pass ==> for _ in (1, x): pass
1297+
before = [
1298+
('LOAD_SMALL_INT', 1, 0),
1299+
('LOAD_NAME', 0, 0),
1300+
('BUILD_LIST', 2, 0),
1301+
('GET_ITER', None, 0),
1302+
start := self.Label(),
1303+
('FOR_ITER', end := self.Label(), 0),
1304+
('STORE_FAST', 0, 0),
1305+
('JUMP', start, 0),
1306+
end,
1307+
('END_FOR', None, 0),
1308+
('POP_ITER', None, 0),
1309+
('LOAD_CONST', 0, 0),
1310+
('RETURN_VALUE', None, 0),
1311+
]
1312+
after = [
1313+
('LOAD_SMALL_INT', 1, 0),
1314+
('LOAD_NAME', 0, 0),
1315+
('BUILD_TUPLE', 2, 0),
1316+
('GET_ITER', None, 0),
1317+
start := self.Label(),
1318+
('FOR_ITER', end := self.Label(), 0),
1319+
('STORE_FAST', 0, 0),
1320+
('JUMP', start, 0),
1321+
end,
1322+
('END_FOR', None, 0),
1323+
('POP_ITER', None, 0),
1324+
('LOAD_CONST', 0, 0),
1325+
('RETURN_VALUE', None, 0),
1326+
]
1327+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None])
1328+
1329+
def test_optimize_literal_set_for_iter(self):
1330+
# for _ in {1, 2}: pass ==> for _ in (1, 2): pass
1331+
before = [
1332+
('LOAD_SMALL_INT', 1, 0),
1333+
('LOAD_SMALL_INT', 2, 0),
1334+
('BUILD_SET', 2, 0),
1335+
('GET_ITER', None, 0),
1336+
start := self.Label(),
1337+
('FOR_ITER', end := self.Label(), 0),
1338+
('STORE_FAST', 0, 0),
1339+
('JUMP', start, 0),
1340+
end,
1341+
('END_FOR', None, 0),
1342+
('POP_ITER', None, 0),
1343+
('LOAD_CONST', 0, 0),
1344+
('RETURN_VALUE', None, 0),
1345+
]
1346+
after = [
1347+
('LOAD_CONST', 1, 0),
1348+
('GET_ITER', None, 0),
1349+
start := self.Label(),
1350+
('FOR_ITER', end := self.Label(), 0),
1351+
('STORE_FAST', 0, 0),
1352+
('JUMP', start, 0),
1353+
end,
1354+
('END_FOR', None, 0),
1355+
('POP_ITER', None, 0),
1356+
('LOAD_CONST', 0, 0),
1357+
('RETURN_VALUE', None, 0),
1358+
]
1359+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})])
1360+
1361+
# non constant literal set is not changed
1362+
# for _ in {1, x}: pass ==> for _ in {1, x}: pass
1363+
same = [
1364+
('LOAD_SMALL_INT', 1, 0),
1365+
('LOAD_NAME', 0, 0),
1366+
('BUILD_SET', 2, 0),
1367+
('GET_ITER', None, 0),
1368+
start := self.Label(),
1369+
('FOR_ITER', end := self.Label(), 0),
1370+
('STORE_FAST', 0, 0),
1371+
('JUMP', start, 0),
1372+
end,
1373+
('END_FOR', None, 0),
1374+
('POP_ITER', None, 0),
1375+
('LOAD_CONST', 0, 0),
1376+
('RETURN_VALUE', None, 0),
1377+
]
1378+
self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None])
1379+
1380+
def test_optimize_literal_list_contains(self):
1381+
# x in [1, 2] ==> x in (1, 2)
1382+
before = [
1383+
('LOAD_NAME', 0, 0),
1384+
('LOAD_SMALL_INT', 1, 0),
1385+
('LOAD_SMALL_INT', 2, 0),
1386+
('BUILD_LIST', 2, 0),
1387+
('CONTAINS_OP', 0, 0),
1388+
('POP_TOP', None, 0),
1389+
('LOAD_CONST', 0, 0),
1390+
('RETURN_VALUE', None, 0),
1391+
]
1392+
after = [
1393+
('LOAD_NAME', 0, 0),
1394+
('LOAD_CONST', 1, 0),
1395+
('CONTAINS_OP', 0, 0),
1396+
('POP_TOP', None, 0),
1397+
('LOAD_CONST', 0, 0),
1398+
('RETURN_VALUE', None, 0),
1399+
]
1400+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)])
1401+
1402+
# x in [1, y] ==> x in (1, y)
1403+
before = [
1404+
('LOAD_NAME', 0, 0),
1405+
('LOAD_SMALL_INT', 1, 0),
1406+
('LOAD_NAME', 1, 0),
1407+
('BUILD_LIST', 2, 0),
1408+
('CONTAINS_OP', 0, 0),
1409+
('POP_TOP', None, 0),
1410+
('LOAD_CONST', 0, 0),
1411+
('RETURN_VALUE', None, 0),
1412+
]
1413+
after = [
1414+
('LOAD_NAME', 0, 0),
1415+
('LOAD_SMALL_INT', 1, 0),
1416+
('LOAD_NAME', 1, 0),
1417+
('BUILD_TUPLE', 2, 0),
1418+
('CONTAINS_OP', 0, 0),
1419+
('POP_TOP', None, 0),
1420+
('LOAD_CONST', 0, 0),
1421+
('RETURN_VALUE', None, 0),
1422+
]
1423+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None])
1424+
1425+
def test_optimize_literal_set_contains(self):
1426+
# x in {1, 2} ==> x in (1, 2)
1427+
before = [
1428+
('LOAD_NAME', 0, 0),
1429+
('LOAD_SMALL_INT', 1, 0),
1430+
('LOAD_SMALL_INT', 2, 0),
1431+
('BUILD_SET', 2, 0),
1432+
('CONTAINS_OP', 0, 0),
1433+
('POP_TOP', None, 0),
1434+
('LOAD_CONST', 0, 0),
1435+
('RETURN_VALUE', None, 0),
1436+
]
1437+
after = [
1438+
('LOAD_NAME', 0, 0),
1439+
('LOAD_CONST', 1, 0),
1440+
('CONTAINS_OP', 0, 0),
1441+
('POP_TOP', None, 0),
1442+
('LOAD_CONST', 0, 0),
1443+
('RETURN_VALUE', None, 0),
1444+
]
1445+
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})])
1446+
1447+
# non constant literal set is not changed
1448+
# x in {1, y} ==> x in {1, y}
1449+
same = [
1450+
('LOAD_NAME', 0, 0),
1451+
('LOAD_SMALL_INT', 1, 0),
1452+
('LOAD_NAME', 1, 0),
1453+
('BUILD_SET', 2, 0),
1454+
('CONTAINS_OP', 0, 0),
1455+
('POP_TOP', None, 0),
1456+
('LOAD_CONST', 0, 0),
1457+
('RETURN_VALUE', None, 0),
1458+
]
1459+
self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None])
12641460

12651461
def test_conditional_jump_forward_const_condition(self):
12661462
# The unreachable branch of the jump is removed, the jump

Python/ast_opt.c

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -567,62 +567,6 @@ fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
567567
return make_const(node, newval, arena);
568568
}
569569

570-
/* Change literal list or set of constants into constant
571-
tuple or frozenset respectively. Change literal list of
572-
non-constants into tuple.
573-
Used for right operand of "in" and "not in" tests and for iterable
574-
in "for" loop and comprehensions.
575-
*/
576-
static int
577-
fold_iter(expr_ty arg, PyArena *arena, _PyASTOptimizeState *state)
578-
{
579-
PyObject *newval;
580-
if (arg->kind == List_kind) {
581-
/* First change a list into tuple. */
582-
asdl_expr_seq *elts = arg->v.List.elts;
583-
if (has_starred(elts)) {
584-
return 1;
585-
}
586-
expr_context_ty ctx = arg->v.List.ctx;
587-
arg->kind = Tuple_kind;
588-
arg->v.Tuple.elts = elts;
589-
arg->v.Tuple.ctx = ctx;
590-
/* Try to create a constant tuple. */
591-
newval = make_const_tuple(elts);
592-
}
593-
else if (arg->kind == Set_kind) {
594-
newval = make_const_tuple(arg->v.Set.elts);
595-
if (newval) {
596-
Py_SETREF(newval, PyFrozenSet_New(newval));
597-
}
598-
}
599-
else {
600-
return 1;
601-
}
602-
return make_const(arg, newval, arena);
603-
}
604-
605-
static int
606-
fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
607-
{
608-
asdl_int_seq *ops;
609-
asdl_expr_seq *args;
610-
Py_ssize_t i;
611-
612-
ops = node->v.Compare.ops;
613-
args = node->v.Compare.comparators;
614-
/* Change literal list or set in 'in' or 'not in' into
615-
tuple or frozenset respectively. */
616-
i = asdl_seq_LEN(ops) - 1;
617-
int op = asdl_seq_GET(ops, i);
618-
if (op == In || op == NotIn) {
619-
if (!fold_iter((expr_ty)asdl_seq_GET(args, i), arena, state)) {
620-
return 0;
621-
}
622-
}
623-
return 1;
624-
}
625-
626570
static int astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
627571
static int astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
628572
static int astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
@@ -783,7 +727,6 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
783727
case Compare_kind:
784728
CALL(astfold_expr, expr_ty, node_->v.Compare.left);
785729
CALL_SEQ(astfold_expr, expr, node_->v.Compare.comparators);
786-
CALL(fold_compare, expr_ty, node_);
787730
break;
788731
case Call_kind:
789732
CALL(astfold_expr, expr_ty, node_->v.Call.func);
@@ -852,8 +795,6 @@ astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOptimizeState
852795
CALL(astfold_expr, expr_ty, node_->target);
853796
CALL(astfold_expr, expr_ty, node_->iter);
854797
CALL_SEQ(astfold_expr, expr, node_->ifs);
< 538E div aria-hidden="true" class="position-absolute top-0 d-flex user-select-none DiffLineTableCellParts-module__comment-indicator--eI0hb">
855-
856-
CALL(fold_iter, expr_ty, node_->iter);
857798
return 1;
858799
}
859800

@@ -940,8 +881,6 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
940881
CALL(astfold_expr, expr_ty, node_->v.For.iter);
941882
CALL_SEQ(astfold_stmt, stmt, node_->v.For.body);
942883
CALL_SEQ(astfold_stmt, stmt, node_->v.For.orelse);
943-
944-
CALL(fold_iter, expr_ty, node_->v.For.iter);
945884
break;
946885
case AsyncFor_kind:
947886
CALL(astfold_expr, expr_ty, node_->v.AsyncFor.target);

0 commit comments

Comments
 (0)
0