summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_peepholer.py51
-rw-r--r--Python/flowgraph.c7
2 files changed, 58 insertions, 0 deletions
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index c7da151..b5b2b35 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -1193,5 +1193,56 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
]
self.cfg_optimization_test(insts, expected_insts, consts=list(range(5)))
+ def test_list_to_tuple_get_iter(self):
+ # for _ in (*foo, *bar) -> for _ in [*foo, *bar]
+ INTRINSIC_LIST_TO_TUPLE = 6
+ insts = [
+ ("BUILD_LIST", 0, 1),
+ ("LOAD_FAST", 0, 2),
+ ("LIST_EXTEND", 1, 3),
+ ("LOAD_FAST", 1, 4),
+ ("LIST_EXTEND", 1, 5),
+ ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6),
+ ("GET_ITER", None, 7),
+ top := self.Label(),
+ ("FOR_ITER", end := self.Label(), 8),
+ ("STORE_FAST", 2, 9),
+ ("JUMP", top, 10),
+ end,
+ ("END_FOR", None, 11),
+ ("POP_TOP", None, 12),
+ ("LOAD_CONST", 0, 13),
+ ("RETURN_VALUE", None, 14),
+ ]
+ expected_insts = [
+ ("BUILD_LIST", 0, 1),
+ ("LOAD_FAST", 0, 2),
+ ("LIST_EXTEND", 1, 3),
+ ("LOAD_FAST", 1, 4),
+ ("LIST_EXTEND", 1, 5),
+ ("NOP", None, 6), # ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6),
+ ("GET_ITER", None, 7),
+ top := self.Label(),
+ ("FOR_ITER", end := self.Label(), 8),
+ ("STORE_FAST", 2, 9),
+ ("JUMP", top, 10),
+ end,
+ ("END_FOR", None, 11),
+ ("POP_TOP", None, 12),
+ ("LOAD_CONST", 0, 13),
+ ("RETURN_VALUE", None, 14),
+ ]
+ self.cfg_optimization_test(insts, expected_insts, consts=[None])
+
+ def test_list_to_tuple_get_iter_is_safe(self):
+ a, b = [], []
+ for item in (*(items := [0, 1, 2, 3]),):
+ a.append(item)
+ b.append(items.pop())
+ self.assertEqual(a, [0, 1, 2, 3])
+ self.assertEqual(b, [3, 2, 1, 0])
+ self.assertEqual(items, [])
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index 017216a..24561c1 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -4,6 +4,7 @@
#include "Python.h"
#include "pycore_flowgraph.h"
#include "pycore_compile.h"
+#include "pycore_intrinsics.h"
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_opcode_utils.h"
@@ -1874,6 +1875,12 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
continue;
}
break;
+ case CALL_INTRINSIC_1:
+ // for _ in (*foo, *bar) -> for _ in [*foo, *bar]
+ if (oparg == INTRINSIC_LIST_TO_TUPLE && nextop == GET_ITER) {
+ INSTR_SET_OP0(inst, NOP);
+ }
+ break;
}
}