diff --git a/_CoqProject b/_CoqProject
index 057a066767d41b490c1f88420619414efdfbf56c..c03b2e2b60c556cb12f90154d5edf63677a55baa 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -65,6 +65,7 @@ theories/typing/lib/refcell/refmut.v
 theories/typing/lib/refcell/ref.v
 theories/typing/lib/rwlock/rwlock.v
 theories/typing/lib/rwlock/rwlockreadguard.v
+theories/typing/lib/rwlock/rwlockwriteguard.v
 theories/typing/examples/get_x.v
 theories/typing/examples/rebor.v
 theories/typing/examples/unbox.v
diff --git a/theories/typing/lib/rwlock/rwlock_code.v b/theories/typing/lib/rwlock/rwlock_code.v
new file mode 100644
index 0000000000000000000000000000000000000000..8387ee2b15f036b048d76fb1248f4b40cdb260e3
--- /dev/null
+++ b/theories/typing/lib/rwlock/rwlock_code.v
@@ -0,0 +1,314 @@
+From iris.proofmode Require Import tactics.
+From iris.algebra Require Import auth csum frac agree.
+From iris.bi Require Import fractional.
+From lrust.lang Require Import memcpy.
+From lrust.lifetime Require Import at_borrow.
+From lrust.typing Require Import typing option.
+From lrust.typing.lib.rwlock Require Import rwlock rwlockreadguard rwlockwriteguard.
+From gpfsl.gps Require Import middleware.
+Set Default Proof Using "Type".
+
+Section rwlock_functions.
+  Context `{typeG Σ, rwlockG Σ}.
+
+  (* Constructing a rwlock. *)
+  Definition rwlock_new ty : val :=
+    funrec: <> ["x"] :=
+      let: "r" := new [ #(S ty.(ty_size))] in
+      "r" +ₗ #0 <- #0;;
+      "r" +ₗ #1 <-{ty.(ty_size)} !"x";;
+       delete [ #ty.(ty_size) ; "x"];; return: ["r"].
+
+  Lemma rwlock_new_type ty `{!TyWf ty} :
+    typed_val (rwlock_new ty) (fn(∅; ty) → rwlock ty).
+  Proof.
+    intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
+      iIntros (_ ret ϝ arg). inv_vec arg=>x. simpl_subst.
+    iApply (type_new (S ty.(ty_size))); [solve_typing..|].
+    iIntros (r tid) "#LFT HE Hna HL Hk HT". simpl_subst.
+    rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val.
+    iDestruct "HT" as "[Hr Hx]". destruct x as [[|lx|]|]; try done.
+    iDestruct "Hx" as "[Hx Hx†]". iDestruct "Hx" as (vl) "[Hx↦ Hx]".
+    destruct r as [[|lr|]|]; try done. iDestruct "Hr" as "[Hr Hr†]".
+    iDestruct "Hr" as (vl') "Hr". rewrite uninit_own.
+    iDestruct "Hr" as "[Hr↦ >SZ]". destruct vl' as [|]; iDestruct "SZ" as %[=].
+    rewrite heap_mapsto_vec_cons. iDestruct "Hr↦" as "[Hr↦0 Hr↦1]". wp_op.
+    rewrite shift_loc_0. wp_write. wp_op. iDestruct (ty.(ty_size_eq) with "Hx") as %Hsz.
+    wp_apply (wp_memcpy with "[$Hr↦1 $Hx↦]"); [done||lia..|].
+    iIntros "[Hr↦1 Hx↦]". wp_seq.
+    iApply wp_hist_inv; [done|iIntros "HI"].
+    iApply (type_type _ _ _ [ #lx ◁ box (uninit (ty_size ty)); #lr ◁ box (rwlock ty)]
+        with "[] LFT HE Hna HL Hk [-]"); last first.
+    { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val' //=. iFrame.
+      iSplitL "Hx↦".
+      - iExists _. rewrite uninit_own. auto.
+      - iExists (_::_). rewrite heap_mapsto_vec_cons. iFrame. simpl. iFrame. auto. }
+    iApply type_delete; [solve_typing..|].
+    iApply type_jump; solve_typing.
+  Qed.
+
+  (* The other direction: getting ownership out of a rwlock.
+     Note: as we ignore poisonning, this cannot fail. *)
+  Definition rwlock_into_inner ty : val :=
+    funrec: <> ["x"] :=
+      let: "r" := new [ #ty.(ty_size)] in
+      "r" <-{ty.(ty_size)} !("x" +ₗ #1);;
+       delete [ #(S ty.(ty_size)) ; "x"];; return: ["r"].
+
+  Lemma rwlock_into_inner_type ty `{!TyWf ty} :
+    typed_val (rwlock_into_inner ty) (fn(∅; rwlock ty) → ty).
+  Proof.
+    intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
+      iIntros (_ ret ϝ arg). inv_vec arg=>x. simpl_subst.
+    iApply (type_new ty.(ty_size)); [solve_typing..|].
+    iIntros (r tid) "#LFT HE Hna HL Hk HT". simpl_subst.
+    rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val.
+    iDestruct "HT" as "[Hr Hx]". destruct x as [[|lx|]|]; try done.
+    iDestruct "Hx" as "[Hx Hx†]".
+    iDestruct "Hx" as ([|[[]|]vl]) "[Hx↦ [HI Hx]]"; try iDestruct "Hx" as ">[]".
+    destruct r as [[|lr|]|]; try done. iDestruct "Hr" as "[Hr Hr†]".
+    iDestruct "Hr" as (vl') "Hr". rewrite uninit_own heap_mapsto_vec_cons.
+    iDestruct "Hr" as "[Hr↦ >%]". iDestruct "Hx↦" as "[Hx↦0 Hx↦1]". wp_op.
+    iDestruct "Hx" as "[% Hx]". iDestruct (ty.(ty_size_eq) with "Hx") as %Hsz.
+    wp_apply (wp_memcpy with "[$Hr↦ $Hx↦1]"); [done||lia..|].
+    iIntros "[Hr↦ Hx↦1]". wp_seq.
+    iApply (type_type _ _ _ [ #lx ◁ box (uninit (S (ty_size ty))); #lr ◁ box ty]
+        with "[] LFT HE Hna HL Hk [-]"); last first.
+    { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val' //. iFrame.
+      iSplitR "Hr↦ Hx".
+      - iExists (_::_). rewrite heap_mapsto_vec_cons uninit_own -Hsz. iFrame. auto.
+      - iExists vl. iFrame. }
+    iApply type_delete; [solve_typing..|].
+    iApply type_jump; solve_typing.
+  Qed.
+
+  Definition rwlock_get_mut : val :=
+    funrec: <> ["x"] :=
+      let: "x'" := !"x" in
+      "x" <- "x'" +ₗ #1;;
+      return: ["x"].
+
+  Lemma rwlock_get_mut_type ty `{!TyWf ty} :
+    typed_val rwlock_get_mut (fn(∀ α, ∅; &uniq{α} (rwlock ty)) → &uniq{α} ty).
+  Proof.
+    intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
+      iIntros (α ϝ ret arg). inv_vec arg=>x. simpl_subst.
+    iApply type_deref; [solve_typing..|]. iIntros (x'). simpl_subst.
+    iIntros (tid) "#LFT HE Hna HL HC HT".
+    rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val.
+    iDestruct "HT" as "[Hx Hx']". destruct x' as [[|lx'|]|];  try iDestruct "Hx'" as "[]".
+    iAssert (&{α} (⎡ hist_inv ⎤ ∗ ∃ (z : Z), lx' ↦ #z ∗ ⌜-1 ≤ z⌝) ∗
+        (&uniq{α} ty).(ty_own) tid [ #(lx' +ₗ 1)])%I with "[> Hx']" as "[_ Hx']".
+    { iApply bor_sep; [done..|]. iApply (bor_proper with "Hx'"). iSplit.
+      - iIntros "[H1 H2]". iDestruct "H1" as "[? H1]".
+        iDestruct "H1" as (z) "[??]". iDestruct "H2" as (vl) "[??]".
+        iExists (_::_). rewrite heap_mapsto_vec_cons. iFrame. iFrame.
+      - iIntros "H". iDestruct "H" as ([|[[| |z]|]vl]) "[H↦ [HI H]]"; try done.
+        rewrite heap_mapsto_vec_cons. iFrame "HI".
+        iDestruct "H" as "[H1 H2]". iDestruct "H↦" as "[H↦1 H↦2]".
+        iSplitL "H1 H↦1"; eauto. iExists _. iFrame. }
+    destruct x as [[|lx|]|]; try done. iDestruct "Hx" as "[Hx Hx†]".
+    iDestruct "Hx" as (vl) "[Hx↦ Hx]". rewrite uninit_own. wp_op.
+    iApply (type_type _ _ _
+            [ #lx ◁ box (uninit 1); #(lx' +ₗ 1) ◁ &uniq{α}ty]
+            with "[] LFT HE Hna HL HC [-]"); last first.
+    { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val' //. iFrame.
+      iNext. iExists _. rewrite uninit_own. iFrame. }
+    iApply type_assign; [solve_typing..|].
+    iApply type_jump; solve_typing.
+  Qed.
+
+  (* Acquiring a read lock. *)
+  Definition rwlock_try_read : val :=
+    funrec: <> ["x"] :=
+      let: "r" := new [ #2 ] in
+      let: "x'" := !"x" in
+    withcont: "k":
+    withcont: "loop":
+      "loop" []
+    cont: "loop" [] :=
+      let: "n" := !ʳˡˣ"x'" in
+        if: "n" ≤ #-1 then
+          "r" <-{Σ none} ();;
+          "k" []
+        else
+          if: CAS "x'" "n" ("n" + #1) AcqRel Relaxed then
+            "r" <-{Σ some} "x'";;
+            "k" []
+          else "loop" []
+    cont: "k" [] :=
+      delete [ #1; "x"];; return: ["r"].
+
+  Lemma rwlock_try_read_type ty `{!TyWf ty} :
+    typed_val rwlock_try_read
+        (fn(∀ α, ∅; &shr{α}(rwlock ty)) → option (rwlockreadguard α ty)).
+  Proof.
+    intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
+      iIntros (α ϝ ret arg). inv_vec arg=>x. simpl_subst.
+    iApply type_new; [solve_typing..|]. iIntros (r). simpl_subst.
+    iApply type_deref; [solve_typing..|]. iIntros (x'). simpl_subst.
+    iApply (type_cont [] [ϝ ⊑ₗ []] (λ _, [x ◁ box (&shr{α}(rwlock ty));
+                                            r ◁ box (option (rwlockreadguard α ty))]));
+      [iIntros (k)|iIntros "/= !#"; iIntros (k arg); inv_vec arg];
+      simpl_subst; last first.
+    { iApply type_delete; [solve_typing..|].
+      iApply type_jump; solve_typing. }
+    iApply (type_cont [] [ϝ ⊑ₗ []] (λ _, [x ◁ _; x' ◁ _; r ◁ _]));
+      [iIntros (loop)|iIntros "/= !#"; iIntros (loop arg); inv_vec arg];
+      simpl_subst.
+    { iApply type_jump; solve_typing. }
+    iIntros (tid) "#LFT #HE Hna HL Hk HT".
+    rewrite 2!tctx_interp_cons tctx_interp_singleton !tctx_hasty_val.
+    iDestruct "HT" as "(Hx & Hx' & Hr)". destruct x' as [[|lx|]|]; try done.
+    iDestruct "Hx'" as (β) "#[Hαβ Hinv]".
+    iMod (lctx_lft_alive_tok α with "HE HL") as (qα) "(Hα & HL & Hclose)";
+      [solve_typing..|].
+    iMod (lft_incl_acc with "Hαβ Hα") as (qβ) "[[Hβtok1 Hβtok2] Hclose']". done.
+    iDestruct "Hinv" as (γ γs tyO tyS) "((EqO & EqS & R) & Hinv)".
+    iDestruct "R" as (vR) "R".
+    wp_bind (!ʳˡˣ(LitV lx))%E.
+    iMod (at_bor_acc with "LFT Hinv Hβtok1") as (Vb) "[INV Hclose'']"; [done..|].
+    iApply (GPS_SWRawReader_read with "[$R $INV]"); [solve_ndisj|by left|..].
+    { iNext. iIntros (? _). iLeft. iModIntro.
+      iIntros (?). by iApply rwlock_interp_duplicable. }
+    iNext. iIntros ([] v') "(_ & R' & INV & Int)".
+    iDestruct (acq_exist with "Int") as (st) "Int".
+    iDestruct (acq_sep_elim with "Int") as "[Int _]".
+    iDestruct (acq_pure_elim with "Int") as %?. subst v'.
+    iMod ("Hclose''" with "INV") as "Hβtok1".
+    iModIntro. wp_let. wp_op; case_bool_decide as Hm1; wp_if.
+    - iMod ("Hclose'" with "[$]") as "Hα". iMod ("Hclose" with "Hα HL") as "HL".
+      iApply (type_type _ _ _
+              [ x ◁ box (&shr{α}(rwlock ty)); r ◁ box (uninit 2) ]
+              with "[] LFT HE Hna HL Hk"); first last.
+      { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val. iFrame. }
+      iApply (type_sum_unit (option $ rwlockreadguard α ty));
+        [solve_typing..|]; first last.
+      simpl. iApply type_jump; solve_typing.
+    - wp_op. wp_bind (CAS _ _ _ _ _).
+      iMod (at_bor_acc with "LFT Hinv Hβtok1") as (Vb') "[INV Hclose'']"; [done..|].
+
+      iDestruct "INV" as (st') "(Hlx & Hownst & Hst)". revert Hm1.
+      destruct (decide (Z_of_rwlock_st st = Z_of_rwlock_st st')) as [->|?]=>?.
+      + iApply (wp_cas_int_suc with "Hlx"). iNext. iIntros "Hlx".
+        iAssert (∃ qν ν, (qβ / 2).[β] ∗ (qν).[ν] ∗
+                         ty_shr ty (β ⊓ ν) tid (lx +ₗ 1) ∗
+                         own γ (◯ reading_st qν ν) ∗ rwlock_inv tid lx γ β ty ∗
+                         ((1).[ν] ={↑lftN,∅}▷=∗ [†ν]))%I
+          with "[> Hlx Hownst Hst Hβtok2]"
+          as (q' ν) "(Hβtok2 & Hν & Hshr & Hreading & INV & H†)".
+        { destruct st' as [[|[[agν q] n]|]|]; try done.
+          - iDestruct "Hst" as (ν q') "(Hag & #H† & Hh & #Hshr & #Hqq' & [Hν1 Hν2])".
+            iExists _, _. iFrame "Hν1". iDestruct "Hag" as %Hag. iDestruct "Hqq'" as %Hqq'.
+            iMod (own_update with "Hownst") as "[Hownst ?]".
+            { apply auth_update_alloc,
+              (op_local_update_discrete _ _ (reading_st (q'/2)%Qp ν))=>-[Hagv _].
+              split; [split|].
+              - by rewrite /= Hag agree_idemp.
+              - apply frac_valid'. rewrite -Hqq' comm -{2}(Qp_div_2 q').
+                apply Qcplus_le_mono_l. rewrite -{1}(Qcplus_0_l (q'/2)%Qp).
+                apply Qcplus_le_mono_r, Qp_ge_0.
+              - done. }
+            iFrame "∗#". iExists _. rewrite Z.add_comm /=. iFrame. iExists _, _.
+            iFrame "∗#". iSplitR; first by rewrite /= Hag agree_idemp.
+            rewrite (comm Qp_plus) (assoc Qp_plus) Qp_div_2 (comm Qp_plus). auto.
+          - iMod (lft_create with "LFT") as (ν) "[[Htok1 Htok2] #Hhν]". solve_ndisj.
+            iMod (own_update with "Hownst") as "[Hownst Hreading]"; first by apply
+              auth_update_alloc, (op_local_update_discrete _ _ (reading_st (1/2)%Qp ν)).
+            rewrite right_id. iExists _, _. iFrame "Htok1 Hreading".
+            iDestruct (lft_intersect_acc with "Hβtok2 Htok2") as (q) "[Htok Hclose]".
+            iApply (fupd_mask_mono (↑lftN)). solve_ndisj.
+            iMod (rebor _ _ (β ⊓ ν) with "LFT [] Hst") as "[Hst Hh]". solve_ndisj.
+            { iApply lft_intersect_incl_l. }
+            iMod (ty_share with "LFT Hst Htok") as "[#Hshr Htok]". solve_ndisj.
+            iFrame "#". iDestruct ("Hclose" with "Htok") as "[$ Htok2]".
+            iExists _. iFrame. iExists _, _. iSplitR; first done. iFrame "#∗".
+            rewrite Qp_div_2. iSplitL; last done.
+            iIntros "!> Hν". iApply "Hh". rewrite -lft_dead_or. auto. }
+        iMod ("Hclose''" with "[$INV]") as "Hβtok1". iModIntro. wp_case.
+        iMod ("Hclose'" with "[$]") as "Hα". iMod ("Hclose" with "Hα HL") as "HL".
+        iApply (type_type  _ _ _
+                   [ x ◁ box (&shr{α}(rwlock ty)); r ◁ box (uninit 2);
+                     #lx ◁ rwlockreadguard α ty]
+              with "[] LFT HE Hna HL Hk"); first last.
+        { rewrite 2!tctx_interp_cons tctx_interp_singleton !tctx_hasty_val
+                  tctx_hasty_val' //. iFrame.
+          iExists _, _, _, _. iFrame "∗#". iApply ty_shr_mono; last done.
+          iApply lft_intersect_mono; first done. iApply lft_incl_refl. }
+        iApply (type_sum_assign (option $ rwlockreadguard α ty)); [solve_typing..|].
+        simpl. iApply type_jump; solve_typing.
+      + iApply (wp_cas_int_fail with "Hlx"); try done. iNext. iIntros "Hlx".
+        iMod ("Hclose''" with "[Hlx Hownst Hst]") as "Hβtok1"; first by iExists _; iFrame.
+        iModIntro. wp_case. iMod ("Hclose'" with "[$]") as "Hα".
+        iMod ("Hclose" with "Hα HL") as "HL".
+        iSpecialize ("Hk" with "[]"); first solve_typing.
+        iApply ("Hk" $! [#] with "Hna HL").
+        rewrite 2!tctx_interp_cons tctx_interp_singleton !tctx_hasty_val. iFrame.
+        iExists _. iSplit. done. simpl. eauto.
+  Qed.
+
+  (* Acquiring a write lock. *)
+  Definition rwlock_try_write : val :=
+    funrec: <> ["x"] :=
+    withcont: "k":
+      let: "r" := new [ #2 ] in
+      let: "x'" := !"x" in
+      if: CAS "x'" #0 #(-1) then
+        "r" <-{Σ some} "x'";;
+        "k" ["r"]
+      else
+        "r" <-{Σ none} ();;
+        "k" ["r"]
+    cont: "k" ["r"] :=
+      delete [ #1; "x"];; return: ["r"].
+
+  Lemma rwlock_try_write_type ty `{!TyWf ty} :
+    typed_val rwlock_try_write
+        (fn(∀ α, ∅; &shr{α}(rwlock ty)) → option (rwlockwriteguard α ty)).
+  Proof.
+    intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
+      iIntros (α ϝ ret arg). inv_vec arg=>x. simpl_subst.
+    iApply (type_cont [_] [ϝ ⊑ₗ []] (λ r, [x ◁ box (&shr{α}(rwlock ty));
+                                        r!!!0 ◁ box (option (rwlockwriteguard α ty))]));
+      [iIntros (k)|iIntros "/= !#"; iIntros (k arg); inv_vec arg=>r];
+      simpl_subst; last first.
+    { iApply type_delete; [solve_typing..|]. iApply type_jump; solve_typing. }
+    iApply type_new; [solve_typing..|]. iIntros (r). simpl_subst.
+    iApply type_deref; [solve_typing..|].
+    iIntros (x' tid) "#LFT #HE Hna HL Hk HT". simpl_subst.
+    rewrite 2!tctx_interp_cons tctx_interp_singleton !tctx_hasty_val.
+    iDestruct "HT" as "(Hx & Hx' & Hr)". destruct x' as [[|lx|]|]; try done.
+    iDestruct "Hx'" as (β γ) "#[Hαβ Hinv]".
+    iMod (lctx_lft_alive_tok α with "HE HL") as (qα) "(Hα & HL & Hclose)"; [solve_typing..|].
+    iMod (lft_incl_acc with "Hαβ Hα") as (qβ) "[Hβtok Hclose']". done.
+    wp_bind (CAS _ _ _).
+    iMod (at_bor_acc_tok with "LFT Hinv Hβtok") as "[INV Hclose'']"; try done.
+    iDestruct "INV" as (st) "(Hlx & >Hownst & Hst)". destruct st.
+    - iApply (wp_cas_int_fail with "Hlx"). by destruct c as [|[[]]|].
+      iNext. iIntros "Hlx".
+      iMod ("Hclose''" with "[Hlx Hownst Hst]") as "Hβtok"; first by iExists _; iFrame.
+      iMod ("Hclose'" with "Hβtok") as "Hα". iMod ("Hclose" with "Hα HL") as "HL".
+      iModIntro. wp_case.
+      iApply (type_type _ _ _
+              [ x ◁ box (&shr{α}(rwlock ty)); r ◁ box (uninit 2) ]
+              with "[] LFT HE Hna HL Hk"); first last.
+      { rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val. iFrame. }
+      iApply (type_sum_unit (option $ rwlockwriteguard α ty));
+        [solve_typing..|]; first last.
+      rewrite /option /=. iApply type_jump; solve_typing.
+    - iApply (wp_cas_int_suc with "Hlx"). iIntros "!> Hlx".
+      iMod (own_update with "Hownst") as "[Hownst ?]".
+      { by eapply auth_update_alloc, (op_local_update_discrete _ _ writing_st). }
+      iMod ("Hclose''" with "[Hlx Hownst]") as "Hβtok". { iExists _. iFrame. }
+      iModIntro. wp_case. iMod ("Hclose'" with "Hβtok") as "Hα".
+      iMod ("Hclose" with "Hα HL") as "HL".
+      iApply (type_type  _ _ _
+                   [ x ◁ box (&shr{α}(rwlock ty)); r ◁ box (uninit 2);
+                     #lx ◁ rwlockwriteguard α ty]
+              with "[] LFT HE Hna HL Hk"); first last.
+      { rewrite 2!tctx_interp_cons tctx_interp_singleton !tctx_hasty_val
+                tctx_hasty_val' //. iFrame.  iExists _, _. iFrame "∗#". }
+      iApply (type_sum_assign (option $ rwlockwriteguard α ty)); [solve_typing..|].
+      simpl. iApply type_jump; solve_typing.
+  Qed.
+End rwlock_functions.
diff --git a/theories/typing/lib/rwlock/rwlockwriteguard.v b/theories/typing/lib/rwlock/rwlockwriteguard.v
new file mode 100644
index 0000000000000000000000000000000000000000..adbce4bcc86b875a8d21ccf15b3cee55873557e6
--- /dev/null
+++ b/theories/typing/lib/rwlock/rwlockwriteguard.v
@@ -0,0 +1,133 @@
+From iris.proofmode Require Import tactics.
+From iris.algebra Require Import auth csum frac agree.
+From iris.bi Require Import fractional.
+From lrust.lifetime Require Import at_borrow.
+From lrust.typing Require Import util typing.
+From lrust.typing.lib.rwlock Require Import rwlock.
+From gpfsl.gps Require Import middleware.
+Set Default Proof Using "Type".
+
+Section rwlockwriteguard.
+  Context `{typeG Σ, rwlockG Σ}.
+
+  (* Original Rust type (we ignore poisoning):
+      pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
+          __lock: &'a RwLock<T>,
+          __poison: poison::Guard,
+      }
+  *)
+
+  Program Definition rwlockwriteguard (α : lft) (ty : type) :=
+    {| ty_size := 1;
+       ty_own tid vl :=
+         match vl return _ with
+         | [ #(LitLoc l) ] =>
+           ∃ γs β, &{β}((l +ₗ 1) ↦∗: ty.(ty_own) tid) ∗
+             α ⊑ β ∗ ⎡ own γs (◯ writing_st) ⎤ ∗
+             (∃ γ tyO tyS, rwlock_proto_lc l γ tyO tyS tid ty ∗
+                    &at{β,rwlockN}(rwlock_proto_inv l γ γs β tyO tyS) ∗
+                    GPS_SWRawReader l () #(-1) γ)
+         | _ => False
+         end;
+       ty_shr κ tid l :=
+         ∃ (l' : loc),
+           &frac{κ} (λ q, l↦∗{q} [ #l']) ∗
+           □ ∀ F q, ⌜↑shrN ∪ lftE ⊆ F⌝ -∗ q.[α ⊓ κ] ={F, F∖↑shrN}▷=∗
+               ty.(ty_shr) (α ⊓ κ) tid (l' +ₗ 1) ∗ q.[α ⊓ κ] |}%I.
+  Next Obligation. by iIntros (???[|[[]|][]]) "?". Qed.
+  Next Obligation.
+    iIntros (α ty E κ l tid q HE) "#LFT Hb Htok".
+    iMod (bor_exists with "LFT Hb") as (vl) "Hb". done.
+    iMod (bor_sep with "LFT Hb") as "[H↦ Hb]". done.
+    iMod (bor_fracture _ (λ q, l ↦∗{q} vl)%I with "LFT H↦") as "#H↦". done.
+    destruct vl as [|[[|l'|]|][]];
+      try by iMod (bor_persistent with "LFT Hb Htok") as "[>[] _]".
+    iMod (bor_exists with "LFT Hb") as (γs) "Hb". done.
+    iMod (bor_exists with "LFT Hb") as (β) "Hb". done.
+    iMod (bor_sep with "LFT Hb") as "[Hb H]". done.
+    iMod (bor_sep with "LFT H") as "[Hαβ _]". done.
+    iMod (bor_persistent with "LFT Hαβ Htok") as "[#Hαβ $]". done.
+    iExists _. iFrame "H↦". iApply delay_sharing_nested; try done.
+    (* FIXME: "iApply lft_intersect_mono" only preserves the later on the last
+       goal, as does "iApply (lft_intersect_mono with ">")". *)
+    iNext. iApply lft_intersect_mono. done. iApply lft_incl_refl.
+  Qed.
+  Next Obligation.
+    iIntros (??????) "#? H". iDestruct "H" as (l') "[#Hf #H]".
+    iExists _. iSplit.
+    - by iApply frac_bor_shorten.
+    - iIntros "!# * % Htok".
+      iMod (lft_incl_acc with "[] Htok") as (q') "[Htok Hclose]"; first solve_ndisj.
+      { iApply lft_intersect_mono. iApply lft_incl_refl. done. }
+      iMod ("H" with "[] Htok") as "Hshr". done. iModIntro. iNext.
+      iMod "Hshr" as "[Hshr Htok]". iMod ("Hclose" with "Htok") as "$".
+      iApply ty_shr_mono; try done. iApply lft_intersect_mono. iApply lft_incl_refl. done.
+  Qed.
+
+  Global Instance rwlockwriteguard_wf α ty `{!TyWf ty} : TyWf (rwlockwriteguard α ty) :=
+    { ty_lfts := [α]; ty_wf_E := ty.(ty_wf_E) ++ ty.(ty_outlives_E) α }.
+
+  Global Instance rwlockwriteguard_type_contractive α : TypeContractive (rwlockwriteguard α).
+  Proof.
+    constructor;
+      solve_proper_core ltac:(fun _ => exact: type_dist2_S || (eapply rwlock_proto_lc_type_ne; try reflexivity) ||
+                                              f_type_equiv || f_contractive || f_equiv).
+  Qed.
+  Global Instance rwlockwriteguard_ne α : NonExpansive (rwlockwriteguard α).
+  Proof. apply type_contractive_ne, _. Qed.
+
+  Global Instance rwlockwriteguard_mono E L :
+    Proper (flip (lctx_lft_incl E L) ==> eqtype E L ==> subtype E L) rwlockwriteguard.
+  Proof.
+    intros α1 α2 Hα ty1 ty2 Hty. generalize Hty. rewrite eqtype_unfold. iIntros (Hty' q) "HL".
+    iDestruct (Hty' with "HL") as "#Hty". iDestruct (Hα with "HL") as "#Hα".
+    iDestruct (rwlock_proto_lc_proper with "HL") as "#Hty1ty2"; first done.
+    iIntros "!# #HE". iDestruct ("Hα" with "HE") as "Hα1α2".
+    iDestruct ("Hty" with "HE") as "(%&#Ho&#Hs)". iSplit; [done|iSplit; iAlways].
+    - iIntros (tid [|[[]|][]]) "H"; try done.
+      iDestruct "H" as (γs β) "(Hb & #H⊑ & Hown & Hinv)".
+      iExists γs, β. iFrame "Hown". iSplit; last iSplit.
+      + iApply bor_iff; last done.
+        iIntros "!>!#". iSplit; iIntros "H"; iDestruct "H" as (vl) "[??]";
+        iExists vl; iFrame; by iApply "Ho".
+      + by iApply lft_incl_trans.
+      + iDestruct "Hinv" as (γ tyO tyS) "(lc & inv & R)".
+        iExists γ, tyO, tyS. iFrame "R inv". by iApply ("Hty1ty2" with "HE lc").
+    - iIntros (κ tid l) "H". iDestruct "H" as (l') "H". iExists l'.
+      iDestruct "H" as "[$ #H]". iIntros "!# * % Htok".
+      iMod (lft_incl_acc with "[] Htok") as (q') "[Htok Hclose]"; first solve_ndisj.
+      { iApply lft_intersect_mono. done. iApply lft_incl_refl. }
+      iMod ("H" with "[] Htok") as "Hshr". done. iModIntro. iNext.
+      iMod "Hshr" as "[Hshr Htok]". iMod ("Hclose" with "Htok") as "$".
+      iApply ty_shr_mono; try done. iApply lft_intersect_mono. done. iApply lft_incl_refl.
+      by iApply "Hs".
+  Qed.
+  Global Instance rwlockwriteguard_mono_flip E L :
+    Proper (lctx_lft_incl E L ==> eqtype E L ==> flip (subtype E L)) rwlockwriteguard.
+  Proof. intros ??????. by apply rwlockwriteguard_mono. Qed.
+  Lemma rwlockwriteguard_mono' E L α1 α2 ty1 ty2 :
+    lctx_lft_incl E L α2 α1 → eqtype E L ty1 ty2 →
+    subtype E L (rwlockwriteguard α1 ty1) (rwlockwriteguard α2 ty2) .
+  Proof. intros. by eapply rwlockwriteguard_mono. Qed.
+  Global Instance rwlockwriteguard_proper E L :
+    Proper (lctx_lft_eq E L ==> eqtype E L ==> eqtype E  L) rwlockwriteguard.
+  Proof. intros ??[]???. split; by apply rwlockwriteguard_mono'. Qed.
+  Lemma rwlockwriteguard_proper' E L α1 α2 ty1 ty2 :
+    lctx_lft_eq E L α1 α2 → eqtype E L ty1 ty2 →
+    eqtype E L (rwlockwriteguard α1 ty1) (rwlockwriteguard α2 ty2).
+  Proof. intros. by eapply rwlockwriteguard_proper. Qed.
+
+  (* Rust requires the type to also be Send.  Not sure why. *)
+  Global Instance rwlockwriteguard_sync α ty :
+    Sync ty → Sync (rwlockwriteguard α ty).
+  Proof.
+    move=>?????/=. apply bi.exist_mono=>?. do 6 f_equiv.
+    by rewrite sync_change_tid.
+  Qed.
+
+  (* POSIX requires the unlock to occur from the thread that acquired
+     the lock, so Rust does not implement Send for RwLockWriteGuard. We could
+     prove this. *)
+End rwlockwriteguard.
+
+Hint Resolve rwlockwriteguard_mono' rwlockwriteguard_proper' : lrust_typing.