Add break/continue/labeled statements/do-while support#418
Open
olivier-aws wants to merge 10 commits into
Open
Add break/continue/labeled statements/do-while support#418olivier-aws wants to merge 10 commits into
olivier-aws wants to merge 10 commits into
Conversation
Bump the Strata submodule from 8593f7cf to 53a3df53 (latest main) and regenerate Laurel Java classes. Schema-affecting Strata commits: - strata-org/Strata#1076 — disallow transparent procedures (require `opaque` for procedures with visible bodies) - strata-org/Strata#969 — add `opaque` keyword to Laurel grammar; ensures and modifies are now wrapped in an optional OpaqueSpec - strata-org/Strata#1031 — add `modifies *` wildcard (new ModifiesWildcard variant; unused here) - strata-org/Strata#1077 — generalized multi-target assign (new MultiAssign + AssignTarget AST nodes; unused here) - strata-org/Strata#1140 — Provenance type / metadata migration Hand-written changes: - JavaToLaurelCompiler: emit OpaqueSpec for impure procedures (always) and for pure functions with non-empty ensures. - LaurelDriver: pass `--solver z3` explicitly. The previous Strata hardcoded `solver := "z3"` for the Laurel pipeline; the bumped Strata removed that override and now defaults to cvc5 (which our CI doesn't install). Passing `--solver z3` preserves prior behavior. All other diffs in verifier/src/main/java/org/strata/jverify/laurel/ are generated by `make generate-laurel-ast`. Note: pure functions that declare @ensures used to be emitted as Transparent and are now emitted as Opaque (forced by the schema). No existing test combines @pure with @ensures, so nothing in the suite regresses; callers of such functions in the future will reason via the postcondition rather than by definitional unfolding.
Add convertStatement cases for JCBreak, JCContinue, JCLabeledStatement, JCDoWhileLoop, and JCSkip in JavaToLaurelCompiler, resolving issue #407 (excluding decreases clause which is deferred to Strata-side work). Design: - Label stack with (javaLabel, breakLabel, continueLabel) tuples pushed on each loop/labeled-statement entry, popped on exit - Only wrap loops in labelledBlock when break/continue is actually present in the loop body (detected via tree scan) - When break/continue is present, desugar for-loops to while manually (not using the forLoop IR node) to produce the correct structure: labelledBlock(breakLbl, { init; while(cond) { labelledBlock(continueLbl, body); step } }) This matches the PythonToLaurel pattern and allows Strata to verify invariants correctly across continue paths. - break/continue emit as exit(label) to the resolved target - do-while desugared via sentinel variable - Labeled statements pass their label to the next loop via pendingLabel Add VerifyBreakContinue test exercising for-break, while-break, infinite-while-break, nested-break, for-continue, and while-continue. Fixes #407 (break/continue/labeled/do-while portion).
Extract the shared loop emission logic (labelled block wrapping, while node creation, preamble handling) into a single emitLoop() method used by while, for, and do-while cases. Parameters: - cond, invariants, loopBody: the core loop components - step: optional (non-null for for-loops, null for while/do-while) - preamble: statements before the while (init for for, sentinel for do-while) - needsLabels, breakLbl, continueLbl: label wrapping control No behavioral change.
extractLoopParts now accepts JCStatement directly instead of requiring a JCBlock, internalizing the if-block-then-extract-else-just-convert pattern that was duplicated in all three loop cases.
Two sequential for-loops with continue in the same method, each generating distinct labelled block labels (loop_break_N, loop_continue_N) to confirm no label conflicts.
Exercises both exit targets (continue skips i==3, break exits at i==7) within a single for-loop, verifying x == 0+1+2+4+5+6 == 18.
Remove whileWithBreak, whileWithContinue, forLoopBreak, forLoopContinue, nestedForLoopBreak, and twoForLoops from VerifyStatements. These are now covered by VerifyBreakContinue which uses static methods that actually exercise the Laurel compiler code paths. The removed tests were instance methods that never went through the compiler (due to the Flags.STATIC gate), making them effectively no-ops. Kept in VerifyStatements: - nestedForLoopContinue: uses labeled 'continue outerLoop' (unique) - doWhileLoop: uses 'decreases' clause (unique) - forLoop, nestedForLoop: test loops without break/continue - skip, nativeAssert, P/P2/P3, underscoreVariableName, methodWithResult, ignoreCallResult: unrelated to break/continue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #407 (break/continue/labeled/do-while portion; decreases deferred).
Design
Translation examples
Simple for loop (no break/continue) — uses
forLoopIR node directly→
For loop with break — desugars to while with labelled blocks
→
For loop with continue
→
Note:
continueexits the inner labelled block (skipping the rest of the body) but the stepi = i + 1still executes because it is outside the continue-labelled block but inside the while body.While loop with break
→
Do-while loop — desugared via sentinel
→
Test plan
New
VerifyBreakContinuetest with 8 methods: for-break, while-break, infinite-while-break, nested-break (inner only), for-continue (i==2andi>=2), while-continue (i==2andi>=2). All existing tests pass.