Skip to content

Commit

Permalink
bpo-42282: Fold constants inside named expressions (pythonGH-23190)
Browse files Browse the repository at this point in the history
* The AST optimiser wasn't descending into named expressions, so
  any constant subexpressions weren't being folded at compile time
* Remove "default:" clauses inside the AST optimiser code to reduce the
  risk of similar bugs passing unnoticed in future compiler changes
  • Loading branch information
ncoghlan committed Nov 7, 2020
1 parent ee2549c commit 8805a4d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Optimise constant subexpressions that appear as part of named expressions
(previously the AST optimiser did not descend into named expressions).
Patch by Nick Coghlan.
54 changes: 43 additions & 11 deletions Python/ast_opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
static int
make_const(expr_ty node, PyObject *val, PyArena *arena)
{
// Even if no new value was calculated, make_const may still
// need to clear an error (e.g. for division by zero)
if (val == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
return 0;
Expand Down Expand Up @@ -49,7 +51,7 @@ fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
of !=. Detecting such cases doesn't seem worthwhile.
Python uses </> for 'is subset'/'is superset' operations on sets.
They don't satisfy not folding laws. */
int op = asdl_seq_GET(arg->v.Compare.ops, 0);
cmpop_ty op = asdl_seq_GET(arg->v.Compare.ops, 0);
switch (op) {
case Is:
op = IsNot;
Expand All @@ -63,8 +65,17 @@ fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
case NotIn:
op = In;
break;
default:
op = 0;
// The remaining comparison operators can't be safely inverted
case Eq:
case NotEq:
case Lt:
case LtE:
case Gt:
case GtE:
op = 0; // The AST enums leave "0" free as an "unused" marker
break;
// No default case, so the compiler will emit a warning if new
// comparison operators are added without being handled here
}
if (op) {
asdl_seq_SET(arg->v.Compare.ops, 0, op);
Expand Down Expand Up @@ -224,7 +235,7 @@ fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)

PyObject *lv = lhs->v.Constant.value;
PyObject *rv = rhs->v.Constant.value;
PyObject *newval;
PyObject *newval = NULL;

switch (node->v.BinOp.op) {
case Add:
Expand Down Expand Up @@ -263,8 +274,11 @@ fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
case BitAnd:
newval = PyNumber_And(lv, rv);
break;
default: // Unknown operator
// No builtin constants implement the following operators
case MatMult:
return 1;
// No default case, so the compiler will emit a warning if new binary
// operators are added without being handled here
}

return make_const(node, newval, arena);
Expand Down Expand Up @@ -457,8 +471,11 @@ astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Expression_kind:
CALL(astfold_expr, expr_ty, node_->v.Expression.body);
break;
default:
// The following top level nodes don't participate in constant folding
case FunctionType_kind:
break;
// No default case, so the compiler will emit a warning if new top level
// compilation nodes are added without being handled here
}
return 1;
}
Expand Down Expand Up @@ -567,8 +584,14 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
return make_const(node_, PyBool_FromLong(!state->optimize), ctx_);
}
break;
default:
case NamedExpr_kind:
CALL(astfold_expr, expr_ty, node_->v.NamedExpr.value);
break;
case Constant_kind:
// Already a constant, nothing further to do
break;
// No default case, so the compiler will emit a warning if new expression
// kinds are added without being handled here
}
return 1;
}
Expand Down Expand Up @@ -686,8 +709,17 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Expr_kind:
CALL(astfold_expr, expr_ty, node_->v.Expr.value);
break;
default:
break;
// The following statements don't contain any subexpressions to be folded
case Import_kind:
case ImportFrom_kind:
case Global_kind:
case Nonlocal_kind:
case Pass_kind:
case Break_kind:
case Continue_kind:
break;
// No default case, so the compiler will emit a warning if new statement
// kinds are added without being handled here
}
return 1;
}
Expand All @@ -700,8 +732,8 @@ astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState
CALL_OPT(astfold_expr, expr_ty, node_->v.ExceptHandler.type);
CALL_SEQ(astfold_stmt, stmt, node_->v.ExceptHandler.body);
break;
default:
break;
// No default case, so the compiler will emit a warning if new handler
// kinds are added without being handled here
}
return 1;
}
Expand Down

0 comments on commit 8805a4d

Please sign in to comment.