refactor(library/class_instance_resolution): use new generic type_inference module to implement type class resolution

This commit is contained in:
Leonardo de Moura 2015-10-20 10:03:26 -07:00
parent 73543f1279
commit 0446c43ebf
3 changed files with 139 additions and 541 deletions

View file

@ -22,6 +22,7 @@ Author: Leonardo de Moura
#include "library/constants.h"
#include "library/pp_options.h"
#include "library/choice_iterator.h"
#include "library/type_inference.h"
#include "library/class_instance_resolution.h"
#ifndef LEAN_DEFAULT_CLASS_TRACE_INSTANCES
@ -40,18 +41,13 @@ namespace lean {
[[ noreturn ]] void throw_class_exception(char const * msg, expr const & m) { throw_generic_exception(msg, m); }
[[ noreturn ]] void throw_class_exception(expr const & m, pp_fn const & fn) { throw_generic_exception(m, fn); }
typedef std::shared_ptr<ci_type_inference> ci_type_inference_ptr;
static name * g_class_trace_instances = nullptr;
static name * g_class_instance_max_depth = nullptr;
static name * g_class_trans_instances = nullptr;
static name * g_prefix1 = nullptr;
static name * g_prefix2 = nullptr;
static name * g_prefix = nullptr;
static ci_type_inference_factory * g_default_factory = nullptr;
LEAN_THREAD_PTR(ci_type_inference_factory, g_factory);
LEAN_THREAD_PTR(io_state, g_ios);
LEAN_THREAD_PTR(ci_local_metavar_types, g_lm_types);
LEAN_THREAD_PTR(io_state, g_ios);
bool get_class_trace_instances(options const & o) {
return o.get_bool(*g_class_trace_instances, LEAN_DEFAULT_CLASS_TRACE_INSTANCES);
@ -65,31 +61,18 @@ bool get_class_trans_instances(options const & o) {
return o.get_bool(*g_class_trans_instances, LEAN_DEFAULT_CLASS_TRANS_INSTANCES);
}
class default_ci_type_inference : public ci_type_inference {
type_checker_ptr m_tc;
class default_ci_local_metavar_types : public ci_local_metavar_types {
public:
default_ci_type_inference(environment const & env):
m_tc(mk_type_checker(env, name_generator(*g_prefix1), UnfoldReducible)) {}
virtual ~default_ci_type_inference() {}
virtual expr whnf(expr const & e) {
return m_tc->whnf(e).first;
}
virtual expr infer_type(expr const & e) {
return m_tc->infer(e).first;
}
virtual expr infer_local(expr const & e) { return mlocal_type(e); }
virtual expr infer_metavar(expr const & e) { return mlocal_type(e); }
};
ci_type_inference_factory::~ci_type_inference_factory() {}
std::shared_ptr<ci_type_inference> ci_type_inference_factory::operator()(environment const & env) const {
return std::shared_ptr<ci_type_inference>(new default_ci_type_inference(env));
static expr ci_infer_local(expr const & e) {
return g_lm_types->infer_local(e);
}
static ci_type_inference_factory & get_ci_factory() {
return g_factory ? *g_factory : *g_default_factory;
static expr ci_infer_metavar(expr const & e) {
return g_lm_types->infer_metavar(e);
}
/** \brief The following global thread local constant is a big hack for mk_subsingleton_instance.
@ -114,11 +97,11 @@ LEAN_THREAD_VALUE(bool, g_subsingleton_hack, false);
struct cienv {
typedef rb_map<unsigned, level, unsigned_cmp> uassignment;
typedef rb_map<unsigned, expr, unsigned_cmp> eassignment;
typedef std::unique_ptr<type_inference> ti_ptr;
environment m_env;
pos_info_provider const * m_pip;
ti_ptr m_ti_ptr;
optional<pos_info> m_pos;
ci_type_inference_ptr m_tc_ptr;
expr_struct_map<expr> m_cache;
name_predicate m_not_reducible_pred;
@ -157,6 +140,69 @@ struct cienv {
bool m_trans_instances;
bool m_trace_instances;
class ti : public type_inference {
cienv & m_cienv;
std::vector<state> m_stack;
public:
ti(cienv & e):type_inference(e.m_env), m_cienv(e) {}
virtual bool is_extra_opaque(name const & n) const { return m_cienv.is_not_reducible(n); }
virtual expr mk_tmp_local(expr const & type, binder_info const & bi) { return m_cienv.mk_local(type, bi); }
virtual bool is_tmp_local(expr const & e) const { return m_cienv.is_internal_local(e); }
virtual bool is_uvar(level const & l) const { return cienv::is_uvar(l); }
virtual bool is_mvar(expr const & e) const { return m_cienv.is_mvar(e); }
virtual level const * get_assignment(level const & u) const { return m_cienv.get_assignment(u); }
virtual expr const * get_assignment(expr const & m) const { return m_cienv.get_assignment(m); }
virtual void update_assignment(level const & u, level const & v) { return m_cienv.update_assignment(u, v); }
virtual void update_assignment(expr const & m, expr const & v) { return m_cienv.update_assignment(m, v); }
virtual expr infer_local(expr const & e) const { return ci_infer_local(e); }
virtual expr infer_metavar(expr const & e) const { return ci_infer_metavar(e); }
virtual void push() { m_stack.push_back(m_cienv.m_state); }
virtual void pop() { m_cienv.m_state = m_stack.back(); m_stack.pop_back(); }
virtual void commit() { m_stack.pop_back(); }
virtual bool ignore_universe_def_eq(level const & l1, level const & l2) const {
if (is_meta(l1) || is_meta(l2)) {
// The unifier may invoke this module before universe metavariables in the class
// have been instantiated. So, we just ignore and assume they will be solved by
// the unifier.
// See comment at g_subsingleton_hack declaration.
if (g_subsingleton_hack && (is_zero(l1) || is_zero(l2)))
return false;
return true; // we ignore
} else {
return false;
}
}
virtual bool validate_assignment(expr const & m, buffer<expr> const & locals, expr const & v) {
// We must check
// 1. Any (internal) local constant occurring in v occurs in locals
// 2. m does not occur in v
bool ok = true;
for_each(v, [&](expr const & e, unsigned) {
if (!ok)
return false; // stop search
if (is_tmp_local(e)) {
if (std::all_of(locals.begin(), locals.end(), [&](expr const & a) {
return mlocal_name(a) != mlocal_name(e); })) {
ok = false; // failed 1
return false;
}
} else if (is_mvar(e)) {
if (m == e) {
ok = false; // failed 2
return false;
}
return false;
}
return true;
});
return ok;
}
};
cienv(bool multiple_instances = false):
m_next_local_idx(0),
m_next_uvar_idx(0),
@ -167,18 +213,20 @@ struct cienv {
return m_not_reducible_pred(n);
}
void reset_cache() {
void clear_cache() {
expr_struct_map<expr> fresh;
fresh.swap(m_cache);
if (m_ti_ptr)
m_ti_ptr->clear_cache();
}
void reset_cache_and_ctx() {
void clear_cache_and_ctx() {
m_next_local_idx = 0;
m_next_uvar_idx = 0;
m_next_mvar_idx = 0;
m_ctx = list<expr>();
m_local_instances.clear();
reset_cache();
clear_cache();
}
optional<expr> check_cache(expr const & type) const {
@ -214,7 +262,7 @@ struct cienv {
if (m_max_depth != max_depth ||
m_trans_instances != trans_instances ||
m_trace_instances != trace_instances) {
reset_cache_and_ctx();
clear_cache_and_ctx();
}
m_max_depth = max_depth;
m_trans_instances = trans_instances;
@ -228,44 +276,44 @@ struct cienv {
if (!m_env.is_descendant(m_env) || !m_env.is_descendant(env)) {
m_env = env;
m_not_reducible_pred = mk_not_reducible_pred(m_env);
m_tc_ptr = nullptr;
reset_cache_and_ctx();
m_ti_ptr = nullptr;
clear_cache_and_ctx();
}
if (!m_tc_ptr) {
ci_type_inference_factory & factory = get_ci_factory();
m_tc_ptr = factory(m_env);
if (!m_ti_ptr) {
m_ti_ptr.reset(new ti(*this));
clear_cache_and_ctx();
}
}
expr whnf(expr const & e) {
return m_tc_ptr->whnf(e);
return m_ti_ptr->whnf(e);
}
expr infer_type(expr const & e) {
return m_tc_ptr->infer_type(e);
return m_ti_ptr->infer(e);
}
bool is_prop(expr const & e) {
if (m_env.impredicative()) {
expr t = whnf(infer_type(e));
return t == mk_Prop();
} else {
return false;
}
bool is_def_eq(expr const & e1, expr const & e2) {
return m_ti_ptr->is_def_eq(e1, e2);
}
expr mk_local(expr const & type) {
expr instantiate_uvars_mvars(expr const & e) {
return m_ti_ptr->instantiate_uvars_mvars(e);
}
expr mk_local(expr const & type, binder_info const & bi = binder_info()) {
unsigned idx = m_next_local_idx;
m_next_local_idx++;
return lean::mk_local(name(*g_prefix2, idx), type);
name n(*g_prefix, idx);
return lean::mk_local(n, n, type, bi);
}
bool is_internal_local(expr const & e) {
if (!is_local(e))
return false;
name const & n = mlocal_name(e);
return !n.is_atomic() && n.get_prefix() == *g_prefix2;
return !n.is_atomic() && n.get_prefix() == *g_prefix;
}
/** \brief If the constant \c e is a class, return its name */
@ -353,10 +401,10 @@ struct cienv {
void set_local_instance(unsigned i, name const & cname, expr const & e) {
lean_assert(i <= m_local_instances.size());
if (i == m_local_instances.size()) {
reset_cache();
clear_cache();
m_local_instances.push_back(mk_pair(cname, e));
} else if (e != m_local_instances[i].second) {
reset_cache();
clear_cache();
m_local_instances[i] = mk_pair(cname, e);
} else {
// we don't need to reset the cache since this local instance
@ -384,7 +432,7 @@ struct cienv {
if (i < m_local_instances.size()) {
// new ctx has fewer local instances than previous one
m_local_instances.resize(i);
reset_cache();
clear_cache();
}
}
@ -398,7 +446,7 @@ struct cienv {
level mk_uvar() {
unsigned idx = m_next_uvar_idx;
m_next_uvar_idx++;
return mk_meta_univ(name(*g_prefix2, idx));
return mk_meta_univ(name(*g_prefix, idx));
}
// Return true iff \c l is an internal universe metavariable created by this module.
@ -406,7 +454,7 @@ struct cienv {
if (!is_meta(l))
return false;
name const & n = meta_id(l);
return !n.is_atomic() && n.get_prefix() == *g_prefix2;
return !n.is_atomic() && n.get_prefix() == *g_prefix;
}
static unsigned uvar_idx(level const & l) {
@ -427,17 +475,11 @@ struct cienv {
m_state.m_uassignment.insert(uvar_idx(u), v);
}
// Assign \c v to the universe metavariable \c u.
void assign(level const & u, level const & v) {
lean_assert(!is_assigned(u));
update_assignment(u, v);
}
// Create an internal metavariable.
expr mk_mvar(expr const & type) {
unsigned idx = m_next_mvar_idx;
m_next_mvar_idx++;
return mk_metavar(name(*g_prefix2, idx), type);
return mk_metavar(name(*g_prefix, idx), type);
}
// Return true iff \c e is an internal metavariable created by this module.
@ -445,7 +487,7 @@ struct cienv {
if (!is_metavar(e))
return false;
name const & n = mlocal_name(e);
return !n.is_atomic() && n.get_prefix() == *g_prefix2;
return !n.is_atomic() && n.get_prefix() == *g_prefix;
}
static unsigned mvar_idx(expr const & m) {
@ -472,454 +514,6 @@ struct cienv {
update_assignment(m, v);
}
bool is_def_eq(level const & l1, level const & l2) {
if (is_equivalent(l1, l2)) {
return true;
}
if (is_uvar(l1)) {
if (auto v = get_assignment(l1)) {
return is_def_eq(*v, l2);
} else {
assign(l1, l2);
return true;
}
}
if (is_uvar(l2)) {
if (auto v = get_assignment(l2)) {
return is_def_eq(l1, *v);
} else {
assign(l2, l1);
return true;
}
}
if (is_meta(l1) || is_meta(l2)) {
// The unifier may invoke this module before universe metavariables in the class
// have been instantiated. So, we just ignore and assume they will be solved by
// the unifier.
// See comment at g_subsingleton_hack declaration.
if (g_subsingleton_hack && (is_zero(l1) || is_zero(l2)))
return false;
return true; // we ignore
}
level new_l1 = normalize(l1);
level new_l2 = normalize(l2);
if (l1 != new_l1 || l2 != new_l2)
return is_def_eq(new_l1, new_l2);
if (l1.kind() != l2.kind())
return false;
switch (l1.kind()) {
case level_kind::Max:
return
is_def_eq(max_lhs(l1), max_lhs(l2)) &&
is_def_eq(max_rhs(l1), max_rhs(l2));
case level_kind::IMax:
return
is_def_eq(imax_lhs(l1), imax_lhs(l2)) &&
is_def_eq(imax_rhs(l1), imax_rhs(l2));
case level_kind::Succ:
return is_def_eq(succ_of(l1), succ_of(l2));
case level_kind::Param:
case level_kind::Global:
return false;
case level_kind::Zero:
case level_kind::Meta:
lean_unreachable();
}
lean_unreachable();
}
bool is_def_eq(levels const & ls1, levels const & ls2) {
if (is_nil(ls1) && is_nil(ls2)) {
return true;
} else if (!is_nil(ls1) && !is_nil(ls2)) {
return
is_def_eq(head(ls1), head(ls2)) &&
is_def_eq(tail(ls1), tail(ls2));
} else {
return false;
}
}
/** \brief Given \c e of the form <tt>?m t_1 ... t_n</tt>, where
?m is an assigned mvar, substitute \c ?m with its assignment. */
expr subst_mvar(expr const & e) {
buffer<expr> args;
expr const & m = get_app_args(e, args);
lean_assert(is_mvar(m));
expr const * v = get_assignment(m);
lean_assert(v);
return apply_beta(*v, args.size(), args.data());
}
bool has_assigned_uvar(level const & l) const {
if (!has_meta(l))
return false;
if (m_state.m_uassignment.empty())
return false;
bool found = false;
for_each(l, [&](level const & l) {
if (!has_meta(l))
return false; // stop search
if (found)
return false; // stop search
if (is_uvar(l) && is_assigned(l)) {
found = true;
return false; // stop search
}
return true; // continue search
});
return found;
}
bool has_assigned_uvar(levels const & ls) const {
for (level const & l : ls) {
if (has_assigned_uvar(l))
return true;
}
return false;
}
bool has_assigned_uvar_mvar(expr const & e) const {
if (!has_expr_metavar(e) && !has_univ_metavar(e))
return false;
if (m_state.m_eassignment.empty() && m_state.m_uassignment.empty())
return false;
bool found = false;
for_each(e, [&](expr const & e, unsigned) {
if (!has_expr_metavar(e) && !has_univ_metavar(e))
return false; // stop search
if (found)
return false; // stop search
if ((is_mvar(e) && is_assigned(e)) ||
(is_constant(e) && has_assigned_uvar(const_levels(e))) ||
(is_sort(e) && has_assigned_uvar(sort_level(e)))) {
found = true;
return false; // stop search
}
return true; // continue search
});
return found;
}
level instantiate_uvars(level const & l) {
if (!has_assigned_uvar(l))
return l;
return replace(l, [&](level const & l) {
if (!has_meta(l)) {
return some_level(l);
} else if (is_uvar(l)) {
if (auto v1 = get_assignment(l)) {
level v2 = instantiate_uvars(*v1);
if (*v1 != v2) {
update_assignment(l, v2);
return some_level(v2);
} else {
return some_level(*v1);
}
}
}
return none_level();
});
}
struct instantiate_uvars_mvars_fn : public replace_visitor {
cienv & m_owner;
level visit_level(level const & l) {
return m_owner.instantiate_uvars(l);
}
levels visit_levels(levels const & ls) {
return map_reuse(ls,
[&](level const & l) { return visit_level(l); },
[](level const & l1, level const & l2) { return is_eqp(l1, l2); });
}
virtual expr visit_sort(expr const & s) {
return update_sort(s, visit_level(sort_level(s)));
}
virtual expr visit_constant(expr const & c) {
return update_constant(c, visit_levels(const_levels(c)));
}
virtual expr visit_local(expr const & e) {
return update_mlocal(e, visit(mlocal_type(e)));
}
virtual expr visit_meta(expr const & m) {
if (is_mvar(m)) {
if (auto v1 = m_owner.get_assignment(m)) {
if (!has_expr_metavar(*v1)) {
return *v1;
} else {
expr v2 = m_owner.instantiate_uvars_mvars(*v1);
if (v2 != *v1)
m_owner.update_assignment(m, v2);
return v2;
}
} else {
return m;
}
} else {
return m;
}
}
virtual expr visit_app(expr const & e) {
buffer<expr> args;
expr const & f = get_app_rev_args(e, args);
if (is_mvar(f)) {
if (auto v = m_owner.get_assignment(f)) {
expr new_app = apply_beta(*v, args.size(), args.data());
if (has_expr_metavar(new_app))
return visit(new_app);
else
return new_app;
}
}
expr new_f = visit(f);
buffer<expr> new_args;
bool modified = !is_eqp(new_f, f);
for (expr const & arg : args) {
expr new_arg = visit(arg);
if (!is_eqp(arg, new_arg))
modified = true;
new_args.push_back(new_arg);
}
if (!modified)
return e;
else
return mk_rev_app(new_f, new_args, e.get_tag());
}
virtual expr visit_macro(expr const & e) {
lean_assert(is_macro(e));
buffer<expr> new_args;
for (unsigned i = 0; i < macro_num_args(e); i++)
new_args.push_back(visit(macro_arg(e, i)));
return update_macro(e, new_args.size(), new_args.data());
}
virtual expr visit(expr const & e) {
if (!has_expr_metavar(e) && !has_univ_metavar(e))
return e;
else
return replace_visitor::visit(e);
}
public:
instantiate_uvars_mvars_fn(cienv & o):m_owner(o) {}
expr operator()(expr const & e) { return visit(e); }
};
expr instantiate_uvars_mvars(expr const & e) {
if (!has_assigned_uvar_mvar(e))
return e;
else
return instantiate_uvars_mvars_fn(*this)(e);
}
/** \brief Given \c ma of the form <tt>?m t_1 ... t_n</tt>, (try to) assign
?m to (an abstraction of) v. Return true if success and false otherwise. */
bool assign_mvar(expr const & ma, expr const & v) {
buffer<expr> args;
expr const & m = get_app_args(ma, args);
buffer<expr> locals;
for (expr const & arg : args) {
if (!is_internal_local(arg))
break; // is not local
if (std::any_of(locals.begin(), locals.end(), [&](expr const & local) {
return mlocal_name(local) == mlocal_name(arg); }))
break; // duplicate local
locals.push_back(arg);
}
lean_assert(is_mvar(m));
expr new_v = instantiate_uvars_mvars(v);
// We must check
// 1. Any local constant occurring in new_v occurs in locals
// 2. m does not occur in new_v
bool ok = true;
for_each(new_v, [&](expr const & e, unsigned) {
if (!ok)
return false; // stop search
if (is_internal_local(e)) {
if (std::all_of(locals.begin(), locals.end(), [&](expr const & a) {
return mlocal_name(a) != mlocal_name(e); })) {
ok = false; // failed 1
return false;
}
} else if (is_mvar(e)) {
if (m == e) {
ok = false; // failed 2
return false;
}
return false;
}
return true;
});
if (!ok)
return false;
if (args.empty()) {
// easy case
assign(m, new_v);
return true;
} else if (args.size() == locals.size()) {
assign(m, Fun(locals, new_v));
return true;
} else {
// This case is imprecise since it is not a higher order pattern.
// That the term \c ma is of the form (?m t_1 ... t_n) and the t_i's are not pairwise
// distinct local constants.
expr m_type = mlocal_type(m);
for (unsigned i = 0; i < args.size(); i++) {
m_type = whnf(m_type);
if (!is_pi(m_type))
return false;
lean_assert(i <= locals.size());
if (i == locals.size())
locals.push_back(mk_local(binding_domain(m_type)));
lean_assert(i < locals.size());
m_type = instantiate(binding_body(m_type), locals[i]);
}
lean_assert(locals.size() == args.size());
assign(m, Fun(locals, new_v));
return true;
}
}
bool is_def_eq_binding(expr e1, expr e2) {
lean_assert(e1.kind() == e2.kind());
lean_assert(is_binding(e1));
expr_kind k = e1.kind();
buffer<expr> subst;
do {
optional<expr> var_e1_type;
if (binding_domain(e1) != binding_domain(e2)) {
var_e1_type = instantiate_rev(binding_domain(e1), subst.size(), subst.data());
expr var_e2_type = instantiate_rev(binding_domain(e2), subst.size(), subst.data());
if (!is_def_eq_core(var_e2_type, *var_e1_type))
return false;
}
if (!closed(binding_body(e1)) || !closed(binding_body(e2))) {
// local is used inside t or s
if (!var_e1_type)
var_e1_type = instantiate_rev(binding_domain(e1), subst.size(), subst.data());
subst.push_back(mk_local(*var_e1_type));
} else {
expr const & dont_care = mk_Prop();
subst.push_back(dont_care);
}
e1 = binding_body(e1);
e2 = binding_body(e2);
} while (e1.kind() == k && e2.kind() == k);
return is_def_eq_core(instantiate_rev(e1, subst.size(), subst.data()),
instantiate_rev(e2, subst.size(), subst.data()));
}
bool is_def_eq_app(expr const & e1, expr const & e2) {
lean_assert(is_app(e1) && is_app(e2));
buffer<expr> args1, args2;
expr const & f1 = get_app_args(e1, args1);
expr const & f2 = get_app_args(e2, args2);
if (args1.size() != args2.size() || !is_def_eq_core(f1, f2))
return false;
for (unsigned i = 0; i < args1.size(); i++) {
if (!is_def_eq_core(args1[i], args2[i]))
return false;
}
return true;
}
bool is_def_eq_eta(expr const & e1, expr const & e2) {
expr new_e1 = try_eta(e1);
expr new_e2 = try_eta(e2);
if (e1 != new_e1 || e2 != new_e2)
return is_def_eq_core(new_e1, new_e2);
return false;
}
bool is_def_eq_proof_irrel(expr const & e1, expr const & e2) {
if (!m_env.prop_proof_irrel())
return false;
expr e1_type = infer_type(e1);
expr e2_type = infer_type(e2);
return is_prop(e1_type) && is_def_eq_core(e1_type, e2_type);
}
bool is_def_eq_core(expr const & e1, expr const & e2) {
check_system("is_def_eq");
if (e1 == e2)
return true;
expr const & f1 = get_app_fn(e1);
if (is_mvar(f1)) {
if (is_assigned(f1)) {
return is_def_eq_core(subst_mvar(e1), e2);
} else {
return assign_mvar(e1, e2);
}
}
expr const & f2 = get_app_fn(e2);
if (is_mvar(f2)) {
if (is_assigned(f2)) {
return is_def_eq_core(e1, subst_mvar(e2));
} else {
return assign_mvar(e2, e1);
}
}
expr e1_n = whnf(e1);
expr e2_n = whnf(e2);
if (e1 != e1_n || e2 != e2_n)
return is_def_eq_core(e1_n, e2_n);
if (e1.kind() == e2.kind()) {
switch (e1.kind()) {
case expr_kind::Lambda:
case expr_kind::Pi:
if (is_def_eq_binding(e1, e2))
return true;
break;
case expr_kind::Sort:
if (is_def_eq(sort_level(e1), sort_level(e2)))
return true;
break;
case expr_kind::Meta:
case expr_kind::Var:
lean_unreachable(); // LCOV_EXCL_LINE
case expr_kind::Local:
case expr_kind::Macro:
break;
case expr_kind::Constant:
if (const_name(e1) == const_name(e2) &&
is_def_eq(const_levels(e1), const_levels(e2)))
return true;
break;
case expr_kind::App:
if (is_def_eq_app(e1, e2))
return true;
break;
}
}
if (is_def_eq_eta(e1, e2))
return true;
return is_def_eq_proof_irrel(e1, e2);
}
bool is_def_eq(expr const & e1, expr const & e2) {
state saved_state = m_state;
if (!is_def_eq_core(e1, e2)) {
m_state = saved_state;
return false;
} else {
return true;
}
}
io_state_stream diagnostic() {
io_state ios(*g_ios);
ios.set_options(m_options);
@ -1196,19 +790,19 @@ struct cienv {
MK_THREAD_LOCAL_GET_DEF(cienv, get_cienv);
static void reset_cache_and_ctx() {
get_cienv().reset_cache_and_ctx();
static void clear_cache_and_ctx() {
get_cienv().clear_cache_and_ctx();
}
ci_type_inference_factory_scope::ci_type_inference_factory_scope(ci_type_inference_factory & factory):
m_old(g_factory) {
g_factory = &factory;
reset_cache_and_ctx();
ci_local_metavar_types_scope::ci_local_metavar_types_scope(ci_local_metavar_types & t):
m_old(g_lm_types) {
g_lm_types = &t;
clear_cache_and_ctx();
}
ci_type_inference_factory_scope::~ci_type_inference_factory_scope() {
reset_cache_and_ctx();
g_factory = m_old;
ci_local_metavar_types_scope::~ci_local_metavar_types_scope() {
clear_cache_and_ctx();
g_lm_types = m_old;
}
static optional<expr> mk_class_instance(environment const & env, io_state const & ios, list<expr> const & ctx, expr const & e, pos_info_provider const * pip,
@ -1347,8 +941,7 @@ optional<expr> mk_subsingleton_instance(type_checker & tc, io_state const & ios,
}
void initialize_class_instance_resolution() {
g_prefix1 = new name(name::mk_internal_unique_name());
g_prefix2 = new name(name::mk_internal_unique_name());
g_prefix = new name(name::mk_internal_unique_name());
g_class_trace_instances = new name{"class", "trace_instances"};
g_class_instance_max_depth = new name{"class", "instance_max_depth"};
g_class_trans_instances = new name{"class", "trans_instances"};
@ -1362,13 +955,12 @@ void initialize_class_instance_resolution() {
register_bool_option(*g_class_trans_instances, LEAN_DEFAULT_CLASS_TRANS_INSTANCES,
"(class) use automatically derived instances from the transitive closure of "
"the structure instance graph");
g_default_factory = new ci_type_inference_factory();
g_lm_types = new default_ci_local_metavar_types();
}
void finalize_class_instance_resolution() {
delete g_default_factory;
delete g_prefix1;
delete g_prefix2;
delete g_lm_types;
delete g_prefix;
delete g_class_trace_instances;
delete g_class_instance_max_depth;
delete g_class_trans_instances;

View file

@ -12,24 +12,27 @@ Author: Leonardo de Moura
#include "library/local_context.h"
namespace lean {
class ci_type_inference {
/** Auxiliary object used to customize type class resolution.
It allows us to specify how the types of local constants and metavariables are retrieved.
\remark We need this object because modules such as blast store
the types of some local constants (e.g., hypotheses) in a
different data-structure.
*/
class ci_local_metavar_types {
public:
virtual ~ci_type_inference() {}
virtual expr whnf(expr const & e) = 0;
virtual expr infer_type(expr const & e) = 0;
virtual ~ci_local_metavar_types() {}
virtual expr infer_local(expr const & e) = 0;
virtual expr infer_metavar(expr const & e) = 0;
};
class ci_type_inference_factory {
/** \brief Auxiliary object for changing the thread local storage that stores the auxiliary object
ci_local_metavar_types used by type class resolution. */
class ci_local_metavar_types_scope {
ci_local_metavar_types * m_old;
public:
virtual ~ci_type_inference_factory();
virtual std::shared_ptr<ci_type_inference> operator()(environment const & env) const;
};
class ci_type_inference_factory_scope {
ci_type_inference_factory * m_old;
public:
ci_type_inference_factory_scope(ci_type_inference_factory & factory);
~ci_type_inference_factory_scope();
ci_local_metavar_types_scope(ci_local_metavar_types & t);
~ci_local_metavar_types_scope();
};
optional<expr> mk_class_instance(environment const & env, io_state const & ios, list<expr> const & ctx, expr const & e, pos_info_provider const * pip = nullptr);

View file

@ -44,6 +44,7 @@ Author: Leonardo de Moura
#include "library/meng_paulson.h"
#include "library/norm_num.h"
#include "library/class_instance_resolution.h"
#include "library/type_inference.h"
namespace lean {
void initialize_library_module() {
@ -87,9 +88,11 @@ void initialize_library_module() {
initialize_meng_paulson();
initialize_norm_num();
initialize_class_instance_resolution();
initialize_type_inference();
}
void finalize_library_module() {
finalize_type_inference();
finalize_class_instance_resolution();
finalize_norm_num();
finalize_meng_paulson();