From 3f257ee4a78073008bd29c5174e83163b8a0b167 Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Tue, 18 Apr 2023 18:20:16 +0200
Subject: [PATCH 1/3] Use `resolve_tc` and remove all uses of "legacy" `apply`
 in Iris Proof Mode.

---
 iris/program_logic/ownp.v     |   4 +-
 iris/proofmode/ltac_tactics.v | 104 +++++++++++++++++++---------------
 iris/proofmode/reduction.v    |   4 +-
 3 files changed, 62 insertions(+), 50 deletions(-)

diff --git a/iris/program_logic/ownp.v b/iris/program_logic/ownp.v
index 7acca3e5f..2b9e6c4d1 100644
--- a/iris/program_logic/ownp.v
+++ b/iris/program_logic/ownp.v
@@ -69,12 +69,12 @@ Theorem ownP_invariance Σ `{!ownPGpreS Λ Σ} s e σ1 t2 σ2 φ :
   φ σ2.
 Proof.
   intros Hwp Hsteps. eapply (wp_invariance Σ Λ s e σ1 t2 σ2 _)=> //.
-  iIntros (? κs).
+  iIntros (Hinv κs).
   iMod (own_alloc (●E σ1 ⋅ ◯E σ1)) as (γσ) "[Hσ Hσf]";
     first by apply auth_both_valid_discrete.
   iExists (λ σ κs' _, own γσ (●E σ))%I, (λ _, True%I).
   iFrame "Hσ".
-  iMod (Hwp (OwnPGS _ _ _ _ γσ) with "[Hσf]") as "[$ H]";
+  iMod (Hwp (OwnPGS _ _ Hinv _ γσ) with "[Hσf]") as "[$ H]";
     first by rewrite /ownP; iFrame.
   iIntros "!> Hσ". iExists ∅. iMod "H" as (σ2') "[Hσf %]". rewrite /ownP.
   iCombine "Hσ Hσf"
diff --git a/iris/proofmode/ltac_tactics.v b/iris/proofmode/ltac_tactics.v
index 1018168a7..3439ddebe 100644
--- a/iris/proofmode/ltac_tactics.v
+++ b/iris/proofmode/ltac_tactics.v
@@ -7,6 +7,9 @@ From iris.proofmode Require Export classes notation.
 From iris.prelude Require Import options.
 Export ident.
 
+(** TODO: Move to some utility file *)
+Ltac resolve_tc := ltac2:(x |- Std.resolve_tc (Option.get (Ltac1.to_constr x))).
+
 (** Tactic used for solving side-conditions arising from TC resolution in [iMod]
 and [iInv]. *)
 Ltac iSolveSideCondition :=
@@ -92,12 +95,12 @@ Tactic Notation "iStartProof" uconstr(PROP) :=
      to find the corresponding bi. *)
   | |- ?φ => notypeclasses refine ((λ P : PROP, @as_emp_valid_2 φ _ P) _ _ _);
                [tc_solve || fail "iStartProof: not a BI assertion"
-               |apply tac_start]
+               |notypeclasses refine (tac_start _ _)]
   end.
 
 Tactic Notation "iStopProof" :=
   lazymatch goal with
-  | |- envs_entails _ _ => apply tac_stop; pm_reduce
+  | |- envs_entails _ _ => notypeclasses refine (tac_stop _ _ _); pm_reduce
   | |- _ => fail "iStopProof: proofmode not started"
   end.
 
@@ -130,7 +133,7 @@ Ltac iFresh :=
 
 (** * Context manipulation *)
 Tactic Notation "iRename" constr(H1) "into" constr(H2) :=
-  eapply tac_rename with H1 H2 _ _; (* (i:=H1) (j:=H2) *)
+  notypeclasses refine (tac_rename _ H1 H2 _ _ _ _ _); (* (i:=H1) (j:=H2) *)
     [pm_reflexivity ||
      let H1 := pretty_ident H1 in
      fail "iRename:" H1 "not found"
@@ -181,7 +184,7 @@ Ltac iElaborateSelPat pat :=
   end.
 
 Local Ltac iClearHyp H :=
-  eapply tac_clear with H _ _; (* (i:=H) *)
+  notypeclasses refine (tac_clear _ H _ _ _ _ _ _); (* (i:=H) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iClear:" H "not found"
@@ -209,7 +212,7 @@ Tactic Notation "iClear" "select" open_constr(pat) :=
 (** ** Simplification *)
 Tactic Notation "iEval" tactic3(t) :=
   iStartProof;
-  eapply tac_eval;
+  notypeclasses refine (tac_eval _ _ _ _ _);
     [let x := fresh in intros x; t; unfold x; reflexivity
     |].
 
@@ -218,7 +221,7 @@ Local Ltac iEval_go t Hs :=
   | [] => idtac
   | ESelPure :: ?Hs => fail "iEval: %: unsupported selection pattern"
   | ESelIdent _ ?H :: ?Hs =>
-    eapply tac_eval_in with H _ _ _;
+    notypeclasses refine (tac_eval_in _ H _ _ _ _ _ _ _);
       [pm_reflexivity || let H := pretty_ident H in fail "iEval:" H "not found"
       |let x := fresh in intros x; t; unfold x; reflexivity
       |pm_reduce; iEval_go t Hs]
@@ -248,7 +251,7 @@ Ltac, but it may be possible in Ltac2. *)
 
 (** * Assumptions *)
 Tactic Notation "iExact" constr(H) :=
-  eapply tac_assumption with H _ _; (* (i:=H) *)
+  notypeclasses refine (tac_assumption _ H _ _ _ _ _ _); (* (i:=H) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iExact:" H "not found"
@@ -293,14 +296,14 @@ Tactic Notation "iAssumption" :=
     lazymatch Γ with
     | Esnoc ?Γ ?j ?P => first
        [pose proof (_ : FromAssumption p P Q) as Hass;
-        eapply (tac_assumption _ j p P);
+        notypeclasses refine (tac_assumption _ j p P _ _ _ _);
           [pm_reflexivity
           |exact Hass
           |pm_reduce; tc_solve ||
            fail 2 "iAssumption: remaining hypotheses not affine and the goal not absorbing"]
        |assert_fails (is_evar P); 
-        assert (P = False%I) as Hass by reflexivity;
-        apply (tac_false_destruct _ j p P);
+        assert (P = False%I) as Hass by notypeclasses refine eq_refl;
+        notypeclasses refine (tac_false_destruct _ j p P _ _ _);
           [pm_reflexivity
           |exact Hass]
        |find p Γ Q]
@@ -316,11 +319,11 @@ Tactic Notation "iAssumption" :=
 (** * False *)
 Tactic Notation "iExFalso" :=
   iStartProof;
-  apply tac_ex_falso.
+  notypeclasses refine (tac_ex_falso _ _ _).
 
 (** * Making hypotheses intuitionistic or pure *)
 Local Tactic Notation "iIntuitionistic" constr(H) "as" constr(H') :=
-  eapply tac_intuitionistic with H H' _ _ _; (* (i:=H) (j:=H') *)
+  notypeclasses refine (tac_intuitionistic _ H H' _ _ _ _ _ _ _ _); (* (i:=H) (j:=H') *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iIntuitionistic:" H "not found"
@@ -339,7 +342,7 @@ Local Tactic Notation "iIntuitionistic" constr(H) "as" constr(H') :=
      end].
 
 Local Tactic Notation "iSpatial" constr(H) "as" constr(H') :=
-  eapply tac_spatial with H H' _ _ _;
+  notypeclasses refine (tac_spatial _ H H' _ _ _ _ _ _ _);
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iSpatial:" H "not found"
@@ -353,7 +356,7 @@ Local Tactic Notation "iSpatial" constr(H) "as" constr(H') :=
      end].
 
 Tactic Notation "iPure" constr(H) "as" simple_intropattern(pat) :=
-  eapply tac_pure with H _ _ _; (* (i:=H1) *)
+  notypeclasses refine (tac_pure _ H _ _ _ _ _ _ _ _); (* (i:=H1) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iPure:" H "not found"
@@ -367,13 +370,13 @@ Tactic Notation "iPure" constr(H) "as" simple_intropattern(pat) :=
 
 Tactic Notation "iEmpIntro" :=
   iStartProof;
-  eapply tac_emp_intro;
+  notypeclasses refine (tac_emp_intro _ _);
     [pm_reduce; tc_solve ||
      fail "iEmpIntro: spatial context contains non-affine hypotheses"].
 
 Tactic Notation "iPureIntro" :=
   iStartProof;
-  eapply tac_pure_intro;
+  notypeclasses refine (tac_pure_intro _ _ _ _ _ _ _);
     [tc_solve ||
      let P := match goal with |- FromPure _ ?P _ => P end in
      fail "iPureIntro:" P "not pure"
@@ -394,13 +397,13 @@ Ltac iFrameFinish :=
 Ltac iFramePure t :=
   iStartProof;
   let φ := type of t in
-  eapply (tac_frame_pure _ _ _ _ t);
+  notypeclasses refine (tac_frame_pure _ _ _ _ t _ _);
     [tc_solve || fail "iFrame: cannot frame" φ
     |iFrameFinish].
 
 Ltac iFrameHyp H :=
   iStartProof;
-  eapply tac_frame with H _ _ _;
+  notypeclasses refine (tac_frame _ H _ _ _ _ _ _ _);
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iFrame:" H "not found"
@@ -472,7 +475,7 @@ Local Tactic Notation "iIntro" "(" simple_intropattern(x) ")" :=
     iStartProof;
     lazymatch goal with
     | |- envs_entails _ _ =>
-      eapply tac_forall_intro;
+      notypeclasses refine (tac_forall_intro _ _ _ _ _ _);
         [tc_solve ||
          let P := match goal with |- FromForall ?P _ _ => P end in
          fail "iIntro: cannot turn" P "into a universal quantifier"
@@ -489,7 +492,7 @@ Local Tactic Notation "iIntro" constr(H) :=
   iStartProof;
   first
   [(* (?Q → _) *)
-    eapply tac_impl_intro with H _ _ _; (* (i:=H) *)
+    notypeclasses refine (tac_impl_intro _ H _ _ _ _ _ _ _ _); (* (i:=H) *)
       [tc_solve
       |pm_reduce; tc_solve ||
        let P := lazymatch goal with |- Persistent ?P => P end in
@@ -506,7 +509,7 @@ Local Tactic Notation "iIntro" constr(H) :=
         | _ => idtac (* subgoal *)
         end]
   |(* (_ -∗ _) *)
-    eapply tac_wand_intro with H _ _; (* (i:=H) *)
+    notypeclasses refine (tac_wand_intro _ H _ _ _ _ _); (* (i:=H) *)
       [tc_solve
       | pm_reduce;
         lazymatch goal with
@@ -522,7 +525,7 @@ Local Tactic Notation "iIntro" "#" constr(H) :=
   iStartProof;
   first
   [(* (?P → _) *)
-   eapply tac_impl_intro_intuitionistic with H _ _ _; (* (i:=H) *)
+   notypeclasses refine (tac_impl_intro_intuitionistic _ H _ _ _ _ _ _ _); (* (i:=H) *)
      [tc_solve
      |tc_solve ||
       let P := match goal with |- IntoPersistent _ ?P _ => P end in
@@ -535,7 +538,7 @@ Local Tactic Notation "iIntro" "#" constr(H) :=
       | _ => idtac (* subgoal *)
       end]
   |(* (?P -∗ _) *)
-   eapply tac_wand_intro_intuitionistic with H _ _ _; (* (i:=H) *)
+   notypeclasses refine (tac_wand_intro_intuitionistic _ H _ _ _ _ _ _ _ _); (* (i:=H) *)
      [tc_solve
      |tc_solve ||
       let P := match goal with |- IntoPersistent _ ?P _ => P end in
@@ -562,11 +565,11 @@ Local Tactic Notation "iIntro" "_" :=
   iStartProof;
   first
   [(* (?Q → _) *)
-   eapply tac_impl_intro_drop;
+   notypeclasses refine (tac_impl_intro_drop _ _ _ _ _ _);
      [tc_solve
      |(* subgoal *)]
   |(* (_ -∗ _) *)
-   eapply tac_wand_intro_drop;
+   notypeclasses refine (tac_wand_intro_drop _ _ _ _ _ _ _);
      [tc_solve
      |tc_solve ||
       let P := match goal with |- TCOr (Affine ?P) _ => P end in
@@ -614,25 +617,26 @@ Ltac iForallRevert x :=
   lazymatch type of A with
   | Prop =>
      revert x; first
-       [eapply tac_pure_revert;
+       [notypeclasses refine (tac_pure_revert _ _ _ _ _ _);
          [tc_solve (* [MakeAffinely], should never fail *)
          |]
        |err x]
   | _ =>
     revert x; first
-      [apply tac_forall_revert;
+      [notypeclasses refine (tac_forall_revert _ _ _);
        (* Ensure the name [x] is preserved, see [test_iRevert_order_and_names]. *)
        lazymatch goal with
        | |- envs_entails ?Δ (bi_forall ?P) =>
          change (envs_entails Δ (∀ x, P x)); lazy beta
        end
       |err x]
+  | _ => revert x; first [notypeclasses refine (tac_forall_revert _ _ _)|err x]
   end.
 
 (** The tactic [iRevertHyp H with tac] reverts the hypothesis [H] and calls
 [tac] with a Boolean that is [true] iff [H] was in the intuitionistic context. *)
 Tactic Notation "iRevertHyp" constr(H) "with" tactic1(tac) :=
-  eapply tac_revert with H;
+  notypeclasses refine (tac_revert _ H _ _);
     [lazymatch goal with
      | |- match envs_lookup_delete true ?i ?Δ with _ => _ end =>
         lazymatch eval pm_eval in (envs_lookup_delete true i Δ) with
@@ -1100,8 +1104,9 @@ Tactic Notation "iPoseProofCore" open_constr(lem)
   | ident =>
      let Htmp := iFresh in
      iPoseProofCoreHyp t as Htmp; spec_tac Htmp; [..|tac Htmp]
-  | _ => iPoseProofCoreLem t as (fun Htmp => spec_tac Htmp; [..|tac Htmp])
-  end.
+  | _ => iPoseProofCoreLem t as (fun Htmp =>
+           spec_tac Htmp; [..|tac Htmp])
+  end; resolve_tc lem.
 
 (** * The apply tactic *)
 (** [iApply lem] takes an argument [lem : P₁ -∗ .. -∗ Pₙ -∗ Q] (after the
@@ -1123,8 +1128,9 @@ premises [n], the tactic will have the following behavior:
 (* The helper [iApplyHypExact] takes care of the [n=0] case. It fails with level
 0 if we should proceed to the [n > 0] case, and with level 1 if there is an
 actual error. *)
+
 Local Ltac iApplyHypExact H :=
-  eapply tac_assumption with H _ _; (* (i:=H) *)
+  notypeclasses refine (tac_assumption _ H _ _ _ _ _ _); (* (i:=H) *)
     [pm_reflexivity
     |tc_solve
     |pm_reduce; tc_solve ||
@@ -1132,7 +1138,7 @@ Local Ltac iApplyHypExact H :=
 
 Local Ltac iApplyHypLoop H :=
   first
-    [eapply tac_apply with H _ _ _;
+    [notypeclasses refine (tac_apply _ H _ _ _ _ _ _ _);
       [pm_reflexivity
       |tc_solve
       |pm_reduce]
@@ -1154,21 +1160,21 @@ Tactic Notation "iApply" open_constr(lem) :=
 (** * Disjunction *)
 Tactic Notation "iLeft" :=
   iStartProof;
-  eapply tac_or_l;
+  notypeclasses refine (tac_or_l _ _ _ _ _ _);
     [tc_solve ||
      let P := match goal with |- FromOr ?P _ _ => P end in
      fail "iLeft:" P "not a disjunction"
     |(* subgoal *)].
 Tactic Notation "iRight" :=
   iStartProof;
-  eapply tac_or_r;
+  notypeclasses refine (tac_or_r _ _ _ _ _ _);
     [tc_solve ||
      let P := match goal with |- FromOr ?P _ _ => P end in
      fail "iRight:" P "not a disjunction"
     |(* subgoal *)].
 
 Tactic Notation "iOrDestruct" constr(H) "as" constr(H1) constr(H2) :=
-  eapply tac_or_destruct with H _ H1 H2 _ _ _; (* (i:=H) (j1:=H1) (j2:=H2) *)
+  notypeclasses refine (tac_or_destruct _ H _ H1 H2 _ _ _ _ _ _ _); (* (i:=H) (j1:=H1) (j2:=H2) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iOrDestruct:" H "not found"
@@ -1187,7 +1193,7 @@ Tactic Notation "iOrDestruct" constr(H) "as" constr(H1) constr(H2) :=
 (** * Conjunction and separating conjunction *)
 Tactic Notation "iSplit" :=
   iStartProof;
-  eapply tac_and_split;
+  notypeclasses refine (tac_and_split _ _ _ _ _ _ _);
     [tc_solve ||
      let P := match goal with |- FromAnd ?P _ _ => P end in
      fail "iSplit:" P "not a conjunction"
@@ -1199,7 +1205,7 @@ Tactic Notation "iSplitL" constr(Hs) :=
   let Hs := String.words Hs in
   let Hs := eval vm_compute in (INamed <$> Hs) in
   let Δ := iGetCtx in
-  eapply tac_sep_split with Left Hs _ _; (* (js:=Hs) *)
+  notypeclasses refine (tac_sep_split _ Left Hs _ _ _ _ _); (* (js:=Hs) *)
     [tc_solve ||
      let P := match goal with |- FromSep ?P _ _ => P end in
      fail "iSplitL:" P "not a separating conjunction"
@@ -1215,7 +1221,7 @@ Tactic Notation "iSplitR" constr(Hs) :=
   let Hs := String.words Hs in
   let Hs := eval vm_compute in (INamed <$> Hs) in
   let Δ := iGetCtx in
-  eapply tac_sep_split with Right Hs _ _; (* (js:=Hs) *)
+  notypeclasses refine (tac_sep_split _ Right Hs _ _ _ _ _); (* (js:=Hs) *)
     [tc_solve ||
      let P := match goal with |- FromSep ?P _ _ => P end in
      fail "iSplitR:" P "not a separating conjunction"
@@ -1230,7 +1236,8 @@ Tactic Notation "iSplitL" := iSplitR "".
 Tactic Notation "iSplitR" := iSplitL "".
 
 Local Tactic Notation "iAndDestruct" constr(H) "as" constr(H1) constr(H2) :=
-  eapply tac_and_destruct with H _ H1 H2 _ _ _; (* (i:=H) (j1:=H1) (j2:=H2) *)
+  notypeclasses refine (tac_and_destruct _ H _ H1 H2 _ _ _ _ _ _ _);
+    (* (i:=H) (j1:=H1) (j2:=H2) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iAndDestruct:" H "not found"
@@ -1251,7 +1258,7 @@ Local Tactic Notation "iAndDestruct" constr(H) "as" constr(H1) constr(H2) :=
      end].
 
 Local Tactic Notation "iAndDestructChoice" constr(H) "as" constr(d) constr(H') :=
-  eapply tac_and_destruct_choice with H _ d H' _ _ _;
+  notypeclasses refine (tac_and_destruct_choice _ H _ d H' _ _ _ _ _ _ _);
     [pm_reflexivity || fail "iAndDestructChoice:" H "not found"
     |pm_reduce; tc_solve ||
      let P := match goal with |- TCOr (IntoAnd _ ?P _ _) _ => P end in
@@ -1268,7 +1275,7 @@ Local Tactic Notation "iAndDestructChoice" constr(H) "as" constr(d) constr(H') :
 
 Ltac _iExists x :=
   iStartProof;
-  eapply tac_exist;
+  notypeclasses refine (tac_exist _ _ _ _ _);
     [tc_solve ||
      let P := match goal with |- FromExist ?P _ => P end in
      fail "iExists:" P "not an existential"
@@ -1280,7 +1287,7 @@ Tactic Notation "iExists" ne_uconstr_list_sep(xs,",") :=
 
 Local Tactic Notation "iExistDestruct" constr(H)
     "as" simple_intropattern(x) constr(Hx) :=
-  eapply tac_exist_destruct with H _ Hx _ _ _; (* (i:=H) (j:=Hx) *)
+  notypeclasses refine (tac_exist_destruct _ H _ Hx _ _ _ _ _ _ _); (* (i:=H) (j:=Hx) *)
     [pm_reflexivity ||
      let H := pretty_ident H in
      fail "iExistDestruct:" H "not found"
@@ -1335,7 +1342,7 @@ Tactic Notation "iNext" := iModIntro (▷^_ _)%I.
 
 (** * Update modality *)
 Tactic Notation "iModCore" constr(H) "as" constr(H') :=
-  eapply tac_modal_elim with H H' _ _ _ _ _ _;
+  notypeclasses refine (tac_modal_elim _ H H' _ _ _ _ _ _ _ _ _ _ _);
     [pm_reflexivity || fail "iMod:" H "not found"
     |tc_solve ||
      let P := match goal with |- ElimModal _ _ _ ?P _ _ _ => P end in
@@ -1906,7 +1913,8 @@ Tactic Notation "iAssertCore" open_constr(Q)
   | _ => fail "iAssert: exactly one specialization pattern should be given"
   end;
   let H := iFresh in
-  eapply tac_assert with H Q;
+  notypeclasses refine (tac_assert _ H Q _ _);
+  resolve_tc Q;
   [pm_reduce;
    iSpecializeCore H with hnil pats as p; [..|tac H]].
 
@@ -1945,7 +1953,7 @@ Local Ltac iRewriteFindPred :=
 
 Local Tactic Notation "iRewriteCore" constr(lr) open_constr(lem) :=
   iPoseProofCore lem as true (fun Heq =>
-    eapply (tac_rewrite _ Heq _ _ lr);
+    notypeclasses refine (tac_rewrite _ Heq _ _ lr _ _ _ _ _ _ _ _ _);
       [pm_reflexivity ||
        let Heq := pretty_ident Heq in
        fail "iRewrite:" Heq "not found"
@@ -1960,7 +1968,7 @@ Tactic Notation "iRewrite" "-" open_constr(lem) := iRewriteCore Left lem.
 
 Local Tactic Notation "iRewriteCore" constr(lr) open_constr(lem) "in" constr(H) :=
   iPoseProofCore lem as true (fun Heq =>
-    eapply (tac_rewrite_in _ Heq _ _ H _ _ lr);
+    notypeclasses refine (tac_rewrite_in _ Heq _ _ H _ _ lr _ _ _ _ _ _ _ _ _ _);
       [pm_reflexivity ||
        let Heq := pretty_ident Heq in
        fail "iRewrite:" Heq "not found"
@@ -2129,7 +2137,9 @@ Tactic Notation "iInv" constr(N) "as" "(" ne_simple_intropattern_list(xs) ")"
 
 (** Miscellaneous *)
 Tactic Notation "iAccu" :=
-  iStartProof; eapply tac_accu; [pm_reflexivity || fail "iAccu: not an evar"].
+  iStartProof;
+  notypeclasses refine (tac_accu _ _ _);
+    [pm_reflexivity || fail "iAccu: not an evar"].
 
 (** Automation *)
 Global Hint Extern 0 (_ ⊢ _) => iStartProof : core.
diff --git a/iris/proofmode/reduction.v b/iris/proofmode/reduction.v
index be61cf47d..716117fe9 100644
--- a/iris/proofmode/reduction.v
+++ b/iris/proofmode/reduction.v
@@ -58,7 +58,9 @@ Ltac pm_reduce :=
   (* Use [change_no_check] instead of [change] to avoid performing the
   conversion check twice. *)
   match goal with |- ?u => let v := pm_eval u in change_no_check v end.
-Ltac pm_reflexivity := pm_reduce; exact eq_refl.
+
+Ltac pm_reflexivity :=
+  pm_reduce; notypeclasses refine eq_refl.
 
 (** Called by many tactics for redexes that are created by instantiation.
     This cannot create any envs redexes so we just do the cbn part. *)
-- 
GitLab


From f8bc6e64f68ad92485db731c112be3b90cfc679b Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Tue, 8 Oct 2024 10:59:16 +0100
Subject: [PATCH 2/3] Call `resolve_tc` in `iSpecialize`.

---
 iris/proofmode/ltac_tactics.v | 11 +++++++++--
 tests/proofmode.v             |  4 +---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/iris/proofmode/ltac_tactics.v b/iris/proofmode/ltac_tactics.v
index 3439ddebe..2c3237806 100644
--- a/iris/proofmode/ltac_tactics.v
+++ b/iris/proofmode/ltac_tactics.v
@@ -1078,10 +1078,17 @@ Tactic Notation "iSpecializeCore" open_constr(t) "as" constr(p) :=
     end
   end.
 
+(** To finish the user-facing [iSpecialize] tactics we call [resolve_tc] to
+solve remaining TC obligations in the given term [t]. See [test_iSpecialize_tc]
+for a test.
+
+Note that we do not call [resolve_tc] in the internal [iSpecializeCore] tactics
+above, because that would be too eager. It will only be called in the very end
+by [iPoseProofCore] below. *)
 Tactic Notation "iSpecialize" open_constr(t) :=
-  iSpecializeCore t as false.
+  iSpecializeCore t as false; resolve_tc t.
 Tactic Notation "iSpecialize" open_constr(t) "as" "#" :=
-  iSpecializeCore t as true.
+  iSpecializeCore t as true; resolve_tc t.
 
 (** The tactic [iPoseProofCore lem as p tac] inserts the resource
 described by [lem] into the context. The tactic takes a continuation [tac] as
diff --git a/tests/proofmode.v b/tests/proofmode.v
index 4d6ba28db..a2c768b7d 100644
--- a/tests/proofmode.v
+++ b/tests/proofmode.v
@@ -636,9 +636,7 @@ Proof. iExists {[ 1%positive ]}, ∅. auto. Qed.
 
 Lemma test_iSpecialize_tc P : (∀ x y z : gset positive, P) -∗ P.
 Proof.
-  iIntros "H".
-  (* FIXME: this [unshelve] and [apply _] should not be needed. *)
-  unshelve iSpecialize ("H" $! ∅ {[ 1%positive ]} ∅); try apply _. done.
+  iIntros "H". iSpecialize ("H" $! ∅ {[ 1%positive ]} ∅). done.
 Qed.
 
 Lemma test_iFrame_pure `{!BiInternalEq PROP} {A : ofe} (φ : Prop) (y z : A) :
