feat(library/tactic): produce better error message when a tactic fails

closes #348
This commit is contained in:
Leonardo de Moura 2015-02-16 16:56:42 -08:00
parent 3a67ddb7c5
commit 7fc216183e
25 changed files with 315 additions and 38 deletions

View file

@ -1480,14 +1480,30 @@ optional<tactic> elaborator::pre_tactic_to_tactic(expr const & pre_tac) {
} }
} }
void elaborator::display_tactic_exception(tactic_exception const & ex, proof_state const & ps, expr const & pre_tac) {
auto out = regular(env(), ios());
flycheck_error err(out);
if (optional<expr> const & e = ex.get_main_expr())
display_error_pos(out, pip(), *e);
else
display_error_pos(out, pip(), pre_tac);
out << ex.pp(out.get_formatter()) << "\nproof state:\n";
if (auto curr_ps = ex.get_proof_state())
out << curr_ps->pp(env(), ios()) << "\n";
else
out << ps.pp(env(), ios()) << "\n";
}
/** \brief Try to instantiate meta-variable \c mvar (modulo its state ps) using the given tactic. /** \brief Try to instantiate meta-variable \c mvar (modulo its state ps) using the given tactic.
If it succeeds, then update subst with the solution. If it succeeds, then update subst with the solution.
Return true iff the metavariable \c mvar has been assigned. Return true iff the metavariable \c mvar has been assigned.
If \c show_failure == true, then display reason for failure. If \c show_failure == true, then display reason for failure.
\remark the argument \c pre_tac is only used for error localization.
*/ */
bool elaborator::try_using(substitution & subst, expr const & mvar, proof_state const & ps, tactic const & tac, bool elaborator::try_using(substitution & subst, expr const & mvar, proof_state const & ps,
bool show_failure) { expr const & pre_tac, tactic const & tac, bool show_failure) {
lean_assert(length(ps.get_goals()) == 1); lean_assert(length(ps.get_goals()) == 1);
// make sure ps is a really a proof state for mvar. // make sure ps is a really a proof state for mvar.
lean_assert(mlocal_name(get_app_fn(head(ps.get_goals()).get_meta())) == mlocal_name(mvar)); lean_assert(mlocal_name(get_app_fn(head(ps.get_goals()).get_meta())) == mlocal_name(mvar));
@ -1511,11 +1527,8 @@ bool elaborator::try_using(substitution & subst, expr const & mvar, proof_state
return true; return true;
} }
} catch (tactic_exception & ex) { } catch (tactic_exception & ex) {
if (show_failure) { if (show_failure)
auto out = regular(env(), ios()); display_tactic_exception(ex, ps, pre_tac);
display_error_pos(out, pip(), ex.get_expr());
out << " tactic failed: " << ex.what() << "\n";
}
return false; return false;
} }
} }
@ -1562,9 +1575,7 @@ void elaborator::try_using_begin_end(substitution & subst, expr const & mvar, pr
} }
ps = r->first; ps = r->first;
} catch (tactic_exception & ex) { } catch (tactic_exception & ex) {
auto out = regular(env(), ios()); display_tactic_exception(ex, ps, ptac);
display_error_pos(out, pip(), ex.get_expr());
out << " tactic failed: " << ex.what() << "\n";
return; return;
} }
} else { } else {
@ -1603,7 +1614,7 @@ void elaborator::solve_unassigned_mvar(substitution & subst, expr mvar, name_set
if (auto tac = pre_tactic_to_tactic(subst.instantiate_all(*pre_tac))) { if (auto tac = pre_tactic_to_tactic(subst.instantiate_all(*pre_tac))) {
bool show_failure = true; bool show_failure = true;
try_using(subst, mvar, ps, *tac, show_failure); try_using(subst, mvar, ps, *pre_tac, *tac, show_failure);
return; return;
} }
} }
@ -1613,7 +1624,7 @@ void elaborator::solve_unassigned_mvar(substitution & subst, expr mvar, name_set
for (expr const & pre_tac : get_tactic_hints(env())) { for (expr const & pre_tac : get_tactic_hints(env())) {
if (auto tac = pre_tactic_to_tactic(pre_tac)) { if (auto tac = pre_tactic_to_tactic(pre_tac)) {
bool show_failure = false; bool show_failure = false;
if (try_using(subst, mvar, ps, *tac, show_failure)) if (try_using(subst, mvar, ps, pre_tac, *tac, show_failure))
return; return;
} }
} }

View file

@ -145,10 +145,11 @@ class elaborator : public coercion_info_manager {
unify_result_seq solve(constraint_seq const & cs); unify_result_seq solve(constraint_seq const & cs);
void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg, expr const & pos); void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg, expr const & pos);
void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg); void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg);
void display_tactic_exception(tactic_exception const & ex, proof_state const & ps, expr const & pre_tac);
optional<expr> get_pre_tactic_for(expr const & mvar); optional<expr> get_pre_tactic_for(expr const & mvar);
optional<tactic> pre_tactic_to_tactic(expr const & pre_tac); optional<tactic> pre_tactic_to_tactic(expr const & pre_tac);
bool try_using(substitution & subst, expr const & mvar, proof_state const & ps, tactic const & tac, bool try_using(substitution & subst, expr const & mvar, proof_state const & ps,
bool show_failure); expr const & pre_tac, tactic const & tac, bool show_failure);
void try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac); void try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac);
void solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited); void solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited);
expr solve_unassigned_mvars(substitution & subst, expr e, name_set & visited); expr solve_unassigned_mvars(substitution & subst, expr e, name_set & visited);

