diff --git a/tests/tactics.v b/tests/tactics.v index 715e747db6d7b30ac1bbe2d91ac8c18709fcd2c7..34f00ed7bf0dbe51e3eacbe42c9a6daeb85b5fdc 100644 --- a/tests/tactics.v +++ b/tests/tactics.v @@ -55,20 +55,10 @@ Proof. intros ?. rename select nat into m. exists m. done. Qed. Goal ∀ (P : nat → Prop), P 3 → P 4 → P 4. Proof. intros P **. rename select (P _) into HP4. apply HP4. Qed. -(** [mk_evar] works on things that coerce to types. *) -(** This is a feature when we have packed structures, for example Iris's [ofe] -(fields other than the carrier omitted). *) -Structure ofe := Ofe { ofe_car :> Type }. -Goal ∀ A : ofe, True. -intros A. -let x := mk_evar A in idtac. -Abort. - -(** More surprisingly, it also works for other coercions into a -universe, like [Is_true : bool → Prop]. *) -Goal True. -let x := mk_evar true in idtac. -Abort. +(** Regression tests for [naive_solver]. *) +Lemma naive_solver_issue_115 (P : nat → Prop) (x : nat) : + (∀ x', P x' → x' = 10) → P x → x + 1 = 11. +Proof. naive_solver. Qed. (** Make sure that [done] is not called recursively when solving [is_Some], which might leave an unresolved evar before performing ex falso. *) diff --git a/theories/tactics.v b/theories/tactics.v index d3910a89c7e524253793f239617aa8d8015b64d7..ba96fdedfd3592d591e0c930ecab2db71d1cb304 100644 --- a/theories/tactics.v +++ b/theories/tactics.v @@ -222,8 +222,20 @@ current context. This is usually a more useful behavior than Coq's [evar], which is a side-effecting tactic (not returning anything) that introduces a local -definition into the context that holds the evar. *) -Ltac mk_evar T := open_constr:(_ : T). +definition into the context that holds the evar. +Note that the obvious alternative [open_constr (_:T)] has subtly different +behavior, see std++ issue 115. + +Usually, Ltacs cannot return a value and have a side-effect, but we use the +trickd escribed at +<https://stackoverflow.com/questions/45949064/check-for-evars-in-a-tactic-that-returns-a-value/46178884#46178884> +to work around that: wrap the side-effect in a [match goal]. *) +Ltac mk_evar T := + let e := fresh in + let _ := match goal with _ => evar (e:T) end in + let e' := eval unfold e in e in + let _ := match goal with _ => clear e end in + e'. (** The tactic [eunify x y] succeeds if [x] and [y] can be unified, and fails otherwise. If it succeeds, it will instantiate necessary evars in [x] and [y].