|
|
|
|
From iris.algebra Require Import gmap auth agree gset coPset.
|
|
|
|
|
From iris.proofmode Require Import proofmode.
|
|
|
|
|
From iris.base_logic.lib Require Import wsat.
|
|
|
|
|
From semantics.pl.program_logic Require Export sequential_wp.
|
|
|
|
|
From iris.prelude Require Import options.
|
|
|
|
|
Import uPred.
|
|
|
|
|
|
|
|
|
|
(** This file contains the adequacy statements of the Iris program logic. First
|
|
|
|
|
we prove a number of auxilary results. *)
|
|
|
|
|
|
|
|
|
|
Section adequacy.
|
|
|
|
|
Context `{!irisGS Λ Σ}.
|
|
|
|
|
Implicit Types e : expr Λ.
|
|
|
|
|
Implicit Types P Q : iProp Σ.
|
|
|
|
|
Implicit Types Φ : val Λ → iProp Σ.
|
|
|
|
|
Implicit Types Φs : list (val Λ → iProp Σ).
|
|
|
|
|
|
|
|
|
|
Notation wptp s t Φs := ([∗ list] e;Φ ∈ t;Φs, wp' s ∅ e Φ)%I.
|
|
|
|
|
|
|
|
|
|
Lemma wp'_step s e1 σ1 e2 σ2 E κs efs Φ :
|
|
|
|
|
prim_step e1 σ1 κs e2 σ2 efs →
|
|
|
|
|
state_interp σ1 -∗ wp' s E e1 Φ
|
|
|
|
|
={E,∅}=∗ |={∅}▷=> |={∅, E}=>
|
|
|
|
|
state_interp σ2 ∗ wp' s E e2 Φ ∗ ⌜efs = []⌝ ∗ ⌜κs = []⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
rewrite wp'_unfold /wp_pre.
|
|
|
|
|
iIntros (?) "Hσ H".
|
|
|
|
|
rewrite (val_stuck e1 σ1 κs e2 σ2 efs) //.
|
|
|
|
|
iMod ("H" $! σ1 with "Hσ") as "(_ & H)". iSpecialize ("H" with "[//]").
|
|
|
|
|
iModIntro. iApply (step_fupd_wand with "[H]"); first by iApply "H".
|
|
|
|
|
iIntros ">(-> & -> & Hσ & H)". eauto with iFrame.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wptp_step s es1 es2 κ σ1 σ2 Φs :
|
|
|
|
|
step (es1,σ1) κ (es2, σ2) →
|
|
|
|
|
state_interp σ1 -∗ wptp s es1 Φs -∗
|
|
|
|
|
|={∅,∅}=> |={∅}▷=> |={∅,∅}=>
|
|
|
|
|
state_interp σ2 ∗
|
|
|
|
|
wptp s es2 Φs ∗
|
|
|
|
|
⌜κ= []⌝ ∗
|
|
|
|
|
⌜length es1 = length es2⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros (Hstep) "Hσ Ht".
|
|
|
|
|
destruct Hstep as [e1' σ1' e2' σ2' efs t2' t3 Hstep]; simplify_eq/=.
|
|
|
|
|
iDestruct (big_sepL2_app_inv_l with "Ht") as (Φs1 Φs2 ->) "[? Ht]".
|
|
|
|
|
iDestruct (big_sepL2_cons_inv_l with "Ht") as (Φ Φs3 ->) "[Ht ?]".
|
|
|
|
|
iMod (wp'_step with "Hσ Ht") as "H"; first done. iModIntro.
|
|
|
|
|
iApply (step_fupd_wand with "H"). iIntros ">($ & He2 & -> & ->) !>".
|
|
|
|
|
rewrite !app_nil_r; iFrame.
|
|
|
|
|
iPureIntro; split; first done.
|
|
|
|
|
rewrite !app_length; simpl; lia.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wptp_steps s n es1 es2 κs σ1 σ2 Φs :
|
|
|
|
|
nsteps n (es1, σ1) κs (es2, σ2) →
|
|
|
|
|
state_interp σ1 -∗ wptp s es1 Φs
|
|
|
|
|
={∅,∅}=∗ |={∅}▷=>^n |={∅,∅}=>
|
|
|
|
|
state_interp σ2 ∗
|
|
|
|
|
wptp s es2 Φs ∗
|
|
|
|
|
⌜κs= []⌝ ∗
|
|
|
|
|
⌜length es1 = length es2⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
revert es1 es2 κs σ1 σ2 Φs.
|
|
|
|
|
induction n as [|n IH]=> es1 es2 κs σ1 σ2 Φs /=.
|
|
|
|
|
{ inversion_clear 1; iIntros "? ?". iFrame. done. }
|
|
|
|
|
iIntros (Hsteps) "Hσ He". inversion_clear Hsteps as [|?? [t1' σ1']].
|
|
|
|
|
iDestruct (wptp_step with "Hσ He") as ">H"; first eauto; simplify_eq.
|
|
|
|
|
iModIntro. iApply step_fupd_fupd. iApply (step_fupd_wand with "H").
|
|
|
|
|
iIntros ">(Hσ & He & -> & %)". iMod (IH with "Hσ He") as "IH"; first done. iModIntro.
|
|
|
|
|
iApply (step_fupdN_wand with "IH"). iIntros ">IH".
|
|
|
|
|
iDestruct "IH" as "(? & ? & -> & %)".
|
|
|
|
|
iFrame. iPureIntro. split; first done. lia.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wp_not_stuck e σ E Φ :
|
|
|
|
|
state_interp σ -∗ wp' NotStuck E e Φ ={E}=∗ ⌜not_stuck e σ⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
rewrite wp'_unfold /wp_pre /not_stuck. iIntros "Hσ H".
|
|
|
|
|
destruct (to_val e) as [v|] eqn:?; first by eauto.
|
|
|
|
|
iSpecialize ("H" $! σ with "Hσ"). rewrite sep_elim_l.
|
|
|
|
|
iMod (fupd_plain_mask with "H") as %?; eauto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma wptp_strong_adequacy Φs s n es1 es2 κs σ1 σ2 :
|
|
|
|
|
nsteps n (es1, σ1) κs (es2, σ2) →
|
|
|
|
|
state_interp σ1 -∗ wptp s es1 Φs
|
|
|
|
|
={∅,∅}=∗ |={∅}▷=>^n |={∅,∅}=>
|
|
|
|
|
⌜ ∀ e2, s = NotStuck → e2 ∈ es2 → not_stuck e2 σ2 ⌝ ∗
|
|
|
|
|
state_interp σ2 ∗
|
|
|
|
|
([∗ list] e;Φ ∈ es2;Φs, from_option Φ True (to_val e)) ∗
|
|
|
|
|
⌜length es1 = length es2⌝ ∗
|
|
|
|
|
⌜κs = []⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
iIntros (Hstep) "Hσ He". iMod (wptp_steps with "Hσ He") as "Hwp"; first done.
|
|
|
|
|
iModIntro. iApply (step_fupdN_wand with "Hwp").
|
|
|
|
|
iMod 1 as "(Hσ & Ht & $ & $)"; simplify_eq/=.
|
|
|
|
|
iMod (fupd_plain_keep_l ∅
|
|
|
|
|
⌜ ∀ e2, s = NotStuck → e2 ∈ es2 → not_stuck e2 σ2 ⌝%I
|
|
|
|
|
(state_interp σ2 ∗
|
|
|
|
|
wptp s es2 (Φs))%I
|
|
|
|
|
with "[$Hσ $Ht]") as "(%&Hσ&Hwp)".
|
|
|
|
|
{ iIntros "(Hσ & Ht)" (e' -> He').
|
|
|
|
|
move: He' => /(elem_of_list_split _ _)[?[?->]].
|
|
|
|
|
iDestruct (big_sepL2_app_inv_l with "Ht") as (Φs1 Φs2 ?) "[? Hwp]".
|
|
|
|
|
iDestruct (big_sepL2_cons_inv_l with "Hwp") as (Φ Φs3 ->) "[Hwp ?]".
|
|
|
|
|
iMod (wp_not_stuck with "Hσ Hwp") as "$"; auto. }
|
|
|
|
|
iSplitR; first done. iFrame "Hσ".
|
|
|
|
|
iApply big_sepL2_fupd.
|
|
|
|
|
iApply (big_sepL2_impl with "Hwp").
|
|
|
|
|
iIntros "!#" (? e Φ ??) "Hwp".
|
|
|
|
|
destruct (to_val e) as [v2|] eqn:He2'; last done.
|
|
|
|
|
apply of_to_val in He2' as <-. simpl. iApply wp'_value_fupd'. done.
|
|
|
|
|
Qed.
|
|
|
|
|
End adequacy.
|
|
|
|
|
|
|
|
|
|
(** Iris's generic adequacy result *)
|
|
|
|
|
Theorem wp_strong_adequacy Σ Λ `{!invGpreS Σ} e σ1 n κs t2 σ2 φ :
|
|
|
|
|
(∀ `{Hinv : !invGS_gen HasNoLc Σ},
|
|
|
|
|
⊢ |={⊤}=> ∃
|
|
|
|
|
(s: stuckness)
|
|
|
|
|
(stateI : state Λ → iProp Σ)
|
|
|
|
|
(Φ : (val Λ → iProp Σ)),
|
|
|
|
|
let _ : irisGS Λ Σ := IrisG _ _ Hinv stateI
|
|
|
|
|
in
|
|
|
|
|
stateI σ1 ∗
|
|
|
|
|
(WP e @ s; ⊤ {{ Φ }}) ∗
|
|
|
|
|
(∀ e',
|
|
|
|
|
(* there will only be a single thread *)
|
|
|
|
|
⌜ t2 = [e'] ⌝ -∗
|
|
|
|
|
(* If this is a stuck-free triple (i.e. [s = NotStuck]), then the thread is not stuck *)
|
|
|
|
|
⌜ s = NotStuck → not_stuck e' σ2 ⌝ -∗
|
|
|
|
|
(* The state interpretation holds for [σ2] *)
|
|
|
|
|
stateI σ2 -∗
|
|
|
|
|
(* If the thread is done, the post-condition [Φ] holds.
|
|
|
|
|
Additionally, we can establish that all invariants will hold in this case.
|
|
|
|
|
*)
|
|
|
|
|
(from_option (λ v, |={∅,⊤}=> Φ v) True (to_val e')) -∗
|
|
|
|
|
(* Under all these assumptions, we can conclude [φ] in the logic.
|
|
|
|
|
In the case that the thread is done, we can use the last assumption to
|
|
|
|
|
establish that all invariants hold.
|
|
|
|
|
After opening all required invariants, one can use [fupd_mask_subseteq] to introduce the fancy update. *)
|
|
|
|
|
|={∅,∅}=> ⌜ φ ⌝)) →
|
|
|
|
|
nsteps n ([e], σ1) κs (t2, σ2) →
|
|
|
|
|
(* Then we can conclude [φ] at the meta-level. *)
|
|
|
|
|
φ.
|
|
|
|
|
Proof.
|
|
|
|
|
intros Hwp ?.
|
|
|
|
|
eapply pure_soundness.
|
|
|
|
|
apply (step_fupdN_soundness_no_lc _ n 0)=> Hinv.
|
|
|
|
|
iIntros "_".
|
|
|
|
|
iMod Hwp as (s stateI Φ) "(Hσ & Hwp & Hφ)".
|
|
|
|
|
rewrite /wp swp_eq /swp_def. iMod "Hwp".
|
|
|
|
|
iMod (@wptp_strong_adequacy _ _ (IrisG _ _ Hinv stateI) [_]
|
|
|
|
|
with "[Hσ] [Hwp]") as "H";[ done | done | | ].
|
|
|
|
|
{ by iApply big_sepL2_singleton. }
|
|
|
|
|
iAssert (|={∅}▷=>^n |={∅}=> ⌜φ⌝)%I
|
|
|
|
|
with "[-]" as "H"; last first.
|
|
|
|
|
{ destruct n as [ | n ]; first done. iModIntro. by iApply step_fupdN_S_fupd. }
|
|
|
|
|
iApply (step_fupdN_wand with "H").
|
|
|
|
|
iMod 1 as "(%Hns & Hσ & Hval & %Hlen & ->) /=".
|
|
|
|
|
destruct t2 as [ | e' []]; simpl in Hlen; [lia | | lia].
|
|
|
|
|
rewrite big_sepL2_singleton.
|
|
|
|
|
iApply ("Hφ" with "[//] [%] Hσ Hval").
|
|
|
|
|
intros ->. apply Hns; first done. by rewrite elem_of_list_singleton.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** Since the full adequacy statement is quite a mouthful, we prove some more
|
|
|
|
|
intuitive and simpler corollaries. These lemmas are morover stated in terms of
|
|
|
|
|
[rtc erased_step] so one does not have to provide the trace. *)
|
|
|
|
|
Record adequate {Λ} (s : stuckness) (e1 : expr Λ) (σ1 : state Λ)
|
|
|
|
|
(φ : val Λ → state Λ → Prop) := {
|
|
|
|
|
adequate_result t2 σ2 v2 :
|
|
|
|
|
rtc erased_step ([e1], σ1) (of_val v2 :: t2, σ2) → φ v2 σ2;
|
|
|
|
|
adequate_not_stuck t2 σ2 e2 :
|
|
|
|
|
s = NotStuck →
|
|
|
|
|
rtc erased_step ([e1], σ1) (t2, σ2) →
|
|
|
|
|
e2 ∈ t2 → not_stuck e2 σ2
|
|
|
|
|
}.
|
|
|
|
|
|
|
|
|
|
Lemma adequate_alt {Λ} s e1 σ1 (φ : val Λ → state Λ → Prop) :
|
|
|
|
|
adequate s e1 σ1 φ ↔ ∀ t2 σ2,
|
|
|
|
|
rtc erased_step ([e1], σ1) (t2, σ2) →
|
|
|
|
|
(∀ v2 t2', t2 = of_val v2 :: t2' → φ v2 σ2) ∧
|
|
|
|
|
(∀ e2, s = NotStuck → e2 ∈ t2 → not_stuck e2 σ2).
|
|
|
|
|
Proof.
|
|
|
|
|
split.
|
|
|
|
|
- intros []; naive_solver.
|
|
|
|
|
- constructor; naive_solver.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Theorem adequate_tp_safe {Λ} (e1 : expr Λ) t2 σ1 σ2 φ :
|
|
|
|
|
adequate NotStuck e1 σ1 φ →
|
|
|
|
|
rtc erased_step ([e1], σ1) (t2, σ2) →
|
|
|
|
|
Forall (λ e, is_Some (to_val e)) t2 ∨ ∃ t3 σ3, erased_step (t2, σ2) (t3, σ3).
|
|
|
|
|
Proof.
|
|
|
|
|
intros Had ?.
|
|
|
|
|
destruct (decide (Forall (λ e, is_Some (to_val e)) t2)) as [|Ht2]; [by left|].
|
|
|
|
|
apply (not_Forall_Exists _), Exists_exists in Ht2; destruct Ht2 as (e2&?&He2).
|
|
|
|
|
destruct (adequate_not_stuck NotStuck e1 σ1 φ Had t2 σ2 e2) as [?|(κ&e3&σ3&efs&?)];
|
|
|
|
|
rewrite ?eq_None_not_Some; auto.
|
|
|
|
|
{ exfalso. eauto. }
|
|
|
|
|
destruct (elem_of_list_split t2 e2) as (t2'&t2''&->); auto.
|
|
|
|
|
right; exists (t2' ++ e3 :: t2'' ++ efs), σ3, κ; econstructor; eauto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Corollary wp_adequacy Σ Λ `{!invGpreS Σ} s e σ φ :
|
|
|
|
|
(∀ `{Hinv : !invGS_gen HasNoLc Σ},
|
|
|
|
|
⊢ |={⊤}=> ∃ (stateI : state Λ → iProp Σ),
|
|
|
|
|
let _ : irisGS Λ Σ := IrisG _ _ Hinv stateI
|
|
|
|
|
in
|
|
|
|
|
stateI σ ∗ WP e @ s; ⊤ {{ v, ⌜φ v⌝ }}) →
|
|
|
|
|
adequate s e σ (λ v _, φ v).
|
|
|
|
|
Proof.
|
|
|
|
|
intros Hwp. apply adequate_alt; intros t2 σ2 [n [κs ?]]%erased_steps_nsteps.
|
|
|
|
|
eapply (wp_strong_adequacy Σ _); [|done]=> ?.
|
|
|
|
|
iMod Hwp as (stateI) "[Hσ Hwp]".
|
|
|
|
|
iExists s, stateI, (λ v, ⌜φ v⌝%I) => /=.
|
|
|
|
|
iIntros "{$Hσ $Hwp} !>" (e2 ->) "% H Hv".
|
|
|
|
|
destruct (to_val e2) as [ v2 | ] eqn:Hv.
|
|
|
|
|
- simpl. iMod "Hv" as "%". iApply fupd_mask_intro_discard; [done|].
|
|
|
|
|
iSplit; iPureIntro.
|
|
|
|
|
+ intros ??. destruct t2'; last done. intros [= ->].
|
|
|
|
|
rewrite to_of_val in Hv. injection Hv as ->. done.
|
|
|
|
|
+ intros ? ?. rewrite elem_of_list_singleton. naive_solver.
|
|
|
|
|
- iModIntro. iSplit; iPureIntro.
|
|
|
|
|
+ intros ??. destruct t2'; last done. intros [= ->].
|
|
|
|
|
rewrite to_of_val in Hv. done.
|
|
|
|
|
+ intros ? ?. rewrite elem_of_list_singleton. naive_solver.
|
|
|
|
|
Qed.
|