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"
|
|
|
|
#include "kernel/for_each_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"
|
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"
|
2013-12-05 11:22:12 +00:00
|
|
|
#include "library/tactic/apply_tactic.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2013-12-25 06:40:34 +00:00
|
|
|
/**
|
2014-06-30 01:26:07 +00:00
|
|
|
\brief Traverse \c e and collect metavariable applications (?m l1 ... ln), and store in result.
|
|
|
|
The function only succeeds if all metavariable applications are "simple", i.e., the arguments
|
|
|
|
are distinct local constants.
|
2013-12-25 06:40:34 +00:00
|
|
|
*/
|
2014-06-30 01:26:07 +00:00
|
|
|
bool collect_simple_metas(expr const & e, buffer<expr> & result) {
|
|
|
|
bool failed = false;
|
|
|
|
// collect metavariables
|
|
|
|
for_each(e, [&](expr const & e, unsigned) {
|
|
|
|
if (is_meta(e)) {
|
|
|
|
if (!is_simple_meta(e)) {
|
|
|
|
failed = true;
|
|
|
|
} else {
|
|
|
|
result.push_back(e);
|
|
|
|
return false; /* do not visit type */
|
2013-12-25 06:40:34 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-30 01:26:07 +00:00
|
|
|
return !failed && has_metavar(e);
|
2013-12-25 06:40:34 +00:00
|
|
|
});
|
2014-06-30 01:26:07 +00:00
|
|
|
return !failed;
|
2013-12-25 06:40:34 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 20:14:50 +00:00
|
|
|
unsigned get_expect_num_args(type_checker & tc, expr e) {
|
|
|
|
unsigned r = 0;
|
|
|
|
while (true) {
|
|
|
|
e = tc.whnf(e);
|
|
|
|
if (!is_pi(e))
|
|
|
|
return r;
|
|
|
|
e = binding_body(e);
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void collect_simple_meta(expr const & e, buffer<expr> & metas) {
|
|
|
|
for_each(e, [&](expr const & e, unsigned) {
|
|
|
|
if (is_meta(e)) {
|
|
|
|
if (is_simple_meta(e))
|
|
|
|
metas.push_back(e);
|
|
|
|
return false; /* do not visit its type */
|
2013-12-25 06:40:34 +00:00
|
|
|
}
|
2014-07-02 20:14:50 +00:00
|
|
|
return has_metavar(e);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
tactic apply_tactic(expr const & _e) {
|
|
|
|
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-02 20:14:50 +00:00
|
|
|
name_generator ngen = s.get_ngen();
|
|
|
|
type_checker tc(env, ngen.mk_child());
|
|
|
|
goal g = head(gs);
|
|
|
|
goals tail_gs = tail(gs);
|
|
|
|
expr t = g.get_type();
|
|
|
|
expr e = _e;
|
|
|
|
expr e_t = tc.infer(e);
|
|
|
|
unsigned num_t = get_expect_num_args(tc, t);
|
|
|
|
unsigned num_e_t = get_expect_num_args(tc, e_t);
|
|
|
|
if (num_t > num_e_t)
|
|
|
|
return proof_state_seq(); // no hope to unify then
|
|
|
|
for (unsigned i = 0; i < num_e_t - num_t; i++) {
|
|
|
|
e_t = tc.whnf(e_t);
|
|
|
|
expr meta = g.mk_meta(ngen.next(), binding_domain(e_t));
|
|
|
|
e = mk_app(e, meta);
|
|
|
|
e_t = instantiate(binding_body(e_t), meta);
|
2013-12-05 11:22:12 +00:00
|
|
|
}
|
2014-07-02 20:14:50 +00:00
|
|
|
lazy_list<substitution> substs = unify(env, t, e_t, ngen.mk_child(), s.get_subst(), ios.get_options());
|
2014-06-30 01:26:07 +00:00
|
|
|
return map2<proof_state>(substs, [=](substitution const & subst) -> proof_state {
|
|
|
|
name_generator new_ngen(ngen);
|
|
|
|
type_checker tc(env, new_ngen.mk_child());
|
2014-07-02 20:14:50 +00:00
|
|
|
expr new_e = subst.instantiate_metavars_wo_jst(e);
|
|
|
|
substitution new_subst = subst.assign(g.get_name(), g.abstract(new_e));
|
|
|
|
buffer<expr> metas;
|
|
|
|
collect_simple_meta(new_e, metas);
|
|
|
|
goals new_gs = tail_gs;
|
|
|
|
unsigned i = metas.size();
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
new_gs = cons(goal(metas[i], subst.instantiate_metavars_wo_jst(tc.infer(metas[i]))), new_gs);
|
2014-06-30 01:26:07 +00:00
|
|
|
}
|
2014-07-02 20:14:50 +00:00
|
|
|
return proof_state(new_gs, new_subst, new_ngen);
|
2014-06-30 01:26:07 +00:00
|
|
|
});
|
2013-12-05 11:22:12 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-30 01:26:07 +00:00
|
|
|
int mk_apply_tactic(lua_State * L) { return push_tactic(L, apply_tactic(to_expr(L, 1))); }
|
2013-12-05 11:22:12 +00:00
|
|
|
void open_apply_tactic(lua_State * L) {
|
2013-12-06 04:00:20 +00:00
|
|
|
SET_GLOBAL_FUN(mk_apply_tactic, "apply_tac");
|
2013-12-05 11:22:12 +00:00
|
|
|
}
|
|
|
|
}
|