-- 
GitLab


From fb81776a93091130748e169ee5c4297e6f73a1ad Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Tue, 8 Oct 2024 14:23:01 +0100
Subject: [PATCH 3/3] Use `refine` for `Frame` base cases.

---
 iris/proofmode/class_instances_frame.v | 30 ++++++++++++++++----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/iris/proofmode/class_instances_frame.v b/iris/proofmode/class_instances_frame.v
index 7a399e4d7..a38d418ff 100644
--- a/iris/proofmode/class_instances_frame.v
+++ b/iris/proofmode/class_instances_frame.v
@@ -4,36 +4,44 @@ From iris.prelude Require Import options.
 Import bi.
 
 (** This file defines the instances that make up the framing machinery. *)
-
-Section class_instances_frame.
-Context {PROP : bi}.
-Implicit Types P Q R : PROP.
-
 (** When framing [R] against itself, we leave [True] if possible (via
 [frame_here_absorbing] or [frame_affinely_here_absorbing]) since it is a weaker
 goal. Otherwise we leave [emp] via [frame_here].
 Only if all those options fail, we start decomposing [R], via instances like
 [frame_exist]. To ensure that, all other instances must have cost > 1. *)
-Global Instance frame_here_absorbing p R :
-  QuickAbsorbing R → Frame p R R True | 0.
+Lemma frame_here_absorbing {PROP : bi} p (R : PROP) :
+  QuickAbsorbing R → Frame p R R True.
 Proof.
   rewrite /QuickAbsorbing /Frame. intros.
   by rewrite intuitionistically_if_elim sep_elim_l.
 Qed.
