Skip to content

Add contract and transparency pass#28

Draft
keyboardDrummer wants to merge 144 commits intoissue-21-assign-variable-typefrom
issue-924-contract-and-proof-pass
Draft

Add contract and transparency pass#28
keyboardDrummer wants to merge 144 commits intoissue-21-assign-variable-typefrom
issue-924-contract-and-proof-pass

Conversation

@keyboardDrummer
Copy link
Copy Markdown
Owner

@keyboardDrummer keyboardDrummer commented Apr 23, 2026

Builds on:

Summary

Add these passes:

  • [New] EliminateReturnStatements: rewrite return to exit statements, needed for the next pass.
  • [New] ContractPass: translate away pre and postconditions entirely by introducing assertion and assumptions at call sites and at procedure starts and ends
  • [New] TransparencyPass: for each Core procedure, generate a function with the same signature and name suffixed with $asFunction. If a Core procedure is marked as transparent, attempt to generate a functional version of it, where assertions are erased and all calls are to functional versions. Tie the functional version to the procedure using a free postcondition.
  • [Existing] Lift assertions, assumptions and procedure calls when they occur in expressions.
  • [Follow-up] AxiomatizeExpressionAssumptionsPass: erase assumptions in Core function expressions by introducing functions and axioms.

The effect of the contract and transparency pass:

  1. Allow postconditions on functions
  2. Allow calling procedures from contracts
  3. Improve diagnostics related to contracts, using the correct verbiage "precondition" and "postcondition" instead of "assertion"
  4. Allow transparent procedures IF they have an expression body
  5. Allow assertions in transparent procedures and functions

The combined effect of 2 and 4 is that there is no more difference between Laurel functions and transparent procedures.

Follow-up work

  • Remove the 'functional' keyword from the Laurel grammar
  • Lift assumptions in expressions to axioms.
  • In the transparency phase, if something has no asserts and only calls functions, only create a function and no procedure
  • Move the transparency phase so its Core->Core instead of UnorderedCoreWithLaurelTypes -> UnorderedCoreWithLaurelTypes

keyboardDrummer-bot and others added 30 commits April 15, 2026 12:18
…aurelTypes

- Add FunctionsAndProofsProgram structure with functions, proofs, datatypes, constants
- Add temporary laurelToFunctionsAndProofs translation (functional → functions, non-functional → proofs)
- Rename OrderedLaurel to CoreWithLaurelTypes
- Change OrderedDecl: replace 'procs' with 'funcs' (for function SCCs) and 'procedure' (for individual proofs)
- Rewire pipeline: Laurel → FunctionsAndProofs → CoreWithLaurelTypes → Core
- Both functions and proofs participate in topological ordering via the call graph

Addresses steps (c) and (d) of strata-org#924.
(a) Contract pass (ContractPass.lean):
- Generates precondition/postcondition helper procedures for non-functional
  procedures with contracts
- Transforms procedure bodies to add assume/assert for own contracts
- Not yet wired into pipeline (needs call-site rewriting for full activation)

(b) Proof pass improvements (FunctionsAndProofs.lean):
- Add stripAssertAssume utility for deep traversal that removes Assert/Assume
  nodes (to be used when full proof pass generates both functions and proofs
  for every procedure)
- Import MapStmtExpr for AST traversal support
- Improve documentation describing the future full proof pass

Also:
- CoreGroupingAndOrdering: use isFunctional flag instead of name lookup to
  partition functions and proofs in orderFunctionsAndProofs (more robust when
  functions and proofs share names)
- Pipeline: import ContractPass, update documentation for new pipeline stages
…to pipeline; proof pass: every procedure generates function + proof

Changes based on review feedback:

1. Contract pass treats all procedures the same — removed isFunctional guard
   from collectContractInfo, contractPass, and helper generation.

2. Call-site rewriting — added rewriteCallSites which uses mapStmtExpr for
   bottom-up traversal and handles three patterns:
   - Assign targets (StaticCall callee args) → Block [assert pre; assign; assume post]
   - LocalVariable name type (some (StaticCall callee args)) → Block [assert pre; decl; assume post]
   - Bare StaticCall callee args → Block [assert pre; call]

3. Contract pass wired into pipeline — replaced placeholder comment with
   actual contractPass call.

4. Full proof pass — every procedure now generates both a function copy
   (isFunctional=true, body only for transparent procedures, with
   Assert/Assume stripped) and a proof copy (isFunctional=false).
…riting and proof pass

Three issues caused CI failures:

1. Call-site rewriting used bottom-up mapStmtExpr, which processed
   StaticCall nodes inside expressions (e.g., inside Assign/LocalVariable
   initializers) before the parent pattern could match. This created
   Block[Assert; StaticCall] inside expression positions, which the
   function translator rejected. Fixed by rewriting at the Block
   (statement) level instead.

