feat(frontends/lean/elaborator): eliminator elaboration procedure first steps

This commit is contained in:
Leonardo de Moura 2016-07-25 21:01:42 -07:00
parent b53e50c968
commit 3be217395c
2 changed files with 104 additions and 11 deletions

View file

@ -20,6 +20,7 @@ Author: Leonardo de Moura
#include "library/choice.h"
#include "library/typed_expr.h"
#include "library/compiler/rec_fn_macro.h"
#include "library/tactic/kabstract.h"
#include "frontends/lean/prenum.h"
#include "frontends/lean/elaborator_exception.h"
#include "frontends/lean/elaborator.h"
@ -33,6 +34,7 @@ static type_context_cache & get_type_context_cache_for(environment const & env,
#define trace_elab(CODE) lean_trace("elaborator", scope_trace_env _scope(m_env, m_ctx); CODE)
#define trace_elab_detail(CODE) lean_trace("elaborator_detail", scope_trace_env _scope(m_env, m_ctx); CODE)
#define trace_elab_debug(CODE) lean_trace("elaborator_debug", scope_trace_env _scope(m_env, m_ctx); CODE)
elaborator::elaborator(environment const & env, options const & opts, local_level_decls const & lls,
metavar_context const & mctx, local_context const & lctx):
@ -258,6 +260,10 @@ auto elaborator::use_elim_elab_core(name const & fn) -> optional<elim_info> {
}
std::reverse(idxs.begin(), idxs.end());
trace_elab_detail(tout() << "'eliminator' elaboration is going to be used for '" << fn << "' applications, "
<< "the motive is computed using the argument(s):";
for (unsigned idx : idxs) tout() << " #" << (idx+1);
tout() << "\n";);
return optional<elim_info>(params.size(), nexplicit, midx, to_list(idxs));
}
@ -429,6 +435,19 @@ void elaborator::validate_overloads(buffer<expr> const & fns, expr const & ref)
}
}
void elaborator::throw_app_type_mismatch(expr const & t, expr const & arg, expr const & arg_type, expr const & expected_type,
expr const & ref) {
format msg = format("type mismatch at application");
msg += pp_indent(t);
msg += line() + format("term");
msg += pp_indent(arg);
msg += line() + format("has type");
msg += pp_indent(arg_type);
msg += line() + format("but is expected to have type");
msg += pp_indent(expected_type);
throw_elaborator_exception(ref, msg);
}
expr elaborator::visit_poly_app(expr const & fn, buffer<expr> const & args, optional<expr> const & expected_type,
expr const & ref) {
// TODO(Leo)
@ -436,15 +455,94 @@ expr elaborator::visit_poly_app(expr const & fn, buffer<expr> const & args, opti
}
expr elaborator::visit_elim_app(expr const & fn, elim_info const & info, buffer<expr> const & args,
optional<expr> const & expected_type, expr const & ref) {
if (!expected_type) {
optional<expr> const & _expected_type, expr const & ref) {
lean_assert(info.m_nexplicit <= args.size());
if (!_expected_type) {
throw_elaborator_exception(sstream() << "invalid '" << const_name(fn) << "' application, "
<< "elaborator has special support for this kind of application "
<< "(it is handled as an \"eliminator\"), "
<< "but the expected type must be known", ref);
}
expr expected_type = instantiate_mvars(*_expected_type);
if (has_expr_metavar(expected_type)) {
throw_elaborator_exception(ref, format("invalid '") + format(const_name(fn)) + format ("' application, ") +
format("elaborator has special support for this kind of application ") +
format("(it is handled as an \"eliminator\"), ") +
format("but expected type must not contain metavariables") +
pp_indent(expected_type));
}
trace_elab_debug(
tout() << "eliminator elaboration for '" << fn << "'\n"
<< " arity: " << info.m_arity << "\n"
<< " nexplicit: " << info.m_nexplicit << "\n"
<< " motive: #" << (info.m_motive_idx+1) << "\n"
<< " major: ";
for (unsigned idx : info.m_explicit_idxs)
tout() << " #" << (idx+1);
tout() << "\n";);
expr fn_type = try_to_pi(infer_type(fn));
buffer<expr> new_args;
// In the first pass we only process the arguments at info.m_explicit_idxs
expr type = fn_type;
unsigned i = 0;
unsigned j = 0;
list<unsigned> const & main_idxs = info.m_explicit_idxs;
while (is_pi(type)) {
expr const & d = binding_domain(type);
binder_info const & bi = binding_info(type);
expr new_arg;
if (std::find(main_idxs.begin(), main_idxs.end(), i) != main_idxs.end()) {
new_arg = visit(args[j], some_expr(d));
j++;
if (has_expr_metavar(new_arg)) {
throw_elaborator_exception(ref, format("invalid '") + format(const_name(fn)) + format ("' application, ") +
format("elaborator has special support for this kind of application ") +
format("(it is handled as an \"eliminator\"), ") +
format("but term") + pp_indent(new_arg) +
line() + format("must not contain metavariables because") +
format("it is used to compute the motive"));
}
expr new_arg_type = infer_type(new_arg);
if (!is_def_eq(new_arg_type, d)) {
throw_app_type_mismatch(mk_app(fn, i+1, new_args.data()), new_arg, new_arg_type, d, ref);
}
} else if (is_explicit(bi)) {
new_arg = mk_metavar(d);
j++;
} else if (bi.is_inst_implicit()) {
new_arg = mk_instance(d);
} else {
new_arg = mk_metavar(d);
}
new_args.push_back(new_arg);
type = try_to_pi(instantiate(binding_body(type), new_arg));
i++;
}
// Compute motive */
trace_elab_debug(tout() << "compute motive by using keyed-abstraction:\n " <<
instantiate_mvars(type) << "\nwith\n " <<
expected_type << "\n";);
buffer<expr> keys;
get_app_args(type, keys);
expr motive = expected_type;
i = keys.size();
while (i > 0) {
--i;
expr k = instantiate_mvars(keys[i]);
expr k_type = infer_type(k);
motive = mk_lambda("_x", k_type, kabstract(m_ctx, motive, k));
}
trace_elab_debug(tout() << "motive:\n " << instantiate_mvars(motive) << "\n";);
expr motive_arg = new_args[info.m_motive_idx];
if (!is_def_eq(motive_arg, motive)) {
throw_elaborator_exception(ref, format("\"eliminator\" elaborator failed to compute the motive"));
}
// TODO(Leo)
lean_unreachable();
@ -537,15 +635,7 @@ expr elaborator::visit_default_app(expr const & fn, arg_mask amask, buffer<expr>
if (optional<expr> new_new_arg = ensure_has_type(new_arg, new_arg_type, *expected_type)) {
new_arg = *new_new_arg;
} else {
throw_elaborator_exception(ref,
format("type mismatch at application") +
pp_indent(mk_app(fn, i+1, new_args.data())) +
line() + format("term") +
pp_indent(new_arg) +
line() + format("has type") +
pp_indent(new_arg_type) +
line() + format("but is expected to have type") +
pp_indent(*expected_type));
throw_app_type_mismatch(mk_app(fn, i+1, new_args.data()), new_arg, new_arg_type, *expected_type, ref);
}
}
}
@ -747,6 +837,7 @@ std::tuple<expr, level_param_names> elaborate(environment const & env, options c
void initialize_elaborator() {
register_trace_class("elaborator");
register_trace_class("elaborator_detail");
register_trace_class("elaborator_debug");
}
void finalize_elaborator() {

View file

@ -110,6 +110,8 @@ class elaborator {
expr ensure_function(expr const & e);
expr visit_function(expr const & fn, bool has_args, expr const & ref);
void throw_overload_exception(buffer<expr> const & fns, sstream & ss, expr const & ref);
void throw_app_type_mismatch(expr const & t, expr const & arg, expr const & arg_type, expr const & expected_type,
expr const & ref);
void validate_overloads(buffer<expr> const & fns, expr const & ref);
expr visit_poly_app(expr const & fn, buffer<expr> const & args,
optional<expr> const & expected_type, expr const & ref);