Skip to content
Snippets Groups Projects
Commit 0ccf17a1 authored by Robbert Krebbers's avatar Robbert Krebbers
Browse files

Merge branch 'msammler/feed_docs' into 'master'

Refactor and improve documentation of feed and efeed tactics

See merge request iris/stdpp!403
parents d6c6e66a 43a60a31
No related branches found
No related tags found
1 merge request!403Refactor and improve documentation of feed and efeed tactics
Pipeline #70983 passed
...@@ -53,6 +53,11 @@ Coq 8.11 is no longer supported. ...@@ -53,6 +53,11 @@ Coq 8.11 is no longer supported.
lemmas using `Qp.lem` instead of `Qp_lem`. lemmas using `Qp.lem` instead of `Qp_lem`.
- Rename `_plus`/`_minus` into `_add`/`_sub` to be consistent with Coq's current - Rename `_plus`/`_minus` into `_add`/`_sub` to be consistent with Coq's current
convention for numbers. See the sed script below for an exact list of renames. convention for numbers. See the sed script below for an exact list of renames.
- Refactor the `feed` and `efeed` tactics. In particular, improve the
documentation of `(e)feed` tactics, rename the primitive `(e)feed`
tactic to `(e)feed_core`, make the syntax of `feed_core` consistent
with `efeed_core`, remove the `by` parameter of `efeed_core`, and add
`(e)feed generalize`, `efeed inversion`, and `efeed destruct`.
The following `sed` script should perform most of the renaming The following `sed` script should perform most of the renaming
(on macOS, replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`). (on macOS, replace `sed` by `gsed`, installed via e.g. `brew install gnu-sed`).
......
...@@ -496,10 +496,16 @@ Tactic Notation "iter" tactic(tac) tactic(l) := ...@@ -496,10 +496,16 @@ Tactic Notation "iter" tactic(tac) tactic(l) :=
let rec go l := let rec go l :=
match l with ?x :: ?l => tac x || go l end in go l. match l with ?x :: ?l => tac x || go l end in go l.
(** Given [H : A_1 → ... → A_n → B] (where each [A_i] is non-dependent), the (** Given [H : A_1 → ... → A_n → B] (where each [A_i] is non-dependent
tactic [feed tac H tac_by] creates a subgoal for each [A_i] and calls [tac p] and [B] is not convertible to an arrow), the tactic [feed_core H using
with the generated proof [p] of [B]. *) tac] creates a subgoal for each [A_i] (in front of the original goal)
Tactic Notation "feed" tactic(tac) constr(H) := and calls [tac p] with the generated proof [p] of [B].
For example, given [H : P → Q → R], [feed_core H using (fun p
=> pose proof p)] creates the subgoals [P] and [Q] in front of the
original goal, and then in the original goal executes
[pose proof Hfeed] where [Hfeed : R], which adds [R] to the context. *)
Tactic Notation "feed_core" constr(H) "using" tactic3(tac) :=
let rec go H := let rec go H :=
let T := type of H in let T := type of H in
lazymatch eval hnf in T with lazymatch eval hnf in T with
...@@ -514,49 +520,97 @@ Tactic Notation "feed" tactic(tac) constr(H) := ...@@ -514,49 +520,97 @@ Tactic Notation "feed" tactic(tac) constr(H) :=
| ?T1 => tac H | ?T1 => tac H
end in go H. end in go H.
(** The tactic [efeed tac H] is similar to [feed], but it also instantiates (** The tactic [efeed_core H using tac] is similar to [feed_core], but
dependent premises of [H] with evars. *) it also instantiates dependent premises of [H] with evars.
Tactic Notation "efeed" constr(H) "using" tactic3(tac) "by" tactic3 (bytac) :=
For example, given [H : ∀ x y, P x → Q y → R x y] (where [R x y] is
not convertible to an arrow/forall), [efeed_core H using (fun p
=> pose proof p)] creates evars [?x] and [?y] for [x] and [y] and
subgoals [P ?x] and [Q ?y] in front of the original goal, and then
in the original goal executes [pose proof Hfeed] where
[Hfeed : R ?x ?y], which adds [R ?x ?y] to the context. *)
Tactic Notation "efeed_core" constr(H) "using" tactic3(tac) :=
let rec go H := let rec go H :=
let T := type of H in let T := type of H in
lazymatch eval hnf in T with lazymatch eval hnf in T with
| ?T1 ?T2 => | ?T1 ?T2 =>
let HT1 := fresh "feed" in assert T1 as HT1; let HT1 := fresh "feed" in assert T1 as HT1;
[bytac | go (H HT1); clear HT1 ] [| go (H HT1); clear HT1 ]
| ?T1 _ => | ?T1 _ =>
let e := mk_evar T1 in let e := mk_evar T1 in
go (H e) go (H e)
| ?T1 => tac H | ?T1 => tac H
end in go H. end in go H.
Tactic Notation "efeed" constr(H) "using" tactic3(tac) :=
efeed H using tac by idtac.
(** The following variants of [pose proof], [specialize], [inversion], and (** The following variants of [pose proof], [specialize], [inversion], and
[destruct], use the [feed] tactic before invoking the actual tactic. *) [destruct], use the [(e)feed_core] tactic before invoking the actual tactic. *)
(** [feed pose proof H as H'] on [H : P → Q → R] creates two new
subgoals [P] and [Q] in front of the original goal and adds [H' : R] to
the context of the original goal. *)
Tactic Notation "feed" "pose" "proof" constr(H) "as" ident(H') := Tactic Notation "feed" "pose" "proof" constr(H) "as" ident(H') :=
feed (fun p => pose proof p as H') H. feed_core H using (fun p => pose proof p as H').
Tactic Notation "feed" "pose" "proof" constr(H) := Tactic Notation "feed" "pose" "proof" constr(H) :=
feed (fun p => pose proof p) H. feed_core H using (fun p => pose proof p).
Tactic Notation "efeed" "pose" "proof" constr(H) "as" ident(H') := Tactic Notation "efeed" "pose" "proof" constr(H) "as" ident(H') :=
efeed H using (fun p => pose proof p as H'). efeed_core H using (fun p => pose proof p as H').
Tactic Notation "efeed" "pose" "proof" constr(H) := Tactic Notation "efeed" "pose" "proof" constr(H) :=
efeed H using (fun p => pose proof p). efeed_core H using (fun p => pose proof p).
(** [feed specialize H] on hypothesis [H : P → Q → R] creates two new
subgoals [P] and [Q] in front of the original goal and changes [H] to have
type [R] in the original goal.
Note that [(e)feed specialize] only works on hypotheses. For arbitrary
proof terms, use [(e)feed pose proof]. *)
Tactic Notation "feed" "specialize" hyp(H) := Tactic Notation "feed" "specialize" hyp(H) :=
feed (fun p => specialize p) H. feed_core H using (fun p => specialize p).
Tactic Notation "efeed" "specialize" hyp(H) := Tactic Notation "efeed" "specialize" hyp(H) :=
efeed H using (fun p => specialize p). efeed_core H using (fun p => specialize p).
(** [feed generalize H] on [H : P → Q → R] creates two new
subgoals [P] and [Q] in front of the original goal and adds [R] to
the original goal (i.e. [Goal] becomes [R → Goal]).
[efeed generalize] is also sometimes called [exploit] (e.g. in
CompCert). *)
Tactic Notation "feed" "generalize" constr(H) :=
feed_core H using (fun p => let H':=fresh in pose proof p as H'; revert H').
Tactic Notation "efeed" "generalize" constr(H) :=
efeed_core H using (fun p => let H':=fresh in pose proof p as H'; revert H').
(** [feed inversion H] on [H : P → Q → R] creates two new subgoals [P]
and [Q] in front of the original goal and performs [inversion] on [R]
in the original goal.
Note that [(e)feed inversion] allows passing terms, not just
identifiers (unlike standard [inversion]). *)
Tactic Notation "feed" "inversion" constr(H) := Tactic Notation "feed" "inversion" constr(H) :=
feed (fun p => let H':=fresh in pose proof p as H'; inversion H') H. feed_core H using (fun p => let H':=fresh in pose proof p as H'; inversion H').
Tactic Notation "efeed" "inversion" constr(H) :=
efeed_core H using (fun p => let H':=fresh in pose proof p as H'; inversion H').
Tactic Notation "feed" "inversion" constr(H) "as" simple_intropattern(IP) := Tactic Notation "feed" "inversion" constr(H) "as" simple_intropattern(IP) :=
feed (fun p => let H':=fresh in pose proof p as H'; inversion H' as IP) H. feed_core H using (fun p => let H':=fresh in pose proof p as H'; inversion H' as IP).
Tactic Notation "efeed" "inversion" constr(H) "as" simple_intropattern(IP) :=
efeed_core H using (fun p => let H':=fresh in pose proof p as H'; inversion H' as IP).
(** [feed destruct H] on [H : P → Q → R] creates two new subgoals [P]
and [Q] in front of the original goal and performs [destruct] on [R]
in the original goal.
[destruct] and [edestruct] already provide the functionality of
[feed destruct] and [efeed destruct], but we provide [feed destruct]
and [efeed destruct] for consistency. *)
Tactic Notation "feed" "destruct" constr(H) := Tactic Notation "feed" "destruct" constr(H) :=
feed (fun p => let H':=fresh in pose proof p as H'; destruct H') H. feed_core H using (fun p => let H':=fresh in pose proof p as H'; destruct H').
Tactic Notation "efeed" "destruct" constr(H) :=
efeed_core H using (fun p => let H':=fresh in pose proof p as H'; destruct H').
Tactic Notation "feed" "destruct" constr(H) "as" simple_intropattern(IP) := Tactic Notation "feed" "destruct" constr(H) "as" simple_intropattern(IP) :=
feed (fun p => let H':=fresh in pose proof p as H'; destruct H' as IP) H. feed_core H using (fun p => let H':=fresh in pose proof p as H'; destruct H' as IP).
Tactic Notation "efeed" "destruct" constr(H) "as" simple_intropattern(IP) :=
efeed_core H using (fun p => let H':=fresh in pose proof p as H'; destruct H' as IP).
(** The block definitions are taken from [Coq.Program.Equality] and can be used (** The block definitions are taken from [Coq.Program.Equality] and can be used
by tactics to separate their goal from hypotheses they generalize over. *) by tactics to separate their goal from hypotheses they generalize over. *)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment