(* ********************************************************************* *)
  (** ** The [solve_uniq] tactic *)

  (** This tactic attempts to solve goals about [uniq].  Given its
      definition, it's likely to work only when the hypotheses in the
      goal already contain all the relevant [uniq] propositions.
      Thus, the tactic may not be generally useful.  It is useful,
      however, for proving facts about [uniq] such as the ones below.

      Implementation note: The second [simpl_asnlist] in the definition
      is because of [disjoint_one_{l,r}].  The "[|| fail]" at the end
      is so that in the case of failure, the error message reported to
      the user is not the one from [fsetdec]. *)

  Ltac solve_uniq :=
    try trivial;
    simpl_asnlist in *;
    autorewrite with rewr_uniq in *;
    simpl_asnlist in *;
    intuition (
      auto using uniq_nil, uniq_one_1 ||
      (rewrite -> disjoint_sym; auto) ||
      (unfold disjoint in *; fsetdec))
    || fail.

(* Specifications: *)
Lemma uniq_cons_3 : uniq E -> x `notin` dom E -> uniq ((VarAsn B x a) :: E).
Lemma uniq_insert_mid : uniq (G ++ E) -> x `notin` dom (G ++ E) -> uniq (G ++ (one (VarAsn B x a)) ++ E).
Lemma uniq_remove_mid : uniq (E ++ F ++ G) -> uniq (E ++ G).
Lemma uniq_map_app_l : forall (f1 : A -> A)(f2: B -> B), uniq (F ++ E) -> uniq (map f1 f2 F ++ E).
Lemma fresh_mid_tail : uniq (F ++ (one (VarAsn B x a)) ++ E) -> x `notin` dom E.
Lemma fresh_mid_head : uniq (F ++ (one (VarAsn B x a)) ++ E) -> x `notin` dom F.
Lemma binds_nil : binds x a (@nil (asn A B)) <-> False.
Lemma binds_one_3 : x = y -> a = b -> binds x a (one (VarAsn B y b)).
Lemma binds_one_1 : binds x a (one (VarAsn B y b)) -> x = y.
Lemma binds_one_2 : binds x a (one (VarAsn B y b)) -> a = b.
Lemma binds_one_iff : binds x a (one (VarAsn B y b)) <-> x = y /\ a = b.
Lemma binds_cons_1 : binds x a ((VarAsn B y b) :: E) -> (x = y /\ a = b) \/ binds x a E.
Lemma binds_cons_2 : x = y -> a = b -> binds x a ((VarAsn B y b) :: E).
Lemma binds_cons_3 : binds x a E -> binds x a ((VarAsn B y b) :: E).
Lemma binds_cons_iff : binds x a ((VarAsn B y b) :: E) <-> (x = y /\ a = b) \/ binds x a E.
Lemma binds_app_1 : binds x a E -> binds x a (E ++ F).
Lemma binds_app_2 : binds x a F -> binds x a (E ++ F).
Lemma binds_app_3 : binds x a (E ++ F) -> binds x a E \/ binds x a F.
Lemma binds_app : binds x a (E ++ F) <-> binds x a E \/ binds x a F.
Lemma binds_dom_contradiction: forall (E : list (asn A B)), binds x a E -> x `notin` dom E -> False.
Lemma binds_app_uniq : uniq (E ++ F) -> (binds x a (E ++ F) <-> (binds x a E /\ x `notin` dom F) \/ (binds x a F /\ x `notin` dom E)).