refactor(kernel/converter): replace extra_opaque_set with predicate
It gives us more flexibility.
This commit is contained in:
parent
1fbb554a16
commit
ea1bae0143
8 changed files with 97 additions and 56 deletions
|
@ -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 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
|
||||
should be considered opaque. Note that, if \c t type checks when using an extra_opaque set S, then t also type checks
|
||||
(modulo resource constraints) with the empty set. Again, the purpose of extra_opaque is to mimimize the number
|
||||
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 predicate P, then t also type checks
|
||||
(modulo resource constraints) without it. Again, the purpose of the predicate is to mimimize the number
|
||||
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
|
||||
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.
|
||||
*/
|
||||
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());
|
||||
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 (mod_idx && d.get_module_idx() == *mod_idx) return false; // the opaque definitions in mod_idx are considered transparent
|
||||
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 */
|
||||
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) {
|
||||
if (is_constant(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 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
|
||||
to be expanded.
|
||||
*/
|
||||
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque, optional<module_idx> const & mod_idx) {
|
||||
return is_delta_core(env, get_app_fn(e), extra_opaque, mod_idx);
|
||||
optional<declaration> is_delta(environment const & env, expr const & e,
|
||||
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);
|
||||
optional<declaration> is_delta(environment const & env, expr const & e, name_set const & extra_opaque) {
|
||||
return is_delta(env, e, extra_opaque, g_opt_main_module_idx);
|
||||
optional<declaration> is_delta(environment const & env, expr const & e, extra_opaque_pred const & pred) {
|
||||
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;
|
||||
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);
|
||||
|
@ -95,12 +106,13 @@ struct default_converter : public converter {
|
|||
environment m_env;
|
||||
optional<module_idx> m_module_idx;
|
||||
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<pair<expr, constraint_seq>> m_whnf_cache;
|
||||
|
||||
default_converter(environment const & env, optional<module_idx> mod_idx, bool memoize, name_set const & extra_opaque):
|
||||
m_env(env), m_module_idx(mod_idx), m_memoize(memoize), m_extra_opaque(extra_opaque) {
|
||||
default_converter(environment const & env, optional<module_idx> mod_idx, bool memoize,
|
||||
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) {
|
||||
|
@ -211,7 +223,7 @@ struct default_converter : public converter {
|
|||
}
|
||||
|
||||
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 */
|
||||
|
@ -252,7 +264,7 @@ struct default_converter : public converter {
|
|||
to be expanded.
|
||||
*/
|
||||
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,
|
||||
bool memoize, name_set const & extra_opaque) {
|
||||
return std::unique_ptr<converter>(new default_converter(env, mod_idx, memoize, extra_opaque));
|
||||
bool memoize, extra_opaque_pred const & pred) {
|
||||
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,
|
||||
name_set const & extra_opaque) {
|
||||
extra_opaque_pred const & pred) {
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
|||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "kernel/environment.h"
|
||||
|
||||
namespace lean {
|
||||
|
@ -24,13 +25,17 @@ public:
|
|||
};
|
||||
|
||||
std::unique_ptr<converter> mk_dummy_converter();
|
||||
std::unique_ptr<converter> mk_default_converter(environment const & env,
|
||||
optional<module_idx> mod_idx = optional<module_idx>(),
|
||||
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 = optional<module_idx>(),
|
||||
bool memoize = true);
|
||||
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,
|
||||
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);
|
||||
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, name_set const & extra_opaque = name_set());
|
||||
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, extra_opaque_pred const & pred, optional<module_idx> const & mod_idx);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ class type_checker;
|
|||
class environment;
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
declaration m_declaration;
|
||||
certified_declaration(environment_id const & id, declaration const & d):m_id(id), m_declaration(d) {}
|
||||
|
|
|
@ -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())
|
||||
check_no_mlocal(env, d.get_name(), d.get_value(), false);
|
||||
check_no_mlocal(env, d.get_name(), d.get_type(), true);
|
||||
check_name(env, d.get_name());
|
||||
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;
|
||||
checker1.ensure_sort(sort, d.get_type());
|
||||
if (d.is_definition()) {
|
||||
optional<module_idx> midx;
|
||||
if (d.is_opaque())
|
||||
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;
|
||||
if (!checker2.is_def_eq(val_type, d.get_type()).first) {
|
||||
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);
|
||||
}
|
||||
|
||||
certified_declaration check(environment const & env, declaration const & d, name_set const & extra_opaque, bool memoize) {
|
||||
return check(env, d, name_generator(g_tmp_prefix), extra_opaque, memoize);
|
||||
certified_declaration check(environment const & env, declaration const & d, name_generator const & g) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
Throw an exception if the declaration is type incorrect.
|
||||
*/
|
||||
certified_declaration check(environment const & env, declaration const & d,
|
||||
name_generator const & g, name_set const & extra_opaque = name_set(), bool memoize = true);
|
||||
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,
|
||||
extra_opaque_pred const & pred);
|
||||
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
|
||||
|
|
|
@ -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)));
|
||||
} else {
|
||||
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);
|
||||
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);
|
||||
return push_type_checker_ref(L, t);
|
||||
}
|
||||
|
@ -1905,28 +1906,29 @@ static const struct luaL_Reg type_checker_ref_m[] = {
|
|||
// type_check procedure
|
||||
static int type_check(lua_State * 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)));
|
||||
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)));
|
||||
else if (nargs == 4)
|
||||
return push_certified_declaration(L, check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 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),
|
||||
lua_toboolean(L, 5)));
|
||||
} else {
|
||||
name_set extra_opaque = to_name_set(L, 4);
|
||||
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), pred));
|
||||
}
|
||||
}
|
||||
|
||||
static int add_declaration(lua_State * L) {
|
||||
int nargs = lua_gettop(L);
|
||||
optional<certified_declaration> d;
|
||||
if (nargs == 2)
|
||||
if (nargs == 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));
|
||||
else if (nargs == 4)
|
||||
d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4));
|
||||
else
|
||||
d = check(to_environment(L, 1), to_declaration(L, 2), to_name_generator(L, 3), to_name_set(L, 4), lua_toboolean(L, 5));
|
||||
} else {
|
||||
name_set extra_opaque = to_name_set(L, 4);
|
||||
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), pred);
|
||||
}
|
||||
return push_environment(L, module::add(to_environment(L, 1), *d));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
bool relax_main_opaque) {
|
||||
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,
|
||||
!ext.m_hide_module && relax_main_opaque,
|
||||
true, ext.m_extra_opaque)));
|
||||
true, pred)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
name_set s;
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue