diff --git a/src/library/tactic/exact_tactic.cpp b/src/library/tactic/exact_tactic.cpp index 76aa7189a..be9e5a234 100644 --- a/src/library/tactic/exact_tactic.cpp +++ b/src/library/tactic/exact_tactic.cpp @@ -5,14 +5,25 @@ Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include "kernel/type_checker.h" +#include "kernel/for_each_fn.h" #include "kernel/error_msgs.h" #include "library/util.h" #include "library/constants.h" +#include "library/reducible.h" #include "library/tactic/tactic.h" #include "library/tactic/elaborate.h" #include "library/tactic/expr_to_tactic.h" namespace lean { +// Return true iff \c e is of the form (?m l_1 ... l_n), where ?m is a metavariable and l_i's local constants +bool is_meta_placeholder(expr const & e) { + if (!is_meta(e)) + return false; + buffer args; + get_app_args(e, args); + return std::all_of(args.begin(), args.end(), is_local); +} + tactic exact_tactic(elaborate_fn const & elab, expr const & e, bool enforce_type_during_elaboration, bool allow_metavars) { return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) { proof_state new_s = s; @@ -39,7 +50,24 @@ tactic exact_tactic(elaborate_fn const & elab, expr const & e, bool enforce_type } substitution subst = new_s.get_subst(); assign(subst, g, *new_e); - return some(proof_state(new_s, tail(gs), subst)); + if (allow_metavars) { + buffer new_goals; + name_generator ngen = new_s.get_ngen(); + auto tc = mk_type_checker(env, ngen.mk_child(), new_s.relax_main_opaque()); + for_each(*new_e, [&](expr const & m, unsigned) { + if (!has_expr_metavar(m)) + return false; + if (is_meta_placeholder(m)) { + new_goals.push_back(goal(m, tc->infer(m).first)); + return false; + } + return !is_metavar(m) && !is_local(m); + }); + goals new_gs = to_list(new_goals.begin(), new_goals.end(), tail(gs)); + return some(proof_state(new_s, new_gs, subst, ngen)); + } else { + return some(proof_state(new_s, tail(gs), subst)); + } } else { return some_proof_state(new_s); } diff --git a/tests/lean/run/refine1.lean b/tests/lean/run/refine1.lean new file mode 100644 index 000000000..bb4902c72 --- /dev/null +++ b/tests/lean/run/refine1.lean @@ -0,0 +1,6 @@ +example (a b : Prop) : a → b → a ∧ b := +begin + intros [Ha, Hb], + refine (and.intro _ Hb), + exact Ha +end diff --git a/tests/lean/run/refine2.lean b/tests/lean/run/refine2.lean new file mode 100644 index 000000000..169457942 --- /dev/null +++ b/tests/lean/run/refine2.lean @@ -0,0 +1,8 @@ +import logic + +example {A : Type} (f : A → A) (a b : A) : f a = b → f (f a) = f b := +begin + intro fa_eq_b, + refine (congr_arg f _), + exact fa_eq_b +end diff --git a/tests/lean/run/refine3.lean b/tests/lean/run/refine3.lean new file mode 100644 index 000000000..1b64b6e8f --- /dev/null +++ b/tests/lean/run/refine3.lean @@ -0,0 +1,14 @@ +import data.nat.basic +open nat + +theorem zero_left (n : ℕ) : 0 + n = n := +nat.induction_on n + !add_zero + (take m IH, + begin + refine + (calc + 0 + succ m = succ (0 + m) : _ + ... = succ m : IH), + esimp + end)