2015-01-29 02:40:21 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include "util/scoped_map.h"
|
|
|
|
#include "util/name_map.h"
|
|
|
|
#include "kernel/instantiate.h"
|
|
|
|
#include "library/match.h"
|
|
|
|
#include "library/app_builder.h"
|
2015-01-29 19:38:56 +00:00
|
|
|
#include "library/kernel_bindings.h"
|
2015-11-01 20:02:49 +00:00
|
|
|
#include "library/tmp_type_context.h"
|
2015-01-29 02:40:21 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
struct app_builder::imp {
|
2015-11-01 20:07:21 +00:00
|
|
|
std::unique_ptr<tmp_type_context> m_ctx;
|
2015-11-01 20:02:49 +00:00
|
|
|
|
|
|
|
struct entry {
|
|
|
|
unsigned m_num_umeta;
|
|
|
|
unsigned m_num_emeta;
|
|
|
|
expr m_app;
|
|
|
|
list<optional<expr>> m_inst_args; // "mask" of implicit instance arguments
|
|
|
|
list<expr> m_expl_args; // metavars for explicit arguments
|
|
|
|
|
|
|
|
/*
|
|
|
|
IMPORTANT: for m_inst_args we store the arguments in reverse order.
|
|
|
|
For example, the first element in the list indicates whether the last argument
|
|
|
|
is an instance implicit argument or not. If it is not none, then the element
|
|
|
|
is the associated metavariable
|
|
|
|
|
|
|
|
m_expl_args are also stored in reverse order
|
|
|
|
*/
|
2015-01-29 02:40:21 +00:00
|
|
|
};
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
struct key {
|
|
|
|
name m_name;
|
|
|
|
unsigned m_num_expl;
|
|
|
|
unsigned m_hash;
|
|
|
|
// If nil, then the mask is composed of the last m_num_expl arguments.
|
|
|
|
// If nonnil, then the mask is NOT of the form [false*, true*]
|
|
|
|
list<bool> m_mask;
|
|
|
|
|
|
|
|
static bool is_simple(list<bool> const & mask) {
|
|
|
|
bool found_true = false;
|
|
|
|
for (bool b : mask) {
|
|
|
|
if (b) {
|
|
|
|
found_true = true;
|
|
|
|
} else if (found_true) {
|
|
|
|
// found (true, false)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
|
|
|
|
key(name const & c, unsigned n):
|
|
|
|
m_name(c), m_num_expl(n),
|
|
|
|
m_hash(::lean::hash(c.hash(), n)) {
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
key(name const & c, list<bool> const & m):
|
|
|
|
m_name(c), m_num_expl(length(m)) {
|
|
|
|
m_hash = ::lean::hash(c.hash(), m_num_expl);
|
|
|
|
if (!is_simple(m)) {
|
|
|
|
m_mask = m;
|
|
|
|
for (bool b : m) {
|
|
|
|
if (b)
|
|
|
|
m_hash = ::lean::hash(m_hash, 17u);
|
|
|
|
else
|
|
|
|
m_hash = ::lean::hash(m_hash, 31u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-29 02:40:21 +00:00
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
bool check_invariant() const {
|
|
|
|
lean_assert(empty(m_mask) || length(m_mask) == m_num_expl);
|
|
|
|
lean_assert(empty(m_mask) || !is_simple(m_mask));
|
|
|
|
return true;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
unsigned hash() const {
|
|
|
|
return m_hash;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
friend bool operator==(key const & k1, key const & k2) {
|
|
|
|
return k1.m_name == k2.m_name && k1.m_num_expl == k2.m_num_expl && k1.m_mask == k2.m_mask;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct key_hash_fn {
|
|
|
|
unsigned operator()(key const & k) const { return k.hash(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::unordered_map<key, entry, key_hash_fn> map;
|
|
|
|
|
|
|
|
map m_map;
|
|
|
|
|
|
|
|
imp(environment const & env, io_state const & ios, reducible_behavior b):
|
2015-11-01 20:07:21 +00:00
|
|
|
m_ctx(new tmp_type_context(env, ios, b)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
imp(std::unique_ptr<tmp_type_context> && ctx):
|
|
|
|
m_ctx(std::move(ctx)) {
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
levels mk_metavars(declaration const & d, buffer<expr> & mvars, buffer<optional<expr>> & inst_args) {
|
2015-11-01 20:07:21 +00:00
|
|
|
m_ctx->clear();
|
2015-11-01 20:02:49 +00:00
|
|
|
unsigned num_univ = d.get_num_univ_params();
|
|
|
|
buffer<level> lvls_buffer;
|
|
|
|
for (unsigned i = 0; i < num_univ; i++) {
|
2015-11-01 20:07:21 +00:00
|
|
|
lvls_buffer.push_back(m_ctx->mk_uvar());
|
2015-11-01 20:02:49 +00:00
|
|
|
}
|
|
|
|
levels lvls = to_list(lvls_buffer);
|
2015-11-01 20:07:21 +00:00
|
|
|
expr type = m_ctx->whnf(instantiate_type_univ_params(d, lvls));
|
2015-01-29 02:40:21 +00:00
|
|
|
while (is_pi(type)) {
|
2015-11-01 20:07:21 +00:00
|
|
|
expr mvar = m_ctx->mk_mvar(binding_domain(type));
|
2015-11-01 20:02:49 +00:00
|
|
|
if (binding_info(type).is_inst_implicit())
|
|
|
|
inst_args.push_back(some_expr(mvar));
|
|
|
|
else
|
|
|
|
inst_args.push_back(none_expr());
|
|
|
|
mvars.push_back(mvar);
|
2015-11-01 20:07:21 +00:00
|
|
|
type = m_ctx->whnf(instantiate(binding_body(type), mvar));
|
2015-01-29 23:30:31 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
return lvls;
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<entry> get_entry(name const & c, unsigned nargs) {
|
|
|
|
key k(c, nargs);
|
|
|
|
lean_assert(k.check_invariant());
|
|
|
|
auto it = m_map.find(k);
|
|
|
|
if (it == m_map.end()) {
|
2015-11-01 20:07:21 +00:00
|
|
|
if (auto d = m_ctx->env().find(c)) {
|
2015-11-01 20:02:49 +00:00
|
|
|
buffer<expr> mvars;
|
|
|
|
buffer<optional<expr>> inst_args;
|
|
|
|
levels lvls = mk_metavars(*d, mvars, inst_args);
|
|
|
|
if (nargs > mvars.size())
|
|
|
|
return optional<entry>(); // insufficient number of arguments
|
|
|
|
entry e;
|
|
|
|
e.m_num_umeta = d->get_num_univ_params();
|
|
|
|
e.m_num_emeta = mvars.size();
|
|
|
|
e.m_app = ::lean::mk_app(mk_constant(c, lvls), mvars);
|
|
|
|
e.m_inst_args = reverse_to_list(inst_args.begin(), inst_args.end());
|
|
|
|
e.m_expl_args = reverse_to_list(mvars.begin() + mvars.size() - nargs, mvars.end());
|
|
|
|
m_map.insert(mk_pair(k, e));
|
|
|
|
return optional<entry>(e);
|
2015-01-29 02:40:21 +00:00
|
|
|
} else {
|
2015-11-01 20:02:49 +00:00
|
|
|
return optional<entry>(); // unknown decl
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-11-01 20:02:49 +00:00
|
|
|
return optional<entry>(it->second);
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
bool check_all_assigned(entry const & e) {
|
|
|
|
lean_assert(e.m_num_emeta == length(e.m_inst_args));
|
|
|
|
// recall that the flags at e.m_inst_args are stored in reverse order.
|
|
|
|
// For example, the first flag in the list indicates whether the last argument
|
|
|
|
// is an instance implicit argument or not.
|
|
|
|
unsigned i = e.m_num_emeta;
|
|
|
|
for (optional<expr> const & inst_arg : e.m_inst_args) {
|
|
|
|
lean_assert(i > 0);
|
|
|
|
--i;
|
|
|
|
if (inst_arg) {
|
2015-11-01 20:07:21 +00:00
|
|
|
expr type = m_ctx->instantiate_uvars_mvars(mlocal_type(*inst_arg));
|
|
|
|
if (auto v = m_ctx->mk_class_instance(type)) {
|
|
|
|
if (!m_ctx->force_assign(*inst_arg, *v))
|
2015-11-01 20:02:49 +00:00
|
|
|
return false;
|
2015-01-29 23:30:31 +00:00
|
|
|
} else {
|
2015-11-01 20:02:49 +00:00
|
|
|
return false;
|
2015-01-29 23:30:31 +00:00
|
|
|
}
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:07:21 +00:00
|
|
|
if (!m_ctx->is_mvar_assigned(i))
|
2015-11-01 20:02:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (unsigned i = 0; i < e.m_num_umeta; i++) {
|
2015-11-01 20:07:21 +00:00
|
|
|
if (!m_ctx->is_uvar_assigned(i))
|
2015-11-01 20:02:49 +00:00
|
|
|
return false;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
return true;
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
optional<expr> mk_app(name const & c, unsigned nargs, expr const * args) {
|
|
|
|
optional<entry> e = get_entry(c, nargs);
|
|
|
|
if (!e)
|
|
|
|
return none_expr();
|
2015-11-01 20:07:21 +00:00
|
|
|
m_ctx->clear();
|
|
|
|
m_ctx->set_next_uvar_idx(e->m_num_umeta);
|
|
|
|
m_ctx->set_next_mvar_idx(e->m_num_emeta);
|
2015-11-01 20:02:49 +00:00
|
|
|
unsigned i = nargs;
|
|
|
|
for (auto m : e->m_expl_args) {
|
|
|
|
if (i == 0)
|
|
|
|
return none_expr();
|
|
|
|
--i;
|
2015-11-01 20:07:21 +00:00
|
|
|
if (!m_ctx->assign(m, args[i]))
|
2015-11-01 20:02:49 +00:00
|
|
|
return none_expr();
|
|
|
|
}
|
|
|
|
if (!check_all_assigned(*e))
|
|
|
|
return none_expr();
|
2015-11-01 20:07:21 +00:00
|
|
|
return some_expr(m_ctx->instantiate_uvars_mvars(e->m_app));
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
optional<expr> mk_app(name const & /* c */, unsigned /* mask_sz */, bool const * /* mask */, expr const * /* args */) {
|
|
|
|
return none_expr();
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
app_builder::app_builder(environment const & env, io_state const & ios, reducible_behavior b):
|
|
|
|
m_ptr(new imp(env, ios, b)) {
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
|
|
|
|
app_builder::app_builder(environment const & env, reducible_behavior b):
|
|
|
|
app_builder(env, get_dummy_ios(), b) {
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
|
2015-11-01 20:07:21 +00:00
|
|
|
app_builder::app_builder(std::unique_ptr<tmp_type_context> && ctx):
|
|
|
|
m_ptr(new imp(std::move(ctx))) {
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:02:49 +00:00
|
|
|
app_builder::~app_builder() {}
|
|
|
|
|
|
|
|
optional<expr> app_builder::mk_app(name const & c, unsigned nargs, expr const * args) {
|
|
|
|
return m_ptr->mk_app(c, nargs, args);
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:02:49 +00:00
|
|
|
|
|
|
|
optional<expr> app_builder::mk_app(name const & c, unsigned mask_sz, bool const * mask, expr const * args) {
|
|
|
|
return m_ptr->mk_app(c, mask_sz, mask, args);
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|
2015-11-01 20:12:41 +00:00
|
|
|
|
|
|
|
void app_builder::set_context(list<expr> const & ctx) {
|
|
|
|
m_ptr->m_ctx->set_context(ctx);
|
|
|
|
}
|
2015-01-29 02:40:21 +00:00
|
|
|
}
|