2013-08-25 01:02:38 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include "elaborator.h"
|
|
|
|
#include "free_vars.h"
|
|
|
|
#include "beta.h"
|
|
|
|
#include "instantiate.h"
|
|
|
|
#include "builtin.h"
|
|
|
|
#include "exception.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2013-08-25 17:34:19 +00:00
|
|
|
static name g_overload_name(name(name(name(0u), "library"), "overload"));
|
|
|
|
static expr g_overload = mk_constant(g_overload_name);
|
|
|
|
|
|
|
|
bool is_overload_marker(expr const & e) {
|
|
|
|
return e == g_overload;
|
|
|
|
}
|
|
|
|
|
|
|
|
expr mk_overload_marker() {
|
|
|
|
return g_overload;
|
|
|
|
}
|
2013-08-25 01:02:38 +00:00
|
|
|
|
|
|
|
expr elaborator::lookup(context const & c, unsigned i) {
|
|
|
|
auto p = lookup_ext(c, i);
|
|
|
|
context_entry const & def = p.first;
|
|
|
|
context const & def_c = p.second;
|
|
|
|
lean_assert(length(c) > length(def_c));
|
|
|
|
return lift_free_vars(def.get_domain(), length(c) - length(def_c));
|
|
|
|
}
|
|
|
|
|
2013-08-25 17:34:19 +00:00
|
|
|
elaborator::elaborator(environment const & env):
|
2013-08-25 01:02:38 +00:00
|
|
|
m_env(env), m_metaenv(env) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void elaborator::unify(expr const & e1, expr const & e2, context const & ctx) {
|
|
|
|
if (has_metavar(e1) || has_metavar(e2)) {
|
|
|
|
m_metaenv.unify(e1, e2, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expr elaborator::check_pi(expr const & e, context const & ctx) {
|
|
|
|
if (!e) {
|
|
|
|
// e is the type of a metavariable.
|
|
|
|
// approx: assume it is Type()
|
|
|
|
return Type();
|
|
|
|
} else if (is_pi(e)) {
|
|
|
|
return e;
|
|
|
|
} else {
|
|
|
|
expr r = head_reduce(e, m_env);
|
|
|
|
if (!is_eqp(r, e)) {
|
|
|
|
return check_pi(r, ctx);
|
|
|
|
} else if (is_var(e)) {
|
|
|
|
auto p = lookup_ext(ctx, var_idx(e));
|
|
|
|
context_entry const & entry = p.first;
|
|
|
|
context const & entry_ctx = p.second;
|
|
|
|
if (entry.get_body()) {
|
|
|
|
return lift_free_vars(check_pi(entry.get_body(), entry_ctx),
|
|
|
|
length(ctx) - length(entry_ctx));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw exception("function expected");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
level elaborator::check_universe(expr const & e, context const & ctx) {
|
|
|
|
if (!e) {
|
|
|
|
// e is the type of a metavariable
|
|
|
|
// approx: assume it is level 0
|
|
|
|
return level();
|
|
|
|
} else if (is_type(e)) {
|
|
|
|
return ty_level(e);
|
|
|
|
} else {
|
|
|
|
expr r = head_reduce(e, m_env);
|
|
|
|
if (!is_eqp(r, e)) {
|
|
|
|
return check_universe(r, ctx);
|
|
|
|
} else if (is_var(e)) {
|
|
|
|
auto p = lookup_ext(ctx, var_idx(e));
|
|
|
|
context_entry const & entry = p.first;
|
|
|
|
context const & entry_ctx = p.second;
|
|
|
|
if (entry.get_body()) {
|
|
|
|
return check_universe(entry.get_body(), entry_ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw exception("type expected");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Given e and a context, try to instantiate the
|
|
|
|
meta-variables in \c e. Return an inferred type for \c e.
|
|
|
|
*/
|
|
|
|
expr elaborator::process(expr const & e, context const & ctx) {
|
|
|
|
switch (e.kind()) {
|
|
|
|
case expr_kind::Constant:
|
|
|
|
if (is_metavar(e)) {
|
2013-08-25 22:21:01 +00:00
|
|
|
expr r = m_metaenv.root_at(e, ctx);
|
|
|
|
if (is_metavar(r)) {
|
|
|
|
return expr();
|
|
|
|
} else {
|
|
|
|
return process(r, ctx);
|
|
|
|
}
|
2013-08-25 01:02:38 +00:00
|
|
|
} else {
|
|
|
|
return m_env.get_object(const_name(e)).get_type();
|
|
|
|
}
|
|
|
|
case expr_kind::Var:
|
|
|
|
return lookup(ctx, var_idx(e));
|
|
|
|
case expr_kind::Type:
|
|
|
|
return mk_type(ty_level(e) + 1);
|
|
|
|
case expr_kind::Value:
|
|
|
|
return to_value(e).get_type();
|
|
|
|
case expr_kind::App: {
|
|
|
|
buffer<expr> types;
|
|
|
|
unsigned num = num_args(e);
|
|
|
|
for (unsigned i = 0; i < num; i++) {
|
|
|
|
types.push_back(process(arg(e,i), ctx));
|
|
|
|
}
|
|
|
|
// TODO: handle overload in args[0]
|
|
|
|
expr f_t = types[0];
|
|
|
|
if (!f_t) {
|
|
|
|
throw exception("invalid use of placeholder, the function must be provided to an application");
|
|
|
|
}
|
|
|
|
for (unsigned i = 1; i < num; i++) {
|
|
|
|
f_t = check_pi(f_t, ctx);
|
|
|
|
if (types[i])
|
|
|
|
unify(abst_domain(f_t), types[i], ctx);
|
|
|
|
f_t = instantiate(abst_body(f_t), arg(e, i));
|
|
|
|
}
|
|
|
|
return f_t;
|
|
|
|
}
|
|
|
|
case expr_kind::Eq: {
|
|
|
|
process(eq_lhs(e), ctx);
|
|
|
|
process(eq_rhs(e), ctx);
|
|
|
|
return mk_bool_type();
|
|
|
|
}
|
|
|
|
case expr_kind::Pi: {
|
|
|
|
expr dt = process(abst_domain(e), ctx);
|
|
|
|
expr bt = process(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
|
|
|
|
return mk_type(max(check_universe(dt, ctx), check_universe(bt, ctx)));
|
|
|
|
}
|
|
|
|
case expr_kind::Lambda: {
|
|
|
|
expr dt = process(abst_domain(e), ctx);
|
|
|
|
expr bt = process(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
|
|
|
|
return mk_pi(abst_name(e), abst_domain(e), bt);
|
|
|
|
}
|
|
|
|
case expr_kind::Let: {
|
|
|
|
expr lt = process(let_value(e), ctx);
|
|
|
|
return process(let_body(e), extend(ctx, let_name(e), lt, let_value(e)));
|
|
|
|
}}
|
|
|
|
lean_unreachable();
|
|
|
|
return expr();
|
|
|
|
}
|
|
|
|
|
|
|
|
expr elaborator::operator()(expr const & e) {
|
2013-08-25 22:21:01 +00:00
|
|
|
while (true) {
|
|
|
|
process(e, context());
|
|
|
|
if (!m_metaenv.modified())
|
|
|
|
break;
|
|
|
|
m_metaenv.reset_modified();
|
|
|
|
}
|
2013-08-25 01:02:38 +00:00
|
|
|
return m_metaenv.instantiate_metavars(e);
|
|
|
|
}
|
|
|
|
}
|