feat(phl): proc rewrite over ranges and whole statements - #1113
Merged
Conversation
strub
force-pushed
the
proc-rewrite-block
branch
5 times, most recently
from
September 4, 2026 14:09
50f22d6 to
ad39678
Compare
`proc rewrite` used to act on exactly one instruction per invocation,
so normalising the constants of a cloned procedure body took one call
per statement, with hand-computed positions for nested branches. The
position is now optional and may be a range:
proc rewrite {2} 3 /= (* one instruction, deep *)
proc rewrite {2} [2..11] /= (* a range, deep *)
proc rewrite {2} /= (* the whole program, deep *)
proc rewrite {2} ^while.1?:[1..1] addzC
All forms recurse into the bodies of if/while/match and apply the
rewrite to every expression (assignment and sampling right-hand sides,
guards, call arguments, raise). In lemma mode, instructions without an
occurrence of the pattern are skipped; the tactic fails only if nothing
was rewritten. One side goal is emitted per rewritten expression and
all are discharged internally.
A single position is the singleton range. This changes the behaviour
of lemma rewrites at an if/while/match position, which used to touch
the guard only; they now also rewrite one occurrence in every body
expression.
Match-arm binders are in scope for the rewrite and are renamed apart
from the proof context in the side goals, so a lemma local sharing a
binder's name does not clash.
The position-less lemma form takes a proof term without a leading `@'
so that `proc rewrite at' stays unambiguous.
`i_map_expr` is now derived from a new `i_fold_map_expr` that threads
an accumulator and the match-arm locals in scope. The single-expression
`t_change` is subsumed by the range version; its only caller, the
expression form of `proc change`, was unreachable from the grammar and
is removed.
strub
force-pushed
the
proc-rewrite-block
branch
from
September 4, 2026 14:16
ad39678 to
affccbd
Compare
strub
enabled auto-merge
September 4, 2026 14:35
bgregoir
approved these changes
Sep 4, 2026
bgregoir
left a comment
Contributor
There was a problem hiding this comment.
I think I don't understand the code correctly. So I trust you. The behavior of the tactic is nice. An side remark. I think those kind of tactics will be much simpler to review if it was not in the trusted base. You can implement it by doing a transitivity (or a conseq for hoare/phoare/ehoare) with the new program and then use the generated subgoal to prove the equivalence.
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.
proc rewriteused to act on exactly one instruction per invocation,so normalising the constants of a cloned procedure body took one call
per statement, with hand-computed positions for nested branches. The
position is now optional and may be a range:
All forms recurse into the bodies of
if/while/matchand apply therewrite to every expression (assignment and sampling right-hand sides,
guards, call arguments, raise). In lemma mode, instructions without an
occurrence of the pattern are skipped; the tactic fails only if nothing
was rewritten. One side goal is emitted per rewritten expression and
all are discharged internally.
A single position is the singleton range. This changes the behaviour
of lemma rewrites at an
if/while/matchposition, which used to touchthe guard only; they now also rewrite one occurrence in every body
expression.
Match-arm binders are in scope for the rewrite and are renamed apart
from the proof context in the side goals, so a lemma local sharing a
binder's name does not clash.
The position-less lemma form takes a proof term without a leading
@so that
proc rewrite atstays unambiguous.i_map_expris now derived from a newi_fold_map_exprthat threadsan accumulator and the match-arm locals in scope.
The single-expression
t_changeis subsumed by the range version; itsonly caller, the expression form of
proc change, was unreachable fromthe grammar and is removed.