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
|
|
|
|
*/
|
|
|
|
#include <limits>
|
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/replace.h"
|
|
|
|
#include "kernel/free_vars.h"
|
|
|
|
#include "kernel/occurs.h"
|
|
|
|
#include "kernel/for_each.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2013-09-16 02:50:48 +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():m_timestamp(0) {}
|
|
|
|
|
2013-09-16 02:37:59 +00:00
|
|
|
expr metavar_env::mk_metavar(context const & ctx) {
|
2013-09-16 02:50:48 +00:00
|
|
|
inc_timestamp();
|
2013-09-13 01:25:38 +00:00
|
|
|
unsigned midx = m_env.size();
|
2013-09-16 02:37:59 +00:00
|
|
|
m_env.push_back(data(ctx));
|
2013-09-13 01:25:38 +00:00
|
|
|
return ::lean::mk_metavar(midx);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool metavar_env::contains(unsigned midx) const {
|
|
|
|
return midx < m_env.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool metavar_env::is_assigned(unsigned midx) const {
|
2013-09-16 02:37:59 +00:00
|
|
|
return m_env[midx].m_subst;
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::get_subst(unsigned midx) const {
|
2013-09-16 02:37:59 +00:00
|
|
|
return m_env[midx].m_subst;
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::get_type(unsigned midx, unification_problems & up) {
|
|
|
|
auto p = m_env[midx];
|
2013-09-16 02:37:59 +00:00
|
|
|
expr t = p->m_type;
|
2013-09-13 01:25:38 +00:00
|
|
|
if (t) {
|
|
|
|
return t;
|
|
|
|
} else {
|
|
|
|
t = mk_metavar();
|
2013-09-16 02:37:59 +00:00
|
|
|
expr s = p->m_subst;
|
|
|
|
m_env[midx] = data(s, t, p->m_ctx);
|
2013-09-13 01:25:38 +00:00
|
|
|
if (s)
|
2013-09-16 02:37:59 +00:00
|
|
|
up.add_type_of_eq(p->m_ctx, s, t);
|
2013-09-13 01:25:38 +00:00
|
|
|
else
|
2013-09-16 02:37:59 +00:00
|
|
|
up.add_type_of_eq(p->m_ctx, ::lean::mk_metavar(midx), t);
|
2013-09-13 01:25:38 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 02:37:59 +00:00
|
|
|
void metavar_env::assign(unsigned midx, expr const & v) {
|
2013-09-16 02:50:48 +00:00
|
|
|
inc_timestamp();
|
2013-09-13 01:25:38 +00:00
|
|
|
lean_assert(!is_assigned(midx));
|
|
|
|
auto p = m_env[midx];
|
2013-09-16 02:37:59 +00:00
|
|
|
m_env[midx] = data(v, p->m_type, p->m_ctx);
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr subst(expr const & a, unsigned i, expr const & c) {
|
|
|
|
auto f = [&](expr const & e, unsigned offset) -> expr {
|
|
|
|
if (is_var(e)) {
|
|
|
|
unsigned vidx = var_idx(e);
|
|
|
|
if (vidx == offset + i)
|
|
|
|
return lift_free_vars(c, 0, offset);
|
|
|
|
else
|
|
|
|
return e;
|
|
|
|
} else if (is_metavar(e)) {
|
|
|
|
return add_subst(e, offset, lift_free_vars(c, 0, offset));
|
|
|
|
} else {
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return replace_fn<decltype(f)>(f)(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr instantiate(expr const & s, meta_ctx const & ctx, metavar_env const & env) {
|
|
|
|
if (ctx) {
|
|
|
|
expr r = instantiate(s, tail(ctx), env);
|
|
|
|
meta_entry const & e = head(ctx);
|
|
|
|
switch (e.kind()) {
|
|
|
|
case meta_entry_kind::Lift: return lift_free_vars(r, e.s(), e.n());
|
|
|
|
case meta_entry_kind::Lower: return lower_free_vars(r, e.s(), e.n());
|
|
|
|
case meta_entry_kind::Subst: return subst(r, e.s(), instantiate_metavars(e.v(), env));
|
|
|
|
}
|
|
|
|
lean_unreachable();
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::get_subst(expr const & m) const {
|
|
|
|
expr s = get_subst(metavar_idx(m));
|
|
|
|
if (s)
|
|
|
|
return instantiate(s, metavar_ctx(m), *this);
|
|
|
|
else
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
expr metavar_env::get_type(expr const & m, unification_problems & up) {
|
|
|
|
expr s = get_type(metavar_idx(m), up);
|
|
|
|
lean_assert(is_metavar(s));
|
|
|
|
lean_assert(!metavar_ctx(s));
|
|
|
|
meta_ctx const & ctx = metavar_ctx(m);
|
|
|
|
if (ctx)
|
|
|
|
return ::lean::mk_metavar(metavar_idx(s), ctx);
|
|
|
|
else
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void metavar_env::assign(expr const & m, expr const & t) {
|
|
|
|
lean_assert(!metavar_ctx(m));
|
|
|
|
assign(metavar_idx(m), t);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr instantiate_metavars(expr const & e, metavar_env const & env) {
|
|
|
|
auto f = [=](expr const & m, unsigned offset) -> expr {
|
|
|
|
if (is_metavar(m) && env.contains(m)) {
|
|
|
|
expr s = env.get_subst(m);
|
|
|
|
return s ? s : m;
|
|
|
|
} else {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return replace_fn<decltype(f)>(f)(e);
|
|
|
|
}
|
|
|
|
|
2013-09-16 17:58:56 +00:00
|
|
|
meta_ctx add_lift(meta_ctx const & ctx, unsigned s, unsigned n) {
|
|
|
|
return cons(mk_lift(s, n), ctx);
|
|
|
|
}
|
|
|
|
|
2013-09-13 01:25:38 +00:00
|
|
|
expr add_lift(expr const & m, unsigned s, unsigned n) {
|
2013-09-16 17:58:56 +00:00
|
|
|
return mk_metavar(metavar_idx(m), add_lift(metavar_ctx(m), s, n));
|
2013-09-13 01:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
meta_ctx add_lower(meta_ctx const & ctx, unsigned s2, unsigned n2) {
|
|
|
|
if (ctx) {
|
|
|
|
meta_entry e = head(ctx);
|
|
|
|
unsigned s1, n1;
|
|
|
|
switch (e.kind()) {
|
|
|
|
case meta_entry_kind::Lift:
|
|
|
|
s1 = e.s();
|
|
|
|
n1 = e.n();
|
|
|
|
if (s1 <= s2 && s2 <= s1 + n1) {
|
|
|
|
if (n1 == n2)
|
|
|
|
return tail(ctx);
|
|
|
|
else if (n1 > n2)
|
|
|
|
return cons(mk_lift(s1, n1 - n2), tail(ctx));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case meta_entry_kind::Lower:
|
|
|
|
s1 = e.s();
|
|
|
|
n1 = e.n();
|
|
|
|
if (s2 == s1 - n1)
|
|
|
|
return add_lower(tail(ctx), s1, n1 + n2);
|
|
|
|
break;
|
|
|
|
case meta_entry_kind::Subst:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cons(mk_lower(s2, n2), ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr add_lower(expr const & m, unsigned s, unsigned n) {
|
|
|
|
return mk_metavar(metavar_idx(m), add_lower(metavar_ctx(m), s, n));
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_ctx add_subst(meta_ctx const & ctx, unsigned s, expr const & v) {
|
|
|
|
if (ctx) {
|
|
|
|
meta_entry e = head(ctx);
|
|
|
|
switch (e.kind()) {
|
|
|
|
case meta_entry_kind::Subst:
|
|
|
|
return cons(mk_subst(s, v), ctx);
|
|
|
|
case meta_entry_kind::Lower:
|
|
|
|
if (s >= e.s())
|
|
|
|
return cons(e, add_subst(tail(ctx), s + e.n(), lift_free_vars(v, e.s(), e.n())));
|
|
|
|
else
|
|
|
|
return cons(e, add_subst(tail(ctx), s, lift_free_vars(v, e.s(), e.n())));
|
|
|
|
case meta_entry_kind::Lift:
|
|
|
|
if (e.s() <= s && s < e.s() + e.n()) {
|
|
|
|
return ctx;
|
|
|
|
} else if (s < e.s() && !has_free_var(v, e.s(), std::numeric_limits<unsigned>::max())) {
|
|
|
|
return cons(e, add_subst(tail(ctx), s, v));
|
|
|
|
} else if (s >= e.s() + e.n() && !has_free_var(v, e.s(), std::numeric_limits<unsigned>::max())) {
|
|
|
|
return cons(e, add_subst(tail(ctx), s - e.n(), v));
|
|
|
|
} else {
|
|
|
|
return cons(mk_subst(s, v), ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lean_unreachable();
|
|
|
|
return ctx;
|
|
|
|
} else {
|
|
|
|
return cons(mk_subst(s, v), ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expr add_subst(expr const & m, unsigned s, expr const & v) {
|
|
|
|
return mk_metavar(metavar_idx(m), add_subst(metavar_ctx(m), s, v));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool has_context(expr const & m) {
|
|
|
|
return metavar_ctx(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr pop_context(expr const & m) {
|
|
|
|
lean_assert(has_context(m));
|
|
|
|
return mk_metavar(metavar_idx(m), tail(metavar_ctx(m)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Auxiliary exception used to sign that a metavariable was
|
|
|
|
found in an expression.
|
|
|
|
*/
|
|
|
|
struct found_metavar {};
|
|
|
|
|
|
|
|
bool has_metavar(expr const & e, unsigned midx, metavar_env const & menv) {
|
|
|
|
auto f = [&](expr const & m, unsigned offset) {
|
|
|
|
if (is_metavar(m)) {
|
|
|
|
unsigned midx2 = metavar_idx(m);
|
|
|
|
if (midx2 == midx)
|
|
|
|
throw found_metavar();
|
|
|
|
if (menv.contains(midx2) &&
|
|
|
|
menv.is_assigned(midx2) &&
|
|
|
|
has_metavar(menv.get_subst(midx2), midx, menv))
|
|
|
|
throw found_metavar();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
try {
|
|
|
|
for_each_fn<decltype(f)> proc(f);
|
|
|
|
proc(e);
|
|
|
|
return false;
|
|
|
|
} catch (found_metavar) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|