feat(*): add [quasireducible] attribute
This commit is contained in:
parent
53df3d86ee
commit
abd238aef0
17 changed files with 203 additions and 135 deletions
|
@ -118,7 +118,7 @@
|
|||
(,(rx symbol-start "_" symbol-end) . 'font-lock-preprocessor-face)
|
||||
;; modifiers
|
||||
(,(rx (or "\[persistent\]" "\[notation\]" "\[visible\]" "\[instance\]" "\[class\]" "\[parsing-only\]"
|
||||
"\[coercion\]" "\[reducible\]" "\[irreducible\]" "\[semireducible\]" "\[wf\]"
|
||||
"\[coercion\]" "\[reducible\]" "\[irreducible\]" "\[semireducible\]" "\[quasireducible\]" "\[wf\]"
|
||||
"\[whnf\]" "\[multiple-instances\]"
|
||||
"\[decls\]" "\[declarations\]" "\[all-transparent\]" "\[coercions\]" "\[classes\]"
|
||||
"\[notations\]" "\[abbreviations\]" "\[begin-end-hints\]" "\[tactic-hints\]" "\[reduce-hints\]"))
|
||||
|
|
|
@ -168,7 +168,7 @@ constraint mk_calc_proof_cnstr(environment const & env, options const & opts,
|
|||
|
||||
unifier_config new_cfg(cfg);
|
||||
new_cfg.m_discard = false;
|
||||
new_cfg.m_conservative = conservative;
|
||||
new_cfg.m_kind = conservative ? unifier_kind::Conservative : unifier_kind::Liberal;
|
||||
unify_result_seq seq = unify(env, cs_buffer.size(), cs_buffer.data(), ngen, substitution(), new_cfg);
|
||||
auto p = seq.pull();
|
||||
lean_assert(p);
|
||||
|
|
|
@ -291,6 +291,7 @@ struct decl_attributes {
|
|||
bool m_is_reducible;
|
||||
bool m_is_irreducible;
|
||||
bool m_is_semireducible;
|
||||
bool m_is_quasireducible;
|
||||
bool m_is_class;
|
||||
bool m_is_parsing_only;
|
||||
bool m_has_multiple_instances;
|
||||
|
@ -306,6 +307,7 @@ struct decl_attributes {
|
|||
m_is_reducible = is_abbrev;
|
||||
m_is_irreducible = false;
|
||||
m_is_semireducible = false;
|
||||
m_is_quasireducible = false;
|
||||
m_is_class = false;
|
||||
m_is_parsing_only = false;
|
||||
m_has_multiple_instances = false;
|
||||
|
@ -364,20 +366,25 @@ struct decl_attributes {
|
|||
throw parser_error("invalid '[coercion]' attribute, coercions cannot be defined in contexts", pos);
|
||||
m_is_coercion = true;
|
||||
} else if (p.curr_is_token(get_reducible_tk())) {
|
||||
if (m_is_irreducible || m_is_semireducible)
|
||||
throw parser_error("invalid '[reducible]' attribute, '[irreducible]' or '[semireducible]' was already provided", pos);
|
||||
if (m_is_irreducible || m_is_semireducible || m_is_quasireducible)
|
||||
throw parser_error("invalid '[reducible]' attribute, '[irreducible]', '[quasireducible]' or '[semireducible]' was already provided", pos);
|
||||
m_is_reducible = true;
|
||||
p.next();
|
||||
} else if (p.curr_is_token(get_irreducible_tk())) {
|
||||
if (m_is_reducible || m_is_semireducible)
|
||||
throw parser_error("invalid '[irreducible]' attribute, '[reducible]' or '[semireducible]' was already provided", pos);
|
||||
if (m_is_reducible || m_is_semireducible || m_is_quasireducible)
|
||||
throw parser_error("invalid '[irreducible]' attribute, '[reducible]', '[quasireducible]' or '[semireducible]' was already provided", pos);
|
||||
m_is_irreducible = true;
|
||||
p.next();
|
||||
} else if (p.curr_is_token(get_semireducible_tk())) {
|
||||
if (m_is_reducible || m_is_irreducible)
|
||||
throw parser_error("invalid '[irreducible]' attribute, '[reducible]' or '[irreducible]' was already provided", pos);
|
||||
if (m_is_reducible || m_is_irreducible || m_is_quasireducible)
|
||||
throw parser_error("invalid '[irreducible]' attribute, '[reducible]', '[quasireducible]' or '[irreducible]' was already provided", pos);
|
||||
m_is_semireducible = true;
|
||||
p.next();
|
||||
} else if (p.curr_is_token(get_quasireducible_tk())) {
|
||||
if (m_is_reducible || m_is_irreducible || m_is_semireducible)
|
||||
throw parser_error("invalid '[quasireducible]' attribute, '[reducible]', '[semireducible]' or '[irreducible]' was already provided", pos);
|
||||
m_is_quasireducible = true;
|
||||
p.next();
|
||||
} else if (p.curr_is_token(get_class_tk())) {
|
||||
if (m_def_only)
|
||||
throw parser_error("invalid '[class]' attribute, definitions cannot be marked as classes", pos);
|
||||
|
@ -451,6 +458,8 @@ struct decl_attributes {
|
|||
env = set_reducible(env, d, reducible_status::Irreducible, persistent);
|
||||
if (m_is_semireducible)
|
||||
env = set_reducible(env, d, reducible_status::Semireducible, persistent);
|
||||
if (m_is_quasireducible)
|
||||
env = set_reducible(env, d, reducible_status::Quasireducible, persistent);
|
||||
if (m_is_class)
|
||||
env = add_class(env, d, persistent);
|
||||
if (m_has_multiple_instances)
|
||||
|
|
|
@ -71,7 +71,7 @@ bool match_pattern(type_checker & tc, expr const & pattern, declaration const &
|
|||
try {
|
||||
unifier_config cfg;
|
||||
cfg.m_max_steps = max_steps;
|
||||
cfg.m_cheap = cheap;
|
||||
cfg.m_kind = cheap ? unifier_kind::Cheap : unifier_kind::Liberal;
|
||||
cfg.m_ignore_context_check = true;
|
||||
auto r = unify(tc.env(), pattern, dt, tc.mk_ngen(), true, substitution(), cfg);
|
||||
return static_cast<bool>(r.pull());
|
||||
|
|
|
@ -766,7 +766,7 @@ bool match_type(type_checker & tc, expr const & meta, expr const & expected_type
|
|||
try {
|
||||
unifier_config cfg;
|
||||
cfg.m_max_steps = LEAN_FINDG_MAX_STEPS;
|
||||
cfg.m_cheap = true;
|
||||
cfg.m_kind = unifier_kind::Cheap;
|
||||
auto r = unify(tc.env(), dt, expected_type, tc.mk_ngen(), true, substitution(), cfg);
|
||||
return static_cast<bool>(r.pull());
|
||||
} catch (exception&) {
|
||||
|
|
|
@ -90,7 +90,7 @@ void init_token_table(token_table & t) {
|
|||
{"theorem", "axiom", "variable", "protected", "private", "opaque", "definition", "example", "coercion",
|
||||
"abbreviation",
|
||||
"variables", "parameter", "parameters", "constant", "constants", "[persistent]", "[visible]", "[instance]",
|
||||
"[off]", "[on]", "[none]", "[class]", "[coercion]", "[reducible]", "[irreducible]", "[semireducible]",
|
||||
"[off]", "[on]", "[none]", "[class]", "[coercion]", "[reducible]", "[irreducible]", "[semireducible]", "[quasireducible]",
|
||||
"[parsing-only]", "[multiple-instances]",
|
||||
"evaluate", "check", "eval", "[wf]", "[whnf]", "[all-transparent]", "[priority", "[unfold-c", "print",
|
||||
"end", "namespace", "section", "prelude",
|
||||
|
|
|
@ -100,6 +100,7 @@ static name * g_priority = nullptr;
|
|||
static name * g_unfold_c = nullptr;
|
||||
static name * g_coercion = nullptr;
|
||||
static name * g_reducible = nullptr;
|
||||
static name * g_quasireducible = nullptr;
|
||||
static name * g_semireducible = nullptr;
|
||||
static name * g_irreducible = nullptr;
|
||||
static name * g_parsing_only = nullptr;
|
||||
|
@ -220,6 +221,7 @@ void initialize_tokens() {
|
|||
g_unfold_c = new name("[unfold-c");
|
||||
g_coercion = new name("[coercion]");
|
||||
g_reducible = new name("[reducible]");
|
||||
g_quasireducible = new name("[quasireducible]");
|
||||
g_semireducible = new name("[semireducible]");
|
||||
g_irreducible = new name("[irreducible]");
|
||||
g_parsing_only = new name("[parsing-only]");
|
||||
|
@ -282,6 +284,7 @@ void finalize_tokens() {
|
|||
delete g_unfold_c;
|
||||
delete g_coercion;
|
||||
delete g_reducible;
|
||||
delete g_quasireducible;
|
||||
delete g_semireducible;
|
||||
delete g_irreducible;
|
||||
delete g_multiple_instances;
|
||||
|
@ -462,6 +465,7 @@ name const & get_priority_tk() { return *g_priority; }
|
|||
name const & get_unfold_c_tk() { return *g_unfold_c; }
|
||||
name const & get_coercion_tk() { return *g_coercion; }
|
||||
name const & get_reducible_tk() { return *g_reducible; }
|
||||
name const & get_quasireducible_tk() { return *g_quasireducible; }
|
||||
name const & get_semireducible_tk() { return *g_semireducible; }
|
||||
name const & get_irreducible_tk() { return *g_irreducible; }
|
||||
name const & get_multiple_instances_tk() { return *g_multiple_instances; }
|
||||
|
|
|
@ -103,6 +103,7 @@ name const & get_unfold_c_tk();
|
|||
name const & get_coercion_tk();
|
||||
name const & get_reducible_tk();
|
||||
name const & get_semireducible_tk();
|
||||
name const & get_quasireducible_tk();
|
||||
name const & get_irreducible_tk();
|
||||
name const & get_multiple_instances_tk();
|
||||
name const & get_attribute_tk();
|
||||
|
|
|
@ -21,27 +21,16 @@ struct reducible_entry {
|
|||
reducible_entry(reducible_status s, name const & n):m_status(s), m_name(n) {}
|
||||
};
|
||||
|
||||
struct reducible_state {
|
||||
name_set m_reducible_on;
|
||||
name_set m_reducible_off;
|
||||
void reducible_state::add(reducible_entry const & e) {
|
||||
m_status.insert(e.m_name, e.m_status);
|
||||
}
|
||||
|
||||
void add(reducible_entry const & e) {
|
||||
switch (e.m_status) {
|
||||
case reducible_status::Reducible:
|
||||
m_reducible_on.insert(e.m_name);
|
||||
m_reducible_off.erase(e.m_name);
|
||||
break;
|
||||
case reducible_status::Irreducible:
|
||||
m_reducible_on.erase(e.m_name);
|
||||
m_reducible_off.insert(e.m_name);
|
||||
break;
|
||||
case reducible_status::Semireducible:
|
||||
m_reducible_on.erase(e.m_name);
|
||||
m_reducible_off.erase(e.m_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
reducible_status reducible_state::get_status(name const & n) const {
|
||||
if (auto it = m_status.find(n))
|
||||
return *it;
|
||||
else
|
||||
return reducible_status::Semireducible;
|
||||
}
|
||||
|
||||
static name * g_class_name = nullptr;
|
||||
static std::string * g_key = nullptr;
|
||||
|
@ -106,46 +95,64 @@ environment set_reducible(environment const & env, name const & n, reducible_sta
|
|||
return reducible_ext::add_entry(env, get_dummy_ios(), reducible_entry(s, n), persistent);
|
||||
}
|
||||
|
||||
bool is_reducible_on(environment const & env, name const & n) {
|
||||
reducible_status get_reducible_status(environment const & env, name const & n) {
|
||||
reducible_state const & s = reducible_ext::get_state(env);
|
||||
return s.m_reducible_on.contains(n);
|
||||
return s.get_status(n);
|
||||
}
|
||||
|
||||
bool is_reducible_off(environment const & env, name const & n) {
|
||||
reducible_state const & s = reducible_ext::get_state(env);
|
||||
return s.m_reducible_off.contains(n);
|
||||
bool is_at_least_quasireducible(environment const & env, name const & n) {
|
||||
reducible_status r = get_reducible_status(env, n);
|
||||
return r == reducible_status::Reducible || r == reducible_status::Quasireducible;
|
||||
}
|
||||
|
||||
reducible_on_converter::reducible_on_converter(environment const & env, bool relax_main_opaque, bool memoize):
|
||||
unfold_reducible_converter::unfold_reducible_converter(environment const & env, bool relax_main_opaque, bool memoize):
|
||||
default_converter(env, relax_main_opaque, memoize) {
|
||||
m_reducible_on = reducible_ext::get_state(env).m_reducible_on;
|
||||
m_state = reducible_ext::get_state(env);
|
||||
}
|
||||
|
||||
bool reducible_on_converter::is_opaque(declaration const & d) const {
|
||||
if (!m_reducible_on.contains(d.get_name())) return true;
|
||||
bool unfold_reducible_converter::is_opaque(declaration const & d) const {
|
||||
auto r = m_state.get_status(d.get_name());
|
||||
if (r != reducible_status::Reducible) return true;
|
||||
return default_converter::is_opaque(d);
|
||||
}
|
||||
|
||||
reducible_off_converter::reducible_off_converter(environment const & env, bool relax_main_opaque, bool memoize):
|
||||
unfold_quasireducible_converter::unfold_quasireducible_converter(environment const & env, bool relax_main_opaque, bool memoize):
|
||||
default_converter(env, relax_main_opaque, memoize) {
|
||||
m_reducible_off = reducible_ext::get_state(env).m_reducible_off;
|
||||
m_state = reducible_ext::get_state(env);
|
||||
}
|
||||
|
||||
bool reducible_off_converter::is_opaque(declaration const & d) const {
|
||||
if (m_reducible_off.contains(d.get_name())) return true;
|
||||
bool unfold_quasireducible_converter::is_opaque(declaration const & d) const {
|
||||
auto r = m_state.get_status(d.get_name());
|
||||
if (r != reducible_status::Reducible && r != reducible_status::Quasireducible) return true;
|
||||
return default_converter::is_opaque(d);
|
||||
}
|
||||
|
||||
unfold_semireducible_converter::unfold_semireducible_converter(environment const & env, bool relax_main_opaque, bool memoize):
|
||||
default_converter(env, relax_main_opaque, memoize) {
|
||||
m_state = reducible_ext::get_state(env);
|
||||
}
|
||||
|
||||
bool unfold_semireducible_converter::is_opaque(declaration const & d) const {
|
||||
auto r = m_state.get_status(d.get_name());
|
||||
if (r == reducible_status::Irreducible) return true;
|
||||
return default_converter::is_opaque(d);
|
||||
}
|
||||
|
||||
std::unique_ptr<type_checker> mk_type_checker(environment const & env, name_generator const & ngen,
|
||||
bool relax_main_opaque, reducible_behavior rb,
|
||||
bool memoize) {
|
||||
if (rb == OpaqueIfNotReducibleOn) {
|
||||
switch (rb) {
|
||||
case UnfoldReducible:
|
||||
return std::unique_ptr<type_checker>(new type_checker(env, ngen,
|
||||
std::unique_ptr<converter>(new reducible_on_converter(env, relax_main_opaque, memoize))));
|
||||
} else {
|
||||
std::unique_ptr<converter>(new unfold_reducible_converter(env, relax_main_opaque, memoize))));
|
||||
case UnfoldQuasireducible:
|
||||
return std::unique_ptr<type_checker>(new type_checker(env, ngen,
|
||||
std::unique_ptr<converter>(new reducible_off_converter(env, relax_main_opaque, memoize))));
|
||||
std::unique_ptr<converter>(new unfold_quasireducible_converter(env, relax_main_opaque, memoize))));
|
||||
case UnfoldSemireducible:
|
||||
return std::unique_ptr<type_checker>(new type_checker(env, ngen,
|
||||
std::unique_ptr<converter>(new unfold_semireducible_converter(env, relax_main_opaque, memoize))));
|
||||
}
|
||||
lean_unreachable();
|
||||
}
|
||||
|
||||
std::unique_ptr<type_checker> mk_type_checker(environment const & env, bool relax_main_opaque, reducible_behavior rb) {
|
||||
|
@ -192,19 +199,11 @@ static int mk_reducible_checker_core(lua_State * L, reducible_behavior rb) {
|
|||
}
|
||||
|
||||
static int mk_reducible_type_checker(lua_State * L) {
|
||||
return mk_reducible_checker_core(L, OpaqueIfNotReducibleOn);
|
||||
return mk_reducible_checker_core(L, UnfoldReducible);
|
||||
}
|
||||
|
||||
static int mk_non_irreducible_type_checker(lua_State * L) {
|
||||
return mk_reducible_checker_core(L, OpaqueIfReducibleOff);
|
||||
}
|
||||
|
||||
static int is_reducible_on(lua_State * L) {
|
||||
return push_boolean(L, is_reducible_on(to_environment(L, 1), to_name_ext(L, 2)));
|
||||
}
|
||||
|
||||
static int is_reducible_off(lua_State * L) {
|
||||
return push_boolean(L, is_reducible_off(to_environment(L, 1), to_name_ext(L, 2)));
|
||||
return mk_reducible_checker_core(L, UnfoldSemireducible);
|
||||
}
|
||||
|
||||
static int set_reducible(lua_State * L) {
|
||||
|
@ -221,12 +220,11 @@ static int set_reducible(lua_State * L) {
|
|||
|
||||
void open_reducible(lua_State * L) {
|
||||
lua_newtable(L);
|
||||
SET_ENUM("On", reducible_status::Reducible);
|
||||
SET_ENUM("Off", reducible_status::Irreducible);
|
||||
SET_ENUM("None", reducible_status::Semireducible);
|
||||
SET_ENUM("Reducible", reducible_status::Reducible);
|
||||
SET_ENUM("QuasiReducible", reducible_status::Quasireducible);
|
||||
SET_ENUM("SemiReducible", reducible_status::Semireducible);
|
||||
SET_ENUM("Irreducible", reducible_status::Irreducible);
|
||||
lua_setglobal(L, "reducible_status");
|
||||
SET_GLOBAL_FUN(is_reducible_on, "is_reducible_on");
|
||||
SET_GLOBAL_FUN(is_reducible_off, "is_reducible_off");
|
||||
SET_GLOBAL_FUN(set_reducible, "set_reducible");
|
||||
SET_GLOBAL_FUN(mk_opaque_type_checker, "opaque_type_checker");
|
||||
SET_GLOBAL_FUN(mk_non_irreducible_type_checker, "non_irreducible_type_checker");
|
||||
|
|
|
@ -10,7 +10,7 @@ Author: Leonardo de Moura
|
|||
#include "kernel/default_converter.h"
|
||||
|
||||
namespace lean {
|
||||
enum class reducible_status { Reducible, Irreducible, Semireducible };
|
||||
enum class reducible_status { Reducible, Quasireducible, Semireducible, Irreducible };
|
||||
/** \brief Mark the definition named \c n as reducible or not.
|
||||
|
||||
The method throws an exception if \c n is
|
||||
|
@ -22,40 +22,52 @@ enum class reducible_status { Reducible, Irreducible, Semireducible };
|
|||
We should view it as a hint to automation.
|
||||
*/
|
||||
environment set_reducible(environment const & env, name const & n, reducible_status s, bool persistent = true);
|
||||
/** \brief Return true iff \c n was explicitly marked as reducible in the given environment.
|
||||
|
||||
\remark is_reducible_on(env, n) and is_reducible_off(env, n) cannot be simultaneously true,
|
||||
but both can be false (when set_reducible(env, n, None))
|
||||
*/
|
||||
bool is_reducible_on(environment const & env, name const & n);
|
||||
/** \brief Return true iff \c n was explicitly marked as not reducible in the given environment.
|
||||
reducible_status get_reducible_status(environment const & env, name const & n);
|
||||
|
||||
\see is_reducible_on
|
||||
*/
|
||||
bool is_reducible_off(environment const & env, name const & n);
|
||||
bool is_at_least_quasireducible(environment const & env, name const & n);
|
||||
|
||||
class reducible_on_converter : public default_converter {
|
||||
name_set m_reducible_on;
|
||||
struct reducible_entry;
|
||||
|
||||
class reducible_state {
|
||||
name_map<reducible_status> m_status;
|
||||
public:
|
||||
reducible_on_converter(environment const & env, bool relax_main_opaque, bool memoize);
|
||||
void add(reducible_entry const & e);
|
||||
reducible_status get_status(name const & n) const;
|
||||
};
|
||||
|
||||
/** \brief Unfold only constants marked as reducible */
|
||||
class unfold_reducible_converter : public default_converter {
|
||||
reducible_state m_state;
|
||||
public:
|
||||
unfold_reducible_converter(environment const & env, bool relax_main_opaque, bool memoize);
|
||||
virtual bool is_opaque(declaration const & d) const;
|
||||
};
|
||||
|
||||
class reducible_off_converter : public default_converter {
|
||||
name_set m_reducible_off;
|
||||
/** \brief Unfold only constants marked as reducible or quasireducible */
|
||||
class unfold_quasireducible_converter : public default_converter {
|
||||
reducible_state m_state;
|
||||
public:
|
||||
reducible_off_converter(environment const & env, bool relax_main_opaque, bool memoize);
|
||||
unfold_quasireducible_converter(environment const & env, bool relax_main_opaque, bool memoize);
|
||||
virtual bool is_opaque(declaration const & d) const;
|
||||
};
|
||||
|
||||
enum reducible_behavior { OpaqueIfNotReducibleOn, OpaqueIfReducibleOff };
|
||||
/** \brief Unfold only constants marked as reducible, quasireducible, or semireducible */
|
||||
class unfold_semireducible_converter : public default_converter {
|
||||
reducible_state m_state;
|
||||
public:
|
||||
unfold_semireducible_converter(environment const & env, bool relax_main_opaque, bool memoize);
|
||||
virtual bool is_opaque(declaration const & d) const;
|
||||
};
|
||||
|
||||
enum reducible_behavior { UnfoldReducible, UnfoldQuasireducible, UnfoldSemireducible };
|
||||
|
||||
/** \brief Create a type checker that takes the "reducibility" hints into account. */
|
||||
std::unique_ptr<type_checker> mk_type_checker(environment const & env, name_generator const & ngen,
|
||||
bool relax_main_opaque = true, reducible_behavior r = OpaqueIfReducibleOff,
|
||||
bool relax_main_opaque = true, reducible_behavior r = UnfoldSemireducible,
|
||||
bool memoize = true);
|
||||
std::unique_ptr<type_checker> mk_type_checker(environment const & env, bool relax_main_opaque,
|
||||
reducible_behavior r = OpaqueIfReducibleOff);
|
||||
reducible_behavior r = UnfoldSemireducible);
|
||||
|
||||
/** \brief Create a type checker that treats all definitions as opaque. */
|
||||
std::unique_ptr<type_checker> mk_opaque_type_checker(environment const & env, name_generator const & ngen);
|
||||
|
|
|
@ -117,7 +117,7 @@ struct class_instance_context {
|
|||
m_max_depth = get_class_instance_max_depth(ios.get_options());
|
||||
m_conservative = get_class_conservative(ios.get_options());
|
||||
if (m_conservative)
|
||||
m_tc = mk_type_checker(env, m_ngen.mk_child(), false, OpaqueIfNotReducibleOn);
|
||||
m_tc = mk_type_checker(env, m_ngen.mk_child(), false, UnfoldReducible);
|
||||
else
|
||||
m_tc = mk_type_checker(env, m_ngen.mk_child(), m_relax);
|
||||
options opts = m_ios.get_options();
|
||||
|
@ -350,7 +350,7 @@ constraint mk_class_instance_root_cnstr(std::shared_ptr<class_instance_context>
|
|||
new_cfg.m_discard = false;
|
||||
new_cfg.m_use_exceptions = false;
|
||||
new_cfg.m_pattern = true;
|
||||
new_cfg.m_conservative = C->m_conservative;
|
||||
new_cfg.m_kind = C->m_conservative ? unifier_kind::VeryConservative : unifier_kind::Liberal;
|
||||
|
||||
auto to_cnstrs_fn = [=](substitution const & subst, constraints const & cnstrs) -> constraints {
|
||||
substitution new_s = subst;
|
||||
|
@ -463,7 +463,7 @@ optional<expr> mk_class_instance(environment const & env, io_state const & ios,
|
|||
new_cfg.m_discard = true;
|
||||
new_cfg.m_use_exceptions = true;
|
||||
new_cfg.m_pattern = true;
|
||||
new_cfg.m_conservative = C->m_conservative;
|
||||
new_cfg.m_kind = C->m_conservative ? unifier_kind::VeryConservative : unifier_kind::Liberal;
|
||||
try {
|
||||
auto p = unify(env, 1, &c, C->m_ngen.mk_child(), substitution(), new_cfg).pull();
|
||||
lean_assert(p);
|
||||
|
|
|
@ -815,7 +815,7 @@ class rewrite_fn {
|
|||
|
||||
pair<expr, constraint> mk_class_instance_elaborator(expr const & type) {
|
||||
unifier_config cfg;
|
||||
cfg.m_conservative = true;
|
||||
cfg.m_kind = unifier_kind::VeryConservative;
|
||||
bool use_local_instances = true;
|
||||
bool is_strict = false;
|
||||
return ::lean::mk_class_instance_elaborator(m_env, m_ios, m_ctx, m_ngen.next(), optional<name>(),
|
||||
|
@ -861,7 +861,7 @@ class rewrite_fn {
|
|||
return unify_result();
|
||||
cs_seq.linearize(cs);
|
||||
unifier_config cfg;
|
||||
cfg.m_conservative = false;
|
||||
cfg.m_kind = unifier_kind::Liberal;
|
||||
cfg.m_discard = true;
|
||||
unify_result_seq rseq = unify(m_env, cs.size(), cs.data(), m_ngen.mk_child(), m_subst, cfg);
|
||||
if (auto p = rseq.pull()) {
|
||||
|
@ -1128,14 +1128,14 @@ class rewrite_fn {
|
|||
}
|
||||
}
|
||||
|
||||
class match_converter : public reducible_on_converter {
|
||||
class match_converter : public unfold_reducible_converter {
|
||||
public:
|
||||
match_converter(environment const & env, bool relax_main_opaque):
|
||||
reducible_on_converter(env, relax_main_opaque, true) {}
|
||||
unfold_reducible_converter(env, relax_main_opaque, true) {}
|
||||
virtual bool is_opaque(declaration const & d) const {
|
||||
if (is_projection(m_env, d.get_name()))
|
||||
return true;
|
||||
return reducible_on_converter::is_opaque(d);
|
||||
return unfold_reducible_converter::is_opaque(d);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1152,7 +1152,7 @@ class rewrite_fn {
|
|||
public:
|
||||
rewrite_fn(environment const & env, io_state const & ios, elaborate_fn const & elab, proof_state const & ps):
|
||||
m_env(env), m_ios(ios), m_elab(elab), m_ps(ps), m_ngen(ps.get_ngen()),
|
||||
m_tc(mk_type_checker(m_env, m_ngen.mk_child(), ps.relax_main_opaque(), OpaqueIfNotReducibleOn)),
|
||||
m_tc(mk_type_checker(m_env, m_ngen.mk_child(), ps.relax_main_opaque(), UnfoldQuasireducible)),
|
||||
m_matcher_tc(mk_matcher_tc()),
|
||||
m_unifier_tc(mk_type_checker(m_env, m_ngen.mk_child(), ps.relax_main_opaque())),
|
||||
m_mplugin(m_ios, *m_matcher_tc) {
|
||||
|
|
|
@ -76,10 +76,9 @@ unifier_config::unifier_config(bool use_exceptions, bool discard):
|
|||
m_max_steps(LEAN_DEFAULT_UNIFIER_MAX_STEPS),
|
||||
m_computation(LEAN_DEFAULT_UNIFIER_COMPUTATION),
|
||||
m_expensive_classes(LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES),
|
||||
m_discard(discard),
|
||||
m_conservative(LEAN_DEFAULT_UNIFIER_CONSERVATIVE) {
|
||||
m_discard(discard) {
|
||||
m_kind = unifier_kind::Liberal;
|
||||
m_pattern = false;
|
||||
m_cheap = false;
|
||||
m_ignore_context_check = false;
|
||||
}
|
||||
|
||||
|
@ -88,9 +87,11 @@ unifier_config::unifier_config(options const & o, bool use_exceptions, bool disc
|
|||
m_max_steps(get_unifier_max_steps(o)),
|
||||
m_computation(get_unifier_computation(o)),
|
||||
m_expensive_classes(get_unifier_expensive_classes(o)),
|
||||
m_discard(discard),
|
||||
m_conservative(get_unifier_conservative(o)) {
|
||||
m_cheap = false;
|
||||
m_discard(discard) {
|
||||
if (get_unifier_conservative(o))
|
||||
m_kind = unifier_kind::Conservative;
|
||||
else
|
||||
m_kind = unifier_kind::Liberal;
|
||||
m_pattern = false;
|
||||
m_ignore_context_check = false;
|
||||
}
|
||||
|
@ -425,21 +426,33 @@ struct unifier_fn {
|
|||
unifier_config const & cfg):
|
||||
m_env(env), m_ngen(ngen), m_subst(s), m_plugin(get_unifier_plugin(env)),
|
||||
m_config(cfg), m_num_steps(0) {
|
||||
if (m_config.m_cheap) {
|
||||
switch (m_config.m_kind) {
|
||||
case unifier_kind::Cheap:
|
||||
m_tc[0] = mk_opaque_type_checker(env, m_ngen.mk_child());
|
||||
m_tc[1] = m_tc[0];
|
||||
m_flex_rigid_tc = m_tc[0];
|
||||
m_config.m_computation = false;
|
||||
} else if (m_config.m_conservative) {
|
||||
m_tc[0] = mk_type_checker(env, m_ngen.mk_child(), false, OpaqueIfNotReducibleOn);
|
||||
break;
|
||||
case unifier_kind::VeryConservative:
|
||||
m_tc[0] = mk_type_checker(env, m_ngen.mk_child(), false, UnfoldReducible);
|
||||
m_tc[1] = m_tc[0];
|
||||
m_flex_rigid_tc = m_tc[0];
|
||||
m_config.m_computation = false;
|
||||
} else {
|
||||
break;
|
||||
case unifier_kind::Conservative:
|
||||
m_tc[0] = mk_type_checker(env, m_ngen.mk_child(), false, UnfoldQuasireducible);
|
||||
m_tc[1] = m_tc[0];
|
||||
m_flex_rigid_tc = m_tc[0];
|
||||
m_config.m_computation = false;
|
||||
break;
|
||||
case unifier_kind::Liberal:
|
||||
m_tc[0] = mk_type_checker(env, m_ngen.mk_child(), false);
|
||||
m_tc[1] = mk_type_checker(env, m_ngen.mk_child(), true);
|
||||
if (!cfg.m_computation)
|
||||
m_flex_rigid_tc = mk_type_checker(env, m_ngen.mk_child(), false, OpaqueIfNotReducibleOn);
|
||||
m_flex_rigid_tc = mk_type_checker(env, m_ngen.mk_child(), false, UnfoldQuasireducible);
|
||||
break;
|
||||
default:
|
||||
lean_unreachable();
|
||||
}
|
||||
m_next_assumption_idx = 0;
|
||||
m_next_cidx = 0;
|
||||
|
@ -1346,8 +1359,8 @@ struct unifier_fn {
|
|||
|
||||
justification a;
|
||||
bool relax = relax_main_opaque(c);
|
||||
if (!m_config.m_cheap && !m_config.m_conservative &&
|
||||
(m_config.m_computation || module::is_definition(m_env, d.get_name()) || is_reducible_on(m_env, d.get_name()))) {
|
||||
if (m_config.m_kind == unifier_kind::Liberal &&
|
||||
(m_config.m_computation || module::is_definition(m_env, d.get_name()) || is_at_least_quasireducible(m_env, d.get_name()))) {
|
||||
// add case_split for t =?= s
|
||||
a = mk_assumption_justification(m_next_assumption_idx);
|
||||
add_case_split(std::unique_ptr<case_split>(new delta_unfold_case_split(*this, j, c)));
|
||||
|
@ -1409,7 +1422,7 @@ struct unifier_fn {
|
|||
|
||||
optional<bool> _has_meta_args;
|
||||
|
||||
bool cheap() const { return u.m_config.m_cheap; }
|
||||
bool cheap() const { return u.m_config.m_kind == unifier_kind::Cheap; }
|
||||
bool pattern() const { return u.m_config.m_pattern; }
|
||||
|
||||
type_checker & tc() {
|
||||
|
@ -1898,7 +1911,7 @@ struct unifier_fn {
|
|||
*/
|
||||
bool use_flex_rigid_whnf_split(expr const & lhs, expr const & rhs) {
|
||||
lean_assert(is_meta(lhs));
|
||||
if (m_config.m_cheap || m_config.m_conservative)
|
||||
if (m_config.m_kind != unifier_kind::Liberal)
|
||||
return false;
|
||||
if (m_config.m_computation)
|
||||
return true; // if unifier.computation is true, we always consider the additional whnf split
|
||||
|
|
|
@ -32,6 +32,8 @@ unify_status unify_simple(substitution & s, expr const & lhs, expr const & rhs,
|
|||
unify_status unify_simple(substitution & s, level const & lhs, level const & rhs, justification const & j);
|
||||
unify_status unify_simple(substitution & s, constraint const & c);
|
||||
|
||||
enum class unifier_kind { Cheap, VeryConservative, Conservative, Liberal };
|
||||
|
||||
struct unifier_config {
|
||||
bool m_use_exceptions;
|
||||
unsigned m_max_steps;
|
||||
|
@ -40,20 +42,25 @@ struct unifier_config {
|
|||
// If m_discard is true, then constraints that cannot be solved are discarded (or incomplete methods are used)
|
||||
// If m_discard is false, unify returns the set of constraints that could not be handled.
|
||||
bool m_discard;
|
||||
// If m_conservative is true, then the following restrictions are imposed:
|
||||
// - All constants that are not marked as reducible as treated as
|
||||
// If m_mind == Conservative, then the following restrictions are imposed:
|
||||
// - All constants that are not at least marked as Quasireducible as treated as
|
||||
// opaque.
|
||||
// - Disables case-split on delta-delta constraints.
|
||||
// - Disables reduction case-split on flex-rigid constraints.
|
||||
// Default is m_conservative == false
|
||||
bool m_conservative;
|
||||
//
|
||||
// If m_kind == VeryConservative, then
|
||||
// - More restrictive than Conservative,
|
||||
// - All constants that are not at least marked as Reducible as treated as
|
||||
// opaque.
|
||||
//
|
||||
// If m_kind == Cheap is true, then expensive case-analysis is not performed (e.g., delta).
|
||||
// It is more restrictive than VeryConservative
|
||||
//
|
||||
// Default is Liberal
|
||||
unifier_kind m_kind;
|
||||
// If m_pattern is true, then we restrict the number of cases splits on
|
||||
// flex-rigid constraints that are *not* in the higher-order pattern case.
|
||||
bool m_pattern;
|
||||
// If m_cheap is true, then expensive case-analysis is not performed (e.g., delta).
|
||||
// It is more restrictive than m_conservative
|
||||
// Default is m_cheap == false
|
||||
bool m_cheap;
|
||||
// If m_ignore_context_check == true, then occurs-check is skipped.
|
||||
// Default is m_ignore_context_check == false
|
||||
bool m_ignore_context_check;
|
||||
|
|
21
tests/lean/quasireducible.lean
Normal file
21
tests/lean/quasireducible.lean
Normal file
|
@ -0,0 +1,21 @@
|
|||
constant g : nat → nat
|
||||
|
||||
definition f [reducible] := g
|
||||
|
||||
example (a : nat) (H : f a = a) : g a = a :=
|
||||
by rewrite H
|
||||
|
||||
attribute f [quasireducible]
|
||||
|
||||
example (a : nat) (H : f a = a) : g a = a :=
|
||||
by rewrite H -- error
|
||||
|
||||
attribute f [semireducible]
|
||||
|
||||
example (a : nat) (H : f a = a) : g a = a :=
|
||||
by rewrite H -- error
|
||||
|
||||
attribute f [reducible]
|
||||
|
||||
example (a : nat) (H : f a = a) : g a = a :=
|
||||
by rewrite H -- error
|
24
tests/lean/quasireducible.lean.expected.out
Normal file
24
tests/lean/quasireducible.lean.expected.out
Normal file
|
@ -0,0 +1,24 @@
|
|||
quasireducible.lean:11:11: error:invalid 'rewrite' tactic, rewrite step failed
|
||||
proof state:
|
||||
a : nat,
|
||||
H : f a = a
|
||||
⊢ g a = a
|
||||
quasireducible.lean:11:3: error: don't know how to synthesize placeholder
|
||||
a : nat,
|
||||
H : f a = a
|
||||
⊢ g a = a
|
||||
quasireducible.lean:11:3: error: failed to add declaration '14.1' to environment, value has metavariables
|
||||
λ (a : nat) (H : f a = a),
|
||||
?M_1
|
||||
quasireducible.lean:16:11: error:invalid 'rewrite' tactic, rewrite step failed
|
||||
proof state:
|
||||
a : nat,
|
||||
H : f a = a
|
||||
⊢ g a = a
|
||||
quasireducible.lean:16:3: error: don't know how to synthesize placeholder
|
||||
a : nat,
|
||||
H : f a = a
|
||||
⊢ g a = a
|
||||
quasireducible.lean:16:3: error: failed to add declaration '14.2' to environment, value has metavariables
|
||||
λ (a : nat) (H : f a = a),
|
||||
?M_1
|
|
@ -40,25 +40,4 @@ opaque definition w := 40
|
|||
assert(tc:whnf(w) == w)
|
||||
*)
|
||||
|
||||
(*
|
||||
local env = get_env()
|
||||
assert(is_reducible_on(env, "x"))
|
||||
assert(not is_reducible_on(env, "y"))
|
||||
assert(not is_reducible_on(env, "z"))
|
||||
assert(not is_reducible_off(env, "x"))
|
||||
assert(not is_reducible_off(env, "y"))
|
||||
assert(is_reducible_off(env, "z"))
|
||||
env = set_reducible(env, "x", reducible_status.Off)
|
||||
assert(not is_reducible_on(env, "x"))
|
||||
assert(is_reducible_off(env, "x"))
|
||||
env = set_reducible(env, "x", reducible_status.None)
|
||||
assert(not is_reducible_on(env, "x"))
|
||||
assert(not is_reducible_off(env, "x"))
|
||||
env = set_reducible(env, "x", reducible_status.On)
|
||||
assert(is_reducible_on(env, "x"))
|
||||
assert(not is_reducible_off(env, "x"))
|
||||
env = set_reducible(env, "x", reducible_status.Off)
|
||||
set_env(env)
|
||||
*)
|
||||
|
||||
eval [whnf] x
|
||||
|
|
Loading…
Reference in a new issue