Constant folding 2026-10-13
Constant folding replaces a program expression whose value is known during translation by a literal value. For
x=2+3*4, first replace the multiplication subtree by Constant(value=12), then replace the addition subtree by Constant(value=14). The variable assignment and its Store target survive: the result still assigns to x. This illustrates why a bottom-up abstract syntax tree traversal is convenient: replacing one child can make its parent eligible for the next replacement.Here is a deliberately small Python transformer. Calling
generic_visit first transforms the children; returning a node replaces the visited node. The location helpers retain or supply the metadata expected for compilation. [ref]ast — Abstract syntax trees, Python 3.14 documentation. NodeTransformer, generic_visit, copy_location and fix_missing_locations
class FoldIntegers(ast.NodeTransformer):
def visit_BinOp(self, node):
self.generic_visit(node)
if (isinstance(node.left, ast.Constant)
and isinstance(node.right, ast.Constant)
and type(node.left.value) is int
and type(node.right.value) is int
and type(node.op) in OPS):
value = OPS[type(node.op)](node.left.value, node.right.value)
return ast.copy_location(ast.Constant(value=value), node)
return node
tree = ast.parse("x=2+3*4", optimize=0)
folded = ast.fix_missing_locations(FoldIntegers().visit(tree))
namespace = {}
exec(compile(folded, "<folded example>", "exec"), namespace)
assert namespace["x"] == 14
assert ast.unparse(folded) == "x = 14"This transformer folds literal integer operands only. It leaves
a+3*4 as a+12, without inventing a value for the program identifier a. It leaves calls intact: replacing 0*f() by 0 could discard a side effect or a failure. Nor does it reassociate floating-point arithmetic, where changing parentheses can change rounding. For the supported integer arithmetic, a short structural induction explains correctness: a retained literal value has the same value; at each folded binary node, the already-correct child values are combined by exactly the original operation in the original left/right order. This claim concerns the supported fragment's values, not unrestricted equivalence of arbitrary Python programs.