fix(kernel/type_checker): the type checker cache was not taking into account binder information

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-05-14 17:14:57 -07:00
parent d5184a1751
commit 606e6226c2
7 changed files with 40 additions and 3 deletions

View file

@ -137,6 +137,10 @@ void expr_app::dealloc(buffer<expr_cell*> & todelete) {
static unsigned dec(unsigned k) { return k == 0 ? 0 : k - 1; }
bool operator==(expr_binder_info const & i1, expr_binder_info const & i2) {
return i1.is_implicit() == i2.is_implicit() && i1.is_cast() == i2.is_cast() && i1.is_contextual() == i2.is_contextual();
}
// Expr binders (Lambda, Pi)
expr_binder::expr_binder(expr_kind k, name const & n, expr const & t, expr const & b, expr_binder_info const & i):
expr_composite(k, ::lean::hash(t.hash(), b.hash()),
@ -390,6 +394,7 @@ unsigned get_free_var_range(expr const & e) {
}
bool operator==(expr const & a, expr const & b) { return expr_eq_fn()(a, b); }
bool is_bi_equal(expr const & a, expr const & b) { return expr_eq_fn(true)(a, b); }
static expr copy_tag(expr const & e, expr && new_e) {
tag t = e.get_tag();

View file

@ -150,8 +150,11 @@ public:
// =======================================
// Structural equality
bool operator==(expr const & a, expr const & b);
/** \brief Binder information is ignored in the following predicate */
bool operator==(expr const & a, expr const & b);
inline bool operator!=(expr const & a, expr const & b) { return !operator==(a, b); }
/** \brief Similar to ==, but it also compares binder information */
bool is_bi_equal(expr const & a, expr const & b);
// =======================================
SPECIALIZE_OPTIONAL_FOR_SMART_PTR(expr)
@ -232,6 +235,9 @@ public:
bool is_contextual() const { return m_contextual; }
};
bool operator==(expr_binder_info const & i1, expr_binder_info const & i2);
inline bool operator!=(expr_binder_info const & i1, expr_binder_info const & i2) { return !(i1 == i2); }
/** \brief Super class for lambda and pi */
class expr_binder : public expr_composite {
name m_name;

View file

@ -39,7 +39,8 @@ bool expr_eq_fn::apply(expr const & a, expr const & b) {
case expr_kind::Lambda: case expr_kind::Pi:
return
apply(binder_domain(a), binder_domain(b)) &&
apply(binder_body(a), binder_body(b));
apply(binder_body(a), binder_body(b)) &&
(!m_compare_binder_info || binder_info(a) == binder_info(b));
case expr_kind::Sort:
return sort_level(a) == sort_level(b);
case expr_kind::Macro:

View file

@ -15,9 +15,12 @@ namespace lean {
\brief Functional object for comparing expressions.
*/
class expr_eq_fn {
bool m_compare_binder_info;
std::unique_ptr<expr_cell_pair_set> m_eq_visited;
bool apply(expr const & a, expr const & b);
public:
/** \brief If \c is true, then functional object will also compare binder information attached to lambda and Pi expressions */
expr_eq_fn(bool c = false):m_compare_binder_info(c) {}
bool operator()(expr const & a, expr const & b) { return apply(a, b); }
void clear() { m_eq_visited.reset(); }
};

View file

@ -26,4 +26,8 @@ using expr_cell_offset_map = typename std::unordered_map<expr_cell_offset, T, ex
// Maps based on structural equality. That is, two keys are equal iff they are structurally equal
template<typename T>
using expr_struct_map = typename std::unordered_map<expr, T, expr_hash, std::equal_to<expr>>;
// The following map also takes into account binder information
struct is_bi_equal_proc { bool operator()(expr const & e1, expr const & e2) const { return is_bi_equal(e1, e2); } };
template<typename T>
using expr_bi_struct_map = typename std::unordered_map<expr, T, expr_hash, is_bi_equal_proc>;
};

View file

@ -60,7 +60,11 @@ struct type_checker::imp {
name_generator m_gen;
constraint_handler & m_chandler;
std::unique_ptr<converter> m_conv;
expr_struct_map<expr> m_infer_type_cache;
// In the type checker cache, we must take into account binder information.
// Examples:
// The type of (lambda x : A, t) is (Pi x : A, typeof(t))
// The type of (lambda {x : A}, t) is (Pi {x : A}, typeof(t))
expr_bi_struct_map<expr> m_infer_type_cache;
converter_context m_conv_ctx;
type_checker_context m_tc_ctx;
bool m_memoize;

14
tests/lua/tc3.lua Normal file
View file

@ -0,0 +1,14 @@
local env = empty_environment()
local t1 = mk_lambda("A", Type, mk_lambda("a", Var(0), Var(0)), binder_info(true))
local t2 = mk_lambda("A", Type, mk_lambda("a", Var(0), Var(0)))
print(t1)
print(t2)
local tc = type_checker(env)
local T1 = mk_pi("A", Type, mk_arrow(Var(0), Var(1)), binder_info(true))
local T2 = mk_pi("A", Type, mk_arrow(Var(0), Var(1)))
print(T1)
print(T2)
print(tc:check(t1))
print(tc:check(t2))
assert(tc:check(t1):binder_info():is_implicit())
assert(not tc:check(t2):binder_info():is_implicit())