From ae5de30b8ee02543f8819f73b3067a358d81d4ac Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Mon, 8 Oct 2018 16:23:00 +0200
Subject: [PATCH] Allow `IntoVal` to take pure steps.

---
 tests/one_shot.v                          |  4 +-
 theories/heap_lang/lib/assert.v           |  4 +-
 theories/heap_lang/lib/par.v              |  2 +-
 theories/heap_lang/lib/spawn.v            |  2 +-
 theories/heap_lang/lib/ticket_lock.v      |  2 +-
 theories/heap_lang/lifting.v              | 89 +++++++++++++++--------
 theories/heap_lang/proofmode.v            | 18 +++--
 theories/program_logic/language.v         |  3 +-
 theories/program_logic/lifting.v          | 14 +++-
 theories/program_logic/ownp.v             |  4 +-
 theories/program_logic/total_lifting.v    | 14 +++-
 theories/program_logic/total_weakestpre.v |  6 --
 theories/program_logic/weakestpre.v       |  7 --
 13 files changed, 106 insertions(+), 63 deletions(-)

diff --git a/tests/one_shot.v b/tests/one_shot.v
index e39d64886..b50d6930c 100644
--- a/tests/one_shot.v
+++ b/tests/one_shot.v
@@ -47,7 +47,7 @@ Proof.
   iMod (own_alloc Pending) as (γ) "Hγ"; first done.
   iMod (inv_alloc N _ (one_shot_inv γ l) with "[Hl Hγ]") as "#HN".
   { iNext. iLeft. by iSplitL "Hl". }
-  wp_closure. wp_closure. wp_pair. iModIntro. iApply "Hf"; iSplit.
+  iModIntro. iApply "Hf"; iSplit.
   - iIntros (n) "!#". wp_lam. wp_inj. wp_inj.
     iInv N as ">[[Hl Hγ]|H]"; last iDestruct "H" as (m) "[Hl Hγ]".
     + iMod (own_update with "Hγ") as "Hγ".
@@ -70,7 +70,7 @@ Proof.
       + Show. iSplit. iLeft; by iSplitL "Hl". eauto.
       + iSplit. iRight; iExists m; by iSplitL "Hl". eauto. }
     iSplitL "Hinv"; first by eauto.
-    iModIntro. wp_let. wp_closure. iIntros "!#". wp_lam.
+    iModIntro. wp_let. iIntros "!#". wp_lam.
     iDestruct "Hv" as "[%|Hv]"; last iDestruct "Hv" as (m) "[% Hγ']"; subst.
     { by wp_match. }
     wp_match. wp_bind (! _)%E.
