refactor(kernel): rename trace to justification

Motivations:

- We have been writing several comments of the form "... trace/justification..." and "this trace object justify ...".
- Avoid confusion with util/trace.h

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-10-23 13:42:14 -07:00
parent 8e1a75ce1c
commit 13531b7d3e
22 changed files with 859 additions and 859 deletions

View file

@ -1,7 +1,7 @@
add_library(kernel expr.cpp free_vars.cpp abstract.cpp instantiate.cpp add_library(kernel expr.cpp free_vars.cpp abstract.cpp instantiate.cpp
normalizer.cpp context.cpp level.cpp object.cpp environment.cpp normalizer.cpp context.cpp level.cpp object.cpp environment.cpp
type_checker.cpp builtin.cpp occurs.cpp metavar.cpp trace.cpp type_checker.cpp builtin.cpp occurs.cpp metavar.cpp justification.cpp
unification_constraint.cpp printer.cpp formatter.cpp unification_constraint.cpp printer.cpp formatter.cpp
kernel_exception.cpp type_checker_trace.cpp pos_info_provider.cpp) kernel_exception.cpp type_checker_justification.cpp pos_info_provider.cpp)
target_link_libraries(kernel ${LEAN_LIBS}) target_link_libraries(kernel ${LEAN_LIBS})

View file

