feat(kernel): add global levels to environment

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-05-07 16:07:31 -07:00
parent 208384b5b6
commit 9c760132e2
6 changed files with 113 additions and 54 deletions

View file

@ -42,8 +42,8 @@ bool environment_id::is_descendant(environment_id const & id) const {
return false; return false;
} }
environment::environment(header const & h, environment_id const & ancestor, definitions const & d, extensions const & exts): environment::environment(header const & h, environment_id const & ancestor, definitions const & d, name_set const & g, extensions const & exts):
m_header(h), m_id(environment_id::mk_descendant(ancestor)), m_definitions(d), m_extensions(exts) {} m_header(h), m_id(environment_id::mk_descendant(ancestor)), m_definitions(d), m_global_levels(g), m_extensions(exts) {}
environment::environment(unsigned trust_lvl, bool proof_irrel, bool eta, bool impredicative): environment::environment(unsigned trust_lvl, bool proof_irrel, bool eta, bool impredicative):
environment(trust_lvl, proof_irrel, eta, impredicative, std::unique_ptr<normalizer_extension>(new noop_normalizer_extension())) environment(trust_lvl, proof_irrel, eta, impredicative, std::unique_ptr<normalizer_extension>(new noop_normalizer_extension()))
@ -78,7 +78,18 @@ environment environment::add(certified_definition const & d) const {
name const & n = d.get_definition().get_name(); name const & n = d.get_definition().get_name();
if (find(n)) if (find(n))
throw_already_declared(*this, n); throw_already_declared(*this, n);
return environment(m_header, m_id, insert(m_definitions, n, d.get_definition()), m_extensions); return environment(m_header, m_id, insert(m_definitions, n, d.get_definition()), m_global_levels, m_extensions);
}
environment environment::add_global_level(name const & n) const {
if (m_global_levels.contains(n))
throw_kernel_exception(*this,
"invalid global universe level declaration, environment already contains a universe level with the given name");
return environment(m_header, m_id, m_definitions, insert(m_global_levels, n), m_extensions);
}
bool environment::is_global_level(name const & n) const {
return m_global_levels.contains(n);
} }
environment environment::replace(certified_definition const & t) const { environment environment::replace(certified_definition const & t) const {
@ -94,7 +105,7 @@ environment environment::replace(certified_definition const & t) const {
throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the new declaration is not a theorem"); throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the new declaration is not a theorem");
if (ax->get_type() != t.get_definition().get_type()) if (ax->get_type() != t.get_definition().get_type())
throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the 'replace' operation can only be used when the axiom and theorem have the same type"); throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the 'replace' operation can only be used when the axiom and theorem have the same type");
return environment(m_header, m_id, insert(m_definitions, n, t.get_definition()), m_extensions); return environment(m_header, m_id, insert(m_definitions, n, t.get_definition()), m_global_levels, m_extensions);
} }
class extension_manager { class extension_manager {
@ -147,6 +158,6 @@ environment environment::update(unsigned id, std::shared_ptr<environment_extensi
if (id >= new_exts->size()) if (id >= new_exts->size())
new_exts->resize(id+1); new_exts->resize(id+1);
(*new_exts)[id] = ext; (*new_exts)[id] = ext;
return environment(m_header, m_id, m_definitions, new_exts); return environment(m_header, m_id, m_definitions, m_global_levels, new_exts);
} }
} }

View file

