You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
9.3 KiB

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 ("" 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.