@ -6,10 +6,10 @@ Author: Leonardo de Moura
*/ */
#include <set> #include <set>
#include "util/buffer.h" #include "util/buffer.h"
#include "kernel/trace.h" #include "kernel/justification.h"
namespace lean { namespace lean {
void trace_cell::add_pos_info(format & r, expr const & e, pos_info_provider const * p) { void justification_cell::add_pos_info(format & r, expr const & e, pos_info_provider const * p) {
if (!p || !e) if (!p || !e)
return; return;
format f = p->pp(e); format f = p->pp(e);
@ -19,41 +19,41 @@ void trace_cell::add_pos_info(format & r, expr const & e, pos_info_provider cons
r += space(); r += space();
} }
format trace_cell::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool display_children) const { format justification_cell::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool display_children) const {
format r; format r;
add_pos_info(r, get_main_expr(), p); add_pos_info(r, get_main_expr(), p);
r += pp_header(fmt, opts); r += pp_header(fmt, opts);
if (display_children) { if (display_children) {
buffer<trace_cell *> children; buffer<justification_cell *> children;
get_children(children); get_children(children);
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
for (trace_cell * child : children) { for (justification_cell * child : children) {
r += nest(indent, compose(line(), child->pp(fmt, opts, p, display_children))); r += nest(indent, compose(line(), child->pp(fmt, opts, p, display_children)));
} }
} }
return r; return r;
} }
bool trace::has_children() const { bool justification::has_children() const {
buffer<trace_cell *> r; buffer<justification_cell *> r;
get_children(r); get_children(r);
return !r.empty(); return !r.empty();
} }
bool depends_on(trace const & t, trace const & d) { bool depends_on(justification const & t, justification const & d) {
buffer<trace_cell *> todo; buffer<justification_cell *> todo;
std::set<trace_cell *> visited; std::set<justification_cell *> visited;
buffer<trace_cell *> children; buffer<justification_cell *> children;
todo.push_back(t.raw()); todo.push_back(t.raw());
while (!todo.empty()) { while (!todo.empty()) {
trace_cell * curr = todo.back(); justification_cell * curr = todo.back();
todo.pop_back(); todo.pop_back();
if (curr == d.raw()) { if (curr == d.raw()) {
return true; return true;
} else { } else {
children.clear(); children.clear();
curr->get_children(children); curr->get_children(children);
for (trace_cell * child : children) { for (justification_cell * child : children) {
if (child->is_shared()) { if (child->is_shared()) {
if (visited.find(child) == visited.end()) { if (visited.find(child) == visited.end()) {
visited.insert(child); visited.insert(child);

View file

@ -15,54 +15,54 @@ Author: Leonardo de Moura
#include "kernel/pos_info_provider.h" #include "kernel/pos_info_provider.h"
namespace lean { namespace lean {
class trace; class justification;
/** /**
\brief Base class used to represent trace objects. \brief Base class used to represent justification objects.
These objects are used to trace the execution of different engines in Lean. These objects are used to justification the execution of different engines in Lean.
The traces may help users understanding why something did not work. The justifications may help users understanding why something did not work.
The traces are particularly important for the elaborator. The justifications are particularly important for the elaborator.
*/ */
class trace_cell { class justification_cell {
MK_LEAN_RC(); MK_LEAN_RC();
void dealloc() { delete this; } void dealloc() { delete this; }
protected: protected:
static void add_pos_info(format & r, expr const & e, pos_info_provider const * p); static void add_pos_info(format & r, expr const & e, pos_info_provider const * p);
public: public:
trace_cell():m_rc(0) {} justification_cell():m_rc(0) {}
virtual ~trace_cell() {} virtual ~justification_cell() {}
virtual format pp_header(formatter const & fmt, options const & opts) const = 0; virtual format pp_header(formatter const & fmt, options const & opts) const = 0;
virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool display_children) const; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool display_children) const;
virtual void get_children(buffer<trace_cell*> & r) const = 0; virtual void get_children(buffer<justification_cell*> & r) const = 0;
virtual expr const & get_main_expr() const { return expr::null(); } virtual expr const & get_main_expr() const { return expr::null(); }
bool is_shared() const { return get_rc() > 1; } bool is_shared() const { return get_rc() > 1; }
}; };
/** /**
\brief Smart pointer for trace_cell's \brief Smart pointer for justification_cell's
*/ */
class trace { class justification {
trace_cell * m_ptr; justification_cell * m_ptr;
public: public:
trace():m_ptr(nullptr) {} justification():m_ptr(nullptr) {}
trace(trace_cell * ptr):m_ptr(ptr) { if (m_ptr) m_ptr->inc_ref(); } justification(justification_cell * ptr):m_ptr(ptr) { if (m_ptr) m_ptr->inc_ref(); }
trace(trace const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); } justification(justification const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
trace(trace && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; } justification(justification && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
~trace() { if (m_ptr) m_ptr->dec_ref(); } ~justification() { if (m_ptr) m_ptr->dec_ref(); }
operator bool() const { return m_ptr != nullptr; } operator bool() const { return m_ptr != nullptr; }
trace_cell * raw() const { return m_ptr; } justification_cell * raw() const { return m_ptr; }
friend void swap(trace & a, trace & b) { std::swap(a.m_ptr, b.m_ptr); } friend void swap(justification & a, justification & b) { std::swap(a.m_ptr, b.m_ptr); }
trace & operator=(trace const & s) { LEAN_COPY_REF(trace, s); } justification & operator=(justification const & s) { LEAN_COPY_REF(justification, s); }
trace & operator=(trace && s) { LEAN_MOVE_REF(trace, s); } justification & operator=(justification && s) { LEAN_MOVE_REF(justification, s); }
format pp(formatter const & fmt, options const & opts, pos_info_provider const * p = nullptr, bool display_children = true) const { format pp(formatter const & fmt, options const & opts, pos_info_provider const * p = nullptr, bool display_children = true) const {
lean_assert(m_ptr); lean_assert(m_ptr);
return m_ptr->pp(fmt, opts, p, display_children); return m_ptr->pp(fmt, opts, p, display_children);
} }
expr const & get_main_expr() const { return m_ptr ? m_ptr->get_main_expr() : expr::null(); } expr const & get_main_expr() const { return m_ptr ? m_ptr->get_main_expr() : expr::null(); }
void get_children(buffer<trace_cell*> & r) const { if (m_ptr) m_ptr->get_children(r); } void get_children(buffer<justification_cell*> & r) const { if (m_ptr) m_ptr->get_children(r); }
bool has_children() const; bool has_children() const;
}; };
@ -70,5 +70,5 @@ public:
\brief Return true iff \c t depends on \c d. \brief Return true iff \c t depends on \c d.
That is \c t is a descendant of \c d. That is \c t is a descendant of \c d.
*/ */
bool depends_on(trace const & t, trace const & d); bool depends_on(justification const & t, justification const & d);
} }

View file

@ -87,12 +87,12 @@ 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();
void swap(metavar_env & a, metavar_env & b) { void swap(metavar_env & a, metavar_env & b) {
swap(a.m_name_generator, b.m_name_generator); swap(a.m_name_generator, b.m_name_generator);
swap(a.m_substitution, b.m_substitution); swap(a.m_substitution, b.m_substitution);
swap(a.m_metavar_types, b.m_metavar_types); swap(a.m_metavar_types, b.m_metavar_types);
swap(a.m_metavar_contexts, b.m_metavar_contexts); swap(a.m_metavar_contexts, b.m_metavar_contexts);
swap(a.m_metavar_traces, b.m_metavar_traces); swap(a.m_metavar_justifications, b.m_metavar_justifications);
std::swap(a.m_timestamp, b.m_timestamp); std::swap(a.m_timestamp, b.m_timestamp);
} }
void metavar_env::inc_timestamp() { void metavar_env::inc_timestamp() {
@ -173,17 +173,17 @@ bool metavar_env::has_type(expr const & m) const {
} }
trace metavar_env::get_trace(expr const & m) const { justification metavar_env::get_justification(expr const & m) const {
lean_assert(is_metavar(m)); lean_assert(is_metavar(m));
return get_trace(metavar_name(m)); return get_justification(metavar_name(m));
} }
trace metavar_env::get_trace(name const & m) const { justification metavar_env::get_justification(name const & m) const {
auto e = const_cast<metavar_env*>(this)->m_metavar_traces.splay_find(m); auto e = const_cast<metavar_env*>(this)->m_metavar_justifications.splay_find(m);
if (e) { if (e) {
return e->second; return e->second;
} else { } else {
return trace(); return justification();
} }
} }
@ -196,18 +196,18 @@ bool metavar_env::is_assigned(expr const & m) const {
return is_assigned(metavar_name(m)); return is_assigned(metavar_name(m));
} }
void metavar_env::assign(name const & m, expr const & t, trace const & tr) { void metavar_env::assign(name const & m, expr const & t, justification const & j) {
lean_assert(!is_assigned(m)); lean_assert(!is_assigned(m));
inc_timestamp(); inc_timestamp();
m_substitution.assign(m, t); m_substitution.assign(m, t);
if (tr) if (j)
m_metavar_traces.insert(m, tr); m_metavar_justifications.insert(m, j);
} }
void metavar_env::assign(expr const & m, expr const & t, trace const & tr) { void metavar_env::assign(expr const & m, expr const & t, justification const & j) {
lean_assert(is_metavar(m)); lean_assert(is_metavar(m));
lean_assert(!has_local_context(m)); lean_assert(!has_local_context(m));
assign(metavar_name(m), t, tr); assign(metavar_name(m), t, j);
} }
struct found_unassigned{}; struct found_unassigned{};

View file

@ -10,7 +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" #include "kernel/justification.h"
namespace lean { namespace lean {
/** /**
@ -89,16 +89,16 @@ void swap(substitution & s1, substitution & s2);
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; typedef splay_map<name, justification, name_cmp> name2justification;
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; name2justification m_metavar_justifications;
unsigned m_timestamp; unsigned m_timestamp;
void inc_timestamp(); void inc_timestamp();
public: public:
@ -146,12 +146,12 @@ public:
bool has_type(name const & m) const; bool has_type(name const & m) const;
/** /**
\brief Return the trace/justification for an assigned metavariable. \brief Return the justification for an assigned metavariable.
\pre is_metavar(m) \pre is_metavar(m)
\pre is_assigned(m) \pre is_assigned(m)
*/ */
trace get_trace(expr const & m) const; justification get_justification(expr const & m) const;
trace get_trace(name const & m) const; justification get_justification(name const & m) const;
/** /**
@ -172,7 +172,7 @@ public:
\pre !is_assigned(m) \pre !is_assigned(m)
*/ */
void assign(name const & m, expr const & t, trace const & tr = trace()); void assign(name const & m, expr const & t, justification const & j = justification());
/** /**
\brief Assign metavariable \c m to \c t. \brief Assign metavariable \c m to \c t.
@ -181,7 +181,7 @@ 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, trace const & tr = trace()); void assign(expr const & m, expr const & t, justification const & j = justification());
/** /**
\brief Return the set of substitutions. \brief Return the set of substitutions.

View file

@ -13,7 +13,7 @@ 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/type_checker_trace.h" #include "kernel/type_checker_justification.h"
namespace lean { namespace lean {
static name g_x_name("x"); static name g_x_name("x");
@ -55,8 +55,8 @@ class type_checker::imp {
expr A = m_menv->mk_metavar(ctx); expr A = m_menv->mk_metavar(ctx);
expr B = m_menv->mk_metavar(ctx); 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)));
trace tr = mk_function_expected_trace(ctx, s); justification jst = mk_function_expected_justification(ctx, s);
m_uc->push_back(mk_eq_constraint(ctx, r, p, tr)); m_uc->push_back(mk_eq_constraint(ctx, r, p, jst));
return p; return p;
} }
throw function_expected_exception(m_env, ctx, s); throw function_expected_exception(m_env, ctx, s);
@ -73,8 +73,8 @@ class type_checker::imp {
if (u == Bool) if (u == Bool)
return Type(); return Type();
if (has_metavar(u) && m_menv) { if (has_metavar(u) && m_menv) {
trace tr = mk_type_expected_trace(ctx, s); justification jst = mk_type_expected_justification(ctx, s);
m_uc->push_back(mk_convertible_constraint(ctx, u, TypeU, tr)); m_uc->push_back(mk_convertible_constraint(ctx, u, TypeU, jst));
return u; return u;
} }
throw type_expected_exception(m_env, ctx, s); throw type_expected_exception(m_env, ctx, s);
@ -123,8 +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];
auto mk_trace = [&](){ return mk_app_type_match_trace(ctx, e, i); }; // thunk for creating trace object if needed auto mk_justification = [&](){ return mk_app_type_match_justification(ctx, e, i); }; // thunk for creating justification object if needed
if (!is_convertible(c_t, abst_domain(f_t), ctx, mk_trace)) if (!is_convertible(c_t, abst_domain(f_t), ctx, mk_justification))
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);
@ -169,9 +169,9 @@ class type_checker::imp {
r = mk_type(max(ty_level(t1), ty_level(t2))); r = mk_type(max(ty_level(t1), ty_level(t2)));
} else { } else {
lean_assert(m_uc); lean_assert(m_uc);
trace tr = mk_max_type_trace(ctx, e); justification jst = mk_max_type_justification(ctx, e);
r = m_menv->mk_metavar(ctx); r = m_menv->mk_metavar(ctx);
m_uc->push_back(mk_max_constraint(ctx, t1, t2, r, tr)); m_uc->push_back(mk_max_constraint(ctx, t1, t2, r, jst));
} }
break; break;
} }
@ -180,8 +180,8 @@ class type_checker::imp {
if (let_type(e)) { if (let_type(e)) {
expr ty = infer_type_core(let_type(e), ctx); expr ty = infer_type_core(let_type(e), ctx);
check_type(ty, let_type(e), ctx); // check if it is really a type 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 auto mk_justification = [&](){ return mk_def_type_match_justification(ctx, let_name(e), let_value(e)); }; // thunk for creating justification object if needed
if (!is_convertible(lt, let_type(e), ctx, mk_trace)) if (!is_convertible(lt, let_type(e), ctx, mk_justification))
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);
} }
{ {
@ -235,8 +235,8 @@ class type_checker::imp {
} }
} }
template<typename MkTrace> template<typename MkJustification>
bool is_convertible(expr const & given, expr const & expected, context const & ctx, MkTrace const & mk_trace) { bool is_convertible(expr const & given, expr const & expected, context const & ctx, MkJustification const & mk_justification) {
if (is_convertible_core(given, expected)) if (is_convertible_core(given, expected))
return true; return true;
expr new_given = normalize(given, ctx); expr new_given = normalize(given, ctx);
@ -244,7 +244,7 @@ class type_checker::imp {
if (is_convertible_core(new_given, new_expected)) if (is_convertible_core(new_given, new_expected))
return true; return true;
if (m_menv && (has_metavar(new_given) || has_metavar(new_expected))) { if (m_menv && (has_metavar(new_given) || has_metavar(new_expected))) {
m_uc->push_back(mk_convertible_constraint(ctx, new_given, new_expected, mk_trace())); m_uc->push_back(mk_convertible_constraint(ctx, new_given, new_expected, mk_justification()));
return true; return true;
} }
return false; return false;
@ -292,8 +292,8 @@ public:
bool is_convertible(expr const & t1, expr const & t2, context const & ctx) { bool is_convertible(expr const & t1, expr const & t2, context const & ctx) {
set_ctx(ctx); set_ctx(ctx);
set_menv(nullptr); set_menv(nullptr);
auto mk_trace = [](){ lean_unreachable(); return trace(); }; auto mk_justification = [](){ lean_unreachable(); return justification(); };
return is_convertible(t1, t2, ctx, mk_trace); return is_convertible(t1, t2, ctx, mk_justification);
} }
void check_type(expr const & e, context const & ctx) { void check_type(expr const & e, context const & ctx) {

View file

@ -4,14 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#include "kernel/type_checker_trace.h" #include "kernel/type_checker_justification.h"
namespace lean { namespace lean {
function_expected_trace_cell::~function_expected_trace_cell() { function_expected_justification_cell::~function_expected_justification_cell() {
} }
format function_expected_trace_cell::pp_header(formatter const & fmt, options const & opts) const { format function_expected_justification_cell::pp_header(formatter const & fmt, options const & opts) const {
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
format expr_fmt = fmt(m_ctx, m_app, false, opts); format expr_fmt = fmt(m_ctx, m_app, false, opts);
format r; format r;
@ -20,17 +20,17 @@ format function_expected_trace_cell::pp_header(formatter const & fmt, options co
return r; return r;
} }
void function_expected_trace_cell::get_children(buffer<trace_cell*> &) const { void function_expected_justification_cell::get_children(buffer<justification_cell*> &) const {
} }
expr const & function_expected_trace_cell::get_main_expr() const { expr const & function_expected_justification_cell::get_main_expr() const {
return m_app; return m_app;
} }
app_type_match_trace_cell::~app_type_match_trace_cell() { app_type_match_justification_cell::~app_type_match_justification_cell() {
} }
format app_type_match_trace_cell::pp_header(formatter const & fmt, options const & opts) const { format app_type_match_justification_cell::pp_header(formatter const & fmt, options const & opts) const {
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
format r; format r;
r += format("Type of argument "); r += format("Type of argument ");
@ -48,17 +48,17 @@ format app_type_match_trace_cell::pp_header(formatter const & fmt, options const
return r; return r;
} }
void app_type_match_trace_cell::get_children(buffer<trace_cell*> &) const { void app_type_match_justification_cell::get_children(buffer<justification_cell*> &) const {
} }
expr const & app_type_match_trace_cell::get_main_expr() const { expr const & app_type_match_justification_cell::get_main_expr() const {
return m_app; return m_app;
} }
type_expected_trace_cell::~type_expected_trace_cell() { type_expected_justification_cell::~type_expected_justification_cell() {
} }
format type_expected_trace_cell::pp_header(formatter const & fmt, options const & opts) const { format type_expected_justification_cell::pp_header(formatter const & fmt, options const & opts) const {
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
format expr_fmt = fmt(m_ctx, m_type, false, opts); format expr_fmt = fmt(m_ctx, m_type, false, opts);
format r; format r;
@ -67,17 +67,17 @@ format type_expected_trace_cell::pp_header(formatter const & fmt, options const
return r; return r;
} }
void type_expected_trace_cell::get_children(buffer<trace_cell*> &) const { void type_expected_justification_cell::get_children(buffer<justification_cell*> &) const {
} }
expr const & type_expected_trace_cell::get_main_expr() const { expr const & type_expected_justification_cell::get_main_expr() const {
return m_type; return m_type;
} }
def_type_match_trace_cell::~def_type_match_trace_cell() { def_type_match_justification_cell::~def_type_match_justification_cell() {
} }
format def_type_match_trace_cell::pp_header(formatter const &, options const &) const { format def_type_match_justification_cell::pp_header(formatter const &, options const &) const {
format r; format r;
r += format("Type of definition '"); r += format("Type of definition '");
r += format(get_name()); r += format(get_name());
@ -85,10 +85,10 @@ format def_type_match_trace_cell::pp_header(formatter const &, options const &)
return r; return r;
} }
void def_type_match_trace_cell::get_children(buffer<trace_cell*> &) const { void def_type_match_justification_cell::get_children(buffer<justification_cell*> &) const {
} }
expr const & def_type_match_trace_cell::get_main_expr() const { expr const & def_type_match_justification_cell::get_main_expr() const {
return m_value; return m_value;
} }
} }

View file

@ -0,0 +1,128 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/justification.h"
#include "kernel/expr.h"
#include "kernel/context.h"
namespace lean {
/**
\brief Justification produced by the type checker when the application \c m_app
is an application <tt>(f ...)</tt>, the type \c T of \c f contains metavariables, and
it is not clear whether it is a Pi or not. In this case, the type checker adds
the constraint
<tt>ctx |- T == Pi (x : ?A), ?B x</tt>
where, \c ?A and \c ?B are fresh metavariables.
This justification cell is used to justify the new constraint.
*/
class function_expected_justification_cell : public justification_cell {
context m_ctx;
expr m_app;
public:
function_expected_justification_cell(context const & c, expr const & app):m_ctx(c), m_app(app) {}
virtual ~function_expected_justification_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<justification_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_app() const { return m_app; }
};
/**
\brief Justification produced by the type checker for application argument type matching.
When checking an application <tt>(f a_1 ... a_i ...)</tt>, the type
\c T_inferred of \c a_i must be convertible to the expected type \c T_expected. If
\c T_expected or \c T_inferred contain metavariables, and it is not clear whether
\c T_inferred is convertible to \c T_expected, then the type checker adds the constraint
<tt>ctx |- T_inferred << T_expected</tt>
This justification cell is used to justify this constraint.
*/
class app_type_match_justification_cell : public justification_cell {
context m_ctx;
expr m_app;
unsigned m_i;
public:
app_type_match_justification_cell(context const & c, expr const & a, unsigned i):m_ctx(c), m_app(a), m_i(i) {}
virtual ~app_type_match_justification_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<justification_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_app() const { return m_app; }
unsigned get_arg_pos() const { return m_i; }
};
/**
\brief Justification produced by the type checker when the type \c T of \c type must be of the form
<tt>Type l</tt>, and \c T constains metavariables, and it is not of this form.
The type checker adds the following constraint
<tt>ctx |- T << Type U</tt>
This justification cell is used to justify these constraints.
*/
class type_expected_justification_cell : public justification_cell {
context m_ctx;
expr m_type;
public:
type_expected_justification_cell(context const & c, expr const & t):m_ctx(c), m_type(t) {}
virtual ~type_expected_justification_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<justification_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_type() const { return m_type; }
};
/**
\brief If \c type is of the form <tt>Pi x : A, B</tt>, where \c A has type \c T1 and \c B has type \c T2,
and \c T1 or \c T2 have metavariables, then the type checker adds the following constraint
<tt>ctx |- max(T1, T2) == ?T
where ?T is a new metavariable, and this justification cell is used to justify the new constraint.
*/
class max_type_justification_cell : public type_expected_justification_cell {
public:
max_type_justification_cell(context const & c, expr const & t):type_expected_justification_cell(c, t) {}
};
/**
\brief Justification produced by the type checker when checking whether the type \c T_inferred of \c value
is convertible to the expected type \c T_expected. If \c T_expected or \c T_inferred contain
metavariables, and it is not clear whether \c T_inferred is convertible to \c T_expected,
then the type checker adds the constraint
<tt>ctx |- T_inferred << T_expected</tt>
This justification cell is used to justify this constraint.
*/
class def_type_match_justification_cell : public justification_cell {
context m_ctx;
name m_name;
expr m_value;
public:
def_type_match_justification_cell(context const & c, name const & n, expr const & v):m_ctx(c), m_name(n), m_value(v) {}
virtual ~def_type_match_justification_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<justification_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
name const & get_name() const { return m_name; }
expr const & get_value() const { return m_value; }
};
inline justification mk_function_expected_justification(context const & ctx, expr const & app) { return justification(new function_expected_justification_cell(ctx, app)); }
inline justification mk_app_type_match_justification(context const & ctx, expr const & app, unsigned i) { return justification(new app_type_match_justification_cell(ctx, app, i)); }
inline justification mk_type_expected_justification(context const & ctx, expr const & type) { return justification(new type_expected_justification_cell(ctx, type)); }
inline justification mk_max_type_justification(context const & ctx, expr const & type) { return justification(new max_type_justification_cell(ctx, type)); }
inline justification mk_def_type_match_justification(context const & ctx, name const & n, expr const & v) { return justification(new def_type_match_justification_cell(ctx, n, v)); }
}

View file

@ -1,128 +0,0 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/trace.h"
#include "kernel/expr.h"
#include "kernel/context.h"
namespace lean {
/**
\brief Trace produced by the type checker when the application \c m_app
is an application <tt>(f ...)</tt>, the type \c T of \c f contains metavariables, and
it is not clear whether it is a Pi or not. In this case, the type checker adds
the constraint
<tt>ctx |- T == Pi (x : ?A), ?B x</tt>
where, \c ?A and \c ?B are fresh metavariables.
This trace cell is used to justify/trace the new constraint.
*/
class function_expected_trace_cell : public trace_cell {
context m_ctx;
expr m_app;
public:
function_expected_trace_cell(context const & c, expr const & app):m_ctx(c), m_app(app) {}
virtual ~function_expected_trace_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<trace_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_app() const { return m_app; }
};
/**
\brief Trace produced by the type checker for application argument type matching.
When checking an application <tt>(f a_1 ... a_i ...)</tt>, the type
\c T_inferred of \c a_i must be convertible to the expected type \c T_expected. If
\c T_expected or \c T_inferred contain metavariables, and it is not clear whether
\c T_inferred is convertible to \c T_expected, then the type checker adds the constraint
<tt>ctx |- T_inferred << T_expected</tt>
This trace cell is used to justify this constraint.
*/
class app_type_match_trace_cell : public trace_cell {
context m_ctx;
expr m_app;
unsigned m_i;
public:
app_type_match_trace_cell(context const & c, expr const & a, unsigned i):m_ctx(c), m_app(a), m_i(i) {}
virtual ~app_type_match_trace_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<trace_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_app() const { return m_app; }
unsigned get_arg_pos() const { return m_i; }
};
/**
\brief Trace produced by the type checker when the type \c T of \c type must be of the form
<tt>Type l</tt>, and \c T constains metavariables, and it is not of this form.
The type checker adds the following constraint
<tt>ctx |- T << Type U</tt>
This trace cell is used to justify these constraints.
*/
class type_expected_trace_cell : public trace_cell {
context m_ctx;
expr m_type;
public:
type_expected_trace_cell(context const & c, expr const & t):m_ctx(c), m_type(t) {}
virtual ~type_expected_trace_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<trace_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
expr const & get_type() const { return m_type; }
};
/**
\brief If \c type is of the form <tt>Pi x : A, B</tt>, where \c A has type \c T1 and \c B has type \c T2,
and \c T1 or \c T2 have metavariables, then the type checker adds the following constraint
<tt>ctx |- max(T1, T2) == ?T
where ?T is a new metavariable, and this trace cell is used to justify the new constraint.
*/
class max_type_trace_cell : public type_expected_trace_cell {
public:
max_type_trace_cell(context const & c, expr const & t):type_expected_trace_cell(c, t) {}
};
/**
\brief Trace produced by the type checker when checking whether the type \c T_inferred of \c value
is convertible to the expected type \c T_expected. If \c T_expected or \c T_inferred contain
metavariables, and it is not clear whether \c T_inferred is convertible to \c T_expected,
then the type checker adds the constraint
<tt>ctx |- T_inferred << T_expected</tt>
This trace cell is used to justify this constraint.
*/
class def_type_match_trace_cell : public trace_cell {
context m_ctx;
name m_name;
expr m_value;
public:
def_type_match_trace_cell(context const & c, name const & n, expr const & v):m_ctx(c), m_name(n), m_value(v) {}
virtual ~def_type_match_trace_cell();
virtual format pp_header(formatter const & fmt, options const & opts) const;
virtual void get_children(buffer<trace_cell*> &) const;
virtual expr const & get_main_expr() const;
context const & get_context() const { return m_ctx; }
name const & get_name() const { return m_name; }
expr const & get_value() const { return m_value; }
};
inline trace mk_function_expected_trace(context const & ctx, expr const & app) { return trace(new function_expected_trace_cell(ctx, app)); }
inline trace mk_app_type_match_trace(context const & ctx, expr const & app, unsigned i) { return trace(new app_type_match_trace_cell(ctx, app, i)); }
inline trace mk_type_expected_trace(context const & ctx, expr const & type) { return trace(new type_expected_trace_cell(ctx, type)); }
inline trace mk_max_type_trace(context const & ctx, expr const & type) { return trace(new max_type_trace_cell(ctx, type)); }
inline trace mk_def_type_match_trace(context const & ctx, name const & n, expr const & v) { return trace(new def_type_match_trace_cell(ctx, n, v)); }
}

View file

@ -7,8 +7,8 @@ Author: Leonardo de Moura
#include "kernel/unification_constraint.h" #include "kernel/unification_constraint.h"
namespace lean { 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, justification const & j):
m_kind(k), m_ctx(c), m_trace(t), m_rc(1) { m_kind(k), m_ctx(c), m_justification(j), m_rc(1) {
} }
unification_constraint_cell::~unification_constraint_cell() { unification_constraint_cell::~unification_constraint_cell() {
} }
@ -23,10 +23,10 @@ static format add_context(formatter const & fmt, options const & opts, context c
return group(format{ctx_fmt, space(), turnstile, line(), body}); return group(format{ctx_fmt, space(), turnstile, line(), body});
} }
static format add_trace(formatter const & fmt, options const & opts, format const & body, trace const & tr, pos_info_provider const * p, bool include_trace) { static format add_justification(formatter const & fmt, options const & opts, format const & body, justification const & jst, pos_info_provider const * p, bool include_justification) {
if (tr && include_trace) { if (jst && include_justification) {
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
return format{body, line(), format("Trace:"), nest(indent, compose(line(), tr.pp(fmt, opts, p)))}; return format{body, line(), format("Justification:"), nest(indent, compose(line(), jst.pp(fmt, opts, p)))};
} else { } else {
return body; return body;
} }
@ -43,8 +43,8 @@ static format mk_unification_op(options const & opts) {
return unicode ? format("\u2248") /* ≈ */ : format("=?="); 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, justification const & j):
unification_constraint_cell(unification_constraint_kind::Eq, c, t), unification_constraint_cell(unification_constraint_kind::Eq, c, j),
m_lhs(lhs), m_lhs(lhs),
m_rhs(rhs) { m_rhs(rhs) {
} }
@ -52,15 +52,15 @@ unification_constraint_eq::unification_constraint_eq(context const & c, expr con
unification_constraint_eq::~unification_constraint_eq() { unification_constraint_eq::~unification_constraint_eq() {
} }
format unification_constraint_eq::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_trace) const { format unification_constraint_eq::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const {
format op = mk_unification_op(opts); format op = mk_unification_op(opts);
format body = mk_binary(fmt, opts, m_ctx, m_lhs, m_rhs, op); format body = mk_binary(fmt, opts, m_ctx, m_lhs, m_rhs, op);
body = add_context(fmt, opts, m_ctx, body); body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, p, include_trace); return add_justification(fmt, opts, body, m_justification, p, include_justification);
} }
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, justification const & j):
unification_constraint_cell(unification_constraint_kind::Convertible, c, t), unification_constraint_cell(unification_constraint_kind::Convertible, c, j),
m_from(from), m_from(from),
m_to(to) { m_to(to) {
} }
@ -68,16 +68,16 @@ unification_constraint_convertible::unification_constraint_convertible(context c
unification_constraint_convertible::~unification_constraint_convertible() { unification_constraint_convertible::~unification_constraint_convertible() {
} }
format unification_constraint_convertible::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_trace) const { format unification_constraint_convertible::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const {
bool unicode = get_pp_unicode(opts); bool unicode = get_pp_unicode(opts);
format op = unicode ? format("\u227A") /* ≺ */ : format("<<"); format op = unicode ? format("\u227A") /* ≺ */ : format("<<");
format body = mk_binary(fmt, opts, m_ctx, m_from, m_to, op); format body = mk_binary(fmt, opts, m_ctx, m_from, m_to, op);
body = add_context(fmt, opts, m_ctx, body); body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, p, include_trace); return add_justification(fmt, opts, body, m_justification, p, include_justification);
} }
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, justification const & j):
unification_constraint_cell(unification_constraint_kind::Max, c, t), unification_constraint_cell(unification_constraint_kind::Max, c, j),
m_lhs1(lhs1), m_lhs1(lhs1),
m_lhs2(lhs2), m_lhs2(lhs2),
m_rhs(rhs) { m_rhs(rhs) {
@ -86,18 +86,18 @@ unification_constraint_max::unification_constraint_max(context const & c, expr c
unification_constraint_max::~unification_constraint_max() { unification_constraint_max::~unification_constraint_max() {
} }
format unification_constraint_max::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_trace) const { format unification_constraint_max::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const {
format op = mk_unification_op(opts); format op = mk_unification_op(opts);
format lhs1_fmt = fmt(m_ctx, m_lhs1, false, opts); format lhs1_fmt = fmt(m_ctx, m_lhs1, false, opts);
format lhs2_fmt = fmt(m_ctx, m_lhs2, false, opts); format lhs2_fmt = fmt(m_ctx, m_lhs2, false, opts);
format rhs_fmt = fmt(m_ctx, m_rhs, 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)), rp(), space(), op, line(), rhs_fmt}); format body = group(format{format("max"), lp(), lhs1_fmt, comma(), nest(4, compose(line(), lhs2_fmt)), rp(), space(), op, line(), rhs_fmt});
body = add_context(fmt, opts, m_ctx, body); body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, p, include_trace); return add_justification(fmt, opts, body, m_justification, p, include_justification);
} }
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, justification const & j):
unification_constraint_cell(unification_constraint_kind::Choice, c, t), unification_constraint_cell(unification_constraint_kind::Choice, c, j),
m_mvar(mvar), m_mvar(mvar),
m_num_choices(num) { m_num_choices(num) {
} }
@ -105,7 +105,7 @@ unification_constraint_choice::unification_constraint_choice(context const & c,
unification_constraint_choice::~unification_constraint_choice() { unification_constraint_choice::~unification_constraint_choice() {
} }
format unification_constraint_choice::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_trace) const { format unification_constraint_choice::pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const {
bool unicode = get_pp_unicode(opts); bool unicode = get_pp_unicode(opts);
format m_fmt = fmt(m_ctx, m_mvar, false, opts); format m_fmt = fmt(m_ctx, m_mvar, false, opts);
format eq_op = mk_unification_op(opts); format eq_op = mk_unification_op(opts);
@ -118,31 +118,31 @@ format unification_constraint_choice::pp(formatter const & fmt, options const &
} }
body = group(body); body = group(body);
body = add_context(fmt, opts, m_ctx, body); body = add_context(fmt, opts, m_ctx, body);
return add_trace(fmt, opts, body, m_trace, p, include_trace); return add_justification(fmt, opts, body, m_justification, p, include_justification);
} }
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, justification const & j) {
return unification_constraint(new unification_constraint_eq(c, lhs, rhs, t)); return unification_constraint(new unification_constraint_eq(c, lhs, rhs, j));
} }
unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, trace const & t) { unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, justification const & j) {
return unification_constraint(new unification_constraint_convertible(c, from, to, t)); return unification_constraint(new unification_constraint_convertible(c, from, to, j));
} }
unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t) { unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, justification const & j) {
return unification_constraint(new unification_constraint_max(c, lhs1, lhs2, rhs, t)); return unification_constraint(new unification_constraint_max(c, lhs1, lhs2, rhs, j));
} }
unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, trace const & t) { unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, justification const & j) {
char * mem = new char[sizeof(unification_constraint_choice) + num*sizeof(expr)]; char * mem = new char[sizeof(unification_constraint_choice) + num*sizeof(expr)];
unification_constraint r(new (mem) unification_constraint_choice(c, mvar, num, t)); unification_constraint r(new (mem) unification_constraint_choice(c, mvar, num, j));
expr * m_choices = to_choice(r)->m_choices; expr * m_choices = to_choice(r)->m_choices;
for (unsigned i = 0; i < num; i++) for (unsigned i = 0; i < num; i++)
new (m_choices+i) expr(choices[i]); new (m_choices+i) expr(choices[i]);
return r; return r;
} }
unification_constraint mk_choice_constraint(context const & c, expr const & mvar, std::initializer_list<expr> const & choices, trace const & t) { unification_constraint mk_choice_constraint(context const & c, expr const & mvar, std::initializer_list<expr> const & choices, justification const & j) {
return mk_choice_constraint(c, mvar, choices.size(), choices.begin(), t); return mk_choice_constraint(c, mvar, choices.size(), choices.begin(), j);
} }
} }