2. The proof pass created both function and proof copies for every
   procedure with the same name, causing 'declaration already exists'
   errors in the Core type checker. Reverted to partition behavior
   (functional → functions, non-functional → proofs).

3. The contract pass changes verification diagnostics from 'precondition
   does not hold' to 'assertion does not hold', breaking test expectations.
   Disabled the contract pass in the pipeline pending test updates.

The contract pass code (ContractPass.lean) is preserved with the fixes
above and can be re-enabled. stripAssertAssume and mkFunctionCopy are
also preserved for when the full proof pass is activated.
…-org/Strata into issue-924-contract-and-proof-pass
- Add 'opaque' keyword to the Laurel grammar (LaurelGrammar.st)
  that groups ensures and modifies clauses under it
- Update ConcreteToAbstractTreeTranslator to parse the new
  opaqueSpec grammar node (8 args instead of 9)
- Update AbstractToConcreteTreeTranslator to emit opaqueSpec
  when formatting procedures with Opaque bodies
- Update all Laurel test files to mark all procedures as opaque
- Update .lr.st and .laurel.st test files accordingly
Keep both the FunctionsAndProofs pipeline from this branch and the
overflowChecks field added on main.
Adds a new Laurel-to-Laurel pass that replaces return statements with
assignments to output parameters followed by exit to a labelled block
wrapping the procedure body. This ensures postcondition assertions
(inserted by the contract pass) are checked on all return paths.

The pass runs after EliminateReturnsInExpression and before
ConstrainedTypeElim/ContractPass in the pipeline.
…assertions

When a requires or ensures clause has a summary annotation, the contract
pass now propagates that summary to the generated assert statement. This
means verification errors will display the user-provided summary (e.g.,
'divisor is non-zero does not hold') instead of the generic 'precondition
does not hold' or 'postcondition does not hold'.

- Added combinedSummary helper to extract summaries from clause metadata
- Added preSummary/postSummary fields to ContractInfo
- Updated all assertion generation sites to use clause summaries when available
@keyboardDrummer-bot
Copy link
Copy Markdown
Collaborator

I investigated the "Run internal benchmarks of Strata" CI failure. This is not a code issue — it's a pre-existing infrastructure problem with running CI on this fork.

Root cause: The benchmark job tries to assume an AWS IAM role using secrets.AWS_BENCHMARK_ACCOUNT, which is not configured on the keyboardDrummer/Strata fork. This causes the ARN to be arn:aws:iam:::role/github-actions-codebuild-role (empty account ID), which fails with:

Could not assume role with OIDC: Request ARN is invalid

This job has failed on every single Build run on this fork (all 5 runs), with the same error. It is not related to any code changes in this PR.

To fix, either:

  1. Add the AWS_BENCHMARK_ACCOUNT secret to the fork's repository settings, or
  2. Add a condition to skip the benchmark on forks, e.g. if: github.repository == 'strata-org/Strata'

All other CI checks (Lean build, Python tests across 3.11–3.14, CBMC, lint, docs) pass successfully.

@keyboardDrummer keyboardDrummer changed the base branch from merge-1076-1077 to issue-21-assign-variable-type May 4, 2026 13:11
@keyboardDrummer keyboardDrummer force-pushed the issue-924-contract-and-proof-pass branch from da18905 to 3ce6673 Compare May 4, 2026 13:17
@github-actions github-actions Bot added SMT github_actions and removed Git conflicts PR has merge conflicts with the base branch labels May 4, 2026
@keyboardDrummer
Copy link
Copy Markdown
Owner Author

keyboardDrummer commented May 5, 2026

@keyboardDrummer-bot can you create another PR that copies these two passes from this PR:
[New] EliminateReturnStatements: rewrite return to exit statements, needed for the next pass.
[New] ContractPass: translate away pre and postconditions entirely by introducing assertion and assumptions at call sites and at procedure starts and ends

However, in the contract pass, the generated $post procedures should be marked as functional, and they should take all inputs and all outputs of the original procedure as parameters, so they don't need to call the original procedure in their body. At the call location, before the call, first assign all input arguments to temporary variables, and then pass those to both the call and the assumed call to the $post.

@keyboardDrummer
Copy link
Copy Markdown
Owner Author

@keyboardDrummer-bot can you create another PR that is a copy of this PR, but without the first two phases:
[New] EliminateReturnStatements: rewrite return to exit statements, needed for the next pass.
[New] ContractPass: translate away pre and postconditions entirely by introducing assertion and assumptions at call sites and at procedure starts and ends

You might run into issues with assertions not being lifted in the lifting pass.
See if there are fixes in #43, strata-org#1113 and strata-org#1130 that you can use. Actually, start with a merge of all the PRs related to those links.

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.

3 participants