Skip to content

Commit d71dfe9

Browse files
Phase 1b: statement-execution relation + preservation (simple-statement fragment) (#115)
## What A big-step **statement-execution semantics** and its **store-typing preservation**, for the simple (non-control-flow) statements. ```lean mutual StmtExec : Stmt → Env → Env → Prop -- single statement StmtsExec : List Stmt → Env → Env → Prop -- block, threaded left-to-right end ``` Covered forms: `complain`, `expr`, `varDecl`, `assign`, `return_`. Each evaluates its expression to a value via the closed-store `MultiStep` (expression evaluation is store-invariant) and then applies its store effect. ## Metatheorem — store-typing preservation ```lean stmt_exec_preservation : StoreWellTyped Γ ρ → StmtWellTyped Γ s Γ' → StmtExec s ρ ρ' → StoreWellTyped Γ' ρ' stmts_exec_preservation : the same, threaded over a block ``` A well-typed statement (or block) run in a well-typed store yields a store well-typed against the statement's output context. The pieces compose exactly as the prior PRs set up: | Statement | Preserved by | |---|---| | `varDecl` | `store_wellTyped_extend` (grows the context) | | `assign` | `store_wellTyped_update` (overwrites an already-declared variable at its type — **new** here) | | `complain` / `expr` / `return_` | store and context unchanged | and the value's type comes from `store_multiStep_preservation` (multi-step store-typed preservation, **new** here) + `hasType_lit_any`. Two **executable smoke tests**: `let x = 0`, and the block `let x = 0; x` staying well-typed against the context it produces. ## Deferred (next increment) — and why The control-flow forms `if` / `loop` / `attempt` / `consent` are **not** included. They introduce **block scoping**, which the flat `Env` (`String → Option Value`) model doesn't yet handle: a block-local `varDecl` shadowing an outer variable at a *different* type would leave the store ill-typed against the outer context after the block, unless the store is **restored on block exit**. That store-restoration design is a real modelling decision (it determines how faithfully the model tracks the Rust implementation's lexical scoping), so I've scoped it out of this PR rather than rush it. `return_`'s value-propagation / block short-circuit (relevant once function calls are modelled) is likewise deferred. Both are flagged in the roadmap. ## Verification - `lean docs/proofs/verification/WokeLang.lean` exits 0 (Lean 4.30.0, Mathlib-free, single-file). - Hole-free: new lemmas/theorems depend only on the classical kernel base (`propext`, `Classical.choice`, `Quot.sound`); `store_wellTyped_update` needs **no** axioms. No `sorryAx`. - **Purely additive (123 insertions, 0 deletions).** No existing proof touched. ## Scope `docs/proofs/verification/WokeLang.lean` (relations + lemmas + theorems + 2 smoke tests) and a Progress entry in `docs/proofs/VERIFICATION-ROADMAP.md`. No changes to the shipping implementation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_015oyMquf4daB6hMhmqB1wAL --- _Generated by [Claude Code](https://claude.ai/code/session_015oyMquf4daB6hMhmqB1wAL)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 01f7329 commit d71dfe9

2 files changed

Lines changed: 141 additions & 1 deletion

File tree

docs/proofs/VERIFICATION-ROADMAP.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,24 @@ unlock Phases 1c / 3a / 4a.
163163
corollary confirms it subsumes the closed theorem (empty context is vacuously store-typed).
164164
Hole-free (classical kernel base: `propext`, `Classical.choice`, `Quot.sound`). Purely
165165
additive — the merged `preservation`/`type_safety` are untouched.
166-
- [ ] Phase 1 (cont.: `[T-Call]` after 1b), 1b (statement-execution relation → stmt preservation), 1c — type-safety + operational metatheory.
166+
- [~] **Phase 1b (statement execution — simple fragment)** — a big-step execution relation
167+
`StmtExec`/`StmtsExec` (mutual) and its **store-typing preservation** for the simple
168+
statements (no embedded blocks): `complain`, `expr`, `varDecl`, `assign`, `return_`. Each
169+
evaluates its expression to a value via the closed-store `MultiStep` then applies its store
170+
effect; `stmt_exec_preservation` / `stmts_exec_preservation` show a well-typed statement/block
171+
run in a well-typed store yields a store well-typed against the statement's output context
172+
(`StmtWellTyped Γ s Γ'`). Supporting lemmas: `store_multiStep_preservation` (multi-step
173+
store-typed preservation) and `store_wellTyped_update` (overwriting an already-declared
174+
variable at its type — the `assign` analogue of `store_wellTyped_extend`). Two executable
175+
smoke tests (`let x = 0`; the block `let x = 0; x`). Hole-free (classical kernel base;
176+
`store_wellTyped_update` needs none). Purely additive.
177+
*Deferred to the next increment:* the control-flow forms `if`/`loop`/`attempt`/`consent`,
178+
which introduce **block scoping** in the flat `Env` model (a block-local `varDecl` shadowing
179+
an outer variable at a different type would break preservation against the outer context
180+
unless the store is restored on block exit). That store-restoration design is the open
181+
modelling decision for control-flow execution; `return_`'s value-propagation / block
182+
short-circuit (relevant once function calls are modelled) is likewise deferred.
183+
- [ ] Phase 1 (cont.: `[T-Call]` after 1b), 1b (control-flow execution + scoping), 1c — type-safety + operational metatheory.
167184
- [ ] Phase 2b, 2c — consent + capability state machines.
168185
- [ ] Phase 3a (+3b) — HM inference.
169186
- [ ] Phase 4a–4c — compiler / parser / WASM.

docs/proofs/verification/WokeLang.lean

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,129 @@ theorem preservation_via_store {e e' : Expr} {ρ ρ' : Env} {t : WokeType}
17781778
HasType emptyTypeEnv e' t :=
17791779
store_step_preservation (fun x t h => by simp [emptyTypeEnv] at h) ht hs
17801780

1781+
-- =========================================================================
1782+
-- 7e. Statement execution — simple-statement fragment (Phase 1b)
1783+
-- =========================================================================
1784+
1785+
/- A big-step statement-execution relation `StmtExec s ρ ρ'` ("statement `s`
1786+
run in store `ρ` produces store `ρ'`"), with `StmtsExec` threading a block
1787+
left-to-right. This increment covers the **simple** statements — those with no
1788+
embedded sub-blocks: `complain`, `expr`, `varDecl`, `assign`, `return_`. Each
1789+
evaluates its expression (if any) to a value via the closed-store `MultiStep`
1790+
(the store is invariant under expression evaluation, `step_store_invariant`),
1791+
then applies its store effect. `return_`'s value-propagation / block
1792+
short-circuit and the control-flow forms (`if`/`loop`/`attempt`/`consent`,
1793+
which introduce block scoping) are deliberately deferred to a later increment.
1794+
1795+
The metatheorem is **store-typing preservation**: a well-typed statement run in
1796+
a well-typed store yields a store well-typed against the statement's output
1797+
context (`StmtWellTyped Γ s Γ'`). -/
1798+
1799+
/-- Multi-step store-typed preservation: evaluating a well-typed expression to
1800+
completion in a well-typed store yields a value of the same type. The store is
1801+
unchanged throughout (`step_store_invariant`), so the one store typing carries. -/
1802+
theorem store_multiStep_preservation {Γ : TypeEnv} {e e' : Expr} {ρ ρ' : Env} {t : WokeType}
1803+
(hst : StoreWellTyped Γ ρ) (ht : HasType Γ e t) (hm : MultiStep e ρ e' ρ') :
1804+
HasType Γ e' t := by
1805+
induction hm generalizing t with
1806+
| refl => exact ht
1807+
| step e₁ e₂ e₃ ρ₁ ρ₂ ρ₃ hs hm' ih =>
1808+
have hρ : ρ₂ = ρ₁ := step_store_invariant hs
1809+
subst hρ
1810+
exact ih hst (store_step_preservation hst ht hs)
1811+
1812+
/-- **Store-update lemma.** Overwriting an *already-declared* variable with a
1813+
value of its declared type preserves store typing against the *same* context.
1814+
This is what an `assign` statement does to the runtime (cf. `store_wellTyped_extend`,
1815+
which a `varDecl` uses to *grow* the context). -/
1816+
theorem store_wellTyped_update {Γ : TypeEnv} {ρ : Env} {x : String} {t : WokeType}
1817+
{v : Value} (hst : StoreWellTyped Γ ρ) (hx : Γ x = some t)
1818+
(hv : HasType emptyTypeEnv (.lit v) t) :
1819+
StoreWellTyped Γ (extendEnv x v ρ) := by
1820+
intro y ty hy
1821+
by_cases hxy : (x == y) = true
1822+
· have hxy' : x = y := eq_of_beq hxy
1823+
subst hxy'
1824+
rw [hx] at hy; injection hy with hty; subst hty
1825+
exact ⟨v, by simp only [extendEnv]; rw [if_pos hxy], hv⟩
1826+
· obtain ⟨v', hv', hvt⟩ := hst y ty hy
1827+
exact ⟨v', by simp only [extendEnv]; rw [if_neg hxy]; exact hv', hvt⟩
1828+
1829+
mutual
1830+
/-- Big-step execution of a single (simple) statement. -/
1831+
inductive StmtExec : Stmt → Env → Env → Prop where
1832+
| complain : ∀ m ρ, StmtExec (.complain m) ρ ρ
1833+
| expr : ∀ e v ρ, MultiStep e ρ (.lit v) ρ → StmtExec (.expr e) ρ ρ
1834+
| varDecl : ∀ x e v ρ, MultiStep e ρ (.lit v) ρ →
1835+
StmtExec (.varDecl x e) ρ (extendEnv x v ρ)
1836+
| assign : ∀ x e v ρ, MultiStep e ρ (.lit v) ρ →
1837+
StmtExec (.assign x e) ρ (extendEnv x v ρ)
1838+
| return_ : ∀ e v ρ, MultiStep e ρ (.lit v) ρ → StmtExec (.return_ e) ρ ρ
1839+
/-- Big-step execution of a block, threading the store left-to-right. -/
1840+
inductive StmtsExec : List Stmt → Env → Env → Prop where
1841+
| nil : ∀ ρ, StmtsExec [] ρ ρ
1842+
| cons : ∀ s ss ρ ρ' ρ'',
1843+
StmtExec s ρ ρ' → StmtsExec ss ρ' ρ'' → StmtsExec (s :: ss) ρ ρ''
1844+
end
1845+
1846+
/-- **Statement-execution preservation (single, simple statement).** A well-typed
1847+
statement run in a well-typed store yields a store well-typed against the
1848+
statement's output context. `varDecl` uses `store_wellTyped_extend`, `assign`
1849+
uses `store_wellTyped_update`; the rest leave the store and context unchanged. -/
1850+
theorem stmt_exec_preservation {Γ Γ' : TypeEnv} {s : Stmt} {ρ ρ' : Env}
1851+
(hst : StoreWellTyped Γ ρ) (hw : StmtWellTyped Γ s Γ') (he : StmtExec s ρ ρ') :
1852+
StoreWellTyped Γ' ρ' := by
1853+
cases he with
1854+
| complain m ρ => cases hw with | complain _ _ => exact hst
1855+
| expr e v ρ hm => cases hw with | expr _ _ t _ => exact hst
1856+
| return_ e v ρ hm => cases hw with | return_ _ _ t _ => exact hst
1857+
| varDecl x e v ρ hm =>
1858+
cases hw with
1859+
| varDecl _ _ _ t hte =>
1860+
exact store_wellTyped_extend hst
1861+
(hasType_lit_any (store_multiStep_preservation hst hte hm))
1862+
| assign x e v ρ hm =>
1863+
cases hw with
1864+
| assign _ _ _ t hx hte =>
1865+
exact store_wellTyped_update hst hx
1866+
(hasType_lit_any (store_multiStep_preservation hst hte hm))
1867+
1868+
/-- **Statement-execution preservation (block of simple statements).** Threading
1869+
the single-statement preservation through the block. -/
1870+
theorem stmts_exec_preservation {Γ Γ' : TypeEnv} {ss : List Stmt} {ρ ρ' : Env}
1871+
(hst : StoreWellTyped Γ ρ) (hw : StmtsWellTyped Γ ss Γ') (he : StmtsExec ss ρ ρ') :
1872+
StoreWellTyped Γ' ρ' := by
1873+
induction ss generalizing Γ Γ' ρ ρ' with
1874+
| nil => cases hw; cases he; exact hst
1875+
| cons s rest ih =>
1876+
cases hw with
1877+
| cons _ _ _ Γ₁ _ hws hwss =>
1878+
cases he with
1879+
| cons _ _ _ ρ₁ _ hse hsse =>
1880+
exact ih (stmt_exec_preservation hst hws hse) hwss hsse
1881+
1882+
/-- Smoke test: `let x = 0` executes from the empty store, binding `x ↦ 0`. -/
1883+
example :
1884+
StmtExec (.varDecl "x" (.lit (.vInt 0))) emptyEnv (extendEnv "x" (.vInt 0) emptyEnv) :=
1885+
.varDecl "x" _ (.vInt 0) emptyEnv (.refl _ _)
1886+
1887+
/-- Smoke test: the block `let x = 0; x` runs from the empty store and stays
1888+
well-typed against the context it produces (`x : int`), via `stmts_exec_preservation`. -/
1889+
example :
1890+
StoreWellTyped (extendTypeEnv "x" .int emptyTypeEnv)
1891+
(extendEnv "x" (.vInt 0) emptyEnv) :=
1892+
stmts_exec_preservation store_wellTyped_empty
1893+
(.cons _ _ _ _ _
1894+
(.varDecl _ "x" (.lit (.vInt 0)) .int (.tInt _ _))
1895+
(.cons _ _ _ _ _ (.expr _ (.var "x") .int (.tVar _ "x" .int (by simp [extendTypeEnv])))
1896+
(.nil _)))
1897+
(.cons _ _ _ _ _
1898+
(.varDecl "x" (.lit (.vInt 0)) (.vInt 0) emptyEnv (.refl _ _))
1899+
(.cons _ _ _ _ _
1900+
(.expr (.var "x") (.vInt 0) (extendEnv "x" (.vInt 0) emptyEnv)
1901+
(.step _ _ _ _ _ _ (.sVar "x" _ (.vInt 0) (by simp [extendEnv])) (.refl _ _)))
1902+
(.nil _)))
1903+
17811904
-- =========================================================================
17821905
-- 8. TODO Stubs
17831906
-- =========================================================================

0 commit comments

Comments
 (0)