Skip to content
Snippets Groups Projects
function.v 13.92 KiB
From iris.base_logic Require Import big_op.
From iris.proofmode Require Import tactics.
From iris.algebra Require Import vector.
From lrust.typing Require Export type.
From lrust.typing Require Import programs cont.
Set Default Proof Using "Type".

Section fn.
  Context `{typeG Σ} {A : Type} {n : nat}.

  Program Definition fn (E : A → elctx)
          (tys : A → vec type n) (ty : A → type) : type :=
    {| st_own tid vl := (∃ fb kb xb e H,
         ⌜vl = [@RecV fb (kb::xb) e H]⌝ ∗ ⌜length xb = n⌝ ∗
         ▷ ∀ (x : A) (k : val) (xl : vec val (length xb)),
            typed_body (E x) []
                       [k◁cont([], λ v : vec _ 1, [v!!!0 ◁ ty x])]
                       (zip_with (TCtx_hasty ∘ of_val) xl (tys x))
                       (subst_v (fb::kb::xb) (RecV fb (kb::xb) e:::k:::xl) e))%I |}.
  Next Obligation.
    iIntros (E tys ty tid vl) "H". iDestruct "H" as (fb kb xb e ?) "[% _]". by subst.
  Qed.

  Global Instance fn_send E tys ty : Send (fn E tys ty).
  Proof. iIntros (tid1 tid2 vl). done. Qed.

  Lemma fn_contractive n' E :
    Proper (pointwise_relation A (dist_later n') ==>
            pointwise_relation A (dist_later n') ==> dist n') (fn E).
  Proof.
    intros ?? Htys ?? Hty. unfold fn. f_equiv. rewrite st_dist_unfold /=.
    f_contractive=>tid vl. unfold typed_body.
    do 12 f_equiv. f_contractive. do 18 f_equiv.
    - rewrite !cctx_interp_singleton /=. do 5 f_equiv.
      rewrite !tctx_interp_singleton /tctx_elt_interp. do 3 f_equiv. apply Hty.
    - rewrite /tctx_interp !big_sepL_zip_with /=. do 3 f_equiv.
      assert (Hprop : ∀ n tid p i, Proper (dist (S n) ==> dist n)
        (λ (l : list _), ∀ ty, ⌜l !! i = Some ty⌝ → tctx_elt_interp tid (p ◁ ty))%I);
        last by apply Hprop, Htys.
      clear. intros n tid p i x y. rewrite list_dist_lookup=>Hxy.
      specialize (Hxy i). destruct (x !! i) as [tyx|], (y !! i) as [tyy|];
        inversion_clear Hxy; last done.
      transitivity (tctx_elt_interp tid (p ◁ tyx));
        last transitivity (tctx_elt_interp tid (p ◁ tyy)); last 2 first.
      + unfold tctx_elt_interp. do 3 f_equiv. by apply ty_own_ne.
      + apply equiv_dist. iSplit.
        * iIntros "H * #EQ". by iDestruct "EQ" as %[=->].
        * iIntros "H". by iApply "H".
      + apply equiv_dist. iSplit.
        * iIntros "H". by iApply "H".
        * iIntros "H * #EQ". by iDestruct "EQ" as %[=->].
  Qed.
  Global Existing Instance fn_contractive.

  Global Instance fn_ne n' E :
    Proper (pointwise_relation A (dist n') ==>
            pointwise_relation A (dist n') ==> dist n') (fn E).
  Proof.
    intros ?? H1 ?? H2.
    apply fn_contractive=>u; (destruct n'; [done|apply dist_S]);
      [apply (H1 u)|apply (H2 u)].
  Qed.
End fn.

Section typing.
  Context `{typeG Σ}.

  Lemma fn_subtype_full {A n} E0 L0 E E' (tys tys' : A → vec type n) ty ty' :
    (∀ x, elctx_incl E0 L0 (E x) (E' x)) →
    (∀ x, Forall2 (subtype (E0 ++ E x) L0) (tys' x) (tys x)) →
    (∀ x, subtype (E0 ++ E x) L0 (ty x) (ty' x)) →
    subtype E0 L0 (fn E' tys ty) (fn E tys' ty').
  Proof.
    intros HE Htys Hty. apply subtype_simple_type=>//= _ vl.
    iIntros "#LFT #HE0 #HL0 Hf". iDestruct "Hf" as (fb kb xb e ?) "[% [% #Hf]]". subst.
    iExists fb, kb, xb, e, _. iSplit. done. iSplit. done. iNext.
    rewrite /typed_body. iIntros "* !# * #HEAP _ Htl HE HL HC HT".
    iDestruct (elctx_interp_persist with "HE") as "#HEp".
    iMod (HE with "HE0 HL0 * HE") as (qE') "[HE' Hclose]". done.
    iApply ("Hf" with "* HEAP LFT Htl HE' HL [HC Hclose] [HT]").
    - iIntros "HE'". unfold cctx_interp. iIntros (elt) "Helt".
      iDestruct "Helt" as %->%elem_of_list_singleton. iIntros (ret) "Htl HL HT".
      iMod ("Hclose" with "HE'") as "HE".
      iSpecialize ("HC" with "HE"). unfold cctx_elt_interp.
      iApply ("HC" $! (_ ◁cont(_, _)%CC) with "[%] * Htl HL >").
      { by apply elem_of_list_singleton. }
      rewrite /tctx_interp !big_sepL_singleton /=.
      iDestruct "HT" as (v) "[HP Hown]". iExists v. iFrame "HP".
      iDestruct (Hty x with "LFT [HE0 HEp] HL0") as "(_ & #Hty & _)".
      { rewrite /elctx_interp_0 big_sepL_app. by iSplit. }
      by iApply "Hty".
    - rewrite /tctx_interp
         -(fst_zip (tys x) (tys' x)) ?vec_to_list_length //
         -{1}(snd_zip (tys x) (tys' x)) ?vec_to_list_length //
         !zip_with_fmap_r !(zip_with_zip (λ _ _, (_ ∘ _) _ _)) !big_sepL_fmap.
      iApply big_sepL_impl. iSplit; last done. iIntros "{HT}!#".
      iIntros (i [p [ty1' ty2']]) "#Hzip H /=".
      iDestruct "H" as (v) "[? Hown]". iExists v. iFrame.
      rewrite !lookup_zip_with.
      iDestruct "Hzip" as %(? & ? & ([? ?] & (? & Hty'1 &
        (? & Hty'2 & [=->->])%bind_Some)%bind_Some & [=->->->])%bind_Some)%bind_Some.
      specialize (Htys x). eapply Forall2_lookup_lr in Htys; try done.
      iDestruct (Htys with "* [] [] []") as "(_ & #Ho & _)"; [done| |done|].
      + rewrite /elctx_interp_0 big_sepL_app. by iSplit.
      + by iApply "Ho".
  Qed.

  Lemma fn_subtype_ty {A n} E0 L0 E (tys1 tys2 : A → vec type n) ty1 ty2 :
    (∀ x, Forall2 (subtype (E0 ++ E x) L0) (tys2 x) (tys1 x)) →
    (∀ x, subtype (E0 ++ E x) L0 (ty1 x) (ty2 x)) →
    subtype E0 L0 (fn E tys1 ty1) (fn E tys2 ty2).
  Proof. intros. by apply fn_subtype_full. Qed.

  (* This proper and the next can probably not be inferred, but oh well. *)
  Global Instance fn_subtype_ty' {A n} E0 L0 E :
    Proper (flip (pointwise_relation A (λ (v1 v2 : vec type n), Forall2 (subtype E0 L0) v1 v2)) ==>
            pointwise_relation A (subtype E0 L0) ==> subtype E0 L0) (fn E).
  Proof.
    intros tys1 tys2 Htys ty1 ty2 Hty. apply fn_subtype_ty.
    - intros. eapply Forall2_impl; first eapply Htys. intros ??.
      eapply subtype_weaken; last done. by apply submseteq_inserts_r.
    - intros. eapply subtype_weaken, Hty; last done. by apply submseteq_inserts_r.
  Qed.

  Global Instance fn_eqtype_ty' {A n} E0 L0 E :
    Proper (pointwise_relation A (λ (v1 v2 : vec type n), Forall2 (eqtype E0 L0) v1 v2) ==>
            pointwise_relation A (eqtype E0 L0) ==> eqtype E0 L0) (fn E).
  Proof.
    intros tys1 tys2 Htys ty1 ty2 Hty. split; eapply fn_subtype_ty'; try (by intro; apply Hty);
      intros x; (apply Forall2_flip + idtac); (eapply Forall2_impl; first by eapply (Htys x)); by intros ??[].
  Qed.

  Lemma fn_subtype_elctx_sat {A n} E0 L0 E E' (tys : A → vec type n) ty :
    (∀ x, elctx_sat (E x) [] (E' x)) →
    subtype E0 L0 (fn E' tys ty) (fn E tys ty).
  Proof.
    intros. apply fn_subtype_full; try done. by intros; apply elctx_sat_incl.
  Qed.

  Lemma fn_subtype_lft_incl {A n} E0 L0 E κ κ' (tys : A → vec type n) ty :
    lctx_lft_incl E0 L0 κ κ' →
    subtype E0 L0 (fn (λ x, (κ ⊑ κ') :: E x)%EL tys ty) (fn E tys ty).
  Proof.
    intros Hκκ'. apply fn_subtype_full; try done. intros.
    apply elctx_incl_lft_incl; last by apply elctx_incl_refl.
    iIntros "#HE #HL". iApply (Hκκ' with "[HE] HL").
    rewrite /elctx_interp_0 big_sepL_app. iDestruct "HE" as "[$ _]".
  Qed.

  Lemma fn_subtype_specialize {A B n} (σ : A → B) E0 L0 E tys ty :
    subtype E0 L0 (fn (n:=n) E tys ty) (fn (E ∘ σ) (tys ∘ σ) (ty ∘ σ)).
  Proof.
    apply subtype_simple_type=>//= _ vl.
    iIntros "#LFT _ _ Hf". iDestruct "Hf" as (fb kb xb e ?) "[% [% #Hf]]". subst.
    iExists fb, kb, xb, e, _. iSplit. done. iSplit. done.
    rewrite /typed_body. iNext. iIntros "*". iApply "Hf".
  Qed.

  Lemma type_call' {A} E L E' T p (ps : list path)
                         (tys : A → vec type (length ps)) ty k x :
    elctx_sat E L (E' x) →
    typed_body E L [k ◁cont(L, λ v : vec _ 1, (v!!!0 ◁ ty x) :: T)]
               ((p ◁ fn E' tys ty) :: zip_with TCtx_hasty ps (tys x) ++ T)
               (call: p ps → k).
  Proof.
    iIntros (HE) "!# * #HEAP #LFT Htl HE HL HC".
    rewrite tctx_interp_cons tctx_interp_app. iIntros "(Hf & Hargs & HT)".
    wp_bind p. iApply (wp_hasty with "Hf"). iIntros (v) "% Hf".
    iApply (wp_app_vec _ _ (_::_) ((λ v, ⌜v = k⌝):::
               vmap (λ ty (v : val), tctx_elt_interp tid (v ◁ ty)) (tys x))%I
            with "* [Hargs]"); first wp_done.
    - rewrite /= big_sepL_cons. iSplitR "Hargs"; first by iApply wp_value'.
      clear dependent ty k p.
      rewrite /tctx_interp vec_to_list_map zip_with_fmap_r
              (zip_with_zip (λ e ty, (e, _))) zip_with_zip !big_sepL_fmap.
      iApply (big_sepL_mono' with "Hargs"). iIntros (i [p ty]) "HT/=".
      iApply (wp_hasty with "HT"). setoid_rewrite tctx_hasty_val. iIntros (?) "? $".
    - simpl. change (@length expr ps) with (length ps).
      iIntros (vl'). inv_vec vl'=>kv vl. rewrite /= big_sepL_cons.
      iIntros "/= [% Hvl]". subst kv. iDestruct "Hf" as (fb kb xb e ?) "[EQ [EQl #Hf]]".
      iDestruct "EQ" as %[=->]. iDestruct "EQl" as %EQl. revert vl tys.
      rewrite <-EQl=>vl tys. iApply wp_rec; try done.
      { rewrite -fmap_cons Forall_fmap Forall_forall=>? _. rewrite /= to_of_val. eauto. }
      { rewrite -fmap_cons -(subst_v_eq (fb::kb::xb) (_:::k:::vl)) //. }
      iNext. iSpecialize ("Hf" $! x k vl).
      iMod (HE with "HE HL") as (q') "[HE' Hclose]"; first done.
      iApply ("Hf" with "HEAP LFT Htl HE' [] [HC Hclose HT]").
      + by rewrite /llctx_interp big_sepL_nil.
      + iIntros "HE'". iApply fupd_cctx_interp. iMod ("Hclose" with "HE'") as "[HE HL]".
        iSpecialize ("HC" with "HE"). iModIntro. iIntros (y) "IN".
        iDestruct "IN" as %->%elem_of_list_singleton. iIntros (args) "Htl _ Hret".
        iSpecialize ("HC" with "* []"); first by (iPureIntro; apply elem_of_list_singleton).
        iApply ("HC" $! args with "Htl HL").
        rewrite tctx_interp_singleton tctx_interp_cons. iFrame.
      + rewrite /tctx_interp vec_to_list_map zip_with_fmap_r
                (zip_with_zip (λ v ty, (v, _))) zip_with_zip !big_sepL_fmap.
        iApply (big_sepL_mono' with "Hvl"). by iIntros (i [v ty']).
  Qed.

  Lemma type_call {A} x E L E' C T T' T'' p (ps : list path)
                        (tys : A → vec type (length ps)) ty k :
    (p ◁ fn E' tys ty)%TC ∈ T →
    elctx_sat E L (E' x) →
    tctx_extract_ctx E L (zip_with TCtx_hasty ps (tys x)) T T' →
    (k ◁cont(L, T''))%CC ∈ C →
    (∀ ret : val, tctx_incl E L ((ret ◁ ty x)::T') (T'' [# ret])) →
    typed_body E L C T (call: p ps → k).
  Proof.
    intros Hfn HE HTT' HC HT'T''.
    rewrite -typed_body_mono /flip; last done; first by eapply type_call'.
    - etrans. eapply (incl_cctx_incl _ [_]); first by intros ? ->%elem_of_list_singleton.
      apply cctx_incl_cons_match; first done. intros args. by inv_vec args.
    - etrans; last by apply (tctx_incl_frame_l [_]).
      apply copy_elem_of_tctx_incl; last done. apply _.
  Qed.

  Lemma type_letcall {A} x E L E' C T T' p (ps : list path)
                        (tys : A → vec type (length ps)) ty b e :
    Closed (b :b: []) e → Closed [] p → Forall (Closed []) ps →
    (p ◁ fn E' tys ty)%TC ∈ T →
    elctx_sat E L (E' x) →
    tctx_extract_ctx E L (zip_with TCtx_hasty ps (tys x)) T T' →
    (∀ ret : val, typed_body E L C ((ret ◁ ty x)::T') (subst' b ret e)) →
    typed_body E L C T (letcall: b := p ps in e).
  Proof.
    intros ?? Hpsc ????. eapply (type_cont [_] _ (λ r, (r!!!0 ◁ ty x) :: T')%TC).
    - (* TODO : make [solve_closed] work here. *)
      eapply is_closed_weaken; first done. set_solver+.
    - (* TODO : make [solve_closed] work here. *)
      rewrite /Closed /= !andb_True. split.
      + by eapply is_closed_weaken, list_subseteq_nil.
      + eapply Is_true_eq_left, forallb_forall, List.Forall_forall, Forall_impl=>//.
        intros. eapply Is_true_eq_true, is_closed_weaken=>//. set_solver+.
    - intros.
      (* TODO : make [simpl_subst] work here. *)
      change (subst' "_k" k (p (Var "_k" :: ps))) with
             ((subst "_k" k p) (of_val k :: map (subst "_k" k) ps)).
      rewrite is_closed_nil_subst //.
      assert (map (subst "_k" k) ps = ps) as ->.
      { clear -Hpsc. induction Hpsc=>//=. rewrite is_closed_nil_subst //. congruence. }
      eapply type_call; try done. constructor. done.
    - move=>/= k ret. inv_vec ret=>ret. rewrite /subst_v /=.
      rewrite ->(is_closed_subst []), incl_cctx_incl; first done; try set_solver+.
      apply subst'_is_closed; last done. apply is_closed_of_val.
  Qed.

  Lemma type_rec {A} E L E' fb (argsb : list binder) e
        (tys : A → vec type (length argsb)) ty
        T `{!CopyC T, !SendC T} :
    Closed (fb :b: "return" :b: argsb +b+ []) e →
    (∀ x (f : val) k (args : vec val (length argsb)),
        typed_body (E' x) [] [k ◁cont([], λ v : vec _ 1, [v!!!0 ◁ ty x])]
                   ((f ◁ fn E' tys ty) ::
                      zip_with (TCtx_hasty ∘ of_val) args (tys x) ++ T)
                   (subst_v (fb :: BNamed "return" :: argsb) (f ::: k ::: args) e)) →
    typed_instruction_ty E L T (funrec: fb argsb := e) (fn E' tys ty).
  Proof.
    iIntros (Hc Hbody) "!# * #HEAP #LFT $ $ $ #HT". iApply wp_value.
    { simpl. rewrite ->(decide_left Hc). done. }
    rewrite tctx_interp_singleton. iLöb as "IH". iExists _. iSplit.
    { simpl. rewrite decide_left. done. }
    iExists fb, _, argsb, e, _. iSplit. done. iSplit. done. iNext. clear qE.
    iIntros (x k args) "!#". iIntros (tid' qE) "_ _ Htl HE HL HC HT'".
    iApply (Hbody with "* HEAP LFT Htl HE HL HC").
    rewrite tctx_interp_cons tctx_interp_app. iFrame "HT' IH".
    by iApply sendc_change_tid.
  Qed.

  Lemma type_fn {A} E L E' (argsb : list binder) e
        (tys : A → vec type (length argsb)) ty
        T `{!CopyC T, !SendC T} :
    Closed ("return" :b: argsb +b+ []) e →
    (∀ x k (args : vec val (length argsb)),
        typed_body (E' x) [] [k ◁cont([], λ v : vec _ 1, [v!!!0 ◁ ty x])]
                   (zip_with (TCtx_hasty ∘ of_val) args (tys x) ++ T)
                   (subst_v (BNamed "return" :: argsb) (k ::: args) e)) →
    typed_instruction_ty E L T (funrec: <> argsb := e) (fn E' tys ty).
  Proof.
    intros. apply type_rec; try done. intros. rewrite -typed_body_mono //=.
    eapply contains_tctx_incl. by constructor.
  Qed.
End typing.

Hint Resolve fn_subtype_full : lrust_typing.