Module CommonTactics
Ltac inv H := 
inversion H; 
clear H; 
subst.
Ltac cases :=
  
repeat match goal with
         | 
H: 
context [ 
match negb ?
x with _ => 
_ end ] |- 
_ =>
           
destruct x; 
simpl; 
try solve [
inv H; 
auto]
         | 
H: 
context [ 
match ?
x with _ => 
_ end ] |- 
_ =>
           
destruct x; 
try solve [
inv H; 
auto]
         | |- 
context [ 
match negb ?
x with _ => 
_ end ] =>
           
destruct x; 
simpl
         | |- 
context [ 
match ?
x with _ => 
_ end ] =>
           
destruct x
         end; 
auto.
Ltac cases_eqn E :=
  
repeat match goal with
         | 
H: 
context [ 
match negb ?
x with _ => 
_ end ] |- 
_ =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
simpl; 
try solve [
inv H; 
auto]
         | 
H: 
context [ 
match ?
x with _ => 
_ end ] |- 
_ =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
try solve [
inv H; 
auto]
         | |- 
context [ 
match negb ?
x with _ => 
_ end ] =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
simpl
         | |- 
context [ 
match ?
x with _ => 
_ end ] =>
           
let E := 
fresh E in
           destruct x eqn: 
E
         end; 
auto.
Ltac cases_in H :=
  
repeat match type of H with
         | 
context [ 
match negb ?
x with _ => 
_ end ] =>
           
destruct x; 
simpl; 
try solve [
inv H; 
auto]
         | 
context [ 
match ?
x with _ => 
_ end ] =>
           
destruct x; 
try solve [
inv H; 
auto]
         
end; 
auto.
Create HintDb conjs.
Ltac destruct_conjs :=
  
autounfold with conjs in *;
  
repeat
    match goal with
    | 
H: 
exists _, 
_ |- 
_ => 
destruct H
    | 
H: 
_ /\ 
_ |- 
_ => 
destruct H
    | 
x: 
_ * 
_ |- 
_ => 
destruct x
    end; 
simpl in *.
Lemma option_map_inv:
  
forall {
A B} (
f: 
A -> 
B) 
oa b,
    
option_map f oa = 
Some b ->
    
exists a, 
oa = 
Some a /\ 
b = 
f a.
Proof.
  unfold option_map; 
intros * 
E.
  
cases; 
inv E; 
eauto.
Qed.
 
Lemma option_map_None:
  
forall {
A B} (
f: 
A -> 
B) 
oa,
    
option_map f oa = 
None <-> 
oa = 
None.
Proof.
  unfold option_map; 
intros; 
cases; 
intuition; 
discriminate.
Qed.
 
Ltac inv_equalities :=
  
destruct_conjs; 
subst;
  
repeat
    match goal with
    | 
H: (
_, 
_) = (
_, 
_) |- 
_ => 
inv H
    | 
H: 
option_map _ _ = 
Some _ |- 
_ =>
        
let Hf := 
fresh "
Hf" 
in
        let Heq := 
fresh "
Heq" 
in
        apply option_map_inv in H as (?&
Hf&
Heq); 
destruct_conjs
    | 
H: 
option_map _ _ = 
None |- 
_ =>
        
apply option_map_None in H
    end; 
subst.
Tactic Notation "
summon" 
uconstr(
ty) "
as" 
ident(
id) :=
  
match goal with H : 
_ |- 
_ => 
pose (
id := 
H : 
ty); 
clear id; 
rename H into id end.
Tactic Notation "
take" 
uconstr(
ty) "
and" 
tactic(
tac) :=
  
let new_it := 
fresh "
it"
  
in try (
rename it into new_it);
     
summon ty as it; 
tac;
     
try (
rename new_it into it).
Tactic Notation "
take" 
uconstr(
ty1) "," 
uconstr(
ty2) "
and" 
tactic(
tac) :=
  
let it1 := 
fresh "
it1" 
in
  let it2 := 
fresh "
it2" 
in
  summon ty1 as it1; 
summon ty2 as it2; 
tac.