feat(frontends/lean): use tactics for solving unassigned metavariables
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
1e39a21823
commit
ffa175009b
6 changed files with 96 additions and 28 deletions
|
@ -13,6 +13,7 @@ Author: Leonardo de Moura
|
||||||
#include "kernel/abstract.h"
|
#include "kernel/abstract.h"
|
||||||
#include "kernel/instantiate.h"
|
#include "kernel/instantiate.h"
|
||||||
#include "kernel/type_checker.h"
|
#include "kernel/type_checker.h"
|
||||||
|
#include "kernel/for_each_fn.h"
|
||||||
#include "kernel/kernel_exception.h"
|
#include "kernel/kernel_exception.h"
|
||||||
#include "kernel/error_msgs.h"
|
#include "kernel/error_msgs.h"
|
||||||
#include "kernel/expr_maps.h"
|
#include "kernel/expr_maps.h"
|
||||||
|
@ -21,6 +22,8 @@ Author: Leonardo de Moura
|
||||||
#include "library/choice.h"
|
#include "library/choice.h"
|
||||||
#include "library/explicit.h"
|
#include "library/explicit.h"
|
||||||
#include "library/unifier.h"
|
#include "library/unifier.h"
|
||||||
|
#include "library/tactic/tactic.h"
|
||||||
|
#include "library/error_handling/error_handling.h"
|
||||||
#include "frontends/lean/parameter.h"
|
#include "frontends/lean/parameter.h"
|
||||||
#include "frontends/lean/hint_table.h"
|
#include "frontends/lean/hint_table.h"
|
||||||
|
|
||||||
|
@ -29,16 +32,17 @@ class elaborator {
|
||||||
typedef list<parameter> context;
|
typedef list<parameter> context;
|
||||||
typedef std::vector<constraint> constraints;
|
typedef std::vector<constraint> constraints;
|
||||||
|
|
||||||
environment m_env;
|
environment m_env;
|
||||||
io_state m_ios;
|
io_state m_ios;
|
||||||
unifier_plugin m_plugin;
|
unifier_plugin m_plugin;
|
||||||
name_generator m_ngen;
|
name_generator m_ngen;
|
||||||
hint_table m_hints;
|
hint_table m_hints;
|
||||||
type_checker m_tc;
|
type_checker m_tc;
|
||||||
substitution m_subst;
|
substitution m_subst;
|
||||||
context m_ctx;
|
context m_ctx;
|
||||||
justification m_accumulated; // accumulate justification of eagerly used substitutions
|
pos_info_provider * m_pos_provider;
|
||||||
constraints m_constraints;
|
justification m_accumulated; // accumulate justification of eagerly used substitutions
|
||||||
|
constraints m_constraints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Auxiliary object for creating backtracking points.
|
\brief Auxiliary object for creating backtracking points.
|
||||||
|
@ -112,11 +116,11 @@ class elaborator {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
elaborator(environment const & env, io_state const & ios, name_generator const & ngen,
|
elaborator(environment const & env, io_state const & ios, name_generator const & ngen,
|
||||||
hint_table const & htable, substitution const & s = substitution(), context const & ctx = context()):
|
hint_table const & htable, substitution const & s, context const & ctx, pos_info_provider * pp):
|
||||||
m_env(env), m_ios(ios),
|
m_env(env), m_ios(ios),
|
||||||
m_plugin([](constraint const &, name_generator const &) { return lazy_list<list<constraint>>(); }),
|
m_plugin([](constraint const &, name_generator const &) { return lazy_list<list<constraint>>(); }),
|
||||||
m_ngen(ngen), m_hints(htable), m_tc(env, m_ngen.mk_child(), mk_default_converter(m_env, optional<module_idx>(0))),
|
m_ngen(ngen), m_hints(htable), m_tc(env, m_ngen.mk_child(), mk_default_converter(m_env, optional<module_idx>(0))),
|
||||||
m_subst(s), m_ctx(ctx) {
|
m_subst(s), m_ctx(ctx), m_pos_provider(pp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr mk_local(name const & n, expr const & t) {
|
expr mk_local(name const & n, expr const & t) {
|
||||||
|
@ -579,12 +583,64 @@ public:
|
||||||
true, get_unifier_max_steps(m_ios.get_options()));
|
true, get_unifier_max_steps(m_ios.get_options()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_metavars(expr const & e, buffer<expr> & mvars) {
|
||||||
|
for_each(e, [&](expr const & e, unsigned) {
|
||||||
|
if (is_metavar(e)) { mvars.push_back(e); return false; /* do not visit its type */ }
|
||||||
|
return has_metavar(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<tactic> get_tactic_for(expr const & mvar) {
|
||||||
|
auto it = m_hints.find(mvar.get_tag());
|
||||||
|
if (it) {
|
||||||
|
return optional<tactic>(*it);
|
||||||
|
} else {
|
||||||
|
// TODO(Leo): m_env tactic hints
|
||||||
|
return optional<tactic>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg) {
|
||||||
|
regular out(m_env, m_ios);
|
||||||
|
display_error_pos(out, m_pos_provider, mvar);
|
||||||
|
out << " unsolved placeholder, " << msg << "\n" << ps << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
expr solve_unassigned_mvars(substitution & subst, expr const & e) {
|
||||||
|
buffer<expr> mvars;
|
||||||
|
collect_metavars(e, mvars);
|
||||||
|
for (auto mvar : mvars) {
|
||||||
|
mvar = update_mlocal(mvar, subst.instantiate_metavars_wo_jst(mlocal_type(mvar)));
|
||||||
|
proof_state ps = to_proof_state(m_env, mvar, m_ngen.mk_child(), m_ios.get_options());
|
||||||
|
if (optional<tactic> t = get_tactic_for(mvar)) {
|
||||||
|
proof_state_seq seq = (*t)(m_env, m_ios, ps);
|
||||||
|
if (auto r = seq.pull()) {
|
||||||
|
if (auto pr = to_proof(r->first)) {
|
||||||
|
subst = subst.assign(mlocal_name(mvar), *pr, justification());
|
||||||
|
} else {
|
||||||
|
display_unsolved_proof_state(mvar, r->first, "unsolved subgoals");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// tactic failed to produce any result
|
||||||
|
display_unsolved_proof_state(mvar, ps, "tactic failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subst.instantiate_metavars_wo_jst(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Apply substitution and solve remaining metavariables using tactics. */
|
||||||
|
expr apply(substitution & s, expr const & e) {
|
||||||
|
expr r = s.instantiate_metavars_wo_jst(e);
|
||||||
|
return solve_unassigned_mvars(s, r);
|
||||||
|
}
|
||||||
|
|
||||||
expr operator()(expr const & e) {
|
expr operator()(expr const & e) {
|
||||||
expr r = visit(e);
|
expr r = visit(e);
|
||||||
auto p = solve().pull();
|
auto p = solve().pull();
|
||||||
lean_assert(p);
|
lean_assert(p);
|
||||||
substitution s = p->first;
|
substitution s = p->first;
|
||||||
return s.instantiate_metavars_wo_jst(r);
|
return apply(s, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<expr, expr> operator()(expr const & t, expr const & v, name const & n) {
|
std::pair<expr, expr> operator()(expr const & t, expr const & v, name const & n) {
|
||||||
|
@ -606,24 +662,23 @@ public:
|
||||||
auto p = solve().pull();
|
auto p = solve().pull();
|
||||||
lean_assert(p);
|
lean_assert(p);
|
||||||
substitution s = p->first;
|
substitution s = p->first;
|
||||||
return mk_pair(s.instantiate_metavars_wo_jst(r_t),
|
return mk_pair(apply(s, r_t), apply(s, r_v));
|
||||||
s.instantiate_metavars_wo_jst(r_v));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static name g_tmp_prefix = name::mk_internal_unique_name();
|
static name g_tmp_prefix = name::mk_internal_unique_name();
|
||||||
|
|
||||||
expr elaborate(environment const & env, io_state const & ios, expr const & e, name_generator const & ngen,
|
expr elaborate(environment const & env, io_state const & ios, expr const & e, name_generator const & ngen,
|
||||||
hint_table const & htable, substitution const & s, list<parameter> const & ctx) {
|
hint_table const & htable, substitution const & s, list<parameter> const & ctx, pos_info_provider * pp) {
|
||||||
return elaborator(env, ios, ngen, htable, s, ctx)(e);
|
return elaborator(env, ios, ngen, htable, s, ctx, pp)(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr elaborate(environment const & env, io_state const & ios, expr const & e, hint_table const & htable) {
|
expr elaborate(environment const & env, io_state const & ios, expr const & e, hint_table const & htable, pos_info_provider * pp) {
|
||||||
return elaborate(env, ios, e, name_generator(g_tmp_prefix), htable, substitution(), list<parameter>());
|
return elaborate(env, ios, e, name_generator(g_tmp_prefix), htable, substitution(), list<parameter>(), pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<expr, expr> elaborate(environment const & env, io_state const & ios, name const & n, expr const & t, expr const & v,
|
std::pair<expr, expr> elaborate(environment const & env, io_state const & ios, name const & n, expr const & t, expr const & v,
|
||||||
hint_table const & htable) {
|
hint_table const & htable, pos_info_provider * pp) {
|
||||||
return elaborator(env, ios, name_generator(g_tmp_prefix), htable)(t, v, n);
|
return elaborator(env, ios, name_generator(g_tmp_prefix), htable, substitution(), list<parameter>(), pp)(t, v, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ Author: Leonardo de Moura
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
expr elaborate(environment const & env, io_state const & ios, expr const & e, name_generator const & ngen,
|
expr elaborate(environment const & env, io_state const & ios, expr const & e, name_generator const & ngen,
|
||||||
hint_table const & htable = hint_table(), substitution const & s = substitution(), list<parameter> const & ctx = list<parameter>());
|
hint_table const & htable = hint_table(), substitution const & s = substitution(),
|
||||||
expr elaborate(environment const & env, io_state const & ios, expr const & e, hint_table const & htable = hint_table());
|
list<parameter> const & ctx = list<parameter>(), pos_info_provider * pp = nullptr);
|
||||||
|
expr elaborate(environment const & env, io_state const & ios, expr const & e, hint_table const & htable = hint_table(),
|
||||||
|
pos_info_provider * pp = nullptr);
|
||||||
std::pair<expr, expr> elaborate(environment const & env, io_state const & ios, name const & n, expr const & t, expr const & v,
|
std::pair<expr, expr> elaborate(environment const & env, io_state const & ios, name const & n, expr const & t, expr const & v,
|
||||||
hint_table const & htable = hint_table());
|
hint_table const & htable = hint_table(), pos_info_provider * pp = nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,15 +546,18 @@ expr parser::mk_Type() {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr parser::elaborate(expr const & e) {
|
expr parser::elaborate(expr const & e) {
|
||||||
return ::lean::elaborate(m_env, m_ios, e, m_hints);
|
parser_pos_provider pp(m_pos_table, get_stream_name(), m_last_cmd_pos);
|
||||||
|
return ::lean::elaborate(m_env, m_ios, e, m_hints, &pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr parser::elaborate(environment const & env, expr const & e) {
|
expr parser::elaborate(environment const & env, expr const & e) {
|
||||||
return ::lean::elaborate(env, m_ios, e, m_hints);
|
parser_pos_provider pp(m_pos_table, get_stream_name(), m_last_cmd_pos);
|
||||||
|
return ::lean::elaborate(env, m_ios, e, m_hints, &pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<expr, expr> parser::elaborate(name const & n, expr const & t, expr const & v) {
|
std::pair<expr, expr> parser::elaborate(name const & n, expr const & t, expr const & v) {
|
||||||
return ::lean::elaborate(m_env, m_ios, n, t, v, m_hints);
|
parser_pos_provider pp(m_pos_table, get_stream_name(), m_last_cmd_pos);
|
||||||
|
return ::lean::elaborate(m_env, m_ios, n, t, v, m_hints, &pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Parse <tt>ID ':' expr</tt>, where the expression represents the type of the identifier. */
|
/** \brief Parse <tt>ID ':' expr</tt>, where the expression represents the type of the identifier. */
|
||||||
|
|
|
@ -151,4 +151,3 @@ void display_error(io_state_stream const & ios, pos_info_provider const * p, exc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,11 @@ Author: Leonardo de Moura
|
||||||
#include "library/io_state_stream.h"
|
#include "library/io_state_stream.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
/**
|
||||||
|
\brief Display position information associated with \c e (IF avaiable).
|
||||||
|
If it is not available, it just displays "error:"
|
||||||
|
*/
|
||||||
|
void display_error_pos(io_state_stream const & ios, pos_info_provider const * p, expr const & e);
|
||||||
/**
|
/**
|
||||||
\brief Display exception in the regular stream of \c ios, using the configuration options and formatter from \c ios.
|
\brief Display exception in the regular stream of \c ios, using the configuration options and formatter from \c ios.
|
||||||
Exceptions that contain expressions use the given \c pos_info_provider (if available) to retrieve line number information.
|
Exceptions that contain expressions use the given \c pos_info_provider (if available) to retrieve line number information.
|
||||||
|
|
4
tests/lean/run/tactic1.lean
Normal file
4
tests/lean/run/tactic1.lean
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import logic
|
||||||
|
|
||||||
|
theorem tst {A B : Bool} (H1 : A) (H2 : B) : A
|
||||||
|
:= by assumption
|
Loading…
Reference in a new issue