5.3. Resources
In this section, we introduce our first notion of a resource: the
resource of heaps. As mentioned in the basics chapter, propositions
in Iris describe / assert ownership of resources. To describe
resources in the resource of heaps, we use the points-to
predicate, written l ↦ some v. (The Rocq tutorial writes l ↦ v;
the Lean port carries an Option because the model also tracks
deallocated locations.) Intuitively, l ↦ some v describes all
heap fragments that have value v stored at location l. The
proposition
l1 ↦ some hl_val(#1) ∗ l2 ↦ some hl_val(#2)
then describes all heap fragments that map l1 to 1 and l2 to
2.
The Rocq tutorial's running example for this section is
let: "x" := ref #1 in "x" <- !"x" + #2 ;; !"x"
which both touches the heap and performs an addition. We can
state and partly proved it in iris-lean, but the addition step is
blocked by the same PureExec gap as above; see the per-step
breakdown below.
def prog : Exp := hl(
let x := ref(#1);
x ← !x + #2;
!x)
-- TODO (upstream — iris-lean): the addition `!x + #2` blocks the
-- proof. The `wp_alloc`/`wp_load`/`wp_store` rules apply fine; the
-- missing piece is reducing `(#1 : Int) + (#2 : Int)` via
-- `wp_pure`. Until `PureExec` for `+` lands, `prog_spec` cannot be
-- proved cleanly.
-- Rocq tutorial reference:
-- Lemma prog_spec : ⊢ WP prog {{ v, ⌜v = #3⌝ }}.
-- Proof.
-- rewrite /prog.
-- wp_alloc l as "Hl".
-- wp_let. wp_load. wp_op. wp_store. wp_load.
-- iModIntro. done.
-- Qed.
To at least demonstrate the heap primitives in isolation, here is a trivial program that allocates and then immediately reads.
def writeread : Exp := hl(
let x := ref(#7);
!x)
theorem writeread_spec :
⊢@{IProp GF} WP writeread {{ v, ⌜v = hl_val(#7)⌝ }} := hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GF⊢ ⊢ WP writeread {{ v, ⌜v = hl_val(#7)⌝ }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GF⊢ ⊢ WP hl(let x := ref(#7); !x) {{ v, ⌜v = hl_val(#7)⌝ }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GF⊢
⊢ WP hl(ref(#7)) {{ v, WP hl(let x := v(&v); !x) {{ v, ⌜v = hl_val(#7)⌝ }} }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GF⊢
⊢ ▷ ∀ l, l ↦ some hl_val(#7) -∗ WP hl(let x := #l; !x) {{ v, ⌜v = hl_val(#7)⌝ }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GFl:Loc⊢
∗Hl : l ↦ some hl_val(#7)
⊢ WP hl(let x := #l; !x) {{ v, ⌜v = hl_val(#7)⌝ }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GFl:Loc⊢
∗Hl : l ↦ some hl_val(#7)
⊢ WP hl(!#l) {{ v, ⌜v = hl_val(#7)⌝ }}
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GFl:Loc⊢
⊢ ▷ (l ↦ some hl_val(#7) -∗ ⌜hl_val(#7) = hl_val(#7)⌝)
hlc:HasLCGF:BundledGFunctorsinst✝:HeapLangGS hlc GFl:Loc⊢
∗_Hl : l ↦ some hl_val(#7)
⊢ ⌜hl_val(#7) = hl_val(#7)⌝
All goals completed! 🐙
Each iapply wp_alloc / iapply wp_load consumes the relevant
primitive law and the surrounding wp_pures advances past the
let β-reductions.
HeapLang also provides the cmpXchg(_, _, _) instruction. The
primitive-law lemmas wp_cmpXchg_fail and wp_cmpXchg_true cover
the two outcomes, with the choice between them dispatched by side
conditions on whether the stored value equals the test value.
-- TODO (upstream — iris-lean): port a `wp_cmpxchg` lemma (and a
-- matching tactic) that branches on the equality decision —
-- equivalent to the Rocq tutorial's `wp_cmpxchg as H1 | H2`. The
-- current iris-lean only ships the two outcome-specific lemmas
-- `wp_cmpXchg_fail` and `wp_cmpXchg_true`.
-- Rocq tutorial reference:
-- Example cmpXchg_0_to_10 (l : loc) : expr := (CmpXchg #l #0 #10).
-- Lemma cmpXchg_0_to_10_spec (l : loc) (v : val) :
-- l ↦ v -∗
-- WP (cmpXchg_0_to_10 l) {{ u, (⌜v = #0⌝ ∗ l ↦ #10) ∨
-- (⌜v ≠ #0⌝ ∗ l ↦ v) }}.
-- Proof.
-- iIntros "Hl". wp_cmpxchg as H1 | H2.
-- - iLeft. by iFrame.
-- - iRight. by iFrame.
-- Qed.
The points-to predicate is not duplicable. That is, for every
location l, there can only exist one full-fraction points-to
associated with it. iris-lean exposes this via the
HeapView-level disjointness lemmas; we omit the detailed proof.