Commit d1ef32dd authored by Robbert Krebbers's avatar Robbert Krebbers

Uniform syntax for selecting hypotheses.

Used in iRevert, iClear, iFrame, and for generalizing the IH in
iInduction and iLöb.
parent 6d021c73
Pipeline #2732 passed with stage
in 9 minutes and 27 seconds
...@@ -23,13 +23,12 @@ Context management ...@@ -23,13 +23,12 @@ Context management
- `iIntros (x1 ... xn) "ipat1 ... ipatn"` : introduce universal quantifiers - `iIntros (x1 ... xn) "ipat1 ... ipatn"` : introduce universal quantifiers
using Coq introduction patterns `x1 ... xn` and implications/wands using proof using Coq introduction patterns `x1 ... xn` and implications/wands using proof
mode introduction patterns `ipat1 ... ipatn`. mode introduction patterns `ipat1 ... ipatn`.
- `iClear (x1 ... xn) "H1 ... Hn"` : clear the hypothesis `H1 ... Hn` as well as - `iClear (x1 ... xn) "selpat"` : clear the hypotheses given by the selection
the Coq level hypotheses/variables `x1 ... xn`. The symbol `★` can be used to pattern `selpat` and the Coq level hypotheses/variables `x1 ... xn`.
clear entire spatial context. - `iRevert (x1 ... xn) "selpat"` : revert the hypotheses given by the selection
- `iRevert (x1 ... xn) "H1 ... Hn"` : revert the proof mode hypotheses pattern `selpat` into wands, and the Coq level hypotheses/variables
`H1 ... Hn` into wands, as well as the Coq level hypotheses/variables `x1 ... xn` into universal quantifiers. Persistent hypotheses are wrapped into
`x1 ... xn` into universal quantifiers. The symbol `★` can be used to revert the always modality.
the entire spatial context.
- `iRename "H1" into "H2"` : rename the hypothesis `H1` into `H2`. - `iRename "H1" into "H2"` : rename the hypothesis `H1` into `H2`.
- `iSpecialize pm_trm` : instantiate universal quantifiers and eliminate - `iSpecialize pm_trm` : instantiate universal quantifiers and eliminate
implications/wands of a hypothesis `pm_trm`. See proof mode terms below. implications/wands of a hypothesis `pm_trm`. See proof mode terms below.
...@@ -83,9 +82,9 @@ Elimination of logical connectives ...@@ -83,9 +82,9 @@ Elimination of logical connectives
Separating logic specific tactics Separating logic specific tactics
--------------------------------- ---------------------------------
- `iFrame (t1 .. tn) "H0 ... Hn"` : cancel the Coq terms (or Coq hypotheses) - `iFrame (t1 .. tn) "selpat"` : cancel the Coq terms (or Coq hypotheses)
`t1 ... tn` and Iris hypotheses `H0 ... Hn` in the goal. Apart from `t1 ... tn` and Iris hypotheses given by `selpat` in the goal. The constructs
hypotheses, the following symbols can be used: of the selection pattern have the following meaning:
+ `%` : repeatedly frame hypotheses from the Coq context. + `%` : repeatedly frame hypotheses from the Coq context.
+ `#` : repeatedly frame hypotheses from the persistent context. + `#` : repeatedly frame hypotheses from the persistent context.
...@@ -102,16 +101,19 @@ Separating logic specific tactics ...@@ -102,16 +101,19 @@ Separating logic specific tactics
The later modality The later modality
------------------ ------------------
- `iNext` : introduce a later by stripping laters from all hypotheses. - `iNext` : introduce a later by stripping laters from all hypotheses.
- `iLöb as "IH" forall (x1 ... xn)` : perform Löb induction while generalizing - `iLöb as "IH" forall (x1 ... xn)` : perform Löb induction by generating a
Please register or sign in to reply
over the Coq level variables `x1 ... xn` and the entire spatial context. hypothesis `IH : ▷ goal`. The tactic generalizes over the Coq level variables
`x1 ... xn`, the hypotheses given by the selection pattern `selpat`, and the
spatial context.
Induction Induction
--------- ---------
- `iInduction x as cpat "IH" forall (x1 ... xn)` : perform induction on the Coq - `iInduction x as cpat "IH" forall (x1 ... xn) "selpat"` : perform induction on
term `x`. The Coq introduction pattern is used to name the introduced the Coq term `x`. The Coq introduction pattern is used to name the introduced
variables. The induction hypotheses are inserted into the persistent context variables. The induction hypotheses are inserted into the persistent context
and given fresh names prefixed `IH`. The tactic generalizes over the Coq level and given fresh names prefixed `IH`. The tactic generalizes over the Coq level
variables `x1 ... xn` and the entire spatial context. variables `x1 ... xn`, the hypotheses given by the selection pattern `selpat`,
and the spatial context.
Rewriting Rewriting
--------- ---------
...@@ -141,14 +143,26 @@ Miscellaneous ...@@ -141,14 +143,26 @@ Miscellaneous
existential quantifiers, implications and wand, always and later modalities, existential quantifiers, implications and wand, always and later modalities,
primitive view shifts, and pure connectives. primitive view shifts, and pure connectives.
Selection patterns
==================
Selection patterns are used to select hypotheses in the tactics `iRevert`,
`iClear`, `iFrame`, `iLöb` and `iInduction`. The proof mode supports the
following _selection patterns_:
- `H` : select the hypothesis named `H`.
- `%` : select the entire pure/Coq context.
- `#` : select the entire persistent context.
- `★` : select the entire spatial context.
Introduction patterns Introduction patterns
===================== =====================
Introduction patterns are used to perform introductions and eliminations of Introduction patterns are used to perform introductions and eliminations of
multiple connectives on the fly. The proof mode supports the following multiple connectives on the fly. The proof mode supports the following
introduction patterns: _introduction patterns_:
- `H` : create a hypothesis named H. - `H` : create a hypothesis named `H`.
- `?` : create an anonymous hypothesis. - `?` : create an anonymous hypothesis.
- `_` : remove the hypothesis. - `_` : remove the hypothesis.
- `$` : frame the hypothesis in the goal. - `$` : frame the hypothesis in the goal.
...@@ -197,9 +211,9 @@ Specialization patterns ...@@ -197,9 +211,9 @@ Specialization patterns
======================= =======================
Since we are reasoning in a spatial logic, when eliminating a lemma or Since we are reasoning in a spatial logic, when eliminating a lemma or
hypotheses of type ``P_0 -★ ... -★ P_n -★ R`` one has to specify how the hypothesis of type ``P_0 -★ ... -★ P_n -★ R``, one has to specify how the
hypotheses are split between the premises. The proof mode supports the following hypotheses are split between the premises. The proof mode supports the following
so called specification patterns to express this splitting: _specification patterns_ to express splitting of hypotheses:
- `H` : use the hypothesis `H` (it should match the premise exactly). If `H` is - `H` : use the hypothesis `H` (it should match the premise exactly). If `H` is
spatial, it will be consumed. spatial, it will be consumed.
......
...@@ -120,6 +120,7 @@ proofmode/pviewshifts.v ...@@ -120,6 +120,7 @@ proofmode/pviewshifts.v
proofmode/environments.v proofmode/environments.v
proofmode/intro_patterns.v proofmode/intro_patterns.v
proofmode/spec_patterns.v proofmode/spec_patterns.v
proofmode/sel_patterns.v
proofmode/tactics.v proofmode/tactics.v
proofmode/notation.v proofmode/notation.v
proofmode/invariants.v proofmode/invariants.v
......
...@@ -152,7 +152,7 @@ Module inv. Section inv. ...@@ -152,7 +152,7 @@ Module inv. Section inv.
iDestruct (finished_dup with "Hf") as "[Hf Hf']". iDestruct (finished_dup with "Hf") as "[Hf Hf']".
iApply pvs_intro. iSplitL "Hf'"; first by eauto. iApply pvs_intro. iSplitL "Hf'"; first by eauto.
(* Step 2: Open the Q-invariant. *) (* Step 2: Open the Q-invariant. *)
iClear "HiP". clear i. iDestruct "HsQ" as (i) "HiQ". iClear (i) "HiP ". iDestruct "HsQ" as (i) "HiQ".
iApply (inv_open' i). iSplit; first done. iApply (inv_open' i). iSplit; first done.
iIntros "[HaQ | [_ #HQ]]". iIntros "[HaQ | [_ #HQ]]".
{ iExFalso. iApply finished_not_start. by iFrame. } { iExFalso. iApply finished_not_start. by iFrame. }
......
...@@ -82,6 +82,9 @@ Definition env_spatial_is_nil {M} (Δ : envs M) := ...@@ -82,6 +82,9 @@ Definition env_spatial_is_nil {M} (Δ : envs M) :=
Definition envs_clear_spatial {M} (Δ : envs M) : envs M := Definition envs_clear_spatial {M} (Δ : envs M) : envs M :=
Envs (env_persistent Δ) Enil. Envs (env_persistent Δ) Enil.
Definition envs_clear_persistent {M} (Δ : envs M) : envs M :=
Envs Enil (env_spatial Δ).
Fixpoint envs_split_go {M} Fixpoint envs_split_go {M}
(js : list string) (Δ1 Δ2 : envs M) : option (envs M * envs M) := (js : list string) (Δ1 Δ2 : envs M) : option (envs M * envs M) :=
match js with match js with
...@@ -272,12 +275,6 @@ Proof. ...@@ -272,12 +275,6 @@ Proof.
destruct Hwf; constructor; simpl; auto using Enil_wf. destruct Hwf; constructor; simpl; auto using Enil_wf.
Qed. Qed.
Lemma env_fold_wand Γ Q : env_fold uPred_wand Q Γ ([] Γ - Q).
Proof.
revert Q; induction Γ as [|Γ IH i P]=> Q /=; [by rewrite wand_True|].
by rewrite IH wand_curry (comm uPred_sep).
Qed.
Lemma env_spatial_is_nil_persistent Δ : Lemma env_spatial_is_nil_persistent Δ :
env_spatial_is_nil Δ = true PersistentP Δ. env_spatial_is_nil Δ = true PersistentP Δ.
Proof. intros; destruct Δ as [? []]; simplify_eq/=; apply _. Qed. Proof. intros; destruct Δ as [? []]; simplify_eq/=; apply _. Qed.
...@@ -385,9 +382,6 @@ Qed. ...@@ -385,9 +382,6 @@ Qed.
Lemma tac_clear Δ Δ' i p P Q : Lemma tac_clear Δ Δ' i p P Q :
envs_lookup_delete i Δ = Some (p,P,Δ') (Δ' Q) Δ Q. envs_lookup_delete i Δ = Some (p,P,Δ') (Δ' Q) Δ Q.
Proof. intros. by rewrite envs_lookup_delete_sound // sep_elim_r. Qed. Proof. intros. by rewrite envs_lookup_delete_sound // sep_elim_r. Qed.
Lemma tac_clear_spatial Δ Δ' Q :
envs_clear_spatial Δ = Δ' (Δ' Q) Δ Q.
Proof. intros <- ?. by rewrite envs_clear_spatial_sound // sep_elim_l. Qed.
(** * False *) (** * False *)
Lemma tac_ex_falso Δ Q : (Δ False) Δ Q. Lemma tac_ex_falso Δ Q : (Δ False) Δ Q.
...@@ -612,12 +606,6 @@ Proof. ...@@ -612,12 +606,6 @@ Proof.
- by rewrite HQ wand_elim_r. - by rewrite HQ wand_elim_r.
Qed. Qed.
Lemma tac_revert_spatial Δ Q :
(envs_clear_spatial Δ env_fold uPred_wand Q (env_spatial Δ)) Δ Q.
Proof.
intros HΔ. by rewrite envs_clear_spatial_sound HΔ env_fold_wand wand_elim_l.
Qed.
Lemma tac_revert_ih Δ P Q : Lemma tac_revert_ih Δ P Q :
env_spatial_is_nil Δ = true env_spatial_is_nil Δ = true
(of_envs Δ P) (of_envs Δ P)
......
...@@ -38,12 +38,6 @@ Instance: Params (@env_to_list) 1. ...@@ -38,12 +38,6 @@ Instance: Params (@env_to_list) 1.
Fixpoint env_dom {A} (Γ : env A) : list string := Fixpoint env_dom {A} (Γ : env A) : list string :=
match Γ with Enil => [] | Esnoc Γ i _ => i :: env_dom Γ end. match Γ with Enil => [] | Esnoc Γ i _ => i :: env_dom Γ end.
Fixpoint env_fold {A B} (f : B A A) (x : A) (Γ : env B) : A :=
match Γ with
| Enil => x
| Esnoc Γ _ y => env_fold f (f y x) Γ
end.
Fixpoint env_app {A} (Γapp : env A) (Γ : env A) : option (env A) := Fixpoint env_app {A} (Γapp : env A) (Γ : env A) : option (env A) :=
match Γapp with match Γapp with
| Enil => Some Γ | Enil => Some Γ
......
From iris.prelude Require Export strings.
Inductive sel_pat :=
| SelPure
| SelPersistent
| SelSpatial
| SelName : string sel_pat.
Fixpoint sel_pat_pure (ps : list sel_pat) : bool :=
match ps with
| [] => false
| SelPure :: ps => true
| _ :: ps => sel_pat_pure ps
end.
Module sel_pat.
Fixpoint cons_name (kn : string) (k : list sel_pat) : list sel_pat :=
match kn with "" => k | _ => SelName (string_rev kn) :: k end.
Fixpoint parse_go (s : string) (k : list sel_pat) (kn : string) : list sel_pat :=
match s with
| "" => rev (cons_name kn k)
| String " " s => parse_go s (cons_name kn k) ""
| String "%" s => parse_go s (SelPure :: cons_name kn k) ""
| String "#" s => parse_go s (SelPersistent :: cons_name kn k) ""
| String (Ascii.Ascii false true false false false true true true) (* unicode ★ *)
(String (Ascii.Ascii false false false true true false false true)
(String (Ascii.Ascii true false true false false false false true) s)) =>
parse_go s (SelSpatial :: cons_name kn k) ""
| String a s => parse_go s k (String a kn)
end.
Definition parse (s : string) : list sel_pat := parse_go s [] "".
Ltac parse s :=
lazymatch type of s with
| list sel_pat => s
| list string => eval vm_compute in (SelName <$> s)
| string => eval vm_compute in (parse s)
end.
End sel_pat.
From iris.proofmode Require Import coq_tactics intro_patterns spec_patterns. From iris.proofmode Require Import coq_tactics.
From iris.proofmode Require Import intro_patterns spec_patterns sel_patterns.
From iris.algebra Require Export upred. From iris.algebra Require Export upred.
From iris.proofmode Require Export classes notation. From iris.proofmode Require Export classes notation.
From iris.proofmode Require Import class_instances. From iris.proofmode Require Import class_instances.
From iris.prelude Require Import stringmap hlist. From iris.prelude Require Import stringmap hlist.
Declare Reduction env_cbv := cbv [ Declare Reduction env_cbv := cbv [
env_lookup env_fold env_lookup_delete env_delete env_app env_replace env_lookup env_lookup_delete env_delete env_app env_replace env_dom
decide (* operational classes *) decide (* operational classes *)
sumbool_rec sumbool_rect (* sumbool *) sumbool_rec sumbool_rect (* sumbool *)
bool_eq_dec bool_rec bool_rect bool_dec eqb andb (* bool *) bool_eq_dec bool_rec bool_rect bool_dec eqb andb (* bool *)
assci_eq_dec ascii_to_digits Ascii.ascii_dec Ascii.ascii_rec Ascii.ascii_rect assci_eq_dec ascii_to_digits Ascii.ascii_dec Ascii.ascii_rec Ascii.ascii_rect
string_eq_dec string_rec string_rect (* strings *) string_eq_dec string_rec string_rect (* strings *)
env_persistent env_spatial env_spatial_is_nil env_persistent env_spatial env_spatial_is_nil envs_dom
envs_lookup envs_lookup_delete envs_delete envs_snoc envs_app envs_lookup envs_lookup_delete envs_delete envs_snoc envs_app
envs_simple_replace envs_replace envs_split envs_clear_spatial envs_simple_replace envs_replace envs_split
envs_clear_spatial envs_clear_persistent
envs_split_go envs_split]. envs_split_go envs_split].
Ltac env_cbv := Ltac env_cbv :=
match goal with |- ?u => let v := eval env_cbv in u in change v end. match goal with |- ?u => let v := eval env_cbv in u in change v end.
...@@ -33,7 +35,7 @@ Ltac iFresh := iFresh' "~". ...@@ -33,7 +35,7 @@ Ltac iFresh := iFresh' "~".
Tactic Notation "iTypeOf" constr(H) tactic(tac):= Tactic Notation "iTypeOf" constr(H) tactic(tac):=
let Δ := match goal with |- of_envs ?Δ _ => Δ end in let Δ := match goal with |- of_envs ?Δ _ => Δ end in
match eval env_cbv in (envs_lookup H Δ) with lazymatch eval env_cbv in (envs_lookup H Δ) with
| Some (?p,?P) => tac p P | Some (?p,?P) => tac p P
end. end.
...@@ -56,16 +58,45 @@ Tactic Notation "iRename" constr(H1) "into" constr(H2) := ...@@ -56,16 +58,45 @@ Tactic Notation "iRename" constr(H1) "into" constr(H2) :=
[env_cbv; reflexivity || fail "iRename:" H1 "not found" [env_cbv; reflexivity || fail "iRename:" H1 "not found"
|env_cbv; reflexivity || fail "iRename:" H2 "not fresh"|]. |env_cbv; reflexivity || fail "iRename:" H2 "not fresh"|].
Local Inductive esel_pat :=
| ESelPure
| ESelName : bool string esel_pat.
Ltac iElaborateSelPat pat tac :=
let rec go pat Δ Hs :=
lazymatch pat with
| [] => let Hs' := eval cbv in Hs in tac Hs'
| SelPure :: ?pat => go pat Δ (ESelPure :: Hs)
| SelPersistent :: ?pat =>
let Hs' := eval env_cbv in (env_dom (env_persistent Δ)) in
let Δ' := eval env_cbv in (envs_clear_persistent Δ) in
go pat Δ' ((ESelName true <$> Hs') ++ Hs)
| SelSpatial :: ?pat =>
let Hs' := eval env_cbv in (env_dom (env_spatial Δ)) in
let Δ' := eval env_cbv in (envs_clear_spatial Δ) in
go pat Δ' ((ESelName false <$> Hs') ++ Hs)
| SelName ?H :: ?pat =>
lazymatch eval env_cbv in (envs_lookup_delete H Δ) with
| Some (?p,_,?Δ') => go pat Δ' (ESelName p H :: Hs)
| None => fail "iElaborateSelPat:" H "not found"
end
end in
lazymatch goal with
| |- of_envs ?Δ _ =>
let pat := sel_pat.parse pat in go pat Δ (@nil esel_pat)
end.
Tactic Notation "iClear" constr(Hs) := Tactic Notation "iClear" constr(Hs) :=
let rec go Hs := let rec go Hs :=
lazymatch Hs with lazymatch Hs with
| [] => idtac | [] => idtac
| "★" :: ?Hs => eapply tac_clear_spatial; [env_cbv; reflexivity|go Hs] | ESelPure :: ?Hs => clear; go Hs
| ?H :: ?Hs => | ESelName _ ?H :: ?Hs =>
eapply tac_clear with _ H _ _; (* (i:=H) *) eapply tac_clear with _ H _ _; (* (i:=H) *)
[env_cbv; reflexivity || fail "iClear:" H "not found"|go Hs] [env_cbv; reflexivity || fail "iClear:" H "not found"|go Hs]
end in end in
let Hs := words Hs in go Hs. iElaborateSelPat Hs go.
Tactic Notation "iClear" "(" ident_list(xs) ")" constr(Hs) := Tactic Notation "iClear" "(" ident_list(xs) ")" constr(Hs) :=
iClear Hs; clear xs. iClear Hs; clear xs.
...@@ -192,12 +223,12 @@ Tactic Notation "iFrame" constr(Hs) := ...@@ -192,12 +223,12 @@ Tactic Notation "iFrame" constr(Hs) :=
let rec go Hs := let rec go Hs :=
match Hs with match Hs with
| [] => idtac | [] => idtac
| "%" :: ?Hs => iFrameAnyPure; go Hs | SelPure :: ?Hs => iFrameAnyPure; go Hs
| "#" :: ?Hs => iFrameAnyPersistent; go Hs | SelPersistent :: ?Hs => iFrameAnyPersistent; go Hs
| "★" :: ?Hs => iFrameAnySpatial; go Hs | SelSpatial :: ?Hs => iFrameAnySpatial; go Hs
| ?H :: ?Hs => iFrameHyp H; go Hs | SelName ?H :: ?Hs => iFrameHyp H; go Hs
end end
in let Hs := words Hs in go Hs. in let Hs := sel_pat.parse Hs in go Hs.
Tactic Notation "iFrame" "(" constr(t1) ")" constr(Hs) := Tactic Notation "iFrame" "(" constr(t1) ")" constr(Hs) :=
iFramePure t1; iFrame Hs. iFramePure t1; iFrame Hs.
Tactic Notation "iFrame" "(" constr(t1) constr(t2) ")" constr(Hs) := Tactic Notation "iFrame" "(" constr(t1) constr(t2) ")" constr(Hs) :=
...@@ -403,17 +434,18 @@ Local Tactic Notation "iForallRevert" ident(x) := ...@@ -403,17 +434,18 @@ Local Tactic Notation "iForallRevert" ident(x) :=
end || fail "iRevert: cannot revert" x. end || fail "iRevert: cannot revert" x.
Tactic Notation "iRevert" constr(Hs) := Tactic Notation "iRevert" constr(Hs) :=
let rec go H2s := let rec go Hs :=
match H2s with lazymatch Hs with
| [] => idtac | [] => idtac
| "★" :: ?H2s => go H2s; eapply tac_revert_spatial; env_cbv | ESelPure :: ?Hs =>
| ?H2 :: ?H2s => repeat match goal with x : _ |- _ => revert x end;
go H2s; go Hs
eapply tac_revert with _ H2 _ _; (* (i:=H2) *) | ESelName _ ?H :: ?Hs =>
[env_cbv; reflexivity || fail "iRevert:" H2 "not found" eapply tac_revert with _ H _ _; (* (i:=H2) *)
|env_cbv] [env_cbv; reflexivity || fail "iRevert:" H "not found"
|env_cbv; go Hs]
end in end in
let Hs := words Hs in go Hs. iElaborateSelPat Hs go.
Tactic Notation "iRevert" "(" ident(x1) ")" := Tactic Notation "iRevert" "(" ident(x1) ")" :=
iForallRevert x1. iForallRevert x1.
...@@ -793,37 +825,71 @@ Tactic Notation "iIntros" "(" simple_intropattern(x1) simple_intropattern(x2) ...@@ -793,37 +825,71 @@ Tactic Notation "iIntros" "(" simple_intropattern(x1) simple_intropattern(x2)
")" constr(p) := ")" constr(p) :=
iIntros ( x1 x2 x3 x4 x5 x6 x7 x8 ); iIntros p. iIntros ( x1 x2 x3 x4 x5 x6 x7 x8 ); iIntros p.
(* Used for generalization in iInduction and iLöb *)
Tactic Notation "iRevertIntros" constr(Hs) "with" tactic(tac) :=
let rec go Hs :=
lazymatch Hs with
| [] => tac
| ESelPure :: ?Hs => fail "iRevertIntros: % not supported"
| ESelName ?p ?H :: ?Hs =>
iRevert H; go Hs;
let H' :=
match p with true => constr:[IAlwaysElim (IName H)] | false => H end in
iIntros H'
end in
iElaborateSelPat Hs go.
Tactic Notation "iRevertIntros" "(" ident(x1) ")" constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1); tac; iIntros (x1)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ")" constr(Hs)
"with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2); tac; iIntros (x1 x2)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ")" constr(Hs)
"with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3); tac; iIntros (x1 x2 x3)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) ")"
constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3 x4); tac; iIntros (x1 x2 x3 x4)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ")" constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3 x4 x5); tac; iIntros (x1 x2 x3 x4 x5)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ")" constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3 x4 x5 x6);
tac; iIntros (x1 x2 x3 x4 x5 x6)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ident(x7) ")" constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3 x4 x5 x6 x7);
tac; iIntros (x1 x2 x3 x4 x5 x6 x7)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ident(x7) ident(x8) ")" constr(Hs) "with" tactic(tac):=
iRevertIntros Hs with (iRevert (x1 x2 x3 x4 x5 x6 x7 x8);
tac; iIntros (x1 x2 x3 x4 x5 x6 x7 x8)).
Tactic Notation "iRevertIntros" "with" tactic(tac) := Tactic Notation "iRevertIntros" "with" tactic(tac) :=
match goal with iRevertIntros "" with tac.
| |- of_envs ?Δ _ =>
let Hs := eval cbv in (reverse (env_dom (env_spatial Δ))) in
iRevert ["★"]; tac; iIntros Hs
end.
Tactic Notation "iRevertIntros" "(" ident(x1) ")" "with" tactic(tac):= Tactic Notation "iRevertIntros" "(" ident(x1) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1); tac; iIntros (x1)). iRevertIntros (x1) "" with tac.
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ")" "with" tactic(tac):= Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2); tac; iIntros (x1 x2)). iRevertIntros (x1 x2) "" with tac.
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ")" Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ")"
"with" tactic(tac):= "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3); tac; iIntros (x1 x2 x3)). iRevertIntros (x1 x2 x3) "" with tac.
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) ")" Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) ")"
"with" tactic(tac):= "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3 x4); tac; iIntros (x1 x2 x3 x4)). iRevertIntros (x1 x2 x3 x4) "" with tac.
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ")" "with" tactic(tac):= ident(x5) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3 x4 x5); tac; iIntros (x1 x2 x3 x4 x5)). iRevertIntros (x1 x2 x3 x4 x5) "" with tac.
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ")" "with" tactic(tac):= ident(x5) ident(x6) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3 x4 x5 x6); iRevertIntros (x1 x2 x3 x4 x5 x6) "" with tac.
tac; iIntros (x1 x2 x3 x4 x5 x6)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ident(x7) ")" "with" tactic(tac):= ident(x5) ident(x6) ident(x7) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3 x4 x5 x6 x7); iRevertIntros (x1 x2 x3 x4 x5 x6 x7) "" with tac.
tac; iIntros (x1 x2 x3 x4 x5 x6 x7)).
Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4) Tactic Notation "iRevertIntros" "(" ident(x1) ident(x2) ident(x3) ident(x4)
ident(x5) ident(x6) ident(x7) ident(x8) ")" "with" tactic(tac):= ident(x5) ident(x6) ident(x7) ident(x8) ")" "with" tactic(tac):=
iRevertIntros with (iRevert (x1 x2 x3 x4 x5 x6 x7 x8); iRevertIntros (x1 x2 x3 x4 x5 x6 x7 x8) "" with tac.
tac; iIntros (x1 x2 x3 x4 x5 x6 x7 x8)).
(** * Destruct tactic *) (** * Destruct tactic *)
Tactic Notation "iDestructCore" open_constr(lem) "as" constr(p) tactic(tac) := Tactic Notation "iDestructCore" open_constr(lem) "as" constr(p) tactic(tac) :=
...@@ -893,7 +959,7 @@ Tactic Notation "iInductionCore" constr(x) ...@@ -893,7 +959,7 @@ Tactic Notation "iInductionCore" constr(x)
lazymatch goal with lazymatch goal with
| H : coq_tactics.of_envs _ _ |- _ => | H : coq_tactics.of_envs _ _ |- _ =>
eapply tac_revert_ih; eapply tac_revert_ih;
[env_cbv; reflexivity [reflexivity || fail "iInduction: persistent context not empty"
|apply H|]; |apply H|];
clear H; fix_ihs; clear H; fix_ihs;
let IH' := iFresh' IH in iIntros [IAlwaysElim (IName IH')] let IH' := iFresh' IH in iIntros [IAlwaysElim (IName IH')]
...@@ -902,64 +968,122 @@ Tactic Notation "iInductionCore" constr(x) ...@@ -902,64 +968,122 @@ Tactic Notation "iInductionCore" constr(x)
induction x as pat; fix_ihs. induction x as pat; fix_ihs.
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) := Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) :=
iRevertIntros with (iInductionCore x as pat IH). iRevertIntros "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ")" := "forall" "(" ident(x1) ")" :=
iRevertIntros(x1) with (iInductionCore x as pat IH). iRevertIntros(x1) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ")" := "forall" "(" ident(x1) ident(x2) ")" :=
iRevertIntros(x1 x2) with (iInductionCore x as pat IH). iRevertIntros(x1 x2) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ")" := "forall" "(" ident(x1) ident(x2) ident(x3) ")" :=
iRevertIntros(x1 x2 x3) with (iInductionCore x as pat IH). iRevertIntros(x1 x2 x3) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ")" := "forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ")" :=
iRevertIntros(x1 x2 x3 x4) with (iInductionCore x as pat IH). iRevertIntros(x1 x2 x3 x4) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ")" := "forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ")" :=
iRevertIntros(x1 x2 x3 x4 x5) with (iInductionCore x as aat IH). iRevertIntros(x1 x2 x3 x4 x5) "★" with (iInductionCore x as aat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6) ")" := "forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6) ")" :=
iRevertIntros(x1 x2 x3 x4 x5 x6) with (iInductionCore x as pat IH). iRevertIntros(x1 x2 x3 x4 x5 x6) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6) "forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6)
ident(x7) ")" := ident(x7) ")" :=
iRevertIntros(x1 x2 x3 x4 x5 x6 x7) with (iInductionCore x as pat IH). iRevertIntros(x1 x2 x3 x4 x5 x6 x7) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH) Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6) "forall" "(" ident(x1) ident(x2) ident(x3) ident(x4) ident(x5) ident(x6)
ident(x7) ident(x8) ")" := ident(x7) ident(x8) ")" :=
iRevertIntros(x1 x2 x3 x4 x5 x6 x7 x8) with (iInductionCore x as pat IH). iRevertIntros(x1 x2 x3 x4 x5 x6 x7 x8) "★" with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" constr(Hs) :=
iRevertIntros Hs with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ")" constr(Hs) :=
iRevertIntros(x1) Hs with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall" "(" ident(x1) ident(x2) ")" constr(Hs) :=
iRevertIntros(x1 x2) Hs with (iInductionCore x as pat IH).
Tactic Notation "iInduction" constr(x) "as" simple_intropattern(pat) constr(IH)
"forall"