refactor(metavar): implement metavar_env, and use unification_constraint and trace objects in the type_checker, light_checker

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-10-01 17:25:17 -07:00
parent 1f0eab7a14
commit 7cf83800c0
25 changed files with 649 additions and 614 deletions

View file

@ -39,6 +39,7 @@ public:
context_entry const & lookup(unsigned vidx) const; context_entry const & lookup(unsigned vidx) const;
std::pair<context_entry const &, context> lookup_ext(unsigned vidx) const; std::pair<context_entry const &, context> lookup_ext(unsigned vidx) const;
bool empty() const { return is_nil(m_list); } bool empty() const { return is_nil(m_list); }
operator bool() const { return !empty(); }
unsigned size() const { return length(m_list); } unsigned size() const { return length(m_list); }
typedef list<context_entry>::iterator iterator; typedef list<context_entry>::iterator iterator;
iterator begin() const { return m_list.begin(); } iterator begin() const { return m_list.begin(); }

View file

@ -235,7 +235,7 @@ struct environment::imp {
infer_universe and infer_type expect an environment instead of environment::imp. infer_universe and infer_type expect an environment instead of environment::imp.
*/ */
void check_type(name const & n, expr const & t, expr const & v, environment const & env) { void check_type(name const & n, expr const & t, expr const & v, environment const & env) {
m_type_checker.infer_universe(t); m_type_checker.check_type(t);
expr v_t = m_type_checker.infer_type(v); expr v_t = m_type_checker.infer_type(v);
if (!m_type_checker.is_convertible(v_t, t)) if (!m_type_checker.is_convertible(v_t, t))
throw def_type_mismatch_exception(env, n, t, v, v_t); throw def_type_mismatch_exception(env, n, t, v, v_t);
@ -296,14 +296,14 @@ struct environment::imp {
/** \brief Add new axiom. */ /** \brief Add new axiom. */
void add_axiom(name const & n, expr const & t, environment const & env) { void add_axiom(name const & n, expr const & t, environment const & env) {
check_name(n, env); check_name(n, env);
m_type_checker.infer_universe(t); m_type_checker.check_type(t);
register_named_object(mk_axiom(n, t)); register_named_object(mk_axiom(n, t));
} }
/** \brief Add new variable. */ /** \brief Add new variable. */
void add_var(name const & n, expr const & t, environment const & env) { void add_var(name const & n, expr const & t, environment const & env) {
check_name(n, env); check_name(n, env);
m_type_checker.infer_universe(t); m_type_checker.check_type(t);
register_named_object(mk_var_decl(n, t)); register_named_object(mk_var_decl(n, t));
} }

View file

@ -137,21 +137,10 @@ expr_value::expr_value(value & v):
expr_value::~expr_value() { expr_value::~expr_value() {
m_val.dec_ref(); m_val.dec_ref();
} }
expr_metavar::expr_metavar(name const & n, expr const & t, local_context const & lctx): expr_metavar::expr_metavar(name const & n, local_context const & lctx):
expr_cell(expr_kind::MetaVar, n.hash(), true), expr_cell(expr_kind::MetaVar, n.hash(), true),
m_name(n), m_type(t), m_lctx(lctx) {} m_name(n), m_lctx(lctx) {}
expr_metavar::~expr_metavar() {} expr_metavar::~expr_metavar() {}
expr expr_metavar::get_type() const {
if (m_type && get_lctx()) {
if (is_metavar(m_type)) {
return update_metavar(m_type, append(get_lctx(), metavar_lctx(m_type)));
} else {
return apply_local_context(m_type, get_lctx());
}
} else {
return m_type;
}
}
void expr_cell::dealloc() { void expr_cell::dealloc() {
switch (kind()) { switch (kind()) {
@ -192,7 +181,7 @@ expr copy(expr const & a) {
case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a));
case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a));
case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a)); case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a));
case expr_kind::MetaVar: return mk_metavar(metavar_name(a), metavar_raw_type(a), metavar_lctx(a)); case expr_kind::MetaVar: return mk_metavar(metavar_name(a), metavar_lctx(a));
} }
lean_unreachable(); lean_unreachable();
} }

View file

@ -31,7 +31,7 @@ class value;
| Type universe | Type universe
| Eq expr expr (heterogeneous equality) | Eq expr expr (heterogeneous equality)
| Let name expr expr expr | Let name expr expr expr
| Metavar name expr? local_context (the expression is the type of the metavariable) | Metavar name local_context
local_context ::= [local_entry] local_context ::= [local_entry]
@ -121,7 +121,7 @@ public:
friend expr mk_pi(name const & n, expr const & t, expr const & e); friend expr mk_pi(name const & n, expr const & t, expr const & e);
friend expr mk_type(level const & l); friend expr mk_type(level const & l);
friend expr mk_let(name const & n, expr const & t, expr const & v, expr const & e); friend expr mk_let(name const & n, expr const & t, expr const & v, expr const & e);
friend expr mk_metavar(name const & n, expr const & t, local_context const & ctx); friend expr mk_metavar(name const & n, local_context const & ctx);
friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; } friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
@ -314,15 +314,11 @@ inline local_entry mk_inst(unsigned s, expr const & v) { return local_entry(s, v
/** \brief Metavariables */ /** \brief Metavariables */
class expr_metavar : public expr_cell { class expr_metavar : public expr_cell {
name m_name; name m_name;
expr m_type;
local_context m_lctx; local_context m_lctx;
public: public:
expr_metavar(name const & n, expr const & t, local_context const & lctx); expr_metavar(name const & n, local_context const & lctx);
~expr_metavar(); ~expr_metavar();
name const & get_name() const { return m_name; } name const & get_name() const { return m_name; }
expr const & get_raw_type() const { return m_type; }
/* \brief Return the type of the metavariable modulo the associated local context */
expr get_type() const;
local_context const & get_lctx() const { return m_lctx; } local_context const & get_lctx() const { return m_lctx; }
}; };
// ======================================= // =======================================
@ -380,8 +376,8 @@ inline expr mk_type(level const & l) { return expr(new expr_type(l)); }
expr mk_type(); expr mk_type();
inline expr Type(level const & l) { return mk_type(l); } inline expr Type(level const & l) { return mk_type(l); }
inline expr Type() { return mk_type(); } inline expr Type() { return mk_type(); }
inline expr mk_metavar(name const & n, expr const & t = expr(), local_context const & ctx = local_context()) { inline expr mk_metavar(name const & n, local_context const & ctx = local_context()) {
return expr(new expr_metavar(n, t, ctx)); return expr(new expr_metavar(n, ctx));
} }
inline expr expr::operator()(expr const & a1) const { return mk_app({*this, a1}); } inline expr expr::operator()(expr const & a1) const { return mk_app({*this, a1}); }
@ -441,8 +437,6 @@ inline expr const & let_value(expr_cell * e) { return to_let(e)->get
inline expr const & let_type(expr_cell * e) { return to_let(e)->get_type(); } inline expr const & let_type(expr_cell * e) { return to_let(e)->get_type(); }
inline expr const & let_body(expr_cell * e) { return to_let(e)->get_body(); } inline expr const & let_body(expr_cell * e) { return to_let(e)->get_body(); }
inline name const & metavar_name(expr_cell * e) { return to_metavar(e)->get_name(); } inline name const & metavar_name(expr_cell * e) { return to_metavar(e)->get_name(); }
inline expr const & metavar_raw_type(expr_cell * e) { return to_metavar(e)->get_raw_type(); }
inline expr metavar_type(expr_cell * e) { return to_metavar(e)->get_type(); }
inline local_context const & metavar_lctx(expr_cell * e) { return to_metavar(e)->get_lctx(); } inline local_context const & metavar_lctx(expr_cell * e) { return to_metavar(e)->get_lctx(); }
/** \brief Return the reference counter of the given expression. */ /** \brief Return the reference counter of the given expression. */
@ -474,8 +468,6 @@ inline expr const & let_type(expr const & e) { return to_let(e)->ge
inline expr const & let_value(expr const & e) { return to_let(e)->get_value(); } inline expr const & let_value(expr const & e) { return to_let(e)->get_value(); }
inline expr const & let_body(expr const & e) { return to_let(e)->get_body(); } inline expr const & let_body(expr const & e) { return to_let(e)->get_body(); }
inline name const & metavar_name(expr const & e) { return to_metavar(e)->get_name(); } inline name const & metavar_name(expr const & e) { return to_metavar(e)->get_name(); }
inline expr const & metavar_raw_type(expr const & e) { return to_metavar(e)->get_raw_type(); }
inline expr metavar_type(expr const & e) { return to_metavar(e)->get_type(); }
inline local_context const & metavar_lctx(expr const & e) { return to_metavar(e)->get_lctx(); } inline local_context const & metavar_lctx(expr const & e) { return to_metavar(e)->get_lctx(); }
inline bool has_metavar(expr const & e) { return e.has_metavar(); } inline bool has_metavar(expr const & e) { return e.has_metavar(); }
@ -594,9 +586,9 @@ template<typename F> expr update_eq(expr const & e, F f) {
else else
return e; return e;
} }
template<typename F> expr update_metavar(expr const & e, name const & n, expr const & t, F f) { template<typename F> expr update_metavar(expr const & e, name const & n, F f) {
buffer<local_entry> new_entries; buffer<local_entry> new_entries;
bool modified = (n != metavar_name(e) || t != metavar_raw_type(e)); bool modified = n != metavar_name(e);
for (local_entry const & me : metavar_lctx(e)) { for (local_entry const & me : metavar_lctx(e)) {
local_entry new_me = f(me); local_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()) {
@ -610,16 +602,16 @@ template<typename F> expr update_metavar(expr const & e, name const & n, expr co
new_entries.push_back(new_me); new_entries.push_back(new_me);
} }
if (modified) if (modified)
return mk_metavar(n, t, to_list(new_entries.begin(), new_entries.end())); return mk_metavar(n, to_list(new_entries.begin(), new_entries.end()));
else else
return e; return e;
} }
template<typename F> expr update_metavar(expr const & e, F f) { template<typename F> expr update_metavar(expr const & e, F f) {
return update_metavar(e, metavar_name(e), metavar_raw_type(e), f); return update_metavar(e, metavar_name(e), f);
} }
inline expr update_metavar(expr const & e, local_context const & lctx) { inline expr update_metavar(expr const & e, local_context const & lctx) {
if (metavar_lctx(e) != lctx) if (metavar_lctx(e) != lctx)
return mk_metavar(metavar_name(e), metavar_raw_type(e), lctx); return mk_metavar(metavar_name(e), lctx);
else else
return e; return e;
} }

View file

@ -60,7 +60,6 @@ class expr_eq_fn {
case expr_kind::MetaVar: case expr_kind::MetaVar:
return return
metavar_name(a) == metavar_name(b) && metavar_name(a) == metavar_name(b) &&
metavar_raw_type(a) == metavar_raw_type(b) &&
compare(metavar_lctx(a), metavar_lctx(b), [&](local_entry const & e1, local_entry const & e2) { compare(metavar_lctx(a), metavar_lctx(b), [&](local_entry const & e1, local_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;

View file

@ -14,24 +14,8 @@ Author: Leonardo de Moura
#include "kernel/for_each.h" #include "kernel/for_each.h"
namespace lean { namespace lean {
void substitution::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++;
}
substitution::substitution(): substitution::substitution():
m_size(0), m_size(0) {
m_timestamp(0) {
}
bool substitution::operator==(substitution const & s) const {
if (size() != s.size())
return false;
// TODO(Leo)
return true;
} }
bool substitution::is_assigned(name const & m) const { bool substitution::is_assigned(name const & m) const {
@ -45,7 +29,6 @@ bool substitution::is_assigned(expr const & m) const {
void substitution::assign(name const & m, expr const & t) { void substitution::assign(name const & m, expr const & t) {
lean_assert(!is_assigned(m)); lean_assert(!is_assigned(m));
m_subst.insert(m, t); m_subst.insert(m, t);
inc_timestamp();
m_size++; m_size++;
} }
@ -93,20 +76,94 @@ expr substitution::get_subst(expr const & m) const {
static name g_unique_name = name::mk_internal_unique_name(); static name g_unique_name = name::mk_internal_unique_name();
metavar_generator::metavar_generator(name const & prefix): void metavar_env::inc_timestamp() {
m_gen(prefix) { 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_generator::metavar_generator(): metavar_env::metavar_env(name const & prefix):
m_gen(g_unique_name) { m_name_generator(prefix),
m_timestamp(0) {
} }
expr metavar_generator::mk(expr const & t) { metavar_env::metavar_env():
return mk_metavar(m_gen.next(), t, local_context()); metavar_env(g_unique_name) {
} }
expr metavar_generator::mk() { expr metavar_env::mk_metavar(context const & ctx, expr const & type) {
return mk(mk(expr())); inc_timestamp();
name m = m_name_generator.next();
expr r = ::lean::mk_metavar(m);
if (ctx)
m_metavar_contexts.insert(m, ctx);
if (type)
m_metavar_types.insert(m, type);
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));
}
context metavar_env::get_context(name const & m) const {
auto e = const_cast<metavar_env*>(this)->m_metavar_contexts.splay_find(m);
if (e)
return e->second;
else
return context();
}
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) {
auto e = const_cast<metavar_env*>(this)->m_metavar_types.splay_find(m);
if (e) {
return e->second;
} else {
expr t = mk_metavar(get_context(m));
m_metavar_types.insert(m, t);
return t;
}
}
bool metavar_env::is_assigned(name const & m) const {
return m_substitution.is_assigned(m);
}
bool metavar_env::is_assigned(expr const & m) const {
lean_assert(is_metavar(m));
return is_assigned(metavar_name(m));
}
void metavar_env::assign(name const & m, expr const & t, trace const & tr) {
lean_assert(!is_assigned(m));
inc_timestamp();
m_substitution.assign(m, t);
if (tr)
m_metavar_traces.insert(m, tr);
}
void metavar_env::assign(expr const & m, expr const & t, trace const & tr) {
lean_assert(is_metavar(m));
lean_assert(!has_local_context(m));
assign(metavar_name(m), t, tr);
} }
expr instantiate_metavars(expr const & e, substitution const & s) { expr instantiate_metavars(expr const & e, substitution const & s) {

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "util/name_generator.h" #include "util/name_generator.h"
#include "kernel/expr.h" #include "kernel/expr.h"
#include "kernel/context.h" #include "kernel/context.h"
#include "kernel/trace.h"
namespace lean { namespace lean {
/** /**
@ -20,18 +21,9 @@ class substitution {
typedef splay_map<name, expr, name_cmp> name2expr; typedef splay_map<name, expr, name_cmp> name2expr;
name2expr m_subst; name2expr m_subst;
unsigned m_size; unsigned m_size;
unsigned m_timestamp;
void inc_timestamp();
public: public:
substitution(); substitution();
/**
\brief The timestamp is increased whenever the substitution is updated by
\c mk_metavar or \c assign.
*/
unsigned get_timestamp() const { return m_timestamp; }
/** /**
\brief Return the number of assigned metavariables in this substitution. \brief Return the number of assigned metavariables in this substitution.
*/ */
@ -77,9 +69,6 @@ public:
*/ */
expr get_subst(expr const & m) const; expr get_subst(expr const & m) const;
bool operator==(substitution const & s) const;
bool operator!=(substitution const & s) const { return !operator==(s); }
/** /**
\brief Apply f to each entry in this substitution. \brief Apply f to each entry in this substitution.
*/ */
@ -96,17 +85,20 @@ public:
4- Collecting constraints 4- Collecting constraints
*/ */
class metavar_env { class metavar_env {
typedef splay_map<name, expr, name_cmp> name2expr; typedef splay_map<name, expr, name_cmp> name2expr;
typedef splay_map<name, context, name_cmp> name2context; typedef splay_map<name, context, name_cmp> name2context;
typedef splay_map<name, trace, name_cmp> name2trace;
name_generator m_name_generator; name_generator m_name_generator;
substitution m_substitution; substitution m_substitution;
name2expr m_metavar_types; name2expr m_metavar_types;
name2context m_metavar_contexts; name2context m_metavar_contexts;
name2trace m_metavar_traces;
unsigned m_timestamp; unsigned m_timestamp;
void inc_timestamp(); void inc_timestamp();
public: public:
metavar_env(name const & prefix);
metavar_env(); metavar_env();
/** /**
@ -123,13 +115,19 @@ public:
/** /**
\brief Return the context where the given metavariable was created. \brief Return the context where the given metavariable was created.
\pre is_metavar(m) \pre is_metavar(m)
\pre !has_local_context(m)
*/ */
context get_context(expr const & m); context get_context(expr const & m) const;
context get_context(name const & m); context get_context(name const & m) const;
/** /**
\brief Return the type of the given metavariable. \brief Return the type of the given metavariable.
\pre is_metavar(m) \pre is_metavar(m)
\remark If \c m does not have a type associated with it, then a new
metavariable is created to represent the type of \c m.
\remark If \c m has a local context, then the local context is applied.
*/ */
expr get_type(expr const & m); expr get_type(expr const & m);
expr get_type(name const & m); expr get_type(name const & m);
@ -152,7 +150,7 @@ public:
\pre !is_assigned(m) \pre !is_assigned(m)
*/ */
void assign(name const & m, expr const & t); void assign(name const & m, expr const & t, trace const & tr = trace());
/** /**
\brief Assign metavariable \c m to \c t. \brief Assign metavariable \c m to \c t.
@ -161,12 +159,14 @@ public:
\pre !has_meta_context(m) \pre !has_meta_context(m)
\pre !is_assigned(m) \pre !is_assigned(m)
*/ */
void assign(expr const & m, expr const & t); void assign(expr const & m, expr const & t, trace const & tr = trace());
/** /**
\brief Return the set of substitutions. \brief Return the set of substitutions.
*/ */
substitution const & get_substitutions() const; substitution const & get_substitutions() const { return m_substitution; }
operator substitution const &() const { return get_substitutions(); }
/** /**
\brief Return the substitution associated with the given metavariable \brief Return the substitution associated with the given metavariable
@ -177,33 +177,7 @@ public:
\pre is_metavar(m) \pre is_metavar(m)
*/ */
expr get_subst(expr const & m) const; expr get_subst(expr const & m) const { return m_substitution.get_subst(m); }
};
/**
\brief Metavar generator.
*/
class metavar_generator {
name_generator m_gen;
public:
metavar_generator(name const & prefix);
metavar_generator();
/**
\brief Return the prefix used to create metavariables in this generator.
*/
name const & prefix() const { return m_gen.prefix(); }
/**
\brief Create a metavariable with the given type.
*/
expr mk(expr const & t);
/**
\brief Create a metavariable where the type is another
metavariable. The type of the type is a null expression.
*/
expr mk();
}; };
/** /**
@ -269,26 +243,4 @@ bool has_assigned_metavar(expr const & e, substitution const & s);
\brief is_metavar(m) \brief is_metavar(m)
*/ */
bool has_metavar(expr const & e, expr const & m, substitution const & s = substitution()); bool has_metavar(expr const & e, expr const & m, substitution const & s = substitution());
/**
\brief Set of unification constraints that need to be solved.
It store two kinds of problems:
1. <tt>ctx |- lhs == rhs</tt>
2. <tt>ctx |- n : t</tt>
*/
class unification_constraints {
public:
virtual ~unification_constraints() {}
/**
\brief Add a new unification problem of the form <tt>ctx |- lhs == rhs</tt>
It means that rhs is convertible to lhs.
If rhs and lhs are not types, then this is just equality (modulo normalization).
*/
virtual void add(context const & ctx, expr const & lhs, expr const & rhs) = 0;
/**
\brief Add a new unification problem of the form <tt>ctx |- n : t</tt>
*/
virtual void add_type_of(context const & ctx, expr const & n, expr const & t) = 0;
};
} }

View file

@ -71,8 +71,8 @@ class normalizer::imp {
environment const & m_env; environment const & m_env;
context m_ctx; context m_ctx;
substitution const * m_subst; metavar_env const * m_menv;
unsigned m_subst_timestamp; unsigned m_menv_timestamp;
cache m_cache; cache m_cache;
unsigned m_max_depth; unsigned m_max_depth;
unsigned m_depth; unsigned m_depth;
@ -193,8 +193,8 @@ class normalizer::imp {
svalue r; svalue r;
switch (a.kind()) { switch (a.kind()) {
case expr_kind::MetaVar: case expr_kind::MetaVar:
if (m_subst && m_subst->is_assigned(a)) { if (m_menv && m_menv->is_assigned(a)) {
r = normalize(m_subst->get_subst(a), s, k); r = normalize(m_menv->get_subst(a), s, k);
} else { } else {
r = svalue(updt_metavar(a, s, k)); r = svalue(updt_metavar(a, s, k));
} }
@ -297,38 +297,38 @@ class normalizer::imp {
} }
} }
void set_subst(substitution const * subst) { void set_menv(metavar_env const * menv) {
if (m_subst == subst) { if (m_menv == menv) {
// Check whether m_subst has been updated since the last time the normalizer has been invoked // Check whether m_menv has been updated since the last time the normalizer has been invoked
if (m_subst && m_subst->get_timestamp() > m_subst_timestamp) { if (m_menv && m_menv->get_timestamp() > m_menv_timestamp) {
m_subst_timestamp = m_subst->get_timestamp(); m_menv_timestamp = m_menv->get_timestamp();
m_cache.clear(); m_cache.clear();
} }
} else { } else {
m_subst = subst; m_menv = menv;
m_cache.clear(); m_cache.clear();
m_subst_timestamp = m_subst ? m_subst->get_timestamp() : 0; m_menv_timestamp = m_menv ? m_menv->get_timestamp() : 0;
} }
} }
public: public:
imp(environment const & env, unsigned max_depth): imp(environment const & env, unsigned max_depth):
m_env(env) { m_env(env) {
m_interrupted = false; m_interrupted = false;
m_max_depth = max_depth; m_max_depth = max_depth;
m_depth = 0; m_depth = 0;
m_subst = nullptr; m_menv = nullptr;
m_subst_timestamp = 0; m_menv_timestamp = 0;
} }
expr operator()(expr const & e, context const & ctx, substitution const * subst) { expr operator()(expr const & e, context const & ctx, metavar_env const * menv) {
set_ctx(ctx); set_ctx(ctx);
set_subst(subst); set_menv(menv);
unsigned k = m_ctx.size(); unsigned k = m_ctx.size();
return reify(normalize(e, value_stack(), k), k); return reify(normalize(e, value_stack(), k), k);
} }
void clear() { m_ctx = context(); m_cache.clear(); m_subst = nullptr; m_subst_timestamp = 0; } void clear() { m_ctx = context(); m_cache.clear(); m_menv = nullptr; m_menv_timestamp = 0; }
void set_interrupt(bool flag) { m_interrupted = flag; } void set_interrupt(bool flag) { m_interrupted = flag; }
}; };
@ -336,12 +336,12 @@ normalizer::normalizer(environment const & env, unsigned max_depth):m_ptr(new im
normalizer::normalizer(environment const & env):normalizer(env, std::numeric_limits<unsigned>::max()) {} normalizer::normalizer(environment const & env):normalizer(env, std::numeric_limits<unsigned>::max()) {}
normalizer::normalizer(environment const & env, options const & opts):normalizer(env, get_normalizer_max_depth(opts)) {} normalizer::normalizer(environment const & env, options const & opts):normalizer(env, get_normalizer_max_depth(opts)) {}
normalizer::~normalizer() {} normalizer::~normalizer() {}
expr normalizer::operator()(expr const & e, context const & ctx, substitution const * subst) { return (*m_ptr)(e, ctx, subst); } expr normalizer::operator()(expr const & e, context const & ctx, metavar_env const * menv) { return (*m_ptr)(e, ctx, menv); }
void normalizer::clear() { m_ptr->clear(); } void normalizer::clear() { m_ptr->clear(); }
void normalizer::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); } void normalizer::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }
expr normalize(expr const & e, environment const & env, context const & ctx, substitution const * subst) { expr normalize(expr const & e, environment const & env, context const & ctx, metavar_env const * menv) {
return normalizer(env)(e, ctx, subst); return normalizer(env)(e, ctx, menv);
} }
} }

View file

@ -13,8 +13,7 @@ Author: Leonardo de Moura
namespace lean { namespace lean {
class environment; class environment;
class options; class options;
class substitution; class metavar_env;
class unification_constraints;
/** \brief Functional object for normalizing expressions */ /** \brief Functional object for normalizing expressions */
class normalizer { class normalizer {
class imp; class imp;
@ -25,7 +24,7 @@ public:
normalizer(environment const & env, options const & opts); normalizer(environment const & env, options const & opts);
~normalizer(); ~normalizer();
expr operator()(expr const & e, context const & ctx = context(), substitution const * subst = nullptr); expr operator()(expr const & e, context const & ctx = context(), metavar_env const * menv = nullptr);
void clear(); void clear();
@ -34,5 +33,5 @@ public:
void reset_interrupt() { set_interrupt(false); } void reset_interrupt() { set_interrupt(false); }
}; };
/** \brief Normalize \c e using the environment \c env and context \c ctx */ /** \brief Normalize \c e using the environment \c env and context \c ctx */
expr normalize(expr const & e, environment const & env, context const & ctx = context(), substitution const * subst = nullptr); expr normalize(expr const & e, environment const & env, context const & ctx = context(), metavar_env const * menv = nullptr);
} }

View file

@ -13,26 +13,26 @@ Author: Leonardo de Moura
#include "kernel/instantiate.h" #include "kernel/instantiate.h"
#include "kernel/builtin.h" #include "kernel/builtin.h"
#include "kernel/free_vars.h" #include "kernel/free_vars.h"
#include "kernel/metavar.h" #include "kernel/type_checker_trace.h"
namespace lean { namespace lean {
static name g_x_name("x"); static name g_x_name("x");
/** \brief Auxiliary functional object used to implement infer_type. */ /** \brief Auxiliary functional object used to implement infer_type. */
class type_checker::imp { class type_checker::imp {
typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache; typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache;
typedef buffer<unification_constraint> unification_constraints;
environment const & m_env; environment const & m_env;
cache m_cache; cache m_cache;
normalizer m_normalizer; normalizer m_normalizer;
context m_ctx; context m_ctx;
substitution * m_subst; metavar_env * m_menv;
unsigned m_subst_timestamp; unsigned m_menv_timestamp;
metavar_generator * m_mgen;
unification_constraints * m_uc; unification_constraints * m_uc;
volatile bool m_interrupted; volatile bool m_interrupted;
expr normalize(expr const & e, context const & ctx) { expr normalize(expr const & e, context const & ctx) {
return m_normalizer(e, ctx, m_subst); return m_normalizer(e, ctx, m_menv);
} }
expr lookup(context const & c, unsigned i) { expr lookup(context const & c, unsigned i) {
@ -49,45 +49,35 @@ class type_checker::imp {
expr r = normalize(e, ctx); expr r = normalize(e, ctx);
if (is_pi(r)) if (is_pi(r))
return r; return r;
if (has_metavar(r) && m_subst && m_uc && m_mgen) { if (has_metavar(r) && m_menv) {
// Create two fresh variables A and B, // Create two fresh variables A and B,
// and assign r == (Pi(x : A), B x) // and assign r == (Pi(x : A), B x)
expr A = m_mgen->mk(); expr A = m_menv->mk_metavar(ctx);
expr B = m_mgen->mk(); expr B = m_menv->mk_metavar(ctx);
expr p = mk_pi(g_x_name, A, B(Var(0))); expr p = mk_pi(g_x_name, A, B(Var(0)));
if (is_metavar(r) && !has_local_context(r)) { trace tr = mk_function_expected_trace(ctx, s);
// cheap case m_uc->push_back(mk_eq_constraint(ctx, r, p, tr));
m_subst->assign(r, p);
} else {
m_uc->add(ctx, r, p);
}
return p; return p;
} }
throw function_expected_exception(m_env, ctx, s); throw function_expected_exception(m_env, ctx, s);
} }
level infer_universe_core(expr const & t, context const & ctx) { expr check_type(expr const & e, expr const & s, context const & ctx) {
expr u = normalize(infer_type_core(t, ctx), ctx); if (is_type(e))
return e;
if (e == Bool)
return Type();
expr u = normalize(e, ctx);
if (is_type(u)) if (is_type(u))
return ty_level(u); return u;
if (u == Bool) if (u == Bool)
return level(); return Type();
if (has_metavar(u) && m_subst && m_uc) { if (has_metavar(u) && m_menv) {
// Remark: in the current implementation we don't have level constraints and variables trace tr = mk_type_expected_trace(ctx, s);
// in the unification problem set. So, we assume the metavariable is in level 0. m_uc->push_back(mk_convertible_constraint(ctx, u, TypeU, tr));
// This is a crude approximation that works most of the time. return u;
// A better solution is consists in creating a fresh universe level k and
// associate the constraint that u == Type k.
// Later the constraint must be solved in the elaborator.
if (is_metavar(u) && !has_local_context(u)) {
// cheap case
m_subst->assign(u, Type());
} else {
m_uc->add(ctx, u, Type());
}
return level();
} }
throw type_expected_exception(m_env, ctx, t); throw type_expected_exception(m_env, ctx, s);
} }
expr infer_type_core(expr const & e, context const & ctx) { expr infer_type_core(expr const & e, context const & ctx) {
@ -103,9 +93,14 @@ class type_checker::imp {
expr r; expr r;
switch (e.kind()) { switch (e.kind()) {
case expr_kind::MetaVar: case expr_kind::MetaVar:
r = metavar_type(e); if (m_menv) {
if (!r) if (m_menv->is_assigned(e))
throw kernel_exception(m_env, "metavariable does not have a type associated with it"); return infer_type_core(m_menv->get_subst(e), ctx);
else
return m_menv->get_type(e);
} else {
throw kernel_exception(m_env, "unexpected metavariable occurrence");
}
break; break;
case expr_kind::Constant: case expr_kind::Constant:
r = m_env.get_object(const_name(e)).get_type(); r = m_env.get_object(const_name(e)).get_type();
@ -128,7 +123,8 @@ class type_checker::imp {
while (true) { while (true) {
expr const & c = arg(e, i); expr const & c = arg(e, i);
expr const & c_t = arg_types[i]; expr const & c_t = arg_types[i];
if (!is_convertible(c_t, abst_domain(f_t), ctx)) auto mk_trace = [&](){ return mk_app_type_match_trace(ctx, e, i); }; // thunk for creating trace object if needed
if (!is_convertible(c_t, abst_domain(f_t), ctx, mk_trace))
throw app_type_mismatch_exception(m_env, ctx, e, arg_types.size(), arg_types.data()); throw app_type_mismatch_exception(m_env, ctx, e, arg_types.size(), arg_types.data());
if (closed(abst_body(f_t))) if (closed(abst_body(f_t)))
f_t = abst_body(f_t); f_t = abst_body(f_t);
@ -151,7 +147,8 @@ class type_checker::imp {
r = mk_bool_type(); r = mk_bool_type();
break; break;
case expr_kind::Lambda: { case expr_kind::Lambda: {
infer_universe_core(abst_domain(e), ctx); expr d = infer_type_core(abst_domain(e), ctx);
check_type(d, abst_domain(e), ctx);
expr t; expr t;
{ {
cache::mk_scope sc(m_cache); cache::mk_scope sc(m_cache);
@ -161,20 +158,30 @@ class type_checker::imp {
break; break;
} }
case expr_kind::Pi: { case expr_kind::Pi: {
level l1 = infer_universe_core(abst_domain(e), ctx); expr t1 = check_type(infer_type_core(abst_domain(e), ctx), abst_domain(e), ctx);
level l2; expr t2;
{ {
cache::mk_scope sc(m_cache); cache::mk_scope sc(m_cache);
l2 = infer_universe_core(abst_body(e), extend(ctx, abst_name(e), abst_domain(e))); context new_ctx = extend(ctx, abst_name(e), abst_domain(e));
t2 = check_type(infer_type_core(abst_body(e), new_ctx), abst_body(e), new_ctx);
}
if (is_type(t1) && is_type(t2)) {
r = mk_type(max(ty_level(t1), ty_level(t2)));
} else {
lean_assert(m_uc);
trace tr = mk_max_type_trace(ctx, e);
r = m_menv->mk_metavar(ctx);
m_uc->push_back(mk_max_constraint(ctx, t1, t2, r, tr));
} }
r = mk_type(max(l1, l2));
break; break;
} }
case expr_kind::Let: { case expr_kind::Let: {
expr lt = infer_type_core(let_value(e), ctx); expr lt = infer_type_core(let_value(e), ctx);
if (let_type(e)) { if (let_type(e)) {
infer_universe_core(let_type(e), ctx); // check if it is really a type expr ty = infer_type_core(let_type(e), ctx);
if (!is_convertible(lt, let_type(e), ctx)) check_type(ty, let_type(e), ctx); // check if it is really a type
auto mk_trace = [&](){ return mk_def_type_match_trace(ctx, let_name(e), let_value(e)); }; // thunk for creating trace object if needed
if (!is_convertible(lt, let_type(e), ctx, mk_trace))
throw def_type_mismatch_exception(m_env, ctx, let_name(e), let_type(e), let_value(e), lt); throw def_type_mismatch_exception(m_env, ctx, let_name(e), let_type(e), let_value(e), lt);
} }
{ {
@ -228,35 +235,22 @@ class type_checker::imp {
} }
} }
bool is_convertible(expr const & given, expr const & expected, context const & ctx) { template<typename MkTrace>
bool is_convertible(expr const & given, expr const & expected, context const & ctx, MkTrace const & mk_trace) {
if (is_convertible_core(given, expected)) if (is_convertible_core(given, expected))
return true; return true;
expr new_given = given; expr new_given = normalize(given, ctx);
expr new_expected = expected; expr new_expected = normalize(expected, ctx);
if (has_metavar(new_given) || has_metavar(new_expected)) { if (is_convertible_core(new_given, new_expected))
if (!m_subst) return true;
return false; if (m_menv && (has_metavar(new_given) || has_metavar(new_expected))) {
new_given = instantiate_metavars(new_given, *m_subst); m_uc->push_back(mk_convertible_constraint(ctx, new_given, new_expected, mk_trace()));
new_expected = instantiate_metavars(new_expected, *m_subst); return true;
if (is_convertible_core(new_given, new_expected))
return true;
if (has_metavar(new_given) || has_metavar(new_expected)) {
// Very conservative approach, just postpone the problem.
// We may also try to normalize new_given and new_expected even if
// they contain metavariables.
if (m_uc) {
m_uc->add(ctx, new_expected, new_given);
return true;
} else {
return false;
}
}
} }
new_given = normalize(new_given, ctx); return false;
new_expected = normalize(new_expected, ctx);
return is_convertible_core(new_given, new_expected);
} }
void set_ctx(context const & ctx) { void set_ctx(context const & ctx) {
if (!is_eqp(m_ctx, ctx)) { if (!is_eqp(m_ctx, ctx)) {
clear(); clear();
@ -264,17 +258,17 @@ class type_checker::imp {
} }
} }
void set_subst(substitution * subst) { void set_menv(metavar_env * menv) {
if (m_subst == subst) { if (m_menv == menv) {
// Check whether m_subst has been updated since the last time the normalizer has been invoked // Check whether m_menv has been updated since the last time the type checker has been invoked
if (m_subst && m_subst->get_timestamp() > m_subst_timestamp) { if (m_menv && m_menv->get_timestamp() > m_menv_timestamp) {
clear(); clear();
m_subst_timestamp = m_subst->get_timestamp(); m_menv_timestamp = m_menv->get_timestamp();
} }
} else { } else {
clear(); clear();
m_subst = subst; m_menv = menv;
m_subst_timestamp = m_subst ? m_subst->get_timestamp() : 0; m_menv_timestamp = m_menv ? m_menv->get_timestamp() : 0;
} }
} }
@ -282,34 +276,31 @@ public:
imp(environment const & env): imp(environment const & env):
m_env(env), m_env(env),
m_normalizer(env) { m_normalizer(env) {
m_subst = nullptr; m_menv = nullptr;
m_subst_timestamp = 0; m_menv_timestamp = 0;
m_mgen = nullptr;
m_uc = nullptr; m_uc = nullptr;
m_interrupted = false; m_interrupted = false;
} }
level infer_universe(expr const & t, context const & ctx, substitution * subst, metavar_generator * mgen, unification_constraints * uc) { expr infer_type(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & uc) {
set_ctx(ctx); set_ctx(ctx);
set_subst(subst); set_menv(menv);
flet<unification_constraints*> set_uc(m_uc, uc); flet<unification_constraints*> set_uc(m_uc, &uc);
flet<metavar_generator*> set_mgen(m_mgen, mgen);
return infer_universe_core(t, ctx);
}
expr infer_type(expr const & e, context const & ctx, substitution * subst, metavar_generator * mgen, unification_constraints * uc) {
set_ctx(ctx);
set_subst(subst);
flet<unification_constraints*> set_uc(m_uc, uc);
flet<metavar_generator*> set_mgen(m_mgen, mgen);
return infer_type_core(e, ctx); return infer_type_core(e, ctx);
} }
bool is_convertible(expr const & t1, expr const & t2, context const & ctx, substitution * subst, unification_constraints * uc) { bool is_convertible(expr const & t1, expr const & t2, context const & ctx) {
set_ctx(ctx); set_ctx(ctx);
set_subst(subst); set_menv(nullptr);
flet<unification_constraints*> set_uc(m_uc, uc); auto mk_trace = [](){ lean_unreachable(); return trace(); };
return is_convertible(t1, t2, ctx); return is_convertible(t1, t2, ctx, mk_trace);
}
void check_type(expr const & e, context const & ctx) {
set_ctx(ctx);
set_menv(nullptr);
expr t = infer_type_core(e, ctx);
check_type(t, e, ctx);
} }
void set_interrupt(bool flag) { void set_interrupt(bool flag) {
@ -321,8 +312,8 @@ public:
m_cache.clear(); m_cache.clear();
m_normalizer.clear(); m_normalizer.clear();
m_ctx = context(); m_ctx = context();
m_subst = nullptr; m_menv = nullptr;
m_subst_timestamp = 0; m_menv_timestamp = 0;
} }
normalizer & get_normalizer() { normalizer & get_normalizer() {
@ -332,24 +323,27 @@ public:
type_checker::type_checker(environment const & env):m_ptr(new imp(env)) {} type_checker::type_checker(environment const & env):m_ptr(new imp(env)) {}
type_checker::~type_checker() {} type_checker::~type_checker() {}
expr type_checker::infer_type(expr const & e, context const & ctx, substitution * subst, metavar_generator * mgen, unification_constraints * uc) { expr type_checker::infer_type(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & uc) {
return m_ptr->infer_type(e, ctx, subst, mgen, uc); return m_ptr->infer_type(e, ctx, menv, uc);
} }
level type_checker::infer_universe(expr const & e, context const & ctx, substitution * subst, metavar_generator * mgen, unification_constraints * uc) { expr type_checker::infer_type(expr const & e, context const & ctx) {
return m_ptr->infer_universe(e, ctx, subst, mgen, uc); buffer<unification_constraint> uc;
return infer_type(e, ctx, nullptr, uc);
}
bool type_checker::is_convertible(expr const & t1, expr const & t2, context const & ctx) {
return m_ptr->is_convertible(t1, t2, ctx);
}
void type_checker::check_type(expr const & e, context const & ctx) {
m_ptr->check_type(e, ctx);
} }
void type_checker::clear() { m_ptr->clear(); } void type_checker::clear() { m_ptr->clear(); }
void type_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); } void type_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }
bool type_checker::is_convertible(expr const & t1, expr const & t2, context const & ctx, substitution * subst, unification_constraints * uc) {
return m_ptr->is_convertible(t1, t2, ctx, subst, uc);
}
normalizer & type_checker::get_normalizer() { return m_ptr->get_normalizer(); } normalizer & type_checker::get_normalizer() { return m_ptr->get_normalizer(); }
expr infer_type(expr const & e, environment const & env, context const & ctx) { expr infer_type(expr const & e, environment const & env, context const & ctx) {
return type_checker(env).infer_type(e, ctx); return type_checker(env).infer_type(e, ctx);
} }
bool is_convertible(expr const & given, expr const & expected, environment const & env, context const & ctx, bool is_convertible(expr const & given, expr const & expected, environment const & env, context const & ctx) {
substitution * subst, unification_constraints * uc) { return type_checker(env).is_convertible(given, expected, ctx);
return type_checker(env).is_convertible(given, expected, ctx, subst, uc);
} }
} }

View file

@ -8,13 +8,12 @@ Author: Leonardo de Moura
#include <memory> #include <memory>
#include "kernel/expr.h" #include "kernel/expr.h"
#include "kernel/context.h" #include "kernel/context.h"
#include "kernel/unification_constraint.h"
#include "kernel/metavar.h"
namespace lean { namespace lean {
class environment; class environment;
class normalizer; class normalizer;
class substitution;
class metavar_generator;
class unification_constraints;
/** /**
\brief Lean Type Checker. It can also be used to infer types, universes and check whether a \brief Lean Type Checker. It can also be used to infer types, universes and check whether a
type \c A is convertible to a type \c B. type \c A is convertible to a type \c B.
@ -26,42 +25,46 @@ public:
type_checker(environment const & env); type_checker(environment const & env);
~type_checker(); ~type_checker();
expr infer_type(expr const & e, /**
context const & ctx = context(), \brief Return the type of \c e in the context \c ctx.
substitution * subst = nullptr,
metavar_generator * mgen = nullptr,
unification_constraints * uc = nullptr);
level infer_universe(expr const & e, \remark This method throws an exception if \c e is not type correct.
context const & ctx = context(),
substitution * subst = nullptr,
metavar_generator * mgen = nullptr,
unification_constraints * uc = nullptr);
void check(expr const & e, \remark If \c menv is not nullptr, then \c e may contain metavariables.
context const & ctx = context(), New metavariables and unification constraints may be created by the type checker.
substitution * subst = nullptr, The new unification constraints are stored in \c new_constraints.
metavar_generator * mgen = nullptr, */
unification_constraints * uc = nullptr) { expr infer_type(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & new_constraints);
infer_type(e, ctx, subst, mgen, uc);
}
bool is_convertible(expr const & t1, /**
expr const & t2, \brief Return the type of \c e in the context \c ctx.
context const & ctx = context(),
substitution * subst = nullptr,
unification_constraints * uc = nullptr);
\remark This method throws an exception if \c e is not type
correct, or if \c e contains metavariables.
*/
expr infer_type(expr const & e, context const & ctx = context());
/** \brief Throw an exception if \c e is not type correct in the context \c ctx. */
void check(expr const & e, context const & ctx = context()) { infer_type(e, ctx); }
/** \brief Throw an exception if \c e is not a type in the context \c ctx. */
void check_type(expr const & e, context const & ctx = context());
/** \brief Return true iff \c t1 is convertible to \c t2 in the context \c ctx. */
bool is_convertible(expr const & t1, expr const & t2, context const & ctx = context());
/** \brief Reset internal caches */
void clear(); void clear();
/** \brief Interrupt type checker */
void set_interrupt(bool flag); void set_interrupt(bool flag);
void interrupt() { set_interrupt(true); } void interrupt() { set_interrupt(true); }
void reset_interrupt() { set_interrupt(false); } void reset_interrupt() { set_interrupt(false); }
/** \brief Return reference to the normalizer used by this type checker. */
normalizer & get_normalizer(); normalizer & get_normalizer();
}; };
expr infer_type(expr const & e, environment const & env, context const & ctx = context()); expr infer_type(expr const & e, environment const & env, context const & ctx = context());
bool is_convertible(expr const & t1, expr const & t2, environment const & env, context const & ctx = context(), bool is_convertible(expr const & t1, expr const & t2, environment const & env, context const & ctx = context());
substitution * subst = nullptr, unification_constraints * uc = nullptr);
} }

View file

@ -10,36 +10,72 @@ namespace lean {
unification_constraint_cell::unification_constraint_cell(unification_constraint_kind k, context const & c, trace const & t): unification_constraint_cell::unification_constraint_cell(unification_constraint_kind k, context const & c, trace const & t):
m_kind(k), m_ctx(c), m_trace(t), m_rc(1) { m_kind(k), m_ctx(c), m_trace(t), m_rc(1) {
} }
unification_constraint_cell::~unification_constraint_cell() {
}
void unification_constraint_cell::dealloc() { void unification_constraint_cell::dealloc() {
switch (m_kind) { delete this;
case unification_constraint_kind::Eq: }
delete static_cast<unification_constraint_eq*>(this);
break; static format add_context(formatter const & fmt, options const & opts, context const & ctx, format const & body) {
case unification_constraint_kind::Convertible: bool unicode = get_pp_unicode(opts);
delete static_cast<unification_constraint_convertible*>(this); format ctx_fmt = fmt(ctx, opts);
break; format turnstile = unicode ? format("\u22A2") /* ⊢ */ : format("|-");
case unification_constraint_kind::Max: return group(format{ctx_fmt, space(), turnstile, line(), body});
delete static_cast<unification_constraint_max*>(this); }
break;
case unification_constraint_kind::Choice: static format add_trace(formatter const & fmt, options const & opts, format const & body, trace const & tr, bool include_trace) {
static_cast<unification_constraint_choice*>(this)->~unification_constraint_choice(); if (include_trace) {
delete[] reinterpret_cast<char*>(this); unsigned indent = get_pp_indent(opts);
break; return format{body, line(), format("Trace:"), nest(indent, compose(line(), tr.pp(fmt, opts)))};
} else {
return body;
} }
} }
static format mk_binary(formatter const & fmt, options const & opts, context const & ctx, expr const & lhs, expr const & rhs, format const & op) {
format lhs_fmt = fmt(ctx, lhs, false, opts);
format rhs_fmt = fmt(ctx, rhs, false, opts);
return group(format{lhs_fmt, space(), op, line(), rhs_fmt});
}
static format mk_unification_op(options const & opts) {
bool unicode = get_pp_unicode(opts);
return unicode ? format("\u2248") /* ≈ */ : format("=?=");
}
unification_constraint_eq::unification_constraint_eq(context const & c, expr const & lhs, expr const & rhs, trace const & t): unification_constraint_eq::unification_constraint_eq(context const & c, expr const & lhs, expr const & rhs, trace const & t):
unification_constraint_cell(unification_constraint_kind::Eq, c, t), unification_constraint_cell(unification_constraint_kind::Eq, c, t),
m_lhs(lhs), m_lhs(lhs),
m_rhs(rhs) { m_rhs(rhs) {
} }
unification_constraint_eq::~unification_constraint_eq() {
}
format unification_constraint_eq::pp(formatter const & fmt, options const & opts, bool include_trace) const {
format op = mk_unification_op(opts);
format body = mk_binary(fmt, opts, m_ctx, m_lhs, m_rhs, op);
body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, include_trace);
}
unification_constraint_convertible::unification_constraint_convertible(context const & c, expr const & from, expr const & to, trace const & t): unification_constraint_convertible::unification_constraint_convertible(context const & c, expr const & from, expr const & to, trace const & t):
unification_constraint_cell(unification_constraint_kind::Convertible, c, t), unification_constraint_cell(unification_constraint_kind::Convertible, c, t),
m_from(from), m_from(from),
m_to(to) { m_to(to) {
} }
unification_constraint_convertible::~unification_constraint_convertible() {
}
format unification_constraint_convertible::pp(formatter const & fmt, options const & opts, bool include_trace) const {
bool unicode = get_pp_unicode(opts);
format op = unicode ? format("\u227A") /* ≺ */ : format("<<");
format body = mk_binary(fmt, opts, m_ctx, m_from, m_to, op);
body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, include_trace);
}
unification_constraint_max::unification_constraint_max(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t): unification_constraint_max::unification_constraint_max(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t):
unification_constraint_cell(unification_constraint_kind::Max, c, t), unification_constraint_cell(unification_constraint_kind::Max, c, t),
m_lhs1(lhs1), m_lhs1(lhs1),
@ -47,12 +83,44 @@ unification_constraint_max::unification_constraint_max(context const & c, expr c
m_rhs(rhs) { m_rhs(rhs) {
} }
unification_constraint_max::~unification_constraint_max() {
}
format unification_constraint_max::pp(formatter const & fmt, options const & opts, bool include_trace) const {
format op = mk_unification_op(opts);
format lhs1_fmt = fmt(m_ctx, m_lhs1, false, opts);
format lhs2_fmt = fmt(m_ctx, m_lhs2, false, opts);
format rhs_fmt = fmt(m_ctx, m_rhs, false, opts);
format body = group(format{format("max"), lp(), lhs1_fmt, comma(), nest(4, compose(line(), lhs2_fmt)), space(), op, line(), rhs_fmt});
body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, include_trace);
}
unification_constraint_choice::unification_constraint_choice(context const & c, expr const & mvar, unsigned num, trace const & t): unification_constraint_choice::unification_constraint_choice(context const & c, expr const & mvar, unsigned num, trace const & t):
unification_constraint_cell(unification_constraint_kind::Choice, c, t), unification_constraint_cell(unification_constraint_kind::Choice, c, t),
m_mvar(mvar), m_mvar(mvar),
m_num_choices(num) { m_num_choices(num) {
} }
unification_constraint_choice::~unification_constraint_choice() {
}
format unification_constraint_choice::pp(formatter const & fmt, options const & opts, bool include_trace) const {
bool unicode = get_pp_unicode(opts);
format m_fmt = fmt(m_ctx, m_mvar, false, opts);
format eq_op = mk_unification_op(opts);
format or_op = unicode ? format("\u2295") : format("OR");
format body;
for (unsigned i = 0; i < m_num_choices; i++) {
body += format{m_fmt, eq_op, fmt(m_ctx, m_choices[i], false, opts)};
if (i + 1 < m_num_choices)
body += format{space(), or_op, line()};
}
body = group(body);
body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, include_trace);
}
unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t) { unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t) {
return unification_constraint(new unification_constraint_eq(c, lhs, rhs, t)); return unification_constraint(new unification_constraint_eq(c, lhs, rhs, t));
} }

View file

@ -34,6 +34,7 @@ enum class unification_constraint_kind { Eq, Convertible, Max, Choice };
\brief Base class for all Lean unification constraints. \brief Base class for all Lean unification constraints.
*/ */
class unification_constraint_cell { class unification_constraint_cell {
protected:
unification_constraint_kind m_kind; unification_constraint_kind m_kind;
context m_ctx; context m_ctx;
trace m_trace; //!< justification for this constraint trace m_trace; //!< justification for this constraint
@ -41,9 +42,11 @@ class unification_constraint_cell {
void dealloc(); void dealloc();
public: public:
unification_constraint_cell(unification_constraint_kind k, context const & c, trace const & t); unification_constraint_cell(unification_constraint_kind k, context const & c, trace const & t);
virtual ~unification_constraint_cell();
unification_constraint_kind kind() const { return m_kind; } unification_constraint_kind kind() const { return m_kind; }
trace const & get_trace() const { return m_trace; } trace const & get_trace() const { return m_trace; }
context const & get_context() const { return m_ctx; } context const & get_context() const { return m_ctx; }
virtual format pp(formatter const & fmt, options const & opts, bool include_trace = false) const = 0;
}; };
class unification_constraint { class unification_constraint {
@ -66,6 +69,11 @@ public:
operator bool() const { return m_ptr != nullptr; } operator bool() const { return m_ptr != nullptr; }
format pp(formatter const & fmt, options const & opts, bool include_trace = false) const {
lean_assert(m_ptr);
return m_ptr->pp(fmt, opts, include_trace);
}
friend unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t); friend unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t);
friend unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, trace const & t); friend unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, trace const & t);
friend unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t); friend unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t);
@ -80,8 +88,10 @@ class unification_constraint_eq : public unification_constraint_cell {
expr m_rhs; expr m_rhs;
public: public:
unification_constraint_eq(context const & c, expr const & lhs, expr const & rhs, trace const & t); unification_constraint_eq(context const & c, expr const & lhs, expr const & rhs, trace const & t);
virtual ~unification_constraint_eq();
expr const & get_lhs() const { return m_lhs; } expr const & get_lhs() const { return m_lhs; }
expr const & get_rhs() const { return m_rhs; } expr const & get_rhs() const { return m_rhs; }
virtual format pp(formatter const & fmt, options const & opts, bool include_trace = false) const;
}; };
/** /**
@ -94,8 +104,10 @@ class unification_constraint_convertible : public unification_constraint_cell {
expr m_to; expr m_to;
public: public:
unification_constraint_convertible(context const & c, expr const & from, expr const & to, trace const & t); unification_constraint_convertible(context const & c, expr const & from, expr const & to, trace const & t);
virtual ~unification_constraint_convertible();
expr const & get_from() const { return m_from; } expr const & get_from() const { return m_from; }
expr const & get_to() const { return m_to; } expr const & get_to() const { return m_to; }
virtual format pp(formatter const & fmt, options const & opts, bool include_trace = false) const;
}; };
/** /**
@ -107,9 +119,11 @@ class unification_constraint_max : public unification_constraint_cell {
expr m_rhs; expr m_rhs;
public: public:
unification_constraint_max(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t); unification_constraint_max(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t);
virtual ~unification_constraint_max();
expr const & get_lhs1() const { return m_lhs1; } expr const & get_lhs1() const { return m_lhs1; }
expr const & get_lhs2() const { return m_lhs2; } expr const & get_lhs2() const { return m_lhs2; }
expr const & get_rhs() const { return m_rhs; } expr const & get_rhs() const { return m_rhs; }
virtual format pp(formatter const & fmt, options const & opts, bool include_trace = false) const;
}; };
/** /**
@ -122,11 +136,13 @@ class unification_constraint_choice : public unification_constraint_cell {
friend unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, trace const & t); friend unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, trace const & t);
public: public:
unification_constraint_choice(context const & c, expr const & mvar, unsigned num, trace const & t); unification_constraint_choice(context const & c, expr const & mvar, unsigned num, trace const & t);
virtual ~unification_constraint_choice();
expr const & get_mvar() const { return m_mvar; } expr const & get_mvar() const { return m_mvar; }
unsigned get_num_choices() const { return m_num_choices; } unsigned get_num_choices() const { return m_num_choices; }
expr const & get_choice(unsigned idx) const { lean_assert(idx < m_num_choices); return m_choices[idx]; } expr const & get_choice(unsigned idx) const { lean_assert(idx < m_num_choices); return m_choices[idx]; }
expr const * begin_choices() const { return m_choices; } expr const * begin_choices() const { return m_choices; }
expr const * end_choices() const { return m_choices + m_num_choices; } expr const * end_choices() const { return m_choices + m_num_choices; }
virtual format pp(formatter const & fmt, options const & opts, bool include_trace = false) const;
}; };
unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t); unification_constraint mk_eq_constraint(context const & c, expr const & lhs, expr const & rhs, trace const & t);
@ -145,16 +161,16 @@ inline unification_constraint_convertible * to_convertible(unification_constrain
inline unification_constraint_max * to_max(unification_constraint const & c) { lean_assert(is_max(c)); return static_cast<unification_constraint_max*>(c.raw()); } inline unification_constraint_max * to_max(unification_constraint const & c) { lean_assert(is_max(c)); return static_cast<unification_constraint_max*>(c.raw()); }
inline unification_constraint_choice * to_choice(unification_constraint const & c) { lean_assert(is_choice(c)); return static_cast<unification_constraint_choice*>(c.raw()); } inline unification_constraint_choice * to_choice(unification_constraint const & c) { lean_assert(is_choice(c)); return static_cast<unification_constraint_choice*>(c.raw()); }
context const & get_context(unification_constraint const & c) { return c.raw()->get_context(); } inline context const & get_context(unification_constraint const & c) { return c.raw()->get_context(); }
trace const & get_trace(unification_constraint const & c) { return c.raw()->get_trace(); } inline trace const & get_trace(unification_constraint const & c) { return c.raw()->get_trace(); }
expr const & eq_lhs(unification_constraint const & c) { return to_eq(c)->get_lhs(); } inline expr const & eq_lhs(unification_constraint const & c) { return to_eq(c)->get_lhs(); }
expr const & eq_rhs(unification_constraint const & c) { return to_eq(c)->get_rhs(); } inline expr const & eq_rhs(unification_constraint const & c) { return to_eq(c)->get_rhs(); }
expr const & convertible_from(unification_constraint const & c) { return to_convertible(c)->get_from(); } inline expr const & convertible_from(unification_constraint const & c) { return to_convertible(c)->get_from(); }
expr const & convertible_to(unification_constraint const & c) { return to_convertible(c)->get_to(); } inline expr const & convertible_to(unification_constraint const & c) { return to_convertible(c)->get_to(); }
expr const & max_lhs1(unification_constraint const & c) { return to_max(c)->get_lhs1(); } inline expr const & max_lhs1(unification_constraint const & c) { return to_max(c)->get_lhs1(); }
expr const & max_lhs2(unification_constraint const & c) { return to_max(c)->get_lhs2(); } inline expr const & max_lhs2(unification_constraint const & c) { return to_max(c)->get_lhs2(); }
expr const & max_rhs(unification_constraint const & c) { return to_max(c)->get_rhs(); } inline expr const & max_rhs(unification_constraint const & c) { return to_max(c)->get_rhs(); }
expr const & choice_mvar(unification_constraint const & c) { return to_choice(c)->get_mvar(); } inline expr const & choice_mvar(unification_constraint const & c) { return to_choice(c)->get_mvar(); }
unsigned choice_size(unification_constraint const & c) { return to_choice(c)->get_num_choices(); } inline unsigned choice_size(unification_constraint const & c) { return to_choice(c)->get_num_choices(); }
expr const & choice_ith(unification_constraint const & c, unsigned i) { return to_choice(c)->get_choice(i); } inline expr const & choice_ith(unification_constraint const & c, unsigned i) { return to_choice(c)->get_choice(i); }
} }

View file

@ -327,25 +327,6 @@ class ho_unifier::imp {
return is_meta_app(a) && has_local_context(arg(a, 0)); return is_meta_app(a) && has_local_context(arg(a, 0));
} }
/**
Auxiliary class for invoking m_type_infer.
If it creates a new unfication problem we mark m_failed to true.
add_eq can be easily supported, but we need to extend ho_unifier API to be able
to support add_type_of_eq and add_is_convertible.
The m_type_infer only invokes add_type_of_eq when it needs to ask for the type
of a metavariable that does not have a type yet.
One possible workaround it o make sure that every metavariable has an associated type
before invoking ho_unifier.
*/
class unification_constraints_wrapper : public unification_constraints {
bool m_failed;
public:
unification_constraints_wrapper():m_failed(false) {}
virtual void add(context const &, expr const &, expr const &) { m_failed = true; }
virtual void add_type_of(context const &, expr const &, expr const &) { m_failed = true; }
bool failed() const { return m_failed; }
};
expr mk_lambda(name const & n, expr const & d, expr const & b) { expr mk_lambda(name const & n, expr const & d, expr const & b) {
return ::lean::mk_lambda(n, d, b); return ::lean::mk_lambda(n, d, b);
} }
@ -382,7 +363,9 @@ class ho_unifier::imp {
We perform a "case split" using "projection" or "imitation". See Huet&Lang's paper on higher order matching We perform a "case split" using "projection" or "imitation". See Huet&Lang's paper on higher order matching
for further details. for further details.
*/ */
bool process_meta_app(context const & ctx, expr const & a, expr const & b) { bool process_meta_app(context const & /* ctx */, expr const & /* a */, expr const & /* b */) {
return true;
#if 0
lean_assert(is_meta_app(a)); lean_assert(is_meta_app(a));
lean_assert(!has_local_context(arg(a, 0))); lean_assert(!has_local_context(arg(a, 0)));
lean_assert(!is_meta_app(b)); lean_assert(!is_meta_app(b));
@ -394,7 +377,7 @@ class ho_unifier::imp {
substitution s = subst_of(top_state); substitution s = subst_of(top_state);
name const & mname = metavar_name(f_a); name const & mname = metavar_name(f_a);
unsigned num_a = num_args(a); unsigned num_a = num_args(a);
unification_constraints_wrapper ucw; // unification_constraints_wrapper ucw;
buffer<expr> arg_types; buffer<expr> arg_types;
for (unsigned i = 1; i < num_a; i++) { for (unsigned i = 1; i < num_a; i++) {
arg_types.push_back(m_type_infer(arg(a, i), ctx, &s, &ucw)); arg_types.push_back(m_type_infer(arg(a, i), ctx, &s, &ucw));
@ -464,6 +447,7 @@ class ho_unifier::imp {
m_state_stack.push_back(mk_state(new_s, new_q)); m_state_stack.push_back(mk_state(new_s, new_q));
reset_delayed(); reset_delayed();
return true; return true;
#endif
} }
/** \brief Return true if \c a is of the form ?m[inst:i t, ...] */ /** \brief Return true if \c a is of the form ?m[inst:i t, ...] */
@ -621,8 +605,8 @@ class ho_unifier::imp {
return true; return true;
} }
expr norm_a = m_normalizer(a, ctx, &s); expr norm_a; // = m_normalizer(a, ctx, &s);
expr norm_b = m_normalizer(b, ctx, &s); expr norm_b; // = m_normalizer(b, ctx, &s);
if (norm_a.kind() != norm_b.kind()) if (norm_a.kind() != norm_b.kind())
return false; return false;
if (is_app(norm_a)) { if (is_app(norm_a)) {

View file

@ -19,11 +19,12 @@ Author: Leonardo de Moura
namespace lean { namespace lean {
class light_checker::imp { class light_checker::imp {
typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache; typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache;
typedef buffer<unification_constraint> unification_constraints;
environment m_env; environment m_env;
context m_ctx; context m_ctx;
substitution * m_subst; metavar_env * m_menv;
unsigned m_subst_timestamp; unsigned m_menv_timestamp;
unification_constraints * m_uc; unification_constraints * m_uc;
normalizer m_normalizer; normalizer m_normalizer;
cache m_cache; cache m_cache;
@ -31,11 +32,12 @@ class light_checker::imp {
level infer_universe(expr const & t, context const & ctx) { level infer_universe(expr const & t, context const & ctx) {
expr u = m_normalizer(infer_type(t, ctx), ctx); expr u = m_normalizer(infer_type(t, ctx), ctx, m_menv);
if (is_type(u)) if (is_type(u))
return ty_level(u); return ty_level(u);
if (u == Bool) if (u == Bool)
return level(); return level();
// TODO(Leo): case when u has metavariables
throw type_expected_exception(m_env, ctx, t); throw type_expected_exception(m_env, ctx, t);
} }
@ -50,6 +52,7 @@ class light_checker::imp {
if (is_pi(t)) { if (is_pi(t)) {
t = abst_body(t); t = abst_body(t);
} else { } else {
// TODO(Leo): case when t has metavariables
throw function_expected_exception(m_env, ctx, e); throw function_expected_exception(m_env, ctx, e);
} }
} }
@ -60,29 +63,32 @@ class light_checker::imp {
return instantiate(t, num_args(e)-1, &arg(e, 1)); return instantiate(t, num_args(e)-1, &arg(e, 1));
} }
void set_subst(substitution * subst) { void set_menv(metavar_env * menv) {
if (m_subst == subst) { if (m_menv == menv) {
// Check whether m_subst has been updated since the last time the normalizer has been invoked // Check whether m_menv has been updated since the last time the checker has been invoked
if (m_subst && m_subst->get_timestamp() > m_subst_timestamp) { if (m_menv && m_menv->get_timestamp() > m_menv_timestamp) {
m_subst_timestamp = m_subst->get_timestamp(); m_menv_timestamp = m_menv->get_timestamp();
m_cache.clear(); m_cache.clear();
} }
} else { } else {
m_subst = subst; m_menv = menv;
m_cache.clear(); m_cache.clear();
m_subst_timestamp = m_subst ? m_subst->get_timestamp() : 0; m_menv_timestamp = m_menv ? m_menv->get_timestamp() : 0;
} }
} }
expr infer_type(expr const & e, context const & ctx) { expr infer_type(expr const & e, context const & ctx) {
// cheap cases, we do not cache results // cheap cases, we do not cache results
switch (e.kind()) { switch (e.kind()) {
case expr_kind::MetaVar: { case expr_kind::MetaVar:
expr r = metavar_type(e); if (m_menv) {
if (!r) if (m_menv->is_assigned(e))
throw kernel_exception(m_env, "metavariable does not have a type associated with it"); return infer_type(m_menv->get_subst(e), ctx);
return r; else
} return m_menv->get_type(e);
} else {
throw kernel_exception(m_env, "unexpected metavariable occurrence");
}
case expr_kind::Constant: { case expr_kind::Constant: {
object const & obj = m_env.get_object(const_name(e)); object const & obj = m_env.get_object(const_name(e));
if (obj.has_type()) if (obj.has_type())
@ -177,16 +183,16 @@ public:
imp(environment const & env): imp(environment const & env):
m_env(env), m_env(env),
m_normalizer(env) { m_normalizer(env) {
m_interrupted = false; m_interrupted = false;
m_subst = nullptr; m_menv = nullptr;
m_subst_timestamp = 0; m_menv_timestamp = 0;
m_uc = nullptr; m_uc = nullptr;
} }
expr operator()(expr const & e, context const & ctx, substitution * subst, unification_constraints * uc) { expr operator()(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & uc) {
set_ctx(ctx); set_ctx(ctx);
set_subst(subst); set_menv(menv);
flet<unification_constraints*> set(m_uc, uc); flet<unification_constraints*> set(m_uc, &uc);
return infer_type(e, ctx); return infer_type(e, ctx);
} }
@ -199,14 +205,18 @@ public:
m_cache.clear(); m_cache.clear();
m_normalizer.clear(); m_normalizer.clear();
m_ctx = context(); m_ctx = context();
m_subst = nullptr; m_menv = nullptr;
m_subst_timestamp = 0; m_menv_timestamp = 0;
} }
}; };
light_checker::light_checker(environment const & env):m_ptr(new imp(env)) {} light_checker::light_checker(environment const & env):m_ptr(new imp(env)) {}
light_checker::~light_checker() {} light_checker::~light_checker() {}
expr light_checker::operator()(expr const & e, context const & ctx, substitution * subst, unification_constraints * uc) { expr light_checker::operator()(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & uc) {
return m_ptr->operator()(e, ctx, subst, uc); return m_ptr->operator()(e, ctx, menv, uc);
}
expr light_checker::operator()(expr const & e, context const & ctx) {
buffer<unification_constraint> uc;
return operator()(e, ctx, nullptr, uc);
} }
void light_checker::clear() { m_ptr->clear(); } void light_checker::clear() { m_ptr->clear(); }
void light_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); } void light_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }

View file

@ -6,13 +6,14 @@ Author: Leonardo de Moura
*/ */
#pragma once #pragma once
#include <memory> #include <memory>
#include "util/buffer.h"
#include "kernel/expr.h" #include "kernel/expr.h"
#include "kernel/context.h" #include "kernel/context.h"
#include "kernel/unification_constraint.h"
namespace lean { namespace lean {
class environment; class environment;
class substitution; class metavar_env;
class unification_constraints;
/** /**
\brief Functional object for "quickly" inferring the type of expressions. \brief Functional object for "quickly" inferring the type of expressions.
It does not check whether the input expression is type correct or not. It does not check whether the input expression is type correct or not.
@ -30,7 +31,8 @@ public:
light_checker(environment const & env); light_checker(environment const & env);
~light_checker(); ~light_checker();
expr operator()(expr const & e, context const & ctx = context(), substitution * subst = nullptr, unification_constraints * uc = nullptr); expr operator()(expr const & e, context const & ctx, metavar_env * menv, buffer<unification_constraint> & uc);
expr operator()(expr const & e, context const & ctx = context());
void clear(); void clear();

View file

@ -7,7 +7,7 @@ Author: Leonardo de Moura
#include "kernel/occurs.h" #include "kernel/occurs.h"
#include "kernel/metavar.h" #include "kernel/metavar.h"
#include "kernel/expr_maps.h" #include "kernel/expr_maps.h"
#include "kernel/replace.h" #include "library/replace_using_ctx.h"
#include "library/placeholder.h" #include "library/placeholder.h"
namespace lean { namespace lean {
@ -24,18 +24,18 @@ bool has_placeholder(expr const & e) {
return occurs(mk_placholder(), e); return occurs(mk_placholder(), e);
} }
expr replace_placeholders_with_metavars(expr const & e, metavar_generator & mgen, expr_map<expr> * trace) { expr replace_placeholders_with_metavars(expr const & e, metavar_env & menv, expr_map<expr> * new2old) {
auto f = [&](expr const & e, unsigned) -> expr { auto f = [&](expr const & e, context const & c, unsigned) -> expr {
if (is_placeholder(e)) { if (is_placeholder(e)) {
return mgen.mk(); return menv.mk_metavar(c);
} else { } else {
return e; return e;
} }
}; };
auto p = [&](expr const & s, expr const & t) { auto p = [&](expr const & s, expr const & t) {
if (trace) if (new2old)
(*trace)[t] = s; (*new2old)[t] = s;
}; };
return replace_fn<decltype(f), decltype(p)>(f, p)(e); return replace_using_ctx_fn<decltype(f), decltype(p)>(f, p)(e);
} }
} }

View file

@ -9,8 +9,7 @@ Author: Leonardo de Moura
#include "kernel/expr_maps.h" #include "kernel/expr_maps.h"
namespace lean { namespace lean {
class substitution; class metavar_env;
class metavar_generator;
/** /**
\brief Return a new placeholder expression. To be able to track location, \brief Return a new placeholder expression. To be able to track location,
a new constant for each placeholder. a new constant for each placeholder.
@ -28,9 +27,9 @@ bool is_placeholder(expr const & e);
bool has_placeholder(expr const & e); bool has_placeholder(expr const & e);
/** /**
\brief Replace the placeholders in \c e with fresh metavariables from \c mgen. \brief Replace the placeholders in \c e with fresh metavariables from \c menv.
if \c trace is not null, then for each new expression \c t created based on if \c new2old is not nullptr, then for each new expression \c t created based on
\c s, we store <tt>(*trace)[t] = s</tt>. We say this is traceability information. \c s, we store <tt>(*new2old)[t] = s</tt>.
*/ */
expr replace_placeholders_with_metavars(expr const & e, metavar_generator & mgen, expr_map<expr> * trace = nullptr); expr replace_placeholders_with_metavars(expr const & e, metavar_env & menv, expr_map<expr> * new2old = nullptr);
} }

View file

@ -17,32 +17,13 @@ Author: Leonardo de Moura
#include "kernel/environment.h" #include "kernel/environment.h"
#include "kernel/type_checker.h" #include "kernel/type_checker.h"
#include "kernel/printer.h" #include "kernel/printer.h"
#include "kernel/kernel_exception.h"
#include "library/placeholder.h" #include "library/placeholder.h"
#include "library/state.h"
#include "library/arith/arith.h" #include "library/arith/arith.h"
#include "library/all/all.h" #include "library/all/all.h"
using namespace lean; using namespace lean;
class unification_constraints_dbg : public unification_constraints {
typedef std::tuple<context, expr, expr> constraint;
typedef std::vector<constraint> constraints;
constraints m_eqs;
constraints m_type_of_eqs;
public:
unification_constraints_dbg() {}
virtual ~unification_constraints_dbg() {}
virtual void add(context const & ctx, expr const & lhs, expr const & rhs) { m_eqs.push_back(constraint(ctx, lhs, rhs)); }
virtual void add_type_of(context const & ctx, expr const & n, expr const & t) { m_type_of_eqs.push_back(constraint(ctx, n, t)); }
constraints const & eqs() const { return m_eqs; }
constraints const & type_of_eqs() const { return m_type_of_eqs; }
friend std::ostream & operator<<(std::ostream & out, unification_constraints_dbg const & uc) {
for (auto c : uc.m_eqs)
std::cout << std::get<0>(c) << " |- " << std::get<1>(c) << " == " << std::get<2>(c) << "\n";
for (auto c : uc.m_type_of_eqs)
std::cout << std::get<0>(c) << " |- " << std::get<1>(c) << " : " << std::get<2>(c) << "\n";
return out;
}
};
std::ostream & operator<<(std::ostream & out, substitution const & env) { std::ostream & operator<<(std::ostream & out, substitution const & env) {
bool first = true; bool first = true;
env.for_each([&](name const & n, expr const & v) { env.for_each([&](name const & n, expr const & v) {
@ -52,82 +33,86 @@ std::ostream & operator<<(std::ostream & out, substitution const & env) {
return out; return out;
} }
std::ostream & operator<<(std::ostream & out, buffer<unification_constraint> const & uc) {
formatter fmt = mk_simple_formatter();
for (auto c : uc) {
out << c.pp(fmt, options(), true) << "\n";
}
return out;
}
static void tst1() { static void tst1() {
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); lean_assert(!menv.is_assigned(m1));
lean_assert(!subst.is_assigned(m1)); expr t1 = menv.get_type(m1);
expr t1 = metavar_type(m1);
lean_assert(is_metavar(t1)); lean_assert(is_metavar(t1));
lean_assert(is_eqp(metavar_type(m1), t1)); lean_assert(is_eqp(menv.get_type(m1), t1));
lean_assert(is_eqp(metavar_type(m1), t1)); lean_assert(is_eqp(menv.get_type(m1), t1));
lean_assert(!subst.is_assigned(m1)); lean_assert(!menv.is_assigned(m1));
expr m2 = gen.mk(); expr m2 = menv.mk_metavar();
lean_assert(!subst.is_assigned(m1)); lean_assert(!menv.is_assigned(m1));
expr t2 = metavar_type(m2); expr t2 = menv.get_type(m2);
lean_assert(is_metavar(m2)); lean_assert(is_metavar(m2));
lean_assert(!is_eqp(t1, t2)); lean_assert(!is_eqp(t1, t2));
lean_assert(t1 != t2); lean_assert(t1 != t2);
expr f = Const("f"); expr f = Const("f");
expr a = Const("a"); expr a = Const("a");
subst.assign(m1, f(a)); menv.assign(m1, f(a));
lean_assert(subst.is_assigned(m1)); lean_assert(menv.is_assigned(m1));
lean_assert(!subst.is_assigned(m2)); lean_assert(!menv.is_assigned(m2));
lean_assert(subst.get_subst(m1) == f(a)); lean_assert(menv.get_subst(m1) == f(a));
} }
static void tst2() { static void tst2() {
substitution subst; metavar_env menv;
metavar_generator gen;
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
expr a = Const("a"); expr a = Const("a");
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr m2 = gen.mk(); 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
std::cout << "---------------------\n"; std::cout << "---------------------\n";
expr m11 = add_inst(m1, 0, f(a, m2)); expr m11 = add_inst(m1, 0, f(a, m2));
std::cout << m11 << "\n"; std::cout << m11 << "\n";
subst.assign(m1, f(Var(0))); menv.assign(m1, f(Var(0)));
std::cout << instantiate_metavars(m11, subst) << "\n"; std::cout << instantiate_metavars(m11, menv) << "\n";
subst.assign(m2, g(a, Var(1))); menv.assign(m2, g(a, Var(1)));
std::cout << instantiate_metavars(h(m11), subst) << "\n"; std::cout << instantiate_metavars(h(m11), menv) << "\n";
lean_assert(instantiate_metavars(h(m11), subst) == h(f(f(a, g(a, Var(1)))))); lean_assert(instantiate_metavars(h(m11), menv) == h(f(f(a, g(a, Var(1))))));
} }
static void tst3() { static void tst3() {
substitution subst; metavar_env menv;
metavar_generator gen;
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
expr a = Const("a"); expr a = Const("a");
expr x = Const("x"); expr x = Const("x");
expr T = Const("T"); expr T = Const("T");
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr F = Fun({x, T}, f(m1, x)); expr F = Fun({x, T}, f(m1, x));
subst.assign(m1, h(Var(0), Var(2))); menv.assign(m1, h(Var(0), Var(2)));
std::cout << instantiate(abst_body(F), g(a)) << "\n"; std::cout << instantiate(abst_body(F), g(a)) << "\n";
std::cout << instantiate_metavars(instantiate(abst_body(F), g(a)), subst) << "\n"; std::cout << instantiate_metavars(instantiate(abst_body(F), g(a)), menv) << "\n";
lean_assert(instantiate_metavars(instantiate(abst_body(F), g(a)), subst) == f(h(g(a), Var(1)), g(a))); lean_assert(instantiate_metavars(instantiate(abst_body(F), g(a)), menv) == f(h(g(a), Var(1)), g(a)));
std::cout << instantiate(instantiate_metavars(abst_body(F), subst), g(a)) << "\n"; std::cout << instantiate(instantiate_metavars(abst_body(F), menv), g(a)) << "\n";
lean_assert(instantiate(instantiate_metavars(abst_body(F), subst), g(a)) == lean_assert(instantiate(instantiate_metavars(abst_body(F), menv), g(a)) ==
instantiate_metavars(instantiate(abst_body(F), g(a)), subst)); instantiate_metavars(instantiate(abst_body(F), g(a)), menv));
} }
static void tst4() { static void tst4() {
substitution subst; metavar_env menv;
metavar_generator gen;
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
expr a = Const("a"); expr a = Const("a");
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr F = f(m1, Var(2)); expr F = f(m1, Var(2));
subst.assign(m1, h(Var(1))); menv.assign(m1, h(Var(1)));
std::cout << instantiate(F, {g(Var(0)), h(a)}) << "\n"; std::cout << instantiate(F, {g(Var(0)), h(a)}) << "\n";
std::cout << instantiate_metavars(instantiate(F, {g(Var(0)), h(a)}), subst) << "\n"; std::cout << instantiate_metavars(instantiate(F, {g(Var(0)), h(a)}), menv) << "\n";
} }
static void tst5() { static void tst5() {
@ -142,18 +127,17 @@ static void tst6() {
expr a = Const("a"); expr a = Const("a");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m2 = menv.mk_metavar();
expr m2 = gen.mk();
expr t = f(Var(0), Fun({x, N}, f(Var(1), x, Fun({y, N}, f(Var(2), x, y))))); expr t = f(Var(0), Fun({x, N}, f(Var(1), x, Fun({y, N}, f(Var(2), x, y)))));
expr r = instantiate(t, g(m1, m2)); expr r = instantiate(t, g(m1, m2));
std::cout << r << std::endl; std::cout << r << std::endl;
subst.assign(m2, Var(2)); menv.assign(m2, Var(2));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
subst.assign(m1, h(Var(3))); menv.assign(m1, h(Var(3)));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
lean_assert(r == f(g(h(Var(3)), Var(2)), Fun({x, N}, f(g(h(Var(4)), Var(3)), x, Fun({y, N}, f(g(h(Var(5)), Var(4)), x, y)))))); lean_assert(r == f(g(h(Var(3)), Var(2)), Fun({x, N}, f(g(h(Var(4)), Var(3)), x, Fun({y, N}, f(g(h(Var(5)), Var(4)), x, y))))));
} }
@ -162,13 +146,12 @@ static void tst7() {
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr a = Const("a"); expr a = Const("a");
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr t = f(m1, Var(0)); expr t = f(m1, Var(0));
expr r = instantiate(t, a); expr r = instantiate(t, a);
subst.assign(m1, g(Var(0))); menv.assign(m1, g(Var(0)));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
lean_assert(r == f(g(a), a)); lean_assert(r == f(g(a), a));
} }
@ -177,13 +160,12 @@ static void tst8() {
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr a = Const("a"); expr a = Const("a");
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr t = f(m1, Var(0), Var(2)); expr t = f(m1, Var(0), Var(2));
expr r = instantiate(t, a); expr r = instantiate(t, a);
subst.assign(m1, g(Var(0), Var(1))); menv.assign(m1, g(Var(0), Var(1)));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
lean_assert(r == f(g(a, Var(0)), a, Var(1))); lean_assert(r == f(g(a, Var(0)), a, Var(1)));
} }
@ -192,16 +174,15 @@ static void tst9() {
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr a = Const("a"); expr a = Const("a");
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr t = f(m1, Var(1), Var(2)); expr t = f(m1, Var(1), Var(2));
expr r = lift_free_vars(t, 1, 2); expr r = lift_free_vars(t, 1, 2);
std::cout << r << std::endl; std::cout << r << std::endl;
r = instantiate(r, a); r = instantiate(r, a);
std::cout << r << std::endl; std::cout << r << std::endl;
subst.assign(m1, g(Var(0), Var(1))); menv.assign(m1, g(Var(0), Var(1)));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
lean_assert(r == f(g(a, Var(2)), Var(2), Var(3))); lean_assert(r == f(g(a, Var(2)), Var(2), Var(3)));
} }
@ -214,39 +195,36 @@ static void tst10() {
expr a = Const("a"); expr a = Const("a");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m2 = menv.mk_metavar();
expr m2 = gen.mk();
expr t = f(Var(0), Fun({x, N}, f(Var(1), Var(2), x, Fun({y, N}, f(Var(2), x, y))))); expr t = f(Var(0), Fun({x, N}, f(Var(1), Var(2), x, Fun({y, N}, f(Var(2), x, y)))));
expr r = instantiate(t, g(m1)); expr r = instantiate(t, g(m1));
std::cout << r << std::endl; std::cout << r << std::endl;
r = instantiate(r, h(m2)); r = instantiate(r, h(m2));
std::cout << r << std::endl; std::cout << r << std::endl;
subst.assign(m1, f(Var(0))); menv.assign(m1, f(Var(0)));
subst.assign(m2, Var(2)); menv.assign(m2, Var(2));
r = instantiate_metavars(r, subst); r = instantiate_metavars(r, menv);
std::cout << r << std::endl; std::cout << r << std::endl;
lean_assert(r == f(g(f(h(Var(2)))), Fun({x, N}, f(g(f(h(Var(3)))), h(Var(3)), x, Fun({y, N}, f(g(f(h(Var(4)))), x, y)))))); lean_assert(r == f(g(f(h(Var(2)))), Fun({x, N}, f(g(f(h(Var(3)))), h(Var(3)), x, Fun({y, N}, f(g(f(h(Var(4)))), x, y))))));
} }
static void tst11() { static void tst11() {
substitution subst; metavar_env menv;
unsigned t1 = subst.get_timestamp(); unsigned t1 = menv.get_timestamp();
metavar_generator gen; expr m = menv.mk_metavar();
expr m = gen.mk(); unsigned t2 = menv.get_timestamp();
unsigned t2 = subst.get_timestamp(); lean_assert(t2 > t1);
lean_assert(t2 == t1); lean_assert(!menv.is_assigned(m));
lean_assert(!subst.is_assigned(m)); lean_assert(menv.get_timestamp() == t2);
lean_assert(subst.get_timestamp() == t2); menv.assign(m, Const("a"));
subst.assign(m, Const("a")); lean_assert(menv.get_timestamp() > t2);
lean_assert(subst.get_timestamp() > t2);
} }
static void tst12() { static void tst12() {
substitution subst; metavar_env menv;
metavar_generator gen; expr m = menv.mk_metavar();
expr m = gen.mk();
expr f = Const("f"); expr f = Const("f");
std::cout << instantiate(f(m), {Var(0), Var(1)}) << "\n"; std::cout << instantiate(f(m), {Var(0), Var(1)}) << "\n";
std::cout << instantiate(f(m), {Var(1), Var(0)}) << "\n"; std::cout << instantiate(f(m), {Var(1), Var(0)}) << "\n";
@ -254,9 +232,8 @@ static void tst12() {
static void tst13() { static void tst13() {
environment env; environment env;
substitution subst; metavar_env menv;
metavar_generator gen; expr m = menv.mk_metavar();
expr m = gen.mk();
env.add_var("N", Type()); env.add_var("N", Type());
expr N = Const("N"); expr N = Const("N");
env.add_var("f", N >> N); env.add_var("f", N >> N);
@ -267,18 +244,17 @@ static void tst13() {
expr F = Fun({x, N}, f(m))(a); expr F = Fun({x, N}, f(m))(a);
normalizer norm(env); normalizer norm(env);
std::cout << norm(F) << "\n"; std::cout << norm(F) << "\n";
subst.assign(m, Var(0)); menv.assign(m, Var(0));
std::cout << norm(instantiate_metavars(F, subst)) << "\n"; std::cout << norm(instantiate_metavars(F, menv)) << "\n";
lean_assert(norm(instantiate_metavars(F, subst)) == lean_assert(norm(instantiate_metavars(F, menv)) ==
instantiate_metavars(norm(F), subst)); instantiate_metavars(norm(F), menv));
} }
static void tst14() { static void tst14() {
environment env; environment env;
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m2 = menv.mk_metavar();
expr m2 = gen.mk();
expr N = Const("N"); expr N = Const("N");
expr f = Const("f"); expr f = Const("f");
expr h = Const("h"); expr h = Const("h");
@ -289,17 +265,17 @@ static void tst14() {
env.add_var("h", Pi({N, Type()}, N >> (N >> N))); env.add_var("h", Pi({N, Type()}, N >> (N >> N)));
expr F1 = Fun({{N, Type()}, {a, N}, {f, N >> N}}, expr F1 = Fun({{N, Type()}, {a, N}, {f, N >> N}},
(Fun({{x, N}, {y, N}}, Eq(f(m1), y)))(a)); (Fun({{x, N}, {y, N}}, Eq(f(m1), y)))(a));
substitution subst2 = subst; metavar_env menv2 = menv;
subst2.assign(m1, h(Var(4), Var(1), Var(3))); menv2.assign(m1, h(Var(4), Var(1), Var(3)));
normalizer norm(env); normalizer norm(env);
env.add_var("M", Type()); env.add_var("M", Type());
expr M = Const("M"); expr M = Const("M");
std::cout << norm(F1) << "\n"; std::cout << norm(F1) << "\n";
std::cout << instantiate_metavars(norm(F1), subst2) << "\n"; std::cout << instantiate_metavars(norm(F1), menv2) << "\n";
std::cout << instantiate_metavars(F1, subst2) << "\n"; std::cout << instantiate_metavars(F1, menv2) << "\n";
std::cout << norm(instantiate_metavars(F1, subst2)) << "\n"; std::cout << norm(instantiate_metavars(F1, menv2)) << "\n";
lean_assert(instantiate_metavars(norm(F1), subst2) == lean_assert(instantiate_metavars(norm(F1), menv2) ==
norm(instantiate_metavars(F1, subst2))); norm(instantiate_metavars(F1, menv2)));
expr F2 = (Fun({{N, Type()}, {f, N >> N}, {a, N}, {b, N}}, expr F2 = (Fun({{N, Type()}, {f, N >> N}, {a, N}, {b, N}},
(Fun({{x, N}, {y, N}}, Eq(f(m1), y)))(a, m2)))(M); (Fun({{x, N}, {y, N}}, Eq(f(m1), y)))(a, m2)))(M);
std::cout << norm(F2) << "\n"; std::cout << norm(F2) << "\n";
@ -310,10 +286,9 @@ static void tst14() {
static void tst15() { static void tst15() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr f = Const("f"); expr f = Const("f");
expr x = Const("x"); expr x = Const("x");
expr y = Const("y"); expr y = Const("y");
@ -322,22 +297,21 @@ static void tst15() {
env.add_var("N", Type()); env.add_var("N", Type());
env.add_var("f", Type() >> Type()); env.add_var("f", Type() >> Type());
expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, f(m1))(N, N)); expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, f(m1))(N, N));
subst.assign(m1, Var(2)); menv.assign(m1, Var(2));
std::cout << norm(F) << "\n"; std::cout << norm(F) << "\n";
std::cout << instantiate_metavars(norm(F), subst) << "\n"; std::cout << instantiate_metavars(norm(F), menv) << "\n";
std::cout << norm(instantiate_metavars(F, subst)) << "\n"; std::cout << norm(instantiate_metavars(F, menv)) << "\n";
lean_assert(instantiate_metavars(norm(F), subst) == lean_assert(instantiate_metavars(norm(F), menv) ==
norm(instantiate_metavars(F, subst))); norm(instantiate_metavars(F, menv)));
} }
static void tst16() { static void tst16() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
context ctx; context ctx;
ctx = extend(ctx, "w", Type()); ctx = extend(ctx, "w", Type());
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr f = Const("f"); expr f = Const("f");
expr x = Const("x"); expr x = Const("x");
expr y = Const("y"); expr y = Const("y");
@ -345,23 +319,22 @@ static void tst16() {
expr N = Const("N"); expr N = Const("N");
env.add_var("N", Type()); env.add_var("N", Type());
expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, m1)(N, N)); expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, m1)(N, N));
subst.assign(m1, Var(3)); menv.assign(m1, Var(3));
std::cout << norm(F, ctx) << "\n"; std::cout << norm(F, ctx) << "\n";
std::cout << instantiate_metavars(norm(F, ctx), subst) << "\n"; std::cout << instantiate_metavars(norm(F, ctx), menv) << "\n";
std::cout << norm(instantiate_metavars(F, subst), ctx) << "\n"; std::cout << norm(instantiate_metavars(F, menv), ctx) << "\n";
} }
static void tst17() { static void tst17() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
context ctx; context ctx;
ctx = extend(ctx, "w1", Type()); ctx = extend(ctx, "w1", Type());
ctx = extend(ctx, "w2", Type()); ctx = extend(ctx, "w2", Type());
ctx = extend(ctx, "w3", Type()); ctx = extend(ctx, "w3", Type());
ctx = extend(ctx, "w4", Type()); ctx = extend(ctx, "w4", Type());
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr f = Const("f"); expr f = Const("f");
expr x = Const("x"); expr x = Const("x");
expr y = Const("y"); expr y = Const("y");
@ -369,33 +342,32 @@ static void tst17() {
expr N = Const("N"); expr N = Const("N");
env.add_var("N", Type()); env.add_var("N", Type());
expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, m1)(N, N)); expr F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}}, m1)(N, N));
substitution subst2 = subst; metavar_env menv2 = menv;
subst.assign(m1, Var(3)); menv.assign(m1, Var(3));
std::cout << norm(F, ctx) << "\n"; std::cout << norm(F, ctx) << "\n";
std::cout << instantiate_metavars(norm(F, ctx), subst) << "\n"; std::cout << instantiate_metavars(norm(F, ctx), menv) << "\n";
std::cout << norm(instantiate_metavars(F, subst), ctx) << "\n"; std::cout << norm(instantiate_metavars(F, menv), ctx) << "\n";
F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}, {x, Type()}, {y, Type()}, {x, Type()}}, m1)(N, N, N, N, N)); F = Fun({z, Type()}, Fun({{x, Type()}, {y, Type()}, {x, Type()}, {y, Type()}, {x, Type()}}, m1)(N, N, N, N, N));
lean_assert(instantiate_metavars(norm(F, ctx), subst) == lean_assert(instantiate_metavars(norm(F, ctx), menv) ==
norm(instantiate_metavars(F, subst), ctx)); norm(instantiate_metavars(F, menv), ctx));
std::cout << "----------------------\n"; std::cout << "----------------------\n";
subst2.assign(m1, Var(8)); menv2.assign(m1, Var(8));
std::cout << norm(F, ctx) << "\n"; std::cout << norm(F, ctx) << "\n";
std::cout << instantiate_metavars(norm(F, ctx), subst2) << "\n"; std::cout << instantiate_metavars(norm(F, ctx), menv2) << "\n";
std::cout << norm(instantiate_metavars(F, subst2), ctx) << "\n"; std::cout << norm(instantiate_metavars(F, menv2), ctx) << "\n";
lean_assert(instantiate_metavars(norm(F, ctx), subst2) == lean_assert(instantiate_metavars(norm(F, ctx), menv2) ==
norm(instantiate_metavars(F, subst2), ctx)); norm(instantiate_metavars(F, menv2), ctx));
} }
static void tst18() { static void tst18() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
context ctx; context ctx;
ctx = extend(ctx, "w1", Type()); ctx = extend(ctx, "w1", Type());
ctx = extend(ctx, "w2", Type()); ctx = extend(ctx, "w2", Type());
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m2 = menv.mk_metavar();
expr m2 = gen.mk();
expr f = Const("f"); expr f = Const("f");
expr g = Const("g"); expr g = Const("g");
expr h = Const("h"); expr h = Const("h");
@ -410,26 +382,25 @@ static void tst18() {
env.add_var("h", N >> (N >> N)); env.add_var("h", N >> (N >> N));
expr F = Fun({z, Type()}, Fun({{f, N >> N}, {y, Type()}}, m1)(Fun({x, N}, g(z, x, m2)), N)); expr F = Fun({z, Type()}, Fun({{f, N >> N}, {y, Type()}}, m1)(Fun({x, N}, g(z, x, m2)), N));
std::cout << norm(F, ctx) << "\n"; std::cout << norm(F, ctx) << "\n";
substitution subst2 = subst; metavar_env menv2 = menv;
subst2.assign(m1, Var(1)); menv2.assign(m1, Var(1));
subst2.assign(m2, h(Var(2), Var(1))); menv2.assign(m2, h(Var(2), Var(1)));
std::cout << instantiate_metavars(norm(F, ctx), subst2) << "\n"; std::cout << instantiate_metavars(norm(F, ctx), menv2) << "\n";
std::cout << instantiate_metavars(F, subst2) << "\n"; std::cout << instantiate_metavars(F, menv2) << "\n";
lean_assert(instantiate_metavars(norm(F, ctx), subst2) == lean_assert(instantiate_metavars(norm(F, ctx), menv2) ==
norm(instantiate_metavars(F, subst2), ctx)); norm(instantiate_metavars(F, menv2), ctx));
lean_assert(instantiate_metavars(norm(F, ctx), subst2) == lean_assert(instantiate_metavars(norm(F, ctx), menv2) ==
Fun({{z, Type()}, {x, N}}, g(z, x, h(Var(2), z)))); Fun({{z, Type()}, {x, N}}, g(z, x, h(Var(2), z))));
} }
static void tst19() { static void tst19() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
context ctx; context ctx;
ctx = extend(ctx, "w1", Type()); ctx = extend(ctx, "w1", Type());
ctx = extend(ctx, "w2", Type()); ctx = extend(ctx, "w2", Type());
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr x = Const("x"); expr x = Const("x");
expr y = Const("y"); expr y = Const("y");
expr N = Const("N"); expr N = Const("N");
@ -442,13 +413,12 @@ static void tst19() {
static void tst20() { static void tst20() {
environment env; environment env;
substitution subst; metavar_env menv;
normalizer norm(env); normalizer norm(env);
context ctx; context ctx;
ctx = extend(ctx, "w1", Type()); ctx = extend(ctx, "w1", Type());
ctx = extend(ctx, "w2", Type()); ctx = extend(ctx, "w2", Type());
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr x = Const("x"); expr x = Const("x");
expr y = Const("y"); expr y = Const("y");
expr z = Const("z"); expr z = Const("z");
@ -464,12 +434,11 @@ static void tst20() {
} }
static void tst21() { static void tst21() {
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk();
expr l = add_lift(add_lift(m1, 0, 1), 1, 1); expr l = add_lift(add_lift(m1, 0, 1), 1, 1);
expr r = add_lift(m1, 0, 2); expr r = add_lift(m1, 0, 2);
std::cout << metavar_type(l) << " " << metavar_type(r) << "\n"; std::cout << menv.get_type(l) << " " << menv.get_type(r) << "\n";
lean_assert_eq(l, r); lean_assert_eq(l, r);
lean_assert_eq(add_lift(add_lift(m1, 1, 2), 3, 4), lean_assert_eq(add_lift(add_lift(m1, 1, 2), 3, 4),
add_lift(m1, 1, 6)); add_lift(m1, 1, 6));
@ -480,21 +449,18 @@ static void tst21() {
#define _ mk_placholder() #define _ mk_placholder()
static void tst22() { static void tst22() {
substitution subst; metavar_env menv;
metavar_generator mgen;
expr f = Const("f"); expr f = Const("f");
expr x = Const("x"); expr x = Const("x");
expr N = Const("N"); expr N = Const("N");
expr F = f(Fun({x, N}, f(_, x)), _); expr F = f(Fun({x, N}, f(_, x)), _);
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << replace_placeholders_with_metavars(F, mgen) << "\n"; std::cout << replace_placeholders_with_metavars(F, menv) << "\n";
} }
static void tst23() { static void tst23() {
environment env; environment env;
substitution subst; metavar_env menv;
unification_constraints_dbg up;
metavar_generator mgen;
type_checker checker(env); type_checker checker(env);
expr N = Const("N"); expr N = Const("N");
expr f = Const("f"); expr f = Const("f");
@ -504,30 +470,35 @@ static void tst23() {
env.add_var("a", N); env.add_var("a", N);
expr x = Const("x"); expr x = Const("x");
expr F0 = f(Fun({x, N}, f(_, x))(a), _); expr F0 = f(Fun({x, N}, f(_, x))(a), _);
expr F1 = replace_placeholders_with_metavars(F0, mgen); expr F1 = replace_placeholders_with_metavars(F0, menv);
buffer<unification_constraint> up;
std::cout << F1 << "\n"; std::cout << F1 << "\n";
std::cout << checker.infer_type(F1, context(), &subst, &mgen, &up) << "\n"; try {
std::cout << checker.infer_type(F1, context(), &menv, up) << "\n";
} catch (kernel_exception & ex) {
formatter fmt = mk_simple_formatter();
state st(options(), fmt);
regular(st) << ex << "\n";
}
std::cout << up << "\n"; std::cout << up << "\n";
} }
static void tst24() { static void tst24() {
substitution subst; metavar_env menv;
metavar_generator gen; expr m1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m2 = menv.mk_metavar();
expr m2 = gen.mk();
expr f = Const("f"); expr f = Const("f");
expr a = Const("a"); expr a = Const("a");
subst.assign(m1, f(m2)); menv.assign(m1, f(m2));
subst.assign(m2, a); menv.assign(m2, a);
lean_assert(instantiate_metavars(f(m1), subst) == f(f(a))); lean_assert(instantiate_metavars(f(m1), menv) == f(f(a)));
std::cout << instantiate_metavars(f(m1), subst) << "\n"; std::cout << instantiate_metavars(f(m1), menv) << "\n";
} }
static void tst25() { static void tst25() {
environment env; environment env;
substitution subst; metavar_env menv;
unification_constraints_dbg up; buffer<unification_constraint> up;
metavar_generator gen;
type_checker checker(env); type_checker checker(env);
expr N = Const("N"); expr N = Const("N");
expr a = Const("a"); expr a = Const("a");
@ -535,10 +506,10 @@ static void tst25() {
env.add_var("N", Type()); env.add_var("N", Type());
env.add_var("a", N); env.add_var("a", N);
env.add_var("b", N); env.add_var("b", N);
expr m = gen.mk(); expr m = menv.mk_metavar();
expr F = m(a, b); expr F = m(a, b);
std::cout << checker.infer_type(F, context(), &subst, &gen, &up) << "\n"; std::cout << checker.infer_type(F, context(), &menv, up) << "\n";
std::cout << subst << "\n"; std::cout << menv << "\n";
std::cout << up << "\n"; std::cout << up << "\n";
} }
@ -556,9 +527,8 @@ static void tst26() {
std::cout << "\ntst26\n"; std::cout << "\ntst26\n";
environment env; environment env;
import_all(env); import_all(env);
substitution subst; metavar_env menv;
unification_constraints_dbg up; buffer<unification_constraint> up;
metavar_generator gen;
type_checker checker(env); type_checker checker(env);
expr list = Const("list"); expr list = Const("list");
expr nil = Const("nil"); expr nil = Const("nil");
@ -575,17 +545,17 @@ static void tst26() {
expr b = Const("b"); expr b = Const("b");
expr n = Const("n"); expr n = Const("n");
expr m = Const("m"); expr m = Const("m");
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr m2 = gen.mk(); expr m2 = menv.mk_metavar();
expr m3 = gen.mk(); expr m3 = menv.mk_metavar();
expr A1 = gen.mk(); expr A1 = menv.mk_metavar();
expr A2 = gen.mk(); expr A2 = menv.mk_metavar();
expr A3 = gen.mk(); expr A3 = menv.mk_metavar();
expr A4 = gen.mk(); expr A4 = menv.mk_metavar();
expr F = cons(A1, m1(a), cons(A2, m2(n), cons(A3, m3(b), nil(A4)))); expr F = cons(A1, m1(a), cons(A2, m2(n), cons(A3, m3(b), nil(A4))));
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &subst, &gen, &up) << "\n"; std::cout << checker.infer_type(F, context(), &menv, up) << "\n";
std::cout << subst << "\n"; std::cout << menv << "\n";
std::cout << up << "\n"; std::cout << up << "\n";
} }
@ -599,9 +569,8 @@ static void tst27() {
std::cout << "\ntst27\n"; std::cout << "\ntst27\n";
environment env; environment env;
import_all(env); import_all(env);
substitution subst; metavar_env menv;
unification_constraints_dbg up; buffer<unification_constraint> up;
metavar_generator gen;
type_checker checker(env); type_checker checker(env);
expr A = Const("A"); expr A = Const("A");
expr f = Const("f"); expr f = Const("f");
@ -612,15 +581,15 @@ static void tst27() {
env.add_var("f", Pi({A, Type()}, A >> (A >> Bool))); env.add_var("f", Pi({A, Type()}, A >> (A >> Bool)));
env.add_var("a", Int); env.add_var("a", Int);
env.add_var("b", Real); env.add_var("b", Real);
expr T1 = gen.mk(); expr T1 = menv.mk_metavar();
expr T2 = gen.mk(); expr T2 = menv.mk_metavar();
expr A1 = gen.mk(); expr A1 = menv.mk_metavar();
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr m2 = gen.mk(); expr m2 = menv.mk_metavar();
expr F = Fun({{x, T1}, {y, T2}}, f(A1, x, y))(m1(a), m2(b)); expr F = Fun({{x, T1}, {y, T2}}, f(A1, x, y))(m1(a), m2(b));
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &subst, &gen, &up) << "\n"; std::cout << checker.infer_type(F, context(), &menv, up) << "\n";
std::cout << subst << "\n"; std::cout << menv << "\n";
std::cout << up << "\n"; std::cout << up << "\n";
} }

View file

@ -7,6 +7,7 @@ Author: Leonardo de Moura
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <string>
#include "util/test.h" #include "util/test.h"
#include "util/trace.h" #include "util/trace.h"
#include "util/exception.h" #include "util/exception.h"

View file

@ -17,7 +17,7 @@ static void tst1() {
expr t = Type(); expr t = Type();
expr z = Const("z"); expr z = Const("z");
local_context lctx{mk_lift(0, 1), mk_inst(0, a)}; local_context lctx{mk_lift(0, 1), mk_inst(0, a)};
expr m = mk_metavar("a", expr(), lctx); expr m = mk_metavar("a", lctx);
expr F = mk_let("z", Type(), Type(level()+1), mk_pi("y", t, mk_lambda("x", t, f(f(f(x, a), Const("10")), Eq(x, m))))); expr F = mk_let("z", Type(), Type(level()+1), mk_pi("y", t, mk_lambda("x", t, f(f(f(x, a), Const("10")), Eq(x, m)))));
expr G = deep_copy(F); expr G = deep_copy(F);
lean_assert(F == G); lean_assert(F == G);

View file

@ -70,12 +70,12 @@ static void tst1() {
local_context lctx3{mk_lift(3, 1), mk_inst(0, Const("a"))}; local_context lctx3{mk_lift(3, 1), mk_inst(0, Const("a"))};
local_context lctx4{mk_lift(0, 1), mk_inst(0, Const("a")), mk_inst(0, Const("b"))}; local_context lctx4{mk_lift(0, 1), mk_inst(0, Const("a")), mk_inst(0, Const("b"))};
local_context lctx5{mk_inst(0, Const("a")), mk_inst(0, Const("a"))}; local_context lctx5{mk_inst(0, Const("a")), mk_inst(0, Const("a"))};
lt(mk_metavar("a", expr(), lctx1), mk_metavar("b", expr(), lctx1), true); lt(mk_metavar("a", lctx1), mk_metavar("b", lctx1), true);
lt(mk_metavar("a", expr(), lctx1), mk_metavar("a", expr(), lctx2), true); lt(mk_metavar("a", lctx1), mk_metavar("a", lctx2), true);
lt(mk_metavar("a", expr(), lctx1), mk_metavar("a", expr(), lctx3), true); lt(mk_metavar("a", lctx1), mk_metavar("a", lctx3), true);
lt(mk_metavar("a", expr(), lctx1), mk_metavar("a", expr(), lctx4), true); lt(mk_metavar("a", lctx1), mk_metavar("a", lctx4), true);
lt(mk_metavar("a", expr(), lctx1), mk_metavar("a", expr(), lctx5), true); lt(mk_metavar("a", lctx1), mk_metavar("a", lctx5), true);
lt(mk_metavar("a", expr(), lctx1), mk_metavar("a", expr(), lctx1), false); lt(mk_metavar("a", lctx1), mk_metavar("a", lctx1), false);
} }
int main() { int main() {

View file

@ -80,8 +80,8 @@ void tst3() {
expr m1; // = subst.mk_metavar(); expr m1; // = subst.mk_metavar();
expr m2; // = subst.mk_metavar(); expr m2; // = subst.mk_metavar();
expr m3; // = subst.mk_metavar(); expr m3; // = subst.mk_metavar();
expr t1 = metavar_type(m1); expr t1; // = metavar_type(m1);
expr t2 = metavar_type(m2); expr t2; // = metavar_type(m2);
expr f = Const("f"); expr f = Const("f");
expr a = Const("a"); expr a = Const("a");
expr b = Const("b"); expr b = Const("b");

View file

@ -30,8 +30,8 @@ static void tst1() {
lean_assert(is_eqp(arg(F2, 1), arg(F2, 2))); lean_assert(is_eqp(arg(F2, 1), arg(F2, 2)));
max_fn.clear(); max_fn.clear();
local_context lctx{mk_lift(1, 1), mk_inst(0, a1)}; local_context lctx{mk_lift(1, 1), mk_inst(0, a1)};
expr m1 = mk_metavar("m1", expr(), lctx); expr m1 = mk_metavar("m1", lctx);
expr m2 = mk_metavar("m1", expr(), lctx); expr m2 = mk_metavar("m1", lctx);
F1 = f(m1, m2); F1 = f(m1, m2);
lean_assert(!is_eqp(arg(F1, 1), arg(F1, 2))); lean_assert(!is_eqp(arg(F1, 1), arg(F1, 2)));
F2 = max_fn(F1); F2 = max_fn(F1);

View file

@ -399,9 +399,9 @@ static void match_eq_tst3() {
static void match_metavar_tst1() { static void match_metavar_tst1() {
cout << "--- match_metavar_tst1() ---" << endl; cout << "--- match_metavar_tst1() ---" << endl;
metavar_generator gen; metavar_env menv;
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr m2 = gen.mk(); expr m2 = menv.mk_metavar();
expr f = Const("f"); expr f = Const("f");
subst_map s; subst_map s;
bool result = test_match(m1, m1, 0, s); bool result = test_match(m1, m1, 0, s);
@ -411,9 +411,9 @@ static void match_metavar_tst1() {
static void match_metavar_tst2() { static void match_metavar_tst2() {
cout << "--- match_metavar_tst2() ---" << endl; cout << "--- match_metavar_tst2() ---" << endl;
metavar_generator gen; metavar_env menv;
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr m2 = gen.mk(); expr m2 = menv.mk_metavar();
expr f = Const("f"); expr f = Const("f");
subst_map s; subst_map s;
bool result = test_match(m1, m2, 0, s); bool result = test_match(m1, m2, 0, s);
@ -423,8 +423,8 @@ static void match_metavar_tst2() {
static void match_metavar_tst3() { static void match_metavar_tst3() {
cout << "--- match_metavar_tst3() ---" << endl; cout << "--- match_metavar_tst3() ---" << endl;
metavar_generator gen; metavar_env menv;
expr m1 = gen.mk(); expr m1 = menv.mk_metavar();
expr f = Const("f"); expr f = Const("f");
subst_map s; subst_map s;
bool result = test_match(m1, f, 0, s); bool result = test_match(m1, f, 0, s);