From 57377e45f4f29b073986dbb50008e7775ad3967e Mon Sep 17 00:00:00 2001
From: Yusuke Matsushita <y.skm24t@gmail.com>
Date: Thu, 17 Mar 2022 23:33:57 +0900
Subject: [PATCH] Verify smallvec_pop

---
 _CoqProject                                 |   1 +
 theories/typing/lib/smallvec/smallvec_pop.v | 146 ++++++++++++++++++++
 2 files changed, 147 insertions(+)
 create mode 100644 theories/typing/lib/smallvec/smallvec_pop.v

diff --git a/_CoqProject b/_CoqProject
index 01cb9313..0550d628 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -94,6 +94,7 @@ theories/typing/lib/smallvec/smallvec_basic.v
 theories/typing/lib/smallvec/smallvec_slice.v
 theories/typing/lib/smallvec/smallvec_index.v
 theories/typing/lib/smallvec/smallvec_push.v
+theories/typing/lib/smallvec/smallvec_pop.v
 # theories/typing/lib/fake_shared.v
 theories/typing/lib/cell.v
 theories/typing/lib/spawn.v
diff --git a/theories/typing/lib/smallvec/smallvec_pop.v b/theories/typing/lib/smallvec/smallvec_pop.v
new file mode 100644
index 00000000..ff65b19c
--- /dev/null
+++ b/theories/typing/lib/smallvec/smallvec_pop.v
@@ -0,0 +1,146 @@
+From lrust.typing Require Export type.
+From lrust.typing Require Import array_util typing.
+From lrust.typing.lib Require Import option vec_util smallvec.smallvec.
+Set Default Proof Using "Type".
+
+Open Scope nat.
+Implicit Type 𝔄 𝔅: syn_type.
+
+Section smallvec_pop.
+  Context `{!typeG Σ}.
+
+  Definition smallvec_pop {𝔄} (ty: type 𝔄) : val :=
+    fn: ["v"] :=
+      let: "v'" := !"v" in delete [ #1; "v"];;
+      let: "len" := !("v'" +ₗ #2) in
+      let: "r" := new [ #(option_ty ty).(ty_size)] in
+      if: "len" ≤ #0 then
+        "r" <- #0;; return: ["r"]
+      else
+        let: "len'" := "len" - #1 in
+        "v'" +ₗ #2 <- "len'";; "r" <- #1;;
+        if: !"v'" then (* array mode *)
+          "r" +ₗ #1 <-{ty.(ty_size)} !("v'" +ₗ #4 +ₗ "len'" * #ty.(ty_size));;
+          return: ["r"]
+        else (* vector mode *)
+          "v'" +ₗ #3 <- !("v'" +ₗ #3) + #1;;
+          "r" +ₗ #1 <-{ty.(ty_size)} !(!("v'" +ₗ #1) +ₗ "len'" * #ty.(ty_size));;
+          return: ["r"].
+
+  Lemma smallvec_pop_type {𝔄} n (ty: type 𝔄) :
+    typed_val (smallvec_pop ty) (fn<α>(∅; &uniq{α} (smallvec n ty)) → option_ty ty)
+      (λ post '-[(al, al')], al' = removelast al → post (last_error al)).
+  Proof.
+    eapply type_fn; [apply _|]=> α ??[v[]]. simpl_subst.
+    iIntros (?[pπ[]]?) "#LFT TIME #PROPH #UNIQ #E Na L C /=[v _] #Obs".
+    rewrite tctx_hasty_val. iDestruct "v" as ([|]) "[_ v]"=>//.
+    case v as [[|v|]|]=>//. iDestruct "v" as "[(%vl & >↦ & [#LftIn uniq]) †]".
+    case vl as [|[[|v'|]|][]]; try by iDestruct "uniq" as ">[]".
+    rewrite heap_mapsto_vec_singleton. wp_read. wp_let. wp_bind (delete _).
+    rewrite -heap_mapsto_vec_singleton freeable_sz_full.
+    iApply (wp_delete with "[$↦ $†]"); [done|]. iIntros "!>_".
+    iDestruct "uniq" as (d ξi [? Eq2]) "[Vo Bor]". move: Eq2. set ξ := PrVar _ ξi=> Eq2.
+    iMod (lctx_lft_alive_tok α with "E L") as (?) "(α & L & ToL)"; [solve_typing..|].
+    iMod (bor_acc with "LFT Bor α") as "[(%&%& #⧖ & Pc & big) ToBor]"; [done|].
+    wp_seq. iDestruct (uniq_agree with "Vo Pc") as %[<-<-].
+    rewrite split_mt_smallvec.
+    iDestruct "big" as (?? len ex aπl Eq1) "(↦ & big)".
+    rewrite !heap_mapsto_vec_cons !shift_loc_assoc.
+    iDestruct "↦" as "(↦₀ & ↦₁ & ↦₂ & ↦₃ &_)". wp_op. wp_read. wp_let.
+    wp_apply wp_new; [lia|done|]. iIntros (r) "[†r ↦r]".
+    rewrite Nat2Z.id/= heap_mapsto_vec_cons. iDestruct "↦r" as "[↦r ↦r']".
+    wp_let. wp_op. wp_if. case len as [|len]=>/=.
+    { wp_write. iMod ("ToBor" with "[↦₀ ↦₁ ↦₂ ↦₃ big Pc]") as "[Bor β]".
+      { iNext. iExists _, _. iFrame "⧖ Pc". rewrite split_mt_smallvec.
+        iExists _, _, _, _, _.
+        rewrite !heap_mapsto_vec_cons heap_mapsto_vec_nil !shift_loc_assoc.
+        by iFrame "↦₀ ↦₁ ↦₂ ↦₃ big". }
+      iMod ("ToL" with "β L") as "L".
+      iApply (type_type +[#v' ◁ &uniq{α} (smallvec n ty); #r ◁ box (option_ty ty)]
+        -[pπ; const None] with "[] LFT TIME PROPH UNIQ E Na L C [-] []").
+      - iApply type_jump; [solve_typing|solve_extract|solve_typing].
+      - rewrite/= !(tctx_hasty_val #_). iSplitR "↦r ↦r' †r".
+        { iExists _. iFrame "⧖ LftIn". iExists _, _. iFrame. iPureIntro.
+          split; [lia|done]. }
+        iSplitL; [|done]. iExists _. rewrite -freeable_sz_full. iFrame "⧖ †r".
+        iNext. rewrite /option_ty. setoid_rewrite mod_ty_own; [|apply _].
+        rewrite split_mt_sum. iExists 0%fin, (const ()). iSplit; [done|]. iFrame "↦r".
+        iSplitL. { iExists _. iFrame. iPureIntro. by rewrite/= repeat_length. }
+        iFrame. iExists []. rewrite heap_mapsto_vec_nil=>/=.
+        iSplit; [done|]. by iExists (const -[]).
+      - iApply proph_obs_impl; [|done]=> π. move: (equal_f Eq1 π)=>/=. clear.
+        inv_vec aπl. by case (pπ π)=>/= ??->. }
+    iMod (uniq_update with "UNIQ Vo Pc") as "[Vo Pc]"; [done|].
+    wp_op. wp_let. have ->: (S len - 1)%Z = len by lia. wp_op. do 2 wp_write.
+    wp_read. wp_if. set pπ' := λ π, (lapply (vinit aπl) π, π ξ). case b=>/=.
+    - iDestruct "big" as "[↦tys (%&% & ↦tl)]".
+      iDestruct (big_sepL_vinitlast with "↦tys") as "[↦tys (%& ↦last & ty)]"=>/=.
+      iDestruct (ty_size_eq with "ty") as %Lvl. do 4 wp_op. rewrite -Nat2Z.inj_mul.
+      wp_apply (wp_memcpy with "[$↦r' $↦last]"); [rewrite repeat_length; lia|lia|].
+      iIntros "[↦r' ↦last]". wp_seq.
+      iMod ("ToBor" with "[↦₀ ↦₁ ↦₂ ↦₃ ↦tys ↦last ↦tl ⧖ Pc]") as "[Bor α]".
+      { iNext. iExists _, _. iFrame "⧖ Pc". rewrite split_mt_smallvec.
+        iExists _, _, _, _, _.
+        rewrite !heap_mapsto_vec_cons heap_mapsto_vec_nil !shift_loc_assoc.
+        iFrame "↦₀ ↦₁ ↦₂ ↦₃ ↦tys". iSplit; [done|]. iExists (_++_).
+        rewrite heap_mapsto_vec_app shift_loc_assoc -Z.add_assoc -Nat2Z.inj_add
+          -Lvl Nat.add_comm.
+        iFrame "↦last ↦tl". iPureIntro. rewrite app_length. lia. }
+      iMod ("ToL" with "α L") as "L".
+      iApply (type_type +[#v' ◁ &uniq{α} (smallvec n ty); #r ◁ box (option_ty ty)]
+        -[pπ'; Some ∘ _] with "[] LFT TIME PROPH UNIQ E Na L C [-] []").
+      + iApply type_jump; [solve_typing|solve_extract|solve_typing].
+      + rewrite/= !(tctx_hasty_val #_) right_id. iSplitL "Vo Bor".
+        * iExists _. iFrame "⧖ LftIn". iExists _, _. rewrite /uniq_body.
+          rewrite (proof_irrel (@prval_to_inh (listₛ 𝔄) (fst ∘ pπ'))
+            (@prval_to_inh (listₛ 𝔄) (fst ∘ pπ))). by iFrame.
+        * iExists _. rewrite -freeable_sz_full. iFrame "⧖ †r". iNext.
+          rewrite /option_ty. setoid_rewrite mod_ty_own; [|apply _].
+          rewrite split_mt_sum. iExists 1%fin, _. iSplit; [done|]. iFrame "↦r". iSplitR.
+          { iExists []. rewrite heap_mapsto_vec_nil left_id. iPureIntro=>/=.
+            move: ty.(ty_size)=> ?. lia. }
+          iExists _. iFrame "↦r'". iApply ty_own_depth_mono; [|done]. lia.
+      + iApply proph_obs_impl; [|done]=>/= π.
+        move: (equal_f Eq1 π) (equal_f Eq2 π)=>/=. clear. case (pπ π)=>/= ??->->.
+        have ->: last_error (lapply aπl π) = Some (vlast aπl π).
+        { inv_vec aπl=> + aπl'. by elim aπl'=>/= *. }
+        have ->: removelast (lapply aπl π) = lapply (vinit aπl) π.
+        { inv_vec aπl=> + aπl'. elim aπl'; [done|]=>/= *. by f_equal. } done.
+    - iDestruct "big" as (??) "(↦tl & ↦tys & (%&% & ↦ex) & †)".
+      iDestruct (big_sepL_vinitlast with "↦tys") as "[↦tys (%& ↦last & ty)]"=>/=.
+      iDestruct (ty_size_eq with "ty") as %Lvl. do 2 wp_op. wp_read. wp_op.
+      wp_write. have ->: (ex + 1)%Z = S ex by lia. do 2 wp_op. wp_read.
+      do 2 wp_op. rewrite -Nat2Z.inj_mul.
+      wp_apply (wp_memcpy with "[$↦r' $↦last]"); [rewrite repeat_length; lia|lia|].
+      iIntros "[↦r' ↦last]". wp_seq.
+      iMod ("ToBor" with "[↦₀ ↦₁ ↦₂ ↦₃ ↦tys ↦tl ↦last ↦ex † ⧖ Pc]") as "[Bor α]".
+      { iNext. iExists _, _. iFrame "⧖ Pc". rewrite split_mt_smallvec.
+        iExists _, _, _, _, _.
+        rewrite !heap_mapsto_vec_cons heap_mapsto_vec_nil !shift_loc_assoc.
+        iFrame "↦₀ ↦₁ ↦₂ ↦₃ ↦tys". iSplit; [done|]. iExists _. iFrame "↦tl".
+        iSplit; [done|]. have ->: len + S ex = S (len + ex) by lia. iFrame "†".
+        iExists (_++_). rewrite heap_mapsto_vec_app. iFrame "↦last".
+        rewrite shift_loc_assoc_nat app_length Nat.add_comm Lvl.
+        iFrame. iPureIntro=>/=. lia. }
+      iMod ("ToL" with "α L") as "L".
+      iApply (type_type +[#v' ◁ &uniq{α} (smallvec n ty); #r ◁ box (option_ty ty)]
+        -[pπ'; Some ∘ _] with "[] LFT TIME PROPH UNIQ E Na L C [-] []").
+      + iApply type_jump; [solve_typing|solve_extract|solve_typing].
+      + rewrite/= !(tctx_hasty_val #_) right_id. iSplitL "Vo Bor".
+        * iExists _. iFrame "⧖ LftIn". iExists _, _. rewrite /uniq_body.
+          rewrite (proof_irrel (@prval_to_inh (listₛ 𝔄) (fst ∘ pπ'))
+            (@prval_to_inh (listₛ 𝔄) (fst ∘ pπ))). by iFrame.
+        * iExists _. rewrite -freeable_sz_full. iFrame "⧖ †r". iNext.
+          rewrite /option_ty. setoid_rewrite mod_ty_own; [|apply _].
+          rewrite split_mt_sum. iExists 1%fin, _. iSplit; [done|]. iFrame "↦r". iSplitR.
+          { iExists []. rewrite heap_mapsto_vec_nil left_id. iPureIntro=>/=.
+            move: ty.(ty_size)=> ?. lia. }
+          iExists _. iFrame "↦r'". iApply ty_own_depth_mono; [|done]. lia.
+      + iApply proph_obs_impl; [|done]=>/= π.
+        move: (equal_f Eq1 π) (equal_f Eq2 π)=>/=. clear. case (pπ π)=>/= ??->->.
+        have ->: last_error (lapply aπl π) = Some (vlast aπl π).
+        { inv_vec aπl=> + aπl'. by elim aπl'=>/= *. }
+        have ->: removelast (lapply aπl π) = lapply (vinit aπl) π.
+        { inv_vec aπl=> + aπl'. elim aπl'; [done|]=>/= *. by f_equal. } done.
+  Qed.
+End smallvec_pop.
-- 
GitLab