Skip to content

Allow later contract fields to reference earlier fields (#229) - #238

Open
palacharlanarendra wants to merge 1 commit into
kaspanet:masterfrom
palacharlanarendra:prior-field-references
Open

Allow later contract fields to reference earlier fields (#229)#238
palacharlanarendra wants to merge 1 commit into
kaspanet:masterfrom
palacharlanarendra:prior-field-references

Conversation

@palacharlanarendra

@palacharlanarendra palacharlanarendra commented Aug 30, 2026

Copy link
Copy Markdown

Allow later contract fields to reference earlier fields #229

Contract field initializers can reference constructor parameters and constants, and static checking accepts references to earlier contract fields. However, bytecode compilation evaluates each field initializer without adding previously resolved fields to the constant environment. This causes compilation to fail with RuntimeEvaluationRequired when a later field references an earlier field.

We resolve this by accumulating successfully resolved contract fields into the constant environment sequentially in declaration order during compilation.

The Defect

In silverscript-lang/src/compiler/compile/helpers.rs, the compiler compiles contract fields in compile_contract_fields by iterating over them and resolving constant references using only base_constants:

let resolved = resolve_constant_references(field.expr.clone(), base_constants, &mut resolve_visiting)?;

base_constants only contains constructor parameters and global constants. Because the resolved expressions of preceding fields are not accumulated, references to earlier fields (e.g. mirrored = amount) remain unresolved as raw ExprKind::Identifier expressions.

When the compiler attempts to encode the value as a constant push (for fixed-size types like int), it fails to encode the identifier and aborts with RuntimeEvaluationRequired.

The Fix

  1. Accumulate Constants: Clone base_constants into a mutable environment map current_constants at the beginning of compile_contract_fields.
  2. Propagate Resolved Fields: After a field's initializer is resolved and compiled, insert its resolved expression into current_constants.
  3. Sequential Reference Resolution: Pass current_constants to resolve_constant_references, fixed_type_size, encode_value_with_constant_size, and the expression environment ExprEnv.
  4. Validation: Undefined variables, forward references, and cyclic dependencies continue to be rejected by the compiler's sequential static check pass.

Tests

We added three regression tests in silverscript-lang/tests/compiler_tests.rs:

  • contract_field_initializer_accepts_a_reference_to_an_earlier_field: Verifies that compiling a contract with prior field references succeeds and matches the expected behavior.
  • contract_field_initializer_rejects_forward_and_undefined_references: Verifies that undefined variables and forward-references to fields declared later are clearly rejected during static checks.
  • contract_field_initializer_rejects_cyclic_references: Verifies that circular field reference dependencies are clearly rejected.

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