From Coq Require Import Setoid.
Require Import Crypto.Util.FixCoqMistakes.
Require Import Crypto.Util.Tactics.DestructHead.

Local Ltac t :=
  repeat first [ progress destruct_head'_ex
               | progress destruct_head'_and
               | progress intros
               | progress subst
               | assumption
               | progress repeat esplit ].

Lemma ex_and_eq_l_iff {A P x}
  : (exists y : A, y = x /\ P y) <-> P x.
Proof. t. Qed.

Lemma ex_and_eq_r_iff {A P x}
  : (exists y : A, x = y /\ P y) <-> P x.
Proof. t. Qed.

Lemma ex_eq_and_l_iff {A P x}
  : (exists y : A, P y /\ y = x) <-> P x.
Proof. t. Qed.

Lemma ex_eq_and_r_iff {A P x}
  : (exists y : A, P y /\ x = y) <-> P x.
Proof. t. Qed.

Ltac ex_eq_and_step :=
  let rew lem := (rewrite lem || setoid_rewrite lem) in
  let rew_in lem H := (rewrite lem in H || setoid_rewrite lem in H) in
  match goal with
  | [ |- context[exists y, _ = y /\ _] ]
    => rew (@ex_and_eq_r_iff)
  | [ |- context[exists y, y = _ /\ _] ]
    => rew (@ex_and_eq_l_iff)
  | [ |- context[exists y, _ /\ _ = y] ]
    => rew (@ex_eq_and_r_iff)
  | [ |- context[exists y, _ /\ y = _] ]
    => rew (@ex_eq_and_l_iff)
  | [ H : context[exists y, _ = y /\ _] |- _ ]
    => rew_in (@ex_and_eq_r_iff) H
  | [ H : context[exists y, y = _ /\ _] |- _ ]
    => rew_in (@ex_and_eq_l_iff) H
  | [ H : context[exists y, _ /\ _ = y] |- _ ]
    => rew_in (@ex_eq_and_r_iff) H
  | [ H : context[exists y, _ /\ y = _] |- _ ]
    => rew_in (@ex_eq_and_l_iff) H
  end.

Ltac ex_eq_and := repeat ex_eq_and_step.
