Problem
constantFolding folds a primop only when every operand is a literal. A chain like 1 + x + 2 + y + 3 keeps all three literals separate because x and y sit between them, even though + is associative and the constants could coalesce to 6. The same holds for *, for string .., and for a resolved user Semigroup append. Flattening the operator spine n-ary and folding adjacent literals within it coalesces such chains (a 2 * … * 60 * … * 42 product collapses to one constant).
Approach
A reassociation rewrite for the Int-backed associative primops (PrimAdd, PrimMul) plus PrimConcat, and for a resolved Semigroup.append: flatten the operator spine, gather the literal operands respecting associativity, fold them, and rebuild. Float arithmetic stays out even if lifted later: IEEE +/* are not associative, and no per-constant guard makes reassociation around a variable sound. Short-circuiting &&/|| are excluded, since reassociating them would change evaluation. Numeric folding stays inside the Lua-5.1 precision limits already documented in Note [Folding primops follows Lua 5.1]: coalesce only where the folded constant is exactly representable (int within ±2^53), never introducing a value the runtime cannot hold.
Prerequisites / Relations
Independent. Reuses the constant-folding machinery in IR/Optimizer.hs and its Lua-5.1 semantics guard. Unrelated to the inlining and loop issues.
Verification / Measurement
1 + x + 2 folds its constants (to the associativity-correct equivalent of x + 3) in a focused optimizer test; a chain mixing a non-associative or short-circuit operator is left untouched. A guard test that a fold which would exceed the Lua-5.1 int/float range does not fire. Eval goldens unchanged; structural goldens shrink where constant chains appear.
Problem
constantFoldingfolds a primop only when every operand is a literal. A chain like1 + x + 2 + y + 3keeps all three literals separate becausexandysit between them, even though+is associative and the constants could coalesce to6. The same holds for*, for string.., and for a resolved userSemigroupappend. Flattening the operator spine n-ary and folding adjacent literals within it coalesces such chains (a2 * … * 60 * … * 42product collapses to one constant).Approach
A reassociation rewrite for the Int-backed associative primops (
PrimAdd,PrimMul) plusPrimConcat, and for a resolvedSemigroup.append: flatten the operator spine, gather the literal operands respecting associativity, fold them, and rebuild. Float arithmetic stays out even if lifted later: IEEE+/*are not associative, and no per-constant guard makes reassociation around a variable sound. Short-circuiting&&/||are excluded, since reassociating them would change evaluation. Numeric folding stays inside the Lua-5.1 precision limits already documented in Note [Folding primops follows Lua 5.1]: coalesce only where the folded constant is exactly representable (int within ±2^53), never introducing a value the runtime cannot hold.Prerequisites / Relations
Independent. Reuses the constant-folding machinery in
IR/Optimizer.hsand its Lua-5.1 semantics guard. Unrelated to the inlining and loop issues.Verification / Measurement
1 + x + 2folds its constants (to the associativity-correct equivalent ofx + 3) in a focused optimizer test; a chain mixing a non-associative or short-circuit operator is left untouched. A guard test that a fold which would exceed the Lua-5.1 int/float range does not fire. Eval goldens unchanged; structural goldens shrink where constant chains appear.