Newer
Older
(** This file defines all of the semantic typing lemmas for term types. Most of
these lemmas are semantic versions of the syntactic typing judgments typically
found in a syntactic type system. *)
From iris.base_logic.lib Require Import invariants.
From iris.heap_lang Require Import metatheory.
From iris.heap_lang.lib Require Export spawn par assert.
From actris.logrel Require Export subtyping term_typing_judgment operators session_types.
From actris.logrel Require Import environments.
From actris.utils Require Import switch.
From actris.channel Require Import proofmode.
Section properties.
Context `{heapG Σ}.
Implicit Types A B : ltty Σ.
Implicit Types S T : lsty Σ.
Implicit Types Γ : gmap string (ltty Σ).
Lemma ltyped_frame Γ Γ' Γ1 Γ1' Γ2 e A :
env_split Γ Γ1 Γ2 -∗
env_split Γ' Γ1' Γ2 -∗
(Γ1 ⊨ e : A ⫤ Γ1') -∗
Γ ⊨ e : A ⫤ Γ'.
Proof.
iIntros "#Hsplit #Hsplit' #Htyped !>" (vs) "Henv".
iDestruct ("Hsplit" with "Henv") as "[Henv1 Henv2]".
iApply (wp_wand with "(Htyped Henv1)").
iIntros (v) "[$ Henv1']".
iApply "Hsplit'". iFrame "Henv1' Henv2".
Qed.
(** Variable properties *)
Lemma ltyped_var Γ (x : string) A :
Γ !! x = Some A → ⊢ Γ ⊨ x : A ⫤ <[x := (copy- A)%lty]> Γ.
Proof.
iDestruct (env_ltyped_lookup with "HΓ") as (v Hv) "[HA HΓ]"; first done; rewrite Hv.
iApply wp_value.
iAssert (ltty_car (copy- A) v)%lty as "#HAm". { iApply coreP_intro. iApply "HA". }
iFrame "HA".
iDestruct (env_ltyped_insert _ _ x with "HAm HΓ") as "HΓ".
rewrite /binder_insert insert_delete (insert_id _ _ _ Hv).
iApply "HΓ".
Qed.
(** Subtyping *)
Theorem ltyped_subsumption Γ Γ2 e τ1 τ2 :
τ1 <: τ2 -∗ (Γ ⊨ e : τ1 ⫤ Γ2) -∗ (Γ ⊨ e : τ2 ⫤ Γ2).
Proof.
iIntros "#Hle #Hltyped" (vs) "!> Henv".
iDestruct ("Hltyped" with "Henv") as "Hltyped'".
iApply (wp_wand with "Hltyped' [Hle]").
iIntros (v) "[H1 $]". by iApply "Hle".
Qed.
(** Basic properties *)
Lemma ltyped_unit Γ : ⊢ Γ ⊨ #() : ().
Proof. iIntros "!>" (vs) "HΓ /=". iApply wp_value. eauto. Qed.
Proof. iIntros "!>" (vs) "HΓ /=". iApply wp_value. eauto. Qed.
Proof. iIntros "!>" (vs) "HΓ /=". iApply wp_value. eauto. Qed.
(** Operations *)
Lemma ltyped_un_op Γ1 Γ2 op e A B :
LTyUnOp op A B →
(Γ1 ⊨ e : A ⫤ Γ2) -∗
Γ1 ⊨ UnOp op e : B ⫤ Γ2.
Proof.
iIntros (Hop) "#He !>". iIntros (vs) "HΓ1"=> /=.
wp_apply (wp_wand with "(He [HΓ1 //])"). iIntros (v1) "[HA HΓ2]".
iDestruct (Hop with "HA") as (w Heval) "HB".
wp_unop. iFrame.
Qed.
Lemma ltyped_bin_op Γ1 Γ2 Γ3 op e1 e2 A1 A2 B :
LTyBinOp op A1 A2 B →
(Γ1 ⊨ e2 : A2 ⫤ Γ2) -∗
(Γ2 ⊨ e1 : A1 ⫤ Γ3) -∗
Γ1 ⊨ BinOp op e1 e2 : B ⫤ Γ3.
Proof.
iIntros (Hop) "#He2 #He1 !>". iIntros (vs) "HΓ1"=> /=.
wp_apply (wp_wand with "(He2 [HΓ1 //])"). iIntros (v2) "[HA2 HΓ2]".
wp_apply (wp_wand with "(He1 [HΓ2 //])"). iIntros (v1) "[HA1 HΓ3]".
iDestruct (Hop with "HA1 HA2") as (w Heval) "HB".
wp_binop. iFrame.
Qed.
(** Conditionals *)
Lemma ltyped_if Γ1 Γ2 Γ3 e1 e2 e3 A :
(Γ1 ⊨ e1 : lty_bool ⫤ Γ2) -∗
(Γ2 ⊨ e2 : A ⫤ Γ3) -∗
(Γ2 ⊨ e3 : A ⫤ Γ3) -∗
Γ1 ⊨ (if: e1 then e2 else e3) : A ⫤ Γ3.
Proof.
iIntros "#He1 #He2 #He3 !>" (v) "HΓ1".
simpl.
wp_apply (wp_wand with "(He1 [HΓ1 //])"). iIntros (b) "[Hbool HΓ2]".
rewrite /lty_bool. iDestruct "Hbool" as ([]) "->".
- wp_apply (wp_wand with "(He2 [HΓ2 //])"). iIntros (w) "[HA HΓ3]". iFrame.
- wp_apply (wp_wand with "(He3 [HΓ2 //])"). iIntros (w) "[HA HΓ3]". iFrame.
Qed.
Lemma ltyped_app Γ1 Γ2 Γ3 e1 e2 A1 A2 :
(Γ2 ⊨ e1 : A1 ⊸ A2 ⫤ Γ3) -∗ (Γ1 ⊨ e2 : A1 ⫤ Γ2) -∗
Γ1 ⊨ e1 e2 : A2 ⫤ Γ3.
Proof.
iIntros "#H1 #H2". iIntros (vs) "!> HΓ /=".
wp_apply (wp_wand with "(H2 [HΓ //])"). iIntros (v) "[HA1 HΓ]".
wp_apply (wp_wand with "(H1 [HΓ //])"). iIntros (f) "[Hf HΓ]".
iApply wp_frame_r. iFrame "HΓ". iApply ("Hf" $! v with "HA1").
Qed.
Lemma ltyped_lam Γ Γ' x e A1 A2 :
Proof.
wp_pures. iSplitL; last by iApply env_ltyped_empty.
iIntros (v) "HA1". wp_pures.
iDestruct ("He" $!((binder_insert x v vs)) with "[HA1 HΓ]") as "He'".
{ iApply (env_ltyped_insert with "[HA1 //] HΓ"). }
iDestruct (wp_wand _ _ _ _ (ltty_car A2) with "He' []") as "He'".
destruct x as [|x]; rewrite /= -?subst_map_insert //.
Qed.
Lemma ltyped_rec Γ Γ' Γ'' f x e A1 A2 :
(<![f:=A1 → A2]!> $ <![x:=A1]!> Γ' ⊨ e : A2 ⫤ Γ'') -∗
Γ ⊨ (rec: f x := e) : A1 → A2 ⫤ ∅.
Proof.
iIntros "#Hcopy #He". iIntros (vs) "!> HΓ /=". iApply wp_fupd. wp_pures.
iDestruct ("Hcopy" with "HΓ") as "HΓ".
iMod (fupd_mask_mono with "HΓ") as "#HΓ"; first done.
iModIntro. iSplitL; last by iApply env_ltyped_empty.
iLöb as "IH".
iIntros (v) "!> HA1". wp_pures. set (r := RecV f x _).
iDestruct ("He" $! (<![f:=r]!> $ <![x:=v]!> vs) with "[HΓ HA1]") as "He'".
{ iApply (env_ltyped_insert with "IH").
iApply (env_ltyped_insert with "HA1 HΓ"). }
iDestruct (wp_wand _ _ _ _ (ltty_car A2) with "He' []") as "He'".
{ iIntros (w) "[$ _]". }
destruct x as [|x], f as [|f]; rewrite /= -?subst_map_insert //.
destruct (decide (x = f)) as [->|].
- by rewrite subst_subst delete_idemp !insert_insert -subst_map_insert.
- rewrite subst_subst_ne // -subst_map_insert.
by rewrite -delete_insert_ne // -subst_map_insert.
Qed.
Lemma ltyped_let Γ1 Γ2 Γ3 x e1 e2 A1 A2 :
(Γ1 ⊨ e1 : A1 ⫤ Γ2) -∗ (<![x:=A1]!> Γ2 ⊨ e2 : A2 ⫤ Γ3) -∗
Γ1 ⊨ (let: x:=e1 in e2) : A2 ⫤ binder_delete x Γ3.
Proof.
iIntros "#He1 #He2 !>". iIntros (vs) "HΓ1"=> /=.
wp_apply (wp_wand with "(He1 HΓ1)").
iIntros (v) "[HA1 HΓ2]".
wp_pures.
iDestruct (env_ltyped_insert _ _ x with "HA1 HΓ2") as "HΓ2".
iDestruct ("He2" with "HΓ2") as "He2'".
destruct x as [|x]; rewrite /= -?subst_map_insert //.
wp_apply (wp_wand with "He2'").
iIntros (w) "[HA2 HΓ3]".
iFrame.
iApply env_ltyped_delete=> //.
Qed.
(** Product properties *)
Lemma ltyped_pair Γ1 Γ2 Γ3 e1 e2 A1 A2 :
(Γ2 ⊨ e1 : A1 ⫤ Γ3) -∗ (Γ1 ⊨ e2 : A2 ⫤ Γ2) -∗
Γ1 ⊨ (e1,e2) : A1 * A2 ⫤ Γ3.
Proof.
iIntros "#H1 #H2". iIntros (vs) "!> HΓ /=".
wp_apply (wp_wand with "(H2 [HΓ //])"); iIntros (w2) "[HA2 HΓ]".
wp_apply (wp_wand with "(H1 [HΓ //])"); iIntros (w1) "[HA1 HΓ]".
wp_pures. iFrame "HΓ". iExists w1, w2. by iFrame.
Qed.
Lemma ltyped_fst Γ A1 A2 (x : string) :
Γ !! x = Some (A1 * A2)%lty →
⊢ Γ ⊨ Fst x : A1 ⫤ <[x := (copy- A1 * A2)%lty]> Γ.
Proof.
iIntros (Hx vs) "!> HΓ /=".
iDestruct (env_ltyped_lookup with "HΓ") as (v Hv) "[HA HΓ]"; first done; rewrite Hv.
iDestruct "HA" as (v1 v2 ->) "[HA1 HA2]".
wp_pures.
iAssert (ltty_car (copy- A1) v1)%lty as "#HA1m". { iApply coreP_intro. iApply "HA1". }
iFrame "HA1".
iAssert (ltty_car (copy- A1 * A2) (v1, v2))%lty with "[HA2]" as "HA".
{ iExists v1, v2. iSplit=>//. iFrame "HA1m HA2". }
iDestruct (env_ltyped_insert _ _ x with "HA HΓ") as "HΓ".
rewrite /binder_insert insert_delete (insert_id _ _ _ Hv).
iFrame "HΓ".
Qed.
Lemma ltyped_snd Γ A1 A2 (x : string) :
Γ !! x = Some (A1 * A2)%lty →
Proof.
iIntros (Hx vs) "!> HΓ /=".
iDestruct (env_ltyped_lookup with "HΓ") as (v Hv) "[HA HΓ]"; first done; rewrite Hv.
iDestruct "HA" as (v1 v2 ->) "[HA1 HA2]".
wp_pures.
iAssert (ltty_car (copy- A2) v2)%lty as "#HA2m". { iApply coreP_intro. iApply "HA2". }
iFrame "HA2".
iAssert (ltty_car (A1 * copy- A2) (v1, v2))%lty with "[HA1]" as "HA".
{ iExists v1, v2. iSplit=>//. iFrame "HA2m HA1". }
iDestruct (env_ltyped_insert _ _ x with "HA HΓ") as "HΓ".
rewrite /binder_insert insert_delete (insert_id _ _ _ Hv).
iFrame "HΓ".
Qed.
(** Sum Properties *)
Lemma ltyped_injl Γ e A1 A2 :
(Γ ⊨ e : A1) -∗ Γ ⊨ InjL e : A1 + A2.
Proof.
iIntros "#HA" (vs) "!> HΓ /=".
wp_apply (wp_wand with "(HA [HΓ //])").
iIntros (v) "[HA' $]". wp_pures.
iLeft. iExists v. auto.
Qed.
Lemma ltyped_injr Γ e A1 A2 :
(Γ ⊨ e : A2) -∗ Γ ⊨ InjR e : A1 + A2.
Proof.
iIntros "#HA" (vs) "!> HΓ /=".
wp_apply (wp_wand with "(HA [HΓ //])").
iIntros (v) "[HA' $]". wp_pures.
iRight. iExists v. auto.
Qed.
(* TODO: This probably requires there to be a rule that allows dropping arbitrary
resources from the postcondition. Check if there is such a rule. *)
Lemma ltyped_case Γ1 Γ2 Γ3 e1 e2 e3 A1 A2 B :
(Γ1 ⊨ e1 : A1 + A2 ⫤ Γ2) -∗
(Γ2 ⊨ e2 : A1 ⊸ B ⫤ Γ3) -∗
(Γ2 ⊨ e3 : A2 ⊸ B ⫤ Γ3) -∗
(Γ1 ⊨ Case e1 e2 e3 : B ⫤ Γ3).
Proof.
iIntros "#H1 #H2 #H3" (vs) "!> HΓ1 /=".
wp_bind (subst_map vs e1).
iSpecialize ("H1" with "HΓ1").
iApply (wp_wand with "H1"). iIntros (s) "[Hs HΓ2]".
iDestruct "Hs" as "[Hs|Hs]"; iDestruct "Hs" as (w ->) "HA"; wp_case.
- wp_bind (subst_map vs e2).
iApply (wp_wand with "(H2 HΓ2)"). iIntros (v) "[Hv HΓ3]".
iApply (wp_wand with "(Hv HA)"). iIntros (v') "HB".
iFrame "HΓ3 HB".
- wp_bind (subst_map vs e3).
iApply (wp_wand with "(H3 HΓ2)"). iIntros (v) "[Hv HΓ3]".
iApply (wp_wand with "(Hv HA)"). iIntros (v') "HB".
iFrame "HΓ3 HB".
Qed.
(** Universal Properties *)
Lemma ltyped_tlam Γ e k (C : lty Σ k → ltty Σ) :
(∀ M, Γ ⊨ e : C M ⫤ ∅) -∗ Γ ⊨ (λ: <>, e) : ∀ M, C M ⫤ ∅.
Proof.
iIntros "#He" (vs) "!> HΓ /=". wp_pures.
iSplitL; last by iApply env_ltyped_empty.
iIntros (M) "/=". wp_pures.
iApply (wp_wand with "(He HΓ)"). iIntros (v) "[$ _]".
Qed.
Lemma ltyped_tapp Γ Γ2 e k (C : lty Σ k → ltty Σ) M :
(Γ ⊨ e : ∀ M, C M ⫤ Γ2) -∗ Γ ⊨ e #() : C M ⫤ Γ2.
Proof.
wp_apply (wp_wand with "(He [HΓ //])"); iIntros (w) "[HB HΓ] /=".
iApply (wp_wand with "HB [HΓ]"). by iIntros (v) "$".
Qed.
(** Existential properties *)
Lemma ltyped_pack Γ e k (C : lty Σ k → ltty Σ) M :
(Γ ⊨ e : C M) -∗ Γ ⊨ e : ∃ M, C M.
Proof.
iIntros "#He" (vs) "!> HΓ /=".
wp_apply (wp_wand with "(He [HΓ //])"); iIntros (w) "[HB $]". by iExists M.
Qed.
Lemma ltyped_unpack {k} Γ1 Γ2 Γ3 x e1 e2 (C : lty Σ k → ltty Σ) B :
(Γ1 ⊨ e1 : ∃ M, C M ⫤ Γ2) -∗
(∀ Y, <![x:=C Y]!> Γ2 ⊨ e2 : B ⫤ Γ3) -∗
Γ1 ⊨ (let: x := e1 in e2) : B ⫤ binder_delete x Γ3.
Proof.
iIntros "#He1 #He2 !>". iIntros (vs) "HΓ1"=> /=.
wp_apply (wp_wand with "(He1 HΓ1)"); iIntros (v) "[HC HΓ2]".
iDestruct "HC" as (X) "HX". wp_pures.
iDestruct (env_ltyped_insert _ _ x with "HX HΓ2") as "HΓ2".
iDestruct ("He2" with "HΓ2") as "He2'".
destruct x as [|x]; rewrite /= -?subst_map_insert //.
wp_apply (wp_wand with "He2'").
iIntros (w) "[$ HΓ3]". by iApply env_ltyped_delete.
Lemma ltyped_alloc Γ1 Γ2 e A :
(Γ1 ⊨ e : A ⫤ Γ2) -∗
Proof.
iIntros "#He" (vs) "!> HΓ1 /=".
wp_bind (subst_map vs e).
iApply (wp_wand with "(He HΓ1)"). iIntros (v) "[Hv HΓ2]".
wp_alloc l as "Hl".
iFrame "HΓ2".
iExists l, v; iSplit=>//. iFrame "Hv Hl".
Qed.
Lemma ltyped_free Γ1 Γ2 e A :
(Γ1 ⊨ e : ref_uniq A ⫤ Γ2) -∗
(Γ1 ⊨ Free e : () ⫤ Γ2).
Proof.
iIntros "#He" (vs) "!> HΓ1 /=".
wp_bind (subst_map vs e).
iApply (wp_wand with "(He HΓ1)"). iIntros (v) "[Hv HΓ2]".
iDestruct "Hv" as (l w ->) "[Hl Hw]".
wp_free. by iFrame "HΓ2".
Qed.
Γ !! x = Some (ref_uniq A)%lty →
⊢ Γ ⊨ ! x : A ⫤ <[x := (ref_uniq (copy- A))%lty]> Γ.
Proof.
iIntros (Hx vs) "!> HΓ".
iDestruct (env_ltyped_lookup with "HΓ") as (v Hv) "[HA HΓ]"; first done.
simpl. rewrite Hv.
iDestruct "HA" as (l w ->) "[Hl Hw]".
wp_load.
iAssert (ltty_car (copy- A) w)%lty as "#HAm".
{ iApply coreP_intro. iApply "Hw". }
iFrame "Hw".
iAssert (ltty_car (ref_uniq (copy- A))%lty #l) with "[Hl]" as "HA".
{ iExists l, w. iSplit=>//. iFrame "Hl HAm". }
iDestruct (env_ltyped_insert _ _ x with "HA HΓ") as "HΓ".
rewrite /binder_insert insert_delete (insert_id _ _ _ Hv).
iFrame "HΓ".
Qed.
Γ ⊨ x <- e : () ⫤ <[x := (ref_uniq B)%lty]> Γ'.
Proof.
iIntros (Hx) "#He". iIntros (vs) "!> HΓ /=".
wp_bind (subst_map vs e).
iApply (wp_wand with "(He HΓ)"). iIntros (v) "[HB HΓ']".
iDestruct (env_ltyped_lookup with "HΓ'") as (w Hw) "[HA HΓ']"; first done.
rewrite Hw.
iDestruct "HA" as (l v' ->) "[Hl HA]".
wp_store. iSplitR; first done.
iAssert (ltty_car (ref_uniq B)%lty #l) with "[Hl HB]" as "HB".
{ iExists l, v. iSplit=>//. iFrame "Hl HB". }
iDestruct (env_ltyped_insert _ _ x with "HB HΓ'") as "HΓ'".
rewrite /binder_insert insert_delete (insert_id _ _ _ Hw).
iFrame "HΓ'".
Qed.
Lemma ltyped_upgrade_shared Γ Γ' e A :
Proof.
iIntros "#He" (vs) "!> HΓ". iApply wp_fupd.
iApply (wp_wand with "(He HΓ)"). iIntros (v) "[Hv HΓ']".
iDestruct "Hv" as (l w ->) "[Hl HA]".
iFrame "HΓ'". iExists l.
iMod (inv_alloc (ref_shrN .@ l) _
(∃ v : val, l ↦ v ∗ □ ltty_car A v) with "[Hl HA]") as "$"; last done.
iExists w. iFrame "Hl HA".
Qed.
Lemma ltyped_load_shared Γ Γ' e A :
(Γ ⊨ e : ref_shr A ⫤ Γ') -∗
Proof.
iIntros "#He" (vs) "!> HΓ /=".
wp_bind (subst_map vs e).
iApply (wp_wand with "(He HΓ)"). iIntros (v) "[Hv HΓ]".
iDestruct "Hv" as (l ->) "#Hv".
iInv (ref_shrN .@ l) as (v) "[>Hl #HA]" "Hclose".
wp_load.
iMod ("Hclose" with "[Hl HA]") as "_".
{ iExists v. iFrame "Hl HA". }
Qed.
Lemma ltyped_store_shared Γ1 Γ2 Γ3 e1 e2 A :
(Γ2 ⊨ e1 : ref_shr A ⫤ Γ3) -∗
(Γ1 ⊨ e1 <- e2 : () ⫤ Γ3).
Proof.
iIntros "#H1 #H2" (vs) "!> HΓ1 /=".
wp_bind (subst_map vs e2).
iApply (wp_wand with "(H1 HΓ1)"). iIntros (v) "[Hv HΓ2]".
wp_bind (subst_map vs e1).
iApply (wp_wand with "(H2 HΓ2)"). iIntros (w) "[Hw HΓ3]".
iDestruct "Hw" as (l ->) "#Hw".
iInv (ref_shrN .@ l) as (?) "[>Hl HA]" "Hclose".
wp_store.
iMod ("Hclose" with "[Hl Hv]") as "_".
{ iExists v. iFrame "Hl Hv". }
Lemma ltyped_fetch_and_add_shared Γ1 Γ2 Γ3 e1 e2 :
(Γ1 ⊨ e2 : lty_int ⫤ Γ2) -∗
(Γ2 ⊨ e1 : ref_shr lty_int ⫤ Γ3) -∗
(Γ1 ⊨ FAA e1 e2 : lty_int ⫤ Γ3).
Proof.
iIntros "#H1 #H2" (vs) "!> HΓ1 /=".
wp_bind (subst_map vs e2).
iApply (wp_wand with "(H1 HΓ1)"). iIntros (v) "[Hv HΓ2]".
wp_bind (subst_map vs e1).
iApply (wp_wand with "(H2 HΓ2)"). iIntros (w) "[Hw HΓ3]".
iDestruct "Hw" as (l ->) "#Hw".
iInv (ref_shrN .@ l) as (w) "[Hl >Hn]" "Hclose".
iDestruct "Hn" as %[k ->].
iDestruct "Hv" as %[n ->].
wp_faa.
iMod ("Hclose" with "[Hl]") as %_.
{ iExists #(k + n). iFrame "Hl". by iExists (k + n)%Z. }
iModIntro. iFrame "HΓ3". by iExists k.
Qed.
Section with_spawn.
Context `{spawnG Σ}.
(** Parallel composition properties *)
Lemma ltyped_par Γ Γ' Γ1 Γ1' Γ2 Γ2' e1 e2 A B :
env_split Γ Γ1 Γ2 -∗
env_split Γ' Γ1' Γ2' -∗
(Γ1 ⊨ e1 : A ⫤ Γ1') -∗
(Γ2 ⊨ e2 : B ⫤ Γ2') -∗
Γ ⊨ e1 ||| e2 : A * B ⫤ Γ'.
Proof.
iIntros "#Hsplit #Hsplit' #H1 #H2" (vs) "!> HΓ /=".
iDestruct ("Hsplit" with "HΓ") as "[HΓ1 HΓ2]".
wp_apply (wp_par with "[HΓ1] [HΓ2]").
- iApply ("H1" with "HΓ1").
- iApply ("H2" with "HΓ2").
- iIntros (v1 v2) "[[HA HΓ1'] [HB HΓ2']]".
iModIntro. iSplitL "HA HB".
+ iExists v1, v2. iSplit=>//. iFrame "HA HB".
+ iApply "Hsplit'". iFrame "HΓ1' HΓ2'".
Qed.
End with_spawn.
Section with_chan.
Context `{chanG Σ}.
Lemma ltyped_new_chan S :
⊢ ∅ ⊨ new_chan : () → (chan S * chan (lty_dual S)).
Proof.
iIntros (vs) "!> HΓ /=". iApply wp_value.
iSplitL; last by iApply env_ltyped_empty.
iIntros "!>" (u) ">->".
iApply (new_chan_spec with "[//]"); iIntros (c1 c2) "!> [Hp1 Hp2]".
iExists c1, c2. iSplit=>//. iFrame "Hp1 Hp2".
Qed.
Lemma ltyped_send Γ Γ' (x : string) e A S :
Γ' !! x = Some (chan (<!!> TY A; S))%lty →
(Γ ⊨ e : A ⫤ Γ') -∗
iIntros (Hx) "#He !>". iIntros (vs) "HΓ"=> /=.
wp_bind (subst_map vs e).
iApply (wp_wand with "(He HΓ)"); iIntros (v) "[HA HΓ']".
iDestruct (env_ltyped_lookup with "HΓ'") as (v' Heq) "[Hc HΓ']".
rewrite Heq.
wp_send with "[HA //]".
iSplitR; first done.
iDestruct (env_ltyped_insert _ _ x (chan _) with "[Hc //] HΓ'")
as "HΓ'"=> /=.
by rewrite insert_delete (insert_id vs).
Lemma iProto_le_lmsg_texist {kt : ktele Σ} (m : ltys Σ kt → iMsg Σ) :
⊢ (<?> (∃.. Xs : ltys Σ kt, m Xs)%lmsg) ⊑ (<? (Xs : ltys Σ kt)> m Xs).
iInduction kt as [|k kt] "IH".
{ rewrite /lty_msg_texist /=. by iExists LTysO. }
rewrite /lty_msg_texist /=. iIntros (X).
iApply (iProto_le_trans with "IH"). iIntros (Xs). by iExists (LTysS _ _).
Qed.
Lemma ltyped_recv_texist {kt} Γ1 Γ2 (xc : string) (x : binder) (e : expr)
(A : ltys Σ kt → ltty Σ) (S : ltys Σ kt → lsty Σ) (B : ltty Σ) :
(∀ Ys,
<![x:=A Ys]!> $ <[xc:=(chan (S Ys))%lty]> Γ1 ⊨ e : B ⫤ Γ2) -∗
(let: x := recv xc in e) : B ⫤ binder_delete x Γ2.
Proof.
iIntros "#He !>". iIntros (vs) "HΓ /=".
iDestruct (env_ltyped_lookup with "HΓ") as (c Hxc) "[Hc HΓ]".
{ by apply lookup_insert. }
rewrite Hxc.
iAssert (c ↣ <? (Xs : ltys Σ kt) (v : val)>
MSG v {{ ▷ ltty_car (A Xs) v }}; lsty_car (S Xs)) with "[Hc]" as "Hc".
{ iApply (iProto_mapsto_le with "Hc"); iIntros "!>".
iApply iProto_le_lmsg_texist. }
wp_recv (Xs v) as "HA". wp_pures.
wp_apply (wp_wand with "(He [-]) []").
{ iApply (env_ltyped_insert _ _ x with "HA").
rewrite delete_insert_delete.
iEval (rewrite -(insert_id vs xc c) // -(insert_delete Γ1)).
by iApply (env_ltyped_insert _ _ xc with "[Hc] HΓ"). }
iIntros (w) "[$ HΓ]". by destruct x; [|by iApply env_ltyped_delete].
Lemma ltyped_recv Γ (x : string) A S :
Γ !! x = Some (chan (<??> TY A; S))%lty →
⊢ Γ ⊨ recv x : A ⫤ <[x:=(chan S)%lty]> Γ.
iIntros (Hx) "!>". iIntros (vs) "HΓ"=> /=.
iDestruct (env_ltyped_lookup _ _ _ _ (Hx) with "HΓ") as (v' Heq) "[Hc HΓ]".
iDestruct (env_ltyped_insert _ _ x (chan _) _ with "[Hc //] HΓ") as "HΓ"=> /=.
by rewrite insert_delete (insert_id vs).
Definition select : val := λ: "c" "i", send "c" "i".
Lemma ltyped_select Γ (x : string) (i : Z) (S : lsty Σ) Ss :
Ss !! i = Some S →
⊢ <[x:=(chan (lty_select Ss))%lty]>Γ ⊨ select x #i : () ⫤
<[x:=(chan S)%lty]>Γ.
iDestruct (env_ltyped_lookup with "HΓ") as (v' Heq) "[Hc HΓ]".
{ by apply lookup_insert. }
rewrite Heq /select.
wp_send with "[]".
{ eauto. }
iSplitR; first done.
iDestruct (env_ltyped_insert _ _ x (chan _) with "[Hc //] HΓ") as "HΓ' /=".
rewrite insert_delete insert_insert (insert_id vs)=> //.
by rewrite lookup_total_alt Hin.
Qed.
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
Fixpoint lty_arr_list (As : list (ltty Σ)) (B : ltty Σ) : ltty Σ :=
match As with
| [] => B
| A :: As => A ⊸ lty_arr_list As B
end.
Lemma lty_arr_list_spec_step A As (e : expr) B ws y i :
(∀ v, ltty_car A v -∗
WP subst_map (<[y+:+pretty i:=v]> ws)
(switch_lams y (S i) (length As) e) {{ ltty_car (lty_arr_list As B) }}) -∗
WP subst_map ws (switch_lams y i (S (length As)) e)
{{ ltty_car (lty_arr_list (A :: As) B) }}.
Proof.
iIntros "H". wp_pures. iIntros (v) "HA".
iDestruct ("H" with "HA") as "H".
rewrite subst_map_insert.
wp_apply "H".
Qed.
Lemma lty_arr_list_spec As (e : expr) B ws y i n :
n = length As →
(∀ vs, ([∗ list] A;v ∈ As;vs, ltty_car A v) -∗
WP subst_map (map_string_seq y i vs ∪ ws) e {{ ltty_car B }}) -∗
WP subst_map ws (switch_lams y i n e) {{ ltty_car (lty_arr_list As B) }}.
Proof.
iIntros (Hlen) "H".
iInduction As as [|A As] "IH" forall (ws i e n Hlen); simplify_eq/=.
- iDestruct ("H" $! [] with "[$]") as "H"=> /=.
by rewrite left_id_L.
- iApply lty_arr_list_spec_step. iIntros (v) "HA".
iApply ("IH" with "[//]"). iIntros (vs) "HAs".
iSpecialize ("H" $! (v::vs)); simpl.
do 2 rewrite insert_union_singleton_l.
rewrite (map_union_comm ({[y +:+ pretty i := v]})); last first.
{ apply map_disjoint_singleton_l_2.
apply lookup_map_string_seq_None_lt. eauto. }
rewrite assoc_L. iApply ("H" with "[$HA $HAs]").
Qed.
switch_lams "f" 0 (length xs) $
let: "y" := recv "c" in
switch_body "y" 0 xs (assert: #false) $ λ i, ("f" +:+ pretty i) "c".
(∀ x, x ∈ xs ↔ is_Some (Ss !! x)) →
iApply wp_value.
iSplitL; last by iApply env_ltyped_empty.
iIntros (c) "Hc". wp_lam.
{ by rewrite fmap_length. }
iIntros (ws) "H".
rewrite big_sepL2_fmap_l.
rewrite -insert_union_singleton_r; last by apply lookup_map_string_seq_None.
rewrite /= lookup_insert.
wp_recv (x) as "HPsx". iDestruct "HPsx" as %HPs_Some.
assert (x ∈ xs) as Hin by naive_solver.
pose proof (list_find_elem_of (x =.) xs x) as [[n z] Hfind_Some]; [done..|].
iApply switch_body_spec.
{ apply fmap_Some_2, Hfind_Some. }
{ by rewrite lookup_insert. }
simplify_map_eq. rewrite lookup_map_string_seq_Some.
{ by apply list_find_Some in Hfind_Some as [? [-> _]]. }
assert (is_Some (ws !! n)) as [w Hws_Some].
{ apply lookup_lt_is_Some_2. rewrite -Heq. eauto using lookup_lt_Some. }
iDestruct (big_sepL2_lookup _ xs ws n with "H") as "HA"; [done..|].
rewrite Hws_Some. by iApply "HA".
End with_chan.
End properties.