From 6aa1559d97ee728ec6aac95010508f998f3a5fc7 Mon Sep 17 00:00:00 2001
From: Ralf Jung <jung@mpi-sws.org>
Date: Tue, 29 Aug 2023 11:06:14 +0200
Subject: [PATCH] =?UTF-8?q?fix=20lock=20spec=20code=20depending=20on=20?=
 =?UTF-8?q?=CE=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 iris_heap_lang/lib/lock.v         | 52 ++++++++++++++++++-------------
 iris_heap_lang/lib/logatom_lock.v |  8 ++---
 iris_heap_lang/lib/spin_lock.v    | 21 ++++++++-----
 iris_heap_lang/lib/ticket_lock.v  | 11 ++++---
 tests/heap_lang.v                 | 30 ++++++++++++++++--
 5 files changed, 82 insertions(+), 40 deletions(-)

diff --git a/iris_heap_lang/lib/lock.v b/iris_heap_lang/lib/lock.v
index 5c66f9c7c..a7ba1b213 100644
--- a/iris_heap_lang/lib/lock.v
+++ b/iris_heap_lang/lib/lock.v
@@ -8,42 +8,52 @@ All parameters are implicit, since it is expected that there is only one
 [heapGS_gen] in scope that could possibly apply.
 
 Only one instance of this class should ever be in scope. To write a library that
