2013-08-04 23:07:37 +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-09-13 03:04:10 +00:00
|
|
|
#include "util/test.h"
|
|
|
|
#include "util/exception.h"
|
|
|
|
#include "util/trace.h"
|
|
|
|
#include "kernel/kernel_exception.h"
|
|
|
|
#include "kernel/environment.h"
|
|
|
|
#include "kernel/type_checker.h"
|
|
|
|
#include "kernel/builtin.h"
|
|
|
|
#include "kernel/normalizer.h"
|
|
|
|
#include "kernel/abstract.h"
|
2013-10-01 01:16:13 +00:00
|
|
|
#include "kernel/printer.h"
|
2013-09-13 15:55:09 +00:00
|
|
|
#include "library/arith/arith.h"
|
2013-09-13 16:06:46 +00:00
|
|
|
#include "library/all/all.h"
|
2013-08-04 23:07:37 +00:00
|
|
|
using namespace lean;
|
|
|
|
|
|
|
|
static void tst1() {
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
level u = env->add_uvar("u", level() + 1);
|
|
|
|
level w = env->add_uvar("w", u + 1);
|
|
|
|
lean_assert(!env->has_children());
|
|
|
|
lean_assert(!env->has_parent());
|
2013-08-04 23:07:37 +00:00
|
|
|
{
|
2013-12-13 00:33:31 +00:00
|
|
|
environment child = env->mk_child();
|
|
|
|
lean_assert(child->is_ge(w, u));
|
|
|
|
lean_assert(child->is_ge(w, level() + 2));
|
|
|
|
lean_assert(env->is_ge(w, level() + 2));
|
|
|
|
lean_assert(env->has_children());
|
|
|
|
lean_assert(child->has_parent());
|
|
|
|
lean_assert(!env->has_parent());
|
2013-08-04 23:07:37 +00:00
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
level o = env->add_uvar("o", w + 1);
|
2013-08-04 23:07:37 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 03:52:14 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-04 23:07:37 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << "tst1 checkpoint" << std::endl;
|
2013-12-13 00:33:31 +00:00
|
|
|
level o = env->add_uvar("o", w + 1);
|
|
|
|
lean_assert(!env->has_children());
|
2013-08-16 22:09:26 +00:00
|
|
|
std::cout << env;
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static environment mk_child() {
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
level u = env->add_uvar("u", level() + 1);
|
|
|
|
return env->mk_child();
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tst2() {
|
|
|
|
environment child = mk_child();
|
2013-12-13 00:33:31 +00:00
|
|
|
lean_assert(child->has_parent());
|
|
|
|
lean_assert(!child->has_children());
|
|
|
|
environment parent = child->parent();
|
2013-08-16 22:09:26 +00:00
|
|
|
std::cout << parent;
|
2013-12-13 00:33:31 +00:00
|
|
|
lean_assert(parent->has_children());
|
|
|
|
std::cout << "uvar: " << child->get_uvar("u") << "\n";
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-05 03:52:14 +00:00
|
|
|
static void tst3() {
|
2013-10-22 21:02:45 +00:00
|
|
|
std::cout << "tst3\n";
|
2013-09-04 15:30:04 +00:00
|
|
|
environment env = mk_toplevel();
|
2013-08-05 03:52:14 +00:00
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, Const("a"));
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, iAdd(iVal(1), iVal(2)));
|
2013-08-13 22:13:54 +00:00
|
|
|
std::cout << env << "\n";
|
2013-08-06 18:27:14 +00:00
|
|
|
expr t = iAdd(Const("a"), iVal(1));
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << t << " --> " << normalize(t, env) << "\n";
|
2013-08-06 18:27:14 +00:00
|
|
|
lean_assert(normalize(t, env) == iVal(4));
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("b", Int, iMul(iVal(2), Const("a")));
|
2013-08-06 18:27:14 +00:00
|
|
|
std::cout << "b --> " << normalize(Const("b"), env) << "\n";
|
|
|
|
lean_assert(normalize(Const("b"), env) == iVal(6));
|
2013-08-05 03:52:14 +00:00
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("c", mk_arrow(Int, Int), Const("a"));
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, iVal(10));
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
environment c_env = env->mk_child();
|
2013-08-05 03:52:14 +00:00
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("c", Int, Const("a"));
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
2013-08-06 18:27:14 +00:00
|
|
|
lean_assert(normalize(Const("b"), env) == iVal(6));
|
|
|
|
lean_assert(normalize(Const("b"), c_env) == iVal(6));
|
2013-12-13 00:33:31 +00:00
|
|
|
c_env->add_definition("c", Int, Const("a"));
|
2013-08-06 18:27:14 +00:00
|
|
|
lean_assert(normalize(Const("c"), c_env) == iVal(3));
|
2013-08-05 03:52:14 +00:00
|
|
|
try {
|
2013-08-06 18:27:14 +00:00
|
|
|
expr r = normalize(Const("c"), env);
|
|
|
|
lean_assert(r == iVal(3));
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
|
|
|
std::cout << "expected error: " << ex.what() << std::endl;
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
2013-08-05 22:47:58 +00:00
|
|
|
std::cout << "end tst3" << std::endl;
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-08-05 17:33:05 +00:00
|
|
|
static void tst4() {
|
2013-10-22 21:02:45 +00:00
|
|
|
std::cout << "tst4\n";
|
2013-09-02 23:09:55 +00:00
|
|
|
environment env = mk_toplevel();
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, iVal(1), true); // add opaque definition
|
2013-08-06 18:27:14 +00:00
|
|
|
expr t = iAdd(Const("a"), iVal(1));
|
2013-08-05 17:33:05 +00:00
|
|
|
std::cout << t << " --> " << normalize(t, env) << "\n";
|
|
|
|
lean_assert(normalize(t, env) == t);
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("b", Int, iAdd(Const("a"), iVal(1)));
|
2013-08-06 18:27:14 +00:00
|
|
|
expr t2 = iSub(Const("b"), iVal(9));
|
2013-08-05 17:33:05 +00:00
|
|
|
std::cout << t2 << " --> " << normalize(t2, env) << "\n";
|
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
|
|
|
lean_assert_eq(normalize(t2, env, context()),
|
|
|
|
iSub(iAdd(Const("a"), iVal(1)), iVal(9)));
|
2013-08-05 17:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tst5() {
|
2013-09-04 15:30:04 +00:00
|
|
|
environment env = mk_toplevel();
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, iVal(1), true); // add opaque definition
|
2013-08-05 17:33:05 +00:00
|
|
|
try {
|
2013-12-22 19:51:38 +00:00
|
|
|
std::cout << type_check(iAdd(Const("a"), Int), env) << "\n";
|
2013-08-05 17:33:05 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 17:33:05 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-05 20:16:20 +00:00
|
|
|
static void tst6() {
|
2013-09-04 15:30:04 +00:00
|
|
|
environment env = mk_toplevel();
|
2013-12-13 00:33:31 +00:00
|
|
|
level u = env->add_uvar("u", level() + 1);
|
|
|
|
level w = env->add_uvar("w", u + 1);
|
|
|
|
env->add_var("f", mk_arrow(Type(u), Type(u)));
|
2013-08-06 18:27:14 +00:00
|
|
|
expr t = Const("f")(Int);
|
2013-12-22 19:51:38 +00:00
|
|
|
std::cout << "type of " << t << " is " << type_check(t, env) << "\n";
|
2013-08-05 20:16:20 +00:00
|
|
|
try {
|
2013-12-22 19:51:38 +00:00
|
|
|
type_check(Const("f")(Type(w)), env);
|
2013-08-05 20:16:20 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 20:16:20 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
|
|
|
try {
|
2013-12-22 19:51:38 +00:00
|
|
|
type_check(Const("f")(Type(u)), env);
|
2013-08-05 20:16:20 +00:00
|
|
|
lean_unreachable();
|
2013-08-05 22:47:58 +00:00
|
|
|
} catch (exception const & ex) {
|
2013-08-05 20:16:20 +00:00
|
|
|
std::cout << "expected error: " << ex.what() << "\n";
|
|
|
|
}
|
2013-08-06 18:27:14 +00:00
|
|
|
t = Const("f")(Type());
|
2013-12-22 19:51:38 +00:00
|
|
|
std::cout << "type of " << t << " is " << type_check(t, env) << "\n";
|
|
|
|
std::cout << type_check(mk_arrow(Type(u), Type(w)), env) << "\n";
|
|
|
|
lean_assert(type_check(mk_arrow(Type(u), Type(w)), env) == Type(max(u+1, w+1)));
|
|
|
|
std::cout << type_check(mk_arrow(Int, Int), env) << "\n";
|
|
|
|
lean_assert(type_check(mk_arrow(Int, Int), env) == Type());
|
2013-08-05 20:16:20 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 03:06:07 +00:00
|
|
|
static void tst7() {
|
|
|
|
environment env = mk_toplevel();
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_var("a", Int);
|
|
|
|
env->add_var("b", Int);
|
2013-08-06 18:27:14 +00:00
|
|
|
expr t = If(Int, True, Const("a"), Const("b"));
|
2013-08-06 03:06:07 +00:00
|
|
|
std::cout << t << " --> " << normalize(t, env) << "\n";
|
2013-12-22 19:51:38 +00:00
|
|
|
std::cout << type_check(t, env) << "\n";
|
2013-08-06 03:06:07 +00:00
|
|
|
std::cout << "Environment\n" << env;
|
|
|
|
}
|
|
|
|
|
2013-08-15 16:29:42 +00:00
|
|
|
static void tst8() {
|
|
|
|
environment env;
|
|
|
|
std::cout << "=======================\n";
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_var("a", Type());
|
|
|
|
env->add_var("b", Type());
|
|
|
|
environment env2 = env->mk_child();
|
|
|
|
env2->add_var("c", Type());
|
|
|
|
env2->add_var("d", Type());
|
|
|
|
env2->add_var("e", Type());
|
2013-08-15 16:29:42 +00:00
|
|
|
unsigned counter = 0;
|
2013-12-13 00:33:31 +00:00
|
|
|
std::for_each(env2->begin_local_objects(), env2->end_local_objects(), [&](object const & obj) { std::cout << obj.keyword() << " " << obj.get_name() << "\n"; counter++; });
|
2013-08-15 16:29:42 +00:00
|
|
|
lean_assert(counter == 3);
|
|
|
|
std::cout << "=======================\n";
|
|
|
|
counter = 0;
|
2013-12-13 00:33:31 +00:00
|
|
|
std::for_each(env2->begin_objects(), env2->end_objects(), [&](object const & obj) { std::cout << obj.keyword() << " " << obj.get_name() << "\n"; counter++; });
|
2013-08-15 16:29:42 +00:00
|
|
|
lean_assert(counter == 5);
|
2013-12-13 00:33:31 +00:00
|
|
|
environment env3 = env2->mk_child();
|
|
|
|
env3->add_var("f", Type() >> Type());
|
2013-08-15 16:29:42 +00:00
|
|
|
std::cout << "=======================\n";
|
|
|
|
counter = 0;
|
2013-12-13 00:33:31 +00:00
|
|
|
std::for_each(env3->begin_objects(), env3->end_objects(), [&](object const & obj) { std::cout << obj.keyword() << " " << obj.get_name() << "\n"; counter++; });
|
2013-08-15 16:29:42 +00:00
|
|
|
lean_assert(counter == 6);
|
|
|
|
}
|
|
|
|
|
2013-08-16 19:51:12 +00:00
|
|
|
static void tst9() {
|
|
|
|
try {
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_uvar("u1", level());
|
|
|
|
env->add_uvar("u2", level());
|
|
|
|
env->add_uvar("u1", level("u2"));
|
2013-08-16 22:09:26 +00:00
|
|
|
} catch (already_declared_exception & ex) {
|
2013-08-16 19:51:12 +00:00
|
|
|
std::cout << ex.what() << "\n";
|
2013-12-13 00:33:31 +00:00
|
|
|
level l = ex.get_environment()->get_uvar(ex.get_name());
|
2013-08-16 19:51:12 +00:00
|
|
|
std::cout << l << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-15 21:50:08 +00:00
|
|
|
static void tst10() {
|
|
|
|
environment env;
|
|
|
|
import_all(env);
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("a", Int, iVal(1));
|
|
|
|
lean_assert(env->get_object("a").get_weight() == 1);
|
2013-10-15 21:50:08 +00:00
|
|
|
expr a = Const("a");
|
|
|
|
expr b = Const("b");
|
|
|
|
expr c = Const("c");
|
2013-12-13 00:33:31 +00:00
|
|
|
env->add_definition("b", Int, iAdd(a, a));
|
|
|
|
lean_assert(env->get_object("b").get_weight() == 2);
|
|
|
|
env->add_definition("c", Int, iAdd(a, b));
|
|
|
|
lean_assert(env->get_object("c").get_weight() == 3);
|
|
|
|
env->add_definition("d", Int, iAdd(b, b));
|
|
|
|
lean_assert(env->get_object("d").get_weight() == 3);
|
2013-10-15 21:50:08 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
struct my_extension : public environment_extension {
|
2013-11-07 03:21:22 +00:00
|
|
|
unsigned m_value1;
|
|
|
|
unsigned m_value2;
|
|
|
|
my_extension():m_value1(0), m_value2(0) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct my_extension_reg {
|
|
|
|
unsigned m_extid;
|
|
|
|
my_extension_reg() {
|
2013-12-13 00:33:31 +00:00
|
|
|
m_extid = environment_cell::register_extension([](){ return std::unique_ptr<environment_extension>(new my_extension()); });
|
2013-11-07 03:21:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static my_extension_reg R;
|
|
|
|
|
|
|
|
static void tst11() {
|
|
|
|
unsigned extid = R.m_extid;
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
my_extension & ext = env->get_extension<my_extension>(extid);
|
2013-11-07 03:21:22 +00:00
|
|
|
ext.m_value1 = 10;
|
|
|
|
ext.m_value2 = 20;
|
2013-12-13 00:33:31 +00:00
|
|
|
my_extension & ext2 = env->get_extension<my_extension>(extid);
|
2013-11-07 03:21:22 +00:00
|
|
|
lean_assert(ext2.m_value1 == 10);
|
|
|
|
lean_assert(ext2.m_value2 == 20);
|
2013-12-13 00:33:31 +00:00
|
|
|
environment child = env->mk_child();
|
|
|
|
my_extension & ext3 = child->get_extension<my_extension>(extid);
|
2013-11-07 03:21:22 +00:00
|
|
|
lean_assert(ext3.m_value1 == 0);
|
|
|
|
lean_assert(ext3.m_value2 == 0);
|
|
|
|
my_extension const * ext4 = ext3.get_parent<my_extension>();
|
|
|
|
lean_assert(ext4);
|
|
|
|
lean_assert(ext4->m_value1 == 10);
|
|
|
|
lean_assert(ext4->m_value2 == 20);
|
|
|
|
lean_assert(ext4->get_parent<my_extension>() == nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst12() {
|
|
|
|
unsigned extid = R.m_extid;
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
environment child = env->mk_child();
|
|
|
|
my_extension & ext = child->get_extension<my_extension>(extid);
|
2013-11-07 03:21:22 +00:00
|
|
|
lean_assert(ext.m_value1 == 0);
|
|
|
|
lean_assert(ext.m_value2 == 0);
|
|
|
|
lean_assert(ext.get_parent<my_extension>() == nullptr);
|
|
|
|
}
|
|
|
|
|
2013-11-17 02:35:17 +00:00
|
|
|
static void tst13() {
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment::weak_ref wref;
|
2013-11-17 02:35:17 +00:00
|
|
|
{
|
|
|
|
environment env;
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment roenv(env);
|
|
|
|
wref = roenv.to_weak_ref();
|
2013-11-17 02:35:17 +00:00
|
|
|
}
|
|
|
|
try {
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment env2(wref);
|
2013-11-17 02:35:17 +00:00
|
|
|
lean_unreachable();
|
|
|
|
} catch (exception &) {}
|
|
|
|
}
|
|
|
|
|
2013-08-04 23:07:37 +00:00
|
|
|
int main() {
|
2013-12-01 20:42:32 +00:00
|
|
|
save_stack_info();
|
2013-08-05 17:33:05 +00:00
|
|
|
enable_trace("is_convertible");
|
2013-08-04 23:07:37 +00:00
|
|
|
tst1();
|
|
|
|
tst2();
|
2013-08-05 03:52:14 +00:00
|
|
|
tst3();
|
2013-08-05 17:33:05 +00:00
|
|
|
tst4();
|
|
|
|
tst5();
|
2013-08-05 20:16:20 +00:00
|
|
|
tst6();
|
2013-08-06 03:06:07 +00:00
|
|
|
tst7();
|
2013-08-15 16:29:42 +00:00
|
|
|
tst8();
|
2013-08-16 19:51:12 +00:00
|
|
|
tst9();
|
2013-10-15 21:50:08 +00:00
|
|
|
tst10();
|
2013-11-07 03:21:22 +00:00
|
|
|
tst11();
|
|
|
|
tst12();
|
2013-11-17 02:35:17 +00:00
|
|
|
tst13();
|
2013-08-04 23:07:37 +00:00
|
|
|
return has_violations() ? 1 : 0;
|
|
|
|
}
|