Skip to content
Snippets Groups Projects
Forked from Iris / lambda-rust
543 commits behind the upstream repository.
join.v 4.51 KiB
From iris.proofmode Require Import tactics.
From iris.base_logic Require Import big_op.
From lrust.lang Require Import spawn.
From lrust.typing Require Export type.
From lrust.typing Require Import typing.
Set Default Proof Using "Type".

Definition joinN := lrustN .@ "join".

Section join.
  Context `{!typeG Σ, !spawnG Σ}.

  (* This model is very far from rayon::join, which uses a persistent
     work-stealing thread-pool.  Still, the important bits are right:
     One of the closures is executed in another thread, and the
     closures can refer to on-stack data (no 'static' bound). *)
  Definition join (call_once_A call_once_B : val) (R_A R_B : type) : val :=
    funrec: <> ["fA"; "fB"] :=
      let: "call_once_A" := call_once_A in
      let: "call_once_B" := call_once_B in
      let: "join" := spawn [λ: ["c"],
                            letcall: "r" := "call_once_A" ["fA"]%E in
                            finish ["c"; "r"]] in
      letcall: "retB" := "call_once_B" ["fB"]%E in
      let: "retA" := join ["join"] in
      (* Put the results in a pair. *)
      let: "ret" := new [ #(R_A.(ty_size) + R_B.(ty_size)) ] in
      "ret" +ₗ #0 <-{R_A.(ty_size)} !"retA";;
      "ret" +ₗ #R_A.(ty_size) <-{R_B.(ty_size)} !"retB";;
      delete [ #R_A.(ty_size); "retA"] ;; delete [ #R_B.(ty_size); "retB"] ;;
      return: ["ret"].

  Lemma join_type A B R_A R_B call_once_A call_once_B
        `{!TyWf A, !TyWf B, !TyWf R_A, !TyWf R_B}
        `(!Send A, !Send B, !Send R_A, !Send R_B) :
    (* A : FnOnce() -> R_A, as witnessed by the impl call_once_A *)
    typed_val call_once_A (fn(∅; A) → R_A) →
    (* B : FnOnce() -> R_B, as witnessed by the impl call_once_B *)
    typed_val call_once_B (fn(∅; B) → R_B) →
    typed_val (join call_once_A call_once_B R_A R_B) (fn(∅; A, B) → Π[R_A; R_B]).
  Proof using Type*.
    intros HfA HfB E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
      iIntros (_ ϝ ret arg). inv_vec arg=>envA envB. simpl_subst.
    iApply type_let; [apply HfA|solve_typing|]. iIntros (fA); simpl_subst.
    iApply type_let; [apply HfB|solve_typing|]. iIntros (fB); simpl_subst.
    (* Drop to Iris. *)
    iIntros (tid) "#LFT #HE Hna HL Hk (HfB & HfA & HenvA & HenvB & _)".
    iMod (lctx_lft_alive_tok ϝ with "HE HL") as (qϝ1) "(Hϝ1 & HL & Hclose1)";
      [solve_typing..|].
    (* FIXME: using wp_apply here breaks calling solve_to_val. *)
    wp_bind (spawn _).
    iApply ((spawn_spec joinN (λ v, (box R_A).(ty_own) tid [v] ∗ (qϝ1).[ϝ])%I) with "[HfA HenvA Hϝ1]");
      first solve_to_val; first simpl_subst.
    { (* The new thread. *)
      iIntros (c) "Hfin". iMod na_alloc as (tid') "Htl". wp_let. wp_let. unlock.
      rewrite !tctx_hasty_val.
      iApply (type_call_iris _ [ϝ] () [_] with "LFT HE Htl [Hϝ1] HfA [HenvA]").
      - rewrite outlives_product. solve_typing.
      - solve_to_val.
      - by rewrite /= (right_id static).
      - by rewrite big_sepL_singleton tctx_hasty_val send_change_tid.
      - iIntros (r) "Htl Hϝ1 Hret".
        wp_rec. iApply (finish_spec with "[$Hfin Hret Hϝ1]"); last auto.
        rewrite right_id. iFrame. by iApply @send_change_tid. }
    iNext. iIntros (c) "Hjoin". wp_let. wp_let.
    iMod (lctx_lft_alive_tok ϝ with "HE HL") as (qϝ2) "(Hϝ2 & HL & Hclose2)";
      [solve_typing..|].
    rewrite !tctx_hasty_val.
    iApply (type_call_iris _ [ϝ] () [_] with "LFT HE Hna [Hϝ2] HfB [HenvB]").
    { rewrite outlives_product. solve_typing. }
    { solve_to_val. }
    { by rewrite /= (right_id static). }
    { by rewrite big_sepL_singleton tctx_hasty_val. }
    (* The return continuation after calling fB in the main thread. *)
    iIntros (retB) "Hna Hϝ2 HretB". rewrite /= (right_id static).
    iMod ("Hclose2" with "Hϝ2 HL") as "HL". wp_rec.
    wp_apply (join_spec with "Hjoin"). iIntros (retA) "[HretA Hϝ1]".
    iMod ("Hclose1" with "Hϝ1 HL") as "HL". wp_let.
    (* Switch back to type system mode. *)
    iApply (type_type _ _ _ [ retA ◁ box R_A; retB ◁ box R_B ]
        with "[] LFT HE Hna HL Hk [-]"); last first.
    { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val. iFrame. }
    iApply (type_new_subtype (Π[uninit R_A.(ty_size); uninit R_B.(ty_size)]));
      (* FIXME: solve_typing should handle this without any aid. *)
      rewrite ?Z_nat_add; [solve_typing..|].
    iIntros (r); simpl_subst.
    iApply (type_memcpy R_A); [solve_typing..|].
    iApply (type_memcpy R_B); [solve_typing..|].
    iApply type_delete; [solve_typing..|].
    iApply type_delete; [solve_typing..|].
    iApply type_jump; solve_typing.
  Qed.

End join.