feat(frontends/lean/elaborator): include overload information in error messages
This commit is contained in:
parent
76c3757db7
commit
d5da659be7
5 changed files with 125 additions and 21 deletions
|
@ -337,7 +337,27 @@ expr elaborator::visit_choice(expr const & e, optional<expr> const & t, constrai
|
||||||
name_generator const & /* ngen */) {
|
name_generator const & /* ngen */) {
|
||||||
return choose(std::make_shared<choice_expr_elaborator>(*this, ctx, full_ctx, meta, type, e));
|
return choose(std::make_shared<choice_expr_elaborator>(*this, ctx, full_ctx, meta, type, e));
|
||||||
};
|
};
|
||||||
justification j = mk_justification("none of the overloads is applicable", some_expr(e));
|
auto pp_fn = [=](formatter const & fmt, pos_info_provider const * pos_prov, substitution const &, bool is_main) {
|
||||||
|
format r = pp_previous_error_header(fmt, pos_prov, some_expr(e), is_main);
|
||||||
|
r += format("none of the overloads is applicable:");
|
||||||
|
for (unsigned i = 0; i < get_num_choices(e); i++) {
|
||||||
|
expr const & c = get_choice(e, i);
|
||||||
|
expr const & f = get_app_fn(c);
|
||||||
|
optional<name> fn;
|
||||||
|
if (is_constant(f))
|
||||||
|
fn = const_name(f);
|
||||||
|
else if (is_local(f))
|
||||||
|
fn = local_pp_name(f);
|
||||||
|
r += space();
|
||||||
|
if (fn) {
|
||||||
|
r += format(*fn);
|
||||||
|
} else {
|
||||||
|
r += format("[nontrivial]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
justification j = mk_justification(some_expr(e), pp_fn);
|
||||||
cs += mk_choice_cnstr(m, fn, to_delay_factor(cnstr_group::Basic), true, j);
|
cs += mk_choice_cnstr(m, fn, to_delay_factor(cnstr_group::Basic), true, j);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
@ -1158,7 +1178,9 @@ expr elaborator::visit_equations(expr const & eqns, constraint_seq & cs) {
|
||||||
new_cs.linearize(tmp_cs);
|
new_cs.linearize(tmp_cs);
|
||||||
for (constraint const & c : tmp_cs) {
|
for (constraint const & c : tmp_cs) {
|
||||||
justification j = c.get_justification();
|
justification j = c.get_justification();
|
||||||
auto pp_fn = [=](formatter const & fmt, pos_info_provider const * pp, substitution const & s) {
|
auto pp_fn = [=](formatter const & fmt, pos_info_provider const * pp, substitution const & s, bool is_main) {
|
||||||
|
if (!is_main)
|
||||||
|
return format();
|
||||||
format r = j.pp(fmt, pp, s);
|
format r = j.pp(fmt, pp, s);
|
||||||
r += compose(line(), format("The following identifier(s) are introduced as free variables by the "
|
r += compose(line(), format("The following identifier(s) are introduced as free variables by the "
|
||||||
"left-hand-side of the equation:"));
|
"left-hand-side of the equation:"));
|
||||||
|
|
|
@ -6,6 +6,7 @@ Author: Leonardo de Moura
|
||||||
*/
|
*/
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
#include "util/buffer.h"
|
#include "util/buffer.h"
|
||||||
#include "util/int64.h"
|
#include "util/int64.h"
|
||||||
#include "util/memory_pool.h"
|
#include "util/memory_pool.h"
|
||||||
|
@ -26,6 +27,18 @@ format to_pos(optional<expr> const & e, pos_info_provider const * p) {
|
||||||
return f + space();
|
return f + space();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format pp_previous_error_header(formatter const &, pos_info_provider const * pos_prov, optional<expr> const & ref, bool is_main) {
|
||||||
|
if (!is_main) {
|
||||||
|
format r = line();
|
||||||
|
r += to_pos(ref, pos_prov);
|
||||||
|
r += format("previous error additional information");
|
||||||
|
r += line();
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
return format();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef uint64 approx_set;
|
typedef uint64 approx_set;
|
||||||
static approx_set mk_empty_set() { return 0; }
|
static approx_set mk_empty_set() { return 0; }
|
||||||
static approx_set mk_union(approx_set s1, approx_set s2) { return s1 | s2; }
|
static approx_set mk_union(approx_set s1, approx_set s2) { return s1 | s2; }
|
||||||
|
@ -263,25 +276,52 @@ optional<expr> justification::get_main_expr() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
format justification::pp(formatter const & fmt, pos_info_provider const * p, substitution const & s) const {
|
|
||||||
|
struct jst_hash_fn {
|
||||||
|
unsigned operator()(justification const & j) const { return j.raw()->m_hash_alloc; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jst_ptr_eq {
|
||||||
|
bool operator()(justification const & j1, justification const & j2) const { return j1.raw() == j2.raw(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class justification_set {
|
||||||
|
std::unordered_set<justification, jst_hash_fn, jst_ptr_eq> m_set;
|
||||||
|
public:
|
||||||
|
bool contains(justification const & j) const { return m_set.find(j) != m_set.end(); }
|
||||||
|
void insert(justification const & j) { m_set.insert(j); }
|
||||||
|
};
|
||||||
|
|
||||||
|
format justification::pp_core(formatter const & fmt, pos_info_provider const * p, substitution const & s,
|
||||||
|
justification_set & set, bool is_main) const {
|
||||||
|
if (set.contains(*this))
|
||||||
|
return format();
|
||||||
|
set.insert(*this);
|
||||||
justification_cell * it = m_ptr;
|
justification_cell * it = m_ptr;
|
||||||
while (true) {
|
if (!it)
|
||||||
if (!it)
|
return format();
|
||||||
return format();
|
switch (it->m_kind) {
|
||||||
switch (it->m_kind) {
|
case justification_kind::Asserted:
|
||||||
case justification_kind::Asserted:
|
return to_asserted(it)->m_fn(fmt, p, s, is_main);
|
||||||
return to_asserted(it)->m_fn(fmt, p, s);
|
case justification_kind::Wrapper:
|
||||||
case justification_kind::Wrapper:
|
return to_wrapper(it)->m_fn(fmt, p, s, is_main);
|
||||||
return to_wrapper(it)->m_fn(fmt, p, s);
|
case justification_kind::Assumption:
|
||||||
case justification_kind::Assumption:
|
if (is_main)
|
||||||
return format(format("Assumption "), format(to_assumption(it)->m_idx));
|
return format(format("Assumption "), format(to_assumption(it)->m_idx));
|
||||||
case justification_kind::Composite:
|
else
|
||||||
it = to_composite(it)->m_child[0].raw();
|
return format();
|
||||||
break;
|
case justification_kind::Composite:
|
||||||
}
|
return
|
||||||
|
to_composite(it)->m_child[0].pp_core(fmt, p, s, set, is_main) +
|
||||||
|
to_composite(it)->m_child[1].pp_core(fmt, p, s, set, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format justification::pp(formatter const & fmt, pos_info_provider const * p, substitution const & s) const {
|
||||||
|
justification_set set;
|
||||||
|
return pp_core(fmt, p, s, set, true);
|
||||||
|
}
|
||||||
|
|
||||||
justification mk_wrapper(justification const & j, optional<expr> const & s, pp_jst_fn const & fn) {
|
justification mk_wrapper(justification const & j, optional<expr> const & s, pp_jst_fn const & fn) {
|
||||||
return justification(new (get_wrapper_allocator().allocate()) wrapper_cell(j, fn, s));
|
return justification(new (get_wrapper_allocator().allocate()) wrapper_cell(j, fn, s));
|
||||||
}
|
}
|
||||||
|
@ -305,16 +345,22 @@ justification mk_justification(optional<expr> const & s, pp_jst_fn const & fn) {
|
||||||
return justification(new (get_asserted_allocator().allocate()) asserted_cell(fn, s));
|
return justification(new (get_asserted_allocator().allocate()) asserted_cell(fn, s));
|
||||||
}
|
}
|
||||||
justification mk_justification(optional<expr> const & s, pp_jst_sfn const & fn) {
|
justification mk_justification(optional<expr> const & s, pp_jst_sfn const & fn) {
|
||||||
return mk_justification(s, [=](formatter const & fmt, pos_info_provider const *, substitution const & subst) {
|
return mk_justification(s, [=](formatter const & fmt, pos_info_provider const *, substitution const & subst, bool is_main) {
|
||||||
// Remark: we are not using to_pos(s, p) anymore because we don't try to display complicated error messages anymore.
|
// Remark: we are not using to_pos(s, p) anymore because we don't try to display complicated error messages anymore.
|
||||||
// return compose(to_pos(s, p), fn(fmt, subst));
|
// return compose(to_pos(s, p), fn(fmt, subst));
|
||||||
return fn(fmt, subst);
|
if (is_main)
|
||||||
|
return fn(fmt, subst);
|
||||||
|
else
|
||||||
|
return format();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
justification mk_justification(char const * msg, optional<expr> const & s) {
|
justification mk_justification(char const * msg, optional<expr> const & s) {
|
||||||
std::string _msg(msg);
|
std::string _msg(msg);
|
||||||
return mk_justification(s, [=](formatter const &, pos_info_provider const *, substitution const &) {
|
return mk_justification(s, [=](formatter const &, pos_info_provider const *, substitution const &, bool is_main) {
|
||||||
return format(_msg);
|
if (is_main)
|
||||||
|
return format(_msg);
|
||||||
|
else
|
||||||
|
return format();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
std::ostream & operator<<(std::ostream & out, justification const & j) {
|
std::ostream & operator<<(std::ostream & out, justification const & j) {
|
||||||
|
|
|
@ -23,7 +23,9 @@ struct justification_cell;
|
||||||
The pp_jst_fn is a generic funciton that produces these messages. We can associate these functions
|
The pp_jst_fn is a generic funciton that produces these messages. We can associate these functions
|
||||||
to justification objects.
|
to justification objects.
|
||||||
*/
|
*/
|
||||||
typedef std::function<format(formatter const &, pos_info_provider const *, substitution const &)> pp_jst_fn;
|
typedef std::function<format(formatter const &, pos_info_provider const *, substitution const &, bool)> pp_jst_fn;
|
||||||
|
|
||||||
|
class justification_set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Objects used to justify unification (and level) constraints and metavariable assignments.
|
\brief Objects used to justify unification (and level) constraints and metavariable assignments.
|
||||||
|
@ -40,6 +42,8 @@ typedef std::function<format(formatter const &, pos_info_provider const *, subst
|
||||||
class justification {
|
class justification {
|
||||||
justification_cell * m_ptr;
|
justification_cell * m_ptr;
|
||||||
justification(justification_cell * ptr);
|
justification(justification_cell * ptr);
|
||||||
|
format pp_core(formatter const & fmt, pos_info_provider const * p, substitution const & s,
|
||||||
|
justification_set & visited, bool is_main) const;
|
||||||
public:
|
public:
|
||||||
justification();
|
justification();
|
||||||
justification(justification const & s);
|
justification(justification const & s);
|
||||||
|
@ -85,6 +89,7 @@ typedef std::function<format(formatter const &, substitution const &)> pp_jst_sf
|
||||||
|
|
||||||
/** \brief Return a format object containing position information for the given expression (if available) */
|
/** \brief Return a format object containing position information for the given expression (if available) */
|
||||||
format to_pos(optional<expr> const & e, pos_info_provider const * p);
|
format to_pos(optional<expr> const & e, pos_info_provider const * p);
|
||||||
|
format pp_previous_error_header(formatter const &, pos_info_provider const * pos_prov, optional<expr> const & ref, bool is_main);
|
||||||
|
|
||||||
/** \brief Provide a custom pretty printer for \c j */
|
/** \brief Provide a custom pretty printer for \c j */
|
||||||
justification mk_wrapper(justification const & j, optional<expr> const & s, pp_jst_fn const & fn);
|
justification mk_wrapper(justification const & j, optional<expr> const & s, pp_jst_fn const & fn);
|
||||||
|
|
19
tests/lean/subset_error.lean
Normal file
19
tests/lean/subset_error.lean
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
constant set : Type₁ → Type₁
|
||||||
|
constant finset : Type₁ → Type₁
|
||||||
|
constant set.mem : Π {A : Type₁}, A → set A → Prop
|
||||||
|
constant finset.mem : Π {A : Type₁}, A → finset A → Prop
|
||||||
|
|
||||||
|
infix ∈ := set.mem
|
||||||
|
infix ∈ := finset.mem
|
||||||
|
|
||||||
|
definition set.subset {A : Type₁} (s₁ s₂ : set A) : Prop :=
|
||||||
|
∀ ⦃a : A⦄, a ∈ s₁ → a ∈ s₂
|
||||||
|
|
||||||
|
definition finset.subset {A : Type₁} (s₁ s₂ : finset A) : Prop :=
|
||||||
|
∀ ⦃a : A⦄, a ∈ s₁ → a ∈ s₂
|
||||||
|
|
||||||
|
infix `⊆`:50 := set.subset
|
||||||
|
infix `⊆`:50 := finset.subset
|
||||||
|
|
||||||
|
example (A : Type₁) (x : A) (S H : set A) (Pin : x ∈ S) (Psub : S ⊆ H) : x ∈ H :=
|
||||||
|
Psub Pin -- Error, we cannot infer at preprocessing time the binder information for Psub
|
12
tests/lean/subset_error.lean.expected.out
Normal file
12
tests/lean/subset_error.lean.expected.out
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
subset_error.lean:18:51: error: type mismatch at application
|
||||||
|
x ∈ S
|
||||||
|
term
|
||||||
|
S
|
||||||
|
has type
|
||||||
|
set A
|
||||||
|
but is expected to have type
|
||||||
|
finset A
|
||||||
|
subset_error.lean:18:51: previous error additional information
|
||||||
|
none of the overloads is applicable: finset.mem set.mem
|
||||||
|
subset_error.lean:18:66: previous error additional information
|
||||||
|
none of the overloads is applicable: finset.subset set.subset
|
Loading…
Reference in a new issue