View file

@ -8,7 +8,7 @@ Author: Leonardo de Moura
#include <algorithm> #include <algorithm>
#include "kernel/expr.h" #include "kernel/expr.h"
#include "kernel/context.h" #include "kernel/context.h"
#include "kernel/trace.h" #include "kernel/justification.h"
namespace lean { namespace lean {
/** /**
@ -37,17 +37,17 @@ class unification_constraint_cell {
protected: protected:
unification_constraint_kind m_kind; unification_constraint_kind m_kind;
context m_ctx; context m_ctx;
trace m_trace; //!< justification for this constraint justification m_justification; //!< justification for this constraint
MK_LEAN_RC(); MK_LEAN_RC();
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, justification const & j);
virtual ~unification_constraint_cell(); 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; } justification const & get_justification() const { return m_justification; }
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, pos_info_provider const * p, bool include_trace) const = 0; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const = 0;
void set_trace(trace const & t) { lean_assert(!m_trace); m_trace = t; } void set_justification(justification const & j) { lean_assert(!m_justification); m_justification = j; }
}; };
class unification_constraint { class unification_constraint {
@ -70,18 +70,18 @@ public:
operator bool() const { return m_ptr != nullptr; } operator bool() const { return m_ptr != nullptr; }
format pp(formatter const & fmt, options const & opts, pos_info_provider const * p = nullptr, bool include_trace = false) const { format pp(formatter const & fmt, options const & opts, pos_info_provider const * p = nullptr, bool include_justification = false) const {
lean_assert(m_ptr); lean_assert(m_ptr);
return m_ptr->pp(fmt, opts, p, include_trace); return m_ptr->pp(fmt, opts, p, include_justification);
} }
trace const & get_trace() const { lean_assert(m_ptr); return m_ptr->get_trace(); } justification const & get_justification() const { lean_assert(m_ptr); return m_ptr->get_justification(); }
void set_trace(trace const & t) { lean_assert(!get_trace()); lean_assert(m_ptr); m_ptr->set_trace(t); } void set_justification(justification const & j) { lean_assert(!get_justification()); lean_assert(m_ptr); m_ptr->set_justification(j); }
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, justification const & j);
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, justification const & j);
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, justification const & j);
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, justification const & j);
}; };
/** /**
@ -91,11 +91,11 @@ class unification_constraint_eq : public unification_constraint_cell {
expr m_lhs; expr m_lhs;
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, justification const & j);
virtual ~unification_constraint_eq(); 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, pos_info_provider const * p, bool include_trace) const; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const;
}; };
/** /**
@ -107,11 +107,11 @@ class unification_constraint_convertible : public unification_constraint_cell {
expr m_from; expr m_from;
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, justification const & j);
virtual ~unification_constraint_convertible(); 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, pos_info_provider const * p, bool include_trace) const; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const;
}; };
/** /**
@ -122,12 +122,12 @@ class unification_constraint_max : public unification_constraint_cell {
expr m_lhs2; expr m_lhs2;
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, justification const & j);
virtual ~unification_constraint_max(); 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, pos_info_provider const * p, bool include_trace) const; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) const;
}; };
/** /**
@ -137,23 +137,23 @@ class unification_constraint_choice : public unification_constraint_cell {
expr m_mvar; expr m_mvar;
unsigned m_num_choices; unsigned m_num_choices;
expr m_choices[0]; expr m_choices[0];
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, justification const & j);
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, justification const & j);
virtual ~unification_constraint_choice(); 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, pos_info_provider const * p, bool include_trace) const; virtual format pp(formatter const & fmt, options const & opts, pos_info_provider const * p, bool include_justification) 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, justification const & j);
unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, trace const & t); unification_constraint mk_convertible_constraint(context const & c, expr const & from, expr const & to, justification const & j);
unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, trace const & t); unification_constraint mk_max_constraint(context const & c, expr const & lhs1, expr const & lhs2, expr const & rhs, justification const & j);
unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, trace const & t); unification_constraint mk_choice_constraint(context const & c, expr const & mvar, unsigned num, expr const * choices, justification const & j);
unification_constraint mk_choice_constraint(context const & c, expr const & mvar, std::initializer_list<expr> const & choices, trace const & t); unification_constraint mk_choice_constraint(context const & c, expr const & mvar, std::initializer_list<expr> const & choices, justification const & j);
inline bool is_eq(unification_constraint const & c) { return c.kind() == unification_constraint_kind::Eq; } inline bool is_eq(unification_constraint const & c) { return c.kind() == unification_constraint_kind::Eq; }
inline bool is_convertible(unification_constraint const & c) { return c.kind() == unification_constraint_kind::Convertible; } inline bool is_convertible(unification_constraint const & c) { return c.kind() == unification_constraint_kind::Convertible; }
@ -166,7 +166,7 @@ inline unification_constraint_max * to_max(unification_constraint const
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()); }
inline 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(); }
inline trace const & get_trace(unification_constraint const & c) { return c.raw()->get_trace(); } inline justification const & get_justification(unification_constraint const & c) { return c.raw()->get_justification(); }
inline 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(); }
inline 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(); }
inline 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(); }

View file

@ -1,2 +1,2 @@
add_library(elaborator elaborator.cpp elaborator_trace.cpp) add_library(elaborator elaborator.cpp elaborator_justification.cpp)
target_link_libraries(elaborator ${LEAN_LIBS}) target_link_libraries(elaborator ${LEAN_LIBS})

View file

@ -18,7 +18,7 @@ Author: Leonardo de Moura
#include "library/update_expr.h" #include "library/update_expr.h"
#include "library/reduce.h" #include "library/reduce.h"
#include "library/elaborator/elaborator.h" #include "library/elaborator/elaborator.h"
#include "library/elaborator/elaborator_trace.h" #include "library/elaborator/elaborator_justification.h"
namespace lean { namespace lean {
static name g_x_name("x"); static name g_x_name("x");
@ -46,9 +46,9 @@ class elaborator::imp {
\brief Base class for case splits performed by the elaborator. \brief Base class for case splits performed by the elaborator.
*/ */
struct case_split { struct case_split {
trace m_curr_assumption; // trace object used to justify current split justification m_curr_assumption; // object used to justify current split
state m_prev_state; state m_prev_state;
std::vector<trace> m_failed_traces; // traces/justifications for failed branches std::vector<justification> m_failed_justifications; // justifications for failed branches
case_split(state const & prev_state):m_prev_state(prev_state) {} case_split(state const & prev_state):m_prev_state(prev_state) {}
virtual ~case_split() {} virtual ~case_split() {}
@ -80,10 +80,10 @@ class elaborator::imp {
\brief General purpose case split object \brief General purpose case split object
*/ */
struct generic_case_split : public case_split { struct generic_case_split : public case_split {
unification_constraint m_constraint; unification_constraint m_constraint;
unsigned m_idx; // current alternative unsigned m_idx; // current alternative
std::vector<state> m_states; // alternatives std::vector<state> m_states; // alternatives
std::vector<trace> m_assumptions; // assumption for each alternative std::vector<justification> m_assumptions; // assumption for each alternative
generic_case_split(unification_constraint const & cnstr, state const & prev_state): generic_case_split(unification_constraint const & cnstr, state const & prev_state):
case_split(prev_state), case_split(prev_state),
@ -97,7 +97,7 @@ class elaborator::imp {
return owner.next_generic_case(*this); return owner.next_generic_case(*this);
} }
void push_back(state const & s, trace const & tr) { void push_back(state const & s, justification const & tr) {
m_states.push_back(s); m_states.push_back(s);
m_assumptions.push_back(tr); m_assumptions.push_back(tr);
} }
@ -142,28 +142,28 @@ class elaborator::imp {
std::shared_ptr<elaborator_plugin> m_plugin; std::shared_ptr<elaborator_plugin> m_plugin;
unsigned m_next_id; unsigned m_next_id;
int m_quota; int m_quota;
trace m_conflict; justification m_conflict;
bool m_first; bool m_first;
bool m_interrupted; bool m_interrupted;
// options // options
bool m_use_traces; bool m_use_justifications;
bool m_use_normalizer; bool m_use_normalizer;
void set_options(options const &) { void set_options(options const &) {
m_use_traces = true; m_use_justifications = true;
m_use_normalizer = true; m_use_normalizer = true;
} }
void reset_quota() { void reset_quota() {
m_quota = m_state.m_queue.size(); m_quota = m_state.m_queue.size();
} }
trace mk_assumption() { justification mk_assumption() {
unsigned id = m_next_id; unsigned id = m_next_id;
m_next_id++; m_next_id++;
return trace(new assumption_trace(id)); return justification(new assumption_justification(id));
} }
/** \brief Add given constraint to the front of the current constraint queue */ /** \brief Add given constraint to the front of the current constraint queue */
@ -190,11 +190,11 @@ class elaborator::imp {
return m_state.m_menv.get_subst(m); return m_state.m_menv.get_subst(m);
} }
/** \brief Return the trace/justification for an assigned metavariable */ /** \brief Return the justification/justification for an assigned metavariable */
trace get_mvar_trace(expr const & m) const { justification get_mvar_justification(expr const & m) const {
lean_assert(is_metavar(m)); lean_assert(is_metavar(m));
lean_assert(is_assigned(m)); lean_assert(is_assigned(m));
return m_state.m_menv.get_trace(m); return m_state.m_menv.get_justification(m);
} }
/** \brief Return the type of an metavariable */ /** \brief Return the type of an metavariable */
@ -286,59 +286,59 @@ class elaborator::imp {
\brief Auxiliary method for pushing a new constraint to the given constraint queue. \brief Auxiliary method for pushing a new constraint to the given constraint queue.
If \c is_eq is true, then a equality constraint is created, otherwise a convertability constraint is created. If \c is_eq is true, then a equality constraint is created, otherwise a convertability constraint is created.
*/ */
void push_new_constraint(cnstr_queue & q, bool is_eq, context const & new_ctx, expr const & new_a, expr const & new_b, trace const & new_tr) { void push_new_constraint(cnstr_queue & q, bool is_eq, context const & new_ctx, expr const & new_a, expr const & new_b, justification const & new_jst) {
if (is_eq) if (is_eq)
q.push_front(mk_eq_constraint(new_ctx, new_a, new_b, new_tr)); q.push_front(mk_eq_constraint(new_ctx, new_a, new_b, new_jst));
else else
q.push_front(mk_convertible_constraint(new_ctx, new_a, new_b, new_tr)); q.push_front(mk_convertible_constraint(new_ctx, new_a, new_b, new_jst));
} }
void push_new_eq_constraint(cnstr_queue & q, context const & new_ctx, expr const & new_a, expr const & new_b, trace const & new_tr) { void push_new_eq_constraint(cnstr_queue & q, context const & new_ctx, expr const & new_a, expr const & new_b, justification const & new_jst) {
push_new_constraint(q, true, new_ctx, new_a, new_b, new_tr); push_new_constraint(q, true, new_ctx, new_a, new_b, new_jst);
} }
/** /**
\brief Auxiliary method for pushing a new constraint to the current constraint queue. \brief Auxiliary method for pushing a new constraint to the current constraint queue.
If \c is_eq is true, then a equality constraint is created, otherwise a convertability constraint is created. If \c is_eq is true, then a equality constraint is created, otherwise a convertability constraint is created.
*/ */
void push_new_constraint(bool is_eq, context const & new_ctx, expr const & new_a, expr const & new_b, trace const & new_tr) { void push_new_constraint(bool is_eq, context const & new_ctx, expr const & new_a, expr const & new_b, justification const & new_jst) {
reset_quota(); reset_quota();
push_new_constraint(m_state.m_queue, is_eq, new_ctx, new_a, new_b, new_tr); push_new_constraint(m_state.m_queue, is_eq, new_ctx, new_a, new_b, new_jst);
} }
/** /**
\brief Auxiliary method for pushing a new constraint to the current constraint queue. \brief Auxiliary method for pushing a new constraint to the current constraint queue.
The new constraint is based on the constraint \c c. The constraint \c c may be a equality or convertability constraint. The new constraint is based on the constraint \c c. The constraint \c c may be a equality or convertability constraint.
The update is justified by \c new_tr. The update is justified by \c new_jst.
*/ */
void push_updated_constraint(unification_constraint const & c, expr const & new_a, expr const & new_b, trace const & new_tr) { void push_updated_constraint(unification_constraint const & c, expr const & new_a, expr const & new_b, justification const & new_jst) {
lean_assert(is_eq(c) || is_convertible(c)); lean_assert(is_eq(c) || is_convertible(c));
context const & ctx = get_context(c); context const & ctx = get_context(c);
if (is_eq(c)) if (is_eq(c))
push_front(mk_eq_constraint(ctx, new_a, new_b, new_tr)); push_front(mk_eq_constraint(ctx, new_a, new_b, new_jst));
else else
push_front(mk_convertible_constraint(ctx, new_a, new_b, new_tr)); push_front(mk_convertible_constraint(ctx, new_a, new_b, new_jst));
} }
/** /**
\brief Auxiliary method for pushing a new constraint to the current constraint queue. \brief Auxiliary method for pushing a new constraint to the current constraint queue.
The new constraint is based on the constraint \c c. The constraint \c c may be a equality or convertability constraint. The new constraint is based on the constraint \c c. The constraint \c c may be a equality or convertability constraint.
The flag \c is_lhs says if the left-hand-side or right-hand-side are being updated with \c new_a. The flag \c is_lhs says if the left-hand-side or right-hand-side are being updated with \c new_a.
The update is justified by \c new_tr. The update is justified by \c new_jst.
*/ */
void push_updated_constraint(unification_constraint const & c, bool is_lhs, expr const & new_a, trace const & new_tr) { void push_updated_constraint(unification_constraint const & c, bool is_lhs, expr const & new_a, justification const & new_jst) {
lean_assert(is_eq(c) || is_convertible(c)); lean_assert(is_eq(c) || is_convertible(c));
context const & ctx = get_context(c); context const & ctx = get_context(c);
if (is_eq(c)) { if (is_eq(c)) {
if (is_lhs) if (is_lhs)
push_front(mk_eq_constraint(ctx, new_a, eq_rhs(c), new_tr)); push_front(mk_eq_constraint(ctx, new_a, eq_rhs(c), new_jst));
else else
push_front(mk_eq_constraint(ctx, eq_lhs(c), new_a, new_tr)); push_front(mk_eq_constraint(ctx, eq_lhs(c), new_a, new_jst));
} else { } else {
if (is_lhs) if (is_lhs)
push_front(mk_convertible_constraint(ctx, new_a, convertible_to(c), new_tr)); push_front(mk_convertible_constraint(ctx, new_a, convertible_to(c), new_jst));
else else
push_front(mk_convertible_constraint(ctx, convertible_from(c), new_a, new_tr)); push_front(mk_convertible_constraint(ctx, convertible_from(c), new_a, new_jst));
} }
} }
@ -347,13 +347,13 @@ class elaborator::imp {
The new constraint is obtained from \c c by one or more normalization steps that produce \c new_a and \c new_b The new constraint is obtained from \c c by one or more normalization steps that produce \c new_a and \c new_b
*/ */
void push_normalized_constraint(unification_constraint const & c, expr const & new_a, expr const & new_b) { void push_normalized_constraint(unification_constraint const & c, expr const & new_a, expr const & new_b) {
push_updated_constraint(c, new_a, new_b, trace(new normalize_trace(c))); push_updated_constraint(c, new_a, new_b, justification(new normalize_justification(c)));
} }
/** /**
\brief Assign \c v to \c m with justification \c tr in the current state. \brief Assign \c v to \c m with justification \c tr in the current state.
*/ */
void assign(expr const & m, expr const & v, context const & ctx, trace const & tr) { void assign(expr const & m, expr const & v, context const & ctx, justification const & tr) {
lean_assert(is_metavar(m)); lean_assert(is_metavar(m));
metavar_env & menv = m_state.m_menv; metavar_env & menv = m_state.m_menv;
m_state.m_menv.assign(m, v, tr); m_state.m_menv.assign(m, v, tr);
@ -362,8 +362,8 @@ class elaborator::imp {
expr tv = m_type_inferer(v, ctx, &menv, ucs); expr tv = m_type_inferer(v, ctx, &menv, ucs);
for (auto c : ucs) for (auto c : ucs)
push_front(c); push_front(c);
trace new_trace(new typeof_mvar_trace(ctx, m, menv.get_type(m), tv, tr)); justification new_jst(new typeof_mvar_justification(ctx, m, menv.get_type(m), tv, tr));
push_front(mk_convertible_constraint(ctx, tv, menv.get_type(m), new_trace)); push_front(mk_convertible_constraint(ctx, tv, menv.get_type(m), new_jst));
} }
} }
@ -400,16 +400,16 @@ class elaborator::imp {
if (is_metavar(a)) { if (is_metavar(a)) {
if (is_assigned(a)) { if (is_assigned(a)) {
// Case 1 // Case 1
trace new_tr(new substitution_trace(c, get_mvar_trace(a))); justification new_jst(new substitution_justification(c, get_mvar_justification(a)));
push_updated_constraint(c, is_lhs, get_mvar_subst(a), new_tr); push_updated_constraint(c, is_lhs, get_mvar_subst(a), new_jst);
return Processed; return Processed;
} else if (!has_local_context(a)) { } else if (!has_local_context(a)) {
// Case 2 // Case 2
if (has_metavar(b, a)) { if (has_metavar(b, a)) {
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return Failed; return Failed;
} else if (allow_assignment) { } else if (allow_assignment) {
assign(a, b, get_context(c), trace(new assignment_trace(c))); assign(a, b, get_context(c), justification(new assignment_justification(c)));
reset_quota(); reset_quota();
return Processed; return Processed;
} }
@ -418,18 +418,18 @@ class elaborator::imp {
if (me.is_lift()) { if (me.is_lift()) {
if (!has_free_var(b, me.s(), me.s() + me.n())) { if (!has_free_var(b, me.s(), me.s() + me.n())) {
// Case 3 // Case 3
trace new_tr(new normalize_trace(c)); justification new_jst(new normalize_justification(c));
expr new_a = pop_meta_context(a); expr new_a = pop_meta_context(a);
expr new_b = lower_free_vars(b, me.s() + me.n(), me.n()); expr new_b = lower_free_vars(b, me.s() + me.n(), me.n());
context new_ctx = get_context(c).remove(me.s(), me.n()); context new_ctx = get_context(c).remove(me.s(), me.n());
if (!is_lhs) if (!is_lhs)
swap(new_a, new_b); swap(new_a, new_b);
push_new_constraint(is_eq(c), new_ctx, new_a, new_b, new_tr); push_new_constraint(is_eq(c), new_ctx, new_a, new_b, new_jst);
return Processed; return Processed;
} else if (is_var(b)) { } else if (is_var(b)) {
// Failure, there is no way to unify // Failure, there is no way to unify
// ?m[lift:s:n, ...] with a variable in [s, s+n] // ?m[lift:s:n, ...] with a variable in [s, s+n]
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return Failed; return Failed;
} }
} }
@ -438,34 +438,34 @@ class elaborator::imp {
if (is_app(a) && is_metavar(arg(a, 0)) && is_assigned(arg(a, 0))) { if (is_app(a) && is_metavar(arg(a, 0)) && is_assigned(arg(a, 0))) {
// Case 4 // Case 4
trace new_tr(new substitution_trace(c, get_mvar_trace(arg(a, 0)))); justification new_jst(new substitution_justification(c, get_mvar_justification(arg(a, 0))));
expr new_a = update_app(a, 0, get_mvar_subst(arg(a, 0))); expr new_a = update_app(a, 0, get_mvar_subst(arg(a, 0)));
push_updated_constraint(c, is_lhs, new_a, new_tr); push_updated_constraint(c, is_lhs, new_a, new_jst);
return Processed; return Processed;
} }
return Continue; return Continue;
} }
trace mk_subst_trace(unification_constraint const & c, buffer<trace> const & subst_traces) { justification mk_subst_justification(unification_constraint const & c, buffer<justification> const & subst_justifications) {
if (subst_traces.size() == 1) { if (subst_justifications.size() == 1) {
return trace(new substitution_trace(c, subst_traces[0])); return justification(new substitution_justification(c, subst_justifications[0]));
} else { } else {
return trace(new multi_substitution_trace(c, subst_traces.size(), subst_traces.data())); return justification(new multi_substitution_justification(c, subst_justifications.size(), subst_justifications.data()));
} }
} }
/** /**
\brief Instantiate the assigned metavariables in \c a, and store the justification \brief Instantiate the assigned metavariables in \c a, and store the justifications
in \c traces. in \c jsts.
*/ */
expr instantiate_metavars(expr const & a, buffer<trace> & traces) { expr instantiate_metavars(expr const & a, buffer<justification> & jsts) {
lean_assert(has_assigned_metavar(a)); lean_assert(has_assigned_metavar(a));
metavar_env & menv = m_state.m_menv; metavar_env & menv = m_state.m_menv;
auto f = [&](expr const & m, unsigned) -> expr { auto f = [&](expr const & m, unsigned) -> expr {
if (is_metavar(m) && menv.is_assigned(m)) { if (is_metavar(m) && menv.is_assigned(m)) {
trace t = menv.get_trace(m); justification t = menv.get_justification(m);
if (t) if (t)
traces.push_back(t); jsts.push_back(t);
return menv.get_subst(m); return menv.get_subst(m);
} else { } else {
return m; return m;
@ -488,10 +488,10 @@ class elaborator::imp {
lean_assert(!is_convertible(c) || !is_lhs || is_eqp(convertible_from(c), a)); lean_assert(!is_convertible(c) || !is_lhs || is_eqp(convertible_from(c), a));
lean_assert(!is_convertible(c) || is_lhs || is_eqp(convertible_to(c), a)); lean_assert(!is_convertible(c) || is_lhs || is_eqp(convertible_to(c), a));
if (has_assigned_metavar(a)) { if (has_assigned_metavar(a)) {
buffer<trace> traces; buffer<justification> jsts;
expr new_a = instantiate_metavars(a, traces); expr new_a = instantiate_metavars(a, jsts);
trace new_tr = mk_subst_trace(c, traces); justification new_jst = mk_subst_justification(c, jsts);
push_updated_constraint(c, is_lhs, new_a, new_tr); push_updated_constraint(c, is_lhs, new_a, new_jst);
return true; return true;
} else { } else {
return false; return false;
@ -679,11 +679,11 @@ class elaborator::imp {
buffer<expr> types; buffer<expr> types;
for (unsigned i = 1; i < num_args(a); i++) for (unsigned i = 1; i < num_args(a); i++)
types.push_back(lookup(ctx, var_idx(arg(a, i))).get_domain()); types.push_back(lookup(ctx, var_idx(arg(a, i))).get_domain());
trace new_trace(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
expr s = mk_lambda(types, b); expr s = mk_lambda(types, b);
if (!is_lhs) if (!is_lhs)
swap(m, s); swap(m, s);
push_front(mk_eq_constraint(ctx, m, s, new_trace)); push_front(mk_eq_constraint(ctx, m, s, new_jst));
return true; return true;
} else { } else {
return false; return false;
@ -711,7 +711,7 @@ class elaborator::imp {
for (unsigned i = 1; i < num_a; i++) { for (unsigned i = 1; i < num_a; i++) {
// Assign f_a <- fun (x_1 : T_0) ... (x_{num_a-1} : T_{num_a-1}), x_i // Assign f_a <- fun (x_1 : T_0) ... (x_{num_a-1} : T_{num_a-1}), x_i
state new_state(m_state); state new_state(m_state);
trace new_assumption = mk_assumption(); justification new_assumption = mk_assumption();
expr proj = mk_lambda(arg_types, mk_var(num_a - i - 1)); expr proj = mk_lambda(arg_types, mk_var(num_a - i - 1));
expr new_a = arg(a, i); expr new_a = arg(a, i);
expr new_b = b; expr new_b = b;
@ -723,7 +723,7 @@ class elaborator::imp {
} }
// Add imitation // Add imitation
state new_state(m_state); state new_state(m_state);
trace new_assumption = mk_assumption(); justification new_assumption = mk_assumption();
expr imitation; expr imitation;
if (is_app(b)) { if (is_app(b)) {
// Imitation for applications // Imitation for applications
@ -829,7 +829,7 @@ class elaborator::imp {
{ {
// Case 1 // Case 1
state new_state(m_state); state new_state(m_state);
trace new_assumption = mk_assumption(); justification new_assumption = mk_assumption();
// add ?m[...] == #1 // add ?m[...] == #1
push_new_eq_constraint(new_state.m_queue, ctx, pop_meta_context(a), mk_var(i), new_assumption); push_new_eq_constraint(new_state.m_queue, ctx, pop_meta_context(a), mk_var(i), new_assumption);
// add t == b (t << b) // add t == b (t << b)
@ -843,7 +843,7 @@ class elaborator::imp {
{ {
// Case 2 // Case 2
state new_state(m_state); state new_state(m_state);
trace new_assumption = mk_assumption(); justification new_assumption = mk_assumption();
expr imitation; expr imitation;
if (is_app(b)) { if (is_app(b)) {
// Imitation for applications b == f(s_1, ..., s_k) // Imitation for applications b == f(s_1, ..., s_k)
@ -911,8 +911,8 @@ class elaborator::imp {
// See comment at process_metavar_inst // See comment at process_metavar_inst
expr imitation = update_abstraction(b, h_1, h_2); expr imitation = update_abstraction(b, h_1, h_2);
expr ma = mk_metavar(metavar_name(a)); expr ma = mk_metavar(metavar_name(a));
trace new_tr(new imitation_trace(c)); justification new_jst(new imitation_justification(c));
push_new_constraint(true, ctx, ma, imitation, new_tr); push_new_constraint(true, ctx, ma, imitation, new_jst);
return true; return true;
} else { } else {
return false; return false;
@ -934,14 +934,14 @@ class elaborator::imp {
if (is_lower(c)) { if (is_lower(c)) {
// Remark: in principle, there are infinite number of choices. // Remark: in principle, there are infinite number of choices.
// We approximate and only consider the most useful ones. // We approximate and only consider the most useful ones.
trace new_tr(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
unification_constraint new_c; unification_constraint new_c;
if (a == Bool) { if (a == Bool) {
expr choices[5] = { Bool, Type(), Type(level() + 1), TypeM, TypeU }; expr choices[5] = { Bool, Type(), Type(level() + 1), TypeM, TypeU };
new_c = mk_choice_constraint(get_context(c), b, 5, choices, new_tr); new_c = mk_choice_constraint(get_context(c), b, 5, choices, new_jst);
} else { } else {
expr choices[5] = { a, Type(ty_level(a) + 1), Type(ty_level(a) + 2), TypeM, TypeU }; expr choices[5] = { a, Type(ty_level(a) + 1), Type(ty_level(a) + 2), TypeM, TypeU };
new_c = mk_choice_constraint(get_context(c), b, 5, choices, new_tr); new_c = mk_choice_constraint(get_context(c), b, 5, choices, new_jst);
} }
push_front(new_c); push_front(new_c);
return true; return true;
@ -997,17 +997,17 @@ class elaborator::imp {
// and just check if the upper bound is satisfied. // and just check if the upper bound is satisfied.
// //
// Remark: we also give preference to lower bounds // Remark: we also give preference to lower bounds
trace new_tr(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
unification_constraint new_c; unification_constraint new_c;
if (b == Type()) { if (b == Type()) {
expr choices[2] = { Type(), Bool }; expr choices[2] = { Type(), Bool };
new_c = mk_choice_constraint(get_context(c), a, 2, choices, new_tr); new_c = mk_choice_constraint(get_context(c), a, 2, choices, new_jst);
} else if (b == TypeU) { } else if (b == TypeU) {
expr choices[5] = { TypeU, TypeM, Type(level() + 1), Type(), Bool }; expr choices[5] = { TypeU, TypeM, Type(level() + 1), Type(), Bool };
new_c = mk_choice_constraint(get_context(c), a, 5, choices, new_tr); new_c = mk_choice_constraint(get_context(c), a, 5, choices, new_jst);
} else if (b == TypeM) { } else if (b == TypeM) {
expr choices[4] = { TypeM, Type(level() + 1), Type(), Bool }; expr choices[4] = { TypeM, Type(level() + 1), Type(), Bool };
new_c = mk_choice_constraint(get_context(c), a, 4, choices, new_tr); new_c = mk_choice_constraint(get_context(c), a, 4, choices, new_jst);
} else { } else {
level const & lvl = ty_level(b); level const & lvl = ty_level(b);
lean_assert(!lvl.is_bottom()); lean_assert(!lvl.is_bottom());
@ -1026,10 +1026,10 @@ class elaborator::imp {
if (!L.is_bottom()) if (!L.is_bottom())
choices.push_back(Type()); choices.push_back(Type());
choices.push_back(Bool); choices.push_back(Bool);
new_c = mk_choice_constraint(get_context(c), a, choices.size(), choices.data(), new_tr); new_c = mk_choice_constraint(get_context(c), a, choices.size(), choices.data(), new_jst);
} else if (is_uvar(lvl)) { } else if (is_uvar(lvl)) {
expr choices[4] = { Type(level() + 1), Type(), b, Bool }; expr choices[4] = { Type(level() + 1), Type(), b, Bool };
new_c = mk_choice_constraint(get_context(c), a, 4, choices, new_tr); new_c = mk_choice_constraint(get_context(c), a, 4, choices, new_jst);
} else { } else {
lean_assert(is_max(lvl)); lean_assert(is_max(lvl));
// TODO(Leo) // TODO(Leo)
@ -1076,45 +1076,45 @@ class elaborator::imp {
if (a == b) { if (a == b) {
return true; return true;
} else { } else {
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return false; return false;
} }
case expr_kind::Type: case expr_kind::Type:
if ((!eq && m_env.is_ge(ty_level(b), ty_level(a))) || (eq && a == b)) { if ((!eq && m_env.is_ge(ty_level(b), ty_level(a))) || (eq && a == b)) {
return true; return true;
} else { } else {
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return false; return false;
} }
case expr_kind::Eq: { case expr_kind::Eq: {
trace new_trace(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
push_front(mk_eq_constraint(ctx, eq_lhs(a), eq_lhs(b), new_trace)); push_front(mk_eq_constraint(ctx, eq_lhs(a), eq_lhs(b), new_jst));
push_front(mk_eq_constraint(ctx, eq_rhs(a), eq_rhs(b), new_trace)); push_front(mk_eq_constraint(ctx, eq_rhs(a), eq_rhs(b), new_jst));
return true; return true;
} }
case expr_kind::Pi: { case expr_kind::Pi: {
trace new_trace(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
push_front(mk_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_trace)); push_front(mk_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_jst));
context new_ctx = extend(ctx, abst_name(a), abst_domain(a)); context new_ctx = extend(ctx, abst_name(a), abst_domain(a));
if (eq) if (eq)
push_front(mk_eq_constraint(new_ctx, abst_body(a), abst_body(b), new_trace)); push_front(mk_eq_constraint(new_ctx, abst_body(a), abst_body(b), new_jst));
else else
push_front(mk_convertible_constraint(new_ctx, abst_body(a), abst_body(b), new_trace)); push_front(mk_convertible_constraint(new_ctx, abst_body(a), abst_body(b), new_jst));
return true; return true;
} }
case expr_kind::Lambda: { case expr_kind::Lambda: {
trace new_trace(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
push_front(mk_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_trace)); push_front(mk_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_jst));
context new_ctx = extend(ctx, abst_name(a), abst_domain(a)); context new_ctx = extend(ctx, abst_name(a), abst_domain(a));
push_front(mk_eq_constraint(new_ctx, abst_body(a), abst_body(b), new_trace)); push_front(mk_eq_constraint(new_ctx, abst_body(a), abst_body(b), new_jst));
return true; return true;
} }
case expr_kind::App: case expr_kind::App:
if (!is_meta_app(a) && !is_meta_app(b)) { if (!is_meta_app(a) && !is_meta_app(b)) {
if (num_args(a) == num_args(b)) { if (num_args(a) == num_args(b)) {
trace new_trace(new destruct_trace(c)); justification new_jst(new destruct_justification(c));
for (unsigned i = 0; i < num_args(a); i++) for (unsigned i = 0; i < num_args(a); i++)
push_front(mk_eq_constraint(ctx, arg(a, i), arg(b, i), new_trace)); push_front(mk_eq_constraint(ctx, arg(a, i), arg(b, i), new_jst));
return true; return true;
} else { } else {
return false; return false;
@ -1135,7 +1135,7 @@ class elaborator::imp {
} }
if (a.kind() != b.kind() && !has_metavar(a) && !has_metavar(b)) { if (a.kind() != b.kind() && !has_metavar(a) && !has_metavar(b)) {
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return false; return false;
} }
@ -1170,26 +1170,26 @@ class elaborator::imp {
expr const & lhs1 = max_lhs1(c); expr const & lhs1 = max_lhs1(c);
expr const & lhs2 = max_lhs2(c); expr const & lhs2 = max_lhs2(c);
expr const & rhs = max_rhs(c); expr const & rhs = max_rhs(c);
buffer<trace> traces; buffer<justification> jsts;
bool modified = false; bool modified = false;
expr new_lhs1 = lhs1; expr new_lhs1 = lhs1;
expr new_lhs2 = lhs2; expr new_lhs2 = lhs2;
expr new_rhs = rhs; expr new_rhs = rhs;
if (has_assigned_metavar(lhs1)) { if (has_assigned_metavar(lhs1)) {
new_lhs1 = instantiate_metavars(lhs1, traces); new_lhs1 = instantiate_metavars(lhs1, jsts);
modified = true; modified = true;
} }
if (has_assigned_metavar(lhs2)) { if (has_assigned_metavar(lhs2)) {
new_lhs2 = instantiate_metavars(lhs2, traces); new_lhs2 = instantiate_metavars(lhs2, jsts);
modified = true; modified = true;
} }
if (has_assigned_metavar(rhs)) { if (has_assigned_metavar(rhs)) {
new_rhs = instantiate_metavars(rhs, traces); new_rhs = instantiate_metavars(rhs, jsts);
modified = true; modified = true;
} }
if (modified) { if (modified) {
trace new_tr = mk_subst_trace(c, traces); justification new_jst = mk_subst_justification(c, jsts);
push_front(mk_max_constraint(get_context(c), new_lhs1, new_lhs2, new_rhs, new_tr)); push_front(mk_max_constraint(get_context(c), new_lhs1, new_lhs2, new_rhs, new_jst));
return true; return true;
} }
if (!is_metavar(lhs1) && !is_type(lhs1)) { if (!is_metavar(lhs1) && !is_type(lhs1)) {
@ -1205,35 +1205,35 @@ class elaborator::imp {
modified = (rhs != new_rhs); modified = (rhs != new_rhs);
} }
if (modified) { if (modified) {
trace new_tr(new normalize_trace(c)); justification new_jst(new normalize_justification(c));
push_front(mk_max_constraint(get_context(c), new_lhs1, new_lhs2, new_rhs, new_tr)); push_front(mk_max_constraint(get_context(c), new_lhs1, new_lhs2, new_rhs, new_jst));
return true; return true;
} }
if (is_type(lhs1) && is_type(lhs2)) { if (is_type(lhs1) && is_type(lhs2)) {
trace new_tr(new normalize_trace(c)); justification new_jst(new normalize_justification(c));
expr new_lhs = mk_type(max(ty_level(lhs1), ty_level(lhs2))); expr new_lhs = mk_type(max(ty_level(lhs1), ty_level(lhs2)));
push_front(mk_eq_constraint(get_context(c), new_lhs, rhs, new_tr)); push_front(mk_eq_constraint(get_context(c), new_lhs, rhs, new_jst));
return true; return true;
} }
if (lhs1 == rhs) { if (lhs1 == rhs) {
// ctx |- max(lhs1, lhs2) == rhs // ctx |- max(lhs1, lhs2) == rhs
// ==> IF lhs1 = rhs // ==> IF lhs1 = rhs
// ctx |- lhs2 << rhs // ctx |- lhs2 << rhs
trace new_tr(new normalize_trace(c)); justification new_jst(new normalize_justification(c));
push_front(mk_convertible_constraint(get_context(c), lhs2, rhs, new_tr)); push_front(mk_convertible_constraint(get_context(c), lhs2, rhs, new_jst));
return true; return true;
} else if (lhs2 == rhs) { } else if (lhs2 == rhs) {
// ctx |- max(lhs1, lhs2) == rhs // ctx |- max(lhs1, lhs2) == rhs
// ==> IF lhs1 = rhs // ==> IF lhs1 = rhs
// ctx |- lhs2 << rhs // ctx |- lhs2 << rhs
trace new_tr(new normalize_trace(c)); justification new_jst(new normalize_justification(c));
push_front(mk_convertible_constraint(get_context(c), lhs1, rhs, new_tr)); push_front(mk_convertible_constraint(get_context(c), lhs1, rhs, new_jst));
return true; return true;
} }
if ((!has_metavar(lhs1) && !is_type(lhs1)) || if ((!has_metavar(lhs1) && !is_type(lhs1)) ||
(!has_metavar(lhs2) && !is_type(lhs2))) { (!has_metavar(lhs2) && !is_type(lhs2))) {
m_conflict = trace(new unification_failure_trace(c)); m_conflict = justification(new unification_failure_justification(c));
return false; return false;
} }
@ -1261,9 +1261,9 @@ class elaborator::imp {
std::unique_ptr<case_split> & d = m_case_splits.back(); std::unique_ptr<case_split> & d = m_case_splits.back();
// std::cout << "Assumption " << d->m_curr_assumption.pp(fmt, options(), nullptr, true) << "\n"; // std::cout << "Assumption " << d->m_curr_assumption.pp(fmt, options(), nullptr, true) << "\n";
if (depends_on(m_conflict, d->m_curr_assumption)) { if (depends_on(m_conflict, d->m_curr_assumption)) {
d->m_failed_traces.push_back(m_conflict); d->m_failed_justifications.push_back(m_conflict);
if (d->next(*this)) { if (d->next(*this)) {
m_conflict = trace(); m_conflict = justification();
reset_quota(); reset_quota();
return; return;
} }
@ -1283,7 +1283,7 @@ class elaborator::imp {
push_front(mk_eq_constraint(get_context(choice), choice_mvar(choice), choice_ith(choice, idx), s.m_curr_assumption)); push_front(mk_eq_constraint(get_context(choice), choice_mvar(choice), choice_ith(choice, idx), s.m_curr_assumption));
return true; return true;
} else { } else {
m_conflict = trace(new unification_failure_by_cases_trace(choice, s.m_failed_traces.size(), s.m_failed_traces.data())); m_conflict = justification(new unification_failure_by_cases_justification(choice, s.m_failed_justifications.size(), s.m_failed_justifications.data()));
return false; return false;
} }
} }
@ -1297,7 +1297,7 @@ class elaborator::imp {
m_state = s.m_states[sz - idx - 1]; m_state = s.m_states[sz - idx - 1];
return true; return true;
} else { } else {
m_conflict = trace(new unification_failure_by_cases_trace(s.m_constraint, s.m_failed_traces.size(), s.m_failed_traces.data())); m_conflict = justification(new unification_failure_by_cases_justification(s.m_constraint, s.m_failed_justifications.size(), s.m_failed_justifications.data()));
return false; return false;
} }
} }
@ -1313,7 +1313,7 @@ class elaborator::imp {
} }
return true; return true;
} catch (exception & ex) { } catch (exception & ex) {
m_conflict = trace(new unification_failure_by_cases_trace(s.m_constraint, s.m_failed_traces.size(), s.m_failed_traces.data())); m_conflict = justification(new unification_failure_by_cases_justification(s.m_constraint, s.m_failed_justifications.size(), s.m_failed_justifications.data()));
return false; return false;
} }
} }
@ -1340,16 +1340,16 @@ public:
if (m_conflict) if (m_conflict)
throw elaborator_exception(m_conflict); throw elaborator_exception(m_conflict);
if (!m_case_splits.empty()) { if (!m_case_splits.empty()) {
buffer<trace> assumptions; buffer<justification> assumptions;
for (std::unique_ptr<case_split> const & cs : m_case_splits) for (std::unique_ptr<case_split> const & cs : m_case_splits)
assumptions.push_back(cs->m_curr_assumption); assumptions.push_back(cs->m_curr_assumption);
m_conflict = trace(new next_solution_trace(assumptions.size(), assumptions.data())); m_conflict = justification(new next_solution_justification(assumptions.size(), assumptions.data()));
resolve_conflict(); resolve_conflict();
} else if (m_first) { } else if (m_first) {
m_first = false; m_first = false;
} else { } else {
// this is not the first run, and there are no case-splits // this is not the first run, and there are no case-splits
m_conflict = trace(new next_solution_trace(0, nullptr)); m_conflict = justification(new next_solution_justification(0, nullptr));
throw elaborator_exception(m_conflict); throw elaborator_exception(m_conflict);
} }
reset_quota(); reset_quota();
@ -1410,7 +1410,7 @@ elaborator::elaborator(environment const & env,
elaborator::elaborator(environment const & env, elaborator::elaborator(environment const & env,
metavar_env const & menv, metavar_env const & menv,
context const & ctx, expr const & lhs, expr const & rhs): context const & ctx, expr const & lhs, expr const & rhs):
elaborator(env, menv, { mk_eq_constraint(ctx, lhs, rhs, trace()) }) { elaborator(env, menv, { mk_eq_constraint(ctx, lhs, rhs, justification()) }) {
} }
elaborator::~elaborator() { elaborator::~elaborator() {

View file

@ -6,20 +6,20 @@ Author: Leonardo de Moura
*/ */
#pragma once #pragma once
#include "util/exception.h" #include "util/exception.h"
#include "kernel/trace.h" #include "kernel/justification.h"
namespace lean { namespace lean {
/** /**
\brief Elaborator and related components store the reason for \brief Elaborator and related components store the reason for
failure in trace objects. failure in justification objects.
*/ */
class elaborator_exception : public exception { class elaborator_exception : public exception {
trace m_trace; justification m_justification;
public: public:
elaborator_exception(trace const & tr):m_trace(tr) {} elaborator_exception(justification const & j):m_justification(j) {}
virtual ~elaborator_exception() {} virtual ~elaborator_exception() {}
virtual char const * what() const noexcept { return "elaborator exception"; } virtual char const * what() const noexcept { return "elaborator exception"; }
trace const & get_trace() const { return m_trace; } justification const & get_justification() const { return m_justification; }
}; };

View file

@ -0,0 +1,187 @@
/*
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 "library/elaborator/elaborator_justification.h"
namespace lean {
static void push_back(buffer<justification_cell*> & r, justification const & t) {
if (t)
r.push_back(t.raw());
}
template<typename T>
static void append(buffer<justification_cell*> & r, T const & s) {
for (auto t : s)
push_back(r, t);
}
// -------------------------
// Assumptions
// -------------------------
assumption_justification::assumption_justification(unsigned idx):m_idx(idx) {
}
void assumption_justification::get_children(buffer<justification_cell*> &) const {
}
expr const & assumption_justification::get_main_expr() const {
return expr::null();
}
format assumption_justification::pp_header(formatter const &, options const &) const {
return format{format("assumption"), space(), format(m_idx)};
}
// -------------------------
// Propagation justification
// -------------------------
propagation_justification::propagation_justification(unification_constraint const & c):
m_constraint(c) {
}
propagation_justification::~propagation_justification() {
}
void propagation_justification::get_children(buffer<justification_cell*> & r) const {
push_back(r, m_constraint.get_justification());
}
expr const & propagation_justification::get_main_expr() const {
return expr::null();
}
format propagation_justification::pp_header(formatter const & fmt, options const & opts) const {
format r;
r += format(get_prop_name());
r += compose(line(), get_constraint().pp(fmt, opts, nullptr, false));
return r;
}
// -------------------------
// Unification failure (by cases)
// -------------------------
unification_failure_by_cases_justification::unification_failure_by_cases_justification(unification_constraint const & c, unsigned num, justification const * cs):
unification_failure_justification(c),
m_cases(cs, cs + num) {
}
unification_failure_by_cases_justification::~unification_failure_by_cases_justification() {
}
void unification_failure_by_cases_justification::get_children(buffer<justification_cell*> & r) const {
push_back(r, get_constraint().get_justification());
append(r, m_cases);
}
// -------------------------
// Substitution justification
// -------------------------
substitution_justification::substitution_justification(unification_constraint const & c, justification const & t):
propagation_justification(c),
m_assignment_justification(t) {
}
substitution_justification::~substitution_justification() {
}
void substitution_justification::get_children(buffer<justification_cell*> & r) const {
propagation_justification::get_children(r);
push_back(r, m_assignment_justification);
}
multi_substitution_justification::multi_substitution_justification(unification_constraint const & c, unsigned num, justification const * ts):
propagation_justification(c),
m_assignment_justifications(ts, ts + num) {
}
multi_substitution_justification::~multi_substitution_justification() {
}
void multi_substitution_justification::get_children(buffer<justification_cell*> & r) const {
propagation_justification::get_children(r);
append(r, m_assignment_justifications);
}
// -------------------------
// typeof metavar justification
// -------------------------
typeof_mvar_justification::typeof_mvar_justification(context const & ctx, expr const & m, expr const & tm, expr const & t, justification const & tr):
m_context(ctx),
m_mvar(m),
m_typeof_mvar(tm),
m_type(t),
m_justification(tr) {
}
typeof_mvar_justification::~typeof_mvar_justification() {
}
format typeof_mvar_justification::pp_header(formatter const & fmt, options const & opts) const {
format r;
unsigned indent = get_pp_indent(opts);
r += format("Propagate type,");
{
format body;
body += fmt(m_context, m_mvar, false, opts);
body += space();
body += colon();
body += nest(indent, compose(line(), fmt(m_context, m_typeof_mvar, false, opts)));
r += nest(indent, compose(line(), body));
}
return group(r);
}
void typeof_mvar_justification::get_children(buffer<justification_cell*> & r) const {
push_back(r, m_justification);
}
// -------------------------
// Synthesis justification objects
// -------------------------
synthesis_justification::synthesis_justification(context const & ctx, expr const & mvar, expr const & type, unsigned num, justification const * substs):
m_context(ctx),
m_mvar(mvar),
m_type(type),
m_substitution_justifications(substs, substs + num) {
}
synthesis_justification::~synthesis_justification() {
}
format synthesis_justification::pp_header(formatter const & fmt, options const & opts) const {
format r;
r += format(get_label());
r += space();
r += fmt(m_context, m_mvar, false, opts);
unsigned indent = get_pp_indent(opts);
r += nest(indent, compose(line(), fmt(m_context, m_type, true, opts)));
return r;
}
void synthesis_justification::get_children(buffer<justification_cell*> & r) const {
append(r, m_substitution_justifications);
}
expr const & synthesis_justification::get_main_expr() const {
return m_mvar;
}
char const * synthesis_failure_justification::get_label() const {
return "Failed to synthesize expression of type for";
}
synthesis_failure_justification::synthesis_failure_justification(context const & ctx, expr const & mvar, expr const & type, justification const & tr, unsigned num, justification const * substs):
synthesis_justification(ctx, mvar, type, num, substs),
m_justification(tr) {
}
synthesis_failure_justification::~synthesis_failure_justification() {
}
void synthesis_failure_justification::get_children(buffer<justification_cell*> & r) const {
synthesis_justification::get_children(r);
push_back(r, m_justification);
}
char const * synthesized_assignment_justification::get_label() const {
return "Synthesized assignment for";
}
// -------------------------
// Next solution justification
// -------------------------
next_solution_justification::next_solution_justification(unsigned num, justification const * as):
m_assumptions(as, as + num) {
}
next_solution_justification::~next_solution_justification() {
}
format next_solution_justification::pp_header(formatter const &, options const &) const {
return format("next solution");
}
void next_solution_justification::get_children(buffer<justification_cell*> & r) const {
append(r, m_assumptions);
}
expr const & next_solution_justification::get_main_expr() const {
return expr::null();
}
}

View file

@ -0,0 +1,229 @@
/*
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 <vector>
#include "kernel/justification.h"
#include "kernel/unification_constraint.h"
namespace lean {
/**
\brief Base class for justification objects used to justify case-splits.
*/
class assumption_justification : public justification_cell {
unsigned m_idx;
public:
assumption_justification(unsigned idx);
virtual void get_children(buffer<justification_cell*> &) const;
virtual expr const & get_main_expr() const;
virtual format pp_header(formatter const &, options const &) const;
};
/**
\brief Base class for justifying propagations and failures
*/
class propagation_justification : public justification_cell {
unification_constraint m_constraint;
protected:
/** \brief Auxiliary method used by pp_header to label a propagation step, subclasses must redefine it. */
virtual char const * get_prop_name() const = 0;
public:
propagation_justification(unification_constraint const & c);
virtual ~propagation_justification();
virtual void get_children(buffer<justification_cell*> & r) const;
virtual expr const & get_main_expr() const;
virtual format pp_header(formatter const &, options const &) const;
unification_constraint const & get_constraint() const { return m_constraint; }
};
/**
\brief Justification object used to mark that a particular unification constraint could not be solved.
*/
class unification_failure_justification : public propagation_justification {
protected:
virtual char const * get_prop_name() const { return "Failed to solve"; }
public:
unification_failure_justification(unification_constraint const & c):propagation_justification(c) {}
};
/**
\brief Justification object created for justifying that a constraint that
generated a case-split does not have a solution. Each case-split
corresponds to a different way of solving the constraint.
*/
class unification_failure_by_cases_justification : public unification_failure_justification {
std::vector<justification> m_cases; // why each case failed
public:
unification_failure_by_cases_justification(unification_constraint const & c, unsigned num, justification const * cs);
virtual ~unification_failure_by_cases_justification();
virtual void get_children(buffer<justification_cell*> & r) const;
};
/**
\brief Justification object used to justify a metavar assignment.
*/
class assignment_justification : public propagation_justification {
protected:
virtual char const * get_prop_name() const { return "Assignment"; }
public:
assignment_justification(unification_constraint const & c):propagation_justification(c) {}
};
/**
\brief Justification object used to justify simple structural steps when processing unification
constraints. For example, given the constraint
<tt>ctx |- (f a) == (f b)</tt>
where \c f is a variable, we must have
<tt>ctx |- a == b</tt>
The justification for the latter is a destruct justification based on the former.
*/
class destruct_justification : public propagation_justification {
protected:
virtual char const * get_prop_name() const { return "Destruct/Decompose"; }
public:
destruct_justification(unification_constraint const & c):propagation_justification(c) {}
};
/**
\brief Justification object used to justify a normalization step such as.
<tt>ctx |- (fun x : T, x) a == b</tt>
==>
<tt>ctx |- a == b</tt>
*/
class normalize_justification : public propagation_justification {
protected:
virtual char const * get_prop_name() const { return "Normalize"; }
public:
normalize_justification(unification_constraint const & c):propagation_justification(c) {}
};
/**
\brief Justification object used to justify an imitation step.
An imitation step is used when solving constraints such as:
<tt>ctx |- ?m[lift:s:n, ...] == Pi (x : A), B x</tt>
In this case, ?m must be a Pi. We make progress, by adding the constraint
<tt>ctx |- ?m == Pi (x : ?M1), (?M2 x)</tt>
where ?M1 and ?M2 are fresh metavariables.
*/
class imitation_justification : public propagation_justification {
protected:
virtual char const * get_prop_name() const { return "Imitation"; }
public:
imitation_justification(unification_constraint const & c):propagation_justification(c) {}
};
/**
\brief Justification object used to justify a new constraint obtained by substitution.
*/
class substitution_justification : public propagation_justification {
justification m_assignment_justification;
protected:
virtual char const * get_prop_name() const { return "Substitution"; }
public:
substitution_justification(unification_constraint const & c, justification const & t);
virtual ~substitution_justification();
virtual void get_children(buffer<justification_cell*> & r) const;
};
/**
\brief Justification object used to justify a new constraint obtained by multiple substitution.
*/
class multi_substitution_justification : public propagation_justification {
std::vector<justification> m_assignment_justifications;
protected:
virtual char const * get_prop_name() const { return "Substitution"; }
public:
multi_substitution_justification(unification_constraint const & c, unsigned num, justification const * ts);
virtual ~multi_substitution_justification();
virtual void get_children(buffer<justification_cell*> & r) const;
};
/**
\brief Justification object used to justify a <tt>typeof(m) == t</tt> constraint generated when
we assign a metavariable \c m.
*/
class typeof_mvar_justification : public justification_cell {
context m_context;
expr m_mvar;
expr m_typeof_mvar;
expr m_type;
justification m_justification;
public:
typeof_mvar_justification(context const & ctx, expr const & m, expr const & mt, expr const & t, justification const & tr);
virtual ~typeof_mvar_justification();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<justification_cell*> & r) const;
};
/**
\brief Base class for synthesis_failure_justification and synthesized_assignment_justification
*/
class synthesis_justification : public justification_cell {
context m_context;
expr m_mvar;
expr m_type;
std::vector<justification> m_substitution_justifications; // justification objects justifying the assignments used to instantiate \c m_type and \c m_context.
protected:
virtual char const * get_label() const = 0;
public:
synthesis_justification(context const & ctx, expr const & mvar, expr const & type, unsigned num, justification const * substs);
virtual ~synthesis_justification();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<justification_cell*> & r) const;
virtual expr const & get_main_expr() const;
};
/**
\brief Justification object for justifying why a synthesis step failed.
A synthesis step is of the form
<tt>ctx |- ?mvar : type</tt>
Before invoking the synthesizer, the elaborator substitutes the
metavariables in \c ctx and \c type with their corresponding assignments.
*/
class synthesis_failure_justification : public synthesis_justification {
justification m_justification; // justification object produced by the synthesizer
protected:
virtual char const * get_label() const;
public:
synthesis_failure_justification(context const & ctx, expr const & mvar, expr const & type, justification const & tr, unsigned num, justification const * substs);
virtual ~synthesis_failure_justification();
virtual void get_children(buffer<justification_cell*> & r) const;
};
/**
\brief Justification object used to justify a metavar assignment produced by a synthesizer.
*/
class synthesized_assignment_justification : public synthesis_justification {
protected:
virtual char const * get_label() const;
public:
synthesized_assignment_justification(context const & ctx, expr const & mvar, expr const & type, unsigned num, justification const * substs):
synthesis_justification(ctx, mvar, type, num, substs) {
}
};
/**
\brief Justification object used to justify that we are moving to the next solution.
*/
class next_solution_justification : public justification_cell {
std::vector<justification> m_assumptions; // Set of assumptions used to derive last solution
public:
next_solution_justification(unsigned num, justification const * as);
virtual ~next_solution_justification();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<justification_cell*> & r) const;
virtual expr const & get_main_expr() const;
};
};

View file

@ -27,7 +27,7 @@ public:
Each result is represented by a pair: the new metavariable Each result is represented by a pair: the new metavariable
environment and a new list of constraints to be solved. environment and a new list of constraints to be solved.
*/ */
virtual std::pair<metavar_env, list<unification_constraint>> next(trace const & assumption) = 0; virtual std::pair<metavar_env, list<unification_constraint>> next(justification const & assumption) = 0;
/** \brief Interrupt the computation for the next solution. */ /** \brief Interrupt the computation for the next solution. */
virtual void interrupt() = 0; virtual void interrupt() = 0;
}; };

View file

@ -1,187 +0,0 @@
/*
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 "library/elaborator/elaborator_trace.h"
namespace lean {
static void push_back(buffer<trace_cell*> & r, trace const & t) {
if (t)
r.push_back(t.raw());
}
template<typename T>
static void append(buffer<trace_cell*> & r, T const & s) {
for (auto t : s)
push_back(r, t);
}
// -------------------------
// Assumptions
// -------------------------
assumption_trace::assumption_trace(unsigned idx):m_idx(idx) {
}
void assumption_trace::get_children(buffer<trace_cell*> &) const {
}
expr const & assumption_trace::get_main_expr() const {
return expr::null();
}
format assumption_trace::pp_header(formatter const &, options const &) const {
return format{format("assumption"), space(), format(m_idx)};
}
// -------------------------
// Propagation trace
// -------------------------
propagation_trace::propagation_trace(unification_constraint const & c):
m_constraint(c) {
}
propagation_trace::~propagation_trace() {
}
void propagation_trace::get_children(buffer<trace_cell*> & r) const {
push_back(r, m_constraint.get_trace());
}
expr const & propagation_trace::get_main_expr() const {
return expr::null();
}
format propagation_trace::pp_header(formatter const & fmt, options const & opts) const {
format r;
r += format(get_prop_name());
r += compose(line(), get_constraint().pp(fmt, opts, nullptr, false));
return r;
}
// -------------------------
// Unification failure (by cases)
// -------------------------
unification_failure_by_cases_trace::unification_failure_by_cases_trace(unification_constraint const & c, unsigned num, trace const * cs):
unification_failure_trace(c),
m_cases(cs, cs + num) {
}
unification_failure_by_cases_trace::~unification_failure_by_cases_trace() {
}
void unification_failure_by_cases_trace::get_children(buffer<trace_cell*> & r) const {
push_back(r, get_constraint().get_trace());
append(r, m_cases);
}
// -------------------------
// Substitution trace
// -------------------------
substitution_trace::substitution_trace(unification_constraint const & c, trace const & t):
propagation_trace(c),
m_assignment_trace(t) {
}
substitution_trace::~substitution_trace() {
}
void substitution_trace::get_children(buffer<trace_cell*> & r) const {
propagation_trace::get_children(r);
push_back(r, m_assignment_trace);
}
multi_substitution_trace::multi_substitution_trace(unification_constraint const & c, unsigned num, trace const * ts):
propagation_trace(c),
m_assignment_traces(ts, ts + num) {
}
multi_substitution_trace::~multi_substitution_trace() {
}
void multi_substitution_trace::get_children(buffer<trace_cell*> & r) const {
propagation_trace::get_children(r);
append(r, m_assignment_traces);
}
// -------------------------
// typeof metavar trace
// -------------------------
typeof_mvar_trace::typeof_mvar_trace(context const & ctx, expr const & m, expr const & tm, expr const & t, trace const & tr):
m_context(ctx),
m_mvar(m),
m_typeof_mvar(tm),
m_type(t),
m_trace(tr) {
}
typeof_mvar_trace::~typeof_mvar_trace() {
}
format typeof_mvar_trace::pp_header(formatter const & fmt, options const & opts) const {
format r;
unsigned indent = get_pp_indent(opts);
r += format("Propagate type,");
{
format body;
body += fmt(m_context, m_mvar, false, opts);
body += space();
body += colon();
body += nest(indent, compose(line(), fmt(m_context, m_typeof_mvar, false, opts)));
r += nest(indent, compose(line(), body));
}
return group(r);
}
void typeof_mvar_trace::get_children(buffer<trace_cell*> & r) const {
push_back(r, m_trace);
}
// -------------------------
// Synthesis trace objects
// -------------------------
synthesis_trace::synthesis_trace(context const & ctx, expr const & mvar, expr const & type, unsigned num, trace const * substs):
m_context(ctx),
m_mvar(mvar),
m_type(type),
m_substitution_traces(substs, substs + num) {
}
synthesis_trace::~synthesis_trace() {
}
format synthesis_trace::pp_header(formatter const & fmt, options const & opts) const {
format r;
r += format(get_label());
r += space();
r += fmt(m_context, m_mvar, false, opts);
unsigned indent = get_pp_indent(opts);
r += nest(indent, compose(line(), fmt(m_context, m_type, true, opts)));
return r;
}
void synthesis_trace::get_children(buffer<trace_cell*> & r) const {
append(r, m_substitution_traces);
}
expr const & synthesis_trace::get_main_expr() const {
return m_mvar;
}
char const * synthesis_failure_trace::get_label() const {
return "Failed to synthesize expression of type for";
}
synthesis_failure_trace::synthesis_failure_trace(context const & ctx, expr const & mvar, expr const & type, trace const & tr, unsigned num, trace const * substs):
synthesis_trace(ctx, mvar, type, num, substs),
m_trace(tr) {
}
synthesis_failure_trace::~synthesis_failure_trace() {
}
void synthesis_failure_trace::get_children(buffer<trace_cell*> & r) const {
synthesis_trace::get_children(r);
push_back(r, m_trace);
}
char const * synthesized_assignment_trace::get_label() const {
return "Synthesized assignment for";
}
// -------------------------
// Next solution trace
// -------------------------
next_solution_trace::next_solution_trace(unsigned num, trace const * as):
m_assumptions(as, as + num) {
}
next_solution_trace::~next_solution_trace() {
}
format next_solution_trace::pp_header(formatter const &, options const &) const {
return format("next solution");
}
void next_solution_trace::get_children(buffer<trace_cell*> & r) const {
append(r, m_assumptions);
}
expr const & next_solution_trace::get_main_expr() const {
return expr::null();
}
}

View file

@ -1,229 +0,0 @@
/*
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 <vector>
#include "kernel/trace.h"
#include "kernel/unification_constraint.h"
namespace lean {
/**
\brief Base class for trace objects used to justify case-splits.
*/
class assumption_trace : public trace_cell {
unsigned m_idx;
public:
assumption_trace(unsigned idx);
virtual void get_children(buffer<trace_cell*> &) const;
virtual expr const & get_main_expr() const;
virtual format pp_header(formatter const &, options const &) const;
};
/**
\brief Base class for justifying propagations and failures
*/
class propagation_trace : public trace_cell {
unification_constraint m_constraint;
protected:
/** \brief Auxiliary method used by pp_header to label a propagation step, subclasses must redefine it. */
virtual char const * get_prop_name() const = 0;
public:
propagation_trace(unification_constraint const & c);
virtual ~propagation_trace();
virtual void get_children(buffer<trace_cell*> & r) const;
virtual expr const & get_main_expr() const;
virtual format pp_header(formatter const &, options const &) const;
unification_constraint const & get_constraint() const { return m_constraint; }
};
/**
\brief Trace object used to mark that a particular unification constraint could not be solved.
*/
class unification_failure_trace : public propagation_trace {
protected:
virtual char const * get_prop_name() const { return "Failed to solve"; }
public:
unification_failure_trace(unification_constraint const & c):propagation_trace(c) {}
};
/**
\brief Trace object created for justifying that a constraint that
generated a case-split does not have a solution. Each case-split
corresponds to a different way of solving the constraint.
*/
class unification_failure_by_cases_trace : public unification_failure_trace {
std::vector<trace> m_cases; // why each case failed
public:
unification_failure_by_cases_trace(unification_constraint const & c, unsigned num, trace const * cs);
virtual ~unification_failure_by_cases_trace();
virtual void get_children(buffer<trace_cell*> & r) const;
};
/**
\brief Trace object used to justify a metavar assignment.
*/
class assignment_trace : public propagation_trace {
protected:
virtual char const * get_prop_name() const { return "Assignment"; }
public:
assignment_trace(unification_constraint const & c):propagation_trace(c) {}
};
/**
\brief Trace object used to justify simple structural steps when processing unification
constraints. For example, given the constraint
<tt>ctx |- (f a) == (f b)</tt>
where \c f is a variable, we must have
<tt>ctx |- a == b</tt>
The justification for the latter is a destruct trace based on the former.
*/
class destruct_trace : public propagation_trace {
protected:
virtual char const * get_prop_name() const { return "Destruct/Decompose"; }
public:
destruct_trace(unification_constraint const & c):propagation_trace(c) {}
};
/**
\brief Trace object used to justify a normalization step such as.
<tt>ctx |- (fun x : T, x) a == b</tt>
==>
<tt>ctx |- a == b</tt>
*/
class normalize_trace : public propagation_trace {
protected:
virtual char const * get_prop_name() const { return "Normalize"; }
public:
normalize_trace(unification_constraint const & c):propagation_trace(c) {}
};
/**
\brief Trace object used to justify an imitation step.
An imitation step is used when solving constraints such as:
<tt>ctx |- ?m[lift:s:n, ...] == Pi (x : A), B x</tt>
In this case, ?m must be a Pi. We make progress, by adding the constraint
<tt>ctx |- ?m == Pi (x : ?M1), (?M2 x)</tt>
where ?M1 and ?M2 are fresh metavariables.
*/
class imitation_trace : public propagation_trace {
protected:
virtual char const * get_prop_name() const { return "Imitation"; }
public:
imitation_trace(unification_constraint const & c):propagation_trace(c) {}
};
/**
\brief Trace object used to justify a new constraint obtained by substitution.
*/
class substitution_trace : public propagation_trace {
trace m_assignment_trace;
protected:
virtual char const * get_prop_name() const { return "Substitution"; }
public:
substitution_trace(unification_constraint const & c, trace const & t);
virtual ~substitution_trace();
virtual void get_children(buffer<trace_cell*> & r) const;
};
/**
\brief Trace object used to justify a new constraint obtained by multiple substitution.
*/
class multi_substitution_trace : public propagation_trace {
std::vector<trace> m_assignment_traces;
protected:
virtual char const * get_prop_name() const { return "Substitution"; }
public:
multi_substitution_trace(unification_constraint const & c, unsigned num, trace const * ts);
virtual ~multi_substitution_trace();
virtual void get_children(buffer<trace_cell*> & r) const;
};
/**
\brief Trace object used to justify a <tt>typeof(m) == t</tt> constraint generated when
we assign a metavariable \c m.
*/
class typeof_mvar_trace : public trace_cell {
context m_context;
expr m_mvar;
expr m_typeof_mvar;
expr m_type;
trace m_trace;
public:
typeof_mvar_trace(context const & ctx, expr const & m, expr const & mt, expr const & t, trace const & tr);
virtual ~typeof_mvar_trace();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<trace_cell*> & r) const;
};
/**
\brief Base class for synthesis_failure_trace and synthesized_assignment_trace
*/
class synthesis_trace : public trace_cell {
context m_context;
expr m_mvar;
expr m_type;
std::vector<trace> m_substitution_traces; // trace objects justifying the assignments used to instantiate \c m_type and \c m_context.
protected:
virtual char const * get_label() const = 0;
public:
synthesis_trace(context const & ctx, expr const & mvar, expr const & type, unsigned num, trace const * substs);
virtual ~synthesis_trace();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<trace_cell*> & r) const;
virtual expr const & get_main_expr() const;
};
/**
\brief Trace object for justifying why a synthesis step failed.
A synthesis step is of the form
<tt>ctx |- ?mvar : type</tt>
Before invoking the synthesizer, the elaborator substitutes the
metavariables in \c ctx and \c type with their corresponding assignments.
*/
class synthesis_failure_trace : public synthesis_trace {
trace m_trace; // trace object produced by the synthesizer
protected:
virtual char const * get_label() const;
public:
synthesis_failure_trace(context const & ctx, expr const & mvar, expr const & type, trace const & tr, unsigned num, trace const * substs);
virtual ~synthesis_failure_trace();
virtual void get_children(buffer<trace_cell*> & r) const;
};
/**
\brief Trace object used to justify a metavar assignment produced by a synthesizer.
*/
class synthesized_assignment_trace : public synthesis_trace {
protected:
virtual char const * get_label() const;
public:
synthesized_assignment_trace(context const & ctx, expr const & mvar, expr const & type, unsigned num, trace const * substs):
synthesis_trace(ctx, mvar, type, num, substs) {
}
};
/**
\brief Trace object used to justify that we are moving to the next solution.
*/
class next_solution_trace : public trace_cell {
std::vector<trace> m_assumptions; // Set of assumptions used to derive last solution
public:
next_solution_trace(unsigned num, trace const * as);
virtual ~next_solution_trace();
virtual format pp_header(formatter const &, options const &) const;
virtual void get_children(buffer<trace_cell*> & r) const;
virtual expr const & get_main_expr() const;
};
};

View file

@ -10,7 +10,7 @@ Author: Leonardo de Moura
#include "kernel/normalizer.h" #include "kernel/normalizer.h"
#include "kernel/builtin.h" #include "kernel/builtin.h"
#include "kernel/kernel_exception.h" #include "kernel/kernel_exception.h"
#include "kernel/type_checker_trace.h" #include "kernel/type_checker_justification.h"
#include "kernel/instantiate.h" #include "kernel/instantiate.h"
#include "kernel/free_vars.h" #include "kernel/free_vars.h"
#include "kernel/metavar.h" #include "kernel/metavar.h"
@ -47,8 +47,8 @@ class type_inferer::imp {
if (u == Bool) if (u == Bool)
return Type(); return Type();
if (has_metavar(u) && m_menv) { if (has_metavar(u) && m_menv) {
trace tr = mk_type_expected_trace(ctx, s); justification jst = mk_type_expected_justification(ctx, s);
m_uc->push_back(mk_convertible_constraint(ctx, u, TypeU, tr)); m_uc->push_back(mk_convertible_constraint(ctx, u, TypeU, jst));
return u; return u;
} }
throw type_expected_exception(m_env, ctx, s); throw type_expected_exception(m_env, ctx, s);
@ -70,8 +70,8 @@ class type_inferer::imp {
expr A = m_menv->mk_metavar(ctx); expr A = m_menv->mk_metavar(ctx);
expr B = m_menv->mk_metavar(ctx); 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)));
trace tr = mk_function_expected_trace(ctx, e); justification jst = mk_function_expected_justification(ctx, e);
m_uc->push_back(mk_eq_constraint(ctx, t, p, tr)); m_uc->push_back(mk_eq_constraint(ctx, t, p, jst));
t = abst_body(p); t = abst_body(p);
} else { } else {
throw function_expected_exception(m_env, ctx, e); throw function_expected_exception(m_env, ctx, e);
@ -186,9 +186,9 @@ class type_inferer::imp {
r = mk_type(max(ty_level(t1), ty_level(t2))); r = mk_type(max(ty_level(t1), ty_level(t2)));
} else { } else {
lean_assert(m_uc); lean_assert(m_uc);
trace tr = mk_max_type_trace(ctx, e); justification jst = mk_max_type_justification(ctx, e);
r = m_menv->mk_metavar(ctx); r = m_menv->mk_metavar(ctx);
m_uc->push_back(mk_max_constraint(ctx, t1, t2, r, tr)); m_uc->push_back(mk_max_constraint(ctx, t1, t2, r, jst));
} }
break; break;
} }

View file

@ -18,7 +18,7 @@ Author: Leonardo de Moura
#include "kernel/normalizer.h" #include "kernel/normalizer.h"
#include "kernel/printer.h" #include "kernel/printer.h"
#include "kernel/kernel_exception.h" #include "kernel/kernel_exception.h"
#include "kernel/type_checker_trace.h" #include "kernel/type_checker_justification.h"
#include "library/basic_thms.h" #include "library/basic_thms.h"
#include "library/arith/arith.h" #include "library/arith/arith.h"
#include "library/all/all.h" #include "library/all/all.h"
@ -297,7 +297,7 @@ static void tst15() {
lean_assert(is_eqp(r, checker.infer_type(F, ctx1))); lean_assert(is_eqp(r, checker.infer_type(F, ctx1)));
} }
static void check_trace_msg(trace const & t, char const * expected) { static void check_justification_msg(justification const & t, char const * expected) {
formatter fmt = mk_simple_formatter(); formatter fmt = mk_simple_formatter();
options opts; options opts;
opts = opts.update({"pp", "indent"}, 2); opts = opts.update({"pp", "indent"}, 2);
@ -309,18 +309,18 @@ static void check_trace_msg(trace const & t, char const * expected) {
} }
static void tst16() { static void tst16() {
std::cout << "Testing type checker trace objects\n"; std::cout << "Testing type checker justification objects\n";
context ctx; context ctx;
expr f = Const("f"); expr f = Const("f");
expr a = Const("a"); expr a = Const("a");
expr x = Var(0); expr x = Var(0);
ctx = extend(ctx, "x", Const("N")); ctx = extend(ctx, "x", Const("N"));
check_trace_msg(mk_function_expected_trace(ctx, f(a, x)), "Function expected at\n f a x"); check_justification_msg(mk_function_expected_justification(ctx, f(a, x)), "Function expected at\n f a x");
check_trace_msg(mk_type_expected_trace(ctx, Pi({a, Const("N")}, Var(1))), "Type expected at\n N -> x"); check_justification_msg(mk_type_expected_justification(ctx, Pi({a, Const("N")}, Var(1))), "Type expected at\n N -> x");
check_trace_msg(mk_type_expected_trace(ctx, Pi({a, Const("N")}, Var(1)(a))), "Type expected at\n Pi a : N, (x a)"); check_justification_msg(mk_type_expected_justification(ctx, Pi({a, Const("N")}, Var(1)(a))), "Type expected at\n Pi a : N, (x a)");
check_trace_msg(mk_app_type_match_trace(ctx, f(a, x), 1), "Type of argument 1 must be convertible to the expected type in the application of\n f\nwith arguments:\n a\n x"); check_justification_msg(mk_app_type_match_justification(ctx, f(a, x), 1), "Type of argument 1 must be convertible to the expected type in the application of\n f\nwith arguments:\n a\n x");
check_trace_msg(mk_max_type_trace(ctx, Pi({a, Const("N")}, Var(1))), "Type expected at\n N -> x"); check_justification_msg(mk_max_type_justification(ctx, Pi({a, Const("N")}, Var(1))), "Type expected at\n N -> x");
check_trace_msg(mk_def_type_match_trace(ctx, "foo", f(a, x)), "Type of definition 'foo' must be convertible to expected type."); check_justification_msg(mk_def_type_match_justification(ctx, "foo", f(a, x)), "Type of definition 'foo' must be convertible to expected type.");
} }
int main() { int main() {

View file

@ -51,9 +51,9 @@ static void tst1() {
std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n"; std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n";
expr int_id = Fun({a, Int}, a); expr int_id = Fun({a, Int}, a);
expr nat_id = Fun({a, Nat}, a); expr nat_id = Fun({a, Nat}, a);
ucs.push_back(mk_choice_constraint(context(), m1, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m1, { int_id, mk_int_to_real_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m2, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m2, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m3, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m3, { int_id, mk_int_to_real_fn() }, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
} }
@ -93,9 +93,9 @@ static void tst2() {
expr F = m1(g(m2, m3(a)), m4(nVal(0))); expr F = m1(g(m2, m3(a)), m4(nVal(0)));
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n"; std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n";
ucs.push_back(mk_choice_constraint(context(), m1, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m1, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m3, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m3, { int_id, mk_int_to_real_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m4, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m4, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
} }
@ -136,9 +136,9 @@ static void tst3() {
expr F = Fun({x, m1}, m2(f(m3, x), m4(nVal(10))))(m5(a)); expr F = Fun({x, m1}, m2(f(m3, x), m4(nVal(10))))(m5(a));
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n"; std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n";
ucs.push_back(mk_choice_constraint(context(), m2, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m2, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m4, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m4, { nat_id, mk_nat_to_int_fn(), mk_nat_to_real_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m5, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m5, { int_id, mk_int_to_real_fn() }, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
} }
@ -181,8 +181,8 @@ static void tst4() {
expr F = Fun({{x, m1}, {y, m2}}, m3(f(m4, x), f(m5, y)))(m6(a), b); expr F = Fun({{x, m1}, {y, m2}}, m3(f(m4, x), f(m5, y)))(m6(a), b);
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n"; std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n";
ucs.push_back(mk_choice_constraint(context(), m3, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m3, { mk_nat_le_fn(), mk_int_le_fn(), mk_real_le_fn() }, justification()));
ucs.push_back(mk_choice_constraint(context(), m6, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m6, { int_id, mk_int_to_real_fn() }, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
} }
@ -223,7 +223,7 @@ static void tst5() {
expr F = Fun({{x, m1}, {y, m2}}, f(m3, x, y))(m4(a), b); expr F = Fun({{x, m1}, {y, m2}}, f(m3, x, y))(m4(a), b);
std::cout << F << "\n"; std::cout << F << "\n";
std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n"; std::cout << checker.infer_type(F, context(), &menv, ucs) << "\n";
ucs.push_back(mk_choice_constraint(context(), m4, { int_id, mk_int_to_real_fn() }, trace())); ucs.push_back(mk_choice_constraint(context(), m4, { int_id, mk_int_to_real_fn() }, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
} }
@ -260,7 +260,7 @@ static void tst6() {
expr V = Subst(m1, m2, m3, m4, H1, H2); expr V = Subst(m1, m2, m3, m4, H1, H2);
expr expected = Eq(f(a, f(b, b)), a); expr expected = Eq(f(a, f(b, b)), a);
expr given = checker.infer_type(V, context(), &menv, ucs); expr given = checker.infer_type(V, context(), &menv, ucs);
ucs.push_back(mk_eq_constraint(context(), expected, given, trace())); ucs.push_back(mk_eq_constraint(context(), expected, given, justification()));
elaborator elb(env, menv, ucs.size(), ucs.data()); elaborator elb(env, menv, ucs.size(), ucs.data());
substitution s = elb.next(); substitution s = elb.next();
std::cout << beta_reduce(instantiate_metavars(V, s)) << "\n"; std::cout << beta_reduce(instantiate_metavars(V, s)) << "\n";