-Global Instance frame_here p R : Frame p R R emp | 1.
+Lemma frame_here {PROP : bi} p (R : PROP) : Frame p R R emp.
 Proof. intros. by rewrite /Frame intuitionistically_if_elim sep_elim_l. Qed.
-Global Instance frame_affinely_here_absorbing p R :
-  QuickAbsorbing R → Frame p (<affine> R) R True | 0.
+Lemma frame_affinely_here_absorbing {PROP : bi} p (R : PROP) :
+  QuickAbsorbing R → Frame p (<affine> R) R True.
 Proof.
   rewrite /QuickAbsorbing /Frame. intros.
   rewrite intuitionistically_if_elim affinely_elim. apply sep_elim_l, _.
 Qed.
-Global Instance frame_affinely_here p R : Frame p (<affine> R) R emp | 1.
+Lemma frame_affinely_here {PROP : bi} p (R : PROP) : Frame p (<affine> R) R emp.
 Proof.
   intros. rewrite /Frame intuitionistically_if_elim affinely_elim.
   apply sep_elim_l, _.
 Qed.
 
+Global Hint Extern 0 (Frame _ _ _ _) =>
+  notypeclasses refine (frame_here_absorbing _ _ _) : typeclass_instances.
+Global Hint Extern 1 (Frame _ _ _ _) =>
+  notypeclasses refine (frame_here _ _) : typeclass_instances.
+Global Hint Extern 0 (Frame _ (<affine> _) _ _) =>
+  notypeclasses refine (frame_affinely_here_absorbing _ _ _) : typeclass_instances.
+Global Hint Extern 1 (Frame _ (<affine> _) _ _) =>
+  notypeclasses refine (frame_affinely_here _ _) : typeclass_instances.
+
+Section class_instances_frame.
+Context {PROP : bi}.
+Implicit Types P Q R : PROP.
+
 Global Instance frame_here_pure_persistent a φ Q :
   FromPure a Q φ → Frame true ⌜φ⌝ Q emp | 2.
 Proof.
-- 
GitLab