View file

@ -13,6 +13,7 @@ Author: Leonardo de Moura
#include "kernel/replace_fn.h" #include "kernel/replace_fn.h"
#include "kernel/instantiate.h" #include "kernel/instantiate.h"
#include "kernel/abstract.h" #include "kernel/abstract.h"
#include "kernel/error_msgs.h"
#include "kernel/type_checker.h" #include "kernel/type_checker.h"
#include "library/reducible.h" #include "library/reducible.h"
#include "library/kernel_bindings.h" #include "library/kernel_bindings.h"
@ -72,8 +73,10 @@ static proof_state_seq apply_tactic_core(environment const & env, io_state const
expr const & _e, buffer<constraint> & cs, expr const & _e, buffer<constraint> & cs,
bool add_meta, subgoals_action_kind subgoals_action) { bool add_meta, subgoals_action_kind subgoals_action) {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return proof_state_seq(); return proof_state_seq();
}
bool class_inst = get_apply_class_instance(ios.get_options()); bool class_inst = get_apply_class_instance(ios.get_options());
name_generator ngen = s.get_ngen(); name_generator ngen = s.get_ngen();
bool relax_opaque = s.relax_main_opaque(); bool relax_opaque = s.relax_main_opaque();
@ -124,8 +127,16 @@ static proof_state_seq apply_tactic_core(environment const & env, io_state const
metavar_closure cls(t); metavar_closure cls(t);
cls.mk_constraints(s.get_subst(), justification(), relax_opaque); cls.mk_constraints(s.get_subst(), justification(), relax_opaque);
pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t); pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t);
if (!dcs.first) if (!dcs.first) {
throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) {
format r = format("invalid 'apply' tactic, failed to unify");
r += pp_indent_expr(fmt, t);
r += compose(line(), format("with"));
r += pp_indent_expr(fmt, e_t);
return r;
});
return proof_state_seq(); return proof_state_seq();
}
dcs.second.linearize(cs); dcs.second.linearize(cs);
unify_result_seq rseq = unify(env, cs.size(), cs.data(), ngen.mk_child(), s.get_subst(), cfg); unify_result_seq rseq = unify(env, cs.size(), cs.data(), ngen.mk_child(), s.get_subst(), cfg);
list<expr> meta_lst = to_list(metas.begin(), metas.end()); list<expr> meta_lst = to_list(metas.begin(), metas.end());
@ -172,14 +183,17 @@ static proof_state_seq apply_tactic_core(environment const & env, io_state const
tactic eassumption_tactic() { tactic eassumption_tactic() {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return proof_state_seq(); return proof_state_seq();
}
proof_state new_s = s.update_report_failure(false);
proof_state_seq r; proof_state_seq r;
goal g = head(gs); goal g = head(gs);
buffer<expr> hs; buffer<expr> hs;
get_app_args(g.get_meta(), hs); get_app_args(g.get_meta(), hs);
for (expr const & h : hs) { for (expr const & h : hs) {
r = append(r, apply_tactic_core(env, ios, s, h, false, IgnoreSubgoals)); r = append(r, apply_tactic_core(env, ios, new_s, h, false, IgnoreSubgoals));
} }
return r; return r;
}); });
@ -188,8 +202,10 @@ tactic eassumption_tactic() {
tactic apply_tactic_core(elaborate_fn const & elab, expr const & e, subgoals_action_kind k) { tactic apply_tactic_core(elaborate_fn const & elab, expr const & e, subgoals_action_kind k) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return proof_state_seq(); return proof_state_seq();
}
goal const & g = head(gs); goal const & g = head(gs);
name_generator ngen = s.get_ngen(); name_generator ngen = s.get_ngen();
expr new_e; expr new_e;

View file

@ -15,13 +15,17 @@ tactic assert_tactic(elaborate_fn const & elab, name const & id, expr const & e)
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
proof_state new_s = s; proof_state new_s = s;
goals const & gs = new_s.get_goals(); goals const & gs = new_s.get_goals();
if (!gs) if (!gs) {
throw_no_goal_if_enabled(s);
return none_proof_state(); return none_proof_state();
}
bool report_unassigned = true; bool report_unassigned = true;
if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(), report_unassigned)) { if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(), report_unassigned)) {
goals const & gs = new_s.get_goals(); goals const & gs = new_s.get_goals();
goal const & g = head(gs); goal const & g = head(gs);
if (g.find_hyp(id)) { if (g.find_hyp(id)) {
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'assert' tactic, goal already has a "
"hypothesis named '" << id << "'");
// goal already has a hypothesis named id // goal already has a hypothesis named id
return none_proof_state(); return none_proof_state();
} }

