-
Notifications
You must be signed in to change notification settings - Fork 45
Lift unlabeled block expressions emitted by Python-to-Laurel #1133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3cfa493
977afc1
7dc0a47
2b4871c
f5bd0f7
ad373f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,57 @@ procedure conditionalAssignmentInExpression(x: int) | |
| } | ||
| }; | ||
|
|
||
| // Regression for #1133: an unlabeled-block expression that contains a | ||
| // destructive assignment must be admissible inside an `assert` condition. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Why must that be admissible? What is the use-case? I was planning to update Resolution.lean so it explicitly rejects assignments to variables that occur inside assert/assume but were the variable was defined outside of it. |
||
| // Before the fix, `containsAssignment` flagged the inner `x := 1` and | ||
| // `transformStmt` bailed out, leaving the block in the assert condition; | ||
| // the Laurel-to-Core translator then rejected it. | ||
| procedure assertWithBlockExpr() | ||
| opaque | ||
| { | ||
| var x: int := 0; | ||
| assert ({ x := 1; x } > 0); | ||
| assert x == 1 | ||
| }; | ||
|
|
||
| // Same regression, but exercising the `assume` path through | ||
| // `containsAssignmentOutsideUnlabeledBlock`. | ||
| procedure assumeWithBlockExpr() | ||
| opaque | ||
| { | ||
| var x: int := 0; | ||
| assume ({ x := 1; x } > 0); | ||
| assert x == 1 | ||
| }; | ||
|
|
||
| // Regression for #1133: an `assert` that itself sits inside an | ||
| // expression-position block and whose condition contains another unlabeled | ||
| // block with a destructive assignment. This pattern only lowers correctly | ||
| // once `transformExpr` itself has cases for `.Assert`/`.Assume` that | ||
| // recursively lift the condition (rather than relying on the surrounding | ||
| // `transformStmt` to do so). | ||
| procedure nestedAssertInBlockExpr() | ||
| opaque | ||
| { | ||
| var z: int := 0; | ||
| var y: int := { assert ({ z := 1; z } > 0); 42 }; | ||
| assert y == 42; | ||
| assert z == 1 | ||
| }; | ||
|
|
||
| // Regression for #1133: an unlabeled block in the initializer of a | ||
| // declare-with-init that itself sits in expression position. Before the | ||
| // fix, `transformExpr` on `.Assign[.Declare]` early-returned the original | ||
| // expression without recursing into the initializer, so the inner | ||
| // `{ x := 1; x }` survived to the Laurel-to-Core translator. | ||
| procedure nestedBlockInDeclInit() | ||
| opaque | ||
| { | ||
| var x: int := 0; | ||
| var y: int := { var t: int := { x := 1; x }; t + 1 }; | ||
| assert y == 2 | ||
| }; | ||
|
|
||
| procedure anotherConditionAssignmentInExpression(c: bool) | ||
| opaque | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the catch-all to false actually correct here? I'm having trouble understanding what happens if it returns a "false negative" to
transformExpr. Is it "accidentally correct" sincetransformExprhas a catch-all that doesn't recurse into the same variants?