Skip to content

codegen: a dependent varip aggregate initializer sees its dependency's value at declaration time - #263

Merged
luisleo526 merged 6 commits into
mainfrom
fix/varip-initializer-order
Oct 27, 2026
Merged

luisleo526 merged 6 commits into
mainfrom
fix/varip-initializer-order

Conversation

@luisleo526

@luisleo526 luisleo526 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What

A varip aggregate (UDT, array, map, matrix) whose initializer reads a value computed by an earlier statement now initializes at its declaration, in statement order, like the var form fixed in #226 (merged in #261). Before, it was initialized in the first-bar preamble, before that statement, and read the zero default.

//@version=6
strategy('varip gap', initial_capital = 100000)
type State
    float value
float base = strategy.initial_capital / 100
varip state = State.new(value=base)
observed = state.value

observed was 0; it is now 1000, the same as the inline form varip state = State.new(value=strategy.initial_capital / 100) and the var form.

How

The varip declaration takes the same declaration-site route as var when its initializer depends on an earlier statement (a two-line change in the statement-order check). Independent initializers and callable-scoped declarations keep their routes and their emission. varip storage and its once flag stay outside the calc_on_order_fills rollback checkpoint, as before: a value set on the first bar survives a fill recalculation and the initializer runs once.

Tests

  • Emission order of the dependency and the declaration, the compiled run against the inline and var controls for each aggregate kind (UDT, array, map, matrix, UDT built by a helper), the issue's own script in the static and dynamic builds, and that the first value is kept when the dependency changes later. All of them fail on main (the value is 0 against 1000, or the declaration comes first).
  • A guard that independent varip initializers keep their preamble emission byte for byte.
  • With a native engine: a calc_on_order_fills strategy with a dependent varip aggregate keeps its first value across fill recalculations (it reads 0 on main), and a static test that the varip storage and its once flag stay out of the rollback checkpoint and the restore.
  • The test that pinned the old behaviour as a known gap is removed; its shapes are covered by the new tests.
  • Full suite with the paired engine: 10881 passed, 221 skipped (private fixtures and empty parameter sets, the same 221 as main), 0 failed.
  • Over the 555 corpus and fixture scripts the emitted C++ is identical to main: none of them has a dependent varip aggregate initializer.

The CHANGELOG entry of #226 now says the varip form takes the same route.

Fixes #258

🤖 Generated with Claude Code

luisleo526 and others added 6 commits October 27, 2026 03:18
… has when the declaration runs (#258)

A varip UDT, array, map or matrix whose initializer reads a value computed by an
earlier statement is initialized in the first-bar preamble, before that
statement, and reads the zero default. The var form was fixed in #226.

Adds the expectations: the emission order of the dependency and the
declaration, the compiled run against the inline and var controls for each
aggregate kind, that the first value is kept when the dependency changes later,
that independent varip initializers keep their preamble, and, with a native
engine, that the dependent value survives fill recalculations and the varip
storage stays out of the rollback checkpoint.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…t order (#258)

A varip UDT, array, map or matrix whose initializer reads a value computed
earlier in the statement walk was initialized in the first-bar preamble and
read the zero default. Route it onto the declaration-site once flag that the
var form already uses (#226). The flag and the varip storage stay outside the
calc_on_order_fills checkpoint and are reset for each new run, as for any
varip member. Independent constructors, scalars and callable-scoped
declarations keep their routes.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
… order (#258)

The CHANGELOG entry for the statement-order initializer said a varip
declaration with the same dependency still read the default, and the
AGENTS.md / CLAUDE.md rule listed varip among the paths left unchanged. With
the varip route they no longer hold: say that varip takes the same route and
that its storage and once flag stay out of the calc_on_order_fills rollback
checkpoint. The rule paragraph keeps its line count.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The row asserted that a dependent varip aggregate keeps its first-bar
preamble route, as a documented gap. With the statement-order fix the
dependent initializer moves to its declaration site, so the row now fails by
design. The new expectations for the same shapes (emission order, compiled
run against the inline and var controls, first value kept, independent varip
initializers keep their preamble) live in
tests/test_varip_initializer_statement_order.py.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…tion (#258)

The static test that the varip storage and its once flag stay out of the
rollback checkpoint found the flag by pattern and passed without it when the
pattern did not match. It now requires the flag the lowering of a persistent
declaration names (the member's `_pf_var_init_` flag) in the guarded write
before checking it against the checkpoint and the restore. The file's docstring
also says what a wrong dependency looks like.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526
luisleo526 merged commit af1778b into main Oct 27, 2026
24 checks passed
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.

varip UDT initializer reads the default when it depends on an earlier declaration

2 participants