2013-12-05 11:22:12 +00:00
|
|
|
/*
|
2014-06-30 01:26:07 +00:00
|
|
|
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
2013-12-05 11:22:12 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <utility>
|
2014-06-30 01:26:07 +00:00
|
|
|
#include "util/lazy_list_fn.h"
|
2014-07-02 21:09:01 +00:00
|
|
|
#include "util/sstream.h"
|
2014-07-08 23:55:11 +00:00
|
|
|
#include "util/name_map.h"
|
2014-06-30 01:26:07 +00:00
|
|
|
#include "kernel/for_each_fn.h"
|
2014-07-08 23:55:11 +00:00
|
|
|
#include "kernel/replace_fn.h"
|
2013-12-05 11:22:12 +00:00
|
|
|
#include "kernel/instantiate.h"
|
2013-12-24 22:23:06 +00:00
|
|
|
#include "kernel/abstract.h"
|
2014-06-30 01:26:07 +00:00
|
|
|
#include "kernel/type_checker.h"
|
2014-10-15 00:12:57 +00:00
|
|
|
#include "library/reducible.h"
|
2013-12-05 11:22:12 +00:00
|
|
|
#include "library/kernel_bindings.h"
|
2014-06-30 01:26:07 +00:00
|
|
|
#include "library/unifier.h"
|
2014-07-03 19:59:48 +00:00
|
|
|
#include "library/occurs.h"
|
2014-10-15 00:12:57 +00:00
|
|
|
#include "library/metavar_closure.h"
|
2014-09-03 14:42:24 +00:00
|
|
|
#include "library/type_util.h"
|
2014-10-21 00:32:32 +00:00
|
|
|
#include "library/tactic/expr_to_tactic.h"
|
2014-10-23 16:01:19 +00:00
|
|
|
#include "library/tactic/apply_tactic.h"
|
2013-12-05 11:22:12 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2014-10-23 01:11:09 +00:00
|
|
|
/**
|
|
|
|
\brief Given a sequence metas: <tt>(?m_1 ...) (?m_2 ... ) ... (?m_k ...)</tt>,
|
|
|
|
we say ?m_i is "redundant" if it occurs in the type of some ?m_j.
|
|
|
|
This procedure removes from metas any redundant element.
|
|
|
|
*/
|
|
|
|
static void remove_redundant_metas(buffer<expr> & metas) {
|
|
|
|
buffer<expr> mvars;
|
|
|
|
for (expr const & m : metas)
|
|
|
|
mvars.push_back(get_app_fn(m));
|
|
|
|
unsigned k = 0;
|
|
|
|
for (unsigned i = 0; i < metas.size(); i++) {
|
|
|
|
bool found = false;
|
|
|
|
for (unsigned j = 0; j < metas.size(); j++) {
|
|
|
|
if (j != i) {
|
|
|
|
if (occurs(mvars[i], mlocal_type(mvars[j]))) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
metas[k] = metas[i];
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
metas.shrink(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
enum subgoals_action_kind { IgnoreSubgoals, AddRevSubgoals, AddSubgoals };
|
|
|
|
|
2014-10-15 16:15:11 +00:00
|
|
|
static proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s,
|
|
|
|
expr const & _e, buffer<constraint> & cs,
|
2014-10-29 15:57:34 +00:00
|
|
|
bool add_meta, subgoals_action_kind subgoals_action) {
|
2014-07-03 19:59:48 +00:00
|
|
|
goals const & gs = s.get_goals();
|
|
|
|
if (empty(gs))
|
|
|
|
return proof_state_seq();
|
|
|
|
name_generator ngen = s.get_ngen();
|
2014-10-29 15:57:34 +00:00
|
|
|
std::shared_ptr<type_checker> tc(mk_type_checker(env, ngen.mk_child(), s.relax_main_opaque()));
|
2014-07-03 19:59:48 +00:00
|
|
|
goal g = head(gs);
|
|
|
|
goals tail_gs = tail(gs);
|
|
|
|
expr t = g.get_type();
|
|
|
|
expr e = _e;
|
2014-10-15 00:12:57 +00:00
|
|
|
auto e_t_cs = tc->infer(e);
|
|
|
|
e_t_cs.second.linearize(cs);
|
|
|
|
expr e_t = e_t_cs.first;
|
2014-07-03 19:59:48 +00:00
|
|
|
buffer<expr> metas;
|
|
|
|
if (add_meta) {
|
2014-10-24 05:36:32 +00:00
|
|
|
// unsigned num_t = get_expect_num_args(*tc, t);
|
2014-10-15 00:12:57 +00:00
|
|
|
unsigned num_e_t = get_expect_num_args(*tc, e_t);
|
2014-10-24 05:36:32 +00:00
|
|
|
// Remark: we used to add (num_e_t - num_t) arguments.
|
|
|
|
// This would allow us to handle (A -> B) without using intros,
|
|
|
|
// but it was preventing us from solving other problems
|
|
|
|
for (unsigned i = 0; i < num_e_t; i++) {
|
2014-10-15 00:12:57 +00:00
|
|
|
auto e_t_cs = tc->whnf(e_t);
|
|
|
|
e_t_cs.second.linearize(cs);
|
|
|
|
e_t = e_t_cs.first;
|
2014-07-03 19:59:48 +00:00
|
|
|
expr meta = g.mk_meta(ngen.next(), binding_domain(e_t));
|
|
|
|
e = mk_app(e, meta);
|
|
|
|
e_t = instantiate(binding_body(e_t), meta);
|
|
|
|
metas.push_back(meta);
|
|
|
|
}
|
|
|
|
}
|
2014-10-15 00:12:57 +00:00
|
|
|
metavar_closure cls(t);
|
2014-10-29 15:57:34 +00:00
|
|
|
cls.mk_constraints(s.get_subst(), justification(), s.relax_main_opaque());
|
2014-10-15 00:12:57 +00:00
|
|
|
pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t);
|
|
|
|
if (!dcs.first)
|
|
|
|
return proof_state_seq();
|
|
|
|
dcs.second.linearize(cs);
|
|
|
|
unifier_config cfg(ios.get_options());
|
|
|
|
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());
|
2014-09-11 21:02:17 +00:00
|
|
|
return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state {
|
2014-10-15 00:12:57 +00:00
|
|
|
substitution const & subst = p.first;
|
|
|
|
constraints const & postponed = p.second;
|
2014-07-03 19:59:48 +00:00
|
|
|
name_generator new_ngen(ngen);
|
2014-07-23 15:51:24 +00:00
|
|
|
substitution new_subst = subst;
|
2014-07-23 21:21:47 +00:00
|
|
|
expr new_e = new_subst.instantiate_all(e);
|
2014-07-03 19:59:48 +00:00
|
|
|
expr new_p = g.abstract(new_e);
|
|
|
|
check_has_no_local(new_p, _e, "apply");
|
2014-07-23 15:51:24 +00:00
|
|
|
new_subst.assign(g.get_name(), new_p);
|
2014-07-03 19:59:48 +00:00
|
|
|
goals new_gs = tail_gs;
|
2014-10-23 01:11:09 +00:00
|
|
|
if (subgoals_action != IgnoreSubgoals) {
|
2014-07-03 19:59:48 +00:00
|
|
|
buffer<expr> metas;
|
|
|
|
for (auto m : meta_lst) {
|
|
|
|
if (!new_subst.is_assigned(get_app_fn(m)))
|
|
|
|
metas.push_back(m);
|
|
|
|
}
|
2014-10-23 01:11:09 +00:00
|
|
|
if (subgoals_action == AddRevSubgoals) {
|
|
|
|
for (unsigned i = 0; i < metas.size(); i++)
|
|
|
|
new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
|
|
|
|
} else {
|
|
|
|
lean_assert(subgoals_action == AddSubgoals);
|
|
|
|
remove_redundant_metas(metas);
|
|
|
|
unsigned i = metas.size();
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
|
|
|
|
}
|
|
|
|
}
|
2014-07-03 19:59:48 +00:00
|
|
|
}
|
2014-10-29 15:57:34 +00:00
|
|
|
return proof_state(s, new_gs, new_subst, new_ngen, postponed);
|
2014-07-03 19:59:48 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-10-15 00:12:57 +00:00
|
|
|
static proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & e,
|
2014-10-29 15:57:34 +00:00
|
|
|
bool add_meta, subgoals_action_kind subgoals_action) {
|
2014-10-15 00:12:57 +00:00
|
|
|
buffer<constraint> cs;
|
2014-10-29 15:57:34 +00:00
|
|
|
return apply_tactic_core(env, ios, s, e, cs, add_meta, subgoals_action);
|
2014-10-15 00:12:57 +00:00
|
|
|
}
|
|
|
|
|
2014-10-29 15:57:34 +00:00
|
|
|
tactic eassumption_tactic() {
|
2014-07-02 20:14:50 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
|
|
|
goals const & gs = s.get_goals();
|
|
|
|
if (empty(gs))
|
2014-06-30 01:26:07 +00:00
|
|
|
return proof_state_seq();
|
2014-07-03 19:59:48 +00:00
|
|
|
proof_state_seq r;
|
|
|
|
goal g = head(gs);
|
|
|
|
buffer<expr> hs;
|
|
|
|
get_app_args(g.get_meta(), hs);
|
|
|
|
for (expr const & h : hs) {
|
2014-10-29 15:57:34 +00:00
|
|
|
r = append(r, apply_tactic_core(env, ios, s, h, false, IgnoreSubgoals));
|
2013-12-05 11:22:12 +00:00
|
|
|
}
|
2014-07-03 19:59:48 +00:00
|
|
|
return r;
|
2013-12-05 11:22:12 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-10-29 15:57:34 +00:00
|
|
|
tactic apply_tactic(elaborate_fn const & elab, expr const & e, bool rev) {
|
2014-10-15 00:12:57 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
|
|
|
goals const & gs = s.get_goals();
|
|
|
|
if (empty(gs))
|
|
|
|
return proof_state_seq();
|
|
|
|
goal const & g = head(gs);
|
|
|
|
name_generator ngen = s.get_ngen();
|
|
|
|
expr new_e;
|
|
|
|
buffer<constraint> cs;
|
|
|
|
auto ecs = elab(g, ngen.mk_child(), e);
|
|
|
|
new_e = ecs.first;
|
|
|
|
to_buffer(ecs.second, cs);
|
|
|
|
to_buffer(s.get_postponed(), cs);
|
2014-10-29 15:57:34 +00:00
|
|
|
proof_state new_s(s, ngen, constraints());
|
|
|
|
return apply_tactic_core(env, ios, new_s, new_e, cs, true, rev ? AddRevSubgoals : AddSubgoals);
|
2014-10-15 00:12:57 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:59:48 +00:00
|
|
|
int mk_eassumption_tactic(lua_State * L) { return push_tactic(L, eassumption_tactic()); }
|
2013-12-05 11:22:12 +00:00
|
|
|
void open_apply_tactic(lua_State * L) {
|
2014-07-03 19:59:48 +00:00
|
|
|
SET_GLOBAL_FUN(mk_eassumption_tactic, "eassumption_tac");
|
2013-12-05 11:22:12 +00:00
|
|
|
}
|
2014-10-21 00:32:32 +00:00
|
|
|
|
|
|
|
void initialize_apply_tactic() {
|
2014-10-23 00:39:06 +00:00
|
|
|
register_tac(name({"tactic", "apply"}),
|
2014-10-22 22:18:43 +00:00
|
|
|
[](type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
|
|
|
check_tactic_expr(app_arg(e), "invalid 'apply' tactic, invalid argument");
|
2014-10-23 01:11:09 +00:00
|
|
|
return apply_tactic(fn, get_tactic_expr_expr(app_arg(e)), false);
|
|
|
|
});
|
|
|
|
|
|
|
|
register_tac(name({"tactic", "rapply"}),
|
|
|
|
[](type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
|
|
|
check_tactic_expr(app_arg(e), "invalid 'apply' tactic, invalid argument");
|
|
|
|
return apply_tactic(fn, get_tactic_expr_expr(app_arg(e)), true);
|
2014-10-22 22:18:43 +00:00
|
|
|
});
|
2014-10-21 00:32:32 +00:00
|
|
|
|
|
|
|
register_simple_tac(name({"tactic", "eassumption"}),
|
|
|
|
[]() { return eassumption_tactic(); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void finalize_apply_tactic() {
|
|
|
|
}
|
2013-12-05 11:22:12 +00:00
|
|
|
}
|