weak.v 24.67 KiB
From Coq.QArith Require Import Qcanon.
From iris.proofmode Require Import tactics.
From iris.algebra Require Import auth csum frac agree.
From iris.base_logic Require Import big_op.
From lrust.lang.lib Require Import memcpy.
From lrust.lifetime Require Import na_borrow.
From lrust.typing Require Export type.
From lrust.typing Require Import typing option.
From lrust.typing.lib Require Export rc.
Set Default Proof Using "Type".
Section weak.
Context `{!typeG Σ, !rcG Σ}.
Program Definition weak (ty : type) :=
{| ty_size := 1;
ty_own tid vl :=
match vl return _ with
| [ #(LitLoc l) ] => ∃ γ ν, rc_persist tid ν γ l ty ∗ own γ weak_tok
| _ => False end;
ty_shr κ tid l :=
∃ (l' : loc), &frac{κ} (λ q, l ↦{q} #l') ∗
□ ∀ F q, ⌜↑shrN ∪ lftE ⊆ F⌝ -∗ q.[κ]
={F, F∖↑shrN}▷=∗ q.[κ] ∗ ∃ γ ν, rc_persist tid ν γ l' ty ∗
&na{κ, tid, rc_shrN}(own γ weak_tok)
|}%I.
Next Obligation. by iIntros (ty tid [|[[]|][]]) "H". Qed.
Next Obligation.
iIntros (ty E κ l tid q ?) "#LFT Hb Htok".
iMod (bor_exists with "LFT Hb") as (vl) "Hb"; first done.
iMod (bor_sep with "LFT Hb") as "[H↦ Hb]"; first done.
(* Ideally, we'd change ty_shr to say "l ↦{q} #l" in the fractured borrow,
but that would be additional work here... *)
iMod (bor_fracture (λ q, l ↦∗{q} vl)%I with "LFT H↦") as "#H↦"; first done.
destruct vl as [|[[|l'|]|][|]];
try by iMod (bor_persistent_tok with "LFT Hb Htok") as "[>[] _]".
setoid_rewrite heap_mapsto_vec_singleton.
iFrame "Htok". iExists _. iFrame "#". rewrite bor_unfold_idx.
iDestruct "Hb" as (i) "(#Hpb&Hpbown)".
set (C := (∃ _ _, _ ∗ &na{_,_,_} _)%I).
iMod (inv_alloc shrN _ (idx_bor_own 1 i ∨ C)%I with "[Hpbown]") as "#Hinv";
first by iLeft.
iIntros "!> !# * % Htok".
iMod (inv_open with "Hinv") as "[INV Hclose1]"; first solve_ndisj.
iDestruct "INV" as "[>Hbtok|#Hshr]".
- iAssert (&{κ} _)%I with "[Hbtok]" as "Hb".
{ rewrite bor_unfold_idx. iExists _. by iFrame. }
iClear "H↦ Hinv Hpb".
iMod (bor_acc_cons with "LFT Hb Htok") as "[HP Hclose2]"; first solve_ndisj.
iDestruct "HP" as (γ ν) "(#Hpersist & Hweak)".
iModIntro. iNext. iMod ("Hclose2" with "[] Hweak") as "[Hb $]"; first by auto 10.
iAssert C with "[>Hb]" as "#HC".
{ iExists _, _. iFrame "Hpersist". iApply (bor_na with "Hb"). solve_ndisj. }
iMod ("Hclose1" with "[]") as "_"; by auto.
- iMod ("Hclose1" with "[]") as "_"; first by auto.
iApply step_fupd_intro; first solve_ndisj. auto.
Qed.
Next Obligation.
iIntros (ty κ κ' tid l) "#Hincl H". iDestruct "H" as (l') "[#Hl #Hshr]".
iExists _. iSplit; first by iApply frac_bor_shorten.
iAlways. iIntros (F q) "% Htok".
iMod (lft_incl_acc with "Hincl Htok") as (q'') "[Htok Hclose]"; first solve_ndisj.
iMod ("Hshr" with "[] Htok") as "Hshr2"; first done.
iModIntro. iNext. iMod "Hshr2" as "[Htok HX]".
iMod ("Hclose" with "Htok") as "$". iDestruct "HX" as (? ν) "(? & ?)".
iExists _, _. iFrame. by iApply na_bor_shorten.
Qed.
Global Instance weak_wf ty `{!TyWf ty} : TyWf (weak ty) :=
{ ty_lfts := ty.(ty_lfts); ty_wf_E := ty.(ty_wf_E) }.
Global Instance weak_type_contractive : TypeContractive weak.
Proof.
constructor;
solve_proper_core ltac:(fun _ => exact: type_dist2_S || exact: type_dist2_dist ||
f_type_equiv || f_contractive || f_equiv).
Qed.
Global Instance weak_ne : NonExpansive weak.
Proof. apply type_contractive_ne, _. Qed.
Lemma weak_subtype ty1 ty2 :
type_incl ty1 ty2 -∗ type_incl (weak ty1) (weak ty2).
Proof.
iIntros "#Hincl". iPoseProof "Hincl" as "(Hsz & #Hoincl & #Hsincl)".
iSplit; first done. iSplit; iAlways.
- iIntros "* Hvl". destruct vl as [|[[|vl|]|] [|]]; try done.
iDestruct "Hvl" as (γ ν) "(#Hpersist & Htok)".
iExists _, _. iFrame "Htok". by iApply rc_persist_type_incl.
- iIntros "* #Hshr". iDestruct "Hshr" as (l') "[Hfrac Hshr]". iExists l'.
iIntros "{$Hfrac} !# * % Htok". iMod ("Hshr" with "[% //] Htok") as "{Hshr} H".
iModIntro. iNext. iMod "H" as "[$ H]". iDestruct "H" as (γ ν) "(Hpersist & Hshr)".
iExists _, _. iFrame "Hshr". by iApply rc_persist_type_incl.
Qed.
Global Instance weak_mono E L :
Proper (subtype E L ==> subtype E L) weak.
Proof.
iIntros (ty1 ty2 Hsub ?) "HL". iDestruct (Hsub with "HL") as "#Hsub".
iIntros "!# #HE". iApply weak_subtype. iApply "Hsub"; done.
Qed.
Global Instance weak_proper E L :
Proper (eqtype E L ==> eqtype E L) weak.
Proof. intros ??[]. by split; apply weak_mono. Qed.
End weak.
Section code.
Context `{!typeG Σ, !rcG Σ}.
Definition rc_upgrade : val :=
funrec: <> ["w"] :=
let: "r" := new [ #2 ] in
withcont: "k":
let: "w'" := !"w" in
let: "w''" := !"w'" in
let: "strong" := !("w''" +ₗ #0) in
if: "strong" = #0 then
"r" <-{Σ none} ();;
"k" []
else
"w''" +ₗ #0 <- "strong" + #1;;
"r" <-{Σ some} "w''";;
"k" []
cont: "k" [] :=
delete [ #1; "w" ];; return: ["r"].
Lemma rc_upgrade_type ty `{!TyWf ty} :
typed_val rc_upgrade (fn(∀ α, ∅; &shr{α} weak ty) → option (rc ty)).
Proof.
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (α ϝ ret arg). inv_vec arg=>w. simpl_subst.
iApply (type_new 2); [solve_typing..|]; iIntros (r); simpl_subst.
iApply (type_cont [] [ϝ ⊑ₗ []]
(λ _, [w ◁ box (&shr{α} weak ty); r ◁ box (option (rc ty))])) ;
[solve_typing..| |]; last first.
{ simpl. iAlways. iIntros (k arg). inv_vec arg. simpl_subst.
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing. }
iIntros (k). simpl_subst.
iApply type_deref; [solve_typing..|]; iIntros (w'); simpl_subst.
iIntros (tid) "#LFT #HE Hna HL Hk [Hw [Hw' [Hr _]]]".
rewrite !tctx_hasty_val [[w]]lock.
destruct w' as [[|lw|]|]; try done. iDestruct "Hw'" as (l') "[#Hlw #Hshr]".
iDestruct (ownptr_uninit_own with "Hr") as (lr vlr) "(% & Hr & Hr†)".
subst r. inv_vec vlr=>r0 r1. rewrite !heap_mapsto_vec_cons.
iDestruct "Hr" as "(Hr1 & Hr2 & _)".
(* All right, we are done preparing our context. Let's get going. *)
iMod (lctx_lft_alive_tok α with "HE HL") as (q) "([Hα1 Hα2] & HL & Hclose1)"; [solve_typing..|].
wp_bind (!_)%E.
iSpecialize ("Hshr" with "[] Hα1"); last iApply (wp_step_fupd with "Hshr"); [done..|].
iMod (frac_bor_acc with "LFT Hlw Hα2") as (q') "[Hlw↦ Hclose]"; first solve_ndisj.
iApply wp_fupd. wp_read.
iMod ("Hclose" with "[$Hlw↦]") as "Hα2". iIntros "!> [Hα1 Hproto]".
iDestruct "Hproto" as (γ ν) "#(Hpersist & Hwtokb)".
iModIntro. wp_let. wp_op. rewrite shift_loc_0.
(* Finally, finally... opening the thread-local Rc protocol. *)
iPoseProof "Hpersist" as (ty') "(_ & Hinv & _ & _)".
iMod (na_inv_open with "Hinv Hna") as "(Hrcproto & Hna & Hclose2)"; [solve_ndisj..|].
iMod (na_bor_acc with "LFT Hwtokb Hα1 Hna") as "(>Hwtok & Hna & Hclose3)"; [solve_ndisj..|].
iDestruct "Hrcproto" as ([st weakc]) "[>Hrc● Hrcst]".
iDestruct (own_valid_2 with "Hrc● Hwtok") as
%[[_ Hweak%nat_included]%prod_included [Hval _]]%auth_valid_discrete_2.
destruct st as [[[q'' strong]| |]|]; try done.
- (* Success case. *)
iDestruct "Hrcst" as (qb) "(Hl'1 & Hl'2 & Hl'† & >Hq''q0 & [Hν1 Hν2] & Hν†)".
iDestruct "Hq''q0" as %Hq''q0.
wp_read. wp_let. wp_op=>[//|_]. wp_if. wp_op. rewrite shift_loc_0. wp_op. wp_write.
(* Closing the invariant. *)
iMod (own_update with "Hrc●") as "[Hrc● Hrctok2]".
{ apply auth_update_alloc, prod_local_update_1,
(op_local_update_discrete _ _ (Some (Cinl ((qb/2)%Qp, 1%positive))))=>-[/= Hqa _].
split; simpl; last done. apply frac_valid'.
rewrite -Hq''q0 comm_L -{2}(Qp_div_2 qb).
apply Qcplus_le_mono_l. rewrite -{1}(Qcplus_0_l (_ / _)%Qp).
apply Qcplus_le_mono_r, Qp_ge_0. }
rewrite right_id -Some_op Cinl_op pair_op.
iMod ("Hclose3" with "[$Hwtok] Hna") as "[Hα1 Hna]".
iMod ("Hclose2" with "[Hrc● Hl'1 Hl'2 Hl'† Hν2 Hν† $Hna]") as "Hna".
{ iExists _. iFrame "Hrc●". iExists _. rewrite Z.add_comm. iFrame.
rewrite [_ ⋅ _]comm frac_op' -[(_ + _)%Qp]assoc Qp_div_2. auto. }
iMod ("Hclose1" with "[$Hα1 $Hα2] HL") as "HL".
(* Finish up the proof. *)
iApply (type_type _ _ _ [ w ◁ box (&shr{α} weak ty); #lr ◁ box (uninit 2);
#l' ◁ rc ty ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite 2!tctx_interp_cons tctx_interp_singleton tctx_hasty_val !tctx_hasty_val' //.
unlock. iFrame "Hr† Hw". iSplitL "Hr1 Hr2".
- setoid_rewrite uninit_own. iExists [_;_].
rewrite heap_mapsto_vec_cons heap_mapsto_vec_singleton. auto with iFrame.
- iRight. auto with iFrame. }
iApply (type_sum_assign (option (rc ty))); [solve_typing..|].
iApply type_jump; solve_typing.
- (* Failure : dropping *)
(* TODO : The two failure cases are almost identical. *)
iDestruct "Hrcst" as "[Hl'1 Hl'2]". wp_read. wp_let. wp_op=>[_|//]. wp_if.
(* Closing the invariant. *)
iMod ("Hclose3" with "[$Hwtok] Hna") as "[Hα1 Hna]".
iMod ("Hclose2" with "[Hrc● Hl'1 Hl'2 $Hna]") as "Hna".
{ iExists _. auto with iFrame. }
iMod ("Hclose1" with "[$Hα1 $Hα2] HL") as "HL".
(* Finish up the proof. *)
iApply (type_type _ _ _ [ w ◁ box (&shr{α} weak ty); #lr ◁ box (uninit 2) ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton tctx_hasty_val tctx_hasty_val' //.
unlock. iFrame. setoid_rewrite uninit_own. iExists [_;_].
rewrite heap_mapsto_vec_cons heap_mapsto_vec_singleton. auto with iFrame. }
iApply (type_sum_unit (option (rc ty))); [solve_typing..|].
iApply type_jump; solve_typing.
- (* Failure : general case *)
destruct weakc as [|weakc]; first by simpl in *; lia.
iDestruct "Hrcst" as "[Hl'1 Hrcst]". wp_read. wp_let. wp_op=>[_|//]. wp_if.
(* Closing the invariant. *)
iMod ("Hclose3" with "[$Hwtok] Hna") as "[Hα1 Hna]".
iMod ("Hclose2" with "[Hrc● Hl'1 Hrcst $Hna]") as "Hna".
{ iExists _. auto with iFrame. }
iMod ("Hclose1" with "[$Hα1 $Hα2] HL") as "HL".
(* Finish up the proof. *)
iApply (type_type _ _ _ [ w ◁ box (&shr{α} weak ty); #lr ◁ box (uninit 2) ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton tctx_hasty_val tctx_hasty_val' //.
unlock. iFrame. setoid_rewrite uninit_own. iExists [_;_].
rewrite heap_mapsto_vec_cons heap_mapsto_vec_singleton. auto with iFrame. }
iApply (type_sum_unit (option (rc ty))); [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
Definition rc_downgrade : val :=
funrec: <> ["rc"] :=
let: "r" := new [ #1 ] in
let: "rc'" := !"rc" in
let: "rc''" := !"rc'" in
let: "weak" := !("rc''" +ₗ #1) in
"rc''" +ₗ #1 <- "weak" + #1;;
"r" <- "rc''";;
delete [ #1; "rc" ];; return: ["r"].
Lemma rc_downgrade_type ty `{!TyWf ty} :
typed_val rc_downgrade (fn(∀ α, ∅; &shr{α} rc ty) → weak ty).
Proof.
(* TODO : this is almost identical to rc_clone *)
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (α ϝ ret arg). inv_vec arg=>x. simpl_subst.
iApply (type_new 1); [solve_typing..|]; iIntros (r); simpl_subst.
iApply type_deref; [solve_typing..|]; iIntros (rc'); simpl_subst.
iIntros (tid) "#LFT #HE Hna HL Hk [Hx [Hrc' [Hr _]]]".
rewrite !tctx_hasty_val [[x]]lock.
destruct rc' as [[|lrc|]|]; try done. iDestruct "Hrc'" as (l') "[#Hlrc #Hshr]".
iDestruct (ownptr_uninit_own with "Hr") as (lr vlr) "(% & Hr & Hr†)".
subst r. inv_vec vlr=>r. rewrite heap_mapsto_vec_singleton.
(* All right, we are done preparing our context. Let's get going. *)
iMod (lctx_lft_alive_tok α with "HE HL") as (q) "([Hα1 Hα2] & HL & Hclose1)"; [solve_typing..|].
wp_bind (!_)%E.
iSpecialize ("Hshr" with "[] Hα1"); last iApply (wp_step_fupd with "Hshr"); [done..|].
iMod (frac_bor_acc with "LFT Hlrc Hα2") as (q') "[Hlrc↦ Hclose]"; first solve_ndisj.
iApply wp_fupd. wp_read.
iMod ("Hclose" with "[$Hlrc↦]") as "Hα2". iIntros "!> [Hα1 Hproto]".
iDestruct "Hproto" as (γ ν q'') "#(Hαν & Hpersist & Hrctokb)".
iModIntro. wp_let. wp_op.
(* Finally, finally... opening the thread-local Rc protocol. *)
iPoseProof "Hpersist" as (ty') "(_ & Hinv & _ & _)".
iMod (na_inv_open with "Hinv Hna") as "(Hrcproto & Hna & Hclose2)"; [solve_ndisj..|].
iMod (na_bor_acc with "LFT Hrctokb Hα1 Hna") as "(>Hrctok & Hna & Hclose3)"; [solve_ndisj..|].
iDestruct "Hrcproto" as ([st weakc]) "[>Hrc● Hrcst]".
iDestruct (own_valid_2 with "Hrc● Hrctok") as %[[[[=]|(?&[[q0 weak0]| |]&[=<-]&?&Hincl)]
%option_included _]%prod_included [Hval _]]%auth_valid_discrete_2;
setoid_subst; try done; last first.
{ exfalso. destruct Hincl as [Hincl|Hincl]. by inversion Hincl.
apply csum_included in Hincl. naive_solver. }
iDestruct "Hrcst" as (qb) "(Hl'1 & Hl'2 & Hrcst)".
wp_read. wp_let. wp_op. wp_op. wp_write. wp_write.
(* And closing it again. *)
iMod (own_update with "Hrc●") as "[Hrc● Hrctok2]".
{ by apply auth_update_alloc, prod_local_update_2, (op_local_update_discrete _ _ 1%nat). }
iMod ("Hclose3" with "[$Hrctok] Hna") as "[Hα1 Hna]".
iMod ("Hclose2" with "[Hrc● Hl'1 Hl'2 Hrcst $Hna]") as "Hna".
{ iExists _. iFrame "Hrc●". iExists _. rewrite /Z.add Pos.add_1_r. iFrame. }
iMod ("Hclose1" with "[$Hα1 $Hα2] HL") as "HL".
(* Finish up the proof. *)
iApply (type_type _ _ _ [ x ◁ box (&shr{α} rc ty); #lr ◁ box (weak ty)]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton tctx_hasty_val tctx_hasty_val' //.
unlock. iFrame "Hx". iFrame "Hr†". iExists [_].
rewrite heap_mapsto_vec_singleton /=. eauto 10 with iFrame. }
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
(* Exact same code as downgrade *)
Definition weak_clone : val :=
funrec: <> ["w"] :=
let: "r" := new [ #1 ] in
let: "w'" := !"w" in
let: "w''" := !"w'" in
let: "weak" := !("w''" +ₗ #1) in
"w''" +ₗ #1 <- "weak" + #1;;
"r" <- "w''";;
delete [ #1; "w" ];; return: ["r"].
Lemma weak_clone_type ty `{!TyWf ty} :
typed_val weak_clone (fn(∀ α, ∅; &shr{α} weak ty) → weak ty).
Proof.
(* TODO : this is almost identical to rc_clone *)
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (α ϝ ret arg). inv_vec arg=>x. simpl_subst.
iApply (type_new 1); [solve_typing..|]; iIntros (r); simpl_subst.
iApply type_deref; [solve_typing..|]; iIntros (rc'); simpl_subst.
iIntros (tid) "#LFT #HE Hna HL Hk [Hx [Hrc' [Hr _]]]".
rewrite !tctx_hasty_val [[x]]lock.
destruct rc' as [[|lrc|]|]; try done. iDestruct "Hrc'" as (l') "[#Hlrc #Hshr]".
iDestruct (ownptr_uninit_own with "Hr") as (lr vlr) "(% & Hr & Hr†)".
subst r. inv_vec vlr=>r. rewrite heap_mapsto_vec_singleton.
(* All right, we are done preparing our context. Let's get going. *)
iMod (lctx_lft_alive_tok α with "HE HL") as (q) "([Hα1 Hα2] & HL & Hclose1)"; [solve_typing..|].
wp_bind (!_)%E.
iSpecialize ("Hshr" with "[] Hα1"); last iApply (wp_step_fupd with "Hshr"); [done..|].
iMod (frac_bor_acc with "LFT Hlrc Hα2") as (q') "[Hlrc↦ Hclose]"; first solve_ndisj.
iApply wp_fupd. wp_read.
iMod ("Hclose" with "[$Hlrc↦]") as "Hα2". iIntros "!> [Hα1 Hproto]".
iDestruct "Hproto" as (γ ν) "#[Hpersist Hwtokb]".
iModIntro. wp_let. wp_op.
(* Finally, finally... opening the thread-local Rc protocol. *)
iPoseProof "Hpersist" as (ty') "(_ & Hinv & _ & _)".
iAssert (∃ wv : Z, shift_loc l' 1 ↦ #wv ∗ (shift_loc l' 1 ↦ #(wv + 1) ={⊤}=∗
na_own tid ⊤ ∗ (q / 2).[α] ∗ own γ weak_tok))%I
with "[> Hna Hα1]" as (wv) "[Hwv Hclose2]".
{ iMod (na_inv_open with "Hinv Hna") as "(Hrcproto & Hna & Hclose2)"; [solve_ndisj..|].
iMod (na_bor_acc with "LFT Hwtokb Hα1 Hna") as "(>Hwtok & Hna & Hclose3)"; [solve_ndisj..|].
iDestruct "Hrcproto" as ([st weakc]) "[>Hrc● Hrcst]".
iDestruct (own_valid_2 with "Hrc● Hwtok") as
%[[_ Hweak%nat_included]%prod_included [Hval _]]%auth_valid_discrete_2.
iMod (own_update with "Hrc●") as "[Hrc● $]".
{ by apply auth_update_alloc, prod_local_update_2,
(op_local_update_discrete _ _ 1%nat). }
destruct st as [[[q'' strong]| |]|]; try done.
- iExists _. iDestruct "Hrcst" as (q0) "(Hl'1 & >$ & Hrcst)".
iIntros "!> Hl'2". iMod ("Hclose3" with "[$Hwtok] Hna") as "[$ Hna]".
iApply ("Hclose2" with "[- $Hna]"). iExists _. iFrame "Hrc●".
iExists _. rewrite /Z.add /= Pos.add_1_r. iFrame.
- iExists _. iDestruct "Hrcst" as "[Hl'1 >$]". iIntros "!> Hl'2".
iMod ("Hclose3" with "[$Hwtok] Hna") as "[$ Hna]".
iApply ("Hclose2" with "[- $Hna]"). iExists _. iFrame "Hrc●".
rewrite /Z.add /= Pos.add_1_r. iFrame.
- destruct weakc as [|weakc]; first by simpl in Hweak; lia.
iExists _. iDestruct "Hrcst" as "(Hl'1 & >$ & Hrcst)". iIntros "!> Hl'2".
iMod ("Hclose3" with "[$Hwtok] Hna") as "[$ Hna]".
iApply ("Hclose2" with "[- $Hna]"). iExists _. iFrame "Hrc●".
rewrite /Z.add /= Pos.add_1_r. iFrame. }
wp_read. wp_let. wp_op. wp_op. wp_write.
iMod ("Hclose2" with "Hwv") as "(Hna & Hα1 & Hwtok)".
iMod ("Hclose1" with "[$Hα1 $Hα2] HL") as "HL". wp_write.
(* Finish up the proof. *)
iApply (type_type _ _ _ [ x ◁ box (&shr{α} weak ty); #lr ◁ box (weak ty)]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton tctx_hasty_val tctx_hasty_val' //.
unlock. iFrame. iExists [_]. rewrite heap_mapsto_vec_singleton /=.
auto 10 with iFrame. }
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
Definition weak_drop ty : val :=
funrec: <> ["w"] :=
withcont: "k":
let: "w'" := !"w" in
let: "weak" := !("w'" +ₗ #1) in
if: "weak" = #1 then
delete [ #(2 + ty.(ty_size)); "w'" ];;
"k" []
else
"w'" +ₗ #1 <- "weak" - #1;;
"k" []
cont: "k" [] :=
let: "r" := new [ #0] in
delete [ #1; "w"];; return: ["r"].
Lemma weak_drop_type ty `{!TyWf ty} :
typed_val (weak_drop ty) (fn(∅; weak ty) → unit).
Proof.
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (_ ϝ ret arg). inv_vec arg=>w. simpl_subst.
iApply (type_cont [] [ϝ ⊑ₗ []] (λ _, [w ◁ box (uninit 1)]));
[solve_typing..| |]; last first.
{ simpl. iAlways. iIntros (k arg). inv_vec arg. simpl_subst.
iApply type_new; [solve_typing..|]. iIntros (r). simpl_subst.
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing. }
iIntros (k). simpl_subst.
iApply type_deref; [solve_typing..|]; iIntros (w'); simpl_subst.
iIntros (tid) "#LFT #HE Hna HL Hk [Hw [Hw' _]]".
rewrite !tctx_hasty_val [[w]]lock. destruct w' as [[|lw|]|]; try done. wp_op.
iDestruct "Hw'" as (γ ν) "[#Hpersist Hwtok]".
iAssert (∃ wv : Z, shift_loc lw 1 ↦ #wv ∗
((⌜wv = 1⌝ ∗ na_own tid ⊤ ∗
∃ s, lw ↦ s ∗ (shift_loc lw 2 ↦∗: λ vl, ⌜length vl = ty.(ty_size)⌝) ∗
† lw … (2 + ty_size ty)) ∨
(⌜wv > 1⌝ ∗ (shift_loc lw 1 ↦ #(wv - 1) ={⊤}=∗ na_own tid ⊤))))%I
with "[>Hna Hwtok]" as (wv) "[Hlw [(% & Hna & H)|[% Hclose]]]".
{ iPoseProof "Hpersist" as (ty') "([>Hszeq _] & Hinv & _ & _)".
iDestruct "Hszeq" as %Hszeq.
iMod (na_inv_open with "Hinv Hna") as "(Hrcproto & Hna & Hclose)"; [solve_ndisj..|].
iDestruct "Hrcproto" as ([st weakc]) "[>Hrc● Hrcst]".
iDestruct (own_valid_2 with "Hrc● Hwtok") as
%[[_ Hweak%nat_included]%prod_included [Hval _]]%auth_valid_discrete_2.
destruct weakc; first by simpl in *; lia.
iMod (own_update_2 with "Hrc● Hwtok") as "Hrc●".
{ apply auth_update_dealloc, prod_local_update_2,
(cancel_local_update_empty 1%nat), _. }
destruct st as [[[q'' strong]| |]|]; try done.
- iExists _. iDestruct "Hrcst" as (q0) "(Hlw & >$ & Hrcst)". iRight.
iSplitR; first by auto with lia. iIntros "!>?". iApply "Hclose". iFrame.
iExists _. iFrame. iExists _. iFrame. simpl. destruct Pos.of_succ_nat; try done.
by rewrite /= Pos.pred_double_succ.
- iExists _. iDestruct "Hrcst" as "[Hlw >$]". iRight.
iSplitR; first by auto with lia. iIntros "!>?". iApply "Hclose". iFrame.
iExists _. iFrame. simpl. destruct Pos.of_succ_nat; try done.
by rewrite /= Pos.pred_double_succ.
- iExists _. iDestruct "Hrcst" as "(>Hlw & >$ & >H† & >H)". destruct weakc.
+ iLeft. iSplitR; first done. iMod ("Hclose" with "[$Hna Hrc●]") as "$".
{ iExists _. iFrame. }
rewrite Hszeq. auto with iFrame.
+ iRight. iSplitR; first by auto with lia. iIntros "!>?". iApply "Hclose".
iFrame. iExists _. iFrame. simpl. destruct Pos.of_succ_nat; try done.
by rewrite /= Pos.pred_double_succ. }
- subst. wp_read. wp_let. wp_op=>[_|//]. wp_if.
iApply (type_type _ _ _ [ w ◁ box (uninit 1); #lw ◁ box (uninit (2 + ty.(ty_size))) ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton tctx_hasty_val tctx_hasty_val' //.
unlock. iFrame. iDestruct "H" as (?) "(? & H↦ & ?)". iDestruct "H↦" as (?) "[? %]".
rewrite /= freeable_sz_full_S. iFrame. iExists (_::_::_).
rewrite 2!heap_mapsto_vec_cons shift_loc_assoc uninit_own. iFrame.
iIntros "!>!%". simpl. congruence. }
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing.
- wp_read. wp_let. wp_op=>[|_]; first lia. wp_if. wp_op. wp_op. wp_write.
iMod ("Hclose" with "Hlw") as "Hna".
iApply (type_type _ _ _ [ w ◁ box (uninit 1) ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ unlock. by rewrite tctx_interp_singleton tctx_hasty_val. }
iApply type_jump; solve_typing.
Qed.
Definition weak_new ty : val :=
funrec: <> [] :=
let: "rcbox" := new [ #(2 + ty.(ty_size))%nat ] in
let: "w" := new [ #1 ] in
"rcbox" +ₗ #0 <- #0;;
"rcbox" +ₗ #1 <- #1;;
"w" <- "rcbox";;
return: ["w"].
Lemma weak_new_type ty `{!TyWf ty} :
typed_val (weak_new ty) (fn(∅) → weak ty).
Proof.
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (_ ϝ ret arg). inv_vec arg. simpl_subst.
iApply (type_new (2 + ty.(ty_size))); [solve_typing..|]; iIntros (rcbox); simpl_subst.
iApply (type_new 1); [solve_typing..|]; iIntros (w); simpl_subst.
iIntros (tid) "#LFT #HE Hna HL Hk [Hw [Hrcbox _]]". rewrite !tctx_hasty_val.
iDestruct (ownptr_uninit_own with "Hrcbox") as (lrcbox vlrcbox)
"(% & Hrcbox↦ & Hrcbox†)". subst rcbox. inv_vec vlrcbox=>??? /=.
iDestruct (heap_mapsto_vec_cons with "Hrcbox↦") as "[Hrcbox↦0 Hrcbox↦1]".
iDestruct (heap_mapsto_vec_cons with "Hrcbox↦1") as "[Hrcbox↦1 Hrcbox↦2]".
iDestruct (ownptr_uninit_own with "Hw") as (lw vlw) "(% & Hw↦ & Hw†)". subst w.
inv_vec vlw=>?. rewrite heap_mapsto_vec_singleton.
(* All right, we are done preparing our context. Let's get going. *)
wp_op. rewrite shift_loc_0. wp_write. wp_op. wp_write.
iMod (lft_create with "LFT") as (ν) "[Hν #Hν†]"; first done.
iPoseProof ("Hν†" with "Hν") as "H†". wp_bind (_ <- _)%E.
iApply wp_mask_mono; last iApply (wp_step_fupd with "H†"); [solve_ndisj..|].
wp_write. iIntros "#Hν !>". wp_seq.
iApply (type_type _ _ _ [ #lw ◁ box (weak ty)]
with "[] LFT HE Hna HL Hk [> -]"); last first.
{ rewrite tctx_interp_singleton tctx_hasty_val' //=. iFrame.
iExists [_]. rewrite heap_mapsto_vec_singleton. iFrame.
iMod (own_alloc (● _ ⋅ ◯ _)) as (γ) "[??]"; last (iExists _, _; iFrame).
{ apply auth_valid_discrete_2. by split. }
iExists ty. iFrame "Hν†". iSplitR; first by iApply type_incl_refl.
iSplitL; last by iRight. iMod (na_inv_alloc with "[-]") as "$"; last done.
iExists _. iFrame. rewrite freeable_sz_full_S shift_loc_assoc. iFrame.
iExists _. iFrame. rewrite vec_to_list_length. auto. }
iApply type_jump; solve_typing.
Qed.
End code.