@ -101,9 +101,10 @@ class environment {
header m_header; header m_header;
environment_id m_id; environment_id m_id;
definitions m_definitions; definitions m_definitions;
name_set m_global_levels;
extensions m_extensions; extensions m_extensions;
environment(header const & h, environment_id const & id, definitions const & d, extensions const & ext); environment(header const & h, environment_id const & id, definitions const & d, name_set const & global_levels, extensions const & ext);
public: public:
environment(unsigned trust_lvl = 0, bool proof_irrel = true, bool eta = true, bool impredicative = true); environment(unsigned trust_lvl = 0, bool proof_irrel = true, bool eta = true, bool impredicative = true);
@ -137,6 +138,15 @@ public:
/** \brief Return definition with name \c n. Throws and exception if definition does not exist in this environment. */ /** \brief Return definition with name \c n. Throws and exception if definition does not exist in this environment. */
definition get(name const & n) const; definition get(name const & n) const;
/**
\brief Add a new global universe level with name \c n
This method throws an exception if the environment already contains a level named \c n.
*/
environment add_global_level(name const & n) const;
/** \brief Return true iff the environment has a universe level named \c n. */
bool is_global_level(name const & n) const;
/** /**
\brief Extends the current environment with the given (certified) definition \brief Extends the current environment with the given (certified) definition
This method throws an exception if: This method throws an exception if:

View file

@ -15,6 +15,7 @@ Author: Leonardo de Moura
#include "util/object_serializer.h" #include "util/object_serializer.h"
#include "util/interrupt.h" #include "util/interrupt.h"
#include "kernel/level.h" #include "kernel/level.h"
#include "kernel/environment.h"
namespace lean { namespace lean {
level_cell const & to_cell(level const & l) { level_cell const & to_cell(level const & l) {
@ -94,7 +95,7 @@ level const & imax_rhs(level const & l) { lean_assert(is_imax(l)); return to_max
struct level_param_core : public level_cell { struct level_param_core : public level_cell {
name m_id; name m_id;
level_param_core(level_kind k, name const & id): level_param_core(level_kind k, name const & id):
level_cell(k, hash(id.hash(), is_param ? 11u : 13u)), level_cell(k, hash(id.hash(), static_cast<unsigned>(k))),
m_id(id) { m_id(id) {
lean_assert(k == level_kind::Meta || k == level_kind::Param || k == level_kind::Global); lean_assert(k == level_kind::Meta || k == level_kind::Param || k == level_kind::Global);
} }
@ -427,28 +428,56 @@ bool has_meta(levels const & ls) { return std::any_of(ls.begin(), ls.end(), [](l
bool has_meta(level_cnstr const & c) { return has_meta(c.first) || has_meta(c.second); } bool has_meta(level_cnstr const & c) { return has_meta(c.first) || has_meta(c.second); }
bool has_meta(level_cnstrs const & cs) { return std::any_of(cs.begin(), cs.end(), [](level_cnstr const & c) { return has_meta(c); }); } bool has_meta(level_cnstrs const & cs) { return std::any_of(cs.begin(), cs.end(), [](level_cnstr const & c) { return has_meta(c); }); }
static optional<name> get_undef_param(level const & l, param_names const & ps) { void for_each_level_fn::apply(level const & l) {
if (!has_param(l)) if (!m_f(l))
return optional<name>(); return;
switch (l.kind()) {
case level_kind::Succ: apply(succ_of(l)); break;
case level_kind::Max: case level_kind::IMax: apply(to_max_core(l).m_lhs); apply(to_max_core(l).m_rhs); break;
case level_kind::Zero: case level_kind::Param:
case level_kind::Meta: case level_kind::Global: break;
}
}
level replace_level_fn::apply(level const & l) {
optional<level> r = m_f(l);
if (r)
return *r;
switch (l.kind()) { switch (l.kind()) {
case level_kind::Succ: case level_kind::Succ:
return get_undef_param(succ_of(l), ps); return update_succ(l, apply(succ_of(l)));
case level_kind::Max: case level_kind::IMax: case level_kind::Max: case level_kind::IMax:
if (auto it = get_undef_param(to_max_core(l).m_lhs, ps)) return update_max(l, apply(to_max_core(l).m_lhs), apply(to_max_core(l).m_rhs));
return it; case level_kind::Zero: case level_kind::Param: case level_kind::Meta: case level_kind::Global:
else return l;
return get_undef_param(to_max_core(l).m_rhs, ps);
case level_kind::Param:
if (std::find(ps.begin(), ps.end(), param_id(l)) == ps.end())
return optional<name>(param_id(l));
else
return optional<name>();
case level_kind::Zero: case level_kind::Meta: case level_kind::Global:
lean_unreachable(); // LCOV_EXCL_LINE
} }
lean_unreachable(); // LCOV_EXCL_LINE lean_unreachable(); // LCOV_EXCL_LINE
} }
optional<name> get_undef_param(level const & l, param_names const & ps) {
optional<name> r;
for_each(l, [&](level const & l) {
if (!has_param(l))
return false;
if (l.kind() == level_kind::Param && std::find(ps.begin(), ps.end(), param_id(l)) != ps.end())
r = param_id(l);
return true;
});
return r;
}
optional<name> get_undef_global(level const & l, environment const & env) {
optional<name> r;
for_each(l, [&](level const & l) {
if (!has_global(l))
return false;
if (l.kind() == level_kind::Global && env.is_global_level(global_id(l)))
r = global_id(l);
return true;
});
return r;
}
optional<name> get_undef_param(level_cnstrs const & cs, param_names const & ps) { optional<name> get_undef_param(level_cnstrs const & cs, param_names const & ps) {
for (auto const & c : cs) { for (auto const & c : cs) {
if (auto it = get_undef_param(c.first, ps)) if (auto it = get_undef_param(c.first, ps))
@ -459,6 +488,16 @@ optional<name> get_undef_param(level_cnstrs const & cs, param_names const & ps)
return optional<name>(); return optional<name>();
} }
optional<name> get_undef_global(level_cnstrs const & cs, environment const & env) {
for (auto const & c : cs) {
if (auto it = get_undef_global(c.first, env))
return it;
if (auto it = get_undef_global(c.second, env))
return it;
}
return optional<name>();
}
level update_succ(level const & l, level const & new_arg) { level update_succ(level const & l, level const & new_arg) {
if (is_eqp(succ_of(l), new_arg)) if (is_eqp(succ_of(l), new_arg))
return l; return l;
@ -475,21 +514,6 @@ level update_max(level const & l, level const & new_lhs, level const & new_rhs)
return mk_imax(new_lhs, new_rhs); return mk_imax(new_lhs, new_rhs);
} }
level replace_level_fn::apply(level const & l) {
optional<level> r = m_f(l);
if (r)
return *r;
switch (l.kind()) {
case level_kind::Succ:
return update_succ(l, apply(succ_of(l)));
case level_kind::Max: case level_kind::IMax:
return update_max(l, apply(to_max_core(l).m_lhs), apply(to_max_core(l).m_rhs));
case level_kind::Zero: case level_kind::Param: case level_kind::Meta: case level_kind::Global:
return l;
}
lean_unreachable(); // LCOV_EXCL_LINE
}
level instantiate(level const & l, param_names const & ps, levels const & ls) { level instantiate(level const & l, param_names const & ps, levels const & ls) {
lean_assert(length(ps) == length(ls)); lean_assert(length(ps) == length(ls));
return replace(l, [=](level const & l) { return replace(l, [=](level const & l) {

View file

@ -124,7 +124,6 @@ bool has_global(level const & l);
/** \brief Return true iff \c l contains parameters */ /** \brief Return true iff \c l contains parameters */
bool has_param(level const & l); bool has_param(level const & l);
/** /**
\brief Return a new level expression based on <tt>l == succ(arg)</tt>, where \c arg is replaced with \brief Return a new level expression based on <tt>l == succ(arg)</tt>, where \c arg is replaced with
\c new_arg. \c new_arg.
@ -169,17 +168,17 @@ bool has_global(level_cnstrs const & cs);
bool has_meta(level_cnstr const & c); bool has_meta(level_cnstr const & c);
bool has_meta(level_cnstrs const & cs); bool has_meta(level_cnstrs const & cs);
typedef list<name> param_names; /** \brief Functional for applying <tt>F</tt> to each level expressions. */
class for_each_level_fn {
std::function<bool(level const &)> m_f; // NOLINT
void apply(level const & l);
public:
template<typename F> for_each_level_fn(F const & f):m_f(f) {}
void operator()(level const & l) { return apply(l); }
};
template<typename F> void for_each(level const & l, F const & f) { return for_each_level_fn(f)(l); }
/** /** \brief Functional for applying <tt>F</tt> to the level expressions. */
\brief If \c cs contains a parameter that is not in \c param_names, then return it.
Otherwise, return none.
*/
optional<name> get_undef_param(level_cnstrs const & cs, param_names const & ps);
/**
\brief Functional for applying <tt>F</tt> to the level expressions.
*/
class replace_level_fn { class replace_level_fn {
std::function<optional<level>(level const &)> m_f; std::function<optional<level>(level const &)> m_f;
level apply(level const & l); level apply(level const & l);
@ -187,10 +186,21 @@ public:
template<typename F> replace_level_fn(F const & f):m_f(f) {} template<typename F> replace_level_fn(F const & f):m_f(f) {}
level operator()(level const & l) { return apply(l); } level operator()(level const & l) { return apply(l); }
}; };
template<typename F> level replace(level const & l, F const & f) { return replace_level_fn(f)(l); }
template<typename F> level replace(level const & l, F const & f) { typedef list<name> param_names;
return replace_level_fn(f)(l);
} /** \brief If \c l contains a global that is not in \c env, then return it. Otherwise, return none. */
optional<name> get_undef_global(level const & l, environment const & env);
/** \brief If \c l contains a parameter that is not in \c ps, then return it. Otherwise, return none. */
optional<name> get_undef_param(level const & l, param_names const & ps);
/** \brief If \c cs contains a global that is not in \c env, then return it. Otherwise, return none. */
optional<name> get_undef_global(level_cnstrs const & cs, environment const & env);
/** \brief If \c cs contains a parameter that is not in \c ps, then return it. Otherwise, return none. */
optional<name> get_undef_param(level_cnstrs const & cs, param_names const & ps);
/** /**
\brief Instantiate the universe level parameters \c ps occurring in \c l with the levels \c ls. \brief Instantiate the universe level parameters \c ps occurring in \c l with the levels \c ls.

View file

@ -75,6 +75,7 @@ struct type_checker::imp {
bool m_memoize; bool m_memoize;
// temp flag // temp flag
bool m_cnstrs_enabled; bool m_cnstrs_enabled;
param_names m_params;
imp(environment const & env, name_generator const & g, constraint_handler & h, std::unique_ptr<converter> && conv, bool memoize): imp(environment const & env, name_generator const & g, constraint_handler & h, std::unique_ptr<converter> && conv, bool memoize):
m_env(env), m_gen(g), m_chandler(h), m_conv(std::move(conv)), m_conv_ctx(*this), m_tc_ctx(*this), m_env(env), m_gen(g), m_chandler(h), m_conv(std::move(conv)), m_conv_ctx(*this), m_tc_ctx(*this),
@ -426,7 +427,10 @@ struct type_checker::imp {
} }
expr infer_type(expr const & e) { return infer_type_core(e, true); } expr infer_type(expr const & e) { return infer_type_core(e, true); }
expr check(expr const & e) { return infer_type_core(e, false); } expr check(expr const & e, param_names const & ps) {
flet<param_names> updt(m_params, ps);
return infer_type_core(e, false);
}
bool is_conv(expr const & t, expr const & s) { return m_conv->is_conv(t, s, m_conv_ctx); } bool is_conv(expr const & t, expr const & s) { return m_conv->is_conv(t, s, m_conv_ctx); }
bool is_def_eq(expr const & t, expr const & s) { return m_conv->is_def_eq(t, s, m_conv_ctx); } bool is_def_eq(expr const & t, expr const & s) { return m_conv->is_def_eq(t, s, m_conv_ctx); }
expr whnf(expr const & t) { return m_conv->whnf(t, m_conv_ctx); } expr whnf(expr const & t) { return m_conv->whnf(t, m_conv_ctx); }
@ -442,7 +446,7 @@ type_checker::type_checker(environment const & env, name_generator const & g, st
type_checker::~type_checker() {} type_checker::~type_checker() {}
expr type_checker::infer(expr const & t) { return m_ptr->infer_type(t); } expr type_checker::infer(expr const & t) { return m_ptr->infer_type(t); }
expr type_checker::check(expr const & t) { return m_ptr->check(t); } expr type_checker::check(expr const & t, param_names const & ps) { return m_ptr->check(t, ps); }
bool type_checker::is_conv(expr const & t, expr const & s) { return m_ptr->is_conv(t, s); } bool type_checker::is_conv(expr const & t, expr const & s) { return m_ptr->is_conv(t, s); }
bool type_checker::is_def_eq(expr const & t, expr const & s) { return m_ptr->is_def_eq(t, s); } bool type_checker::is_def_eq(expr const & t, expr const & s) { return m_ptr->is_def_eq(t, s); }
bool type_checker::is_prop(expr const & t) { return m_ptr->is_prop(t); } bool type_checker::is_prop(expr const & t) { return m_ptr->is_prop(t); }

View file

@ -84,7 +84,7 @@ public:
The result is meaningful only if the constraints sent to the The result is meaningful only if the constraints sent to the
constraint handler can be solved. constraint handler can be solved.
*/ */
expr check(expr const & t); expr check(expr const & t, param_names const & ps = param_names());
/** \brief Return true iff t is convertible to s. */ /** \brief Return true iff t is convertible to s. */
bool is_conv(expr const & t, expr const & s); bool is_conv(expr const & t, expr const & s);
/** \brief Return true iff t is definitionally equal to s. */ /** \brief Return true iff t is definitionally equal to s. */