Handle (and pretty print) elaborator error messages in the lean default frontend
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
03a5b5dbd0
commit
71b8b6408e
8 changed files with 214 additions and 53 deletions
|
@ -18,6 +18,7 @@ Author: Leonardo de Moura
|
||||||
#include "expr_maps.h"
|
#include "expr_maps.h"
|
||||||
#include "sstream.h"
|
#include "sstream.h"
|
||||||
#include "kernel_exception.h"
|
#include "kernel_exception.h"
|
||||||
|
#include "elaborator_exception.h"
|
||||||
#include "metavar.h"
|
#include "metavar.h"
|
||||||
#include "elaborator.h"
|
#include "elaborator.h"
|
||||||
#include "lean_frontend.h"
|
#include "lean_frontend.h"
|
||||||
|
@ -552,7 +553,8 @@ class parser::imp {
|
||||||
if (m_frontend.has_implicit_arguments(obj.get_name())) {
|
if (m_frontend.has_implicit_arguments(obj.get_name())) {
|
||||||
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj.get_name());
|
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj.get_name());
|
||||||
buffer<expr> args;
|
buffer<expr> args;
|
||||||
args.push_back(save(mk_constant(obj.get_name()), pos()));
|
pos_info p = pos();
|
||||||
|
args.push_back(save(mk_constant(obj.get_name()), p));
|
||||||
// We parse all the arguments to make sure we
|
// We parse all the arguments to make sure we
|
||||||
// get all explicit arguments.
|
// get all explicit arguments.
|
||||||
for (unsigned i = 0; i < imp_args.size(); i++) {
|
for (unsigned i = 0; i < imp_args.size(); i++) {
|
||||||
|
@ -906,6 +908,15 @@ class parser::imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create a new application and associate position of left with the resultant expression.
|
||||||
|
*/
|
||||||
|
expr mk_app_left(expr const & left, expr const & arg) {
|
||||||
|
auto it = m_expr_pos_info.find(left);
|
||||||
|
lean_assert(it != m_expr_pos_info.end());
|
||||||
|
return save(mk_app(left, arg), it->second);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Auxiliary method used when processing the 'inside' of an expression.
|
\brief Auxiliary method used when processing the 'inside' of an expression.
|
||||||
*/
|
*/
|
||||||
|
@ -914,12 +925,12 @@ class parser::imp {
|
||||||
case scanner::token::Id: return parse_led_id(left);
|
case scanner::token::Id: return parse_led_id(left);
|
||||||
case scanner::token::Eq: return parse_eq(left);
|
case scanner::token::Eq: return parse_eq(left);
|
||||||
case scanner::token::Arrow: return parse_arrow(left);
|
case scanner::token::Arrow: return parse_arrow(left);
|
||||||
case scanner::token::LeftParen: return mk_app(left, parse_lparen());
|
case scanner::token::LeftParen: return mk_app_left(left, parse_lparen());
|
||||||
case scanner::token::IntVal: return mk_app(left, parse_int());
|
case scanner::token::IntVal: return mk_app_left(left, parse_int());
|
||||||
case scanner::token::DecimalVal: return mk_app(left, parse_decimal());
|
case scanner::token::DecimalVal: return mk_app_left(left, parse_decimal());
|
||||||
case scanner::token::StringVal: return mk_app(left, parse_string());
|
case scanner::token::StringVal: return mk_app_left(left, parse_string());
|
||||||
case scanner::token::Placeholder: return mk_app(left, parse_placeholder());
|
case scanner::token::Placeholder: return mk_app_left(left, parse_placeholder());
|
||||||
case scanner::token::Type: return mk_app(left, parse_type());
|
case scanner::token::Type: return mk_app_left(left, parse_type());
|
||||||
default: return left;
|
default: return left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -961,13 +972,7 @@ class parser::imp {
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
expr elaborate(expr const & e) {
|
expr elaborate(expr const & e) {
|
||||||
if (has_metavar(e)) {
|
return m_elaborator(e);
|
||||||
expr r = m_elaborator(e);
|
|
||||||
m_elaborator.clear();
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1410,7 +1415,12 @@ class parser::imp {
|
||||||
display_error(msg, m_scanner.get_line(), m_scanner.get_pos());
|
display_error(msg, m_scanner.get_line(), m_scanner.get_pos());
|
||||||
}
|
}
|
||||||
void display_error(kernel_exception const & ex) {
|
void display_error(kernel_exception const & ex) {
|
||||||
display_error_pos(ex.get_main_expr());
|
display_error_pos(m_elaborator.get_original(ex.get_main_expr()));
|
||||||
|
regular(m_frontend) << " " << ex << endl;
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
void display_error(elaborator_exception const & ex) {
|
||||||
|
display_error_pos(m_elaborator.get_original(ex.get_expr()));
|
||||||
regular(m_frontend) << " " << ex << endl;
|
regular(m_frontend) << " " << ex << endl;
|
||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
@ -1477,6 +1487,12 @@ public:
|
||||||
display_error(ex);
|
display_error(ex);
|
||||||
if (m_use_exceptions)
|
if (m_use_exceptions)
|
||||||
throw;
|
throw;
|
||||||
|
} catch (elaborator_exception & ex) {
|
||||||
|
m_found_errors = true;
|
||||||
|
if (m_show_errors)
|
||||||
|
display_error(ex);
|
||||||
|
if (m_use_exceptions)
|
||||||
|
throw;
|
||||||
} catch (interrupted & ex) {
|
} catch (interrupted & ex) {
|
||||||
if (m_verbose)
|
if (m_verbose)
|
||||||
regular(m_frontend) << "\n!!!Interrupted!!!" << endl;
|
regular(m_frontend) << "\n!!!Interrupted!!!" << endl;
|
||||||
|
|
|
@ -66,6 +66,10 @@ static format g_let_fmt = highlight_keyword(format("let"));
|
||||||
static format g_in_fmt = highlight_keyword(format("in"));
|
static format g_in_fmt = highlight_keyword(format("in"));
|
||||||
static format g_assign_fmt = highlight_keyword(format(":="));
|
static format g_assign_fmt = highlight_keyword(format(":="));
|
||||||
static format g_geq_fmt = format("\u2265");
|
static format g_geq_fmt = format("\u2265");
|
||||||
|
static format g_lift_fmt = highlight_keyword(format("lift"));
|
||||||
|
static format g_lower_fmt = highlight_keyword(format("lower"));
|
||||||
|
static format g_subst_fmt = highlight_keyword(format("subst"));
|
||||||
|
|
||||||
|
|
||||||
static name g_pp_max_depth {"lean", "pp", "max_depth"};
|
static name g_pp_max_depth {"lean", "pp", "max_depth"};
|
||||||
static name g_pp_max_steps {"lean", "pp", "max_steps"};
|
static name g_pp_max_steps {"lean", "pp", "max_steps"};
|
||||||
|
@ -98,18 +102,17 @@ static name g_nu("\u03BD");
|
||||||
/**
|
/**
|
||||||
\brief Return a fresh name for the given abstraction or let.
|
\brief Return a fresh name for the given abstraction or let.
|
||||||
By fresh, we mean a name that is not used for any constant in
|
By fresh, we mean a name that is not used for any constant in
|
||||||
abst_body(e). If fe != nullptr, then the resultant name also does
|
abst_body(e).
|
||||||
not clash with the name of any object defined in fe.
|
|
||||||
|
|
||||||
The resultant name is based on abst_name(e).
|
The resultant name is based on abst_name(e).
|
||||||
*/
|
*/
|
||||||
name get_unused_name(expr const & e, frontend const * fe = nullptr) {
|
name get_unused_name(expr const & e) {
|
||||||
lean_assert(is_abstraction(e) || is_let(e));
|
lean_assert(is_abstraction(e) || is_let(e));
|
||||||
name const & n = is_abstraction(e) ? abst_name(e) : let_name(e);
|
name const & n = is_abstraction(e) ? abst_name(e) : let_name(e);
|
||||||
name n1 = n;
|
name n1 = n;
|
||||||
unsigned i = 1;
|
unsigned i = 1;
|
||||||
expr const & b = is_abstraction(e) ? abst_body(e) : let_body(e);
|
expr const & b = is_abstraction(e) ? abst_body(e) : let_body(e);
|
||||||
while (occurs(n1, b) || (fe != nullptr && fe->find_object(n1))) {
|
while (occurs(n1, b)) {
|
||||||
n1 = name(n, i);
|
n1 = name(n, i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +193,7 @@ class pp_fn {
|
||||||
result pp_constant(expr const & e) {
|
result pp_constant(expr const & e) {
|
||||||
name const & n = const_name(e);
|
name const & n = const_name(e);
|
||||||
if (is_metavar(e)) {
|
if (is_metavar(e)) {
|
||||||
return mk_result(format("_"), 1);
|
return mk_result(format{format("?M"), format(metavar_idx(e))}, 1);
|
||||||
} else if (has_implicit_arguments(n)) {
|
} else if (has_implicit_arguments(n)) {
|
||||||
return mk_result(format(m_frontend.get_explicit_version(n)), 1);
|
return mk_result(format(m_frontend.get_explicit_version(n)), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -852,6 +855,32 @@ class pp_fn {
|
||||||
return mk_result(r_format, p_arg1.second + p_arg2.second + 1);
|
return mk_result(r_format, p_arg1.second + p_arg2.second + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result pp_lower(expr const & e, unsigned depth) {
|
||||||
|
expr arg; unsigned s, n;
|
||||||
|
is_lower(e, arg, s, n);
|
||||||
|
result p_arg = pp_child(arg, depth);
|
||||||
|
format r_format = format{g_lower_fmt, colon(), format(s), colon(), format(s), nest(m_indent, compose(line(), p_arg.first))};
|
||||||
|
return mk_result(r_format, p_arg.second + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result pp_lift(expr const & e, unsigned depth) {
|
||||||
|
expr arg; unsigned s, n;
|
||||||
|
is_lift(e, arg, s, n);
|
||||||
|
result p_arg = pp_child(arg, depth);
|
||||||
|
format r_format = format{g_lift_fmt, colon(), format(s), colon(), format(s), nest(m_indent, compose(line(), p_arg.first))};
|
||||||
|
return mk_result(r_format, p_arg.second + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result pp_subst(expr const & e, unsigned depth) {
|
||||||
|
expr arg, v; unsigned i;
|
||||||
|
is_subst(e, arg, i, v);
|
||||||
|
result p_arg = pp_child(arg, depth);
|
||||||
|
result p_v = pp_child(v, depth);
|
||||||
|
format r_format = format{g_subst_fmt, colon(), format(i),
|
||||||
|
nest(m_indent, format{line(), p_arg.first, line(), p_v.first})};
|
||||||
|
return mk_result(r_format, p_arg.second + p_v.second + 1);
|
||||||
|
}
|
||||||
|
|
||||||
result pp(expr const & e, unsigned depth, bool main = false) {
|
result pp(expr const & e, unsigned depth, bool main = false) {
|
||||||
check_interrupted(m_interrupted);
|
check_interrupted(m_interrupted);
|
||||||
if (!is_atomic(e) && (m_num_steps > m_max_steps || depth > m_max_depth)) {
|
if (!is_atomic(e) && (m_num_steps > m_max_steps || depth > m_max_depth)) {
|
||||||
|
@ -864,16 +893,24 @@ class pp_fn {
|
||||||
return mk_result(format(it->second), 1);
|
return mk_result(format(it->second), 1);
|
||||||
}
|
}
|
||||||
result r;
|
result r;
|
||||||
switch (e.kind()) {
|
if (is_lower(e)) {
|
||||||
case expr_kind::Var: r = pp_var(e); break;
|
r = pp_lower(e, depth);
|
||||||
case expr_kind::Constant: r = pp_constant(e); break;
|
} else if (is_lift(e)) {
|
||||||
case expr_kind::Value: r = pp_value(e); break;
|
r = pp_lift(e, depth);
|
||||||
case expr_kind::App: r = pp_app(e, depth); break;
|
} else if (is_subst(e)) {
|
||||||
case expr_kind::Lambda:
|
r = pp_subst(e, depth);
|
||||||
case expr_kind::Pi: r = pp_abstraction(e, depth); break;
|
} else {
|
||||||
case expr_kind::Type: r = pp_type(e); break;
|
switch (e.kind()) {
|
||||||
case expr_kind::Eq: r = pp_eq(e, depth); break;
|
case expr_kind::Var: r = pp_var(e); break;
|
||||||
case expr_kind::Let: r = pp_let(e, depth); break;
|
case expr_kind::Constant: r = pp_constant(e); break;
|
||||||
|
case expr_kind::Value: r = pp_value(e); break;
|
||||||
|
case expr_kind::App: r = pp_app(e, depth); break;
|
||||||
|
case expr_kind::Lambda:
|
||||||
|
case expr_kind::Pi: r = pp_abstraction(e, depth); break;
|
||||||
|
case expr_kind::Type: r = pp_type(e); break;
|
||||||
|
case expr_kind::Eq: r = pp_eq(e, depth); break;
|
||||||
|
case expr_kind::Let: r = pp_let(e, depth); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!main && m_extra_lets && is_shared(e) && r.second > m_alias_min_weight) {
|
if (!main && m_extra_lets && is_shared(e) && r.second > m_alias_min_weight) {
|
||||||
name new_aux = name(m_aux, m_aliases_defs.size()+1);
|
name new_aux = name(m_aux, m_aliases_defs.size()+1);
|
||||||
|
@ -965,6 +1002,10 @@ public:
|
||||||
void set_interrupt(bool flag) {
|
void set_interrupt(bool flag) {
|
||||||
m_interrupted = flag;
|
m_interrupted = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void register_local(name const & n) {
|
||||||
|
m_local_names.insert(n);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class pp_formatter_cell : public formatter_cell {
|
class pp_formatter_cell : public formatter_cell {
|
||||||
|
@ -979,17 +1020,20 @@ class pp_formatter_cell : public formatter_cell {
|
||||||
}
|
}
|
||||||
|
|
||||||
format pp(context const & c, expr const & e, bool include_e, options const & opts) {
|
format pp(context const & c, expr const & e, bool include_e, options const & opts) {
|
||||||
|
pp_fn fn(m_frontend, opts);
|
||||||
|
scoped_set_interruptable_ptr<pp_fn> set(m_pp_fn, &fn);
|
||||||
unsigned indent = get_pp_indent(opts);
|
unsigned indent = get_pp_indent(opts);
|
||||||
format r;
|
format r;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
expr c2 = context_to_lambda(c, e);
|
expr c2 = context_to_lambda(c, e);
|
||||||
while (is_fake_context(c2)) {
|
while (is_fake_context(c2)) {
|
||||||
check_interrupted(m_interrupted);
|
check_interrupted(m_interrupted);
|
||||||
name n1 = get_unused_name(c2, &m_frontend);
|
name n1 = get_unused_name(c2);
|
||||||
format entry = format{format(n1), space(), colon(), space(), pp(fake_context_domain(c2), opts)};
|
fn.register_local(n1);
|
||||||
|
format entry = format{format(n1), space(), colon(), space(), fn(fake_context_domain(c2))};
|
||||||
expr val = fake_context_value(c2);
|
expr val = fake_context_value(c2);
|
||||||
if (val)
|
if (val)
|
||||||
entry += format{space(), g_assign_fmt, nest(indent, format{line(), pp(val, opts)})};
|
entry += format{space(), g_assign_fmt, nest(indent, format{line(), fn(val)})};
|
||||||
if (first) {
|
if (first) {
|
||||||
r = group(entry);
|
r = group(entry);
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -1000,9 +1044,9 @@ class pp_formatter_cell : public formatter_cell {
|
||||||
}
|
}
|
||||||
if (include_e) {
|
if (include_e) {
|
||||||
if (first)
|
if (first)
|
||||||
r += format{line(), pp(c2, opts)};
|
r += format{line(), fn(c2)};
|
||||||
else
|
else
|
||||||
r = pp(c2, opts);
|
r = fn(c2);
|
||||||
} else {
|
} else {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1090,14 +1134,17 @@ public:
|
||||||
if (format_ctx) {
|
if (format_ctx) {
|
||||||
return pp(c, e, true, opts);
|
return pp(c, e, true, opts);
|
||||||
} else {
|
} else {
|
||||||
|
pp_fn fn(m_frontend, opts);
|
||||||
|
scoped_set_interruptable_ptr<pp_fn> set(m_pp_fn, &fn);
|
||||||
expr c2 = context_to_lambda(c, e);
|
expr c2 = context_to_lambda(c, e);
|
||||||
while (is_fake_context(c2)) {
|
while (is_fake_context(c2)) {
|
||||||
check_interrupted(m_interrupted);
|
check_interrupted(m_interrupted);
|
||||||
name n1 = get_unused_name(c2, &m_frontend);
|
name n1 = get_unused_name(c2);
|
||||||
|
fn.register_local(n1);
|
||||||
expr const & rest = fake_context_rest(c2);
|
expr const & rest = fake_context_rest(c2);
|
||||||
c2 = instantiate_with_closed(rest, mk_constant(n1));
|
c2 = instantiate_with_closed(rest, mk_constant(n1));
|
||||||
}
|
}
|
||||||
return pp(c2, opts);
|
return fn(c2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ Author: Leonardo de Moura
|
||||||
namespace lean {
|
namespace lean {
|
||||||
static name g_overload_name(name(name(name(0u), "library"), "overload"));
|
static name g_overload_name(name(name(name(0u), "library"), "overload"));
|
||||||
static expr g_overload = mk_constant(g_overload_name);
|
static expr g_overload = mk_constant(g_overload_name);
|
||||||
|
static format g_assignment_fmt = format(":=");
|
||||||
|
static format g_unification_fmt = format("\u2248");
|
||||||
|
|
||||||
bool is_overload_marker(expr const & e) {
|
bool is_overload_marker(expr const & e) {
|
||||||
return e == g_overload;
|
return e == g_overload;
|
||||||
|
@ -65,12 +67,19 @@ class elaborator::imp {
|
||||||
environment const & m_env;
|
environment const & m_env;
|
||||||
name_set const * m_available_defs;
|
name_set const * m_available_defs;
|
||||||
elaborator const * m_owner;
|
elaborator const * m_owner;
|
||||||
|
expr m_root;
|
||||||
|
|
||||||
constraint_queue m_constraints;
|
constraint_queue m_constraints;
|
||||||
metavars m_metavars;
|
metavars m_metavars;
|
||||||
|
|
||||||
bool m_add_constraints;
|
bool m_add_constraints;
|
||||||
|
|
||||||
|
// The following mapping is used to store the relationship
|
||||||
|
// between elaborated expressions and non-elaborated expressions.
|
||||||
|
// We need that because a frontend may associate line number information
|
||||||
|
// with the original non-elaborated expressions.
|
||||||
|
expr_map<expr> m_trace;
|
||||||
|
|
||||||
volatile bool m_interrupted;
|
volatile bool m_interrupted;
|
||||||
|
|
||||||
expr metavar_type(expr const & m) {
|
expr metavar_type(expr const & m) {
|
||||||
|
@ -434,7 +443,14 @@ class elaborator::imp {
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
replace_fn<decltype(proc)> replacer(proc);
|
|
||||||
|
auto tracer = [&](expr const & old_e, expr const & new_e) {
|
||||||
|
if (!is_eqp(new_e, old_e)) {
|
||||||
|
m_trace[new_e] = old_e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
replace_fn<decltype(proc), decltype(tracer)> replacer(proc, tracer);
|
||||||
return replacer(e);
|
return replacer(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,14 +460,14 @@ class elaborator::imp {
|
||||||
solve_core();
|
solve_core();
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
bool progress = false;
|
bool progress = false;
|
||||||
unsigned unsolved_midx = 0;
|
// unsigned unsolved_midx = 0;
|
||||||
for (unsigned midx = 0; midx < num_meta; midx++) {
|
for (unsigned midx = 0; midx < num_meta; midx++) {
|
||||||
if (m_metavars[midx].m_assignment) {
|
if (m_metavars[midx].m_assignment) {
|
||||||
if (has_assigned_metavar(m_metavars[midx].m_assignment)) {
|
if (has_assigned_metavar(m_metavars[midx].m_assignment)) {
|
||||||
m_metavars[midx].m_assignment = instantiate(m_metavars[midx].m_assignment);
|
m_metavars[midx].m_assignment = instantiate(m_metavars[midx].m_assignment);
|
||||||
}
|
}
|
||||||
if (has_metavar(m_metavars[midx].m_assignment)) {
|
if (has_metavar(m_metavars[midx].m_assignment)) {
|
||||||
unsolved_midx = midx;
|
// unsolved_midx = midx;
|
||||||
cont = true; // must continue
|
cont = true; // must continue
|
||||||
} else {
|
} else {
|
||||||
if (m_metavars[midx].m_type && !m_metavars[midx].m_type_cnstr) {
|
if (m_metavars[midx].m_type && !m_metavars[midx].m_type_cnstr) {
|
||||||
|
@ -473,7 +489,7 @@ class elaborator::imp {
|
||||||
if (!cont)
|
if (!cont)
|
||||||
return;
|
return;
|
||||||
if (!progress)
|
if (!progress)
|
||||||
throw unsolved_placeholder_exception(*m_owner, m_metavars[unsolved_midx].m_ctx, m_metavars[unsolved_midx].m_mvar);
|
throw unsolved_placeholder_exception(*m_owner, context(), m_root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,8 +510,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
m_constraints.clear();
|
m_trace.clear();
|
||||||
m_metavars.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_interrupt(bool flag) {
|
void set_interrupt(bool flag) {
|
||||||
|
@ -524,23 +539,69 @@ public:
|
||||||
return m_env;
|
return m_env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct resetter {
|
||||||
|
imp & m_ref;
|
||||||
|
resetter(imp & r):m_ref(r) {}
|
||||||
|
~resetter() { m_ref.m_constraints.clear(); m_ref.m_metavars.clear(); }
|
||||||
|
};
|
||||||
|
|
||||||
expr operator()(expr const & e, elaborator const & elb) {
|
expr operator()(expr const & e, elaborator const & elb) {
|
||||||
// std::cout << "ELABORATIMG: " << e << "\n";
|
if (has_metavar(e)) {
|
||||||
m_owner = &elb;
|
resetter r(*this);
|
||||||
unsigned num_meta = m_metavars.size();
|
m_owner = &elb;
|
||||||
m_add_constraints = true;
|
m_root = e;
|
||||||
infer(e, context());
|
unsigned num_meta = m_metavars.size();
|
||||||
solve(num_meta);
|
m_add_constraints = true;
|
||||||
return instantiate(e);
|
infer(e, context());
|
||||||
|
solve(num_meta);
|
||||||
|
return instantiate(e);
|
||||||
|
} else {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr const & get_original(expr const & e) const {
|
||||||
|
expr const * r = &e;
|
||||||
|
while (true) {
|
||||||
|
auto it = m_trace.find(*r);
|
||||||
|
if (it == m_trace.end()) {
|
||||||
|
return *r;
|
||||||
|
} else {
|
||||||
|
r = &(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format pp(formatter & f, options const & o) const {
|
||||||
|
format r;
|
||||||
|
bool first = true;
|
||||||
|
for (unsigned i = 0; i < m_metavars.size(); i++) {
|
||||||
|
metavar_info const & info = m_metavars[i];
|
||||||
|
expr m = ::lean::mk_metavar(i);
|
||||||
|
if (first) first = false; else r += line();
|
||||||
|
format r_assignment;
|
||||||
|
if (info.m_assignment)
|
||||||
|
r_assignment = f(info.m_assignment, o);
|
||||||
|
else
|
||||||
|
r_assignment = highlight(format("[unassigned]"));
|
||||||
|
r += group(format{f(m,o), space(), g_assignment_fmt, line(), r_assignment});
|
||||||
|
}
|
||||||
|
for (auto c : m_constraints) {
|
||||||
|
if (first) first = false; else r += line();
|
||||||
|
r += group(format{f(c.m_lhs, o), space(), g_unification_fmt, line(), f(c.m_rhs, o)});
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
elaborator::elaborator(environment const & env):m_ptr(new imp(env, nullptr)) {}
|
elaborator::elaborator(environment const & env):m_ptr(new imp(env, nullptr)) {}
|
||||||
elaborator::~elaborator() {}
|
elaborator::~elaborator() {}
|
||||||
expr elaborator::mk_metavar() { return m_ptr->mk_metavar(); }
|
expr elaborator::mk_metavar() { return m_ptr->mk_metavar(); }
|
||||||
expr elaborator::operator()(expr const & e) { return (*m_ptr)(e, *this); }
|
expr elaborator::operator()(expr const & e) { return (*m_ptr)(e, *this); }
|
||||||
|
expr const & elaborator::get_original(expr const & e) const { return m_ptr->get_original(e); }
|
||||||
void elaborator::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }
|
void elaborator::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }
|
||||||
void elaborator::clear() { m_ptr->clear(); }
|
void elaborator::clear() { m_ptr->clear(); }
|
||||||
environment const & elaborator::get_environment() const { return m_ptr->get_environment(); }
|
environment const & elaborator::get_environment() const { return m_ptr->get_environment(); }
|
||||||
void elaborator::display(std::ostream & out) const { m_ptr->display(out); }
|
void elaborator::display(std::ostream & out) const { m_ptr->display(out); }
|
||||||
|
format elaborator::pp(formatter & f, options const & o) const { return m_ptr->pp(f,o); }
|
||||||
void elaborator::print(imp * ptr) { ptr->display(std::cout); }
|
void elaborator::print(imp * ptr) { ptr->display(std::cout); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "formatter.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +27,13 @@ public:
|
||||||
|
|
||||||
expr operator()(expr const & e);
|
expr operator()(expr const & e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief If \c e is an expression instantiated by the elaborator, then it
|
||||||
|
returns the expression (the one with "holes") used to generate \c e.
|
||||||
|
Otherwise, it just returns \c e.
|
||||||
|
*/
|
||||||
|
expr const & get_original(expr const & e) const;
|
||||||
|
|
||||||
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); }
|
||||||
|
@ -35,6 +43,7 @@ public:
|
||||||
environment const & get_environment() const;
|
environment const & get_environment() const;
|
||||||
|
|
||||||
void display(std::ostream & out) const;
|
void display(std::ostream & out) const;
|
||||||
|
format pp(formatter & f, options const & o) const;
|
||||||
};
|
};
|
||||||
/** \brief Return true iff \c e is a special constant used to mark application of overloads. */
|
/** \brief Return true iff \c e is a special constant used to mark application of overloads. */
|
||||||
bool is_overload_marker(expr const & e);
|
bool is_overload_marker(expr const & e);
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
class unsolved_placeholder_exception : public elaborator_exception {
|
class unsolved_placeholder_exception : public elaborator_exception {
|
||||||
public:
|
public:
|
||||||
unsolved_placeholder_exception(elaborator const & elb, context const & ctx, expr const & e):elaborator_exception(elb, ctx, e) {}
|
unsolved_placeholder_exception(elaborator const & elb, context const & ctx, expr const & e):elaborator_exception(elb, ctx, e) {}
|
||||||
virtual char const * what() const noexcept { return "unsolved placeholder, system could not fill this placeholder"; }
|
virtual char const * what() const noexcept { return "unsolved placeholder"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class unification_app_mismatch_exception : public elaborator_exception {
|
class unification_app_mismatch_exception : public elaborator_exception {
|
||||||
|
@ -45,12 +45,12 @@ class unification_app_mismatch_exception : public elaborator_exception {
|
||||||
public:
|
public:
|
||||||
unification_app_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s, unsigned pos):elaborator_exception(elb, ctx, s), m_arg_pos(pos) {}
|
unification_app_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s, unsigned pos):elaborator_exception(elb, ctx, s), m_arg_pos(pos) {}
|
||||||
unsigned get_arg_pos() const { return m_arg_pos; }
|
unsigned get_arg_pos() const { return m_arg_pos; }
|
||||||
virtual char const * what() const noexcept { return "failed to solve unification problem during elaboration"; }
|
virtual char const * what() const noexcept { return "application type mismatch during term elaboration"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class unification_type_mismatch_exception : public elaborator_exception {
|
class unification_type_mismatch_exception : public elaborator_exception {
|
||||||
public:
|
public:
|
||||||
unification_type_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s):elaborator_exception(elb, ctx, s) {}
|
unification_type_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s):elaborator_exception(elb, ctx, s) {}
|
||||||
virtual char const * what() const noexcept { return "failed to solve unification problem during elaboration"; }
|
virtual char const * what() const noexcept { return "type mismatch during term elaboration"; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ Author: Leonardo de Moura
|
||||||
#include "formatter.h"
|
#include "formatter.h"
|
||||||
#include "printer.h"
|
#include "printer.h"
|
||||||
#include "kernel_exception.h"
|
#include "kernel_exception.h"
|
||||||
|
#include "elaborator_exception.h"
|
||||||
|
#include "elaborator.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
class simple_formatter_cell : public formatter_cell {
|
class simple_formatter_cell : public formatter_cell {
|
||||||
public:
|
public:
|
||||||
|
@ -76,4 +79,14 @@ format formatter::operator()(kernel_exception const & ex, options const & opts)
|
||||||
return format(ex.what());
|
return format(ex.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format formatter::operator()(elaborator_exception const & ex, options const & opts) {
|
||||||
|
unsigned indent = get_pp_indent(opts);
|
||||||
|
format expr_f = operator()(ex.get_context(), ex.get_expr(), false, opts);
|
||||||
|
format elb_f = ex.get_elaborator().pp(*this, opts);
|
||||||
|
return format({format(ex.what()), space(), format("at term"),
|
||||||
|
nest(indent, compose(line(), expr_f)),
|
||||||
|
line(), format("Elaborator state"),
|
||||||
|
nest(indent, compose(line(), elb_f))});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
virtual void set_interrupt(bool flag) {}
|
virtual void set_interrupt(bool flag) {}
|
||||||
};
|
};
|
||||||
class kernel_exception;
|
class kernel_exception;
|
||||||
|
class elaborator_exception;
|
||||||
class formatter {
|
class formatter {
|
||||||
std::shared_ptr<formatter_cell> m_cell;
|
std::shared_ptr<formatter_cell> m_cell;
|
||||||
public:
|
public:
|
||||||
|
@ -50,6 +51,8 @@ public:
|
||||||
format operator()(environment const & env, options const & opts = options()) { return (*m_cell)(env, opts); }
|
format operator()(environment const & env, options const & opts = options()) { return (*m_cell)(env, opts); }
|
||||||
/** \brief Pretty print a kernel exception using the this formatter */
|
/** \brief Pretty print a kernel exception using the this formatter */
|
||||||
format operator()(kernel_exception const & ex, options const & opts = options());
|
format operator()(kernel_exception const & ex, options const & opts = options());
|
||||||
|
/** \brief Pretty print a elaborator exception using the this formatter */
|
||||||
|
format operator()(elaborator_exception const & ex, options const & opts = options());
|
||||||
void set_interrupt(bool flag) { m_cell->set_interrupt(flag); }
|
void set_interrupt(bool flag) { m_cell->set_interrupt(flag); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,18 @@ inline diagnostic const & operator<<(diagnostic const & out, kernel_exception co
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline regular const & operator<<(regular const & out, elaborator_exception const & ex) {
|
||||||
|
options const & opts = out.m_state.get_options();
|
||||||
|
out.m_state.get_regular_channel().get_stream() << mk_pair(out.m_state.get_formatter()(ex, opts), opts);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline diagnostic const & operator<<(diagnostic const & out, elaborator_exception const & ex) {
|
||||||
|
options const & opts = out.m_state.get_options();
|
||||||
|
out.m_state.get_diagnostic_channel().get_stream() << mk_pair(out.m_state.get_formatter()(ex, opts), opts);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline regular const & operator<<(regular const & out, T const & t) {
|
inline regular const & operator<<(regular const & out, T const & t) {
|
||||||
out.m_state.get_regular_channel().get_stream() << t;
|
out.m_state.get_regular_channel().get_stream() << t;
|
||||||
|
|
Loading…
Add table
Reference in a new issue