The small-step semantics of Imperative must have scoped var init, remove unlabeled exit from Core#1141
Conversation
MikaelMayer
left a comment
There was a problem hiding this comment.
🤖 Overall this is a well-structured PR that correctly implements block-scoped variable semantics via projectStore. The Kleene language extension mirrors the deterministic semantics cleanly, and the new tests provide good coverage of the scoping behavior.
A few items to consider:
- The
PostWFdefinition quantifies over allσ_parent, which is stronger than needed (in practice only the actual parent store matters). This is conservative and safe, but worth documenting that it means postconditions must not reference block-local variables. - There is significant code duplication in the new
core_step_preserves_wf*/core_wf*_preservedtheorems — all six follow the exact same proof pattern ascore_step_preserves_wfBool. Stmt.labels/Block.labelsappear to be dead code (not referenced anywhere outside their definition).
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 The new commit is a merge of main — no changes to the files I previously commented on. My three suggestions (deduplicating the wf-preservation proofs, clarifying whether Stmt.labels/Block.labels are dead code, and documenting PostWF's universal quantification over σ_parent) remain unaddressed. These were non-blocking suggestions so LGTM overall, but it would be good to get a response on the labels question in particular.
…s 'break' or 'continue', and in fact was never used.
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 Verified the new commits since last review:
.labelsdead code: ✅ Fixed — removed in commit 917ea90.- Deduplicating wf-preservation proofs: Not addressed (non-blocking, still a nice-to-have).
PostWFdocumentation: Not addressed (non-blocking).
The one actionable item was properly fixed. The "Disallow unlabeled exit" commit is a clean refactor that simplifies the semantics. LGTM.
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 LGTM — the latest commit (3a875b08) is a minor omit annotation cleanup. My previous non-blocking suggestions (deduplicating wf-preservation proofs, documenting PostWF) remain open but are not blockers.
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 LGTM — the latest commit is a merge of main with no changes to PR files. Previous non-blocking suggestions (deduplicating wf-preservation proofs, documenting PostWF) remain open but are not blockers.
|
I think this is an excellent move to have scoped semantics. It will likely make proofs simpler |
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 LGTM — the latest commit removes @[simp] from variable-tracking definitions, keeping only @[expose]. Clean change. Previous non-blocking suggestions (deduplicating wf-preservation proofs, documenting PostWF) remain open but are not blockers.
|
Also, could you update the docs please? Right now it says "An exit statement transfers control out of the nearest enclosing block with a matching label, or, if no label is provided, the nearest enclosing block.". |
|
Fixed, thanks. Setifying the result of touchedVars and relevant helper functions make sense to me (their item order in the list shouldn't matter). |
MikaelMayer
left a comment
There was a problem hiding this comment.
🔍 LGTM — the "address comments" commit properly addresses feedback: @[expose] removed from variable-tracking and sizeOf defs, anonymous suffices hypotheses named (h_gen), @call_sem simplified to named-argument style, outdated test comment removed, and docs updated to reflect unlabeled exit removal. Previous non-blocking suggestions (deduplicating wf-preservation proofs, documenting PostWF) remain open but are not blockers.
There was a problem hiding this comment.
I think a similar Option construct for the GOTO exits could be simplified as well. This is non-blocking, but perhaps they can be addressed in future PRs.
| | s :: srest => Stmt.modifiedOrDefinedVars s ++ Block.modifiedOrDefinedVars srest | ||
| end | ||
|
|
||
| mutual |
There was a problem hiding this comment.
Mutual block unnecessary?
Issue #, if available:
Closes #372
Description of changes:
Formalizing scoped variable initialization:
(nondeterministic).
Removing unlabeled
exitcommand (exit;, notexit lbl;):exitcommand doesn't have clear meaning when it is insidewhile. Inwhile cond { ... exit; ... }, isexitequivalent tocontinueorbreakin C/Python? No translation to Core was introducing the unlabeledexit, and the small-step semantics wasn't clear about the meaning ofexitinside a loop.exitappears inside the body of a while loop / if statement (unless it is wrapped by another nested block), but the DDM syntax of core allows it, so from user's perspective this gap is kind of surprising.exitcase because it can always be simulated by a labeled block + labeled exit.On top of this, this also renames
touchedVarstomodifiedOrDefinedVarsfor clarity, and instead makestouchedVarsall vars that are read + modified + defined.How to review?
.blockconstructor now has the input store which will be used to 'project' the output store to the variables that have been defined before. Also, any block-exiting small steps likestep_block_donewill do the projection, to define variables which were defined inside the inner scope.touchedVarsupdate and Strata/Languages/Core/StatementSemantics.lean has some additional well-formedness about evaluator extension that are useful.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.