]
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()
#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"
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;
}
}