View file

@ -15,8 +15,10 @@ tactic exact_tactic(elaborate_fn const & elab, expr const & e) {
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
proof_state new_s = s; proof_state new_s = s;
goals const & gs = new_s.get_goals(); goals const & gs = new_s.get_goals();
if (!gs) if (!gs) {
throw_no_goal_if_enabled(s);
return none_proof_state(); return none_proof_state();
}
expr t = head(gs).get_type(); expr t = head(gs).get_type();
bool report_unassigned = true; bool report_unassigned = true;
if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, some_expr(t), report_unassigned)) { if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, some_expr(t), report_unassigned)) {

View file

@ -65,10 +65,12 @@ expr const & get_repeat_tac_fn();
expr const & get_determ_tac_fn(); expr const & get_determ_tac_fn();
/** \brief Exception used to report a problem when an expression is being converted into a tactic. */ /** \brief Exception used to report a problem when an expression is being converted into a tactic. */
class expr_to_tactic_exception : public tactic_exception { class expr_to_tactic_exception : public exception {
expr m_expr;
public: public:
expr_to_tactic_exception(expr const & e, char const * msg):tactic_exception(e, msg) {} expr_to_tactic_exception(expr const & e, char const * msg):exception(msg), m_expr(e) {}
expr_to_tactic_exception(expr const & e, sstream const & strm):tactic_exception(e, strm) {} expr_to_tactic_exception(expr const & e, sstream const & strm):exception(strm), m_expr(e) {}
expr const & get_expr() const { return m_expr; }
}; };
typedef std::function<tactic(type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *)> typedef std::function<tactic(type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *)>

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/ */
#include "library/constants.h" #include "library/constants.h"
#include "kernel/abstract.h" #include "kernel/abstract.h"
#include "kernel/kernel_exception.h"
#include "library/reducible.h" #include "library/reducible.h"
#include "library/tactic/elaborate.h" #include "library/tactic/elaborate.h"
#include "library/tactic/expr_to_tactic.h" #include "library/tactic/expr_to_tactic.h"
@ -21,8 +22,11 @@ tactic generalize_tactic(elaborate_fn const & elab, expr const & e, name const &
goal const & g = head(gs); goal const & g = head(gs);
auto tc = mk_type_checker(env, ngen.mk_child()); auto tc = mk_type_checker(env, ngen.mk_child());
auto e_t_cs = tc->infer(*new_e); auto e_t_cs = tc->infer(*new_e);
if (e_t_cs.second) if (e_t_cs.second) {
throw_tactic_exception_if_enabled(s, "invalid 'generalize' tactic, unification constraints "
"have been generated when inferring type");
return none_proof_state(); // constraints were generated return none_proof_state(); // constraints were generated
}
expr e_t = e_t_cs.first; expr e_t = e_t_cs.first;
expr t = subst.instantiate(g.get_type()); expr t = subst.instantiate(g.get_type());
name n; name n;
@ -37,7 +41,14 @@ tactic generalize_tactic(elaborate_fn const & elab, expr const & e, name const &
expr new_v = g.abstract(mk_app(new_m, *new_e)); expr new_v = g.abstract(mk_app(new_m, *new_e));
try { try {
tc->check_ignore_levels(g.abstract(new_t)); tc->check_ignore_levels(g.abstract(new_t));
} catch (exception &) { } catch (kernel_exception const & ex) {
std::shared_ptr<kernel_exception> ex_ptr(static_cast<kernel_exception*>(ex.clone()));
throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) {
format r = format("invalid 'generalize' tactic, type error");
r += line();
r += ex_ptr->pp(fmt);
return r;
});
return none_proof_state(); return none_proof_state();
} }

View file

@ -15,8 +15,10 @@ tactic intros_tactic(list<name> _ns, bool relax_main_opaque) {
auto fn = [=](environment const & env, io_state const &, proof_state const & s) { auto fn = [=](environment const & env, io_state const &, proof_state const & s) {
list<name> ns = _ns; list<name> ns = _ns;
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return optional<proof_state>(); return optional<proof_state>();
}
goal const & g = head(gs); goal const & g = head(gs);
name_generator ngen = s.get_ngen(); name_generator ngen = s.get_ngen();
auto tc = mk_type_checker(env, ngen.mk_child(), relax_main_opaque); auto tc = mk_type_checker(env, ngen.mk_child(), relax_main_opaque);

View file

@ -13,8 +13,10 @@ namespace lean {
tactic rename_tactic(name const & from, name const & to) { tactic rename_tactic(name const & from, name const & to) {
return tactic01([=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> { return tactic01([=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return none_proof_state(); return none_proof_state();
}
goal const & g = head(gs); goal const & g = head(gs);
goals const & rest_gs = tail(gs); goals const & rest_gs = tail(gs);
buffer<expr> locals; buffer<expr> locals;

View file

@ -14,8 +14,10 @@ namespace lean {
tactic revert_tactic(name const & n) { tactic revert_tactic(name const & n) {
auto fn = [=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> { auto fn = [=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return none_proof_state(); return none_proof_state();
}
goal g = head(gs); goal g = head(gs);
goals tail_gs = tail(gs); goals tail_gs = tail(gs);
if (auto p = g.find_hyp(n)) { if (auto p = g.find_hyp(n)) {
@ -24,8 +26,11 @@ tactic revert_tactic(name const & n) {
buffer<expr> hyps; buffer<expr> hyps;
g.get_hyps(hyps); g.get_hyps(hyps);
hyps.erase(hyps.size() - i - 1); hyps.erase(hyps.size() - i - 1);
if (depends_on(i, hyps.end() - i, h)) if (optional<expr> other_h = depends_on(i, hyps.end() - i, h)) {
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'revert' tactic, hypothesis '" << local_pp_name(*other_h)
<< "' depends on '" << local_pp_name(h) << "'");
return none_proof_state(); // other hypotheses depend on h return none_proof_state(); // other hypotheses depend on h
}
name_generator ngen = s.get_ngen(); name_generator ngen = s.get_ngen();
expr new_type = Pi(h, g.get_type()); expr new_type = Pi(h, g.get_type());
expr new_meta = mk_app(mk_metavar(ngen.next(), Pi(hyps, new_type)), hyps); expr new_meta = mk_app(mk_metavar(ngen.next(), Pi(hyps, new_type)), hyps);
@ -36,6 +41,7 @@ tactic revert_tactic(name const & n) {
proof_state new_s(s, goals(new_g, tail_gs), new_subst, ngen); proof_state new_s(s, goals(new_g, tail_gs), new_subst, ngen);
return some_proof_state(new_s); return some_proof_state(new_s);
} else { } else {
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'revert' tactic, unknown hypothesis '" << n << "'");
return none_proof_state(); return none_proof_state();
} }
}; };

View file

@ -1161,6 +1161,11 @@ public:
for (expr const & elem : elems) { for (expr const & elem : elems) {
flet<expr> set1(m_expr_loc, elem); flet<expr> set1(m_expr_loc, elem);
if (!process_step(elem)) { if (!process_step(elem)) {
if (m_ps.report_failure()) {
proof_state curr_ps(m_ps, cons(m_g, tail(m_ps.get_goals())), m_subst, m_ngen);
throw tactic_exception("rewrite step failed", some_expr(elem), curr_ps,
[](formatter const &) { return format("invalid 'rewrite' tactic, rewrite step failed"); });
}
return proof_state_seq(); return proof_state_seq();
} }
} }
@ -1178,8 +1183,10 @@ public:
tactic mk_rewrite_tactic(elaborate_fn const & elab, buffer<expr> const & elems) { tactic mk_rewrite_tactic(elaborate_fn const & elab, buffer<expr> const & elems) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
goals const & gs = s.get_goals(); goals const & gs = s.get_goals();
if (empty(gs)) if (empty(gs)) {
throw_no_goal_if_enabled(s);
return proof_state_seq(); return proof_state_seq();
}
return rewrite_fn(env, ios, elab, s)(elems); return rewrite_fn(env, ios, elab, s)(elems);
}); });
} }

View file

@ -34,8 +34,24 @@ void check_has_no_local(expr const & v, expr const & e, char const * tac_name) {
} }
} }
tactic_exception::tactic_exception(expr const & e, char const * msg):exception(msg), m_expr(e) {} tactic_exception::tactic_exception(char const * msg, optional<expr> const & m, pp_fn const & fn):
tactic_exception::tactic_exception(expr const & e, sstream const & strm):exception(strm), m_expr(e) {} generic_exception(msg, m, fn) {}
tactic_exception::tactic_exception(char const * msg, optional<expr> const & m, proof_state const & ps, pp_fn const & fn):
generic_exception(msg, m, fn), m_ps(ps) {}
tactic_exception::tactic_exception(expr const & e, std::string const & msg):
generic_exception(msg.c_str(), some_expr(e), [=](formatter const &) { return format(msg); }) {}
tactic_exception::tactic_exception(std::string const & msg):
generic_exception(msg.c_str(), none_expr(), [=](formatter const &) { return format(msg); }) {}
tactic_exception::tactic_exception(char const * msg):tactic_exception(std::string(msg)) {}
tactic_exception::tactic_exception(sstream const & strm):tactic_exception(strm.str()) {}
tactic_exception::tactic_exception(expr const & e, char const * msg):tactic_exception(e, std::string(msg)) {}
tactic_exception::tactic_exception(expr const & e, sstream const & strm):tactic_exception(e, strm.str()) {}
tactic_exception::tactic_exception(expr const & e, pp_fn const & fn):generic_exception("tactic exception", some_expr(e), fn) {}
tactic_exception::tactic_exception(pp_fn const & fn):generic_exception("tactic exception", none_expr(), fn) {}
void throw_no_goal_if_enabled(proof_state const & ps) {
throw_tactic_exception_if_enabled(ps, "invalid tactic, there are no goals to be solved");
}
tactic tactic01(std::function<optional<proof_state>(environment const &, io_state const & ios, proof_state const &)> f) { tactic tactic01(std::function<optional<proof_state>(environment const &, io_state const & ios, proof_state const &)> f) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {

View file

@ -11,20 +11,32 @@ Author: Leonardo de Moura
#include <string> #include <string>
#include "util/lazy_list.h" #include "util/lazy_list.h"
#include "library/io_state.h" #include "library/io_state.h"
#include "library/generic_exception.h"
#include "library/tactic/proof_state.h" #include "library/tactic/proof_state.h"
namespace lean { namespace lean {
/** \brief Throw an exception is \c v contains local constants, \c e is only used for position information. */ /** \brief Throw an exception is \c v contains local constants, \c e is only used for position information. */
void check_has_no_local(expr const & v, expr const & e, char const * tac_name); void check_has_no_local(expr const & v, expr const & e, char const * tac_name);
class tactic_exception : public exception { class tactic_exception : public generic_exception {
expr m_expr; optional<proof_state> m_ps;
public: public:
tactic_exception(char const * msg, optional<expr> const & m, pp_fn const & fn);
tactic_exception(char const * msg, optional<expr> const & m, proof_state const & ps, pp_fn const & fn);
tactic_exception(expr const & e, std::string const & msg);
tactic_exception(expr const & e, char const * msg); tactic_exception(expr const & e, char const * msg);
tactic_exception(expr const & e, sstream const & strm); tactic_exception(expr const & e, sstream const & strm);
expr const & get_expr() const { return m_expr; } tactic_exception(expr const & e, pp_fn const & fn);
tactic_exception(std::string const & msg);
tactic_exception(char const * msg);
tactic_exception(sstream const & strm);
tactic_exception(pp_fn const & fn);
optional<proof_state> const & get_proof_state() const { return m_ps; }
}; };
#define throw_tactic_exception_if_enabled(ps, msg) if (ps.report_failure()) throw tactic_exception(msg);
void throw_no_goal_if_enabled(proof_state const & ps);
typedef lazy_list<proof_state> proof_state_seq; typedef lazy_list<proof_state> proof_state_seq;
typedef std::function<proof_state_seq(environment const &, io_state const &, proof_state const &)> tactic; typedef std::function<proof_state_seq(environment const &, io_state const &, proof_state const &)> tactic;

View file

@ -0,0 +1,4 @@
example (a b : Prop) : a ∧ b :=
begin
apply or.inr
end

View file

@ -0,0 +1,13 @@
apply_fail.lean:3:2: error:invalid 'apply' tactic, failed to unify
a ∧ b
with
?M_1 ?M_2
proof state:
a b : Prop
⊢ a ∧ b
apply_fail.lean:4:0: error: don't know how to synthesize placeholder
a b : Prop
⊢ a ∧ b
apply_fail.lean:4:0: error: failed to add declaration '14.0' to environment, value has metavariables
λ (a b : Prop),
?M_1

View file

@ -0,0 +1,10 @@
example (a b : Prop) (H : b ∧ a) : a ∧ b :=
begin
assert (H : a)
end
example (a : Prop) (Ha : a) : a :=
begin
exact Ha,
assert (H : a)
end

View file

@ -0,0 +1,22 @@
assert_fail.lean:3:2: error:invalid 'assert' tactic, goal already has a hypothesis named 'H'
proof state:
a b : Prop,
H : b ∧ a
⊢ a ∧ b
assert_fail.lean:4:0: error: don't know how to synthesize placeholder
a b : Prop,
H : b ∧ a
⊢ a ∧ b
assert_fail.lean:4:0: error: failed to add declaration '14.0' to environment, value has metavariables
λ (a b : Prop) (H : b ∧ a),
?M_1
assert_fail.lean:9:2: error:invalid tactic, there are no goals to be solved
proof state:
no goals
assert_fail.lean:10:0: error: don't know how to synthesize placeholder
a : Prop,
Ha : a
⊢ a
assert_fail.lean:10:0: error: failed to add declaration '14.1' to environment, value has metavariables
λ (a : Prop) (Ha : a),
?M_1

View file

@ -1,4 +1,8 @@
beginend_bug.lean:7:2: error: tactic failed beginend_bug.lean:7:2: error:invalid 'apply' tactic, failed to unify
a = ?M_1
with
b = c
proof state:
A : Type, A : Type,
a b c : A, a b c : A,
Hab : a = b, Hab : a = b,
@ -10,6 +14,12 @@ a b c : A,
Hab : a = b, Hab : a = b,
Hbc : b = c Hbc : b = c
⊢ ?M_1 = c ⊢ ?M_1 = c
beginend_bug.lean:9:0: error: don't know how to synthesize placeholder
A : Type,
a b c : A,
Hab : a = b,
Hbc : b = c
⊢ a = c
beginend_bug.lean:9:0: error: failed to add declaration 'foo' to environment, value has metavariables beginend_bug.lean:9:0: error: failed to add declaration 'foo' to environment, value has metavariables
λ (A : Type) (a b c : A) (Hab : a = b) (Hbc : b = c), λ (A : Type) (a b c : A) (Hab : a = b) (Hbc : b = c),
?M_1 ?M_1

View file

@ -1,9 +1,23 @@
gen_bug.lean:9:2: error: tactic failed gen_bug.lean:9:2: error:invalid 'generalize' tactic, type error
type mismatch at application
@heq B b
term
b
has type
B_1
but is expected to have type
B
proof state:
A B : Type, A B : Type,
a : A, a : A,
b : B, b : B,
H : @heq A a B b H : @heq A a B b
⊢ @heq B b A a ⊢ @heq B b A a
gen_bug.lean:12:0: error: don't know how to synthesize placeholder
A B : Type,
a : A,
b : B
⊢ @heq A a B b → @heq B b A a
gen_bug.lean:12:0: error: failed to add declaration 'tst' to environment, value has metavariables gen_bug.lean:12:0: error: failed to add declaration 'tst' to environment, value has metavariables
λ (A B : Type) (a : A) (b : B), λ (A B : Type) (a : A) (b : B),
?M_1 ?M_1

7
tests/lean/gen_fail.lean Normal file
View file

@ -0,0 +1,7 @@
import data.vector
open nat
theorem tst (n : nat) (v : vector nat n) : v = v :=
begin
generalize n,
end

View file

@ -0,0 +1,20 @@
gen_fail.lean:6:2: error:invalid 'generalize' tactic, type error
type mismatch at application
eq v
term
v
has type
vector n_1
but is expected to have type
vector n
proof state:
n : ,
v : vector n
⊢ v = v
gen_fail.lean:7:0: error: don't know how to synthesize placeholder
n : ,
v : vector n
⊢ v = v
gen_fail.lean:7:0: error: failed to add declaration 'tst' to environment, value has metavariables
λ (n : ) (v : vector n),
?M_1

View file

@ -0,0 +1,17 @@
import data.vector
example (A : Type) (n : nat) (v : vector A n) : v = v :=
begin
revert n
end
example (n : nat) : n = n :=
begin
esimp,
revert n
end
example (n : nat) : n = n :=
begin
revert m
end

View file

@ -0,0 +1,33 @@
revert_fail.lean:5:2: error:invalid 'revert' tactic, hypothesis 'v' depends on 'n'
proof state:
A : Type,
n : nat,
v : vector A n
⊢ v = v
revert_fail.lean:6:0: error: don't know how to synthesize placeholder
A : Type,
n : nat,
v : vector A n
⊢ v = v
revert_fail.lean:6:0: error: failed to add declaration '14.0' to environment, value has metavariables
λ (A : Type) (n : nat) (v : vector A n),
?M_1
revert_fail.lean:11:2: error:invalid tactic, there are no goals to be solved
proof state:
no goals
revert_fail.lean:12:0: error: don't know how to synthesize placeholder
n : nat
⊢ n = n
revert_fail.lean:12:0: error: failed to add declaration '14.1' to environment, value has metavariables
λ (n : nat),
?M_1
revert_fail.lean:16:2: error:invalid 'revert' tactic, unknown hypothesis 'm'
proof state:
n : nat
⊢ n = n
revert_fail.lean:17:0: error: don't know how to synthesize placeholder
n : nat
⊢ n = n
revert_fail.lean:17:0: error: failed to add declaration '14.2' to environment, value has metavariables
λ (n : nat),
?M_1

View file

@ -0,0 +1,12 @@
open nat
example (a b : nat) (Ha : a = 0) (Hb : b = 0) : a + b = 0 :=
begin
rewrite [Ha, Ha]
end
example (a : nat) : a = a :=
begin
esimp,
esimp
end

View file

@ -0,0 +1,23 @@
rewrite_fail.lean:5:15: error:invalid 'rewrite' tactic, rewrite step failed
proof state:
a b : ,
Ha : a = 0,
Hb : b = 0
⊢ 0 + b = 0
rewrite_fail.lean:6:0: error: don't know how to synthesize placeholder
a b : ,
Ha : a = 0,
Hb : b = 0
⊢ a + b = 0
rewrite_fail.lean:6:0: error: failed to add declaration '14.0' to environment, value has metavariables
λ (a b : ) (Ha : a = 0) (Hb : b = 0),
?M_1
rewrite_fail.lean:11:2: error:invalid tactic, there are no goals to be solved
proof state:
no goals
rewrite_fail.lean:12:0: error: don't know how to synthesize placeholder
a :
⊢ a = a
rewrite_fail.lean:12:0: error: failed to add declaration '14.1' to environment, value has metavariables
λ (a : ),
?M_1