-is generic over the lock, just add a [`{lock}] implicit parameter. To use a
-particular lock instance, use [Local Existing Instance <lock instance>].
+is generic over the lock, just add a [`{!lock}] implicit parameter around the
+code and [`{!lockG Σ}] around the proofs. To use a particular lock instance, use
+[Local Existing Instance <lock instance>].
 
 When writing an instance of this class, please take care not to shadow the class
 projections (e.g., either use [Local Definition newlock] or avoid the name
 [newlock] altogether), and do not register an instance -- just make it a
 [Definition] that others can register later. *)
-Class lock `{!heapGS_gen hlc Σ} := Lock {
+Class lock := Lock {
   (** * Operations *)
   newlock : val;
   acquire : val;
   release : val;
-  (** * Predicates *)
-  (** [name] is used to associate locked with [is_lock] *)
+  (** * Ghost state *)
+  (** The assumptions about [Σ] *)
+  lockG : gFunctors → Type;
+  (** [name] is used to associate [locked] with [is_lock] *)
   lock_name : Type;
+  (** * Predicates *)
   (** No namespace [N] parameter because we only expose program specs, which
   anyway have the full mask. *)
-  is_lock (γ: lock_name) (lock: val) (R: iProp Σ) : iProp Σ;
-  locked (γ: lock_name) : iProp Σ;
+  is_lock `{!heapGS_gen hlc Σ} {L : lockG Σ} (γ: lock_name) (lock: val) (R: iProp Σ) : iProp Σ;
+  locked `{!heapGS_gen hlc Σ} {L : lockG Σ} (γ: lock_name) : iProp Σ;
   (** * General properties of the predicates *)
-  is_lock_persistent γ lk R :> Persistent (is_lock γ lk R);
-  is_lock_iff γ lk R1 R2 :
-    is_lock γ lk R1 -∗ ▷ □ (R1 ∗-∗ R2) -∗ is_lock γ lk R2;
-  locked_timeless γ :> Timeless (locked γ);
-  locked_exclusive γ : locked γ -∗ locked γ -∗ False;
+  is_lock_persistent `{!heapGS_gen hlc Σ} {L : lockG Σ} γ lk R :>
+    Persistent (is_lock (L:=L) γ lk R);
+  is_lock_iff `{!heapGS_gen hlc Σ} {L : lockG Σ} γ lk R1 R2 :
+    is_lock (L:=L) γ lk R1 -∗ ▷ □ (R1 ∗-∗ R2) -∗ is_lock (L:=L) γ lk R2;
+  locked_timeless `{!heapGS_gen hlc Σ} {L : lockG Σ} γ :>
+    Timeless (locked (L:=L) γ);
+  locked_exclusive `{!heapGS_gen hlc Σ} {L : lockG Σ} γ :
+    locked (L:=L) γ -∗ locked (L:=L) γ -∗ False;
   (** * Program specs *)
-  newlock_spec (R : iProp Σ) :
-    {{{ R }}} newlock #() {{{ lk γ, RET lk; is_lock γ lk R }}};
-  acquire_spec γ lk R :
-    {{{ is_lock γ lk R }}} acquire lk {{{ RET #(); locked γ ∗ R }}};
-  release_spec γ lk R :
-    {{{ is_lock γ lk R ∗ locked γ ∗ R }}} release lk {{{ RET #(); True }}}
+  newlock_spec `{!heapGS_gen hlc Σ} {L : lockG Σ} (R : iProp Σ) :
+    {{{ R }}} newlock #() {{{ lk γ, RET lk; is_lock (L:=L) γ lk R }}};
+  acquire_spec `{!heapGS_gen hlc Σ} {L : lockG Σ} γ lk R :
+    {{{ is_lock (L:=L) γ lk R }}} acquire lk {{{ RET #(); locked (L:=L) γ ∗ R }}};
+  release_spec `{!heapGS_gen hlc Σ} {L : lockG Σ} γ lk R :
+    {{{ is_lock (L:=L) γ lk R ∗ locked (L:=L) γ ∗ R }}} release lk {{{ RET #(); True }}}
 }.
-Global Hint Mode lock + + + : typeclass_instances.
 
-Global Instance is_lock_contractive `{!heapGS_gen hlc Σ, !lock} γ lk :
+Existing Class lockG.
+Global Hint Mode lockG + + : typeclass_instances.
+Global Hint Extern 0 (lockG _) => progress simpl : typeclass_instances.
+
+Global Instance is_lock_contractive `{!heapGS_gen hlc Σ, !lock, !lockG Σ} γ lk :
   Contractive (is_lock γ lk).
 Proof.
   apply (uPred.contractive_internal_eq (M:=iResUR Σ)).
@@ -52,5 +62,5 @@ Proof.
     iNext; iRewrite "HPQ"; auto.
 Qed.
 
-Global Instance is_lock_proper `{!heapGS_gen hlc Σ, !lock} γ lk :
+Global Instance is_lock_proper `{!heapGS_gen hlc Σ, !lock, !lockG Σ} γ lk :
   Proper ((≡) ==> (≡)) (is_lock γ lk) := ne_proper _.
diff --git a/iris_heap_lang/lib/logatom_lock.v b/iris_heap_lang/lib/logatom_lock.v
index e2cddb9ee..859fea3d5 100644
--- a/iris_heap_lang/lib/logatom_lock.v
+++ b/iris_heap_lang/lib/logatom_lock.v
@@ -18,14 +18,14 @@ From iris.prelude Require Import options.
 
 Inductive state := Free | Locked.
 
-Class lockG Σ := LockG { lock_tokG : ghost_varG Σ state }.
+Class alockG Σ := LockG { lock_tokG : ghost_varG Σ state }.
 Local Existing Instance lock_tokG.
-Definition lockΣ : gFunctors := #[ghost_varΣ state].
-Global Instance subG_lockΣ {Σ} : subG lockΣ Σ → lockG Σ.
+Definition alockΣ : gFunctors := #[ghost_varΣ state].
+Global Instance subG_alockΣ {Σ} : subG alockΣ Σ → alockG Σ.
 Proof. solve_inG. Qed.
 
 Section tada.
-  Context `{!heapGS Σ, !lockG Σ, !lock}.
+  Context `{!heapGS Σ, !alockG Σ, !lock, !lockG Σ}.
 
   Record tada_lock_name := TadaLockName {
     tada_lock_name_state : gname;
diff --git a/iris_heap_lang/lib/spin_lock.v b/iris_heap_lang/lib/spin_lock.v
index 8686e3e03..9055ad138 100644
--- a/iris_heap_lang/lib/spin_lock.v
+++ b/iris_heap_lang/lib/spin_lock.v
@@ -14,16 +14,16 @@ Local Definition release : val := λ: "l", "l" <- #false.
 
 (** The CMRA we need. *)
 (* Not bundling heapGS, as it may be shared with other users. *)
-Class lockG Σ := LockG { lock_tokG : inG Σ (exclR unitO) }.
+Class spin_lockG Σ := LockG { lock_tokG : inG Σ (exclR unitO) }.
 Local Existing Instance lock_tokG.
 
-Definition lockΣ : gFunctors := #[GFunctor (exclR unitO)].
+Definition spin_lockΣ : gFunctors := #[GFunctor (exclR unitO)].
 
-Global Instance subG_lockΣ {Σ} : subG lockΣ Σ → lockG Σ.
+Global Instance subG_spin_lockΣ {Σ} : subG spin_lockΣ Σ → spin_lockG Σ.
 Proof. solve_inG. Qed.
 
 Section proof.
-  Context `{!heapGS_gen hlc Σ, !lockG Σ}.
+  Context `{!heapGS_gen hlc Σ, !spin_lockG Σ}.
   Let N := nroot .@ "spin_lock".
 
   Local Definition lock_inv (γ : gname) (l : loc) (R : iProp Σ) : iProp Σ :=
@@ -92,7 +92,12 @@ Section proof.
   Qed.
 End proof.
 
-Definition spin_lock `{!heapGS_gen hlc Σ, !lockG Σ} : lock :=
-  {| lock.locked_exclusive := locked_exclusive; lock.is_lock_iff := is_lock_iff;
-     lock.newlock_spec := newlock_spec;
-     lock.acquire_spec := acquire_spec; lock.release_spec := release_spec |}.
+(* NOT an instance because users should choose explicitly to use it
+     (using [Explicit Instance]). *)
+Definition spin_lock : lock :=
+  {| lock.lockG := spin_lockG;
+     lock.locked_exclusive _ _ _ _ := locked_exclusive;
+     lock.is_lock_iff _ _ _ _ := is_lock_iff;
+     lock.newlock_spec _ _ _ _ := newlock_spec;
+     lock.acquire_spec _ _ _ _ := acquire_spec;
+     lock.release_spec _ _ _ _ := release_spec |}.
diff --git a/iris_heap_lang/lib/ticket_lock.v b/iris_heap_lang/lib/ticket_lock.v
index 02c4e48d0..0f9f1f47d 100644
--- a/iris_heap_lang/lib/ticket_lock.v
+++ b/iris_heap_lang/lib/ticket_lock.v
@@ -163,7 +163,10 @@ Section proof.
   Qed.
 End proof.
 
-Definition ticket_lock `{!heapGS_gen hlc Σ, !tlockG Σ} : lock :=
-  {| lock.locked_exclusive := locked_exclusive; lock.is_lock_iff := is_lock_iff;
-     lock.newlock_spec := newlock_spec;
-     lock.acquire_spec := acquire_spec; lock.release_spec := release_spec |}.
+Definition ticket_lock : lock :=
+  {| lock.lockG := tlockG;
+     lock.locked_exclusive _ _ _ _ := locked_exclusive;
+     lock.is_lock_iff _ _ _ _ := is_lock_iff;
+     lock.newlock_spec _ _ _ _ := newlock_spec;
+     lock.acquire_spec _ _ _ _ := acquire_spec;
+     lock.release_spec _ _ _ _ := release_spec |}.
diff --git a/tests/heap_lang.v b/tests/heap_lang.v
index 96d71b08b..c5f966bb0 100644
--- a/tests/heap_lang.v
+++ b/tests/heap_lang.v
@@ -1,6 +1,6 @@
 From iris.base_logic.lib Require Import gen_inv_heap invariants.
 From iris.program_logic Require Export weakestpre total_weakestpre.
-From iris.heap_lang Require Import lang adequacy total_adequacy proofmode notation lib.lock.
+From iris.heap_lang Require Import lang adequacy total_adequacy proofmode notation lib.spin_lock.
 From iris.prelude Require Import options.
 
 Unset Mangle Names.
@@ -516,7 +516,7 @@ Qed.
 
 (** Just making sure the lock typeclass actually works. *)
 Section lock.
-  Context `{!heapGS Σ, !lock}.
+  Context `{!lock}.
 
   Definition lock_client : val :=
     λ: "loc" "lock",
@@ -524,6 +524,8 @@ Section lock.
       "loc" <- #42;;
       release "lock".
 
+  Context `{!heapGS Σ, !lockG Σ}.
+
   Lemma wp_lock_client loc lock γ :
     is_lock γ lock (∃ v, loc ↦ v) -∗
     WP lock_client #loc lock {{ _, True }}.
@@ -535,6 +537,28 @@ Section lock.
     { iFrame "Hislock". eauto. }
     eauto.
   Qed.
-
 End lock.
+Section spin_lock.
+  Local Existing Instance spin_lock.
 
+  Definition spin_lock_client : val :=
+    λ: "loc" "lock",
+      acquire "lock";;
+      "loc" <- #42;;
+      release "lock".
+
+  (* Making sure that using [spin_lockG] here works, not just [lockG]. *)
+  Context `{!heapGS Σ, !spin_lockG Σ}.
+
+  Lemma wp_spin_lock_client loc lock γ :
+    is_lock γ lock (∃ v, loc ↦ v) -∗
+    WP spin_lock_client #loc lock {{ _, True }}.
+  Proof.
+    iIntros "#Hislock".
+    wp_lam. wp_smart_apply (acquire_spec with "Hislock") as "[Hlocked [%v Hloc]]".
+    wp_store.
+    wp_smart_apply (release_spec with "[$Hlocked Hloc]").
+    { iFrame "Hislock". eauto. }
+    eauto.
+  Qed.
+End spin_lock.
-- 
GitLab