Add (optional) type to let declarations
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
6da194334e
commit
2459c4ae7c
26 changed files with 186 additions and 45 deletions
|
@ -425,10 +425,30 @@ class elaborator::imp {
|
||||||
return expr_pair(new_e, t);
|
return expr_pair(new_e, t);
|
||||||
}
|
}
|
||||||
case expr_kind::Let: {
|
case expr_kind::Let: {
|
||||||
|
expr_pair t_p;
|
||||||
|
if (let_type(e))
|
||||||
|
t_p = process(let_type(e), ctx);
|
||||||
auto v_p = process(let_value(e), ctx);
|
auto v_p = process(let_value(e), ctx);
|
||||||
auto b_p = process(let_body(e), extend(ctx, let_name(e), v_p.second, v_p.first));
|
if (let_type(e)) {
|
||||||
|
expr const & expected = t_p.first;
|
||||||
|
expr const & given = v_p.second;
|
||||||
|
if (has_metavar(expected) || has_metavar(given)) {
|
||||||
|
info_ref r = mk_expected_type_info(let_value(e), v_p.first, expected, given, ctx);
|
||||||
|
m_constraints.push_back(constraint(expected, given, ctx, r));
|
||||||
|
} else {
|
||||||
|
if (!is_convertible(expected, given, ctx)) {
|
||||||
|
expr coercion = m_frontend.get_coercion(given, expected);
|
||||||
|
if (coercion) {
|
||||||
|
v_p.first = mk_app(coercion, v_p.first);
|
||||||
|
} else {
|
||||||
|
throw def_type_mismatch_exception(m_env, ctx, let_name(e), let_type(e), v_p.first, v_p.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto b_p = process(let_body(e), extend(ctx, let_name(e), t_p.first ? t_p.first : v_p.second, v_p.first));
|
||||||
expr t = lower_free_vars_mmv(b_p.second, 1, 1);
|
expr t = lower_free_vars_mmv(b_p.second, 1, 1);
|
||||||
expr new_e = update_let(e, v_p.first, b_p.first);
|
expr new_e = update_let(e, t_p.first, v_p.first, b_p.first);
|
||||||
add_trace(e, new_e);
|
add_trace(e, new_e);
|
||||||
return expr_pair(new_e, t);
|
return expr_pair(new_e, t);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -853,14 +853,19 @@ class parser::imp {
|
||||||
expr parse_let() {
|
expr parse_let() {
|
||||||
next();
|
next();
|
||||||
mk_scope scope(*this);
|
mk_scope scope(*this);
|
||||||
buffer<std::tuple<pos_info, name, expr>> bindings;
|
buffer<std::tuple<pos_info, name, expr, expr>> bindings;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto p = pos();
|
auto p = pos();
|
||||||
name id = check_identifier_next("invalid let expression, identifier expected");
|
name id = check_identifier_next("invalid let expression, identifier expected");
|
||||||
|
expr type;
|
||||||
|
if (curr_is_colon()) {
|
||||||
|
next();
|
||||||
|
type = parse_expr();
|
||||||
|
}
|
||||||
check_assign_next("invalid let expression, ':=' expected");
|
check_assign_next("invalid let expression, ':=' expected");
|
||||||
expr val = parse_expr();
|
expr val = parse_expr();
|
||||||
register_binding(id);
|
register_binding(id);
|
||||||
bindings.push_back(std::make_tuple(p, id, val));
|
bindings.push_back(std::make_tuple(p, id, type, val));
|
||||||
if (curr_is_in()) {
|
if (curr_is_in()) {
|
||||||
next();
|
next();
|
||||||
expr r = parse_expr();
|
expr r = parse_expr();
|
||||||
|
@ -868,7 +873,7 @@ class parser::imp {
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
--i;
|
--i;
|
||||||
auto p = std::get<0>(bindings[i]);
|
auto p = std::get<0>(bindings[i]);
|
||||||
r = save(mk_let(std::get<1>(bindings[i]), std::get<2>(bindings[i]), r), p);
|
r = save(mk_let(std::get<1>(bindings[i]), std::get<2>(bindings[i]), std::get<3>(bindings[i]), r), p);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -842,11 +842,11 @@ class pp_fn {
|
||||||
return pp_abstraction_core(e, depth, expr());
|
return pp_abstraction_core(e, depth, expr());
|
||||||
}
|
}
|
||||||
|
|
||||||
expr collect_nested_let(expr const & e, buffer<std::pair<name, expr>> & bindings) {
|
expr collect_nested_let(expr const & e, buffer<std::tuple<name, expr, expr>> & bindings) {
|
||||||
if (is_let(e)) {
|
if (is_let(e)) {
|
||||||
name n1 = get_unused_name(e);
|
name n1 = get_unused_name(e);
|
||||||
m_local_names.insert(n1);
|
m_local_names.insert(n1);
|
||||||
bindings.push_back(mk_pair(n1, let_value(e)));
|
bindings.push_back(std::make_tuple(n1, let_type(e), let_value(e)));
|
||||||
expr b = instantiate_with_closed(let_body(e), mk_constant(n1));
|
expr b = instantiate_with_closed(let_body(e), mk_constant(n1));
|
||||||
return collect_nested_let(b, bindings);
|
return collect_nested_let(b, bindings);
|
||||||
} else {
|
} else {
|
||||||
|
@ -856,19 +856,28 @@ class pp_fn {
|
||||||
|
|
||||||
result pp_let(expr const & e, unsigned depth) {
|
result pp_let(expr const & e, unsigned depth) {
|
||||||
local_names::mk_scope mk(m_local_names);
|
local_names::mk_scope mk(m_local_names);
|
||||||
buffer<std::pair<name, expr>> bindings;
|
buffer<std::tuple<name, expr, expr>> bindings;
|
||||||
expr body = collect_nested_let(e, bindings);
|
expr body = collect_nested_let(e, bindings);
|
||||||
unsigned r_weight = 2;
|
unsigned r_weight = 2;
|
||||||
format r_format = g_let_fmt;
|
format r_format = g_let_fmt;
|
||||||
unsigned sz = bindings.size();
|
unsigned sz = bindings.size();
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
for (unsigned i = 0; i < sz; i++) {
|
||||||
auto b = bindings[i];
|
auto b = bindings[i];
|
||||||
name const & n = b.first;
|
name const & n = std::get<0>(b);
|
||||||
result p_def = pp(b.second, depth+1);
|
|
||||||
format beg = i == 0 ? space() : line();
|
format beg = i == 0 ? space() : line();
|
||||||
format sep = i < sz - 1 ? comma() : format();
|
format sep = i < sz - 1 ? comma() : format();
|
||||||
r_format += nest(3 + 1, format{beg, format(n), space(), g_assign_fmt, nest(n.size() + 1 + 2 + 1, format{space(), p_def.first, sep})});
|
result p_def = pp(std::get<2>(b), depth+1);
|
||||||
r_weight += p_def.second;
|
expr type = std::get<1>(b);
|
||||||
|
if (type) {
|
||||||
|
result p_type = pp(type, depth+1);
|
||||||
|
r_format += nest(3 + 1, compose(beg, group(format{format(n), space(),
|
||||||
|
colon(), nest(n.size() + 1 + 1 + 1, compose(space(), p_type.first)), space(), g_assign_fmt,
|
||||||
|
nest(m_indent, format{line(), p_def.first, sep})})));
|
||||||
|
r_weight += p_type.second + p_def.second;
|
||||||
|
} else {
|
||||||
|
r_format += nest(3 + 1, format{beg, format(n), space(), g_assign_fmt, nest(n.size() + 1 + 2 + 1, format{space(), p_def.first, sep})});
|
||||||
|
r_weight += p_def.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result p_body = pp(body, depth+1);
|
result p_body = pp(body, depth+1);
|
||||||
r_weight += p_body.second;
|
r_weight += p_body.second;
|
||||||
|
|
|
@ -47,8 +47,14 @@ inline expr Pi(std::pair<expr const &, expr const &> const & p, expr const & b)
|
||||||
/**
|
/**
|
||||||
\brief Create a Let expression (Let x := v in b), the term b is abstracted using abstract(b, x).
|
\brief Create a Let expression (Let x := v in b), the term b is abstracted using abstract(b, x).
|
||||||
*/
|
*/
|
||||||
inline expr Let(name const & x, expr const & v, expr const & b) { return mk_let(x, v, abstract(b, mk_constant(x))); }
|
inline expr Let(name const & x, expr const & v, expr const & b) { return mk_let(x, expr(), v, abstract(b, mk_constant(x))); }
|
||||||
inline expr Let(expr const & x, expr const & v, expr const & b) { return mk_let(const_name(x), v, abstract(b, x)); }
|
inline expr Let(expr const & x, expr const & v, expr const & b) { return mk_let(const_name(x), expr(), v, abstract(b, x)); }
|
||||||
inline expr Let(std::pair<expr const &, expr const &> const & p, expr const & b) { return Let(p.first, p.second, b); }
|
inline expr Let(std::pair<expr const &, expr const &> const & p, expr const & b) { return Let(p.first, p.second, b); }
|
||||||
expr Let(std::initializer_list<std::pair<expr const &, expr const &>> const & l, expr const & b);
|
expr Let(std::initializer_list<std::pair<expr const &, expr const &>> const & l, expr const & b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create a Let expression (Let x : t := v in b), the term b is abstracted using abstract(b, x).
|
||||||
|
*/
|
||||||
|
inline expr Let(name const & x, expr const & t, expr const & v, expr const & b) { return mk_let(x, t, v, abstract(b, mk_constant(x))); }
|
||||||
|
inline expr Let(expr const & x, expr const & t, expr const & v, expr const & b) { return mk_let(const_name(x), t, v, abstract(b, x)); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,9 +94,10 @@ expr_type::expr_type(level const & l):
|
||||||
m_level(l) {
|
m_level(l) {
|
||||||
}
|
}
|
||||||
expr_type::~expr_type() {}
|
expr_type::~expr_type() {}
|
||||||
expr_let::expr_let(name const & n, expr const & v, expr const & b):
|
expr_let::expr_let(name const & n, expr const & t, expr const & v, expr const & b):
|
||||||
expr_cell(expr_kind::Let, ::lean::hash(v.hash(), b.hash())),
|
expr_cell(expr_kind::Let, ::lean::hash(v.hash(), b.hash())),
|
||||||
m_name(n),
|
m_name(n),
|
||||||
|
m_type(t),
|
||||||
m_value(v),
|
m_value(v),
|
||||||
m_body(b) {
|
m_body(b) {
|
||||||
}
|
}
|
||||||
|
@ -154,7 +155,7 @@ expr copy(expr const & a) {
|
||||||
case expr_kind::Eq: return mk_eq(eq_lhs(a), eq_rhs(a));
|
case expr_kind::Eq: return mk_eq(eq_lhs(a), eq_rhs(a));
|
||||||
case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a));
|
case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a));
|
||||||
case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a));
|
case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a));
|
||||||
case expr_kind::Let: return mk_let(let_name(a), let_value(a), let_body(a));
|
case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a));
|
||||||
}
|
}
|
||||||
lean_unreachable();
|
lean_unreachable();
|
||||||
return expr();
|
return expr();
|
||||||
|
|
|
@ -26,7 +26,7 @@ class value;
|
||||||
| Pi name expr expr
|
| Pi name expr expr
|
||||||
| Type universe
|
| Type universe
|
||||||
| Eq expr expr (heterogeneous equality)
|
| Eq expr expr (heterogeneous equality)
|
||||||
| Let name expr expr
|
| Let name expr expr expr
|
||||||
|
|
||||||
TODO: match expressions.
|
TODO: match expressions.
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ public:
|
||||||
friend expr mk_lambda(name const & n, expr const & t, expr const & e);
|
friend expr mk_lambda(name const & n, expr const & t, expr const & e);
|
||||||
friend expr mk_pi(name const & n, expr const & t, expr const & e);
|
friend expr mk_pi(name const & n, expr const & t, expr const & e);
|
||||||
friend expr mk_type(level const & l);
|
friend expr mk_type(level const & l);
|
||||||
friend expr mk_let(name const & n, expr const & v, expr const & e);
|
friend expr mk_let(name const & n, expr const & t, expr const & v, expr const & e);
|
||||||
|
|
||||||
friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
|
friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
|
||||||
|
|
||||||
|
@ -179,12 +179,14 @@ public:
|
||||||
/** \brief Let expressions */
|
/** \brief Let expressions */
|
||||||
class expr_let : public expr_cell {
|
class expr_let : public expr_cell {
|
||||||
name m_name;
|
name m_name;
|
||||||
|
expr m_type;
|
||||||
expr m_value;
|
expr m_value;
|
||||||
expr m_body;
|
expr m_body;
|
||||||
public:
|
public:
|
||||||
expr_let(name const & n, expr const & v, expr const & b);
|
expr_let(name const & n, expr const & t, expr const & v, expr const & b);
|
||||||
~expr_let();
|
~expr_let();
|
||||||
name const & get_name() const { return m_name; }
|
name const & get_name() const { return m_name; }
|
||||||
|
expr const & get_type() const { return m_type; }
|
||||||
expr const & get_value() const { return m_value; }
|
expr const & get_value() const { return m_value; }
|
||||||
expr const & get_body() const { return m_body; }
|
expr const & get_body() const { return m_body; }
|
||||||
};
|
};
|
||||||
|
@ -271,7 +273,7 @@ inline expr mk_lambda(name const & n, expr const & t, expr const & e) { return e
|
||||||
inline expr mk_pi(name const & n, expr const & t, expr const & e) { return expr(new expr_pi(n, t, e)); }
|
inline expr mk_pi(name const & n, expr const & t, expr const & e) { return expr(new expr_pi(n, t, e)); }
|
||||||
inline expr mk_arrow(expr const & t, expr const & e) { return mk_pi(name("_"), t, e); }
|
inline expr mk_arrow(expr const & t, expr const & e) { return mk_pi(name("_"), t, e); }
|
||||||
inline expr operator>>(expr const & t, expr const & e) { return mk_arrow(t, e); }
|
inline expr operator>>(expr const & t, expr const & e) { return mk_arrow(t, e); }
|
||||||
inline expr mk_let(name const & n, expr const & v, expr const & e) { return expr(new expr_let(n, v, e)); }
|
inline expr mk_let(name const & n, expr const & t, expr const & v, expr const & e) { return expr(new expr_let(n, t, v, e)); }
|
||||||
inline expr mk_type(level const & l) { return expr(new expr_type(l)); }
|
inline expr mk_type(level const & l) { return expr(new expr_type(l)); }
|
||||||
expr mk_type();
|
expr mk_type();
|
||||||
inline expr Type(level const & l) { return mk_type(l); }
|
inline expr Type(level const & l) { return mk_type(l); }
|
||||||
|
@ -327,6 +329,7 @@ inline expr const & abst_body(expr_cell * e) { return to_abstraction
|
||||||
inline level const & ty_level(expr_cell * e) { return to_type(e)->get_level(); }
|
inline level const & ty_level(expr_cell * e) { return to_type(e)->get_level(); }
|
||||||
inline name const & let_name(expr_cell * e) { return to_let(e)->get_name(); }
|
inline name const & let_name(expr_cell * e) { return to_let(e)->get_name(); }
|
||||||
inline expr const & let_value(expr_cell * e) { return to_let(e)->get_value(); }
|
inline expr const & let_value(expr_cell * e) { return to_let(e)->get_value(); }
|
||||||
|
inline expr const & let_type(expr_cell * e) { return to_let(e)->get_type(); }
|
||||||
inline expr const & let_body(expr_cell * e) { return to_let(e)->get_body(); }
|
inline expr const & let_body(expr_cell * e) { return to_let(e)->get_body(); }
|
||||||
|
|
||||||
/** \brief Return the reference counter of the given expression. */
|
/** \brief Return the reference counter of the given expression. */
|
||||||
|
@ -354,6 +357,7 @@ inline expr const & abst_domain(expr const & e) { return to_abstractio
|
||||||
inline expr const & abst_body(expr const & e) { return to_abstraction(e)->get_body(); }
|
inline expr const & abst_body(expr const & e) { return to_abstraction(e)->get_body(); }
|
||||||
inline level const & ty_level(expr const & e) { return to_type(e)->get_level(); }
|
inline level const & ty_level(expr const & e) { return to_type(e)->get_level(); }
|
||||||
inline name const & let_name(expr const & e) { return to_let(e)->get_name(); }
|
inline name const & let_name(expr const & e) { return to_let(e)->get_name(); }
|
||||||
|
inline expr const & let_type(expr const & e) { return to_let(e)->get_type(); }
|
||||||
inline expr const & let_value(expr const & e) { return to_let(e)->get_value(); }
|
inline expr const & let_value(expr const & e) { return to_let(e)->get_value(); }
|
||||||
inline expr const & let_body(expr const & e) { return to_let(e)->get_body(); }
|
inline expr const & let_body(expr const & e) { return to_let(e)->get_body(); }
|
||||||
// =======================================
|
// =======================================
|
||||||
|
@ -447,14 +451,15 @@ template<typename F> expr update_abst(expr const & e, F f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<typename F> expr update_let(expr const & e, F f) {
|
template<typename F> expr update_let(expr const & e, F f) {
|
||||||
static_assert(std::is_same<typename std::result_of<F(expr const &, expr const &)>::type,
|
static_assert(std::is_same<typename std::result_of<F(expr const &, expr const &, expr const &)>::type,
|
||||||
std::pair<expr, expr>>::value,
|
std::tuple<expr, expr, expr>>::value,
|
||||||
"update_let: return type of f is not pair<expr, expr>");
|
"update_let: return type of f is not pair<expr, expr>");
|
||||||
|
expr const & old_t = let_type(e);
|
||||||
expr const & old_v = let_value(e);
|
expr const & old_v = let_value(e);
|
||||||
expr const & old_b = let_body(e);
|
expr const & old_b = let_body(e);
|
||||||
std::pair<expr, expr> p = f(old_v, old_b);
|
std::tuple<expr, expr, expr> t = f(old_t, old_v, old_b);
|
||||||
if (!is_eqp(p.first, old_v) || !is_eqp(p.second, old_b))
|
if (!is_eqp(std::get<0>(t), old_t) || !is_eqp(std::get<1>(t), old_v) || !is_eqp(std::get<2>(t), old_b))
|
||||||
return mk_let(let_name(e), p.first, p.second);
|
return mk_let(let_name(e), std::get<0>(t), std::get<1>(t), std::get<2>(t));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,14 @@ class expr_eq_fn {
|
||||||
case expr_kind::Pi: return apply(abst_domain(a), abst_domain(b)) && apply(abst_body(a), abst_body(b));
|
case expr_kind::Pi: return apply(abst_domain(a), abst_domain(b)) && apply(abst_body(a), abst_body(b));
|
||||||
case expr_kind::Type: return ty_level(a) == ty_level(b);
|
case expr_kind::Type: return ty_level(a) == ty_level(b);
|
||||||
case expr_kind::Value: return to_value(a) == to_value(b);
|
case expr_kind::Value: return to_value(a) == to_value(b);
|
||||||
case expr_kind::Let: return apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b));
|
case expr_kind::Let:
|
||||||
|
if (let_type(a) && let_type(b)) {
|
||||||
|
if (!apply(let_type(a), let_type(b)))
|
||||||
|
return false;
|
||||||
|
} else if (let_type(a) || let_type(b)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b));
|
||||||
}
|
}
|
||||||
lean_unreachable(); // LCOV_EXCL_LINE
|
lean_unreachable(); // LCOV_EXCL_LINE
|
||||||
return false; // LCOV_EXCL_LINE
|
return false; // LCOV_EXCL_LINE
|
||||||
|
|
|
@ -42,6 +42,8 @@ class for_each_fn {
|
||||||
apply(abst_body(e), offset + 1);
|
apply(abst_body(e), offset + 1);
|
||||||
return;
|
return;
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
|
if (let_type(e))
|
||||||
|
apply(let_type(e), offset);
|
||||||
apply(let_value(e), offset);
|
apply(let_value(e), offset);
|
||||||
apply(let_body(e), offset + 1);
|
apply(let_body(e), offset + 1);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -65,7 +65,7 @@ protected:
|
||||||
result = apply(abst_domain(e), offset) || apply(abst_body(e), offset + 1);
|
result = apply(abst_domain(e), offset) || apply(abst_body(e), offset + 1);
|
||||||
break;
|
break;
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
result = apply(let_value(e), offset) || apply(let_body(e), offset + 1);
|
result = (let_type(e) && apply(let_type(e), offset)) || apply(let_value(e), offset) || apply(let_body(e), offset + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ protected:
|
||||||
result = apply(abst_domain(e), offset) || apply(abst_body(e), offset + 1);
|
result = apply(abst_domain(e), offset) || apply(abst_body(e), offset + 1);
|
||||||
break;
|
break;
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
result = apply(let_value(e), offset) || apply(let_body(e), offset + 1);
|
result = (let_type(e) && apply(let_type(e), offset)) || apply(let_value(e), offset) || apply(let_body(e), offset + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,17 +154,24 @@ public:
|
||||||
get_name(), type get_type() and value get_value() is incorrect
|
get_name(), type get_type() and value get_value() is incorrect
|
||||||
because the value has type get_value_type() and it not matches
|
because the value has type get_value_type() and it not matches
|
||||||
the given type get_type().
|
the given type get_type().
|
||||||
|
|
||||||
|
This exception is also used to sign declaration mismatches in
|
||||||
|
let declarations.
|
||||||
*/
|
*/
|
||||||
class def_type_mismatch_exception : public type_checker_exception {
|
class def_type_mismatch_exception : public type_checker_exception {
|
||||||
name m_name;
|
context m_context;
|
||||||
expr m_type;
|
name m_name;
|
||||||
expr m_value;
|
expr m_type;
|
||||||
expr m_value_type;
|
expr m_value;
|
||||||
|
expr m_value_type;
|
||||||
public:
|
public:
|
||||||
|
def_type_mismatch_exception(environment const & env, context const & ctx, name const & n, expr const & type, expr const & val, expr const & val_type):
|
||||||
|
type_checker_exception(env), m_context(ctx), m_name(n), m_type(type), m_value(val), m_value_type(val_type) {}
|
||||||
def_type_mismatch_exception(environment const & env, name const & n, expr const & type, expr const & val, expr const & val_type):
|
def_type_mismatch_exception(environment const & env, name const & n, expr const & type, expr const & val, expr const & val_type):
|
||||||
type_checker_exception(env), m_name(n), m_type(type), m_value(val), m_value_type(val_type) {}
|
type_checker_exception(env), m_name(n), m_type(type), m_value(val), m_value_type(val_type) {}
|
||||||
virtual ~def_type_mismatch_exception() {}
|
virtual ~def_type_mismatch_exception() {}
|
||||||
name const & get_name() const { return m_name; }
|
name const & get_name() const { return m_name; }
|
||||||
|
context const & get_context() const { return m_context; }
|
||||||
expr const & get_type() const { return m_type; }
|
expr const & get_type() const { return m_type; }
|
||||||
expr const & get_value() const { return m_value; }
|
expr const & get_value() const { return m_value; }
|
||||||
expr const & get_value_type() const { return m_value_type; }
|
expr const & get_value_type() const { return m_value_type; }
|
||||||
|
|
|
@ -65,7 +65,10 @@ class replace_fn {
|
||||||
r = update_abst(e, [=](expr const & t, expr const & b) { return std::make_pair(apply(t, offset), apply(b, offset+1)); });
|
r = update_abst(e, [=](expr const & t, expr const & b) { return std::make_pair(apply(t, offset), apply(b, offset+1)); });
|
||||||
break;
|
break;
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
r = update_let(e, [=](expr const & v, expr const & b) { return std::make_pair(apply(v, offset), apply(b, offset+1)); });
|
r = update_let(e, [=](expr const & t, expr const & v, expr const & b) {
|
||||||
|
expr new_t = t ? apply(t, offset) : expr();
|
||||||
|
return std::make_tuple(new_t, apply(v, offset), apply(b, offset+1));
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,11 @@ public:
|
||||||
}
|
}
|
||||||
case expr_kind::Let: {
|
case expr_kind::Let: {
|
||||||
expr lt = infer_type(let_value(e), ctx);
|
expr lt = infer_type(let_value(e), ctx);
|
||||||
|
if (let_type(e)) {
|
||||||
|
infer_universe(let_type(e), ctx); // check if it is really a type
|
||||||
|
if (!m_normalizer.is_convertible(let_type(e), lt, ctx))
|
||||||
|
throw def_type_mismatch_exception(m_env, ctx, let_name(e), let_type(e), let_value(e), lt);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
cache::mk_scope sc(m_cache);
|
cache::mk_scope sc(m_cache);
|
||||||
r = lower_free_vars(infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e))), 1);
|
r = lower_free_vars(infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e))), 1);
|
||||||
|
|
|
@ -35,7 +35,10 @@ class deep_copy_fn {
|
||||||
case expr_kind::Eq: r = mk_eq(apply(eq_lhs(a)), apply(eq_rhs(a))); break;
|
case expr_kind::Eq: r = mk_eq(apply(eq_lhs(a)), apply(eq_rhs(a))); break;
|
||||||
case expr_kind::Lambda: r = mk_lambda(abst_name(a), apply(abst_domain(a)), apply(abst_body(a))); break;
|
case expr_kind::Lambda: r = mk_lambda(abst_name(a), apply(abst_domain(a)), apply(abst_body(a))); break;
|
||||||
case expr_kind::Pi: r = mk_pi(abst_name(a), apply(abst_domain(a)), apply(abst_body(a))); break;
|
case expr_kind::Pi: r = mk_pi(abst_name(a), apply(abst_domain(a)), apply(abst_body(a))); break;
|
||||||
case expr_kind::Let: r = mk_let(let_name(a), apply(let_value(a)), apply(let_body(a))); break;
|
case expr_kind::Let: {
|
||||||
|
expr new_t = let_type(a) ? apply(let_type(a)) : expr();
|
||||||
|
r = mk_let(let_name(a), new_t, apply(let_value(a)), apply(let_body(a))); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sh)
|
if (sh)
|
||||||
m_cache.insert(std::make_pair(a.raw(), r));
|
m_cache.insert(std::make_pair(a.raw(), r));
|
||||||
|
|
|
@ -55,7 +55,10 @@ struct max_sharing_fn::imp {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
case expr_kind::Let: {
|
case expr_kind::Let: {
|
||||||
expr r = update_let(a, [=](expr const & v, expr const & b) { return std::make_pair(apply(v), apply(b)); });
|
expr r = update_let(a, [=](expr const & t, expr const & v, expr const & b) {
|
||||||
|
expr new_t = t ? apply(t) : expr();
|
||||||
|
return std::make_tuple(new_t, apply(v), apply(b));
|
||||||
|
});
|
||||||
cache(r);
|
cache(r);
|
||||||
return r;
|
return r;
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -124,7 +124,10 @@ struct print_expr_fn {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
out() << "let " << let_name(a) << " := ";
|
out() << "let " << let_name(a);
|
||||||
|
if (let_type(a))
|
||||||
|
out() << " : " << let_type(a);
|
||||||
|
out() << " := ";
|
||||||
print(let_value(a), c);
|
print(let_value(a), c);
|
||||||
out() << " in ";
|
out() << " in ";
|
||||||
print_child(let_body(a), extend(c, let_name(a), let_value(a)));
|
print_child(let_body(a), extend(c, let_name(a), let_value(a)));
|
||||||
|
|
|
@ -38,11 +38,11 @@ expr update_pi(expr const & pi, expr const & d, expr const & b) {
|
||||||
return mk_pi(abst_name(pi), d, b);
|
return mk_pi(abst_name(pi), d, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_let(expr const & let, expr const & v, expr const & b) {
|
expr update_let(expr const & let, expr const & t, expr const & v, expr const & b) {
|
||||||
if (is_eqp(let_value(let), v) && is_eqp(let_body(let), b))
|
if (is_eqp(let_type(let), t) && is_eqp(let_value(let), v) && is_eqp(let_body(let), b))
|
||||||
return let;
|
return let;
|
||||||
else
|
else
|
||||||
return mk_let(let_name(let), v, b);
|
return mk_let(let_name(let), t, v, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_eq(expr const & eq, expr const & l, expr const & r) {
|
expr update_eq(expr const & eq, expr const & l, expr const & r) {
|
||||||
|
|
|
@ -27,11 +27,11 @@ expr update_lambda(expr const & lambda, expr const & d, expr const & b);
|
||||||
*/
|
*/
|
||||||
expr update_pi(expr const & pi, expr const & d, expr const & b);
|
expr update_pi(expr const & pi, expr const & d, expr const & b);
|
||||||
/**
|
/**
|
||||||
\brief Return a let expression based on \c let with value \c v and \c body b.
|
\brief Return a let expression based on \c let with type \c t value \c v and \c body b.
|
||||||
|
|
||||||
\remark Return \c let if the given value and body are (pointer) equal to the ones in \c let.
|
\remark Return \c let if the given value and body are (pointer) equal to the ones in \c let.
|
||||||
*/
|
*/
|
||||||
expr update_let(expr const & let, expr const & v, expr const & b);
|
expr update_let(expr const & let, expr const & t, expr const & v, expr const & b);
|
||||||
/**
|
/**
|
||||||
\brief Return a new equality with lhs \c l and rhs \c r.
|
\brief Return a new equality with lhs \c l and rhs \c r.
|
||||||
|
|
||||||
|
|
|
@ -345,7 +345,7 @@ void tst14() {
|
||||||
void tst15() {
|
void tst15() {
|
||||||
expr t = Eq(Const("a"), Const("b"));
|
expr t = Eq(Const("a"), Const("b"));
|
||||||
std::cout << t << "\n";
|
std::cout << t << "\n";
|
||||||
expr l = mk_let("a", Const("b"), Var(0));
|
expr l = mk_let("a", expr(), Const("b"), Var(0));
|
||||||
std::cout << l << "\n";
|
std::cout << l << "\n";
|
||||||
lean_assert(closed(l));
|
lean_assert(closed(l));
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ static void tst3() {
|
||||||
static void tst4() {
|
static void tst4() {
|
||||||
environment env;
|
environment env;
|
||||||
env.add_var("b", Type());
|
env.add_var("b", Type());
|
||||||
expr t1 = mk_let("a", Const("b"), mk_lambda("c", Type(), Var(1)(Var(0))));
|
expr t1 = mk_let("a", expr(), Const("b"), mk_lambda("c", Type(), Var(1)(Var(0))));
|
||||||
std::cout << t1 << " --> " << normalize(t1, env) << "\n";
|
std::cout << t1 << " --> " << normalize(t1, env) << "\n";
|
||||||
lean_assert(normalize(t1, env) == mk_lambda("c", Type(), Const("b")(Var(0))));
|
lean_assert(normalize(t1, env) == mk_lambda("c", Type(), Const("b")(Var(0))));
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ static void tst3() {
|
||||||
expr f = Fun("a", Bool, Eq(Const("a"), True));
|
expr f = Fun("a", Bool, Eq(Const("a"), True));
|
||||||
std::cout << infer_type(f, env) << "\n";
|
std::cout << infer_type(f, env) << "\n";
|
||||||
lean_assert(infer_type(f, env) == mk_arrow(Bool, Bool));
|
lean_assert(infer_type(f, env) == mk_arrow(Bool, Bool));
|
||||||
expr t = mk_let("a", True, Var(0));
|
expr t = mk_let("a", expr(), True, Var(0));
|
||||||
std::cout << infer_type(t, env) << "\n";
|
std::cout << infer_type(t, env) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ static void tst11() {
|
||||||
expr t3 = f(b,b);
|
expr t3 = f(b,b);
|
||||||
for (unsigned i = 0; i < n; i++) {
|
for (unsigned i = 0; i < n; i++) {
|
||||||
t1 = f(t1,t1);
|
t1 = f(t1,t1);
|
||||||
t2 = mk_let("x", t2, f(Var(0), Var(0)));
|
t2 = mk_let("x", expr(), t2, f(Var(0), Var(0)));
|
||||||
t3 = f(t3,t3);
|
t3 = f(t3,t3);
|
||||||
}
|
}
|
||||||
lean_assert(t1 != t2);
|
lean_assert(t1 != t2);
|
||||||
|
|
11
tests/lean/let1.lean
Normal file
11
tests/lean/let1.lean
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
Show let a : Nat := 10, b : Nat := 20, c : Nat := 30, d : Nat := 10 in a + b + c + d
|
||||||
|
Show let a : Nat := 1000000000000000000, b : Nat := 20000000000000000000, c : Nat := 3000000000000000000, d : Nat := 4000000000000000000 in a + b + c + d
|
||||||
|
Check let a : Nat := 10 in a + 1
|
||||||
|
Eval let a : Nat := 20 in a + 10
|
||||||
|
Eval let a := 20 in a + 10
|
||||||
|
Check let a : Int := 20 in a + 10
|
||||||
|
Set pp::coercion true
|
||||||
|
Show let a : Int := 20 in a + 10
|
||||||
|
|
||||||
|
|
14
tests/lean/let1.lean.expected.out
Normal file
14
tests/lean/let1.lean.expected.out
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Set: pp::colors
|
||||||
|
Set: pp::unicode
|
||||||
|
let a : ℕ := 10, b : ℕ := 20, c : ℕ := 30, d : ℕ := 10 in a + b + c + d
|
||||||
|
let a : ℕ := 1000000000000000000,
|
||||||
|
b : ℕ := 20000000000000000000,
|
||||||
|
c : ℕ := 3000000000000000000,
|
||||||
|
d : ℕ := 4000000000000000000
|
||||||
|
in a + b + c + d
|
||||||
|
ℕ
|
||||||
|
30
|
||||||
|
30
|
||||||
|
ℤ
|
||||||
|
Set: lean::pp::coercion
|
||||||
|
let a : ℤ := nat_to_int 20 in a + (nat_to_int 10)
|
11
tests/lean/let2.lean
Normal file
11
tests/lean/let2.lean
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
(* Annotating lemmas *)
|
||||||
|
|
||||||
|
Theorem simple (p q r : Bool) : (p ⇒ q) ∧ (q ⇒ r) ⇒ p ⇒ r :=
|
||||||
|
Discharge (λ H_pq_qr, Discharge (λ H_p,
|
||||||
|
let P_pq : (p ⇒ q) := Conjunct1 H_pq_qr,
|
||||||
|
P_qr : (q ⇒ r) := Conjunct2 H_pq_qr,
|
||||||
|
P_q : q := MP P_pq H_p
|
||||||
|
in MP P_qr P_q))
|
||||||
|
|
||||||
|
Show Environment 1
|
12
tests/lean/let2.lean.expected.out
Normal file
12
tests/lean/let2.lean.expected.out
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Set: pp::colors
|
||||||
|
Set: pp::unicode
|
||||||
|
Proved: simple
|
||||||
|
Theorem simple (p q r : Bool) : (p ⇒ q) ∧ (q ⇒ r) ⇒ p ⇒ r :=
|
||||||
|
Discharge
|
||||||
|
(λ H_pq_qr : (p ⇒ q) ∧ (q ⇒ r),
|
||||||
|
Discharge
|
||||||
|
(λ H_p : p,
|
||||||
|
let P_pq : p ⇒ q := Conjunct1 H_pq_qr,
|
||||||
|
P_qr : q ⇒ r := Conjunct2 H_pq_qr,
|
||||||
|
P_q : q := MP P_pq H_p
|
||||||
|
in MP P_qr P_q))
|
8
tests/lean/let3.lean
Normal file
8
tests/lean/let3.lean
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
Variable magic : Pi (H : Bool), H
|
||||||
|
|
||||||
|
Set pp::notation false
|
||||||
|
Set pp::coercion true
|
||||||
|
Show let a : Int := 1,
|
||||||
|
H : a > 0 := magic (a > 0)
|
||||||
|
in H
|
6
tests/lean/let3.lean.expected.out
Normal file
6
tests/lean/let3.lean.expected.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Set: pp::colors
|
||||||
|
Set: pp::unicode
|
||||||
|
Assumed: magic
|
||||||
|
Set: lean::pp::notation
|
||||||
|
Set: lean::pp::coercion
|
||||||
|
let a : ℤ := nat_to_int 1, H : Int::gt a (nat_to_int 0) := magic (Int::gt a (nat_to_int 0)) in H
|
Loading…
Reference in a new issue