|
|
|
|
(** This file proves the basic laws of the HeapLang program logic by applying
|
|
|
|
|
the Iris lifting lemmas. *)
|
|
|
|
|
|
|
|
|
|
From iris.proofmode Require Import proofmode.
|
|
|
|
|
From iris.bi.lib Require Import fractional.
|
|
|
|
|
From iris.base_logic.lib Require Export gen_heap.
|
|
|
|
|
From semantics.pl.program_logic Require Export sequential_wp.
|
|
|
|
|
From semantics.pl.program_logic Require Import ectx_lifting.
|
|
|
|
|
From iris.heap_lang Require Export class_instances.
|
|
|
|
|
From iris.heap_lang Require Import tactics notation.
|
|
|
|
|
From semantics.pl.program_logic Require Export notation.
|
|
|
|
|
From iris.prelude Require Import options.
|
|
|
|
|
|
|
|
|
|
Class heapGS Σ := HeapGS {
|
|
|
|
|
heapGS_invGS : invGS_gen HasNoLc Σ;
|
|
|
|
|
heapGS_gen_heapGS : gen_heapGS loc (option val) Σ;
|
|
|
|
|
}.
|
|
|
|
|
#[export] Existing Instance heapGS_gen_heapGS.
|
|
|
|
|
|
|
|
|
|
Global Instance heapGS_irisGS `{!heapGS Σ} : irisGS heap_lang Σ := {
|
|
|
|
|
iris_invGS := heapGS_invGS;
|
|
|
|
|
state_interp σ := (gen_heap_interp σ.(heap))%I;
|
|
|
|
|
}.
|
|
|
|
|
|
|
|
|
|
(** Since we use an [option val] instance of [gen_heap], we need to overwrite
|
|
|
|
|
the notations. That also helps for scopes and coercions. *)
|
|
|
|
|
(** FIXME: Refactor these notations using custom entries once Coq bug #13654
|
|
|
|
|
has been fixed. *)
|
|
|
|
|
Notation "l ↦{ dq } v" := (mapsto (L:=loc) (V:=option val) l dq (Some v%V))
|
|
|
|
|
(at level 20, format "l ↦{ dq } v") : bi_scope.
|
|
|
|
|
Notation "l ↦□ v" := (mapsto (L:=loc) (V:=option val) l DfracDiscarded (Some v%V))
|
|
|
|
|
(at level 20, format "l ↦□ v") : bi_scope.
|
|
|
|
|
Notation "l ↦{# q } v" := (mapsto (L:=loc) (V:=option val) l (DfracOwn q) (Some v%V))
|
|
|
|
|
(at level 20, format "l ↦{# q } v") : bi_scope.
|
|
|
|
|
Notation "l ↦ v" := (mapsto (L:=loc) (V:=option val) l (DfracOwn 1) (Some v%V))
|
|
|
|
|
(at level 20, format "l ↦ v") : bi_scope.
|
|
|
|
|
|
|
|
|
|
Section lifting.
|
|
|
|
|
Context `{!heapGS Σ}.
|
|
|
|
|
Implicit Types P Q : iProp Σ.
|
|
|
|
|
Implicit Types Φ Ψ : val → iProp Σ.
|
|
|
|
|
Implicit Types efs : list expr.
|
|
|
|
|
Implicit Types σ : state.
|
|
|
|
|
Implicit Types v : val.
|
|
|
|
|
Implicit Types l : loc.
|
|
|
|
|
|
|
|
|
|
(** Recursive functions: we do not use this lemmas as it is easier to use Löb
|
|
|
|
|
induction directly, but this demonstrates that we can state the expected
|
|
|
|
|
reasoning principle for recursive functions, without any visible ▷. *)
|
|
|
|
|
Lemma wp_rec_löb s E1 E2 f x e Φ Ψ :
|
|
|
|
|
□ ( □ (∀ v, Ψ v -∗ WP (rec: f x := e)%V v @ s; E1; E2 {{ Φ }}) -∗
|
|
|
|
|
∀ v, Ψ v -∗ WP (subst' x v (subst' f (rec: f x := e) e)) @ s; E1; E2 {{ Φ }}) -∗
|
|
|
|
|
∀ v, Ψ v -∗ WP (rec: f x := e)%V v @ s; E1; E2 {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros "#Hrec". iLöb as "IH". iIntros (v) "HΨ".
|
|
|
|
|
iApply lifting.wp_pure_step_later; first done.
|
|
|
|
|
iNext. iApply ("Hrec" with "[] HΨ"). iIntros "!>" (w) "HΨ".
|
|
|
|
|
iApply ("IH" with "HΨ").
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** Heap *)
|
|
|
|
|
|
|
|
|
|
(** We need to adjust the [gen_heap] and [gen_inv_heap] lemmas because of our
|
|
|
|
|
value type being [option val]. *)
|
|
|
|
|
|
|
|
|
|
Lemma mapsto_valid l dq v : l ↦{dq} v -∗ ⌜✓ dq⌝.
|
|
|
|
|
Proof. apply mapsto_valid. Qed.
|
|
|
|
|
Lemma mapsto_valid_2 l dq1 dq2 v1 v2 :
|
|
|
|
|
l ↦{dq1} v1 -∗ l ↦{dq2} v2 -∗ ⌜✓ (dq1 ⋅ dq2) ∧ v1 = v2⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros "H1 H2".
|
|
|
|
|
iDestruct (mapsto_valid_2 with "H1 H2") as %[? [=]]. done.
|
|
|
|
|
Qed.
|
|
|
|
|
Lemma mapsto_agree l dq1 dq2 v1 v2 : l ↦{dq1} v1 -∗ l ↦{dq2} v2 -∗ ⌜v1 = v2⌝.
|
|
|
|
|
Proof. iIntros "H1 H2". iDestruct (mapsto_agree with "H1 H2") as %[=]. done. Qed.
|
|
|
|
|
|
|
|
|
|
Lemma mapsto_combine l dq1 dq2 v1 v2 :
|
|
|
|
|
l ↦{dq1} v1 -∗ l ↦{dq2} v2 -∗ l ↦{dq1 ⋅ dq2} v1 ∗ ⌜v1 = v2⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros "Hl1 Hl2". iDestruct (mapsto_combine with "Hl1 Hl2") as "[$ Heq]".
|
|
|
|
|
by iDestruct "Heq" as %[= ->].
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma mapsto_frac_ne l1 l2 dq1 dq2 v1 v2 :
|
|
|
|
|
¬ ✓(dq1 ⋅ dq2) → l1 ↦{dq1} v1 -∗ l2 ↦{dq2} v2 -∗ ⌜l1 ≠ l2⌝.
|
|
|
|
|
Proof. apply mapsto_frac_ne. Qed.
|
|
|
|
|
Lemma mapsto_ne l1 l2 dq2 v1 v2 : l1 ↦ v1 -∗ l2 ↦{dq2} v2 -∗ ⌜l1 ≠ l2⌝.
|
|
|
|
|
Proof. apply mapsto_ne. Qed.
|
|
|
|
|
|
|
|
|
|
Lemma mapsto_persist l dq v : l ↦{dq} v ==∗ l ↦□ v.
|
|
|
|
|
Proof. apply mapsto_persist. Qed.
|
|
|
|
|
|
|
|
|
|
Lemma heap_array_to_seq_mapsto l v (n : nat) :
|
|
|
|
|
([∗ map] l' ↦ ov ∈ heap_array l (replicate n v), gen_heap.mapsto l' (DfracOwn 1) ov) -∗
|
|
|
|
|
[∗ list] i ∈ seq 0 n, (l +ₗ (i : nat)) ↦ v.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros "Hvs". iInduction n as [|n] "IH" forall (l); simpl.
|
|
|
|
|
{ done. }
|
|
|
|
|
rewrite big_opM_union; last first.
|
|
|
|
|
{ apply map_disjoint_spec=> l' v1 v2 /lookup_singleton_Some [-> _].
|
|
|
|
|
intros (j&w&?&Hjl&_)%heap_array_lookup.
|
|
|
|
|
rewrite Loc.add_assoc -{1}[l']Loc.add_0 in Hjl. simplify_eq; lia. }
|
|
|
|
|
rewrite Loc.add_0 -fmap_S_seq big_sepL_fmap.
|
|
|
|
|
setoid_rewrite Nat2Z.inj_succ. setoid_rewrite <-Z.add_1_l.
|
|
|
|
|
setoid_rewrite <-Loc.add_assoc.
|
|
|
|
|
rewrite big_opM_singleton; iDestruct "Hvs" as "[$ Hvs]". by iApply "IH".
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_allocN_seq s E v n Φ :
|
|
|
|
|
(0 < n)%Z →
|
|
|
|
|
▷ (∀ l, ([∗ list] i ∈ seq 0 (Z.to_nat n), (l +ₗ (i : nat)) ↦ v) -∗ Φ (LitV $ LitLoc l)) -∗
|
|
|
|
|
WP AllocN (Val $ LitV $ LitInt $ n) (Val v) @ s; E; E {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros (Hn) "HΦ".
|
|
|
|
|
iApply wp_lift_head_step_fupd_nomask; first done.
|
|
|
|
|
iIntros (σ1) "Hσ !>"; iSplit; first by destruct n; auto with lia head_step.
|
|
|
|
|
iIntros (e2 σ2 κ efs Hstep); inv_head_step.
|
|
|
|
|
iMod (gen_heap_alloc_big _ (heap_array _ (replicate (Z.to_nat n) v)) with "Hσ")
|
|
|
|
|
as "(Hσ & Hl & Hm)".
|
|
|
|
|
{ apply heap_array_map_disjoint.
|
|
|
|
|
rewrite replicate_length Z2Nat.id; auto with lia. }
|
|
|
|
|
iApply step_fupd_intro; first done.
|
|
|
|
|
iModIntro. iFrame "Hσ". do 2 (iSplit; first done).
|
|
|
|
|
iApply wp_value_fupd. iApply "HΦ".
|
|
|
|
|
by iApply heap_array_to_seq_mapsto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_alloc s E v Φ :
|
|
|
|
|
▷ (∀ l, l ↦ v -∗ Φ (LitV $ LitLoc l)) -∗
|
|
|
|
|
WP Alloc (Val v) @ s; E; E {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros "HΦ". iApply wp_allocN_seq; [auto with lia..|].
|
|
|
|
|
iIntros "!>" (l) "/= (? & _)". rewrite Loc.add_0. iApply "HΦ"; iFrame.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_free s E l v Φ :
|
|
|
|
|
▷ l ↦ v -∗
|
|
|
|
|
(▷ Φ (LitV LitUnit)) -∗
|
|
|
|
|
WP Free (Val $ LitV $ LitLoc l) @ s; E; E {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros ">Hl HΦ". iApply wp_lift_head_step_fupd_nomask; first done.
|
|
|
|
|
iIntros (σ1) "Hσ !>". iDestruct (gen_heap_valid with "Hσ Hl") as %?.
|
|
|
|
|
iSplit; first by eauto with head_step.
|
|
|
|
|
iIntros (e2 σ2 κ efs Hstep); inv_head_step.
|
|
|
|
|
iMod (gen_heap_update with "Hσ Hl") as "[$ Hl]".
|
|
|
|
|
iIntros "!>!>!>". iSplit; first done. iSplit; first done.
|
|
|
|
|
iApply wp_value. by iApply "HΦ".
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_load s E l dq v Φ :
|
|
|
|
|
▷ l ↦{dq} v -∗
|
|
|
|
|
▷ (l ↦{dq} v -∗ Φ v) -∗
|
|
|
|
|
WP Load (Val $ LitV $ LitLoc l) @ s; E; E {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros ">Hl HΦ". iApply wp_lift_head_step_fupd_nomask; first done.
|
|
|
|
|
iIntros (σ1) "Hσ !>". iDestruct (gen_heap_valid with "Hσ Hl") as %?.
|
|
|
|
|
iSplit; first by eauto with head_step.
|
|
|
|
|
iIntros (e2 σ2 κ efs Hstep); inv_head_step.
|
|
|
|
|
iApply step_fupd_intro; first done. iNext. iFrame.
|
|
|
|
|
iSplitR; first done. iSplitR; first done. iApply wp_value. by iApply "HΦ".
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_store s E l v' v Φ :
|
|
|
|
|
▷ l ↦ v' -∗
|
|
|
|
|
▷ (l ↦ v -∗ Φ (LitV LitUnit)) -∗
|
|
|
|
|
WP Store (Val $ LitV $ LitLoc l) (Val v) @ s; E; E {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros ">Hl HΦ". iApply wp_lift_head_step_fupd_nomask; first done.
|
|
|
|
|
iIntros (σ1) "Hσ !>". iDestruct (gen_heap_valid with "Hσ Hl") as %?.
|
|
|
|
|
iSplit; first by eauto with head_step.
|
|
|
|
|
iIntros (e2 σ2 κ efs Hstep); inv_head_step.
|
|
|
|
|
iMod (gen_heap_update with "Hσ Hl") as "[$ Hl]".
|
|
|
|
|
iApply step_fupd_intro; first done. iNext.
|
|
|
|
|
iSplit; first done. iSplit; first done.
|
|
|
|
|
iApply wp_value. by iApply "HΦ".
|
|
|
|
|
Qed.
|
|
|
|
|
End lifting.
|