refactor(kernel/converter): replace extra_opaque_set with predicate

It gives us more flexibility.
This commit is contained in:
Leonardo de Moura 2014-09-17 17:05:13 -07:00
parent 1fbb554a16
commit ea1bae0143
8 changed files with 97 additions and 56 deletions

View file

@ -23,31 +23,36 @@ namespace lean {
We also believe it increases the modularity of Lean developments by minimizing the dependency on how things are defined. We also believe it increases the modularity of Lean developments by minimizing the dependency on how things are defined.
We should view non-opaque definitions as "inline definitions" used in programming languages such as C++. We should view non-opaque definitions as "inline definitions" used in programming languages such as C++.
2) Whenever type checking an expression, the user can provide an additional set of definition names (m_extra_opaque) that 2) Whenever type checking an expression, the user can provide a predicate that is true for for additional definitions that
should be considered opaque. Note that, if \c t type checks when using an extra_opaque set S, then t also type checks should be considered opaque. Note that, if \c t type checks when using predicate P, then t also type checks
(modulo resource constraints) with the empty set. Again, the purpose of extra_opaque is to mimimize the number (modulo resource constraints) without it. Again, the purpose of the predicate is to mimimize the number
of delta-reduction steps. of delta-reduction steps.
3) To be able to prove theorems about an opaque definition, we treat an opaque definition D in a module M as 3) To be able to prove theorems about an opaque definition, we treat an opaque definition D in a module M as
transparent when we are type checking another definition/theorem D' also in M. This rule only applies if transparent when we are type checking another definition/theorem D' also in M. This rule only applies if
D is not a theorem, nor D is in the set m_extra_opaque. To implement this feature, this class has a field D is not a theorem, nor pred(D) is true. To implement this feature, this class has a field
m_module_idx that is not none when this rule should be applied. m_module_idx that is not none when this rule should be applied.
*/ */
bool is_opaque(declaration const & d, name_set const & extra_opaque, optional<module_idx> const & mod_idx) { bool is_opaque(declaration const & d, extra_opaque_pred const & pred, optional<module_idx> const & mod_idx) {
lean_assert(d.is_definition()); lean_assert(d.is_definition());
if (d.is_theorem()) return true; // theorems are always opaque if (d.is_theorem()) return true; // theorems are always opaque
if (extra_opaque.contains(d.get_name())) return true; // extra_opaque set overrides opaque flag if (pred(d.get_name())) return true; // extra_opaque predicate overrides opaque flag
if (!d.is_opaque()) return false; // d is a transparent definition if (!d.is_opaque()) return false; // d is a transparent definition
if (mod_idx && d.get_module_idx() == *mod_idx) return false; // the opaque definitions in mod_idx are considered transparent if (mod_idx && d.get_module_idx() == *mod_idx) return false; // the opaque definitions in mod_idx are considered transparent
return true; // d is opaque return true; // d is opaque
} }
extra_opaque_pred g_always_false([](name const &) { return false; });
extra_opaque_pred const & no_extra_opaque() {
return g_always_false;
}
/** \brief Auxiliary method for \c is_delta */ /** \brief Auxiliary method for \c is_delta */
static optional<declaration> is_delta_core(environment const & env, expr const & e, name_set const & extra_opaque, static optional<declaration> is_delta_core(environment const & env, expr const & e, extra_opaque_pred const & pred,
optional<module_idx> const & mod_idx) { optional<module_idx> const & mod_idx) {
if (is_constant(e)) { if (is_constant(e)) {
if (auto d = env.find(const_name(e))) if (auto d = env.find(const_name(e)))
if (d->is_definition() && !is_opaque(*d, extra_opaque, mod_idx)) if (d->is_definition() && !is_opaque(*d, pred, mod_idx))
return d; return d;
} }
return none_declaration(); return none_declaration();
@ -57,15 +62,21 @@ static optional<declaration> is_delta_core(environment const & env, expr const &
\brief Return some definition \c d iff \c e is a target for delta-reduction, and the given definition is the one \brief Return some definition \c d iff \c e is a target for delta-reduction, and the given definition is the one
to be expanded. to be expanded.
*/ */
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque, optional<module_idx> const & mod_idx) { optional<declaration> is_delta(environment const & env, expr const & e,
return is_delta_core(env, get_app_fn(e), extra_opaque, mod_idx); extra_opaque_pred const & pred, optional<module_idx> const & mod_idx) {
return is_delta_core(env, get_app_fn(e), pred, mod_idx);
} }
static optional<module_idx> g_opt_main_module_idx(g_main_module_idx); static optional<module_idx> g_opt_main_module_idx(g_main_module_idx);
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque) { optional<declaration> is_delta(environment const & env, expr const & e, extra_opaque_pred const & pred) {
return is_delta(env, e, extra_opaque, g_opt_main_module_idx); return is_delta(env, e, pred, g_opt_main_module_idx);
} }
optional<declaration> is_delta(environment const & env, expr const & e) {
return is_delta(env, e, g_always_false);
}
static no_delayed_justification g_no_delayed_jst; static no_delayed_justification g_no_delayed_jst;
pair<bool, constraint_seq> converter::is_def_eq(expr const & t, expr const & s, type_checker & c) { pair<bool, constraint_seq> converter::is_def_eq(expr const & t, expr const & s, type_checker & c) {
return is_def_eq(t, s, c, g_no_delayed_jst); return is_def_eq(t, s, c, g_no_delayed_jst);
@ -95,12 +106,13 @@ struct default_converter : public converter {
environment m_env; environment m_env;
optional<module_idx> m_module_idx; optional<module_idx> m_module_idx;
bool m_memoize; bool m_memoize;
name_set m_extra_opaque; extra_opaque_pred m_extra_pred;
expr_struct_map<expr> m_whnf_core_cache; expr_struct_map<expr> m_whnf_core_cache;
expr_struct_map<pair<expr, constraint_seq>> m_whnf_cache; expr_struct_map<pair<expr, constraint_seq>> m_whnf_cache;
default_converter(environment const & env, optional<module_idx> mod_idx, bool memoize, name_set const & extra_opaque): default_converter(environment const & env, optional<module_idx> mod_idx, bool memoize,
m_env(env), m_module_idx(mod_idx), m_memoize(memoize), m_extra_opaque(extra_opaque) { extra_opaque_pred const & pred):
m_env(env), m_module_idx(mod_idx), m_memoize(memoize), m_extra_pred(pred) {
} }
constraint mk_eq_cnstr(expr const & lhs, expr const & rhs, justification const & j) { constraint mk_eq_cnstr(expr const & lhs, expr const & rhs, justification const & j) {
@ -211,7 +223,7 @@ struct default_converter : public converter {
} }
bool is_opaque(declaration const & d) const { bool is_opaque(declaration const & d) const {
return ::lean::is_opaque(d, m_extra_opaque, m_module_idx); return ::lean::is_opaque(d, m_extra_pred, m_module_idx);
} }
/** \brief Expand \c e if it is non-opaque constant with weight >= w */ /** \brief Expand \c e if it is non-opaque constant with weight >= w */
@ -252,7 +264,7 @@ struct default_converter : public converter {
to be expanded. to be expanded.
*/ */
optional<declaration> is_delta(expr const & e) { optional<declaration> is_delta(expr const & e) {
return ::lean::is_delta(m_env, get_app_fn(e), m_extra_opaque, m_module_idx); return ::lean::is_delta(m_env, get_app_fn(e), m_extra_pred, m_module_idx);
} }
/** /**
@ -632,14 +644,21 @@ struct default_converter : public converter {
}; };
std::unique_ptr<converter> mk_default_converter(environment const & env, optional<module_idx> mod_idx, std::unique_ptr<converter> mk_default_converter(environment const & env, optional<module_idx> mod_idx,
bool memoize, name_set const & extra_opaque) { bool memoize, extra_opaque_pred const & pred) {
return std::unique_ptr<converter>(new default_converter(env, mod_idx, memoize, extra_opaque)); return std::unique_ptr<converter>(new default_converter(env, mod_idx, memoize, pred));
}
std::unique_ptr<converter> mk_default_converter(environment const & env, optional<module_idx> mod_idx,
bool memoize) {
return mk_default_converter(env, mod_idx, memoize, g_always_false);
} }
std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main, bool memoize, std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main, bool memoize,
name_set const & extra_opaque) { extra_opaque_pred const & pred) {
if (unfold_opaque_main) if (unfold_opaque_main)
return mk_default_converter(env, optional<module_idx>(0), memoize, extra_opaque); return mk_default_converter(env, optional<module_idx>(0), memoize, pred);
else else
return mk_default_converter(env, optional<module_idx>(), memoize, extra_opaque); return mk_default_converter(env, optional<module_idx>(), memoize, pred);
}
std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main, bool memoize) {
return mk_default_converter(env, unfold_opaque_main, memoize, g_always_false);
} }
} }

View file

@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#pragma once #pragma once
#include <functional>
#include "kernel/environment.h" #include "kernel/environment.h"
namespace lean { namespace lean {
@ -24,13 +25,17 @@ public:
}; };
std::unique_ptr<converter> mk_dummy_converter(); std::unique_ptr<converter> mk_dummy_converter();
std::unique_ptr<converter> mk_default_converter(environment const & env, std::unique_ptr<converter> mk_default_converter(environment const & env, optional<module_idx> mod_idx = optional<module_idx>(),
optional<module_idx> mod_idx = optional<module_idx>(), bool memoize = true);
bool memoize = true, name_set const & extra_opaque = name_set()); std::unique_ptr<converter> mk_default_converter(environment const & env, optional<module_idx> mod_idx,
bool memoize, extra_opaque_pred const & pred);
std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main, std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main,
bool memoize = true, name_set const & extra_opaque = name_set()); bool memoize = true);
std::unique_ptr<converter> mk_default_converter(environment const & env, bool unfold_opaque_main,
bool memoize, extra_opaque_pred const & pred);
bool is_opaque(declaration const & d, name_set const & extra_opaque, optional<module_idx> const & mod_idx); bool is_opaque(declaration const & d, extra_opaque_pred const & pred, optional<module_idx> const & mod_idx);
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque, optional<module_idx> const & mod_idx); optional<declaration> is_delta(environment const & env, expr const & e, extra_opaque_pred const & pred, optional<module_idx> const & mod_idx);
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque = name_set()); optional<declaration> is_delta(environment const & env, expr const & e, extra_opaque_pred const & pred);
optional<declaration> is_delta(environment const & env, expr const & e);
} }

View file

@ -29,6 +29,9 @@ class type_checker;
class environment; class environment;
class certified_declaration; class certified_declaration;
typedef std::function<bool(name const &)> extra_opaque_pred;
extra_opaque_pred const & no_extra_opaque();
/** /**
\brief The header of an environment is created when we create the empty environment. \brief The header of an environment is created when we create the empty environment.
Moreover if environment B is an extension of environment A, then A and B share the same header. Moreover if environment B is an extension of environment A, then A and B share the same header.
@ -223,7 +226,8 @@ class name_generator;
Only the type_checker class can create certified declarations. Only the type_checker class can create certified declarations.
*/ */
class certified_declaration { class certified_declaration {
friend certified_declaration check(environment const & env, declaration const & d, name_generator const & g, name_set const & extra_opaque, bool memoize); friend certified_declaration check(environment const & env, declaration const & d,
name_generator const & g, extra_opaque_pred const & extra_opaque);
environment_id m_id; environment_id m_id;
declaration m_declaration; declaration m_declaration;
certified_declaration(environment_id const & id, declaration const & d):m_id(id), m_declaration(d) {} certified_declaration(environment_id const & id, declaration const & d):m_id(id), m_declaration(d) {}

View file

@ -453,20 +453,22 @@ static void check_duplicated_params(environment const & env, declaration const &
} }
} }
certified_declaration check(environment const & env, declaration const & d, name_generator const & g, name_set const & extra_opaque, bool memoize) { certified_declaration check(environment const & env, declaration const & d, name_generator const & g,
extra_opaque_pred const & pred) {
if (d.is_definition()) if (d.is_definition())
check_no_mlocal(env, d.get_name(), d.get_value(), false); check_no_mlocal(env, d.get_name(), d.get_value(), false);
check_no_mlocal(env, d.get_name(), d.get_type(), true); check_no_mlocal(env, d.get_name(), d.get_type(), true);
check_name(env, d.get_name()); check_name(env, d.get_name());
check_duplicated_params(env, d); check_duplicated_params(env, d);
type_checker checker1(env, g, mk_default_converter(env, optional<module_idx>(), memoize, extra_opaque)); bool memoize = true;
type_checker checker1(env, g, mk_default_converter(env, optional<module_idx>(), memoize, pred));
expr sort = checker1.check(d.get_type(), d.get_univ_params()).first; expr sort = checker1.check(d.get_type(), d.get_univ_params()).first;
checker1.ensure_sort(sort, d.get_type()); checker1.ensure_sort(sort, d.get_type());
if (d.is_definition()) { if (d.is_definition()) {
optional<module_idx> midx; optional<module_idx> midx;
if (d.is_opaque()) if (d.is_opaque())
midx = optional<module_idx>(d.get_module_idx()); midx = optional<module_idx>(d.get_module_idx());
type_checker checker2(env, g, mk_default_converter(env, midx, memoize, extra_opaque)); type_checker checker2(env, g, mk_default_converter(env, midx, memoize, pred));
expr val_type = checker2.check(d.get_value(), d.get_univ_params()).first; expr val_type = checker2.check(d.get_value(), d.get_univ_params()).first;
if (!checker2.is_def_eq(val_type, d.get_type()).first) { if (!checker2.is_def_eq(val_type, d.get_type()).first) {
throw_kernel_exception(env, d.get_value(), [=](formatter const & fmt) { throw_kernel_exception(env, d.get_value(), [=](formatter const & fmt) {
@ -477,7 +479,15 @@ certified_declaration check(environment const & env, declaration const & d, name
return certified_declaration(env.get_id(), d); return certified_declaration(env.get_id(), d);
} }
certified_declaration check(environment const & env, declaration const & d, name_set const & extra_opaque, bool memoize) { certified_declaration check(environment const & env, declaration const & d, name_generator const & g) {
return check(env, d, name_generator(g_tmp_prefix), extra_opaque, memoize); return check(env, d, g, no_extra_opaque());
}
certified_declaration check(environment const & env, declaration const & d, extra_opaque_pred const & pred) {
return check(env, d, name_generator(g_tmp_prefix), pred);
}
certified_declaration check(environment const & env, declaration const & d) {
return check(env, d, no_extra_opaque());
} }
} }

View file

@ -209,9 +209,11 @@ void check_no_metavar(environment const & env, name const & n, expr const & e, b
\brief Type check the given declaration, and return a certified declaration if it is type correct. \brief Type check the given declaration, and return a certified declaration if it is type correct.
Throw an exception if the declaration is type incorrect. Throw an exception if the declaration is type incorrect.
*/ */
certified_declaration check(environment const & env, declaration const & d, certified_declaration check(environment const & env, declaration const & d, name_generator const & g,
name_generator const & g, name_set const & extra_opaque = name_set(), bool memoize = true); extra_opaque_pred const & pred);
certified_declaration check(environment const & env, declaration const & d, name_set const & extra_opaque = name_set(), bool memoize = true); certified_declaration check(environment const & env, declaration const & d, name_generator const & g);
certified_declaration check(environment const & env, declaration const & d, extra_opaque_pred const & pred);
certified_declaration check(environment const & env, declaration const & d);
/** /**
\brief Create a justification for an application \c e where the expected type must be \c d_type and \brief Create a justification for an application \c e where the expected type must be \c d_type and

View file

@ -1842,9 +1842,10 @@ static int mk_type_checker(lua_State * L) {
return push_type_checker_ref(L, std::make_shared<type_checker>(to_environment(L, 1), to_name_generator(L, 2))); return push_type_checker_ref(L, std::make_shared<type_checker>(to_environment(L, 1), to_name_generator(L, 2)));
} else { } else {
optional<module_idx> mod_idx; bool memoize; name_set extra_opaque; optional<module_idx> mod_idx; bool memoize; name_set extra_opaque;
extra_opaque_pred pred([=](name const & n) { return extra_opaque.contains(n); });
get_type_checker_args(L, 3, mod_idx, memoize, extra_opaque); get_type_checker_args(L, 3, mod_idx, memoize, extra_opaque);
auto t = std::make_shared<type_checker>(to_environment(L, 1), to_name_generator(L, 2), auto t = std::make_shared<type_checker>(to_environment(L, 1), to_name_generator(L, 2),
mk_default_converter(to_environment(L, 1), mod_idx, memoize, extra_opaque), mk_default_converter(to_environment(L, 1), mod_idx, memoize, pred),
memoize); memoize);
return push_type_checker_ref(L, t); return push_type_checker_ref(L, t);
} }
@ -1905,28 +1906,29 @@ static const struct luaL_Reg type_checker_ref_m[] = {
// type_check procedure // type_check procedure
static int type_check(lua_State * L) { static int type_check(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
if (nargs == 2) if (nargs == 2) {
return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2))); return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2)));
else if (nargs == 3) } else if (nargs == 3) {
return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3))); return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3)));
else if (nargs == 4) } else {
return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4))); name_set extra_opaque = to_name_set(L, 4);
else extra_opaque_pred pred([=](name const & n) { return extra_opaque.contains(n); });
return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4), return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), pred));
lua_toboolean(L, 5))); }
} }
static int add_declaration(lua_State * L) { static int add_declaration(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
optional<certified_declaration> d; optional<certified_declaration> d;
if (nargs == 2) if (nargs == 2) {
d = check(to_environment(L, 1), to_declaration(L, 2)); d = check(to_environment(L, 1), to_declaration(L, 2));
else if (nargs == 3) } else if (nargs == 3) {
d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3)); d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3));
else if (nargs == 4) } else {
d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4)); name_set extra_opaque = to_name_set(L, 4);
else extra_opaque_pred pred([=](name const & n) { return extra_opaque.contains(n); });
d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4), lua_toboolean(L, 5)); d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), pred);
}
return push_environment(L, module::add(to_environment(L, 1), *d)); return push_environment(L, module::add(to_environment(L, 1), *d));
} }

View file

@ -56,8 +56,10 @@ bool get_hide_main_opaque(environment const & env) {
std::unique_ptr<type_checker> mk_type_checker_with_hints(environment const & env, name_generator const & ngen, std::unique_ptr<type_checker> mk_type_checker_with_hints(environment const & env, name_generator const & ngen,
bool relax_main_opaque) { bool relax_main_opaque) {
auto const & ext = get_extension(env); auto const & ext = get_extension(env);
name_set extra_opaque = ext.m_extra_opaque;
extra_opaque_pred pred([=](name const & n) { return extra_opaque.contains(n); });
return std::unique_ptr<type_checker>(new type_checker(env, ngen, mk_default_converter(env, return std::unique_ptr<type_checker>(new type_checker(env, ngen, mk_default_converter(env,
!ext.m_hide_module && relax_main_opaque, !ext.m_hide_module && relax_main_opaque,
true, ext.m_extra_opaque))); true, pred)));
} }
} }

View file

@ -106,9 +106,6 @@ static void tst2() {
lean_assert(checker.is_def_eq(f98(c1, id(Prop, id(Prop, c2))), f97(f97(c1, id(Prop, c2)), f97(c2, c1))).first); lean_assert(checker.is_def_eq(f98(c1, id(Prop, id(Prop, c2))), f97(f97(c1, id(Prop, c2)), f97(c2, c1))).first);
name_set s; name_set s;
s.insert(name(base, 96)); s.insert(name(base, 96));
type_checker checker2(env, name_generator("tmp"), mk_default_converter(env, optional<module_idx>(), true, s));
lean_assert_eq(checker2.whnf(f98(c1, c2)).first,
f96(f96(f97(c1, c2), f97(c2, c1)), f96(f97(c2, c1), f97(c1, c2))));
} }
class normalizer_extension_tst : public normalizer_extension { class normalizer_extension_tst : public normalizer_extension {