Deadlock-Free Separation Logic: Linearity Yields Progress for Dependent Higher-Order Message Passing (Artifact)

Jules Jacobs, Jonas Kastberg Hinrichsen, Robbert Krebbers

(** This file defines all of the semantic typing lemmas for session types. Most of
these lemmas are semantic versions of the syntactic typing judgments typically
found in a syntactic type system. *)
From iris.bi.lib Require Import core.
From dlfactris.lang Require Import metatheory.
From dlfactris.session_logic Require Import proofmode.
From dlfactris.logrel Require Export session_types term_typing_rules.

Section session_typing_rules.
  Implicit Types A B : ltty.
  Implicit Types S T : lsty.
  Implicit Types Γ : ctx.

  Lemma ltyped_fork_chan Γ1 Γ2 S f :                                             (* https://apndx.org/pub/icnp/dlfactris.pdf#nameddest=406e6468 *)
    (Γ2  f : chan (lty_dual S)  any  []) -
    Γ1 ++ Γ2  fork_chan f : chan S  Γ1.
  Proof.
    iIntros "#Hf" (vs) "!> HΓ /=".
    iDestruct (ctx_ltyped_app with "HΓ") as "[HΓ1 HΓ2]".
    iApply ("Hf" with "HΓ2"); iIntros (v) "[HA HΓ']".
    iApply (wp_fork_chan with "[HA]").
    { iIntros "!>" (c) "Hc". by iApply "HA". }
    iIntros "!>" (c) "Hc". iFrame.
  Qed.

  Lemma ltyped_send Γ Γ' (x : string) e A S :
    Γ' !! x = Some (chan (<!!> TY A; S))%lty 
    (Γ  e : A  Γ') -
    (Γ  send x e : ()  ctx_overwrite x (chan S) Γ').
  Proof.
    iIntros (HΓx%ctx_lookup_perm) "#He !>". iIntros (vs) "HΓ /=".
    iApply ("He" with "HΓ"); iIntros (v) "[HA HΓ']".
    rewrite {2}HΓx /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ'") as (c Hvs) "[Hc HΓ']".
    rewrite Hvs. wp_send with "[HA //]". iSplitR; [done|].
    iDestruct (ctx_ltyped_overwrite _ _ x (chan _) with "Hc HΓ'") as "HΓ' /=".
    by rewrite (insert_id vs).
  Qed.

  Lemma ltyped_send_texist {kt : ktele} Γ Γ' (x : string) e M
      (A : kt -k> ltty) (S : kt -k> lsty) Xs :
    LtyMsgTele M A S 
    Γ' !! x = Some (chan (<!!> M))%lty 
    (Γ  e : ktele_app A Xs  Γ') -
    (Γ  send x e : ()  ctx_overwrite x (chan (ktele_app S Xs)) Γ').
  Proof.
    rewrite /LtyMsgTele.
    iIntros (HM HΓx%ctx_lookup_perm) "#He".
    iDestruct (ltyped_subsumption with "[] [] [] He") as "He'";
      [iApply ctx_le_refl|iApply lty_le_refl|..].
    { rewrite {2}HΓx.
      iApply ctx_le_cons; [|iApply ctx_le_refl]. iApply lty_le_chan.
      iEval (rewrite HM).
      iApply (lty_le_texist_intro_l (kt:=kt)). }
    iDestruct (ltyped_send _ _ x _ (ktele_app A Xs) (ktele_app S Xs) with "He'")
      as "He''".
    { apply ctx_insert_lookup. }
    rewrite /ctx_overwrite ctx_filter_ne_cons ctx_filter_ne_idemp.
    iApply "He''".
  Qed.

  Lemma ltyped_close Γ (x : string) :
    Γ !! x = Some (chan END!!)%lty 
    Γ  close x : ()  ctx_filter_ne x Γ.
  Proof.
    iIntros (HΓx%ctx_lookup_perm) "!>". iIntros (vs) "HΓ /=".
    rewrite {1}HΓx /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ") as (c Hvs) "[Hc HΓ]". rewrite Hvs.
    wp_close. by iFrame.
  Qed.

  Lemma subprot_lmsg_texist {kt : ktele} (m : ltys kt  msg) :
     (<?> (∃.. Xs : ltys kt, m Xs)%lmsg)  (<? (Xs : ltys kt)> m Xs).
  Proof.
    iInduction kt as [|k kt] "IH".
    { rewrite /lty_msg_texist /=. by iExists LTysO. }
    rewrite /lty_msg_texist /=. iIntros (X).
    iApply (subprot_trans with "IH"). iIntros (Xs). by iExists (LTysS _ _).
  Qed.

  Lemma ltyped_recv_texist {kt} Γ1 Γ2 M x (xc : string) (e : expr)
      (A : kt -k> ltty) (S : kt -k> lsty) (B : ltty) :
    x  BNamed xc 
    Γ1 !! xc = Some (chan (<??> M))%lty 
    LtyMsgTele M A S 
    (∀ Ys,
      ctx_overwrite x (ktele_app A Ys)
        (ctx_overwrite xc (chan (ktele_app S Ys)) Γ1)  e : B  Γ2) -
    Γ1  (let: x := recv xc in e) : B 
          ctx_filter_eq x (ctx_filter_ne xc Γ1) ++ ctx_anonymize x Γ2.
  Proof.
    rewrite /LtyMsgTele.
    iIntros (Hx HΓxc%ctx_lookup_perm HM) "#He !>". iIntros (vs) "HΓ1 /=".
    rewrite {2}HΓxc /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ1") as (c Hvs) "[Hc HΓ1]".
    rewrite Hvs {1}(ctx_filter_eq_perm (ctx_filter_ne xc Γ1) x).
    iDestruct (ctx_ltyped_app with "HΓ1") as "[HΓ1eq HΓ1neq]".
    iAssert (c  <? (Xs : ltys kt) (v : val)>
      MSG v {{ ltty_car (ktele_app A Xs) v }};
        lsty_car (ktele_app S Xs))%I with "[Hc]" as "Hc".
    { iApply (own_chan_subprot with "Hc"); iIntros "!>". rewrite HM.
      iApply subprot_lmsg_texist. }
    wp_recv (Xs v) as "HA". wp_pures. rewrite -subst_map_binder_insert.
    iApply ("He" with "[- HΓ1eq]").
    { iApply (ctx_ltyped_overwrite with "HA").
      destruct (decide (x = xc)) as [->|]; [done|].
      rewrite ctx_filter_ne_cons_ne //.
      iApply ctx_ltyped_cons_named. eauto with iFrame. }
    iIntros (w) "[$ HΓ]".
    iApply ctx_ltyped_app. iFrame "HΓ1eq". by iApply ctx_ltyped_anonymize'.
  Qed.

  Lemma ltyped_recv Γ (x : string) A S :
    Γ !! x = Some (chan (<??> TY A; S))%lty 
    Γ  recv x : A  ctx_overwrite x (chan S) Γ.
  Proof.
    iIntros (HΓx%ctx_lookup_perm) "!>". iIntros (vs) "HΓ /=".
    rewrite {1}HΓx /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ") as (c Hvs) "[Hc HΓ]". rewrite Hvs.
    wp_recv (v) as "HA". iFrame "HA".
    iApply ctx_ltyped_cons_named. eauto with iFrame.
  Qed.

  Lemma ltyped_wait Γ (x : string) :
    Γ !! x = Some (chan END??)%lty 
    Γ  wait x : ()  ctx_filter_ne x Γ.
  Proof.
    iIntros (HΓx%ctx_lookup_perm) "!>". iIntros (vs) "HΓ /=".
    rewrite {1}HΓx /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ") as (c Hvs) "[Hc HΓ]". rewrite Hvs.
    wp_wait. by iFrame.
  Qed.

  Lemma ltyped_select Γ1 Γ2 (x : string) e t A S ASs :
    Γ2 !! x = Some (chan (lty_select ASs))%lty 
    ASs !! t = Some (A,S) 
    (Γ1  e : A  Γ2) -
    Γ1  send x (Sum t e) : ()  ctx_overwrite x (chan S) Γ2.
  Proof.
    iIntros (HΓx%ctx_lookup_perm Ht); iIntros "#He !>" (vs) "HΓ /=".
    iApply ("He" with "HΓ"); iIntros (v) "[HA HΓ]". rewrite {2}HΓx /=.
    iDestruct (ctx_ltyped_cons_named with "HΓ") as (c Hvs) "[Hc HΓ]". rewrite Hvs.
    wp_send with "[HA]"; first by rewrite Ht /=.
    rewrite lookup_total_alt Ht /=. iSplitR; [done|].
    iApply ctx_ltyped_cons_named. eauto with iFrame.
  Qed.

  Lemma ltyped_branch Γ1 Γ2 ASs B (x : string) tes :
    Γ1 !! x = Some (chan (lty_branch ASs))%lty 
    ([ map] t  AS  ASs,  e,
       sum_branch t tes = Some e  
      (ctx_overwrite x (chan AS.2) Γ1  e : AS.1  B  Γ2)) -
    Γ1  MatchSum (recv x) tes : B  Γ2.
  Proof.
    iIntros (HΓx%ctx_lookup_perm) "#HAS !> %vs HΓ /=". rewrite {2}HΓx.
    iDestruct (ctx_ltyped_cons_named with "HΓ") as (c Hvs) "[Hc HΓ]". rewrite Hvs.
    wp_recv (t v) as "HA". rewrite lookup_total_alt.
    destruct (ASs !! t) as [[A S]|] eqn:Ht; simpl; [|done].
    iDestruct (big_sepM_lookup with "HAS") as (e He) "He"; first done. simpl.
    assert (TCEq (sum_branch t (prod_map id (subst_map vs) <$> tes))
                 (Some (subst_map vs e))).
    { apply TCEq_eq. revert e He. induction tes as [|[]];
        intros; repeat (case_decide || simplify_eq/=); eauto. }
    wp_pures. iApply ("He" with "[HΓ Hc]").
    { iApply ctx_ltyped_cons_named. eauto with iFrame. }
    iIntros (vret) "[HAB HΓ]". iApply ("HAB" with "HA"). eauto with iFrame.
  Qed.
End session_typing_rules.