Skip to content

laurel: wire old() to Core two-state semantics#1203

Open
julesmt wants to merge 1 commit into
main2from
julesmt/features/laurel-old-two-state
Open

laurel: wire old() to Core two-state semantics#1203
julesmt wants to merge 1 commit into
main2from
julesmt/features/laurel-old-two-state

Conversation

@julesmt
Copy link
Copy Markdown
Member

@julesmt julesmt commented May 21, 2026

laurel: wire old() to Core two-state semantics

Modifies-clause frame conditions now flow through Core's old-prefixed
identifiers via Core's native two-state semantics, replacing the previous
synthetic $heap_in parameter.

  1. HeapParameterization: heap-writing procedures take $heap as a true
    inout parameter (same name in inputs and outputs) rather than a
    $heap_in / $heap pair with a synthesized assignment prelude.

  2. ModifiesClauses: frame condition references old($heap) via
    StmtExpr.Old instead of a separate $heap_in variable.

  3. New PushOldInward Laurel-to-Laurel pass: distributes StmtExpr.Old
    through its sub-expressions until each Old immediately wraps a Local
    Var. Warns if old(...) does not mention any inout parameter.

  4. LaurelToCoreTranslator: Old (Var (Local n)) translates directly to
    fvar (mkOld n). Inout parameters at call sites are detected and emit
    .inoutArg rather than paired .inArg + .outArg. Call-arg
    construction is shared between the two StaticCall sites via a new
    buildCallArgs helper.

Tests: PushOldInwardTest exercises the new pass on hand-built ASTs
covering distribution over operators, calls, conditionals, fields,
quantifiers, and the warning behaviour. Existing modifies-clause coverage
in T2_ModifiesClauses already drives the synthetic Old path end-to-end.

Copy link
Copy Markdown
Contributor

@keyboardDrummer keyboardDrummer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!! This feature is super useful to have. Love the reliance on Core's support for old.

| .staticProcedure proc => proc.outputs
| .instanceProcedure _ proc => proc.outputs
| _ => []
let (calleeInputs, calleeOutputs) := match model.get callee with
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you extract the duplication between the two cases that handle StaticCall, the bare call and the assigning call?

let id ← freshId
return LExpr.fvar () (⟨s!"DUMMY_VAR_{id}", ()⟩) none

private def oldifyExpr (inoutNames : List String) : Core.Expression.Expr → Core.Expression.Expr
Copy link
Copy Markdown
Contributor

@keyboardDrummer keyboardDrummer May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a warning if old is pushed inward but hits no inout parameter?

Interesting to have this transformation at the Core level. Alternatively you can have a "PushOldInward" phase at the Laurel level that pushes old inwards until it hits identifiers, so LaurelToCoreTranslator only needs to support Old that immediately wraps an identifier. I think if you use mapStmtExprM then PushOldInward could be about as short as this function.

I think I would prefer that since it would move a little code out of LaurelToCoreTranslator and I prefer to keep this transformation as dumb as possible. Computing the Core in/inout/out arguments in LaurelToCoreTranslator is unfortunate but seems unavoidable unless we change Laurel.

@@ -0,0 +1,92 @@
/-
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR is implicitly also adding support for inout parameters to Laurel, could you add a separate test for that? Could you also check how Resolution.lean currently deals with in and out parameters that have the same name? How come it is not reporting duplicate names in this PR ?

Copy link
Copy Markdown
Member Author

@julesmt julesmt May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveParameter calls defineNameCheckDup on every input and output, so a user-written procedure with the same name in both does get a duplicate-definition error at the initial resolve.

Is there's a user-facing way to declare an inout parameter today? I don't really know how to add a "user-declared inout" test... @keyboardDrummer

module

/-
End-to-end coverage of the two-state path that runs through Core's
Copy link
Copy Markdown
Contributor

@keyboardDrummer keyboardDrummer May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about this test because the programs being tested do not use the old keyword. The tests here are for things that I think are already tested in T2_ModifiesClauses. I see that this PR also simplifies the implementation of ModifiesClauses.lean, but since that's a refactoring it shouldn't need additional testing. Could you replace the tests here with tests that use StmtExpr.Old ? Also, given your implementation, you could use old both for the implicit heap parameter, and for explicit inout parameters, so we should test both.

Secondly, this comment describes part of the implementation of StmtExpr.Old, which I think shouldn't be part of a test.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes will do

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that the test programs don't write old(...) — turns out .Old has no Laurel surface syntax today. My bad

@keyboardDrummer
Copy link
Copy Markdown
Contributor

Note: this PR should target main2 given the ongoing Strata refactoring

@julesmt julesmt force-pushed the julesmt/features/laurel-old-two-state branch from 67e3e0e to 8a153ae Compare May 21, 2026 17:16
@github-actions github-actions Bot added Git conflicts Python Core GOTO dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code SMT labels May 21, 2026
@julesmt julesmt changed the base branch from main to main2 May 21, 2026 17:18
Modifies-clause frame conditions now flow through Core's `old`-prefixed
identifiers via Core's native two-state semantics, replacing the previous
synthetic `$heap_in` parameter.

1. HeapParameterization: heap-writing procedures take `$heap` as a true
   inout parameter (same name in inputs and outputs) rather than a
   `$heap_in` / `$heap` pair with a synthesized assignment prelude.

2. ModifiesClauses: frame condition references `old($heap)` via
   `StmtExpr.Old` instead of a separate `$heap_in` variable.

3. New PushOldInward Laurel-to-Laurel pass: distributes `StmtExpr.Old`
   through its sub-expressions until each `Old` immediately wraps a Local
   Var. Warns if `old(...)` does not mention any inout parameter.

4. LaurelToCoreTranslator: `Old (Var (Local n))` translates directly to
   `fvar (mkOld n)`. Inout parameters at call sites are detected and emit
   `.inoutArg` rather than paired `.inArg` + `.outArg`. Call-arg
   construction is shared between the two StaticCall sites via a new
   buildCallArgs helper.

Tests: PushOldInwardTest exercises the new pass on hand-built ASTs
covering distribution over operators, calls, conditionals, fields,
quantifiers, and the warning behaviour. Existing modifies-clause coverage
in T2_ModifiesClauses already drives the synthetic `Old` path end-to-end.
@julesmt julesmt force-pushed the julesmt/features/laurel-old-two-state branch 2 times, most recently from 8a153ae to 2f9dfce Compare May 21, 2026 18:08
@github-actions github-actions Bot removed Python Core GOTO dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code SMT Git conflicts labels May 21, 2026
@julesmt
Copy link
Copy Markdown
Member Author

julesmt commented May 21, 2026

@keyboardDrummer I added changes, let me know what you think

@julesmt julesmt requested a review from keyboardDrummer May 22, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants