Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d112c60

Browse filesBrowse files
authored
bpo-39220: Do not optimise annotation if 'from __future__ import annotations' is used (GH-17866)
Do not apply AST-based optimizations if 'from __future__ import annotations' is used in order to prevent information lost in the final version of the annotations.
1 parent 8849e59 commit d112c60
Copy full SHA for d112c60

5 files changed

+67-40Lines changed: 67 additions & 40 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎Include/compile.h‎

Copy file name to clipboardExpand all lines: Include/compile.h
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name);
8383
PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg);
8484
PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump);
8585

86-
PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, int optimize);
86+
typedef struct {
87+
int optimize;
88+
int ff_features;
89+
} _PyASTOptimizeState;
90+
91+
PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, _PyASTOptimizeState *state);
8792

8893
#ifdef __cplusplus
8994
}
Collapse file

‎Lib/test/test_future.py‎

Copy file name to clipboardExpand all lines: Lib/test/test_future.py
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ def f() -> {ann}:
111111
...
112112
def g(arg: {ann}) -> None:
113113
...
114+
async def f2() -> {ann}:
115+
...
116+
async def g2(arg: {ann}) -> None:
117+
...
114118
var: {ann}
115119
var2: {ann} = None
116120
"""
@@ -121,9 +125,13 @@ def getActual(self, annotation):
121125
exec(self.template.format(ann=annotation), {}, scope)
122126
func_ret_ann = scope['f'].__annotations__['return']
123127
func_arg_ann = scope['g'].__annotations__['arg']
128+
async_func_ret_ann = scope['f2'].__annotations__['return']
129+
async_func_arg_ann = scope['g2'].__annotations__['arg']
124130
var_ann1 = scope['__annotations__']['var']
125131
var_ann2 = scope['__annotations__']['var2']
126132
self.assertEqual(func_ret_ann, func_arg_ann)
133+
self.assertEqual(func_ret_ann, async_func_ret_ann)
134+
self.assertEqual(func_ret_ann, async_func_arg_ann)
127135
self.assertEqual(func_ret_ann, var_ann1)
128136
self.assertEqual(func_ret_ann, var_ann2)
129137
return func_ret_ann
@@ -288,6 +296,7 @@ def test_annotations(self):
288296
eq('(((a, b)))', '(a, b)')
289297
eq("(x:=10)")
290298
eq("f'{(x:=10):=10}'")
299+
eq("1 + 2 + 3")
291300

292301
def test_fstring_debug_annotations(self):
293302
# f-strings with '=' don't round trip very well, so set the expected
@@ -299,6 +308,5 @@ def test_fstring_debug_annotations(self):
299308
self.assertAnnotationEqual("f'{x=!a}'", expected="f'x={x!a}'")
300309
self.assertAnnotationEqual("f'{x=!s:*^20}'", expected="f'x={x!s:*^20}'")
301310

302-
303311
if __name__ == "__main__":
304312
unittest.main()
Collapse file
+2Lines changed: 2 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Do not optimize annotations if 'from __future__ import annotations' is used.
2+
Patch by Pablo Galindo.
Collapse file

‎Python/ast_opt.c‎

Copy file name to clipboardExpand all lines: Python/ast_opt.c
+45-37Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ unary_not(PyObject *v)
3535
}
3636

3737
static int
38-
fold_unaryop(expr_ty node, PyArena *arena, int optimize)
38+
fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
3939
{
4040
expr_ty arg = node->v.UnaryOp.operand;
4141

@@ -212,7 +212,7 @@ safe_mod(PyObject *v, PyObject *w)
212212
}
213213

214214
static int
215-
fold_binop(expr_ty node, PyArena *arena, int optimize)
215+
fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
216216
{
217217
expr_ty lhs, rhs;
218218
lhs = node->v.BinOp.left;
@@ -294,7 +294,7 @@ make_const_tuple(asdl_seq *elts)
294294
}
295295

296296
static int
297-
fold_tuple(expr_ty node, PyArena *arena, int optimize)
297+
fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
298298
{
299299
PyObject *newval;
300300

@@ -306,7 +306,7 @@ fold_tuple(expr_ty node, PyArena *arena, int optimize)
306306
}
307307

308308
static int
309-
fold_subscr(expr_ty node, PyArena *arena, int optimize)
309+
fold_subscr(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
310310
{
311311
PyObject *newval;
312312
expr_ty arg, idx;
@@ -331,7 +331,7 @@ fold_subscr(expr_ty node, PyArena *arena, int optimize)
331331
in "for" loop and comprehensions.
332332
*/
333333
static int
334-
fold_iter(expr_ty arg, PyArena *arena, int optimize)
334+
fold_iter(expr_ty arg, PyArena *arena, _PyASTOptimizeState *state)
335335
{
336336
PyObject *newval;
337337
if (arg->kind == List_kind) {
@@ -364,7 +364,7 @@ fold_iter(expr_ty arg, PyArena *arena, int optimize)
364364
}
365365

366366
static int
367-
fold_compare(expr_ty node, PyArena *arena, int optimize)
367+
fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
368368
{
369369
asdl_int_seq *ops;
370370
asdl_seq *args;
@@ -378,36 +378,36 @@ fold_compare(expr_ty node, PyArena *arena, int optimize)
378378
i = asdl_seq_LEN(ops) - 1;
379379
int op = asdl_seq_GET(ops, i);
380380
if (op == In || op == NotIn) {
381-
if (!fold_iter((expr_ty)asdl_seq_GET(args, i), arena, optimize)) {
381+
if (!fold_iter((expr_ty)asdl_seq_GET(args, i), arena, state)) {
382382
return 0;
383383
}
384384
}
385385
return 1;
386386
}
387387

388-
static int astfold_mod(mod_ty node_, PyArena *ctx_, int optimize_);
389-
static int astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_);
390-
static int astfold_expr(expr_ty node_, PyArena *ctx_, int optimize_);
391-
static int astfold_arguments(arguments_ty node_, PyArena *ctx_, int optimize_);
392-
static int astfold_comprehension(comprehension_ty node_, PyArena *ctx_, int optimize_);
393-
static int astfold_keyword(keyword_ty node_, PyArena *ctx_, int optimize_);
394-
static int astfold_arg(arg_ty node_, PyArena *ctx_, int optimize_);
395-
static int astfold_withitem(withitem_ty node_, PyArena *ctx_, int optimize_);
396-
static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int optimize_);
388+
static int astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
389+
static int astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
390+
static int astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
391+
static int astfold_arguments(arguments_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
392+
static int astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
393+
static int astfold_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
394+
static int astfold_arg(arg_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
395+
static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
396+
static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
397397
#define CALL(FUNC, TYPE, ARG) \
398-
if (!FUNC((ARG), ctx_, optimize_)) \
398+
if (!FUNC((ARG), ctx_, state)) \
399399
return 0;
400400

401401
#define CALL_OPT(FUNC, TYPE, ARG) \
402-
if ((ARG) != NULL && !FUNC((ARG), ctx_, optimize_)) \
402+
if ((ARG) != NULL && !FUNC((ARG), ctx_, state)) \
403403
return 0;
404404

405405
#define CALL_SEQ(FUNC, TYPE, ARG) { \
406406
int i; \
407407
asdl_seq *seq = (ARG); /* avoid variable capture */ \
408408
for (i = 0; i < asdl_seq_LEN(seq); i++) { \
409409
TYPE elt = (TYPE)asdl_seq_GET(seq, i); \
410-
if (elt != NULL && !FUNC(elt, ctx_, optimize_)) \
410+
if (elt != NULL && !FUNC(elt, ctx_, state)) \
411411
return 0; \
412412
} \
413413
}
@@ -417,13 +417,13 @@ static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int opti
417417
asdl_int_seq *seq = (ARG); /* avoid variable capture */ \
418418
for (i = 0; i < asdl_seq_LEN(seq); i++) { \
419419
TYPE elt = (TYPE)asdl_seq_GET(seq, i); \
420-
if (!FUNC(elt, ctx_, optimize_)) \
420+
if (!FUNC(elt, ctx_, state)) \
421421
return 0; \
422422
} \
423423
}
424424

425425
static int
426-
astfold_body(asdl_seq *stmts, PyArena *ctx_, int optimize_)
426+
astfold_body(asdl_seq *stmts, PyArena *ctx_, _PyASTOptimizeState *state)
427427
{
428428
int docstring = _PyAST_GetDocString(stmts) != NULL;
429429
CALL_SEQ(astfold_stmt, stmt_ty, stmts);
@@ -445,7 +445,7 @@ astfold_body(asdl_seq *stmts, PyArena *ctx_, int optimize_)
445445
}
446446

447447
static int
448-
astfold_mod(mod_ty node_, PyArena *ctx_, int optimize_)
448+
astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
449449
{
450450
switch (node_->kind) {
451451
case Module_kind:
@@ -464,7 +464,7 @@ astfold_mod(mod_ty node_, PyArena *ctx_, int optimize_)
464464
}
465465

466466
static int
467-
astfold_expr(expr_ty node_, PyArena *ctx_, int optimize_)
467+
astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
468468
{
469469
switch (node_->kind) {
470470
case BoolOp_kind:
@@ -563,7 +563,7 @@ astfold_expr(expr_ty node_, PyArena *ctx_, int optimize_)
563563
break;
564564
case Name_kind:
565565
if (_PyUnicode_EqualToASCIIString(node_->v.Name.id, "__debug__")) {
566-
return make_const(node_, PyBool_FromLong(!optimize_), ctx_);
566+
return make_const(node_, PyBool_FromLong(!state->optimize), ctx_);
567567
}
568568
break;
569569
default:
@@ -573,14 +573,14 @@ astfold_expr(expr_ty node_, PyArena *ctx_, int optimize_)
573573
}
574574

575575
static int
576-
astfold_keyword(keyword_ty node_, PyArena *ctx_, int optimize_)
576+
astfold_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
577577
{
578578
CALL(astfold_expr, expr_ty, node_->value);
579579
return 1;
580580
}
581581

582582
static int
583-
astfold_comprehension(comprehension_ty node_, PyArena *ctx_, int optimize_)
583+
astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
584584
{
585585
CALL(astfold_expr, expr_ty, node_->target);
586586
CALL(astfold_expr, expr_ty, node_->iter);
@@ -591,7 +591,7 @@ astfold_comprehension(comprehension_ty node_, PyArena *ctx_, int optimize_)
591591
}
592592

593593
static int
594-
astfold_arguments(arguments_ty node_, PyArena *ctx_, int optimize_)
594+
astfold_arguments(arguments_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
595595
{
596596
CALL_SEQ(astfold_arg, arg_ty, node_->posonlyargs);
597597
CALL_SEQ(astfold_arg, arg_ty, node_->args);
@@ -604,27 +604,33 @@ astfold_arguments(arguments_ty node_, PyArena *ctx_, int optimize_)
604604
}
605605

606606
static int
607-
astfold_arg(arg_ty node_, PyArena *ctx_, int optimize_)
607+
astfold_arg(arg_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
608608
{
609-
CALL_OPT(astfold_expr, expr_ty, node_->annotation);
609+
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
610+
CALL_OPT(astfold_expr, expr_ty, node_->annotation);
611+
}
610612
return 1;
611613
}
612614

613615
static int
614-
astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_)
616+
astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
615617
{
616618
switch (node_->kind) {
617619
case FunctionDef_kind:
618620
CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args);
619621
CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body);
620622
CALL_SEQ(astfold_expr, expr_ty, node_->v.FunctionDef.decorator_list);
621-
CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns);
623+
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
624+
CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns);
625+
}
622626
break;
623627
case AsyncFunctionDef_kind:
624628
CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args);
625629
CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body);
626630
CALL_SEQ(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.decorator_list);
627-
CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns);
631+
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
632+
CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns);
633+
}
628634
break;
629635
case ClassDef_kind:
630636
CALL_SEQ(astfold_expr, expr_ty, node_->v.ClassDef.bases);
@@ -648,7 +654,9 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_)
648654
break;
649655
case AnnAssign_kind:
650656
CALL(astfold_expr, expr_ty, node_->v.AnnAssign.target);
651-
CALL(astfold_expr, expr_ty, node_->v.AnnAssign.annotation);
657+
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
658+
CALL(astfold_expr, expr_ty, node_->v.AnnAssign.annotation);
659+
}
652660
CALL_OPT(astfold_expr, expr_ty, node_->v.AnnAssign.value);
653661
break;
654662
case For_kind:
@@ -707,7 +715,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, int optimize_)
707715
}
708716

709717
static int
710-
astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int optimize_)
718+
astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
711719
{
712720
switch (node_->kind) {
713721
case ExceptHandler_kind:
@@ -721,7 +729,7 @@ astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, int optimize_)
721729
}
722730

723731
static int
724-
astfold_withitem(withitem_ty node_, PyArena *ctx_, int optimize_)
732+
astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
725733
{
726734
CALL(astfold_expr, expr_ty, node_->context_expr);
727735
CALL_OPT(astfold_expr, expr_ty, node_->optional_vars);
@@ -734,9 +742,9 @@ astfold_withitem(withitem_ty node_, PyArena *ctx_, int optimize_)
734742
#undef CALL_INT_SEQ
735743

736744
int
737-
_PyAST_Optimize(mod_ty mod, PyArena *arena, int optimize)
745+
_PyAST_Optimize(mod_ty mod, PyArena *arena, _PyASTOptimizeState *state)
738746
{
739-
int ret = astfold_mod(mod, arena, optimize);
747+
int ret = astfold_mod(mod, arena, state);
740748
assert(ret || PyErr_Occurred());
741749
return ret;
742750
}
Collapse file

‎Python/compile.c‎

Copy file name to clipboardExpand all lines: Python/compile.c
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,11 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
354354
c.c_nestlevel = 0;
355355
c.c_do_not_emit_bytecode = 0;
356356

357-
if (!_PyAST_Optimize(mod, arena, c.c_optimize)) {
357+
_PyASTOptimizeState state;
358+
state.optimize = c.c_optimize;
359+
state.ff_features = merged;
360+
361+
if (!_PyAST_Optimize(mod, arena, &state)) {
358362
goto finally;
359363
}
360364

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.