Module Type Test.
Variable P : nat -> Prop.
Variable L : forall (l : nat), P l -> P l.
Goal P 0 -> True.
intros.
specialize L with (1:=H).
Abort.
End Test.
(* Two examples that show that hnf_constr is used when unifying types of bindings (a simplification of a script from Field_Theory) *)
Open Scope list_scope.
Fixpoint P (l : list nat) : Prop :=
match l with
| nil => True
| e1 :: nil => e1 = e1
| e1 :: l1 => e1 = e1 /\ P l1
end.
Variable L : forall n l, P (n::l) -> P l.
Goal forall (x:nat) l, P (x::l) -> P l.
intros.
apply L with (1:=H).
Qed.
Goal forall (x:nat) l, match l with nil => x=x | _::_ => x=x /\ P l end -> P l.
intros.
apply L with (1:=H).
Qed.
(* The following call to auto fails if the type of the clause associated to the H is not beta-reduced [but apply H works] (a simplification of a script from FSetAVL) *)
Definition apply (f:nat->Prop) := forall x, f x.
Goal apply (fun n => n=0) -> 1=0.
intro H.
auto.
Qed.
(* The following fails if the coercion Zpos is not introduced around p before trying a subterm that matches the left-hand-side of the equality (a simplication of an example taken from Nijmegen/QArith) *)
Coercion Zpos : positive >-> Z.
Variable f : Z -> Z -> Z.
Variable g : forall q1 q2 p : Z, f (f q1 p) (f q2 p) = Z0.
Goal forall p q1 q2, f (f q1 (Zpos p)) (f q2 (Zpos p)) = Z0.
intros; rewrite g with (p:=p).
reflexivity.
Qed.
(* A funny example where the behavior differs depending on which of a multiple solution to a unification problem is chosen (an instance of this case can be found in the proof of Buchberger.BuchRed.nf_divp) *)
Definition succ x := S x.
Goal forall (I : nat -> Set) (P : nat -> Prop) (Q : forall n:nat, I n -> Prop),
(forall x y, P x -> Q x y) ->
(forall x, P (S x)) -> forall y: I (S 0), Q (succ 0) y.
intros.
apply H with (y:=y).
(* [x] had two possible instances: [S 0], coming from unifying the type of [y] with [I ?n] and [succ 0] coming from the unification with the goal; only the first one allows the next apply (which does not work modulo delta) work *)
apply H0.
Qed.
(* A similar example with a arbitrary long conversion between the two possible instances *)
Fixpoint compute_succ x :=
match x with O => S 0 | S n => S (compute_succ n) end.
Goal forall (I : nat -> Set) (P : nat -> Prop) (Q : forall n:nat, I n -> Prop),
(forall x y, P x -> Q x y) ->
(forall x, P (S x)) -> forall y: I (S 100), Q (compute_succ 100) y.
intros.
apply H with (y:=y).
apply H0.
Qed.
(* Another example with multiple convertible solutions to the same metavariable (extracted from Algebra.Hom_module.Hom_module, 10th subgoal which precisely fails) *)
Definition ID (A:Type) := A.
Goal forall f:Type -> Type,
forall (P : forall A:Type, A -> Prop),
(forall (B:Type) x, P (f B) x -> P (f B) x) ->
(forall (A:Type) x, P (f (f A)) x) ->
forall (A:Type) (x:f (f A)), P (f (ID (f A))) x.
intros.
apply H.
(* The parameter [B] had two possible instances: [ID (f A)] by direct unification and [f A] by unification of the type of [x]; only the first choice makes the next command fail, as it was (unfortunately?) in Hom_module *)
try apply H.
unfold ID; apply H0.
Qed.
(* Test hyp in "apply -> ... in hyp" is correctly instantiated by Ltac *)
Goal (True <-> False) -> True -> False.
intros Heq H.
match goal with [ H : True |- _ ] => apply -> Heq in H end.
Abort.
(* Test coercion below product and on non meta-free terms in with bindings *)
(* Cf wishes #1408 from E. Makarov *)
Parameter bool_Prop :> bool -> Prop.
Parameter r : bool -> bool -> bool.
apply ax with (R := r).
Qed.
(* Check verification of type at unification (submitted by Stéphane Lengrand): without verification, the first "apply" works what leads to the incorrect instantiation of x by Prop *)
unfold not.
intro.
eapply H.
apply (forall B:Prop,B->B) || (instantiate (1:=True); exact I).
Defined.
(* Fine-tuning coercion insertion in presence of unfolding (bug #1883) *)
Parameter name : Set.
Definition atom := name.
Inductive exp : Set :=
| var : atom -> exp.
Coercion var : atom >-> exp.
intros x.
apply silly_axiom with (v := x).  (* fails *)
reflexivity.
Qed.
(* Check that unification does not commit too early to a representative of an eta-equivalence class that would be incompatible with other unification constraints *)
intros.
apply H.
Qed.
(* Test propagation of evars from subgoal to brother subgoals *)
(* This works because unfold calls clos_norm_flags which calls nf_evar *)
intros x H; eapply eq_trans;
[apply H | unfold x;match goal with |- ?x = ?x => reflexivity end].
Qed.
(* Test non-regression of (temporary) bug 1981 *)
Goal exists n : nat, True.
eapply ex_intro.
exact O.
trivial.
Qed.
(* Check pattern-unification on evars in apply unification *)
(* Check that "as" clause applies to main premise only and leave the side conditions away *)
(* Check that "apply" is chained on the last subgoal of each lemma and that side conditions come first (as it is the case since 8.2) *)

Lemma chaining :
forall A B C : Prop,
(1=1 -> (2=2 -> A -> B) /\ True) ->
(3=3 -> (True /\ (4=4 -> C -> A))) -> C -> B.