diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 1c202f82e941e8..b952c0c984b1f1 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -153,22 +153,6 @@ def test_optimization_levels__debug__(self): self.assertIsInstance(res.body[0].value, ast.Name) self.assertEqual(res.body[0].value.id, expected) - def test_optimization_levels_const_folding(self): - folded = ('Expr', (1, 0, 1, 6), ('Constant', (1, 0, 1, 6), (1, 2), None)) - not_folded = ('Expr', (1, 0, 1, 6), - ('Tuple', (1, 0, 1, 6), - [('Constant', (1, 1, 1, 2), 1, None), - ('Constant', (1, 4, 1, 5), 2, None)], ('Load',))) - - cases = [(-1, not_folded), (0, not_folded), (1, folded), (2, folded)] - for (optval, expected) in cases: - with self.subTest(optval=optval): - tree1 = ast.parse("(1, 2)", optimize=optval) - tree2 = ast.parse(ast.parse("(1, 2)"), optimize=optval) - for tree in [tree1, tree2]: - res = to_tuple(tree.body[0]) - self.assertEqual(res, expected) - def test_invalid_position_information(self): invalid_linenos = [ (10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1) @@ -3138,101 +3122,6 @@ def test_folding_format(self): self.assert_ast(code, non_optimized_target, optimized_target) - - def test_folding_tuple(self): - code = "(1,)" - - non_optimized_target = self.wrap_expr(ast.Tuple(elts=[ast.Constant(1)])) - optimized_target = self.wrap_expr(ast.Constant(value=(1,))) - - self.assert_ast(code, non_optimized_target, optimized_target) - - def test_folding_type_param_in_function_def(self): - code = "def foo[%s = (1, 2)](): pass" - - unoptimized_tuple = ast.Tuple(elts=[ast.Constant(1), ast.Constant(2)]) - unoptimized_type_params = [ - ("T", "T", ast.TypeVar), - ("**P", "P", ast.ParamSpec), - ("*Ts", "Ts", ast.TypeVarTuple), - ] - - for type, name, type_param in unoptimized_type_params: - result_code = code % type - optimized_target = self.wrap_statement( - ast.FunctionDef( - name='foo', - args=ast.arguments(), - body=[ast.Pass()], - type_params=[type_param(name=name, default_value=ast.Constant((1, 2)))] - ) - ) - non_optimized_target = self.wrap_statement( - ast.FunctionDef( - name='foo', - args=ast.arguments(), - body=[ast.Pass()], - type_params=[type_param(name=name, default_value=unoptimized_tuple)] - ) - ) - self.assert_ast(result_code, non_optimized_target, optimized_target) - - def test_folding_type_param_in_class_def(self): - code = "class foo[%s = (1, 2)]: pass" - - unoptimized_tuple = ast.Tuple(elts=[ast.Constant(1), ast.Constant(2)]) - unoptimized_type_params = [ - ("T", "T", ast.TypeVar), - ("**P", "P", ast.ParamSpec), - ("*Ts", "Ts", ast.TypeVarTuple), - ] - - for type, name, type_param in unoptimized_type_params: - result_code = code % type - optimized_target = self.wrap_statement( - ast.ClassDef( - name='foo', - body=[ast.Pass()], - type_params=[type_param(name=name, default_value=ast.Constant((1, 2)))] - ) - ) - non_optimized_target = self.wrap_statement( - ast.ClassDef( - name='foo', - body=[ast.Pass()], - type_params=[type_param(name=name, default_value=unoptimized_tuple)] - ) - ) - self.assert_ast(result_code, non_optimized_target, optimized_target) - - def test_folding_type_param_in_type_alias(self): - code = "type foo[%s = (1, 2)] = 1" - - unoptimized_tuple = ast.Tuple(elts=[ast.Constant(1), ast.Constant(2)]) - unoptimized_type_params = [ - ("T", "T", ast.TypeVar), - ("**P", "P", ast.ParamSpec), - ("*Ts", "Ts", ast.TypeVarTuple), - ] - - for type, name, type_param in unoptimized_type_params: - result_code = code % type - optimized_target = self.wrap_statement( - ast.TypeAlias( - name=ast.Name(id='foo', ctx=ast.Store()), - type_params=[type_param(name=name, default_value=ast.Constant((1, 2)))], - value=ast.Constant(value=1), - ) - ) - non_optimized_target = self.wrap_statement( - ast.TypeAlias( - name=ast.Name(id='foo', ctx=ast.Store()), - type_params=[type_param(name=name, default_value=unoptimized_tuple)], - value=ast.Constant(value=1), - ) - ) - self.assert_ast(result_code, non_optimized_target, optimized_target) - def test_folding_match_case_allowed_expressions(self): def get_match_case_values(node): result = [] diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d15964fe9dd88b..c6c0d844ab960d 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -555,7 +555,7 @@ def test_compile_async_generator(self): self.assertEqual(type(glob['ticker']()), AsyncGeneratorType) def test_compile_ast(self): - args = ("a*(1,2)", "f.py", "exec") + args = ("a*__debug__", "f.py", "exec") raw = compile(*args, flags = ast.PyCF_ONLY_AST).body[0] opt1 = compile(*args, flags = ast.PyCF_OPTIMIZED_AST).body[0] opt2 = compile(ast.parse(args[0]), *args[1:], flags = ast.PyCF_OPTIMIZED_AST).body[0] @@ -566,14 +566,13 @@ def test_compile_ast(self): self.assertIsInstance(tree.value.left, ast.Name) self.assertEqual(tree.value.left.id, 'a') - raw_right = raw.value.right # expect Tuple((1, 2)) - self.assertIsInstance(raw_right, ast.Tuple) - self.assertListEqual([elt.value for elt in raw_right.elts], [1, 2]) + raw_right = raw.value.right + self.assertIsInstance(raw_right, ast.Name) for opt in [opt1, opt2]: - opt_right = opt.value.right # expect Constant((1,2)) + opt_right = opt.value.right self.assertIsInstance(opt_right, ast.Constant) - self.assertEqual(opt_right.value, (1, 2)) + self.assertEqual(opt_right.value, __debug__) def test_delattr(self): sys.spam = 1 diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e0a33b8141c709..bed91337581fa9 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -797,9 +797,9 @@ def check_same_constant(const): f1, f2 = lambda: "not a name", lambda: ("not a name",) f3 = lambda x: x in {("not a name",)} self.assertIs(f1.__code__.co_consts[0], - f2.__code__.co_consts[0][0]) + f2.__code__.co_consts[1][0]) self.assertIs(next(iter(f3.__code__.co_consts[1])), - f2.__code__.co_consts[0]) + f2.__code__.co_consts[1]) # {0} is converted to a constant frozenset({0}) by the peephole # optimizer diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index e4224b843b2e00..c55a569b570783 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1665,8 +1665,10 @@ def to_bool_str(): @requires_specialization_ft def test_unpack_sequence(self): def unpack_sequence_two_tuple(): + + t = 1, 2 for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = 1, 2 + a, b = t self.assertEqual(a, 1) self.assertEqual(b, 2) @@ -1677,8 +1679,8 @@ def unpack_sequence_two_tuple(): def unpack_sequence_tuple(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, = 1, - self.assertEqual(a, 1) + a, b, c, d = 1, 2, 3, 4 + self.assertEqual((a, b, c, d), (1, 2, 3, 4)) unpack_sequence_tuple() self.assert_specialized(unpack_sequence_tuple, "UNPACK_SEQUENCE_TUPLE") diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 98f6b29dc7fc5e..7ee8aa4de51c5d 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -154,9 +154,12 @@ def test_folding_of_tuples_of_constants(self): for line, elem in ( ('a = 1,2,3', (1, 2, 3)), ('("a","b","c")', ('a', 'b', 'c')), - ('a,b,c = 1,2,3', (1, 2, 3)), + ('a,b,c,d = 1,2,3,4', (1, 2, 3, 4)), ('(None, 1, None)', (None, 1, None)), ('((1, 2), 3, 4)', ((1, 2), 3, 4)), + ('(1, 2, (3, 4))', (1, 2, (3, 4))), + ('()', ()), + ('(1, (2, (3, (4, (5,)))))', (1, (2, (3, (4, (5,)))))), ): with self.subTest(line=line): code = compile(line,'','single') @@ -164,8 +167,20 @@ def test_folding_of_tuples_of_constants(self): self.assertNotInBytecode(code, 'BUILD_TUPLE') self.check_lnotab(code) - # Long tuples should be folded too. - code = compile(repr(tuple(range(10000))),'','single') + for expr, length in ( + ('(1, a)', 2), + ('(a, b, c)', 3), + ('(a, (b, c))', 2), + ('(1, [], {})', 3), + ): + with self.subTest(expr=expr, length=length): + code = compile(expr, '', 'single') + self.assertInBytecode(code, 'BUILD_TUPLE', length) + self.check_lnotab(code) + + # Long tuples should be folded too, but their length should not + # exceed the `STACK_USE_GUIDELINE` + code = compile(repr(tuple(range(30))),'','single') self.assertNotInBytecode(code, 'BUILD_TUPLE') # One LOAD_CONST for the tuple, one for the None return value load_consts = [instr for instr in dis.get_instructions(code) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 0fe8d3d3f7d8c6..18537311174dcf 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -9,19 +9,19 @@ unsigned char M_test_frozenmain[] = { 31,0,89,1,78,8,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,33,0,51,0,0,0,0,0, 0,0,80,3,44,26,0,0,0,0,0,0,0,0,0,0, - 112,5,80,4,16,0,68,24,0,0,112,6,89,2,33,0, - 80,5,89,6,12,0,80,6,89,5,89,6,44,26,0,0, + 112,5,80,6,16,0,68,24,0,0,112,6,89,2,33,0, + 80,4,89,6,12,0,80,5,89,5,89,6,44,26,0,0, 0,0,0,0,0,0,0,0,12,0,49,4,51,1,0,0, 0,0,0,0,31,0,73,26,0,0,9,0,30,0,80,0, 35,0,41,7,78,122,18,70,114,111,122,101,110,32,72,101, 108,108,111,32,87,111,114,108,100,122,8,115,121,115,46,97, - 114,103,118,218,6,99,111,110,102,105,103,41,5,218,12,112, - 114,111,103,114,97,109,95,110,97,109,101,218,10,101,120,101, - 99,117,116,97,98,108,101,218,15,117,115,101,95,101,110,118, - 105,114,111,110,109,101,110,116,218,17,99,111,110,102,105,103, - 117,114,101,95,99,95,115,116,100,105,111,218,14,98,117,102, - 102,101,114,101,100,95,115,116,100,105,111,122,7,99,111,110, - 102,105,103,32,122,2,58,32,41,7,218,3,115,121,115,218, + 114,103,118,218,6,99,111,110,102,105,103,122,7,99,111,110, + 102,105,103,32,122,2,58,32,41,5,218,12,112,114,111,103, + 114,97,109,95,110,97,109,101,218,10,101,120,101,99,117,116, + 97,98,108,101,218,15,117,115,101,95,101,110,118,105,114,111, + 110,109,101,110,116,218,17,99,111,110,102,105,103,117,114,101, + 95,99,95,115,116,100,105,111,218,14,98,117,102,102,101,114, + 101,100,95,115,116,100,105,111,41,7,218,3,115,121,115,218, 17,95,116,101,115,116,105,110,116,101,114,110,97,108,99,97, 112,105,218,5,112,114,105,110,116,218,4,97,114,103,118,218, 11,103,101,116,95,99,111,110,102,105,103,115,114,2,0,0, diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 2c6e16817f2aad..78b0626a6f9379 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -278,40 +278,6 @@ fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) return 1; } -static PyObject* -make_const_tuple(asdl_expr_seq *elts) -{ - for (Py_ssize_t i = 0; i < asdl_seq_LEN(elts); i++) { - expr_ty e = (expr_ty)asdl_seq_GET(elts, i); - if (e->kind != Constant_kind) { - return NULL; - } - } - - PyObject *newval = PyTuple_New(asdl_seq_LEN(elts)); - if (newval == NULL) { - return NULL; - } - - for (Py_ssize_t i = 0; i < asdl_seq_LEN(elts); i++) { - expr_ty e = (expr_ty)asdl_seq_GET(elts, i); - PyObject *v = e->v.Constant.value; - PyTuple_SET_ITEM(newval, i, Py_NewRef(v)); - } - return newval; -} - -static int -fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) -{ - PyObject *newval; - - if (node->v.Tuple.ctx != Load) - return 1; - - newval = make_const_tuple(node->v.Tuple.elts); - return make_const(node, newval, arena); -} static int astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); @@ -505,7 +471,6 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) break; case Tuple_kind: CALL_SEQ(astfold_expr, expr, node_->v.Tuple.elts); - CALL(fold_tuple, expr_ty, node_); break; case Name_kind: if (node_->v.Name.ctx == Load && diff --git a/Python/codegen.c b/Python/codegen.c index cd77b34c06296b..cb26b5307660ab 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -1693,11 +1693,26 @@ codegen_typealias(compiler *c, stmt_ty s) return SUCCESS; } +static bool +is_const_tuple(asdl_expr_seq *elts) +{ + for (Py_ssize_t i = 0; i < asdl_seq_LEN(elts); i++) { + expr_ty e = (expr_ty)asdl_seq_GET(elts, i); + if (e->kind != Constant_kind) { + return false; + } + } + return true; +} + /* Return false if the expression is a constant value except named singletons. Return true otherwise. */ static bool check_is_arg(expr_ty e) { + if (e->kind == Tuple_kind) { + return !is_const_tuple(e->v.Tuple.elts); + } if (e->kind != Constant_kind) { return true; }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: