Skip to content

fix(codegen): alias UDT array-element loop-locals so field mutation writes back#50

Merged
luisleo526 merged 1 commit into
mainfrom
fix/udt-array-element-lvalue-alias-writeback
Jul 7, 2026
Merged

fix(codegen): alias UDT array-element loop-locals so field mutation writes back#50
luisleo526 merged 1 commit into
mainfrom
fix/udt-array-element-lvalue-alias-writeback

Conversation

@luisleo526

Copy link
Copy Markdown
Contributor

Summary

Pine array elements of a user-defined type are references. A global-scope, non-var, loop-nested UDT VarDecl bound from a UDT-array-element lvalue (z = arr.get(i) / .first / .last) that is later field-mutated must alias the element so the mutation writes back into the array.

Previously this mis-lowered to a value copy:

  • a global while loop hoisted the local to a class member whose in-loop init became a value-copy assignment, and
  • a global for loop kept it a true local but the function-local alias path no-ops at global scope (_current_func_body is None).

Both silently dropped the field mutation, causing stale-array over-fire.

Fix

_register_udt_array_get_ref_locals detects exactly this shape (UDT-array-element RHS AND global field-mutation AND loop-nested), suppresses the hoisted class member, and emits a fresh per-iteration UDT& z = arr[i]; reference — the same alias form the non-hoisted function-local path already produces.

Strictly gated: read-only get-locals keep value-copy semantics and function-local get-locals are excluded, so all other output is byte-identical.

Verification (independent R7 regression gate)

  • pytest: 1449 passed / 1 skipped / 0 failed (PYTHONHASHSEED=0).
  • Byte-identity proof: transpiled 257 corpus/validation + 77 data/standard + 2 finnp17 beneficiaries under PYTHONHASHSEED=0, fix vs HEAD. Only the 2 finnp17 dirs differ; every corpus and standard strategy is byte-identical. The finnp17 diff is precisely Zone z = Zone{} / z = active_zones[i]Zone& z = active_zones[i].
  • Corpus gate: excellent=239, strong=12, anomaly=1 — no demotion.
  • Sweep: finnp17-atm (+ twin) weak → strong; engine/TV trade-count delta collapses from a ~1300-trade over-fire to +5; 4 tripwires + 3 3commas DCA/grid sentinels unchanged; 0 downward tier moves.

🤖 Generated with Claude Code

…rites back

Pine array elements of a user-defined type are references, so a global-scope,
non-`var`, loop-nested UDT VarDecl bound from a UDT-array-element lvalue
(`z = arr.get(i)` / `.first` / `.last`) that is later field-mutated must ALIAS
the element — the mutation has to write back into the array.

Previously this mis-lowered to a value copy: a global `while` loop hoisted the
local to a class member whose in-loop init became a value-copy assignment, and a
global `for` loop kept it a true local but the function-local alias path no-ops
at global scope (`_current_func_body` is None). Both silently dropped the field
mutation, causing stale-array over-fire.

`_register_udt_array_get_ref_locals` now detects exactly this shape (UDT-array-
element RHS AND global field-mutation AND loop-nested), suppresses the hoisted
class member, and emits a fresh per-iteration `UDT& z = arr[i];` reference — the
same alias form the non-hoisted function-local path already produces. Strictly
gated: read-only get-locals keep value-copy semantics and function-local
get-locals are excluded, so all other output is byte-identical.

Fixes data/draft/finnp17-atm (+ its byte-identical twin): weak -> strong,
engine/TV trade-count delta collapses from a ~1300-trade over-fire to +5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@luisleo526 luisleo526 merged commit b0d7046 into main Jul 7, 2026
9 checks passed
@luisleo526 luisleo526 deleted the fix/udt-array-element-lvalue-alias-writeback branch July 7, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant