From 6a086fc67cc07bd01d58a99c6d587e5329101258 Mon Sep 17 00:00:00 2001
From: Jacques-Henri Jourdan <jacques-henri.jourdan@normalesup.org>
Date: Mon, 12 Feb 2018 23:59:15 +0100
Subject: [PATCH] Make FromPure depend on an affinity parameter.

---
 theories/base_logic/base_logic.v     |   6 +-
 theories/proofmode/class_instances.v | 156 ++++++++++++++++-----------
 theories/proofmode/classes.v         |  27 ++---
 theories/proofmode/coq_tactics.v     |  17 +--
 theories/proofmode/monpred.v         |   8 +-
 theories/proofmode/tactics.v         |  10 +-
 theories/tests/proofmode.v           |  14 +++
 7 files changed, 145 insertions(+), 93 deletions(-)

diff --git a/theories/base_logic/base_logic.v b/theories/base_logic/base_logic.v
index bcc18e6fd..5a947722e 100644
--- a/theories/base_logic/base_logic.v
+++ b/theories/base_logic/base_logic.v
@@ -31,10 +31,10 @@ Global Instance into_pure_cmra_valid `{CmraDiscrete A} (a : A) :
   @IntoPure (uPredI M) (✓ a) (✓ a).
 Proof. by rewrite /IntoPure discrete_valid. Qed.
 
-Global Instance from_pure_cmra_valid {A : cmraT} (a : A) :
-  @FromPure (uPredI M) (✓ a) (✓ a).
+Global Instance from_pure_cmra_valid {A : cmraT} af (a : A) :
+  @FromPure (uPredI M) af (✓ a) (✓ a).
 Proof.
-  rewrite /FromPure. eapply bi.pure_elim; [done|]=> ?.
+  rewrite /FromPure. eapply bi.pure_elim; [by apply affinely_if_elim|]=> ?.
   rewrite -cmra_valid_intro //. by apply pure_intro.
 Qed.
 
diff --git a/theories/proofmode/class_instances.v b/theories/proofmode/class_instances.v
index 52e0daac8..93383cc92 100644
--- a/theories/proofmode/class_instances.v
+++ b/theories/proofmode/class_instances.v
@@ -138,8 +138,8 @@ Global Instance into_pure_pure_or (φ1 φ2 : Prop) P1 P2 :
   IntoPure P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 ∨ P2) (φ1 ∨ φ2).
 Proof. rewrite /IntoPure pure_or. by intros -> ->. Qed.
 Global Instance into_pure_pure_impl (φ1 φ2 : Prop) P1 P2 :
-  FromPure P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 → P2) (φ1 → φ2).
-Proof. rewrite /FromPure /IntoPure pure_impl. by intros -> ->. Qed.
+  FromPure false P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 → P2) (φ1 → φ2).
+Proof. rewrite /FromPure /IntoPure pure_impl=> <- -> //. Qed.
 
 Global Instance into_pure_exist {A} (Φ : A → PROP) (φ : A → Prop) :
   (∀ x, IntoPure (Φ x) (φ x)) → IntoPure (∃ x, Φ x) (∃ x, φ x).
@@ -152,8 +152,13 @@ Global Instance into_pure_pure_sep (φ1 φ2 : Prop) P1 P2 :
   IntoPure P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 ∗ P2) (φ1 ∧ φ2).
 Proof. rewrite /IntoPure=> -> ->. by rewrite sep_and pure_and. Qed.
 Global Instance into_pure_pure_wand (φ1 φ2 : Prop) P1 P2 :
-  FromPure P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 -∗ P2) (φ1 → φ2).
-Proof. rewrite /FromPure /IntoPure=> <- ->. by rewrite pure_impl impl_wand_2. Qed.
+  FromPure true P1 φ1 → IntoPure P2 φ2 → IntoPure (P1 -∗ P2) (φ1 → φ2).
+Proof.
+  rewrite /FromPure /IntoPure=> <- -> /=.
+  rewrite pure_impl -impl_wand_2. apply bi.wand_intro_l.
+  rewrite {1}(persistent_absorbingly_affinely ⌜φ1⌝%I) absorbingly_sep_l
+          bi.wand_elim_r absorbing //.
+Qed.
 
 Global Instance into_pure_affinely P φ :
   IntoPure P φ → IntoPure (bi_affinely P) φ.
@@ -170,53 +175,83 @@ Global Instance into_pure_embed `{BiEmbedding PROP PROP'} P φ :
 Proof. rewrite /IntoPure=> ->. by rewrite bi_embed_pure. Qed.
 
 (* FromPure *)
-Global Instance from_pure_pure φ : @FromPure PROP ⌜φ⌝ φ.
-Proof. by rewrite /FromPure. Qed.
-Global Instance from_pure_pure_and (φ1 φ2 : Prop) P1 P2 :
-  FromPure P1 φ1 → FromPure P2 φ2 → FromPure (P1 ∧ P2) (φ1 ∧ φ2).
-Proof. rewrite /FromPure pure_and. by intros -> ->. Qed.
-Global Instance from_pure_pure_or (φ1 φ2 : Prop) P1 P2 :
-  FromPure P1 φ1 → FromPure P2 φ2 → FromPure (P1 ∨ P2) (φ1 ∨ φ2).
-Proof. rewrite /FromPure pure_or. by intros -> ->. Qed.
-Global Instance from_pure_pure_impl (φ1 φ2 : Prop) P1 P2 :
-  IntoPure P1 φ1 → FromPure P2 φ2 → FromPure (P1 → P2) (φ1 → φ2).
-Proof. rewrite /FromPure /IntoPure pure_impl. by intros -> ->. Qed.
-
-Global Instance from_pure_exist {A} (Φ : A → PROP) (φ : A → Prop) :
-  (∀ x, FromPure (Φ x) (φ x)) → FromPure (∃ x, Φ x) (∃ x, φ x).
-Proof. rewrite /FromPure=>Hx. rewrite pure_exist. by setoid_rewrite Hx. Qed.
-Global Instance from_pure_forall {A} (Φ : A → PROP) (φ : A → Prop) :
-  (∀ x, FromPure (Φ x) (φ x)) → FromPure (∀ x, Φ x) (∀ x, φ x).
-Proof. rewrite /FromPure=>Hx. rewrite pure_forall. by setoid_rewrite Hx. Qed.
-
-Global Instance from_pure_pure_sep (φ1 φ2 : Prop) P1 P2 :
-  FromPure P1 φ1 → FromPure P2 φ2 → FromPure (P1 ∗ P2) (φ1 ∧ φ2).
-Proof. rewrite /FromPure=> <- <-. by rewrite pure_and persistent_and_sep_1. Qed.
-Global Instance from_pure_pure_wand (φ1 φ2 : Prop) P1 P2 :
-  IntoPure P1 φ1 → FromPure P2 φ2 → FromPure (P1 -∗ P2) (φ1 → φ2).
-Proof.
-  rewrite /FromPure /IntoPure=> -> <-.
-  by rewrite pure_wand_forall pure_impl pure_impl_forall.
+Global Instance from_pure_pure a φ : @FromPure PROP a ⌜φ⌝ φ.
+Proof. rewrite /FromPure. apply affinely_if_elim. Qed.
+Global Instance from_pure_pure_and a (φ1 φ2 : Prop) P1 P2 :
+  FromPure a P1 φ1 → FromPure a P2 φ2 → FromPure a (P1 ∧ P2) (φ1 ∧ φ2).
+Proof. rewrite /FromPure pure_and=> <- <- /=. by rewrite affinely_if_and. Qed.
+Global Instance from_pure_pure_or a (φ1 φ2 : Prop) P1 P2 :
+  FromPure a P1 φ1 → FromPure a P2 φ2 → FromPure a (P1 ∨ P2) (φ1 ∨ φ2).
+Proof. by rewrite /FromPure pure_or affinely_if_or=><- <-. Qed.
+Global Instance from_pure_pure_impl a (φ1 φ2 : Prop) P1 P2 :
+  IntoPure P1 φ1 → FromPure a P2 φ2 → FromPure a (P1 → P2) (φ1 → φ2).
+Proof.
+  rewrite /FromPure /IntoPure pure_impl=> -> <-. destruct a=>//=.
+  apply bi.impl_intro_l. by rewrite affinely_and_r bi.impl_elim_r.
+Qed.
+
+Global Instance from_pure_exist {A} a (Φ : A → PROP) (φ : A → Prop) :
+  (∀ x, FromPure a (Φ x) (φ x)) → FromPure a (∃ x, Φ x) (∃ x, φ x).
+Proof.
+  rewrite /FromPure=>Hx. rewrite pure_exist affinely_if_exist.
+  by setoid_rewrite Hx.
+Qed.
+Global Instance from_pure_forall {A} a (Φ : A → PROP) (φ : A → Prop) :
+  (∀ x, FromPure a (Φ x) (φ x)) → FromPure a (∀ x, Φ x) (∀ x, φ x).
+Proof.
+  rewrite /FromPure=>Hx. rewrite pure_forall. setoid_rewrite <-Hx.
+  destruct a=>//=. apply affinely_forall.
+Qed.
+
+Global Instance from_pure_pure_sep_true (φ1 φ2 : Prop) P1 P2 :
+  FromPure true P1 φ1 → FromPure true P2 φ2 → FromPure true (P1 ∗ P2) (φ1 ∧ φ2).
+Proof.
+  rewrite /FromPure=> <- <- /=.
+  by rewrite -persistent_and_affinely_sep_l affinely_and_r pure_and.
+Qed.
+Global Instance from_pure_pure_sep_false_l (φ1 φ2 : Prop) P1 P2 :
+  FromPure false P1 φ1 → FromPure true P2 φ2 → FromPure false (P1 ∗ P2) (φ1 ∧ φ2).
+Proof.
+  rewrite /FromPure=> <- <- /=. by rewrite -persistent_and_affinely_sep_r pure_and.
+Qed.
+Global Instance from_pure_pure_sep_false_r (φ1 φ2 : Prop) P1 P2 :
+  FromPure true P1 φ1 → FromPure false P2 φ2 → FromPure false (P1 ∗ P2) (φ1 ∧ φ2).
+Proof.
+  rewrite /FromPure=> <- <- /=. by rewrite -persistent_and_affinely_sep_l pure_and.
+Qed.
+Global Instance from_pure_pure_wand (φ1 φ2 : Prop) a P1 P2 :
+  IntoPure P1 φ1 → FromPure false P2 φ2 → FromPure a (P1 -∗ P2) (φ1 → φ2).
+Proof.
+  rewrite /FromPure /IntoPure=> -> <- /=.
+  by rewrite bi.affinely_if_elim pure_wand_forall pure_impl pure_impl_forall.
 Qed.
 
 Global Instance from_pure_plainly P φ :
-  FromPure P φ → FromPure (bi_plainly P) φ.
+  FromPure false P φ → FromPure false (bi_plainly P) φ.
 Proof. rewrite /FromPure=> <-. by rewrite plainly_pure. Qed.
-Global Instance from_pure_persistently P φ :
-  FromPure P φ → FromPure (bi_persistently P) φ.
-Proof. rewrite /FromPure=> <-. by rewrite persistently_pure. Qed.
-Global Instance from_pure_affinely P φ `{!Affine P} :
-  FromPure P φ → FromPure (bi_affinely P) φ.
-Proof. by rewrite /FromPure affine_affinely. Qed.
-Global Instance from_pure_absorbingly P φ : FromPure P φ → FromPure (bi_absorbingly P) φ.
-Proof. rewrite /FromPure=> <-. by rewrite absorbingly_pure. Qed.
-Global Instance from_pure_embed `{BiEmbedding PROP PROP'} P φ :
-  FromPure P φ → FromPure ⎡P⎤ φ.
-Proof. rewrite /FromPure=> <-. by rewrite bi_embed_pure. Qed.
-
-Global Instance from_pure_bupd `{BUpdFacts PROP} P φ :
-  FromPure P φ → FromPure (|==> P) φ.
-Proof. rewrite /FromPure=> ->. apply bupd_intro. Qed.
+Global Instance from_pure_persistently P a φ :
+  FromPure true P φ → FromPure a (bi_persistently P) φ.
+Proof.
+  rewrite /FromPure=> <- /=.
+  by rewrite persistently_affinely affinely_if_elim persistently_pure.
+Qed.
+Global Instance from_pure_affinely_true P φ :
+  FromPure true P φ → FromPure true (bi_affinely P) φ.
+Proof. rewrite /FromPure=><- /=. by rewrite affinely_idemp. Qed.
+Global Instance from_pure_affinely_false P φ `{!Affine P} :
+  FromPure false P φ → FromPure false (bi_affinely P) φ.
+Proof. rewrite /FromPure /= affine_affinely //. Qed.
+
+Global Instance from_pure_absorbingly P φ :
+  FromPure true P φ → FromPure false (bi_absorbingly P) φ.
+Proof. rewrite /FromPure=> <- /=. apply persistent_absorbingly_affinely, _. Qed.
+Global Instance from_pure_embed `{BiEmbedding PROP PROP'} a P φ :
+  FromPure a P φ → FromPure a ⎡P⎤ φ.
+Proof. rewrite /FromPure=> <-. by rewrite bi_embed_affinely_if bi_embed_pure. Qed.
+
+Global Instance from_pure_bupd `{BUpdFacts PROP} a P φ :
+  FromPure a P φ → FromPure a (|==> P) φ.
+Proof. rewrite /FromPure=> <-. apply bupd_intro. Qed.
 
 (* IntoPersistent *)
 Global Instance into_persistent_persistently p P Q :
@@ -857,7 +892,7 @@ Proof.
   intros. by rewrite /Frame affinely_persistently_if_elim affinely_elim sep_elim_l.
 Qed.
 
-Global Instance frame_here_pure p φ Q : FromPure Q φ → Frame p ⌜φ⌝ Q True.
+Global Instance frame_here_pure p φ Q : FromPure false Q φ → Frame p ⌜φ⌝ Q True.
 Proof.
   rewrite /FromPure /Frame=> <-. by rewrite affinely_persistently_if_elim sep_elim_l.
 Qed.
@@ -1126,17 +1161,17 @@ Global Instance from_assumption_fupd `{FUpdFacts PROP} E p P Q :
 Proof. rewrite /FromAssumption=>->. apply bupd_fupd. Qed.
 
 (* FromPure *)
-Global Instance from_pure_internal_eq {A : ofeT} (a b : A) :
-  @FromPure PROP (a ≡ b) (a ≡ b).
-Proof. by rewrite /FromPure pure_internal_eq. Qed.
-Global Instance from_pure_later P φ : FromPure P φ → FromPure (▷ P) φ.
+Global Instance from_pure_internal_eq af {A : ofeT} (a b : A) :
+  @FromPure PROP af (a ≡ b) (a ≡ b).
+Proof. by rewrite /FromPure pure_internal_eq affinely_if_elim. Qed.
+Global Instance from_pure_later a P φ : FromPure a P φ → FromPure a (▷ P) φ.
 Proof. rewrite /FromPure=> ->. apply later_intro. Qed.
-Global Instance from_pure_laterN n P φ : FromPure P φ → FromPure (▷^n P) φ.
+Global Instance from_pure_laterN a n P φ : FromPure a P φ → FromPure a (▷^n P) φ.
 Proof. rewrite /FromPure=> ->. apply laterN_intro. Qed.
-Global Instance from_pure_except_0 P φ : FromPure P φ → FromPure (◇ P) φ.
+Global Instance from_pure_except_0 a P φ : FromPure a P φ → FromPure a (◇ P) φ.
 Proof. rewrite /FromPure=> ->. apply except_0_intro. Qed.
-Global Instance from_pure_fupd `{FUpdFacts PROP} E P φ :
-  FromPure P φ → FromPure (|={E}=> P) φ.
+Global Instance from_pure_fupd `{FUpdFacts PROP} a E P φ :
+  FromPure a P φ → FromPure a (|={E}=> P) φ.
 Proof. rewrite /FromPure. intros <-. apply fupd_intro. Qed.
 
 (* IntoPure *)
@@ -1333,16 +1368,17 @@ Global Instance into_forall_except_0 {A} P (Φ : A → PROP) :
   IntoForall P Φ → IntoForall (◇ P) (λ a, ◇ (Φ a))%I.
 Proof. rewrite /IntoForall=> HP. by rewrite HP except_0_forall. Qed.
 Global Instance into_forall_impl_pure φ P Q :
-  FromPureT P φ → IntoForall (P → Q) (λ _ : φ, Q).
+  FromPureT false P φ → IntoForall (P → Q) (λ _ : φ, Q).
 Proof.
   rewrite /FromPureT /FromPure /IntoForall=> -[φ' [-> <-]].
   by rewrite pure_impl_forall.
 Qed.
 Global Instance into_forall_wand_pure φ P Q :
-  Absorbing Q → FromPureT P φ → IntoForall (P -∗ Q) (λ _ : φ, Q).
+  FromPureT true P φ → IntoForall (P -∗ Q) (λ _ : φ, Q).
 Proof.
-  rewrite /FromPureT /FromPure /IntoForall=> ? -[φ' [-> <-]].
-  by rewrite pure_wand_forall.
+  rewrite /FromPureT /FromPure /IntoForall=> -[φ' [-> <-]] /=.
+  apply forall_intro=>? /=.
+  by rewrite -(pure_intro True%I) // /bi_affinely right_id emp_wand.
 Qed.
 
 (* FromForall *)
diff --git a/theories/proofmode/classes.v b/theories/proofmode/classes.v
index 5c2efcaf6..25e01bcbf 100644
--- a/theories/proofmode/classes.v
+++ b/theories/proofmode/classes.v
@@ -43,18 +43,19 @@ Proof. by exists φ. Qed.
 Hint Extern 0 (IntoPureT _ _) =>
   notypeclasses refine (into_pureT_hint _ _ _) : typeclass_instances.
 
-Class FromPure {PROP : bi} (P : PROP) (φ : Prop) :=
-  from_pure : ⌜φ⌝ ⊢ P.
-Arguments FromPure {_} _%I _%type_scope : simpl never.
-Arguments from_pure {_} _%I _%type_scope {_}.
-Hint Mode FromPure + ! - : typeclass_instances.
-
-Class FromPureT {PROP : bi} (P : PROP) (φ : Type) :=
-  from_pureT : ∃ ψ : Prop, φ = ψ ∧ FromPure P ψ.
-Lemma from_pureT_hint {PROP : bi} (P : PROP) (φ : Prop) : FromPure P φ → FromPureT P φ.
+Class FromPure {PROP : bi} (a : bool) (P : PROP) (φ : Prop) :=
+  from_pure : bi_affinely_if a ⌜φ⌝ ⊢ P.
+Arguments FromPure {_} _ _%I _%type_scope : simpl never.
+Arguments from_pure {_} _ _%I _%type_scope {_}.
+Hint Mode FromPure + + ! - : typeclass_instances.
+
+Class FromPureT {PROP : bi} (a : bool) (P : PROP) (φ : Type) :=
+  from_pureT : ∃ ψ : Prop, φ = ψ ∧ FromPure a P ψ.
+Lemma from_pureT_hint {PROP : bi} (a : bool) (P : PROP) (φ : Prop) :
+  FromPure a P φ → FromPureT a P φ.
 Proof. by exists φ. Qed.
-Hint Extern 0 (FromPureT _ _) =>
-  notypeclasses refine (from_pureT_hint _ _ _) : typeclass_instances.
+Hint Extern 0 (FromPureT _ _ _) =>
+  notypeclasses refine (from_pureT_hint _ _ _ _) : typeclass_instances.
 
 Class IntoInternalEq {PROP : sbi} {A : ofeT} (P : PROP) (x y : A) :=
   into_internal_eq : P ⊢ x ≡ y.
@@ -448,8 +449,8 @@ with the exception of:
 *)
 Instance into_pure_tc_opaque {PROP : bi} (P : PROP) φ :
   IntoPure P φ → IntoPure (tc_opaque P) φ := id.
-Instance from_pure_tc_opaque {PROP : bi} (P : PROP) φ :
-  FromPure P φ → FromPure (tc_opaque P) φ := id.
+Instance from_pure_tc_opaque {PROP : bi} (a : bool) (P : PROP) φ :
+  FromPure a P φ → FromPure a (tc_opaque P) φ := id.
 Instance from_laterN_tc_opaque {PROP : sbi} n (P Q : PROP) :
   FromLaterN n P Q → FromLaterN n (tc_opaque P) Q := id.
 Instance from_wand_tc_opaque {PROP : bi} (P Q1 Q2 : PROP) :
diff --git a/theories/proofmode/coq_tactics.v b/theories/proofmode/coq_tactics.v
index 376a0806e..498e6f55b 100644
--- a/theories/proofmode/coq_tactics.v
+++ b/theories/proofmode/coq_tactics.v
@@ -520,8 +520,8 @@ Proof.
 Qed.
 
 (** * Pure *)
-Lemma tac_pure_intro Δ Q φ : FromPure Q φ → φ → envs_entails Δ Q.
-Proof. intros ??. rewrite /envs_entails -(from_pure Q). by apply pure_intro. Qed.
+Lemma tac_pure_intro Δ Q φ : FromPure false Q φ → φ → envs_entails Δ Q.
+Proof. intros ??. rewrite /envs_entails -(from_pure _ Q). by apply pure_intro. Qed.
 
 Lemma tac_pure Δ Δ' i p P φ Q :
   envs_lookup_delete i Δ = Some (p, P, Δ') →
@@ -821,13 +821,14 @@ Qed.
 Lemma tac_specialize_assert_pure Δ Δ' j q R P1 P2 φ Q :
   envs_lookup j Δ = Some (q, R) →
   IntoWand q true R P1 P2 →
-  FromPure P1 φ →
+  FromPure true P1 φ →
   envs_simple_replace j q (Esnoc Enil j P2) Δ = Some Δ' →
   φ → envs_entails Δ' Q → envs_entails Δ Q.
 Proof.
   rewrite /envs_entails=> ????? <-. rewrite envs_simple_replace_singleton_sound //=.
-  rewrite -affinely_persistently_if_idemp into_wand /= -(from_pure P1).
-  rewrite pure_True // persistently_pure affinely_True_emp affinely_emp.
+  rewrite -affinely_persistently_if_idemp into_wand /= -(from_pure _ P1).
+  rewrite pure_True //= persistently_affinely persistently_pure
+          affinely_True_emp affinely_emp.
   by rewrite emp_wand wand_elim_r.
 Qed.
 
@@ -926,14 +927,14 @@ Proof.
 Qed.
 
 Lemma tac_assert_pure Δ Δ' j P P' φ Q :
-  FromPure P φ →
+  FromPure true P φ →
   FromAffinely P' P →
   envs_app false (Esnoc Enil j P') Δ = Some Δ' →
   φ → envs_entails Δ' Q → envs_entails Δ Q.
 Proof.
   rewrite /envs_entails => ???? <-. rewrite envs_app_singleton_sound //=.
-  rewrite -(from_affinely P') -(from_pure P) pure_True //.
-  by rewrite affinely_True_emp affinely_emp emp_wand.
+  rewrite -(from_affinely P') -(from_pure _ P) pure_True //.
+  by rewrite affinely_idemp affinely_True_emp affinely_emp emp_wand.
 Qed.
 
 Lemma tac_pose_proof Δ Δ' j P Q :
diff --git a/theories/proofmode/monpred.v b/theories/proofmode/monpred.v
index f9461af7e..116f30b5d 100644
--- a/theories/proofmode/monpred.v
+++ b/theories/proofmode/monpred.v
@@ -157,12 +157,12 @@ Qed.
 
 Global Instance into_pure_monPred_at P φ i : IntoPure P φ → IntoPure (P i) φ.
 Proof. rewrite /IntoPure=>->. by rewrite monPred_at_pure. Qed.
-Global Instance from_pure_monPred_at P φ i : FromPure P φ → FromPure (P i) φ.
-Proof. rewrite /FromPure=><-. by rewrite monPred_at_pure. Qed.
+Global Instance from_pure_monPred_at a P φ i : FromPure a P φ → FromPure a (P i) φ.
+Proof. rewrite /FromPure=><-. by rewrite monPred_at_affinely_if monPred_at_pure. Qed.
 Global Instance into_pure_monPred_in i j : @IntoPure PROP (monPred_in i j) (i ⊑ j).
 Proof. by rewrite /IntoPure monPred_at_in. Qed.
-Global Instance from_pure_monPred_in i j : @FromPure PROP (monPred_in i j) (i ⊑ j).
-Proof. by rewrite /FromPure monPred_at_in. Qed.
+Global Instance from_pure_monPred_in i j af : @FromPure PROP af (monPred_in i j) (i ⊑ j).
+Proof. by rewrite /FromPure monPred_at_in bi.affinely_if_elim. Qed.
 
 Global Instance into_persistent_monPred_at p P Q 𝓠 i :
   IntoPersistent p P Q → MakeMonPredAt i Q 𝓠 → IntoPersistent p (P i) 𝓠 | 0.
diff --git a/theories/proofmode/tactics.v b/theories/proofmode/tactics.v
index 5d9765b17..12f7c8c5a 100644
--- a/theories/proofmode/tactics.v
+++ b/theories/proofmode/tactics.v
@@ -230,7 +230,7 @@ Tactic Notation "iPureIntro" :=
   iStartProof;
   eapply tac_pure_intro;
     [apply _ ||
-     let P := match goal with |- FromPure ?P _ => P end in
+     let P := match goal with |- FromPure _ ?P _ => P end in
      fail "iPureIntro:" P "not pure"
     |].
 
@@ -494,7 +494,7 @@ Local Tactic Notation "iSpecializePat" open_constr(H) constr(pat) :=
          [env_reflexivity || fail "iSpecialize:" H1 "not found"
          |solve_to_wand H1
          |apply _ ||
-          let Q := match goal with |- FromPure ?Q _ => Q end in
+          let Q := match goal with |- FromPure _ ?Q _ => Q end in
           fail "iSpecialize:" Q "not pure"
          |env_reflexivity
          |done_if d (*goal*)
@@ -1663,10 +1663,10 @@ Tactic Notation "iAssertCore" open_constr(Q)
   let Hs := spec_pat.parse Hs in
   lazymatch Hs with
   | [SPureGoal ?d] =>
-     eapply tac_assert_pure with _ H Q _;
-       [env_reflexivity
-       |apply _ || fail "iAssert:" Q "not pure"
+     eapply tac_assert_pure with _ H Q _ _;
+       [apply _ || fail "iAssert:" Q "not pure"
        |apply _
+       |env_reflexivity
        |done_if d (*goal*)
        |tac H]
   | [SGoal (SpecGoal GPersistent _ ?Hs_frame [] ?d)] =>
diff --git a/theories/tests/proofmode.v b/theories/tests/proofmode.v
index 7389faf69..41cbbb148 100644
--- a/theories/tests/proofmode.v
+++ b/theories/tests/proofmode.v
@@ -300,4 +300,18 @@ Lemma test_iNext_later_laterN P n : ▷^n ▷ P ⊢ ▷ ▷^n P.
 Proof. iIntros "H". iNext. by iNext. Qed.
 Lemma test_iNext_laterN_laterN P n1 n2 : ▷ ▷^n1 ▷^n2 P ⊢ ▷^n1 ▷^n2 ▷ P.
 Proof. iIntros "H". iNext. iNext. by iNext. Qed.
+
+Lemma test_specialize_affine_pure (φ : Prop) P :
+  φ → (bi_affinely ⌜φ⌝ -∗ P) ⊢ P.
+Proof.
+  iIntros (Hφ) "H". by iSpecialize ("H" with "[% //]").
+Qed.
+
+Lemma test_assert_affine_pure (φ : Prop) P :
+  φ → P ⊢ P ∗ bi_affinely ⌜φ⌝.
+Proof. iIntros (Hφ). iAssert (bi_affinely ⌜φ⌝) with "[%]" as "$"; auto. Qed.
+Lemma test_assert_pure (φ : Prop) P :
+  φ → P ⊢ P ∗ ⌜φ⌝.
+Proof. iIntros (Hφ). iAssert ⌜φ⌝%I with "[%]" as "$"; auto. Qed.
+
 End tests.
-- 
GitLab