Require Export VST.msl.Extensionality.
(*  These three hints are considered "dangerous" because they make proofs noncomputational, which is an issue for things we want to solve with "compute". *)
(* Can't use "Hint Resolve" because a bug in "apply proof_irr" matches things that are not Props, which leads the Qed to fail (later) *)
Hint Extern 1 (@eq _ _ _) => exact (proof_irr _ _) : extensionality.
(* Can't use "Hint Resolve" because it doesn't seem to do anything... *)
Hint Extern 2 (eq _ _)  => apply exist_ext : extensionality.
(* Can't use "Hint Resolve" because it doesn't seem to do anything... *)
Hint Extern 2 (@eq _ (@existT _ _ _ _) (@existT _ _ _ _))  => apply existT_ext : extensionality.
Tactic Notation "forget" constr(X) "as" ident(y) :=
set (y:=X) in *; clearbody y.
Ltac proof_irr := match goal with H: ?A, H' : ?A |- _ => generalize (proof_irr H H'); intro; subst H' end.
Ltac inversion2 H1 H2 :=
rewrite H1 in H2; symmetry in H2; inv H2.
Ltac invT H :=
match type of H  with
| existT _ ?a ?b = existT _ ?a ?c =>
generalize (inj_pair2 _ _ a b c H); clear H; intro H; invT H
| existT _ _ _ = existT _ _ _ =>
let HH := fresh in (injection H; intros _ HH; invT HH; invT H)
| _ => inv H
end.
Ltac invSome :=
match goal with
| H: match ?A with Some _ =>  _ | None => None end = Some _ |- _ =>
let Hx := fresh in
(revert H; case_eq A; [intros ? H Hx | intros H Hx]; inv Hx)
| H: match ?A with Some _ => _  | None => False end |- _ =>
(revert H; case_eq A; [intros ? H ? | intros; contradiction])
| H: match ?A return _ with Some _ =>  _ | None => _ end eq_refl = Some _ |- _ =>
let Hx := fresh in
(revert H; generalize (eq_refl A); pattern A at 1 3; destruct A;
[ intros Hx H | intros ? H; discriminate H])
end.
Ltac split3 := split; [|split].
(* END Tactics copied from ecm/Coqlib2.v *)
Ltac spec H :=
match type of H with ?a -> _ =>
let H1 := fresh in (assert (H1: a); [|generalize (H H1); clear H H1; intro H]) end.
Hint Resolve f_equal_Some f_equal_prod : core.
Unset Implicit Arguments.
Set Implicit Arguments.
(*  The built-in "remember" tactic is weaker than this one! The built-in one can lead to "Error: The correctness of the conclusion relies on the body of a" where this one will succeed. [this comment may be obsolete, perhaps from Coq 8.2 or before Tactic Notation "remember" constr(a) "as" ident(x) := let x := fresh x in let H := fresh "Heq" x in (set (x:=a) in *; assert (H: x=a) by reflexivity; clearbody x). *)
Ltac simple_if_tac :=
match goal with |- context [if ?A then _ else _] =>
lazymatch type of A with
| bool => destruct A
| sumbool _ _ => fail "Use if_tac instead of simple_if_tac, since your expression "A" has type sumbool"
| ?t => fail "Use simple_if_tac only for bool; your expression"A" has type" t
end end.
Tactic Notation "if_tac" :=
match goal with |- context [if ?a then _ else _] =>
lazymatch type of a with
| sumbool _ _ =>destruct a as [?H | ?H]
| bool => fail "Use simple_if_tac instead of if_tac, since your expression"a" has type bool"
| ?t => fail "Use if_tac only for sumbool; your expression"a" has type" t
end end.
Tactic Notation "if_tac" simple_intropattern(H)
:= match goal with |- context [if ?a then _ else _] =>
lazymatch type of a with
| sumbool _ _ =>destruct a as H
| bool => fail "Use simple_if_tac instead of if_tac, since your expression"a" has type bool"
| ?t => fail "Use if_tac only for sumbool; your expression"a" has type" t
end end.
Tactic Notation "if_tac" "in" hyp(H0)
:= match type of H0 with context [if ?a then _ else _] =>
lazymatch type of a with
| sumbool _ _ =>destruct a as [?H | ?H]
| bool => fail "Use simple_if_tac instead of if_tac, since your expression"a" has type bool"
| ?t => fail "Use if_tac only for sumbool; your expression"a" has type" t
end end.
Tactic Notation "if_tac" simple_intropattern(H) "in" hyp(H1)
:= match type of H1 with context [if ?a then _ else _] =>
lazymatch type of a with
| sumbool _ _ =>destruct a as H
| bool => fail "Use simple_if_tac instead of if_tac, since your expression"a" has type bool"
| ?t => fail "Use if_tac only for sumbool; your expression"a" has type" t
end end.

Lemma sumbool_dec_and: forall A B, {A} + {~A} -> {B} + {~B} -> {A /\ B} + {~(A /\ B)}.