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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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.