Simplify metavariable context. Now, we have only 'lift' and 'inst' instead of 'subst', 'lift' and 'lower'

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-09-16 19:21:40 -07:00
parent cad562a448
commit 99a163f11d
19 changed files with 119 additions and 262 deletions

View file

@ -576,12 +576,12 @@ class elaborator::imp {
/** /**
\brief Temporary hack until we build the new elaborator. \brief Temporary hack until we build the new elaborator.
*/ */
bool is_lower_lift_core(meta_entry_kind k, expr const & e, expr & c, unsigned & s, unsigned & n) { bool is_lift(expr const & e, expr & c, unsigned & s, unsigned & n) {
if (!is_metavar(e) || !has_context(e)) if (!is_metavar(e) || !has_context(e))
return false; return false;
meta_ctx const & ctx = metavar_ctx(e); meta_ctx const & ctx = metavar_ctx(e);
meta_entry const & entry = head(ctx); meta_entry const & entry = head(ctx);
if (entry.kind() == k) { if (entry.kind() == meta_entry_kind::Lift) {
c = ::lean::mk_metavar(metavar_idx(e), tail(ctx)); c = ::lean::mk_metavar(metavar_idx(e), tail(ctx));
add_trace(e, c); add_trace(e, c);
s = entry.s(); s = entry.s();
@ -595,26 +595,12 @@ class elaborator::imp {
/** /**
\brief Temporary hack until we build the new elaborator. \brief Temporary hack until we build the new elaborator.
*/ */
bool is_lower(expr const & e, expr & c, unsigned & s, unsigned & n) { bool is_inst(expr const & e, expr & c, unsigned & s, expr & v) {
return is_lower_lift_core(meta_entry_kind::Lower, e, c, s, n);
}
/**
\brief Temporary hack until we build the new elaborator.
*/
bool is_lift(expr const & e, expr & c, unsigned & s, unsigned & n) {
return is_lower_lift_core(meta_entry_kind::Lift, e, c, s, n);
}
/**
\brief Temporary hack until we build the new elaborator.
*/
bool is_subst(expr const & e, expr & c, unsigned & s, expr & v) {
if (!is_metavar(e) || !has_context(e)) if (!is_metavar(e) || !has_context(e))
return false; return false;
meta_ctx const & ctx = metavar_ctx(e); meta_ctx const & ctx = metavar_ctx(e);
meta_entry const & entry = head(ctx); meta_entry const & entry = head(ctx);
if (entry.kind() == meta_entry_kind::Subst) { if (entry.kind() == meta_entry_kind::Inst) {
c = ::lean::mk_metavar(metavar_idx(e), tail(ctx)); c = ::lean::mk_metavar(metavar_idx(e), tail(ctx));
add_trace(e, c); add_trace(e, c);
s = entry.s(); s = entry.s();
@ -639,11 +625,6 @@ class elaborator::imp {
} }
if (!has_metavar(t)) { if (!has_metavar(t)) {
if (is_lower(e, a, s, n)) {
m_constraints.push_back(constraint(a, lift_free_vars(t, s-n, n), c));
return true;
}
if (is_lift(e, a, s, n)) { if (is_lift(e, a, s, n)) {
if (!has_free_var(t, s, s+n)) { if (!has_free_var(t, s, s+n)) {
m_constraints.push_back(constraint(a, lower_free_vars(t, s+n, n), c)); m_constraints.push_back(constraint(a, lower_free_vars(t, s+n, n), c));
@ -660,9 +641,9 @@ class elaborator::imp {
return true; return true;
} }
if (is_subst(e, a, i, v) && is_lift(a, b, s, n) && has_free_var(t, s, s+n)) { if (is_inst(e, a, i, v) && is_lift(a, b, s, n) && !has_free_var(t, s, s+n)) {
// subst (lift b s n) i v == t // subst (lift b s n) i v == t
// (lift b s n) does not have free-variables in the range [s, s+n) // t does not have free-variables in the range [s, s+n)
// Thus, if t has a free variables in [s, s+n), then the only possible solution is // Thus, if t has a free variables in [s, s+n), then the only possible solution is
// (lift b s n) == i // (lift b s n) == i
// v == t // v == t
@ -670,7 +651,6 @@ class elaborator::imp {
m_constraints.push_back(constraint(v, t, c)); m_constraints.push_back(constraint(v, t, c));
return true; return true;
} }
return false; return false;
} }

View file

@ -15,10 +15,10 @@ Author: Leonardo de Moura
#include "util/interruptable_ptr.h" #include "util/interruptable_ptr.h"
#include "kernel/context.h" #include "kernel/context.h"
#include "kernel/for_each.h" #include "kernel/for_each.h"
#include "kernel/instantiate.h"
#include "kernel/occurs.h" #include "kernel/occurs.h"
#include "kernel/builtin.h" #include "kernel/builtin.h"
#include "kernel/free_vars.h" #include "kernel/free_vars.h"
#include "kernel/replace.h"
#include "library/context_to_lambda.h" #include "library/context_to_lambda.h"
#include "library/placeholder.h" #include "library/placeholder.h"
#include "frontends/lean/notation.h" #include "frontends/lean/notation.h"
@ -75,8 +75,7 @@ static format g_in_fmt = highlight_keyword(format("in"));
static format g_assign_fmt = highlight_keyword(format(":=")); static format g_assign_fmt = highlight_keyword(format(":="));
static format g_geq_fmt = format("\u2265"); static format g_geq_fmt = format("\u2265");
static format g_lift_fmt = highlight_keyword(format("lift")); static format g_lift_fmt = highlight_keyword(format("lift"));
static format g_lower_fmt = highlight_keyword(format("lower")); static format g_inst_fmt = highlight_keyword(format("inst"));
static format g_subst_fmt = highlight_keyword(format("subst"));
static name g_pp_max_depth {"lean", "pp", "max_depth"}; static name g_pp_max_depth {"lean", "pp", "max_depth"};
static name g_pp_max_steps {"lean", "pp", "max_steps"}; static name g_pp_max_steps {"lean", "pp", "max_steps"};
@ -129,6 +128,24 @@ name get_unused_name(expr const & e) {
return n1; return n1;
} }
/**
\brief Replace free variable \c 0 in \c a with the name \c n.
\remark Metavariable context is ignored.
*/
expr replace_var_with_name(expr const & a, name const & n) {
expr c = mk_constant(n);
auto f = [=](expr const & m, unsigned offset) -> expr {
if (is_var(m)) {
unsigned vidx = var_idx(m);
if (vidx >= offset)
return vidx == offset ? c : mk_var(vidx - 1);
}
return m;
};
return replace_fn<decltype(f)>(f)(a);
}
/** \brief Functional object for pretty printing expressions */ /** \brief Functional object for pretty printing expressions */
class pp_fn { class pp_fn {
typedef scoped_map<expr, name, expr_hash, expr_eqp> aliases; typedef scoped_map<expr, name, expr_hash, expr_eqp> aliases;
@ -288,7 +305,7 @@ class pp_fn {
name n1 = get_unused_name(lambda); name n1 = get_unused_name(lambda);
m_local_names.insert(n1); m_local_names.insert(n1);
r.push_back(mk_pair(n1, abst_domain(lambda))); r.push_back(mk_pair(n1, abst_domain(lambda)));
expr b = instantiate_with_closed(abst_body(lambda), mk_constant(n1)); expr b = replace_var_with_name(abst_body(lambda), n1);
if (is_quant_expr(b, is_forall)) if (is_quant_expr(b, is_forall))
return collect_nested_quantifiers(b, is_forall, r); return collect_nested_quantifiers(b, is_forall, r);
else else
@ -696,9 +713,9 @@ class pp_fn {
name n1 = get_unused_name(e); name n1 = get_unused_name(e);
m_local_names.insert(n1); m_local_names.insert(n1);
r.push_back(mk_pair(n1, abst_domain(e))); r.push_back(mk_pair(n1, abst_domain(e)));
expr b = instantiate_with_closed(abst_body(e), mk_constant(n1)); expr b = replace_var_with_name(abst_body(e), n1);
if (T) if (T)
T = instantiate_with_closed(abst_body(T), mk_constant(n1)); T = replace_var_with_name(abst_body(T), n1);
return collect_nested(b, T, k, r); return collect_nested(b, T, k, r);
} else { } else {
return mk_pair(e, T); return mk_pair(e, T);
@ -931,7 +948,7 @@ class pp_fn {
name n1 = get_unused_name(e); name n1 = get_unused_name(e);
m_local_names.insert(n1); m_local_names.insert(n1);
bindings.push_back(std::make_tuple(n1, let_type(e), let_value(e))); bindings.push_back(std::make_tuple(n1, let_type(e), let_value(e)));
expr b = instantiate_with_closed(let_body(e), mk_constant(n1)); expr b = replace_var_with_name(let_body(e), n1);
return collect_nested_let(b, bindings); return collect_nested_let(b, bindings);
} else { } else {
return e; return e;
@ -1017,18 +1034,17 @@ class pp_fn {
format e_fmt; format e_fmt;
switch (e.kind()) { switch (e.kind()) {
case meta_entry_kind::Lift: e_fmt = format{g_lift_fmt, colon(), format(e.s()), colon(), format(e.n())}; break; case meta_entry_kind::Lift: e_fmt = format{g_lift_fmt, colon(), format(e.s()), colon(), format(e.n())}; break;
case meta_entry_kind::Lower: e_fmt = format{g_lower_fmt, colon(), format(e.s()), colon(), format(e.n())}; break; case meta_entry_kind::Inst: {
case meta_entry_kind::Subst: {
auto p_e = pp_child_with_paren(e.v(), depth); auto p_e = pp_child_with_paren(e.v(), depth);
r_weight += p_e.second; r_weight += p_e.second;
e_fmt = format{g_subst_fmt, colon(), format(e.s()), space(), nest(m_indent, p_e.first)}; e_fmt = format{g_inst_fmt, colon(), format(e.s()), space(), nest(m_indent, p_e.first)};
break; break;
}} }}
if (first) { if (first) {
ctx_fmt = e_fmt; ctx_fmt = e_fmt;
first = false; first = false;
} else { } else {
ctx_fmt += compose(line(), e_fmt); ctx_fmt += format{comma(), line(), e_fmt};
} }
} }
return mk_result(group(compose(mv_fmt, nest(m_indent, format{lsb(), ctx_fmt, rsb()}))), r_weight); return mk_result(group(compose(mv_fmt, nest(m_indent, format{lsb(), ctx_fmt, rsb()}))), r_weight);
@ -1195,7 +1211,7 @@ class pp_formatter_cell : public formatter_cell {
} else { } else {
r += format{line(), group(entry)}; r += format{line(), group(entry)};
} }
c2 = instantiate_with_closed(fake_context_rest(c2), mk_constant(n1)); c2 = replace_var_with_name(fake_context_rest(c2), n1);
} }
if (include_e) { if (include_e) {
if (first) if (first)
@ -1319,7 +1335,7 @@ public:
name n1 = get_unused_name(c2); name n1 = get_unused_name(c2);
fn.register_local(n1); fn.register_local(n1);
expr const & rest = fake_context_rest(c2); expr const & rest = fake_context_rest(c2);
c2 = instantiate_with_closed(rest, mk_constant(n1)); c2 = replace_var_with_name(rest, n1);
} }
return fn(c2); return fn(c2);
} }

View file

@ -13,8 +13,8 @@ Author: Leonardo de Moura
#include "kernel/expr_eq.h" #include "kernel/expr_eq.h"
namespace lean { namespace lean {
meta_entry::meta_entry(meta_entry_kind k, unsigned s, unsigned n):m_kind(k), m_s(s), m_n(n) {} meta_entry::meta_entry(unsigned s, unsigned n):m_kind(meta_entry_kind::Lift), m_s(s), m_n(n) {}
meta_entry::meta_entry(unsigned s, expr const & v):m_kind(meta_entry_kind::Subst), m_s(s), m_v(v) {} meta_entry::meta_entry(unsigned s, expr const & v):m_kind(meta_entry_kind::Inst), m_s(s), m_v(v) {}
meta_entry::~meta_entry() {} meta_entry::~meta_entry() {}
unsigned hash_args(unsigned size, expr const * args) { unsigned hash_args(unsigned size, expr const * args) {

View file

@ -36,8 +36,7 @@ class value;
meta_ctx ::= [meta_entry] meta_ctx ::= [meta_entry]
meta_entry ::= lift idx idx meta_entry ::= lift idx idx
| lower idx idx | inst idx expr
| subst idx expr
TODO(Leo): match expressions. TODO(Leo): match expressions.
@ -248,27 +247,26 @@ public:
/** /**
\see meta_entry \see meta_entry
*/ */
enum class meta_entry_kind { Lift, Lower, Subst }; enum class meta_entry_kind { Lift, Inst };
/** /**
\brief An entry in a metavariable context. \brief An entry in a metavariable context.
It represents objects of the form: It represents objects of the form:
<code> <code>
| Lift s n | Lift s n
| Lower s n | Inst s v
| Subst s v
</code> </code>
where \c s and \c n are unsigned integers, and where \c s and \c n are unsigned integers, and
\c v is an expression \c v is an expression
The meaning of <tt>Lift s n</tt> is: lift the free variables greater than or equal to \c s by \c n. The meaning of <tt>Lift s n</tt> is: lift the free variables greater than or equal to \c s by \c n.
The meaning of <tt>Lower s n</tt> is: lower the free variables greater than or equal to \c s by \c n. The meaning of <tt>Inst s v</tt> is: instantiate free variable \c s with the expression \c v, and
The meaning of <tt>Subst s v</tt> is: substitute the free variable \c s with the expression \c v. lower free variables greater than \c s.
The metavariable context records operations that must be applied The metavariable context records operations that must be applied
whenever we substitute a metavariable with an actual expression. whenever we substitute a metavariable with an actual expression.
For example, let ?M be a metavariable with context For example, let ?M be a metavariable with context
<code> <code>
[ Lower 1 1, Subst 0 a, Lift 1 2 ] [ Inst 0 a, Lift 1 2 ]
</code> </code>
Now, assume we want to instantiate \c ?M with <tt>f #0 (g #2)</tt>. Now, assume we want to instantiate \c ?M with <tt>f #0 (g #2)</tt>.
Then, we apply the metavariable entries from right to left. Then, we apply the metavariable entries from right to left.
@ -276,11 +274,7 @@ enum class meta_entry_kind { Lift, Lower, Subst };
<code> <code>
f #0 (g #4) f #0 (g #4)
</code> </code>
Then, we apply <tt>(Subst 0 a)</tt> and produce Then, we apply <tt>(Inst 0 a)</tt> and produce
<code>
f a (g #4)
</code>
Finally, we apply <tt>(Lower 1 1)</tt> and get the final result
<code> <code>
f a (g #3) f a (g #3)
</code> </code>
@ -290,22 +284,20 @@ class meta_entry {
unsigned m_s; unsigned m_s;
unsigned m_n; unsigned m_n;
expr m_v; expr m_v;
meta_entry(meta_entry_kind k, unsigned s, unsigned n); meta_entry(unsigned s, unsigned n);
meta_entry(unsigned s, expr const & v); meta_entry(unsigned s, expr const & v);
public: public:
~meta_entry(); ~meta_entry();
friend meta_entry mk_lift(unsigned s, unsigned n); friend meta_entry mk_lift(unsigned s, unsigned n);
friend meta_entry mk_lower(unsigned s, unsigned n); friend meta_entry mk_inst(unsigned s, expr const & v);
friend meta_entry mk_subst(unsigned s, expr const & v);
meta_entry_kind kind() const { return m_kind; } meta_entry_kind kind() const { return m_kind; }
bool is_subst() const { return kind() == meta_entry_kind::Subst; } bool is_inst() const { return kind() == meta_entry_kind::Inst; }
unsigned s() const { return m_s; } unsigned s() const { return m_s; }
unsigned n() const { lean_assert(kind() != meta_entry_kind::Subst); return m_n; } unsigned n() const { lean_assert(kind() == meta_entry_kind::Lift); return m_n; }
expr const & v() const { lean_assert(kind() == meta_entry_kind::Subst); return m_v; } expr const & v() const { lean_assert(kind() == meta_entry_kind::Inst); return m_v; }
}; };
inline meta_entry mk_lift(unsigned s, unsigned n) { return meta_entry(meta_entry_kind::Lift, s, n); } inline meta_entry mk_lift(unsigned s, unsigned n) { return meta_entry(s, n); }
inline meta_entry mk_lower(unsigned s, unsigned n) { return meta_entry(meta_entry_kind::Lower, s, n); } inline meta_entry mk_inst(unsigned s, expr const & v) { return meta_entry(s, v); }
inline meta_entry mk_subst(unsigned s, expr const & v) { return meta_entry(s, v); }
/** \brief Metavariables */ /** \brief Metavariables */
class expr_metavar : public expr_cell { class expr_metavar : public expr_cell {
@ -586,7 +578,7 @@ template<typename F> expr update_metavar(expr const & e, unsigned i, F f) {
meta_entry new_me = f(me); meta_entry new_me = f(me);
if (new_me.kind() != me.kind() || new_me.s() != me.s()) { if (new_me.kind() != me.kind() || new_me.s() != me.s()) {
modified = true; modified = true;
} else if (new_me.is_subst()) { } else if (new_me.is_inst()) {
if (!is_eqp(new_me.v(), me.v())) if (!is_eqp(new_me.v(), me.v()))
modified = true; modified = true;
} else if (new_me.n() != me.n()) { } else if (new_me.n() != me.n()) {

View file

@ -68,7 +68,7 @@ class expr_eq_fn {
compare(metavar_ctx(a), metavar_ctx(b), [&](meta_entry const & e1, meta_entry const & e2) { compare(metavar_ctx(a), metavar_ctx(b), [&](meta_entry const & e1, meta_entry const & e2) {
if (e1.kind() != e2.kind() || e1.s() != e2.s()) if (e1.kind() != e2.kind() || e1.s() != e2.s())
return false; return false;
if (e1.is_subst()) if (e1.is_inst())
return apply(e1.v(), e2.v()); return apply(e1.v(), e2.v());
else else
return e1.n() == e2.n(); return e1.n() == e2.n();

View file

@ -175,13 +175,15 @@ bool has_free_var(expr const & e, unsigned low, unsigned high) {
} }
expr lower_free_vars(expr const & e, unsigned s, unsigned d) { expr lower_free_vars(expr const & e, unsigned s, unsigned d) {
lean_assert(d > 0); lean_assert(s >= d);
lean_assert(!has_free_var(e, s-d, s));
auto f = [=](expr const & e, unsigned offset) -> expr { auto f = [=](expr const & e, unsigned offset) -> expr {
if (is_var(e) && var_idx(e) >= s + offset) { if (is_var(e) && var_idx(e) >= s + offset) {
lean_assert(var_idx(e) >= offset + d); lean_assert(var_idx(e) >= offset + d);
return mk_var(var_idx(e) - d); return mk_var(var_idx(e) - d);
} else if (is_metavar(e)) { } else if (is_metavar(e)) {
return add_lower(e, s + offset, d); lean_unreachable();
return e;
} else { } else {
return e; return e;
} }

View file

@ -35,7 +35,7 @@ bool has_free_var(expr const & e, unsigned low, unsigned high);
\pre !has_free_var(e, 0, d) \pre !has_free_var(e, 0, d)
*/ */
expr lower_free_vars(expr const & e, unsigned s, unsigned d); expr lower_free_vars(expr const & e, unsigned s, unsigned d);
inline expr lower_free_vars(expr const & e, unsigned d) { return lower_free_vars(e, 0, d); } inline expr lower_free_vars(expr const & e, unsigned d) { return lower_free_vars(e, d, d); }
/** /**
\brief Lift free variables >= s in \c e by d. \brief Lift free variables >= s in \c e by d.

View file

@ -27,21 +27,21 @@ expr instantiate_with_closed(expr const & a, unsigned n, expr const * s) {
} else if (is_metavar(m)) { } else if (is_metavar(m)) {
expr r = m; expr r = m;
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
r = add_subst(r, offset + i, s[n - i - 1]); r = add_inst(r, offset + n - i - 1, s[i]);
return add_lower(r, offset + n, n); return r;
} else { } else {
return m; return m;
} }
}; };
return replace_fn<decltype(f)>(f)(a); return replace_fn<decltype(f)>(f)(a);
} }
expr instantiate(expr const & a, unsigned n, expr const * s) { expr instantiate(expr const & a, unsigned s, unsigned n, expr const * subst) {
auto f = [=](expr const & m, unsigned offset) -> expr { auto f = [=](expr const & m, unsigned offset) -> expr {
if (is_var(m)) { if (is_var(m)) {
unsigned vidx = var_idx(m); unsigned vidx = var_idx(m);
if (vidx >= offset) { if (vidx >= offset + s) {
if (vidx < offset + n) if (vidx < offset + s + n)
return lift_free_vars(s[n - (vidx - offset) - 1], offset); return lift_free_vars(subst[n - (vidx - s - offset) - 1], offset);
else else
return mk_var(vidx - n); return mk_var(vidx - n);
} else { } else {
@ -50,12 +50,18 @@ expr instantiate(expr const & a, unsigned n, expr const * s) {
} else if (is_metavar(m)) { } else if (is_metavar(m)) {
expr r = m; expr r = m;
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
r = add_subst(r, offset + i, lift_free_vars(s[n - i - 1], offset + n)); r = add_inst(r, offset + s + n - i - 1, lift_free_vars(subst[i], offset + n - i - 1));
return add_lower(r, offset + n, n); return r;
} else { } else {
return m; return m;
} }
}; };
return replace_fn<decltype(f)>(f)(a); return replace_fn<decltype(f)>(f)(a);
} }
expr instantiate(expr const & e, unsigned n, expr const * s) {
return instantiate(e, 0, n, s);
}
expr instantiate(expr const & e, unsigned i, expr const & s) {
return instantiate(e, i, 1, &s);
}
} }

View file

@ -25,4 +25,8 @@ inline expr instantiate_with_closed(expr const & e, expr const & s) { return ins
expr instantiate(expr const & e, unsigned n, expr const * s); expr instantiate(expr const & e, unsigned n, expr const * s);
inline expr instantiate(expr const & e, std::initializer_list<expr> const & l) { return instantiate(e, l.size(), l.begin()); } inline expr instantiate(expr const & e, std::initializer_list<expr> const & l) { return instantiate(e, l.size(), l.begin()); }
inline expr instantiate(expr const & e, expr const & s) { return instantiate(e, 1, &s); } inline expr instantiate(expr const & e, expr const & s) { return instantiate(e, 1, &s); }
/**
\brief Replace free variable \c i with \c s in \c e.
*/
expr instantiate(expr const & e, unsigned i, expr const & s);
} }

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include "kernel/metavar.h" #include "kernel/metavar.h"
#include "kernel/replace.h" #include "kernel/replace.h"
#include "kernel/free_vars.h" #include "kernel/free_vars.h"
#include "kernel/instantiate.h"
#include "kernel/occurs.h" #include "kernel/occurs.h"
#include "kernel/for_each.h" #include "kernel/for_each.h"
@ -66,31 +67,13 @@ void metavar_env::assign(unsigned midx, expr const & v) {
m_env[midx] = data(v, p->m_type, p->m_ctx); m_env[midx] = data(v, p->m_type, p->m_ctx);
} }
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) { expr instantiate(expr const & s, meta_ctx const & ctx, metavar_env const & env) {
if (ctx) { if (ctx) {
expr r = instantiate(s, tail(ctx), env); expr r = instantiate(s, tail(ctx), env);
meta_entry const & e = head(ctx); meta_entry const & e = head(ctx);
switch (e.kind()) { switch (e.kind()) {
case meta_entry_kind::Lift: return lift_free_vars(r, e.s(), e.n()); 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::Inst: return ::lean::instantiate(r, e.s(), instantiate_metavars(e.v(), env));
case meta_entry_kind::Subst: return subst(r, e.s(), instantiate_metavars(e.v(), env));
} }
lean_unreachable(); lean_unreachable();
return s; return s;
@ -143,69 +126,23 @@ expr add_lift(expr const & m, unsigned s, unsigned n) {
return mk_metavar(metavar_idx(m), add_lift(metavar_ctx(m), s, n)); return mk_metavar(metavar_idx(m), add_lift(metavar_ctx(m), s, n));
} }
meta_ctx add_lower(meta_ctx const & ctx, unsigned s2, unsigned n2) { meta_ctx add_inst(meta_ctx const & ctx, unsigned s, expr const & v) {
if (ctx) { if (ctx) {
meta_entry e = head(ctx); meta_entry e = head(ctx);
unsigned s1, n1; if (e.kind() == meta_entry_kind::Lift) {
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()) { if (e.s() <= s && s < e.s() + e.n()) {
return ctx; if (e.n() == 1)
} else if (s < e.s() && !has_free_var(v, e.s(), std::numeric_limits<unsigned>::max())) { return tail(ctx);
return cons(e, add_subst(tail(ctx), s, v)); else
} else if (s >= e.s() + e.n() && !has_free_var(v, e.s(), std::numeric_limits<unsigned>::max())) { return add_lift(tail(ctx), e.s(), e.n() - 1);
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);
} }
return cons(mk_inst(s, v), ctx);
} }
expr add_subst(expr const & m, unsigned s, expr const & v) { expr add_inst(expr const & m, unsigned s, expr const & v) {
return mk_metavar(metavar_idx(m), add_subst(metavar_ctx(m), s, v)); return mk_metavar(metavar_idx(m), add_inst(metavar_ctx(m), s, v));
} }
bool has_context(expr const & m) { bool has_context(expr const & m) {

View file

@ -163,31 +163,16 @@ meta_ctx add_lift(meta_ctx const & ctx, unsigned s, unsigned n);
expr add_lift(expr const & m, unsigned s, unsigned n); expr add_lift(expr const & m, unsigned s, unsigned n);
/** /**
\brief Add a lower:s:n operation to the context of the given metavariable. \brief Add an inst:s:v operation to the context of the given metavariable.
\pre is_metavar(m) \pre is_metavar(m)
\pre n <= s
*/ */
expr add_lower(expr const & m, unsigned s, unsigned n); expr add_inst(expr const & m, unsigned s, expr const & v);
/** /**
\brief Extend the context \c ctx with the entry <tt>lower:s:n</tt> \brief Extend the context \c ctx with the entry <tt>inst:s v</tt>
*/ */
meta_ctx add_lower(meta_ctx const & ctx, unsigned s, unsigned n); meta_ctx add_inst(meta_ctx const & ctx, unsigned s, expr const & v);
/**
\brief Add a subst:s:v operation to the context of the given metavariable.
\pre is_metavar(m)
\pre !occurs(m, v)
*/
expr add_subst(expr const & m, unsigned s, expr const & v);
/**
\brief Extend the context \c ctx with the entry <tt>subst:s v</tt>
*/
meta_ctx add_subst(meta_ctx const & ctx, unsigned s, expr const & v);
/** /**
\brief Return true iff the given metavariable has a non-empty \brief Return true iff the given metavariable has a non-empty

View file

@ -141,46 +141,6 @@ class normalizer::imp {
return expr(); return expr();
} }
bool is_identity_stack(value_stack const & s, unsigned k) {
if (length(s) != k)
return false;
unsigned i = 0;
for (auto e : s) {
if (e.kind() != svalue_kind::BoundedVar || k - to_bvar(e) - 1 != i)
return false;
++i;
}
return true;
}
/**
\brief Update the metavariable context for \c m based on the
value_stack \c s and the number of binders \c k.
\pre is_metavar(m)
*/
expr updt_metavar(expr const & m, value_stack const & s, unsigned k) {
lean_assert(is_metavar(m));
if (is_identity_stack(s, k))
return m;
meta_ctx ctx = metavar_ctx(m);
unsigned midx = metavar_idx(m);
unsigned s_len = length(s);
unsigned i = 0;
ctx = add_lift(ctx, s_len, s_len);
for (auto e : s) {
ctx = add_subst(ctx, i, lift_free_vars(reify(e, k), s_len));
++i;
}
ctx = add_lower(ctx, s_len, s_len);
unsigned m_ctx_len = m_ctx.size();
lean_assert(s_len + m_ctx_len >= k);
if (s_len + m_ctx_len > k)
ctx = add_lower(ctx, s_len, s_len + m_ctx_len - k);
return mk_metavar(midx, ctx);
}
/** \brief Normalize the expression \c a in a context composed of stack \c s and \c k binders. */ /** \brief Normalize the expression \c a in a context composed of stack \c s and \c k binders. */
svalue normalize(expr const & a, value_stack const & s, unsigned k) { svalue normalize(expr const & a, value_stack const & s, unsigned k) {
flet<unsigned> l(m_depth, m_depth+1); flet<unsigned> l(m_depth, m_depth+1);
@ -201,7 +161,8 @@ class normalizer::imp {
if (m_menv && m_menv->contains(a) && m_menv->is_assigned(a)) { if (m_menv && m_menv->contains(a) && m_menv->is_assigned(a)) {
r = normalize(m_menv->get_subst(a), s, k); r = normalize(m_menv->get_subst(a), s, k);
} else { } else {
r = svalue(updt_metavar(a, s, k)); // TODO(Leo): update metavariable
r = svalue(a);
} }
break; break;
case expr_kind::Var: case expr_kind::Var:

View file

@ -42,8 +42,8 @@ class deep_copy_fn {
} }
case expr_kind::MetaVar: case expr_kind::MetaVar:
r = update_metavar(a, [&](meta_entry const & e) -> meta_entry { r = update_metavar(a, [&](meta_entry const & e) -> meta_entry {
if (e.is_subst()) if (e.is_inst())
return mk_subst(e.s(), apply(e.v())); return mk_inst(e.s(), apply(e.v()));
else else
return e; return e;
}); });

View file

@ -64,8 +64,8 @@ struct max_sharing_fn::imp {
} }
case expr_kind::MetaVar: { case expr_kind::MetaVar: {
expr r = update_metavar(a, [=](meta_entry const & e) -> meta_entry { expr r = update_metavar(a, [=](meta_entry const & e) -> meta_entry {
if (e.is_subst()) if (e.is_inst())
return mk_subst(e.s(), apply(e.v())); return mk_inst(e.s(), apply(e.v()));
else else
return e; return e;
}); });

View file

@ -84,8 +84,7 @@ struct print_expr_fn {
if (first) first = false; else out() << ", "; if (first) first = false; else out() << ", ";
switch (e.kind()) { switch (e.kind()) {
case meta_entry_kind::Lift: out() << "lift:" << e.s() << ":" << e.n(); break; case meta_entry_kind::Lift: out() << "lift:" << e.s() << ":" << e.n(); break;
case meta_entry_kind::Lower: out() << "lower:" << e.s() << ":" << e.n(); break; case meta_entry_kind::Inst: out() << "inst:" << e.s() << " "; print_child(e.v(), c); break;
case meta_entry_kind::Subst: out() << "subst:" << e.s() << " "; print_child(e.v(), c); break;
} }
} }
out() << "]"; out() << "]";

View file

@ -72,14 +72,14 @@ static void tst2() {
expr m1 = menv.mk_metavar(); expr m1 = menv.mk_metavar();
expr m2 = menv.mk_metavar(); expr m2 = menv.mk_metavar();
// move m1 to a different context, and store new metavariable + context in m11 // move m1 to a different context, and store new metavariable + context in m11
expr m11 = add_lower(add_subst(m1, 0, f(a, m2)), 1, 1); std::cout << "---------------------\n";
expr m11 = add_inst(m1, 0, f(a, m2));
std::cout << m11 << "\n"; std::cout << m11 << "\n";
menv.assign(m1, f(Var(0))); menv.assign(m1, f(Var(0)));
std::cout << instantiate_metavars(m11, menv) << "\n"; std::cout << instantiate_metavars(m11, menv) << "\n";
lean_assert(instantiate_metavars(m11, menv) == f(f(a, add_lower(m2, 1, 1))));
menv.assign(m2, g(a, Var(1))); menv.assign(m2, g(a, Var(1)));
std::cout << instantiate_metavars(h(m11), menv) << "\n"; std::cout << instantiate_metavars(h(m11), menv) << "\n";
lean_assert(instantiate_metavars(h(m11), menv) == h(f(f(a, g(a, Var(0)))))); lean_assert(instantiate_metavars(h(m11), menv) == h(f(f(a, g(a, Var(1))))));
} }
static void tst3() { static void tst3() {
@ -115,34 +115,7 @@ static void tst4() {
} }
static void tst5() { static void tst5() {
metavar_env menv; return;
expr m1 = menv.mk_metavar();
expr f = Const("f");
expr m11 = add_lower(m1, 2, 1);
std::cout << add_subst(add_lower(m1, 2, 1), 1, f(Var(0))) << "\n";
std::cout << add_subst(add_lower(m1, 2, 1), 1, f(Var(3))) << "\n";
std::cout << add_subst(add_lower(m1, 2, 1), 3, f(Var(0))) << "\n";
std::cout << add_subst(add_lower(add_lower(m1, 2, 1), 3, 1), 3, f(Var(0))) << "\n";
std::cout << add_lower(add_lift(m1, 1, 1), 1, 1) << "\n";
std::cout << add_lower(add_lift(m1, 1, 1), 2, 1) << "\n";
std::cout << add_lower(add_lift(m1, 1, 1), 2, 2) << "\n";
std::cout << add_lower(add_lift(m1, 1, 3), 2, 2) << "\n";
std::cout << add_subst(add_lift(m1, 1, 1), 0, f(Var(0))) << "\n";
std::cout << add_subst(add_lift(m1, 1, 1), 1, f(Var(0))) << "\n";
lean_assert(add_subst(add_lower(m1, 2, 1), 1, f(Var(0))) ==
add_lower(add_subst(m1, 1, f(Var(0))), 2, 1));
lean_assert(add_subst(add_lower(m1, 2, 1), 1, f(Var(3))) ==
add_lower(add_subst(m1, 1, f(Var(4))), 2, 1));
lean_assert(add_subst(add_lower(m1, 2, 1), 2, f(Var(0))) ==
add_lower(add_subst(m1, 3, f(Var(0))), 2, 1));
lean_assert(add_subst(add_lower(add_lower(m1, 2, 1), 3, 1), 3, f(Var(0))) ==
add_lower(add_lower(add_subst(m1, 5, f(Var(0))), 2, 1), 3, 1));
lean_assert(add_lower(add_lift(m1, 1, 1), 2, 1) == m1);
lean_assert(add_lower(add_lift(m1, 1, 3), 2, 2) == add_lift(m1, 1, 1));
lean_assert(add_subst(add_lift(m1, 1, 1), 0, f(Var(0))) ==
add_lift(add_subst(m1, 0, f(Var(0))), 1, 1));
lean_assert(add_subst(add_lift(m1, 1, 1), 1, f(Var(0))) ==
add_lift(m1, 1, 1));
} }
static void tst6() { static void tst6() {
@ -256,6 +229,7 @@ static void tst12() {
std::cout << instantiate(f(m), {Var(1), Var(0)}) << "\n"; std::cout << instantiate(f(m), {Var(1), Var(0)}) << "\n";
} }
#if 0
static void tst13() { static void tst13() {
environment env; environment env;
metavar_env menv; metavar_env menv;
@ -384,6 +358,7 @@ static void tst17() {
lean_assert(instantiate_metavars(norm(F, ctx), menv2) == lean_assert(instantiate_metavars(norm(F, ctx), menv2) ==
norm(instantiate_metavars(F, menv2), ctx)); norm(instantiate_metavars(F, menv2), ctx));
} }
#endif
int main() { int main() {
tst1(); tst1();
@ -398,11 +373,11 @@ int main() {
tst10(); tst10();
tst11(); tst11();
tst12(); tst12();
tst13(); // tst13();
tst14(); // tst14();
tst15(); // tst15();
tst16(); // tst16();
tst17(); // tst17();
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }

View file

@ -19,7 +19,7 @@ Function type:
Π (A : Type), A → A Π (A : Type), A → A
Arguments types: Arguments types:
A : Type A : Type
x : ?M0 x : ?M0[lift:0:2]
Elaborator state Elaborator state
#0 ≈ ?M0[lift:0:2] #0 ≈ ?M0[lift:0:2]
Assumed: eq Assumed: eq
@ -29,8 +29,8 @@ Function type:
Π (A : Type), A → A → Bool Π (A : Type), A → A → Bool
Arguments types: Arguments types:
C : Type C : Type
a : ?M0[lower:5:5 lift:0:3 subst:0 B subst:1 A] a : ?M0[lift:0:3]
b : ?M2[lower:5:5 lift:0:2 subst:0 a subst:1 B subst:2 A] b : ?M2[lift:0:2]
Elaborator state Elaborator state
#0 ≈ ?M2[lift:0:2] #0 ≈ ?M2[lift:0:2]
#0 ≈ ?M0[lift:0:3] #0 ≈ ?M0[lift:0:3]

View file

@ -15,8 +15,8 @@ Candidates:
Int::add : Int::add :
Nat::add : Nat::add :
Arguments: Arguments:
a : ?M0 a : ?M0[lift:0:2]
b : ?M2[lower:2:2 lift:0:1 subst:0 a] b : ?M2[lift:0:1]
λ a b c : , a + c + b λ a b c : , a + c + b
Error (line: 17, pos: 19) ambiguous overloads Error (line: 17, pos: 19) ambiguous overloads
Candidates: Candidates:
@ -24,7 +24,7 @@ Candidates:
Int::add : Int::add :
Nat::add : Nat::add :
Arguments: Arguments:
a : ?M0 a : ?M0[lift:0:2]
b : ?M2[lower:2:2 lift:0:1 subst:0 a] b : ?M2[lift:0:1]
Assumed: x Assumed: x
λ a b : , a + x + b λ a b : , a + x + b

View file

@ -8,7 +8,7 @@ Function type:
Π (A : Type), A → Bool Π (A : Type), A → Bool
Arguments types: Arguments types:
B : Type B : Type
a : ?M0[lower:3:3 lift:0:2 subst:0 A] a : ?M0[lift:0:2]
Elaborator state Elaborator state
#0 ≈ ?M0[lift:0:2] #0 ≈ ?M0[lift:0:2]
Assumed: myeq Assumed: myeq