2013-07-29 05:34:39 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-11-18 02:11:44 +00:00
|
|
|
#include <cstdlib>
|
2013-07-29 05:34:39 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
2013-10-26 18:07:06 +00:00
|
|
|
#include <tuple>
|
2013-12-29 01:31:35 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <string>
|
2013-12-09 22:56:48 +00:00
|
|
|
#include "util/thread.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "util/safe_arith.h"
|
2013-11-18 17:52:47 +00:00
|
|
|
#include "util/realpath.h"
|
2013-12-20 18:45:44 +00:00
|
|
|
#include "util/sstream.h"
|
2013-12-29 01:31:35 +00:00
|
|
|
#include "util/lean_path.h"
|
2013-11-19 19:24:02 +00:00
|
|
|
#include "kernel/for_each_fn.h"
|
2013-11-19 21:03:46 +00:00
|
|
|
#include "kernel/find_fn.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "kernel/kernel_exception.h"
|
|
|
|
#include "kernel/environment.h"
|
2013-11-12 04:29:53 +00:00
|
|
|
#include "kernel/threadsafe_environment.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "kernel/type_checker.h"
|
|
|
|
#include "kernel/normalizer.h"
|
2013-12-29 01:31:35 +00:00
|
|
|
#include "version.h"
|
2013-07-29 05:34:39 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-12-28 22:39:10 +00:00
|
|
|
class set_opaque_command : public neutral_object_cell {
|
|
|
|
name m_obj_name;
|
|
|
|
bool m_opaque;
|
|
|
|
public:
|
|
|
|
set_opaque_command(name const & n, bool opaque):m_obj_name(n), m_opaque(opaque) {}
|
|
|
|
virtual ~set_opaque_command() {}
|
|
|
|
virtual char const * keyword() const { return "SetOpaque"; }
|
|
|
|
virtual void write(serializer & s) const { s << "SetOpaque" << m_obj_name << m_opaque; }
|
|
|
|
};
|
|
|
|
static void read_set_opaque(environment const & env, io_state const &, deserializer & d) {
|
|
|
|
name n = read_name(d);
|
|
|
|
bool o = d.read_bool();
|
|
|
|
env->set_opaque(n, o);
|
|
|
|
}
|
|
|
|
static object_cell::register_deserializer_fn set_opaque_ds("SetOpaque", read_set_opaque);
|
|
|
|
|
2013-12-29 01:31:35 +00:00
|
|
|
class import_command : public neutral_object_cell {
|
|
|
|
std::string m_mod_name;
|
|
|
|
public:
|
|
|
|
import_command(std::string const & n):m_mod_name(n) {}
|
|
|
|
virtual ~import_command() {}
|
|
|
|
virtual char const * keyword() const { return "Import"; }
|
|
|
|
virtual void write(serializer & s) const { s << "Import" << m_mod_name; }
|
|
|
|
};
|
|
|
|
static void read_import(environment const & env, io_state const & ios, deserializer & d) {
|
|
|
|
std::string n = d.read_string();
|
|
|
|
env->import(n, ios);
|
|
|
|
}
|
|
|
|
static object_cell::register_deserializer_fn import_ds("Import", read_import);
|
|
|
|
|
|
|
|
class end_import_mark : public neutral_object_cell {
|
|
|
|
public:
|
|
|
|
end_import_mark() {}
|
|
|
|
virtual ~end_import_mark() {}
|
|
|
|
virtual char const * keyword() const { return "EndImport"; }
|
|
|
|
virtual void write(serializer &) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
// For Importing builtin modules
|
|
|
|
class begin_import_mark : public neutral_object_cell {
|
|
|
|
public:
|
|
|
|
begin_import_mark() {}
|
|
|
|
virtual ~begin_import_mark() {}
|
|
|
|
virtual char const * keyword() const { return "BeginImport"; }
|
|
|
|
virtual void write(serializer &) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool is_begin_import(object const & obj) {
|
|
|
|
return dynamic_cast<import_command const*>(obj.cell()) || dynamic_cast<begin_import_mark const*>(obj.cell());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_end_import(object const & obj) {
|
|
|
|
return dynamic_cast<end_import_mark const*>(obj.cell());
|
|
|
|
}
|
|
|
|
|
2013-11-18 02:11:44 +00:00
|
|
|
static name g_builtin_module("builtin_module");
|
2013-11-07 03:21:22 +00:00
|
|
|
class extension_factory {
|
2013-12-13 00:33:31 +00:00
|
|
|
std::vector<environment_cell::mk_extension> m_makers;
|
|
|
|
mutex m_makers_mutex;
|
2013-11-07 03:21:22 +00:00
|
|
|
public:
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned register_extension(environment_cell::mk_extension mk) {
|
2013-12-09 22:56:48 +00:00
|
|
|
lock_guard<mutex> lock(m_makers_mutex);
|
2013-11-07 03:21:22 +00:00
|
|
|
unsigned r = m_makers.size();
|
|
|
|
m_makers.push_back(mk);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
std::unique_ptr<environment_extension> mk(unsigned extid) {
|
2013-12-09 22:56:48 +00:00
|
|
|
lock_guard<mutex> lock(m_makers_mutex);
|
2013-11-07 03:21:22 +00:00
|
|
|
return m_makers[extid]();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static std::unique_ptr<extension_factory> g_extension_factory;
|
|
|
|
static extension_factory & get_extension_factory() {
|
|
|
|
if (!g_extension_factory)
|
|
|
|
g_extension_factory.reset(new extension_factory());
|
|
|
|
return *g_extension_factory;
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::register_extension(mk_extension mk) {
|
2013-11-07 03:21:22 +00:00
|
|
|
return get_extension_factory().register_extension(mk);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::env() const {
|
|
|
|
lean_assert(!m_this.expired()); // it is not possible to expire since it is a reference to this object
|
|
|
|
lean_assert(this == m_this.lock().get());
|
|
|
|
return environment(m_this.lock());
|
|
|
|
}
|
2013-08-04 23:07:37 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::parent() const {
|
|
|
|
lean_assert(has_parent());
|
|
|
|
return environment(m_parent);
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::mk_child() const {
|
|
|
|
return environment(m_this.lock(), true);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension & environment_cell::get_extension_core(unsigned extid) {
|
|
|
|
if (extid >= m_extensions.size())
|
|
|
|
m_extensions.resize(extid+1);
|
|
|
|
if (!m_extensions[extid]) {
|
|
|
|
std::unique_ptr<environment_extension> ext = get_extension_factory().mk(extid);
|
|
|
|
ext->m_extid = extid;
|
|
|
|
ext->m_env = this;
|
|
|
|
m_extensions[extid].swap(ext);
|
2013-08-16 22:09:26 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
return *(m_extensions[extid].get());
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension const & environment_cell::get_extension_core(unsigned extid) const {
|
|
|
|
return const_cast<environment_cell *>(this)->get_extension_core(extid);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::get_max_weight(expr const & e) {
|
|
|
|
unsigned w = 0;
|
|
|
|
auto proc = [&](expr const & c, unsigned) {
|
|
|
|
if (is_constant(c)) {
|
|
|
|
optional<object> obj = get_object_core(const_name(c));
|
|
|
|
if (obj)
|
|
|
|
w = std::max(w, obj->get_weight());
|
2013-08-16 22:09:26 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
for_each_fn<decltype(proc)> visitor(proc);
|
|
|
|
visitor(e);
|
|
|
|
return w;
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Throw exception if environment or its ancestors already have an object with the given name. */
|
|
|
|
void environment_cell::check_name_core(name const & n) {
|
|
|
|
if (has_parent())
|
|
|
|
m_parent->check_name_core(n);
|
|
|
|
if (m_object_dictionary.find(n) != m_object_dictionary.end())
|
|
|
|
throw already_declared_exception(env(), n);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
void environment_cell::check_name(name const & n) {
|
|
|
|
if (has_children())
|
|
|
|
throw read_only_environment_exception(env());
|
|
|
|
check_name_core(n);
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Store new named object inside internal data-structures */
|
|
|
|
void environment_cell::register_named_object(object const & new_obj) {
|
|
|
|
m_objects.push_back(new_obj);
|
|
|
|
m_object_dictionary.insert(std::make_pair(new_obj.get_name(), new_obj));
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Return the object named \c n in the environment or its
|
|
|
|
ancestors. Return null object if there is no object with the
|
|
|
|
given name.
|
|
|
|
*/
|
|
|
|
optional<object> environment_cell::get_object_core(name const & n) const {
|
|
|
|
auto it = m_object_dictionary.find(n);
|
|
|
|
if (it == m_object_dictionary.end()) {
|
2013-08-05 00:47:54 +00:00
|
|
|
if (has_parent())
|
2013-12-13 00:33:31 +00:00
|
|
|
return m_parent->get_object_core(n);
|
2013-08-05 00:47:54 +00:00
|
|
|
else
|
2013-12-13 00:33:31 +00:00
|
|
|
return none_object();
|
|
|
|
} else {
|
|
|
|
return some_object(it->second);
|
2013-08-13 22:13:54 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-13 22:13:54 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
object environment_cell::get_object(name const & n) const {
|
|
|
|
optional<object> obj = get_object_core(n);
|
|
|
|
if (obj) {
|
|
|
|
return *obj;
|
|
|
|
} else {
|
|
|
|
throw unknown_object_exception(env(), n);
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Return true if u >= v + k is implied by constraints
|
|
|
|
\pre is_uvar(u) && is_uvar(v)
|
|
|
|
*/
|
|
|
|
bool environment_cell::is_implied(level const & u, level const & v, int k) const {
|
|
|
|
lean_assert(is_uvar(u) && is_uvar(v));
|
|
|
|
if (u == v)
|
|
|
|
return k <= 0;
|
|
|
|
else
|
|
|
|
return std::any_of(m_constraints.begin(), m_constraints.end(),
|
|
|
|
[&](constraint const & c) { return std::get<0>(c) == u && std::get<1>(c) == v && std::get<2>(c) >= k; });
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Return true iff l1 >= l2 + k by asserted universe constraints. */
|
|
|
|
bool environment_cell::is_ge(level const & l1, level const & l2, int k) const {
|
|
|
|
if (l1 == l2)
|
|
|
|
return k <= 0;
|
|
|
|
switch (kind(l2)) {
|
|
|
|
case level_kind::UVar:
|
|
|
|
switch (kind(l1)) {
|
|
|
|
case level_kind::UVar: return is_implied(l1, l2, k);
|
|
|
|
case level_kind::Lift: return is_ge(lift_of(l1), l2, safe_sub(k, lift_offset(l1)));
|
|
|
|
case level_kind::Max: return std::any_of(max_begin_levels(l1), max_end_levels(l1), [&](level const & l) { return is_ge(l, l2, k); });
|
2013-09-04 15:53:00 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
case level_kind::Lift: return is_ge(l1, lift_of(l2), safe_add(k, lift_offset(l2)));
|
|
|
|
case level_kind::Max: return std::all_of(max_begin_levels(l2), max_end_levels(l2), [&](level const & l) { return is_ge(l1, l, k); });
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
2013-09-04 15:30:04 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Return true iff l1 >= l2 is implied by asserted universe constraints. */
|
|
|
|
bool environment_cell::is_ge(level const & l1, level const & l2) const {
|
|
|
|
if (has_parent())
|
|
|
|
return m_parent->is_ge(l1, l2);
|
|
|
|
else
|
|
|
|
return is_ge(l1, l2, 0);
|
|
|
|
}
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new universe variable */
|
|
|
|
level environment_cell::add_uvar_core(name const & n) {
|
|
|
|
check_name(n);
|
|
|
|
level r(n);
|
|
|
|
m_uvars.push_back(r);
|
|
|
|
return r;
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Add basic constraint u >= v + d, and all basic
|
|
|
|
constraints implied by transitivity.
|
2013-08-15 16:29:42 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
\pre is_uvar(u) && is_uvar(v)
|
|
|
|
*/
|
|
|
|
void environment_cell::add_constraint(level const & u, level const & v, int d) {
|
|
|
|
lean_assert(is_uvar(u) && is_uvar(v));
|
|
|
|
if (is_implied(u, v, d))
|
|
|
|
return; // redundant
|
|
|
|
buffer<constraint> to_add;
|
|
|
|
for (constraint const & c : m_constraints) {
|
|
|
|
if (std::get<0>(c) == v) {
|
|
|
|
level const & l3 = std::get<1>(c);
|
|
|
|
int u_l3_d = safe_add(d, std::get<2>(c));
|
|
|
|
if (!is_implied(u, l3, u_l3_d))
|
|
|
|
to_add.emplace_back(u, l3, u_l3_d);
|
2013-08-15 16:29:42 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
m_constraints.emplace_back(u, v, d);
|
|
|
|
for (constraint const & c : to_add) {
|
|
|
|
m_constraints.push_back(c);
|
2013-09-01 23:59:15 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-09-01 23:59:15 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Add all basic constraints implied by n >= l + k
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
A basic constraint is a constraint of the form u >= v + k
|
|
|
|
where u and v are universe variables.
|
|
|
|
*/
|
|
|
|
void environment_cell::add_constraints(level const & n, level const & l, int k) {
|
|
|
|
lean_assert(is_uvar(n));
|
|
|
|
switch (kind(l)) {
|
|
|
|
case level_kind::UVar: add_constraint(n, l, k); return;
|
|
|
|
case level_kind::Lift: add_constraints(n, lift_of(l), safe_add(k, lift_offset(l))); return;
|
|
|
|
case level_kind::Max: std::for_each(max_begin_levels(l), max_end_levels(l), [&](level const & l1) { add_constraints(n, l1, k); }); return;
|
|
|
|
}
|
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Add a new universe variable with constraint n >= l */
|
|
|
|
level environment_cell::add_uvar(name const & n, level const & l) {
|
|
|
|
if (has_parent())
|
|
|
|
throw kernel_exception(env(), "invalid universe declaration, universe variables can only be declared in top-level environments");
|
|
|
|
if (has_children())
|
|
|
|
throw read_only_environment_exception(env());
|
|
|
|
level r = add_uvar_core(n);
|
|
|
|
add_constraints(r, l, 0);
|
|
|
|
register_named_object(mk_uvar_decl(n, l));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Return the universe variable with given name. Throw an
|
|
|
|
exception if the environment and its ancestors do not
|
|
|
|
contain a universe variable named \c n.
|
|
|
|
*/
|
|
|
|
level environment_cell::get_uvar(name const & n) const {
|
|
|
|
if (has_parent()) {
|
|
|
|
return m_parent->get_uvar(n);
|
|
|
|
} else {
|
|
|
|
auto it = std::find_if(m_uvars.begin(), m_uvars.end(), [&](level const & l) { return uvar_name(l) == n; });
|
|
|
|
if (it == m_uvars.end())
|
|
|
|
throw unknown_universe_variable_exception(env(), n);
|
2013-11-18 02:11:44 +00:00
|
|
|
else
|
2013-12-13 00:33:31 +00:00
|
|
|
return *it;
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Initialize the set of universe variables with bottom
|
|
|
|
*/
|
|
|
|
void environment_cell::init_uvars() {
|
|
|
|
m_uvars.emplace_back();
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
The kernel should *not* accept expressions containing cached types.
|
|
|
|
Reason: Cached types may introduce unsoundness.
|
|
|
|
For example, in the environment env, the constant x may have type T.
|
|
|
|
Now suppose we are trying to add a new definition D that contains x,
|
|
|
|
and x is associated with a cached type T'. The cached type may allow
|
|
|
|
us to accept a definition that is type incorrect with respect to env.
|
|
|
|
*/
|
|
|
|
void environment_cell::check_no_cached_type(expr const & e) {
|
|
|
|
if (find(e, [](expr const & a) { return is_constant(a) && const_type(a); }))
|
|
|
|
throw kernel_exception(env(), "expression has a constant with a cached type, this is a bug in one of Lean tactics and/or solvers");
|
2013-11-17 02:35:17 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Throw an exception if \c t is not a type or type of \c
|
|
|
|
v is not convertible to \c t.
|
|
|
|
*/
|
|
|
|
void environment_cell::check_type(name const & n, expr const & t, expr const & v) {
|
|
|
|
m_type_checker->check_type(t);
|
2013-12-22 19:51:38 +00:00
|
|
|
expr v_t = m_type_checker->check(v);
|
2013-12-13 00:33:31 +00:00
|
|
|
if (!m_type_checker->is_convertible(v_t, t))
|
|
|
|
throw def_type_mismatch_exception(env(), n, t, v, v_t);
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Throw exception if it is not a valid new definition */
|
|
|
|
void environment_cell::check_new_definition(name const & n, expr const & t, expr const & v) {
|
|
|
|
check_name(n);
|
|
|
|
check_type(n, t, v);
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new builtin value to this environment */
|
|
|
|
void environment_cell::add_builtin(expr const & v) {
|
|
|
|
if (!is_value(v))
|
|
|
|
throw invalid_builtin_value_declaration(env(), v);
|
|
|
|
name const & n = to_value(v).get_name();
|
|
|
|
check_name(n);
|
|
|
|
name const & u = to_value(v).get_unicode_name();
|
|
|
|
check_name(u);
|
|
|
|
register_named_object(mk_builtin(v));
|
|
|
|
if (u != n) {
|
|
|
|
add_definition(u, to_value(v).get_type(), mk_constant(n), false);
|
|
|
|
}
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new builtin value set to this environment */
|
|
|
|
void environment_cell::add_builtin_set(expr const & r) {
|
|
|
|
if (!is_value(r))
|
|
|
|
throw invalid_builtin_value_declaration(env(), r);
|
|
|
|
check_name(to_value(r).get_name());
|
|
|
|
register_named_object(mk_builtin_set(r));
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new definition. */
|
|
|
|
void environment_cell::add_definition(name const & n, expr const & t, expr const & v, bool opaque) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_new_definition(n, t, v);
|
|
|
|
unsigned w = get_max_weight(v) + 1;
|
2013-12-28 22:39:10 +00:00
|
|
|
register_named_object(mk_definition(n, t, v, w));
|
|
|
|
if (opaque)
|
|
|
|
set_opaque(n, opaque);
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
2013-08-09 22:33:34 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Add new definition.
|
|
|
|
The type of the new definition is the type of \c v.
|
|
|
|
*/
|
|
|
|
void environment_cell::add_definition(name const & n, expr const & v, bool opaque) {
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_name(n);
|
2013-12-22 19:51:38 +00:00
|
|
|
expr v_t = m_type_checker->check(v);
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned w = get_max_weight(v) + 1;
|
2013-12-28 22:39:10 +00:00
|
|
|
register_named_object(mk_definition(n, v_t, v, w));
|
|
|
|
if (opaque)
|
|
|
|
set_opaque(n, opaque);
|
2013-08-09 22:33:34 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new theorem. */
|
|
|
|
void environment_cell::add_theorem(name const & n, expr const & t, expr const & v) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_new_definition(n, t, v);
|
|
|
|
register_named_object(mk_theorem(n, t, v));
|
2013-08-09 22:33:34 +00:00
|
|
|
}
|
|
|
|
|
2013-12-20 18:45:44 +00:00
|
|
|
void environment_cell::set_opaque(name const & n, bool opaque) {
|
|
|
|
auto obj = find_object(n);
|
|
|
|
if (!obj || !obj->is_definition())
|
|
|
|
throw kernel_exception(env(), sstream() << "set_opaque failed, '" << n << "' is not a definition");
|
|
|
|
obj->set_opaque(opaque);
|
2013-12-28 22:39:10 +00:00
|
|
|
add_neutral_object(new set_opaque_command(n, opaque));
|
2013-12-20 18:45:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new axiom. */
|
|
|
|
void environment_cell::add_axiom(name const & n, expr const & t) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_name(n);
|
|
|
|
m_type_checker->check_type(t);
|
|
|
|
register_named_object(mk_axiom(n, t));
|
2013-08-05 00:47:54 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new variable. */
|
|
|
|
void environment_cell::add_var(name const & n, expr const & t) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_name(n);
|
|
|
|
m_type_checker->check_type(t);
|
|
|
|
register_named_object(mk_var_decl(n, t));
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
void environment_cell::add_neutral_object(neutral_object_cell * o) {
|
|
|
|
m_objects.push_back(mk_neutral(o));
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::get_num_objects(bool local) const {
|
|
|
|
if (local || !has_parent()) {
|
|
|
|
return m_objects.size();
|
|
|
|
} else {
|
|
|
|
return m_objects.size() + m_parent->get_num_objects(false);
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
object const & environment_cell::get_object(unsigned i, bool local) const {
|
|
|
|
if (local || !has_parent()) {
|
|
|
|
return m_objects[i];
|
|
|
|
} else {
|
|
|
|
unsigned num_parent_objects = m_parent->get_num_objects(false);
|
|
|
|
if (i >= num_parent_objects)
|
|
|
|
return m_objects[i - num_parent_objects];
|
|
|
|
else
|
|
|
|
return m_parent->get_object(i, false);
|
|
|
|
}
|
2013-08-06 19:24:20 +00:00
|
|
|
}
|
|
|
|
|
2013-12-22 19:51:38 +00:00
|
|
|
expr environment_cell::type_check(expr const & e, context const & ctx) const {
|
|
|
|
return m_type_checker->check(e, ctx);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
expr environment_cell::infer_type(expr const & e, context const & ctx) const {
|
|
|
|
return m_type_checker->infer_type(e, ctx);
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
refactor(kernel): add unfold_opaque flag to normalizer, modify how type checker uses the opaque flag, remove hidden_defs, and mark most builtin definitions as opaque
After this commit, in the type checker, when checking convertability, we first compute a normal form without expanding opaque terms.
If the terms are convertible, then we are done, and saved a lot of time by not expanding unnecessary definitions.
If they are not, instead of throwing an error, we try again expanding the opaque terms.
This seems to be the best of both worlds.
The opaque flag is a hint for the type checker, but it would never prevent us from type checking a valid term.
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2013-12-20 20:47:36 +00:00
|
|
|
expr environment_cell::normalize(expr const & e, context const & ctx, bool unfold_opaque) const {
|
|
|
|
return m_type_checker->get_normalizer()(e, ctx, unfold_opaque);
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Display universal variable constraints and objects stored in this environment and its parents. */
|
|
|
|
void environment_cell::display(std::ostream & out) const {
|
|
|
|
if (has_parent())
|
|
|
|
m_parent->display(out);
|
|
|
|
for (object const & obj : m_objects) {
|
|
|
|
if (obj.has_name()) {
|
|
|
|
out << obj.keyword() << " " << obj.get_name() << "\n";
|
|
|
|
}
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::already_imported(name const & n) const {
|
|
|
|
if (m_imported_modules.find(n) != m_imported_modules.end())
|
|
|
|
return true;
|
|
|
|
else if (has_parent())
|
|
|
|
return m_parent->already_imported(n);
|
|
|
|
else
|
|
|
|
return false;
|
2013-08-15 01:16:11 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::mark_imported_core(name n) {
|
|
|
|
if (already_imported(n)) {
|
|
|
|
return false;
|
|
|
|
} else if (has_children()) {
|
|
|
|
throw read_only_environment_exception(env());
|
|
|
|
} else {
|
|
|
|
m_imported_modules.insert(n);
|
|
|
|
return true;
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::mark_imported(char const * fname) {
|
|
|
|
return mark_imported_core(name(realpath(fname)));
|
2013-08-17 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
2013-12-29 01:31:35 +00:00
|
|
|
void environment_cell::auxiliary_section(std::function<void()> fn) {
|
|
|
|
add_neutral_object(new begin_import_mark());
|
|
|
|
try {
|
|
|
|
fn();
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
} catch (...) {
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void environment_cell::import_builtin(char const * id, std::function<void()> fn) {
|
|
|
|
if (mark_imported_core(name(g_builtin_module, id))) {
|
|
|
|
auxiliary_section(fn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char const * g_olean_header = "oleanfile";
|
|
|
|
static char const * g_olean_end_file = "EndFile";
|
|
|
|
void environment_cell::export_objects(std::string const & fname) {
|
|
|
|
std::ofstream out(fname);
|
|
|
|
serializer s(out);
|
|
|
|
s << g_olean_header << LEAN_VERSION_MAJOR << LEAN_VERSION_MINOR;
|
|
|
|
auto it = begin_objects();
|
|
|
|
auto end = end_objects();
|
|
|
|
unsigned num_imports = 0;
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
object const & obj = *it;
|
|
|
|
if (dynamic_cast<import_command const*>(obj.cell())) {
|
|
|
|
if (num_imports == 0)
|
|
|
|
obj.write(s);
|
|
|
|
num_imports++;
|
|
|
|
} else if (dynamic_cast<end_import_mark const*>(obj.cell())) {
|
|
|
|
lean_assert(num_imports > 0);
|
|
|
|
num_imports--;
|
|
|
|
} else if (dynamic_cast<begin_import_mark const*>(obj.cell())) {
|
|
|
|
num_imports++;
|
|
|
|
} else if (num_imports == 0) {
|
|
|
|
obj.write(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s << g_olean_end_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool environment_cell::import(std::string const & fname, io_state const & ios) {
|
|
|
|
std::string full_fname = realpath(find_file(fname, {".olean"}).c_str());
|
|
|
|
if (mark_imported_core(full_fname)) {
|
|
|
|
std::ifstream in(fname);
|
|
|
|
deserializer d(in);
|
|
|
|
std::string header;
|
|
|
|
d >> header;
|
|
|
|
if (header != g_olean_header)
|
|
|
|
throw exception(sstream() << "file '" << full_fname << "' does not seem to be a valid object Lean file");
|
|
|
|
unsigned major, minor;
|
|
|
|
// Perhaps we should enforce the right version number
|
|
|
|
d >> major >> minor;
|
|
|
|
try {
|
|
|
|
add_neutral_object(new import_command(fname));
|
|
|
|
while (true) {
|
|
|
|
std::string k;
|
|
|
|
d >> k;
|
|
|
|
if (k == g_olean_end_file) {
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
read_object(env(), ios, k, d);
|
|
|
|
}
|
|
|
|
} catch (...) {
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2013-08-08 23:12:46 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::environment_cell():
|
|
|
|
m_num_children(0) {
|
|
|
|
init_uvars();
|
2013-08-08 23:12:46 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::environment_cell(std::shared_ptr<environment_cell> const & parent):
|
|
|
|
m_num_children(0),
|
|
|
|
m_parent(parent) {
|
|
|
|
parent->inc_children();
|
2013-09-01 23:59:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::~environment_cell() {
|
|
|
|
if (m_parent)
|
|
|
|
m_parent->dec_children();
|
2013-09-01 23:59:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment::environment():
|
2013-12-24 19:32:09 +00:00
|
|
|
m_ptr(std::make_shared<environment_cell>()) {
|
2013-12-13 00:33:31 +00:00
|
|
|
m_ptr->m_this = m_ptr;
|
|
|
|
m_ptr->m_type_checker.reset(new type_checker(*this));
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
2013-08-24 23:11:35 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
// used when creating a new child environment
|
|
|
|
environment::environment(std::shared_ptr<environment_cell> const & parent, bool):
|
2013-12-24 19:32:09 +00:00
|
|
|
m_ptr(std::make_shared<environment_cell>(parent)) {
|
2013-12-13 00:33:31 +00:00
|
|
|
m_ptr->m_this = m_ptr;
|
|
|
|
m_ptr->m_type_checker.reset(new type_checker(*this));
|
2013-11-18 02:11:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
// used when creating a reference to the parent environment
|
|
|
|
environment::environment(std::shared_ptr<environment_cell> const & ptr):
|
|
|
|
m_ptr(ptr) {
|
2013-11-18 02:11:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment::ro_environment(environment const & env):
|
|
|
|
m_ptr(env.m_ptr) {
|
2013-11-07 19:29:01 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment::ro_environment(weak_ref const & r) {
|
|
|
|
if (r.expired())
|
|
|
|
throw exception("weak reference to environment object has expired (i.e., the environment has been deleted)");
|
|
|
|
m_ptr = r.lock();
|
2013-11-07 03:21:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension::environment_extension():
|
2013-11-07 03:21:22 +00:00
|
|
|
m_env(nullptr),
|
|
|
|
m_extid(0) {
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension::~environment_extension() {
|
2013-11-07 03:21:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension const * environment_extension::get_parent_core() const {
|
2013-11-07 03:21:22 +00:00
|
|
|
if (m_env == nullptr)
|
|
|
|
return nullptr;
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell * parent = m_env->m_parent.get();
|
2013-11-07 03:21:22 +00:00
|
|
|
while (parent) {
|
|
|
|
if (m_extid < parent->m_extensions.size()) {
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension * ext = parent->m_extensions[m_extid].get();
|
2013-11-07 03:21:22 +00:00
|
|
|
if (ext)
|
|
|
|
return ext;
|
|
|
|
}
|
|
|
|
parent = parent->m_parent.get();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-11-12 04:29:53 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
read_only_shared_environment::read_only_shared_environment(ro_environment const & env):
|
2013-11-12 04:29:53 +00:00
|
|
|
m_env(env),
|
2013-12-13 00:33:31 +00:00
|
|
|
m_lock(const_cast<environment_cell*>(m_env.m_ptr.get())->m_mutex) {
|
2013-11-12 04:29:53 +00:00
|
|
|
}
|
2013-12-12 19:19:09 +00:00
|
|
|
read_only_shared_environment::~read_only_shared_environment() {}
|
2013-11-12 04:29:53 +00:00
|
|
|
|
2013-12-12 19:19:09 +00:00
|
|
|
read_write_shared_environment::read_write_shared_environment(environment const & env):
|
2013-11-12 04:29:53 +00:00
|
|
|
m_env(env),
|
|
|
|
m_lock(m_env.m_ptr->m_mutex) {
|
|
|
|
}
|
2013-12-12 19:19:09 +00:00
|
|
|
read_write_shared_environment::~read_write_shared_environment() {}
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|