diff --git a/theories/channel/multi_channel.v b/theories/channel/multi_channel.v index 0868ed665ac7396b32c6fa92e45221467975db3c..590820f5779270211741e8f3f59a76906ad435a5 100644 --- a/theories/channel/multi_channel.v +++ b/theories/channel/multi_channel.v @@ -28,22 +28,19 @@ From actris.channel Require Import multi_proto_model. From actris.channel Require Export multi_proto. Set Default Proof Using "Type". -(* TODO: Update new_chan definition to use pointers with offsets *) (** * The definition of the message-passing connectives *) Definition new_chan : val := - λ: "n", - let: "l" := AllocN ("n"*"n") NONEV in - let: "xxs" := AllocN "n" NONEV in - (rec: "go1" "i" := if: "i" = "n" then #() else - let: "xs" := AllocN "n" NONEV in - (rec: "go2" "j" := if: "j" = "n" then #() else - ("xs" +â‚— "j") <- ("l" +â‚— ("i"*"n"+"j"), "l" +â‚— ("j"*"n"+"i"));; - "go2" ("j"+#1)) #0;; - ("xxs" +â‚— "i") <- "xs";; - "go1" ("i"+#1)) #0;; "xxs". + λ: "n", (AllocN ("n"*"n") NONEV, "n"). Definition get_chan : val := - λ: "cs" "i", ! ("cs" +â‚— "i"). + λ: "cs" "i", ("cs","i"). + +Definition diverge : val := + λ: <>, (rec: "go" <> := "go" #())%V #(). + +Definition guard : val := + λ: "i" "n", + if: "i" < "n" then #() else diverge #(). Definition wait : val := rec: "go" "c" := @@ -52,27 +49,30 @@ Definition wait : val := | SOME <> => "go" "c" end. + +Definition pos (n i j : nat) : nat := i * n + j. +Definition vpos : val := λ: "n" "i" "j", "i"*"n" + "j". + Definition send : val := - λ: "c" "i" "v", - let: "len" := Fst "c" in - if: "i" < "len" then - let: "l" := Fst (! ((Snd "c") +â‚— "i")) in - "l" <- SOME "v";; wait "l" - (* OBS: Hacky *) - else (rec: "go" <> := "go" #())%V #(). + λ: "c" "j" "v", + let: "n" := Snd (Fst "c") in guard "j" "n";; + let: "ls" := Fst (Fst "c") in + let: "i" := Snd "c" in + let: "l" := "ls" +â‚— vpos "n" "i" "j" in + "l" <- SOME "v";; wait "l". +(* TODO: Move recursion further in *) Definition recv : val := - rec: "go" "c" "i" := - let: "len" := Fst "c" in - if: "i" < "len" then - let: "l" := Snd (! ((Snd "c") +â‚— "i")) in - let: "v" := Xchg "l" NONEV in - match: "v" with - NONE => "go" "c" "i" - | SOME "v" => "v" - end - (* OBS: Hacky *) - else (rec: "go" <> := "go" #())%V #(). + rec: "go" "c" "j" := + let: "n" := Snd (Fst "c") in guard "j" "n";; + let: "ls" := Fst (Fst "c") in + let: "i" := Snd "c" in + let: "l" := "ls" +â‚— vpos "n" "j" "i" in + let: "v" := Xchg "l" NONEV in + match: "v" with + NONE => "go" "c" "j" + | SOME "v" => "v" + end. (** * Setup of Iris's cameras *) Class proto_exclG Σ V := @@ -99,7 +99,7 @@ Notation iMsg Σ := (iMsg Σ val). Definition tok `{!chanG Σ} (γ : gname) : iProp Σ := own γ (Excl ()). Definition chan_inv `{!heapGS Σ, !chanG Σ} γ γE γt i j (l:loc) : iProp Σ := - (l ↦ NONEV ∗ tok γt) ∨ + (l ↦ NONEV ∗ tok γt)%I ∨ (∃ v m, l ↦ SOMEV v ∗ iProto_own γ i (<(Send, j)> m)%proto ∗ (∃ p, iMsg_car m v (Next p) ∗ own γE (â—E (Next p)))) ∨ @@ -108,15 +108,13 @@ Definition chan_inv `{!heapGS Σ, !chanG Σ} γ γE γt i j (l:loc) : iProp Σ : Definition iProto_pointsto_def `{!heapGS Σ, !chanG Σ} (c : val) (p : iProto Σ) : iProp Σ := - ∃ γ γE1 γE2 γt1 γt2 i (l:loc) ls p', - ⌜ c = PairV #(length ls) #l ⌠∗ + ∃ γ γE1 (l:loc) (i:nat) (n:nat) p', + ⌜ c = (#l,#n,#i)%V ⌠∗ inv (nroot.@"ctx") (iProto_ctx γ) ∗ - l ↦∗ ls ∗ - ([∗list] j ↦ v ∈ ls, - ∃ (l1 l2 : loc), - ⌜v = PairV #l1 #l2⌠∗ - inv (nroot.@"p") (chan_inv γ γE1 γt1 i j l1) ∗ - inv (nroot.@"p") (chan_inv γ γE2 γt2 j i l2)) ∗ + ([∗list] j ↦ _ ∈ replicate n (), + ∃ γE2 γt1 γt2, + inv (nroot.@"p") (chan_inv γ γE1 γt1 i j (l +â‚— (pos n i j))) ∗ + inv (nroot.@"p") (chan_inv γ γE2 γt2 j i (l +â‚— (pos n j i)))) ∗ â–· (p' ⊑ p) ∗ own γE1 (â—E (Next p')) ∗ own γE1 (â—¯E (Next p')) ∗ iProto_own γ i p'. @@ -131,10 +129,18 @@ Notation "c ↣ p" := (iProto_pointsto c p) Definition chan_pool `{!heapGS Σ, !chanG Σ} (cs : val) (ps : gmap nat (iProto Σ)) : iProp Σ := - ∃ (l:loc) (ls : list val), - ⌜cs = #l⌠∗ ⌜∀ i, is_Some (ps !! i) → is_Some (ls !! i)⌠∗ - l ↦∗ ls ∗ - [∗list] i ↦ c ∈ ls, (∀ p, ⌜ps !! i = Some p⌠-∗ c ↣ p). + ∃ γ (γEs : list gname) (l:loc) (n:nat), + ⌜cs = (#l,#n)%V⌠∗ ⌜∀ i, is_Some (ps !! i) → i < n⌠∗ + inv (nroot.@"ctx") (iProto_ctx γ) ∗ + [∗ list] i ↦ _ ∈ replicate n (), + (∀ p, ⌜ps !! i = Some p⌠-∗ + own (γEs !!! i) (â—E (Next p)) ∗ + own (γEs !!! i) (â—¯E (Next p)) ∗ + iProto_own γ i p) ∗ + [∗ list] j ↦ _ ∈ replicate n (), + ∃ γt1 γt2, + inv (nroot.@"p") (chan_inv γ (γEs !!! i) γt1 i j (l +â‚— (pos n i j))) ∗ + inv (nroot.@"p") (chan_inv γ (γEs !!! j) γt2 j i (l +â‚— (pos n j i))). Section channel. Context `{!heapGS Σ, !chanG Σ}. @@ -150,20 +156,185 @@ Section channel. Proof. rewrite iProto_pointsto_eq. iDestruct 1 as - (γ γE1 γE2 γt1 γt2 i l ls p ->) "(#IH & Hl & Hls & Hle & Hâ— & Hâ—¯ & Hown)". - iIntros "Hle'". iExists γ, γE1, γE2, γt1, γt2, i, l, ls, p. + (γ γE l n i p ->) "(#IH & Hls & Hle & Hâ— & Hâ—¯ & Hown)". + iIntros "Hle'". iExists γ, γE, l, n, i, p. iSplit; [done|]. iFrame "#∗". iApply (iProto_le_trans with "Hle Hle'"). Qed. + Lemma big_sepL_replicate {A B} n (x1 : A) (x2 : B) (P : nat → iProp Σ) : + ([∗ list] i ↦ _ ∈ replicate n x1, P i) ⊢ + ([∗ list] i ↦ _ ∈ replicate n x2, P i). + Proof. + iIntros "H". + iInduction n as [|n] "IHn". + { done. } + replace (S n) with (n + 1) by lia. + rewrite !replicate_add. + simpl. iDestruct "H" as "[H1 H2]". + iSplitL "H1". + { by iApply "IHn". } + simpl. rewrite !replicate_length. iFrame. + Qed. + + Lemma array_to_matrix_pre l n m v : + l ↦∗ replicate (n * m) v -∗ + [∗ list] i ↦ _ ∈ replicate n (), + (l +â‚— i*m) ↦∗ replicate m v. + Proof. + iIntros "Hl". + iInduction n as [|n] "IHn". + { done. } + replace (S n) with (n + 1) by lia. + replace ((n + 1) * m) with (n * m + m) by lia. + rewrite !replicate_add. simpl. + rewrite array_app. + iDestruct "Hl" as "[H1 H2]". + iDestruct ("IHn" with "H1") as "H1". + iFrame. + simpl. + rewrite Nat.add_0_r. + rewrite !replicate_length. + replace (Z.of_nat (n * m)) with (Z.of_nat n * Z.of_nat m)%Z by lia. + iFrame. + Qed. + + Lemma array_to_matrix l n v : + l ↦∗ replicate (n * n) v -∗ + [∗ list] i ↦ _ ∈ replicate n (), + [∗ list] j ↦ _ ∈ replicate n (), + (l +â‚— pos n i j) ↦ v. + Proof. + iIntros "H". + iDestruct (array_to_matrix_pre with "H") as "H". + iApply (big_sepL_impl with "H"). + iIntros "!>" (i ? HSome) "H". + clear HSome. + rewrite /array. + iApply big_sepL_replicate. + iApply (big_sepL_impl with "H"). + iIntros "!>" (j ? HSome) "Hl". + rewrite /pos. + rewrite Loc.add_assoc. + replace (Z.of_nat i * Z.of_nat n + Z.of_nat j)%Z with + (Z.of_nat (i * n + j))%Z by lia. + apply lookup_replicate in HSome as [-> _]. done. + Qed. + (** ** Specifications of [send] and [recv] *) Lemma new_chan_spec (n:nat) (ps:gmap nat (iProto Σ)) : - (∀ i, i < n → is_Some (ps !! i)) → - n = (size (dom ps)) → + 0 < n → + (∀ i, i < n ↔ is_Some (ps !! i)) → (* TODO: Weaken this! *) + (* n = (size (dom ps)) → *) {{{ iProto_consistent ps }}} new_chan #n {{{ cs, RET cs; chan_pool cs ps }}}. - Proof. Admitted. + Proof. + iIntros (Hle HSome Φ) "Hps HΦ". wp_lam. + wp_smart_apply wp_allocN; [lia|done|]. + iIntros (l) "[Hl _]". + iMod (iProto_init with "Hps") as (γ) "[Hps Hps']". + wp_pures. iApply "HΦ". + iAssert (|==> ∃ (γEs : list gname), + ⌜length γEs = n⌠∗ + [∗ list] i ↦ _ ∈ replicate n (), + own (γEs !!! i) (â—E (Next (ps !!! i))) ∗ + own (γEs !!! i) (â—¯E (Next (ps !!! i))) ∗ + iProto_own γ i (ps !!! i))%I with "[Hps']" as "H". + { clear Hle. + (* iInduction n as [|n] "IHn" forall (ps HSome Heq). *) + iInduction n as [|n] "IHn" forall (ps HSome). + { iExists []. iModIntro. simpl. done. } + assert (n < S n) by lia. + apply HSome in H. destruct H as [p ?]. + iDestruct (big_sepM_delete _ _ n with "Hps'") as "[Hp Hps']". + { done. } + iMod (own_alloc (â—E (Next p) â‹… â—¯E (Next p))) as (γE) "[Hauth Hfrag]". + { apply excl_auth_valid. } + iMod ("IHn" with "[] Hps'") as (γEs Hlen) "H". + { iPureIntro. + intros i. + split. + - intros Hle. + rewrite lookup_delete_ne; [|lia]. + apply HSome. lia. + - intros HSome'. + destruct (decide (i=n)). + + simplify_eq. rewrite lookup_delete in HSome'. by inversion HSome'. + + rewrite lookup_delete_ne in HSome'; [|lia]. apply HSome in HSome'. + lia. + } + iModIntro. iExists (γEs++[γE]). + replace (S n) with (n + 1) by lia. + rewrite replicate_add. + rewrite big_sepL_app. + rewrite app_length. + rewrite Hlen. iSplit; [done|]. + simpl. + iSplitL "H". + { iApply (big_sepL_impl with "H"). + iIntros "!>" (i ? HSome') "(Hauth & Hfrag & Hown)". + assert (i < n). + { by apply lookup_replicate_1 in HSome' as [? ?]. } + assert (delete n ps !!! i = ps !!! i) as Heq'. + { apply lookup_total_delete_ne. lia. } + rewrite Heq'. iFrame. + rewrite lookup_total_app_l; [|lia]. iFrame. } + simpl. rewrite replicate_length. rewrite Nat.add_0_r. + rewrite list_lookup_total_middle; [|done]. + rewrite lookup_total_alt. rewrite H. simpl. iFrame. } + iMod "H" as (γEs Hlen) "H". + iAssert (|={⊤}=> + [∗ list] i ↦ _ ∈ replicate n (), + [∗ list] j ↦ _ ∈ replicate n (), + ∃ γt, + inv (nroot.@"p") (chan_inv γ (γEs !!! i) γt i j + (l +â‚— (pos n i j))))%I with "[Hl]" as "IH". + { replace (Z.to_nat (Z.of_nat n * Z.of_nat n)) with (n*n) by lia. + iDestruct (array_to_matrix with "Hl") as "Hl". + iApply big_sepL_fupd. + iApply (big_sepL_impl with "Hl"). + iIntros "!>" (i ? HSome') "H1". + iApply big_sepL_fupd. + iApply (big_sepL_impl with "H1"). + iIntros "!>" (j ? HSome'') "H1". + iMod (own_alloc (Excl ())) as (γ') "Hγ'". + { done. } + iExists γ'. + iApply inv_alloc. + iLeft. iFrame. } + iMod "IH" as "#IH". + iMod (inv_alloc with "Hps") as "#IHp". + iExists _,_,_,_. + iModIntro. iSplit; [done|]. + iSplit. + { iPureIntro. intros. apply HSome in H. done. } + iFrame "IHp". + iApply (big_sepL_impl with "H"). + iIntros "!>" (i ? HSome') "(Hauth & Hfrag & Hown)". + iSplitL. + { iIntros (p HSome''). + rewrite lookup_total_alt. rewrite HSome''. + iFrame. } + iApply big_sepL_intro. + iIntros "!>" (j ? HSome''). + assert (i < n) as Hle'. + { apply lookup_replicate in HSome' as [_ Hle']. done. } + assert (j < n) as Hle''. + { apply lookup_replicate in HSome'' as [_ Hle'']. done. } + iDestruct (big_sepL_lookup _ _ i () with "IH") as "IH''". + { rewrite lookup_replicate. done. } + iDestruct (big_sepL_lookup _ _ j () with "IH''") as "IH'''". + { rewrite lookup_replicate. done. } + iFrame "#". + iDestruct (big_sepL_lookup _ _ j () with "IH") as "H". + { rewrite lookup_replicate. done. } + iDestruct (big_sepL_lookup _ _ i () with "H") as "H'". + { rewrite lookup_replicate. done. } + iDestruct "IH'''" as (γ1) "?". + iDestruct "H'" as (γ2) "?". + iExists _, _. iFrame "#". + Qed. Lemma get_chan_spec cs (i:nat) ps p : ps !! i = Some p → @@ -172,30 +343,37 @@ Section channel. {{{ c, RET c; c ↣ p ∗ chan_pool cs (delete i ps) }}}. Proof. iIntros (HSome Φ) "Hcs HΦ". - iDestruct "Hcs" as (l ls -> Hlen) "[Hl Hls]". - wp_lam. - assert (is_Some (ls !! i)) as [c HSome']. - { by apply Hlen. } - wp_smart_apply (wp_load_offset with "Hl"); [done|]. - iIntros "Hcs". + iDestruct "Hcs" as (γp γEs l n -> Hle) "[#IHp Hl]". + wp_lam. wp_pures. + assert (i < n). + { apply Hle. eexists _. done. } + iDestruct (big_sepL_delete _ _ i () with "Hl") as "[[Hi #IHs] H]". + { by apply lookup_replicate. } + iDestruct ("Hi" with "[//]") as "(Hauth & Hown & Hp)". + iModIntro. iApply "HΦ". - iDestruct (big_sepL_delete' _ _ i with "Hls") as "[Hc Hls]"; [set_solver|]. - iDestruct ("Hc" with "[//]") as "Hc". - iFrame. - iExists _, _. iSplit; [done|]. iFrame "Hcs". - iSplitR. - { iPureIntro. intros j HSome''. - destruct (decide (i=j)) as [<-|Hneq]. - { rewrite lookup_delete in HSome''. done. } - rewrite lookup_delete_ne in HSome''; [|done]. - by apply Hlen. } - iApply (big_sepL_impl with "Hls"). - iIntros "!>" (j v Hin) "H". - iIntros (p' HSome''). - destruct (decide (i=j)) as [<-|Hneq]. - { rewrite lookup_delete in HSome''. done. } - rewrite lookup_delete_ne in HSome''; [|done]. - by iApply "H". + iSplitR "H". + { rewrite iProto_pointsto_eq. + iExists _, _, _, _, _, _. + iSplit; [done|]. + iFrame "#∗". iSplit; [|iNext; done]. + iApply (big_sepL_impl with "IHs"). + iIntros "!>" (???). iDestruct 1 as (γt1 γt2) "[H1 H2]". + iExists _,_,_. iFrame. } + iExists _, _, _, _. + iSplit; [done|]. + iSplit. + { iPureIntro. intros i' HSome'. apply Hle. + assert (i ≠i'). + { intros ->. rewrite lookup_delete in HSome'. by inversion HSome'. } + rewrite lookup_delete_ne in HSome'; done. } + iFrame "#∗". + iApply (big_sepL_impl with "H"). + iIntros "!>" (i' ? HSome''). + case_decide. + { simplify_eq. iFrame "#". + iIntros "_" (p' Hin). simplify_eq. by rewrite lookup_delete in Hin. } + rewrite lookup_delete_ne; [|done]. eauto. Qed. Lemma own_prot_excl γ i (p1 p2 : iProto Σ) : @@ -206,6 +384,33 @@ Section channel. iIntros "Hi Hj". by iDestruct (own_prot_idx with "Hi Hj") as %Hneq. Qed. + Lemma diverge_spec P : + {{{ True }}} diverge #() {{{ RET #(); P }}}. + Proof. + iIntros (Φ) "_ HΦ". + wp_lam. iLöb as "IH". + wp_pures. by iApply "IH". + Qed. + + Lemma guard_spec (i n : nat) : + {{{ True }}} guard #i #n {{{ RET #(); ⌜i < n⌠}}}. + Proof. + iIntros (Φ) "_ HΦ". + wp_lam. wp_pures. + case_bool_decide. + - wp_pures. iApply "HΦ". iPureIntro. lia. + - by wp_smart_apply diverge_spec. + Qed. + + Lemma vpos_spec (n i j : nat) : + {{{ True }}} vpos #n #i #j {{{ RET #(pos n i j); True }}}. + Proof. + iIntros (Φ) "_ HΦ". wp_lam. wp_pures. rewrite /pos. + replace (Z.of_nat i * Z.of_nat n + Z.of_nat j)%Z with + (Z.of_nat (i * n + j)) by lia. + by iApply "HΦ". + Qed. + Lemma send_spec c j v p : {{{ c ↣ <(Send, j)> MSG v; p }}} send c #j v @@ -213,27 +418,21 @@ Section channel. Proof. rewrite iProto_pointsto_eq. iIntros (Φ) "Hc HΦ". wp_lam; wp_pures. iDestruct "Hc" as - (γ γE1 γE2 γt1 γt2 i l ls p' ->) "(#IH & Hl & Hls & Hle & Hâ— & Hâ—¯ & Hown)". + (γ γE l i n p' ->) "(#IH & #Hls & Hle & Hâ— & Hâ—¯ & Hown)". wp_pures. - case_bool_decide; last first. - { wp_pures. iClear "IH Hâ— Hâ—¯ Hown HΦ Hls Hl". - iLöb as "IH". wp_lam. iApply "IH". done. } - assert (is_Some (ls !! j)) as [l' HSome]. - { apply lookup_lt_is_Some_2. lia. } + wp_smart_apply guard_spec; [done|]. + iDestruct 1 as %Hle. wp_pures. - wp_smart_apply (wp_load_offset with "Hl"). - { done. } - iIntros "Hl". wp_pures. - iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj Hls]"; [done|]. - iDestruct "Hj" as (l1 l2 ->) "#[IHl1 IHl2]". - iDestruct ("Hls" with "[]") as "Hls". - { iExists _, _. iFrame "#". done. } + wp_smart_apply (vpos_spec); [done|]. iIntros "_". + iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj _]". + { by apply lookup_replicate_2. } + iDestruct "Hj" as (γE' γt γt') "#[IHl1 IHl2]". wp_pures. wp_bind (Store _ _). iInv "IHl1" as "HIp". iDestruct "HIp" as "[HIp|HIp]"; last first. { iDestruct "HIp" as "[HIp|HIp]". - - iDestruct "HIp" as (? m) "(>Hl' & Hown' & HIp)". + - iDestruct "HIp" as (? m) "(>Hl & Hown' & HIp)". wp_store. rewrite /iProto_own. iDestruct "Hown" as (p'') "[Hle' Hown]". @@ -268,7 +467,7 @@ Section channel. wp_load. iModIntro. iSplitL "Hl' Hown HIp". { iRight. iLeft. iExists _, _. iFrame. } - wp_pures. iApply ("HL" with "HΦ Hl Hls Htok Hâ—¯"). + wp_pures. iApply ("HL" with "HΦ Htok Hâ—¯"). - iDestruct "HIp" as (p'') "(>Hl' & Hown & Hâ—)". wp_load. iModIntro. @@ -281,11 +480,11 @@ Section channel. { apply excl_auth_update. } iModIntro. iApply "HΦ". - iExists _,_, _, _, _, _, _, _, _. + iExists _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". iRewrite -"Hagree'". iApply iProto_le_refl. Qed. - + Lemma send_spec_tele {TT} c i (tt : TT) (v : TT → val) (P : TT → iProp Σ) (p : TT → iProto Σ) : {{{ c ↣ (<(Send,i) @.. x > MSG v x {{ P x }}; p x) ∗ P tt }}} @@ -302,7 +501,6 @@ Section channel. by iApply (send_spec with "Hc"). Qed. - Lemma recv_spec {TT} c j (v : TT → val) (P : TT → iProp Σ) (p : TT → iProto Σ) : {{{ c ↣ <(Recv, j) @.. x> MSG v x {{ â–· P x }}; p x }}} recv c #j @@ -311,21 +509,16 @@ Section channel. iIntros (Φ) "Hc HΦ". iLöb as "HL". wp_lam. rewrite iProto_pointsto_eq. iDestruct "Hc" as - (γ γE1 γE2 γt1 γt2 i l ls p' ->) "(#IH & Hl & Hls & Hle & Hâ— & Hâ—¯ & Hown)". + (γ γE l i n p' ->) "(#IH & #Hls & Hle & Hâ— & Hâ—¯ & Hown)". + wp_pures. wp_pures. - case_bool_decide; last first. - { wp_pures. iClear "IH Hâ— Hâ—¯ Hown HΦ Hls Hl". - iLöb as "IH". wp_lam. iApply "IH". done. } + wp_smart_apply guard_spec; [done|]. + iDestruct 1 as %Hle. wp_pures. - assert (is_Some (ls !! j)) as [l' HSome]. - { apply lookup_lt_is_Some_2. lia. } - wp_smart_apply (wp_load_offset with "Hl"). - { done. } - iIntros "Hl". wp_pures. - iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj Hls]"; [done|]. - iDestruct "Hj" as (l1 l2 ->) "#[IHl1 IHl2]". - iDestruct ("Hls" with "[]") as "Hls". - { iExists _, _. iFrame "#". done. } + wp_smart_apply (vpos_spec); [done|]. iIntros "_". + iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj _]". + { by apply lookup_replicate_2. } + iDestruct "Hj" as (γE' γt γt') "#[IHl1 IHl2]". wp_pures. wp_bind (Xchg _ _). iInv "IHl2" as "HIp". @@ -335,16 +528,16 @@ Section channel. iModIntro. iSplitL "Hl' Htok". { iLeft. iFrame. } - wp_pures. iApply ("HL" with "[Hâ— Hâ—¯ Hown Hls Hl Hle] HΦ"). - iExists _, _, _, _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". } + wp_pures. iApply ("HL" with "[Hâ— Hâ—¯ Hown Hle] HΦ"). + iExists _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". } iDestruct "HIp" as "[HIp|HIp]"; last first. { iDestruct "HIp" as (p'') "[>Hl' [Hown' Hâ—¯']]". wp_xchg. iModIntro. iSplitL "Hl' Hown' Hâ—¯'". { iRight. iRight. iExists _. iFrame. } - wp_pures. iApply ("HL" with "[Hâ— Hâ—¯ Hown Hls Hl Hle] HΦ"). - iExists _, _, _, _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". } + wp_pures. iApply ("HL" with "[Hâ— Hâ—¯ Hown Hle] HΦ"). + iExists _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". } iDestruct "HIp" as (w m) "(>Hl' & Hown' & HIp)". iDestruct "HIp" as (p'') "[Hm Hp']". iInv "IH" as "Hctx". @@ -365,7 +558,7 @@ Section channel. { apply excl_auth_update. } iModIntro. iApply "HΦ". iFrame. - iExists _, _, _, _, _, _, _, _, _. iSplit; [done|]. + iExists _, _, _, _, _, _. iSplit; [done|]. iRewrite "Hp". iFrame "#∗". iApply iProto_le_refl. Qed.