diff --git a/theories/heap_lang/lib/assert.v b/theories/heap_lang/lib/assert.v
index 4a7733f14..74153e753 100644
--- a/theories/heap_lang/lib/assert.v
+++ b/theories/heap_lang/lib/assert.v
@@ -12,13 +12,13 @@ Notation "'assert:' e" := (assert (λ: <>, e))%E (at level 99) : expr_scope.
 Lemma twp_assert `{heapG Σ} E (Φ : val → iProp Σ) e :
   WP e @ E [{ v, ⌜v = #true⌝ ∧ Φ #() }] -∗ WP assert: e @ E [{ Φ }].
 Proof.
-  iIntros "HΦ". rewrite /assert. wp_closure. wp_lam. wp_lam.
+  iIntros "HΦ". rewrite /assert. wp_lam. wp_lam.
   wp_apply (twp_wand with "HΦ"). iIntros (v) "[% ?]"; subst. by wp_if.
 Qed.
 
 Lemma wp_assert `{heapG Σ} E (Φ : val → iProp Σ) e :
   WP e @ E {{ v, ⌜v = #true⌝ ∧ ▷ Φ #() }} -∗ WP assert: e @ E {{ Φ }}.
 Proof.
-  iIntros "HΦ". rewrite /assert. wp_closure. wp_lam. wp_lam.
+  iIntros "HΦ". rewrite /assert. wp_lam. wp_lam.
   wp_apply (wp_wand with "HΦ"). iIntros (v) "[% ?]"; subst. by wp_if.
 Qed.
diff --git a/theories/heap_lang/lib/par.v b/theories/heap_lang/lib/par.v
index 4691dfefc..ee7f1c8c7 100644
--- a/theories/heap_lang/lib/par.v
+++ b/theories/heap_lang/lib/par.v
@@ -32,7 +32,7 @@ Proof.
   iIntros (l) "Hl". wp_let. wp_bind (f2 _).
   wp_apply (wp_wand with "Hf2"); iIntros (v) "H2". wp_let.
   wp_apply (join_spec with "[$Hl]"). iIntros (w) "H1".
-  iSpecialize ("HΦ" with "[-]"); first by iSplitL "H1". wp_let. by wp_pair.
+  iSpecialize ("HΦ" with "[-]"); first by iSplitL "H1". by wp_let.
 Qed.
 
 Lemma wp_par (Ψ1 Ψ2 : val → iProp Σ) (e1 e2 : expr) (Φ : val → iProp Σ) :
diff --git a/theories/heap_lang/lib/spawn.v b/theories/heap_lang/lib/spawn.v
index 900f75786..ae8208bbe 100644
--- a/theories/heap_lang/lib/spawn.v
+++ b/theories/heap_lang/lib/spawn.v
@@ -48,7 +48,7 @@ Lemma spawn_spec (Ψ : val → iProp Σ) e (f : val) :
   IntoVal e f →
   {{{ WP f #() {{ Ψ }} }}} spawn e {{{ l, RET #l; join_handle l Ψ }}}.
 Proof.
-  iIntros (<- Φ) "Hf HΦ". rewrite /spawn /=.
+  iIntros (? Φ) "Hf HΦ". rewrite /spawn /=.
   wp_lam. wp_inj. wp_alloc l as "Hl". wp_let.
   iMod (own_alloc (Excl ())) as (γ) "Hγ"; first done.
   iMod (inv_alloc N _ (spawn_inv γ l Ψ) with "[Hl]") as "#?".
diff --git a/theories/heap_lang/lib/ticket_lock.v b/theories/heap_lang/lib/ticket_lock.v
index 2da04f578..509c13753 100644
--- a/theories/heap_lang/lib/ticket_lock.v
+++ b/theories/heap_lang/lib/ticket_lock.v
@@ -80,7 +80,7 @@ Section proof.
     iMod (inv_alloc _ _ (lock_inv γ lo ln R) with "[-HΦ]").
     { iNext. rewrite /lock_inv.
       iExists 0%nat, 0%nat. iFrame. iLeft. by iFrame. }
-    wp_pair. iModIntro. iApply ("HΦ" $! (#lo, #ln)%V γ). iExists lo, ln. eauto.
+    iModIntro. iApply ("HΦ" $! (#lo, #ln)%V γ). iExists lo, ln. eauto.
   Qed.
 
   Lemma wait_loop_spec γ lk x R :
diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v
index efbd8ffa9..5e5010252 100644
--- a/theories/heap_lang/lifting.v
+++ b/theories/heap_lang/lifting.v
@@ -47,11 +47,6 @@ Local Hint Constructors head_step.
 Local Hint Resolve alloc_fresh.
 Local Hint Resolve to_of_val.
 
-Instance into_val_val v : IntoVal (Val v) v.
-Proof. done. Qed.
-Instance as_val_val v : AsVal (Val v).
-Proof. by eexists. Qed.
-
 Local Ltac solve_atomic :=
   apply strongly_atomic_atomic, ectx_language_atomic;
     [inversion 1; naive_solver
@@ -72,10 +67,19 @@ Proof. solve_atomic. Qed.
 Instance skip_atomic s  : Atomic s Skip.
 Proof. solve_atomic. Qed.
 
+Local Ltac pure_exec_step :=
+  lazymatch goal with
+  | |- PureExec _ _ ?e _ => eapply pure_exec_0_l;
+     [reshape_expr e ltac:(fun K e' =>
+        eapply (pure_exec_fill K); eassumption)
+     |simpl]
+  end.
 Local Ltac solve_exec_safe := intros; subst; do 3 eexists; econstructor; eauto.
 Local Ltac solve_exec_puredet := simpl; intros; by inv_head_step.
 Local Ltac solve_pure_exec :=
-  subst;
+  intros; unfold IntoVal;
+  repeat pure_exec_step;
+  eapply pure_exec_mono_steps with 1%nat; [lia|];
   apply mk_pure_exec; intros ?;
   apply nsteps_once, pure_head_step_pure_step;
     constructor; [solve_exec_safe | solve_exec_puredet].
@@ -87,51 +91,78 @@ Instance AsRecV_recv_locked v f x e :
   AsRecV v f x e → AsRecV (locked v) f x e.
 Proof. by unlock. Qed.
 
-Instance pure_recc f x (erec : expr) :
+Instance into_val_val v : IntoVal (Val v) v.
+Proof. apply pure_exec_refl. Qed.
+Instance into_val_recc f x erec :
+  IntoVal (Rec f x erec) (RecV f x erec).
+Proof. solve_pure_exec. Qed.
+Instance into_val_pairc e1 e2 v1 v2 :
+  IntoVal e1 v1 → IntoVal e2 v2 →
+  IntoVal (Pair e1 e2) (PairV v1 v2).
+Proof. solve_pure_exec. Qed.
+Instance into_val_injlc v :
+  IntoVal e v → IntoVal (InjL e) (InjLV v).
+Proof. solve_pure_exec. Qed.
+Instance into_val_injrc e v :
+  IntoVal e v → IntoVal (InjR e) (InjRV v).
+Proof. solve_pure_exec. Qed.
+
+Instance pure_recc f x erec :
   PureExec True 1 (Rec f x erec) (Val $ RecV f x erec).
 Proof. solve_pure_exec. Qed.
-Instance pure_pairc (v1 v2 : val) :
-  PureExec True 1 (Pair (Val v1) (Val v2)) (Val $ PairV v1 v2).
+Instance pure_pairc v1 v2 :
+  IntoVal e1 v1 → IntoVal e2 v2 →
+  PureExec True 1 (Pair e1 e2) (Val $ PairV v1 v2).
 Proof. solve_pure_exec. Qed.
-Instance pure_injlc (v : val) :
-  PureExec True 1 (InjL $ Val v) (Val $ InjLV v).
+Instance pure_injlc v :
+  IntoVal e v → PureExec True 1 (InjL e) (Val $ InjLV v).
 Proof. solve_pure_exec. Qed.
 Instance pure_injrc (v : val) :
-  PureExec True 1 (InjR $ Val v) (Val $ InjRV v).
+  IntoVal e v → PureExec True 1 (InjR e) (Val $ InjRV v).
 Proof. solve_pure_exec. Qed.
 
-Instance pure_beta f x (erec : expr) (v1 v2 : val) `{AsRecV v1 f x erec} :
-  PureExec True 1 (App (Val v1) (Val v2)) (subst' x v2 (subst' f v1 erec)).
-Proof. unfold AsRecV in *. solve_pure_exec. Qed.
+Instance pure_beta e1 e2 f x (erec : expr) (v1 v2 : val)  :
+  IntoVal e1 v1 → AsRecV v1 f x erec →
+  IntoVal e2 v2 →
+  PureExec True 1 (App e1 e2) (subst' x v2 (subst' f v1 erec)).
+Proof. unfold AsRecV. solve_pure_exec. Qed.
 
-Instance pure_unop op v v' :
-  PureExec (un_op_eval op v = Some v') 1 (UnOp op (Val v)) (Val v').
+Instance pure_unop op e v v' :
+  IntoVal e v →
+  PureExec (un_op_eval op v = Some v') 1 (UnOp op e) (Val v').
 Proof. solve_pure_exec. Qed.
 
-Instance pure_binop op v1 v2 v' :
-  PureExec (bin_op_eval op v1 v2 = Some v') 1 (BinOp op (Val v1) (Val v2)) (Val v').
+Instance pure_binop op e1 e2 v1 v2 v' :
+  IntoVal e1 v1 → IntoVal e2 v2 →
+  PureExec (bin_op_eval op v1 v2 = Some v') 1 (BinOp op e1 e2) (Val v').
 Proof. solve_pure_exec. Qed.
 
-Instance pure_if_true e1 e2 : PureExec True 1 (If (Val $ LitV $ LitBool true) e1 e2) e1.
+Instance pure_if_true e1 e2 :
+  PureExec True 1 (If (Val $ LitV $ LitBool true) e1 e2) e1.
 Proof. solve_pure_exec. Qed.
 
-Instance pure_if_false e1 e2 : PureExec True 1 (If (Val $ LitV  $ LitBool false) e1 e2) e2.
+Instance pure_if_false e1 e2 :
+  PureExec True 1 (If (Val $ LitV  $ LitBool false) e1 e2) e2.
 Proof. solve_pure_exec. Qed.
 
-Instance pure_fst v1 v2 :
-  PureExec True 1 (Fst (Val $ PairV v1 v2)) (Val v1).
+Instance pure_fst e v1 v2 :
+  IntoVal e (PairV v1 v2) →
+  PureExec True 1 (Fst e) (Val v1).
 Proof. solve_pure_exec. Qed.
 
-Instance pure_snd v1 v2 :
-  PureExec True 1 (Snd (Val $ PairV v1 v2)) (Val v2).
+Instance pure_snd e v1 v2 :
+  IntoVal e (PairV v1 v2) →
+  PureExec True 1 (Snd e) (Val v2).
 Proof. solve_pure_exec. Qed.
 
-Instance pure_case_inl v e1 e2 :
-  PureExec True 1 (Case (Val $ InjLV v) e1 e2) (App e1 (Val v)).
+Instance pure_case_inl e v e1 e2 :
+  IntoVal e (InjLV v) →
+  PureExec True 1 (Case e e1 e2) (App e1 (Val v)).
 Proof. solve_pure_exec. Qed.
 
-Instance pure_case_inr v e1 e2 :
-  PureExec True 1 (Case (Val $ InjRV v) e1 e2) (App e2 (Val v)).
+Instance pure_case_inr e v e1 e2 :
+  IntoVal e (InjRV v) →
+  PureExec True 1 (Case e e1 e2) (App e2 (Val v)).
 Proof. solve_pure_exec. Qed.
 
 Section lifting.
diff --git a/theories/heap_lang/proofmode.v b/theories/heap_lang/proofmode.v
index 5b36ffb62..911d55e0a 100644
--- a/theories/heap_lang/proofmode.v
+++ b/theories/heap_lang/proofmode.v
@@ -48,15 +48,19 @@ Proof.
   rewrite envs_entails_eq=> ?? ->. rewrite -total_lifting.twp_pure_step //.
 Qed.
 
-Lemma tac_wp_value `{heapG Σ} Δ s E Φ v :
-  envs_entails Δ (Φ v) → envs_entails Δ (WP (Val v) @ s; E {{ Φ }}).
-Proof. rewrite envs_entails_eq=> ->. by apply wp_value. Qed.
-Lemma tac_twp_value `{heapG Σ} Δ s E Φ v :
-  envs_entails Δ (Φ v) → envs_entails Δ (WP (Val v) @ s; E [{ Φ }]).
-Proof. rewrite envs_entails_eq=> ->. by apply twp_value. Qed.
+Lemma tac_wp_value `{heapG Σ} Δ s E Φ e v :
+  IntoVal e v →
+  envs_entails Δ (Φ v) → envs_entails Δ (WP e @ s; E {{ Φ }}).
+Proof. rewrite envs_entails_eq=> ? ->. by apply lifting.wp_value. Qed.
+Lemma tac_twp_value `{heapG Σ} Δ s E Φ e v :
+  IntoVal e v →
+  envs_entails Δ (Φ v) → envs_entails Δ (WP e @ s; E [{ Φ }]).
+Proof. rewrite envs_entails_eq=> ? ->. by apply total_lifting.twp_value. Qed.
 
 Ltac wp_value_head :=
-  first [eapply tac_wp_value || eapply tac_twp_value]; reduction.pm_prettify.
+  first [eapply tac_wp_value || eapply tac_twp_value];
+    [iSolveTC
+    |reduction.pm_prettify].
 
 Tactic Notation "wp_pure" open_constr(efoc) :=
   iStartProof;
diff --git a/theories/program_logic/language.v b/theories/program_logic/language.v
index e75364098..49402f7c9 100644
--- a/theories/program_logic/language.v
+++ b/theories/program_logic/language.v
@@ -198,8 +198,9 @@ Section language.
 
   (* This is a family of frequent assumptions for PureExec *)
   Class IntoVal (e : expr Λ) (v : val Λ) :=
-    into_val : of_val v = e.
+    into_val : PureExec True 0 e (of_val v).
 
+  (* TODO: either drop this class, or change it so that it matches IntoVal *)
   Class AsVal (e : expr Λ) := as_val : ∃ v, of_val v = e.
   (* There is no instance [IntoVal → AsVal] as often one can solve [AsVal] more
   efficiently since no witness has to be computed. *)
diff --git a/theories/program_logic/lifting.v b/theories/program_logic/lifting.v
index c00630b8d..7c9e2991f 100644
--- a/theories/program_logic/lifting.v
+++ b/theories/program_logic/lifting.v
@@ -93,8 +93,8 @@ Proof.
   iMod ("H" $! e2 σ2 efs with "[#]") as "H"; [done|].
   iMod (fupd_intro_mask' E2 ∅) as "Hclose"; [set_solver|]. iIntros "!> !>".
   iMod "Hclose" as "_". iMod "H" as "($ & HΦ & $)".
-  destruct (to_val e2) eqn:?; last by iExFalso.
-  iApply wp_value; last done. by apply of_to_val.
+  destruct (to_val e2) eqn:He2; last by iExFalso.
+  apply of_to_val in He2 as <-. by iApply wp_value'.
 Qed.
 
 Lemma wp_lift_atomic_step {s E Φ} e1 :
@@ -150,4 +150,14 @@ Proof.
   intros Hexec ?. rewrite -wp_pure_step_fupd //. clear Hexec.
   induction n as [|n IH]; by rewrite //= -step_fupd_intro // IH.
 Qed.
+
+Lemma wp_value `{Inhabited (state Λ)} s E Φ e v :
+  IntoVal e v → Φ v ⊢ WP e @ s; E {{ Φ }}.
+Proof.
+  rewrite /IntoVal. iIntros (?) "?". iApply wp_pure_step_later=> //=.
+  by iApply wp_value'.
+Qed.
+Lemma wp_value_fupd `{Inhabited (state Λ)} s E Φ e v :
+  IntoVal e v → (|={E}=> Φ v) ⊢ WP e @ s; E {{ Φ }}.
+Proof. intros. rewrite -wp_fupd -wp_value //. Qed.
 End lifting.
diff --git a/theories/program_logic/ownp.v b/theories/program_logic/ownp.v
index 59f471673..c8385a2a7 100644
--- a/theories/program_logic/ownp.v
+++ b/theories/program_logic/ownp.v
@@ -146,8 +146,8 @@ Section lifting.
     iModIntro; iExists σ1; iFrame; iSplit; first by destruct s.
     iNext; iIntros (e2 σ2 efs) "% Hσ".
     iDestruct ("H" $! e2 σ2 efs with "[] [Hσ]") as "[HΦ $]"; [by eauto..|].
-    destruct (to_val e2) eqn:?; last by iExFalso.
-    iMod "Hclose"; iApply wp_value; last done. by apply of_to_val.
+    destruct (to_val e2) eqn:He2; last by iExFalso.
+    iMod "Hclose". apply of_to_val in He2 as <-. by iApply wp_value'.
   Qed.
 
   Lemma ownP_lift_atomic_det_step {s E Φ e1} σ1 v2 σ2 efs :
diff --git a/theories/program_logic/total_lifting.v b/theories/program_logic/total_lifting.v
index 2577a5b14..ce3c36652 100644
--- a/theories/program_logic/total_lifting.v
+++ b/theories/program_logic/total_lifting.v
@@ -53,8 +53,8 @@ Proof.
   iMod (fupd_intro_mask' E ∅) as "Hclose"; first set_solver.
   iIntros "!>" (e2 σ2 efs) "%". iMod "Hclose" as "_".
   iMod ("H" $! e2 σ2 efs with "[#]") as "($ & HΦ & $)"; first by eauto.
-  destruct (to_val e2) eqn:?; last by iExFalso.
-  iApply twp_value; last done. by apply of_to_val.
+  destruct (to_val e2) eqn:He2; last by iExFalso.
+  apply of_to_val in He2 as <-. by iApply twp_value'.
 Qed.
 
 Lemma twp_lift_pure_det_step `{Inhabited (state Λ)} {s E Φ} e1 e2 efs :
@@ -78,4 +78,14 @@ Proof.
   iApply twp_lift_pure_det_step; [done|naive_solver|].
   iModIntro. rewrite /= right_id. by iApply "IH".
 Qed.
+
+Lemma twp_value `{Inhabited (state Λ)} s E Φ e v :
+  IntoVal e v → Φ v -∗ WP e @ s; E [{ Φ }].
+Proof.
+  rewrite /IntoVal. iIntros (?) "?". iApply twp_pure_step=> //=.
+  by iApply twp_value'.
+Qed.
+Lemma twp_value_fupd `{Inhabited (state Λ)} s E Φ e v :
+  IntoVal e v → (|={E}=> Φ v) -∗ WP e @ s; E [{ Φ }].
+Proof. intros ?. rewrite -twp_fupd -twp_value //. Qed.
 End lifting.
diff --git a/theories/program_logic/total_weakestpre.v b/theories/program_logic/total_weakestpre.v
index 9e8cf93ef..9e0aaa747 100644
--- a/theories/program_logic/total_weakestpre.v
+++ b/theories/program_logic/total_weakestpre.v
@@ -213,14 +213,8 @@ Global Instance twp_mono' s E e :
   Proper (pointwise_relation _ (⊢) ==> (⊢)) (twp (PROP:=iProp Σ) s E e).
 Proof. by intros Φ Φ' ?; apply twp_mono. Qed.
 
-Lemma twp_value s E Φ e v : IntoVal e v → Φ v -∗ WP e @ s; E [{ Φ }].
-Proof. intros <-. by apply twp_value'. Qed.
 Lemma twp_value_fupd' s E Φ v : (|={E}=> Φ v) -∗ WP of_val v @ s; E [{ Φ }].
 Proof. intros. by rewrite -twp_fupd -twp_value'. Qed.
-Lemma twp_value_fupd s E Φ e v : IntoVal e v → (|={E}=> Φ v) -∗ WP e @ s; E [{ Φ }].
-Proof. intros ?. rewrite -twp_fupd -twp_value //. Qed.
-Lemma twp_value_inv s E Φ e v : IntoVal e v → WP e @ s; E [{ Φ }] ={E}=∗ Φ v.
-Proof. intros <-. by apply twp_value_inv'. Qed.
 
 Lemma twp_frame_l s E e Φ R : R ∗ WP e @ s; E [{ Φ }] -∗ WP e @ s; E [{ v, R ∗ Φ v }].
 Proof. iIntros "[? H]". iApply (twp_strong_mono with "H"); auto with iFrame. Qed.
diff --git a/theories/program_logic/weakestpre.v b/theories/program_logic/weakestpre.v
index 023966eb0..62c230e59 100644
--- a/theories/program_logic/weakestpre.v
+++ b/theories/program_logic/weakestpre.v
@@ -175,15 +175,8 @@ Global Instance wp_mono' s E e :
   Proper (pointwise_relation _ (⊢) ==> (⊢)) (wp (PROP:=iProp Σ) s E e).
 Proof. by intros Φ Φ' ?; apply wp_mono. Qed.
 
-Lemma wp_value s E Φ e v : IntoVal e v → Φ v ⊢ WP e @ s; E {{ Φ }}.
-Proof. intros <-. by apply wp_value'. Qed.
 Lemma wp_value_fupd' s E Φ v : (|={E}=> Φ v) ⊢ WP of_val v @ s; E {{ Φ }}.
 Proof. intros. by rewrite -wp_fupd -wp_value'. Qed.
-Lemma wp_value_fupd s E Φ e v `{!IntoVal e v} :
-  (|={E}=> Φ v) ⊢ WP e @ s; E {{ Φ }}.
-Proof. intros. rewrite -wp_fupd -wp_value //. Qed.
-Lemma wp_value_inv s E Φ e v : IntoVal e v → WP e @ s; E {{ Φ }} ={E}=∗ Φ v.
-Proof. intros <-. by apply wp_value_inv'. Qed.
 
 Lemma wp_frame_l s E e Φ R : R ∗ WP e @ s; E {{ Φ }} ⊢ WP e @ s; E {{ v, R ∗ Φ v }}.
 Proof. iIntros "[? H]". iApply (wp_strong_mono with "H"); auto with iFrame. Qed.
-- 
GitLab