2013-09-13 01:25:38 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-10-29 10:00:43 +00:00
|
|
|
#include <utility>
|
2013-10-27 18:02:29 +00:00
|
|
|
#include <vector>
|
2013-09-13 01:25:38 +00:00
|
|
|
#include <limits>
|
2013-10-16 20:26:31 +00:00
|
|
|
#include <algorithm>
|
2013-09-16 02:50:48 +00:00
|
|
|
#include "util/exception.h"
|
2013-09-13 01:25:38 +00:00
|
|
|
#include "kernel/metavar.h"
|
|
|
|
#include "kernel/free_vars.h"
|
2013-09-17 02:21:40 +00:00
|
|
|
#include "kernel/instantiate.h"
|
2013-09-13 01:25:38 +00:00
|
|
|
#include "kernel/occurs.h"
|
|
|
|
#include "kernel/for_each.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2013-10-27 18:02:29 +00:00
|
|
|
/**
|
|
|
|
\brief Assignment normalization justification. That is, when other assignments are applied to an existing assignment.
|
|
|
|
*/
|
|
|
|
class normalize_assignment_justification : public justification_cell {
|
|
|
|
context m_ctx;
|
|
|
|
expr m_expr;
|
|
|
|
std::vector<justification> m_jsts;
|
|
|
|
public:
|
|
|
|
normalize_assignment_justification(context const & ctx, expr const & e,
|
|
|
|
justification const & jst,
|
|
|
|
unsigned num_assignment_jsts, justification const * assignment_jsts):
|
|
|
|
m_ctx(ctx),
|
|
|
|
m_expr(e),
|
|
|
|
m_jsts(assignment_jsts, assignment_jsts + num_assignment_jsts) {
|
|
|
|
m_jsts.push_back(jst);
|
|
|
|
std::reverse(m_jsts.begin(), m_jsts.end());
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
virtual format pp_header(formatter const & fmt, options const & opts) const {
|
|
|
|
unsigned indent = get_pp_indent(opts);
|
|
|
|
format expr_fmt = fmt(m_ctx, m_expr, false, opts);
|
|
|
|
format r;
|
|
|
|
r += format("Normalize assignment");
|
|
|
|
r += nest(indent, compose(line(), expr_fmt));
|
2013-09-27 01:24:45 +00:00
|
|
|
return r;
|
|
|
|
}
|
2013-10-27 18:02:29 +00:00
|
|
|
|
|
|
|
virtual void get_children(buffer<justification_cell*> & r) const {
|
|
|
|
append(r, m_jsts);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual expr const & get_main_expr() const { return m_expr; }
|
|
|
|
};
|
2013-09-13 01:25:38 +00:00
|
|
|
|
2013-09-27 01:24:45 +00:00
|
|
|
static name g_unique_name = name::mk_internal_unique_name();
|
|
|
|
|
2013-10-16 20:26:31 +00:00
|
|
|
void swap(metavar_env & a, metavar_env & b) {
|
2013-10-23 20:42:14 +00:00
|
|
|
swap(a.m_name_generator, b.m_name_generator);
|
2013-10-25 18:02:19 +00:00
|
|
|
swap(a.m_metavar_data, b.m_metavar_data);
|
2013-10-27 18:02:29 +00:00
|
|
|
std::swap(a.m_size, b.m_size);
|
|
|
|
std::swap(a.m_beta_reduce_mv, b.m_beta_reduce_mv);
|
2013-10-23 20:42:14 +00:00
|
|
|
std::swap(a.m_timestamp, b.m_timestamp);
|
2013-10-16 20:26:31 +00:00
|
|
|
}
|
|
|
|
|
2013-10-02 00:25:17 +00:00
|
|
|
void metavar_env::inc_timestamp() {
|
|
|
|
if (m_timestamp == std::numeric_limits<unsigned>::max()) {
|
|
|
|
// This should not happen in real examples. We add it just to be safe.
|
|
|
|
throw exception("metavar_env timestamp overflow");
|
|
|
|
}
|
|
|
|
m_timestamp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
metavar_env::metavar_env(name const & prefix):
|
|
|
|
m_name_generator(prefix),
|
2013-10-27 18:02:29 +00:00
|
|
|
m_size(0),
|
|
|
|
m_beta_reduce_mv(true),
|
2013-10-02 00:25:17 +00:00
|
|
|
m_timestamp(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
metavar_env::metavar_env():
|
|
|
|
metavar_env(g_unique_name) {
|
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::mk_metavar(context const & ctx, expr const & type) {
|
|
|
|
inc_timestamp();
|
|
|
|
name m = m_name_generator.next();
|
|
|
|
expr r = ::lean::mk_metavar(m);
|
2013-10-25 18:02:19 +00:00
|
|
|
m_metavar_data.insert(m, data(type, ctx));
|
2013-10-02 00:25:17 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
context metavar_env::get_context(expr const & m) const {
|
|
|
|
lean_assert(is_metavar(m));
|
|
|
|
lean_assert(!has_local_context(m));
|
|
|
|
return get_context(metavar_name(m));
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-10-02 00:25:17 +00:00
|
|
|
context metavar_env::get_context(name const & m) const {
|
2013-10-25 18:02:19 +00:00
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
|
|
|
lean_assert(it);
|
|
|
|
return it->m_context;
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-10-02 00:25:17 +00:00
|
|
|
expr metavar_env::get_type(expr const & m) {
|
|
|
|
lean_assert(is_metavar(m));
|
|
|
|
expr t = get_type(metavar_name(m));
|
|
|
|
if (has_local_context(m)) {
|
|
|
|
if (is_metavar(t)) {
|
|
|
|
return update_metavar(t, append(metavar_lctx(m), metavar_lctx(t)));
|
|
|
|
} else {
|
|
|
|
return apply_local_context(t, metavar_lctx(m));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::get_type(name const & m) {
|
2013-10-25 18:02:19 +00:00
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
|
|
|
lean_assert(it);
|
|
|
|
if (it->m_type) {
|
|
|
|
return it->m_type;
|
2013-10-02 00:25:17 +00:00
|
|
|
} else {
|
|
|
|
expr t = mk_metavar(get_context(m));
|
2013-10-25 18:02:19 +00:00
|
|
|
it->m_type = t;
|
2013-10-02 00:25:17 +00:00
|
|
|
return t;
|
|
|
|
}
|
2013-09-27 01:24:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 20:26:31 +00:00
|
|
|
bool metavar_env::has_type(name const & m) const {
|
2013-10-25 18:02:19 +00:00
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
|
|
|
lean_assert(it);
|
|
|
|
return it->m_type;
|
2013-10-16 20:26:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool metavar_env::has_type(expr const & m) const {
|
|
|
|
lean_assert(is_metavar(m));
|
|
|
|
return has_type(metavar_name(m));
|
|
|
|
}
|
|
|
|
|
2013-10-23 20:42:14 +00:00
|
|
|
justification metavar_env::get_justification(expr const & m) const {
|
2013-10-16 20:26:31 +00:00
|
|
|
lean_assert(is_metavar(m));
|
2013-10-23 20:42:14 +00:00
|
|
|
return get_justification(metavar_name(m));
|
2013-10-16 20:26:31 +00:00
|
|
|
}
|
|
|
|
|
2013-10-23 20:42:14 +00:00
|
|
|
justification metavar_env::get_justification(name const & m) const {
|
2013-10-29 09:39:52 +00:00
|
|
|
return get_subst_jst(m).second;
|
2013-10-16 20:26:31 +00:00
|
|
|
}
|
|
|
|
|
2013-10-02 00:25:17 +00:00
|
|
|
bool metavar_env::is_assigned(name const & m) const {
|
2013-10-27 18:02:29 +00:00
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
|
|
|
return it && it->m_subst;
|
2013-10-02 00:25:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool metavar_env::is_assigned(expr const & m) const {
|
|
|
|
lean_assert(is_metavar(m));
|
|
|
|
return is_assigned(metavar_name(m));
|
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
void metavar_env::assign(name const & m, expr const & t, justification const & jst) {
|
2013-10-02 00:25:17 +00:00
|
|
|
lean_assert(!is_assigned(m));
|
|
|
|
inc_timestamp();
|
2013-10-27 18:02:29 +00:00
|
|
|
m_size++;
|
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
|
|
|
lean_assert(it);
|
|
|
|
it->m_subst = t;
|
|
|
|
it->m_justification = jst;
|
2013-10-02 00:25:17 +00:00
|
|
|
}
|
|
|
|
|
2013-10-23 20:42:14 +00:00
|
|
|
void metavar_env::assign(expr const & m, expr const & t, justification const & j) {
|
2013-10-02 00:25:17 +00:00
|
|
|
lean_assert(is_metavar(m));
|
|
|
|
lean_assert(!has_local_context(m));
|
2013-10-23 20:42:14 +00:00
|
|
|
assign(metavar_name(m), t, j);
|
2013-09-27 01:24:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
expr apply_local_context(expr const & a, local_context const & lctx) {
|
|
|
|
if (lctx) {
|
|
|
|
if (is_metavar(a)) {
|
|
|
|
return mk_metavar(metavar_name(a), append(lctx, metavar_lctx(a)));
|
|
|
|
} else {
|
|
|
|
expr r = apply_local_context(a, tail(lctx));
|
|
|
|
local_entry const & e = head(lctx);
|
|
|
|
if (e.is_lift()) {
|
|
|
|
return lift_free_vars(r, e.s(), e.n());
|
|
|
|
} else {
|
|
|
|
lean_assert(e.is_inst());
|
|
|
|
return instantiate(r, e.s(), e.v());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return a;
|
2013-10-16 00:32:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 09:39:52 +00:00
|
|
|
std::pair<expr, justification> metavar_env::get_subst_jst(expr const & m) const {
|
2013-10-27 18:02:29 +00:00
|
|
|
lean_assert(is_metavar(m));
|
2013-10-29 09:39:52 +00:00
|
|
|
auto p = get_subst_jst(metavar_name(m));
|
|
|
|
expr r = p.first;
|
|
|
|
if (p.first) {
|
|
|
|
local_context const & lctx = metavar_lctx(m);
|
|
|
|
if (lctx)
|
|
|
|
r = apply_local_context(r, lctx);
|
|
|
|
return mk_pair(r, p.second);
|
|
|
|
} else {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<expr, justification> metavar_env::get_subst_jst(name const & m) const {
|
|
|
|
auto it = const_cast<metavar_env*>(this)->m_metavar_data.splay_find(m);
|
2013-10-27 18:02:29 +00:00
|
|
|
if (it->m_subst) {
|
|
|
|
if (has_assigned_metavar(it->m_subst, *this)) {
|
|
|
|
buffer<justification> jsts;
|
|
|
|
expr new_subst = instantiate_metavars(it->m_subst, *this, jsts);
|
|
|
|
if (!jsts.empty()) {
|
|
|
|
it->m_justification = justification(new normalize_assignment_justification(it->m_context, it->m_subst, it->m_justification,
|
|
|
|
jsts.size(), jsts.data()));
|
|
|
|
it->m_subst = new_subst;
|
|
|
|
}
|
|
|
|
}
|
2013-10-29 09:39:52 +00:00
|
|
|
return mk_pair(it->m_subst, it->m_justification);
|
2013-10-23 23:35:47 +00:00
|
|
|
} else {
|
2013-10-29 09:39:52 +00:00
|
|
|
return mk_pair(expr(), justification());
|
2013-10-23 23:35:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 09:39:52 +00:00
|
|
|
expr metavar_env::get_subst(expr const & m) const {
|
|
|
|
return get_subst_jst(m).first;
|
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
class instantiate_metavars_proc : public replace_visitor {
|
|
|
|
protected:
|
|
|
|
metavar_env const & m_menv;
|
|
|
|
buffer<justification> & m_jsts;
|
|
|
|
|
|
|
|
void push_back(justification const & jst) {
|
|
|
|
if (jst)
|
|
|
|
m_jsts.push_back(jst);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual expr visit_metavar(expr const & m, context const & ctx) {
|
|
|
|
if (is_metavar(m) && m_menv.is_assigned(m)) {
|
2013-10-29 09:39:52 +00:00
|
|
|
auto p = m_menv.get_subst_jst(m);
|
|
|
|
expr r = p.first;
|
|
|
|
push_back(p.second);
|
2013-10-27 18:02:29 +00:00
|
|
|
if (has_assigned_metavar(r, m_menv)) {
|
|
|
|
return visit(r, ctx);
|
|
|
|
} else {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual expr visit_app(expr const & e, context const & ctx) {
|
|
|
|
expr const & f = arg(e, 0);
|
|
|
|
if (m_menv.beta_reduce_metavar_application() && is_metavar(f) && m_menv.is_assigned(f)) {
|
2013-10-23 23:35:47 +00:00
|
|
|
buffer<expr> new_args;
|
2013-10-27 18:02:29 +00:00
|
|
|
for (unsigned i = 0; i < num_args(e); i++)
|
2013-10-23 23:35:47 +00:00
|
|
|
new_args.push_back(visit(arg(e, i), ctx));
|
2013-10-27 18:02:29 +00:00
|
|
|
if (is_lambda(new_args[0]))
|
|
|
|
return apply_beta(new_args[0], new_args.size() - 1, new_args.data() + 1);
|
|
|
|
else
|
|
|
|
return mk_app(new_args);
|
|
|
|
} else {
|
|
|
|
return replace_visitor::visit_app(e, ctx);
|
2013-10-23 23:35:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
public:
|
|
|
|
instantiate_metavars_proc(metavar_env const & menv, buffer<justification> & jsts):
|
|
|
|
m_menv(menv),
|
|
|
|
m_jsts(jsts) {
|
|
|
|
}
|
|
|
|
};
|
2013-10-23 23:35:47 +00:00
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
expr instantiate_metavars(expr const & e, metavar_env const & menv, buffer<justification> & jsts) {
|
2013-09-17 14:15:47 +00:00
|
|
|
if (!has_metavar(e)) {
|
|
|
|
return e;
|
|
|
|
} else {
|
2013-10-27 18:02:29 +00:00
|
|
|
return instantiate_metavars_proc(menv, jsts)(e);
|
2013-09-17 14:15:47 +00:00
|
|
|
}
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
bool has_assigned_metavar(expr const & e, metavar_env const & menv) {
|
2013-09-27 01:24:45 +00:00
|
|
|
if (!has_metavar(e)) {
|
|
|
|
return false;
|
|
|
|
} else {
|
2013-10-25 22:19:59 +00:00
|
|
|
bool result = false;
|
2013-09-27 01:24:45 +00:00
|
|
|
auto proc = [&](expr const & n, unsigned) {
|
2013-10-25 22:19:59 +00:00
|
|
|
if (result)
|
|
|
|
return false;
|
2013-10-25 21:58:02 +00:00
|
|
|
if (!has_metavar(n))
|
|
|
|
return false;
|
2013-10-27 18:02:29 +00:00
|
|
|
if (is_metavar(n) && menv.is_assigned(n)) {
|
2013-10-25 22:19:59 +00:00
|
|
|
result = true;
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-25 21:58:02 +00:00
|
|
|
return true;
|
2013-09-27 01:24:45 +00:00
|
|
|
};
|
|
|
|
for_each_fn<decltype(proc)> visitor(proc);
|
2013-10-25 22:19:59 +00:00
|
|
|
visitor(e);
|
|
|
|
return result;
|
2013-09-27 01:24:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
local_context add_lift(local_context const & lctx, unsigned s, unsigned n) {
|
2013-09-17 10:14:02 +00:00
|
|
|
if (n == 0) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return lctx;
|
|
|
|
} else if (lctx) {
|
|
|
|
local_entry e = head(lctx);
|
2013-09-17 10:14:02 +00:00
|
|
|
// Simplification rule
|
|
|
|
// lift:(s1+n1):n2 lift:s1:n1 ---> lift:s1:n1+n2
|
|
|
|
if (e.is_lift() && s == e.s() + e.n()) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return add_lift(tail(lctx), e.s(), e.n() + n);
|
2013-09-17 10:14:02 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-27 01:24:45 +00:00
|
|
|
return cons(mk_lift(s, n), lctx);
|
2013-09-16 17:58:56 +00:00
|
|
|
}
|
|
|
|
|
2013-09-13 01:25:38 +00:00
|
|
|
expr add_lift(expr const & m, unsigned s, unsigned n) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return update_metavar(m, add_lift(metavar_lctx(m), s, n));
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-27 01:24:45 +00:00
|
|
|
local_context add_inst(local_context const & lctx, unsigned s, expr const & v) {
|
|
|
|
if (lctx) {
|
|
|
|
local_entry e = head(lctx);
|
2013-09-17 02:29:19 +00:00
|
|
|
if (e.is_lift() && e.s() <= s && s < e.s() + e.n()) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return add_lift(tail(lctx), e.s(), e.n() - 1);
|
2013-09-17 09:57:28 +00:00
|
|
|
}
|
|
|
|
// Simplifications such as
|
|
|
|
// inst:4 #6 lift:5:3 --> lift:4:2
|
|
|
|
// inst:3 #7 lift:4:5 --> lift:3:4
|
|
|
|
// General rule is:
|
|
|
|
// inst:(s-1) #(s+n-2) lift:s:n --> lift:s-1:n-1
|
|
|
|
if (e.is_lift() && is_var(v) && e.s() > 0 && s == e.s() - 1 && e.s() + e.n() > 2 && var_idx(v) == e.s() + e.n() - 2) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return add_lift(tail(lctx), e.s() - 1, e.n() - 1);
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-27 01:24:45 +00:00
|
|
|
return cons(mk_inst(s, v), lctx);
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-17 02:21:40 +00:00
|
|
|
expr add_inst(expr const & m, unsigned s, expr const & v) {
|
2013-09-27 01:24:45 +00:00
|
|
|
return update_metavar(m, add_inst(metavar_lctx(m), s, v));
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-27 01:24:45 +00:00
|
|
|
bool has_local_context(expr const & m) {
|
|
|
|
return metavar_lctx(m);
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 03:46:00 +00:00
|
|
|
expr pop_meta_context(expr const & m) {
|
2013-09-27 01:24:45 +00:00
|
|
|
lean_assert(has_local_context(m));
|
|
|
|
return update_metavar(m, tail(metavar_lctx(m)));
|
2013-09-19 03:46:00 +00:00
|
|
|
}
|
|
|
|
|
2013-09-13 01:25:38 +00:00
|
|
|
/**
|
|
|
|
\brief Auxiliary exception used to sign that a metavariable was
|
|
|
|
found in an expression.
|
|
|
|
*/
|
|
|
|
struct found_metavar {};
|
|
|
|
|
2013-10-27 18:02:29 +00:00
|
|
|
bool has_metavar(expr const & e, expr const & m, metavar_env const & menv) {
|
2013-10-25 16:24:01 +00:00
|
|
|
if (has_metavar(e)) {
|
|
|
|
lean_assert(is_metavar(m));
|
2013-10-27 18:02:29 +00:00
|
|
|
lean_assert(!menv.is_assigned(m));
|
2013-10-25 16:24:01 +00:00
|
|
|
auto f = [&](expr const & m2, unsigned) {
|
|
|
|
if (is_metavar(m2)) {
|
|
|
|
if (metavar_name(m) == metavar_name(m2))
|
|
|
|
throw found_metavar();
|
2013-10-27 18:02:29 +00:00
|
|
|
if (menv.is_assigned(m2) &&
|
|
|
|
has_metavar(menv.get_subst(m2), m, menv))
|
2013-10-25 16:24:01 +00:00
|
|
|
throw found_metavar();
|
|
|
|
}
|
2013-10-25 21:58:02 +00:00
|
|
|
return true;
|
2013-10-25 16:24:01 +00:00
|
|
|
};
|
|
|
|
try {
|
|
|
|
for_each_fn<decltype(f)> proc(f);
|
|
|
|
proc(e);
|
|
|
|
return false;
|
|
|
|
} catch (found_metavar) {
|
|
|
|
return true;
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
2013-10-25 16:24:01 +00:00
|
|
|
} else {
|
2013-09-13 01:25:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|