refactor(library/util): isolate util procedures that depend on old_type_checker

This commit is contained in:
Leonardo de Moura 2016-03-21 13:36:08 -07:00
parent 4f9ebd1cfb
commit 8dde1489f9
30 changed files with 1044 additions and 987 deletions

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "library/user_recursors.h"
#include "library/normalize.h"
#include "library/util.h"
#include "library/old_util.h"
#include "compiler/eta_expansion.h"
#include "compiler/simp_pr1_rec.h"

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include "kernel/find_fn.h"
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/old_util.h"
namespace lean {
static bool is_typeformer_app(buffer<name> const & typeformer_names, expr const & e) {

View file

@ -5,7 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "library/util.h"
#include "library/old_util.h"
namespace lean {
class parser;

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include "kernel/expr_sets.h"
#include "kernel/type_checker.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/locals.h"
#include "library/tactic/util.h"
#include "frontends/lean/local_decls.h"

View file

@ -23,4 +23,6 @@ add_library(library OBJECT deep_copy.cpp expr_lt.cpp io_state.cpp
type_context.cpp
# Legacy
justification.cpp constraint.cpp metavar.cpp
legacy_type_context.cpp old_type_checker.cpp old_converter.cpp old_default_converter.cpp)
legacy_type_context.cpp old_type_checker.cpp old_converter.cpp old_default_converter.cpp
old_util.cpp
)

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include "util/name_map.h"
#include "kernel/instantiate.h"
#include "kernel/abstract.h"
#include "library/util.h"
#include "library/trace.h"
#include "library/match.h"
#include "library/constants.h"

View file

@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/blast/blast.h"
#include "library/blast/trace.h"

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/blast/blast.h"
#include "library/blast/proof_expr.h"
#include "library/blast/choice_point.h"

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "kernel/abstract.h"
#include "library/trace.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/blast/simplifier/simp_lemmas.h"
#include "library/blast/congruence_closure.h"
#include "library/blast/util.h"

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include "util/sexpr/option_declarations.h"
#include "library/constants.h"
#include "library/idx_metavar.h"
#include "library/util.h"
#include "library/head_map.h"
#include "library/blast/blast.h"
#include "library/blast/trace.h"

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#include "library/attribute_manager.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/blast/blast.h"
#include "library/blast/trace.h"
#include "library/blast/options.h"

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#pragma once
#include "library/util.h"
#include "library/old_util.h"
namespace lean {
/** \brief Create type checker that treats classes as opaque constants */
old_type_checker_ptr mk_class_type_checker(environment const & env, bool conservative);

View file

@ -16,6 +16,7 @@ Author: Leonardo de Moura
#include "library/module.h"
#include "library/bin_app.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/normalize.h"
#include "library/aux_recursors.h"
#include "library/scoped_ext.h"
@ -52,7 +53,7 @@ static environment mk_below(environment const & env, name const & n, bool ibelow
unsigned nminors = *inductive::get_num_minor_premises(env, n);
unsigned ntypeformers = length(std::get<2>(decls));
level_param_names lps = rec_decl.get_univ_params();
bool is_reflexive = is_reflexive_datatype(tc, n);
bool is_reflexive = is_reflexive_datatype(tc.get_type_context(), n);
level lvl = mk_param_univ(head(lps));
levels lvls = param_names_to_levels(tail(lps));
level_param_names blvls; // universe level parameters of ibelow/below
@ -176,7 +177,7 @@ static environment mk_brec_on(environment const & env, name const & n, bool ind)
unsigned nminors = *inductive::get_num_minor_premises(env, n);
unsigned ntypeformers = length(std::get<2>(decls));
level_param_names lps = rec_decl.get_univ_params();
bool is_reflexive = is_reflexive_datatype(tc, n);
bool is_reflexive = is_reflexive_datatype(tc.get_type_context(), n);
level lvl = mk_param_univ(head(lps));
levels lvls = param_names_to_levels(tail(lps));
level rlvl;

View file

@ -22,6 +22,7 @@ Author: Leonardo de Moura
#include "library/io_state_stream.h"
#include "library/annotation.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/locals.h"
#include "library/constants.h"
#include "library/normalize.h"
@ -1612,7 +1613,7 @@ class equation_compiler_fn {
};
level rlvl = get_brec_on_result_level();
bool reflexive = env().prop_proof_irrel() && is_reflexive_datatype(m_tc, const_name(I0));
bool reflexive = env().prop_proof_irrel() && is_reflexive_datatype(m_tc.get_type_context(), const_name(I0));
bool use_ibelow = reflexive && is_zero(rlvl);
if (reflexive) {
if (!is_zero(rlvl) && !is_not_zero(rlvl))

View file

@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "library/util.h"
#include "library/old_util.h"
#include "library/definitional/equations.h"
#include "library/definitional/projection.h"

View file

@ -57,19 +57,24 @@ Author: Leonardo de Moura
#include "library/old_converter.h"
#include "library/old_default_converter.h"
#include "library/old_type_checker.h"
#include "library/old_util.h"
namespace lean {
void initialize_library_module() {
initialize_constants();
// TODO(Leo): delete legacy....
initialize_library_old_util();
initialize_old_converter();
initialize_old_default_converter();
initialize_old_type_checker();
// ----------------------------
initialize_local_context();
initialize_metavar_context();
initialize_attribute_manager();
initialize_trace();
initialize_constants();
initialize_fingerprint();
initialize_print();
initialize_placeholder();
@ -167,8 +172,11 @@ void finalize_library_module() {
finalize_metavar_context();
finalize_local_context();
// TODO(Leo): delete legacy....
finalize_library_old_util();
finalize_old_converter();
finalize_old_default_converter();
finalize_old_type_checker();
// -------------------
}
}

780
src/library/old_util.cpp Normal file
View file

@ -0,0 +1,780 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <algorithm>
#include "kernel/find_fn.h"
#include "kernel/instantiate.h"
#include "kernel/error_msgs.h"
#include "kernel/abstract.h"
#include "kernel/inductive/inductive.h"
#include "library/metavar.h"
#include "library/locals.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/constants.h"
#include "library/unfold_macros.h"
#include "library/pp_options.h"
#include "library/projection.h"
#include "library/old_type_checker.h"
namespace lean {
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo,
constraint_seq & cs) {
expr new_type = tc.whnf(type, cs);
while (is_pi(new_type)) {
type = new_type;
expr local;
if (binfo)
local = mk_local(mk_fresh_name(), binding_name(type), binding_domain(type), *binfo);
else
local = mk_local(mk_fresh_name(), binding_name(type), binding_domain(type), binding_info(type));
telescope.push_back(local);
type = instantiate(binding_body(type), local);
new_type = tc.whnf(type, cs);
}
return type;
}
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo) {
constraint_seq cs;
return to_telescope(tc, type, telescope, binfo, cs);
}
expr mk_false() {
return mk_constant(get_false_name());
}
expr mk_empty() {
return mk_constant(get_empty_name());
}
expr mk_false(environment const & env) {
return is_standard(env) ? mk_false() : mk_empty();
}
bool is_false(expr const & e) {
return is_constant(e) && const_name(e) == get_false_name();
}
bool is_empty(expr const & e) {
return is_constant(e) && const_name(e) == get_empty_name();
}
bool is_false(environment const & env, expr const & e) {
return is_standard(env) ? is_false(e) : is_empty(e);
}
expr mk_false_rec(old_type_checker & tc, expr const & f, expr const & t) {
level t_lvl = sort_level(tc.ensure_type(t).first);
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_false_rec_name(), {t_lvl}), t, f);
} else {
expr f_type = tc.infer(f).first;
return mk_app(mk_constant(get_empty_rec_name(), {t_lvl}), mk_lambda("e", f_type, t), f);
}
}
bool is_or(expr const & e) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_or_name() && args.size() == 2) return true;
else return false;
}
bool is_or(expr const & e, expr & A, expr & B) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_or_name() && args.size() == 2) {
A = args[0];
B = args[1];
return true;
} else {
return false;
}
}
bool is_not(environment const & env, expr const & e, expr & a) {
if (is_app(e)) {
expr const & f = app_fn(e);
if (!is_constant(f) || const_name(f) != get_not_name())
return false;
a = app_arg(e);
return true;
} else if (is_pi(e)) {
if (!is_false(env, binding_body(e)))
return false;
a = binding_domain(e);
return true;
} else {
return false;
}
}
bool is_not(environment const & env, expr const & e) {
if (is_app(e)) {
expr const & f = app_fn(e);
if (!is_constant(f) || const_name(f) != get_not_name())
return false;
return true;
} else if (is_pi(e)) {
if (!is_false(env, binding_body(e))) return false;
return true;
} else {
return false;
}
}
expr mk_not(old_type_checker & tc, expr const & e) {
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_not_name()), e);
} else {
level l = sort_level(tc.ensure_type(e).first);
return mk_app(mk_constant(get_not_name(), {l}), e);
}
}
expr mk_absurd(old_type_checker & tc, expr const & t, expr const & e, expr const & not_e) {
level t_lvl = sort_level(tc.ensure_type(t).first);
expr e_type = tc.infer(e).first;
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_absurd_name(), {t_lvl}), e_type, t, e, not_e);
} else {
level e_lvl = sort_level(tc.ensure_type(e_type).first);
return mk_app(mk_constant(get_absurd_name(), {e_lvl, t_lvl}), e_type, t, e, not_e);
}
}
optional<expr> lift_down_if_hott(old_type_checker & tc, expr const & v) {
if (is_standard(tc.env())) {
return some_expr(v);
} else {
expr v_type = tc.whnf(tc.infer(v).first).first;
if (!is_app(v_type))
return none_expr();
expr const & lift = app_fn(v_type);
if (!is_constant(lift) || const_name(lift) != get_lift_name())
return none_expr();
return some_expr(mk_app(mk_constant(get_lift_down_name(), const_levels(lift)), app_arg(v_type), v));
}
}
static expr * g_true = nullptr;
static expr * g_true_intro = nullptr;
static expr * g_and = nullptr;
static expr * g_and_intro = nullptr;
static expr * g_and_elim_left = nullptr;
static expr * g_and_elim_right = nullptr;
void initialize_library_old_util() {
g_true = new expr(mk_constant(get_true_name()));
g_true_intro = new expr(mk_constant(get_true_intro_name()));
g_and = new expr(mk_constant(get_and_name()));
g_and_intro = new expr(mk_constant(get_and_intro_name()));
g_and_elim_left = new expr(mk_constant(get_and_elim_left_name()));
g_and_elim_right = new expr(mk_constant(get_and_elim_right_name()));
}
void finalize_library_old_util() {
delete g_true;
delete g_true_intro;
delete g_and;
delete g_and_intro;
delete g_and_elim_left;
delete g_and_elim_right;
}
expr mk_true() {
return *g_true;
}
bool is_true(expr const & e) {
return e == *g_true;
}
expr mk_true_intro() {
return *g_true_intro;
}
bool is_and(expr const & e, expr & arg1, expr & arg2) {
if (get_app_fn(e) == *g_and) {
buffer<expr> args; get_app_args(e, args);
if (args.size() == 2) {
arg1 = args[0];
arg2 = args[1];
return true;
} else {
return false;
}
} else {
return false;
}
}
bool is_and(expr const & e) {
if (get_app_fn(e) == *g_and) {
buffer<expr> args; get_app_args(e, args);
if (args.size() == 2) return true;
else return false;
} else {
return false;
}
}
expr mk_and(expr const & a, expr const & b) {
return mk_app(*g_and, a, b);
}
expr mk_and_intro(old_type_checker & tc, expr const & Ha, expr const & Hb) {
return mk_app(*g_and_intro, tc.infer(Ha).first, tc.infer(Hb).first, Ha, Hb);
}
expr mk_and_elim_left(old_type_checker & tc, expr const & H) {
expr a_and_b = tc.whnf(tc.infer(H).first).first;
return mk_app(*g_and_elim_left, app_arg(app_fn(a_and_b)), app_arg(a_and_b), H);
}
expr mk_and_elim_right(old_type_checker & tc, expr const & H) {
expr a_and_b = tc.whnf(tc.infer(H).first).first;
return mk_app(*g_and_elim_right, app_arg(app_fn(a_and_b)), app_arg(a_and_b), H);
}
expr mk_unit(level const & l) {
return mk_constant(get_poly_unit_name(), {l});
}
expr mk_unit_mk(level const & l) {
return mk_constant(get_poly_unit_star_name(), {l});
}
expr mk_prod(old_type_checker & tc, expr const & A, expr const & B) {
level l1 = sort_level(tc.ensure_type(A).first);
level l2 = sort_level(tc.ensure_type(B).first);
return mk_app(mk_constant(get_prod_name(), {l1, l2}), A, B);
}
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b) {
expr A = tc.infer(a).first;
expr B = tc.infer(b).first;
level l1 = sort_level(tc.ensure_type(A).first);
level l2 = sort_level(tc.ensure_type(B).first);
return mk_app(mk_constant(get_prod_mk_name(), {l1, l2}), A, B, a, b);
}
expr mk_pr1(old_type_checker & tc, expr const & p) {
expr AxB = tc.whnf(tc.infer(p).first).first;
expr const & A = app_arg(app_fn(AxB));
expr const & B = app_arg(AxB);
return mk_app(mk_constant(get_prod_pr1_name(), const_levels(get_app_fn(AxB))), A, B, p);
}
expr mk_pr2(old_type_checker & tc, expr const & p) {
expr AxB = tc.whnf(tc.infer(p).first).first;
expr const & A = app_arg(app_fn(AxB));
expr const & B = app_arg(AxB);
return mk_app(mk_constant(get_prod_pr2_name(), const_levels(get_app_fn(AxB))), A, B, p);
}
expr mk_unit(level const & l, bool prop) { return prop ? mk_true() : mk_unit(l); }
expr mk_unit_mk(level const & l, bool prop) { return prop ? mk_true_intro() : mk_unit_mk(l); }
expr mk_prod(old_type_checker & tc, expr const & a, expr const & b, bool prop) { return prop ? mk_and(a, b) : mk_prod(tc, a, b); }
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b, bool prop) {
return prop ? mk_and_intro(tc, a, b) : mk_pair(tc, a, b);
}
expr mk_pr1(old_type_checker & tc, expr const & p, bool prop) { return prop ? mk_and_elim_left(tc, p) : mk_pr1(tc, p); }
expr mk_pr2(old_type_checker & tc, expr const & p, bool prop) { return prop ? mk_and_elim_right(tc, p) : mk_pr2(tc, p); }
bool is_ite(expr const & e, expr & c, expr & H, expr & A, expr & t, expr & f) {
expr const & fn = get_app_fn(e);
if (is_constant(fn) && const_name(fn) == get_ite_name()) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() == 5) {
c = args[0]; H = args[1]; A = args[2]; t = args[3]; f = args[4];
return true;
} else {
return false;
}
} else {
return false;
}
}
bool is_ite(expr const & e) {
expr const & fn = get_app_fn(e);
if (is_constant(fn) && const_name(fn) == get_ite_name()) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() == 5) return true;
else return false;
} else {
return false;
}
}
bool is_iff(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_iff_name();
}
bool is_iff(expr const & e, expr & lhs, expr & rhs) {
if (!is_iff(e) || !is_app(app_fn(e)))
return false;
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
expr mk_iff(expr const & lhs, expr const & rhs) {
return mk_app(mk_constant(get_iff_name()), lhs, rhs);
}
expr mk_iff_refl(expr const & a) {
return mk_app(mk_constant(get_iff_refl_name()), a);
}
expr apply_propext(expr const & iff_pr, expr const & iff_term) {
lean_assert(is_iff(iff_term));
return mk_app(mk_constant(get_propext_name()), app_arg(app_fn(iff_term)), app_arg(iff_term), iff_pr);
}
expr mk_eq(old_type_checker & tc, expr const & lhs, expr const & rhs) {
expr A = tc.whnf(tc.infer(lhs).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_name(), {lvl}), A, lhs, rhs);
}
expr mk_refl(old_type_checker & tc, expr const & a) {
expr A = tc.whnf(tc.infer(a).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_refl_name(), {lvl}), A, a);
}
expr mk_symm(old_type_checker & tc, expr const & H) {
expr p = tc.whnf(tc.infer(H).first).first;
lean_assert(is_eq(p));
expr lhs = app_arg(app_fn(p));
expr rhs = app_arg(p);
expr A = tc.infer(lhs).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_symm_name(), {lvl}), A, lhs, rhs, H);
}
expr mk_trans(old_type_checker & tc, expr const & H1, expr const & H2) {
expr p1 = tc.whnf(tc.infer(H1).first).first;
expr p2 = tc.whnf(tc.infer(H2).first).first;
lean_assert(is_eq(p1) && is_eq(p2));
expr lhs1 = app_arg(app_fn(p1));
expr rhs1 = app_arg(p1);
expr rhs2 = app_arg(p2);
expr A = tc.infer(lhs1).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app({mk_constant(get_eq_trans_name(), {lvl}), A, lhs1, rhs1, rhs2, H1, H2});
}
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & x, expr const & y, expr const & xeqy, expr const & h) {
expr A = tc.infer(x).first;
level l1 = sort_level(tc.ensure_type(A).first);
expr r;
if (is_standard(tc.env())) {
r = mk_constant(get_eq_subst_name(), {l1});
} else {
level l2 = sort_level(tc.ensure_type(tc.infer(h).first).first);
r = mk_constant(get_eq_subst_name(), {l1, l2});
}
return mk_app({r, A, x, y, motive, xeqy, h});
}
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & xeqy, expr const & h) {
expr xeqy_type = tc.whnf(tc.infer(xeqy).first).first;
return mk_subst(tc, motive, app_arg(app_fn(xeqy_type)), app_arg(xeqy_type), xeqy, h);
}
expr mk_subsingleton_elim(old_type_checker & tc, expr const & h, expr const & x, expr const & y) {
expr A = tc.infer(x).first;
level l = sort_level(tc.ensure_type(A).first);
expr r;
if (is_standard(tc.env())) {
r = mk_constant(get_subsingleton_elim_name(), {l});
} else {
r = mk_constant(get_is_trunc_is_prop_elim_name(), {l});
}
return mk_app({r, A, h, x, y});
}
expr mk_heq(old_type_checker & tc, expr const & lhs, expr const & rhs) {
expr A = tc.whnf(tc.infer(lhs).first).first;
expr B = tc.whnf(tc.infer(rhs).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_heq_name(), {lvl}), A, lhs, B, rhs);
}
bool is_eq_rec_core(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_eq_rec_name();
}
bool is_eq_rec(environment const & env, expr const & e) {
expr const & fn = get_app_fn(e);
if (!is_constant(fn))
return false;
return is_standard(env) ? const_name(fn) == get_eq_rec_name() : const_name(fn) == get_eq_nrec_name();
}
bool is_eq_drec(environment const & env, expr const & e) {
expr const & fn = get_app_fn(e);
if (!is_constant(fn))
return false;
return is_standard(env) ? const_name(fn) == get_eq_drec_name() : const_name(fn) == get_eq_rec_name();
}
bool is_eq(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_eq_name();
}
bool is_eq(expr const & e, expr & lhs, expr & rhs) {
if (!is_eq(e) || get_app_num_args(e) != 3)
return false;
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
bool is_eq(expr const & e, expr & A, expr & lhs, expr & rhs) {
if (!is_eq(e) || get_app_num_args(e) != 3)
return false;
A = app_arg(app_fn(app_fn(e)));
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
bool is_eq_a_a(expr const & e) {
if (!is_eq(e))
return false;
buffer<expr> args;
get_app_args(e, args);
return args.size() == 3 && args[1] == args[2];
}
bool is_eq_a_a(old_type_checker & tc, expr const & e) {
if (!is_eq(e))
return false;
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 3)
return false;
pair<bool, constraint_seq> d = tc.is_def_eq(args[1], args[2]);
return d.first && !d.second;
}
bool is_heq(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_heq_name();
}
bool is_heq(expr const & e, expr & A, expr & lhs, expr & B, expr & rhs) {
if (is_heq(e)) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 4)
return false;
A = args[0]; lhs = args[1]; B = args[2]; rhs = args[3];
return true;
} else {
return false;
}
}
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> const & s, buffer<expr> & eqs) {
lean_assert(t.size() == s.size());
lean_assert(std::all_of(s.begin(), s.end(), is_local));
lean_assert(inductive::has_dep_elim(tc.env(), get_eq_name()));
buffer<buffer<expr>> t_aux;
name e_name("e");
for (unsigned i = 0; i < t.size(); i++) {
expr s_i = s[i];
expr s_i_ty = mlocal_type(s_i);
expr s_i_ty_a = abstract_locals(s_i_ty, i, s.data());
expr t_i = t[i];
t_aux.push_back(buffer<expr>());
t_aux.back().push_back(t_i);
for (unsigned j = 0; j < i; j++) {
if (depends_on(s_i_ty, s[j])) {
// we need to "cast"
buffer<expr> ty_inst_args;
for (unsigned k = 0; k <= j; k++)
ty_inst_args.push_back(s[k]);
for (unsigned k = j + 1; k < i; k++)
ty_inst_args.push_back(t_aux[k][j+1]);
lean_assert(ty_inst_args.size() == i);
expr s_i_ty = instantiate_rev(s_i_ty_a, i, ty_inst_args.data());
buffer<expr> rec_args;
rec_args.push_back(mlocal_type(s[j]));
rec_args.push_back(t_aux[j][j]);
rec_args.push_back(Fun(s[j], Fun(eqs[j], s_i_ty))); // type former ("promise")
rec_args.push_back(t_i); // minor premise
rec_args.push_back(s[j]);
rec_args.push_back(eqs[j]);
level rec_l1 = sort_level(tc.ensure_type(s_i_ty).first);
level rec_l2 = sort_level(tc.ensure_type(mlocal_type(s[j])).first);
t_i = mk_app(mk_constant(get_eq_rec_name(), {rec_l1, rec_l2}), rec_args.size(), rec_args.data());
}
t_aux.back().push_back(t_i);
}
expr eq = mk_local(mk_fresh_name(), e_name.append_after(i+1), mk_eq(tc, t_i, s_i), binder_info());
eqs.push_back(eq);
}
}
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> & eqs) {
lean_assert(std::all_of(t.begin(), t.end(), is_local));
lean_assert(inductive::has_dep_elim(tc.env(), get_eq_name()));
buffer<expr> s;
for (unsigned i = 0; i < t.size(); i++) {
expr ty = mlocal_type(t[i]);
ty = abstract_locals(ty, i, t.data());
ty = instantiate_rev(ty, i, s.data());
expr local = mk_local(mk_fresh_name(), local_pp_name(t[i]).append_after("'"), ty, local_info(t[i]));
s.push_back(local);
}
return mk_telescopic_eq(tc, t, s, eqs);
}
level mk_max(levels const & ls) {
if (!ls)
return mk_level_zero();
else if (!tail(ls))
return head(ls);
else
return mk_max(head(ls), mk_max(tail(ls)));
}
expr telescope_to_sigma(old_type_checker & tc, unsigned sz, expr const * ts, constraint_seq & cs) {
lean_assert(sz > 0);
unsigned i = sz - 1;
expr r = mlocal_type(ts[i]);
while (i > 0) {
--i;
expr const & a = ts[i];
expr const & A = mlocal_type(a);
expr const & Ba = r;
level l1 = sort_level(tc.ensure_type(A, cs));
level l2 = sort_level(tc.ensure_type(Ba, cs));
r = mk_app(mk_constant(get_sigma_name(), {l1, l2}), A, Fun(a, Ba));
}
return r;
}
expr mk_sigma_mk(old_type_checker & tc, unsigned sz, expr const * ts, expr const * as, constraint_seq & cs) {
lean_assert(sz > 0);
if (sz == 1)
return as[0];
buffer<expr> new_ts;
for (unsigned i = 1; i < sz; i++)
new_ts.push_back(instantiate(abstract_local(ts[i], ts[0]), as[0]));
expr arg1 = mlocal_type(ts[0]);
expr arg2_core = telescope_to_sigma(tc, sz-1, ts+1, cs);
expr arg2 = Fun(ts[0], arg2_core);
expr arg3 = as[0];
expr arg4 = mk_sigma_mk(tc, sz-1, new_ts.data(), as+1, cs);
level l1 = sort_level(tc.ensure_type(arg1, cs));
level l2 = sort_level(tc.ensure_type(arg2_core, cs));
return mk_app(mk_constant(get_sigma_mk_name(), {l1, l2}), arg1, arg2, arg3, arg4);
}
expr mk_sigma_mk(old_type_checker & tc, buffer<expr> const & ts, buffer<expr> const & as, constraint_seq & cs) {
lean_assert(ts.size() == as.size());
return mk_sigma_mk(tc, ts.size(), ts.data(), as.data(), cs);
}
bool is_none(expr const & e, expr & A) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_option_none_name() && args.size() == 1) {
A = args[0];
return true;
} else {
return false;
}
}
bool is_some(expr const & e, expr & A, expr & a) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_option_some_name() && args.size() == 2) {
A = args[0];
a = args[1];
return true;
} else {
return false;
}
}
expr infer_implicit_params(expr const & type, unsigned nparams, implicit_infer_kind k) {
switch (k) {
case implicit_infer_kind::Implicit: {
bool strict = true;
return infer_implicit(type, nparams, strict);
}
case implicit_infer_kind::RelaxedImplicit: {
bool strict = false;
return infer_implicit(type, nparams, strict);
}
case implicit_infer_kind::None:
return type;
}
lean_unreachable(); // LCOV_EXCL_LINE
}
bool has_expr_metavar_relaxed(expr const & e) {
if (!has_expr_metavar(e))
return false;
bool found = false;
for_each(e, [&](expr const & e, unsigned) {
if (found || !has_expr_metavar(e))
return false;
if (is_metavar(e)) {
found = true;
return false;
}
if (is_local(e))
return false; // do not visit type
return true;
});
return found;
}
constraint instantiate_metavars(constraint const & c, substitution & s) {
switch (c.kind()) {
case constraint_kind::Eq:
return mk_eq_cnstr(s.instantiate_all(cnstr_lhs_expr(c)),
s.instantiate_all(cnstr_rhs_expr(c)),
c.get_justification());
case constraint_kind::LevelEq:
return mk_level_eq_cnstr(s.instantiate(cnstr_lhs_level(c)), s.instantiate(cnstr_rhs_level(c)), c.get_justification());
case constraint_kind::Choice: {
expr m = cnstr_expr(c);
lean_assert(is_meta(m));
buffer<expr> args;
expr mvar = get_app_args(m, args);
mvar = update_mlocal(mvar, s.instantiate_all(mlocal_type(mvar)));
for (expr & arg : args)
arg = s.instantiate_all(arg);
return mk_choice_cnstr(mk_app(mvar, args),
cnstr_choice_fn(c),
cnstr_delay_factor_core(c),
cnstr_is_owner(c), c.get_justification());
}}
lean_unreachable(); // LCOV_EXCL_LINE
}
void check_term(old_type_checker & tc, expr const & e) {
expr tmp = unfold_untrusted_macros(tc.env(), e);
tc.check_ignore_undefined_universes(tmp);
}
void check_term(environment const & env, expr const & e) {
expr tmp = unfold_untrusted_macros(env, e);
old_type_checker(env).check_ignore_undefined_universes(tmp);
}
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src) {
return mk_justification(src, [=](formatter const & fmt, substitution const & subst, bool) {
substitution s(subst);
return pp_type_mismatch(fmt, s.instantiate(v), s.instantiate(v_type), s.instantiate(t));
});
}
format format_goal(formatter const & _fmt, buffer<expr> const & hyps, expr const & conclusion, substitution const & s) {
substitution tmp_subst(s);
options opts = _fmt.get_options();
opts = opts.update_if_undef(get_pp_purify_locals_name(), false);
formatter fmt = _fmt.update_options(opts);
unsigned indent = get_pp_indent(opts);
bool unicode = get_pp_unicode(opts);
bool compact = get_pp_goal_compact(opts);
unsigned max_hs = get_pp_goal_max_hyps(opts);
format turnstile = unicode ? format("\u22A2") /* ⊢ */ : format("|-");
format r;
unsigned i = std::min(max_hs, hyps.size());
bool first = true;
while (i > 0) {
i--;
expr l = hyps[i];
format ids = fmt(l);
expr t = tmp_subst.instantiate(mlocal_type(l));
lean_assert(hyps.size() > 0);
while (i > 0) {
expr l2 = hyps[i-1];
expr t2 = tmp_subst.instantiate(mlocal_type(l2));
if (t2 != t)
break;
ids = fmt(l2) + space() + ids;
i--;
}
if (first)
first = false;
else
r = compose(comma(), line()) + r;
r = group(ids + space() + colon() + nest(indent, line() + fmt(t))) + r;
}
if (hyps.size() > max_hs)
r = r + compose(comma(), line()) + format("... (set pp.goal.max_hypotheses to display remaining hypotheses)");
if (compact)
r = group(r);
r += line() + turnstile + space() + nest(indent, fmt(tmp_subst.instantiate(conclusion)));
if (compact)
r = group(r);
return r;
}
pair<expr, justification> update_meta(expr const & meta, substitution s) {
buffer<expr> args;
expr mvar = get_app_args(meta, args);
justification j;
auto p = s.instantiate_metavars(mlocal_type(mvar));
mvar = update_mlocal(mvar, p.first);
j = p.second;
for (expr & arg : args) {
auto p = s.instantiate_metavars(mlocal_type(arg));
arg = update_mlocal(arg, p.first);
j = mk_composite1(j, p.second);
}
return mk_pair(mk_app(mvar, args), j);
}
expr instantiate_meta(expr const & meta, substitution & subst) {
lean_assert(is_meta(meta));
buffer<expr> locals;
expr mvar = get_app_args(meta, locals);
mvar = update_mlocal(mvar, subst.instantiate_all(mlocal_type(mvar)));
for (auto & local : locals)
local = subst.instantiate_all(local);
return mk_app(mvar, locals);
}
justification mk_failed_to_synthesize_jst(environment const & env, expr const & m) {
return mk_justification(m, [=](formatter const & fmt, substitution const & subst, bool) {
substitution tmp(subst);
expr new_m = instantiate_meta(m, tmp);
expr new_type = old_type_checker(env).infer(new_m).first;
buffer<expr> hyps;
get_app_args(new_m, hyps);
return format("failed to synthesize placeholder") + line() + format_goal(fmt, hyps, new_type, subst);
});
}
old_type_checker_ptr mk_type_checker(environment const & env, name_predicate const & pred) {
return std::unique_ptr<old_type_checker>(new old_type_checker(env,
std::unique_ptr<old_converter>(new hint_old_converter<projection_converter>(env, pred))));
}
old_type_checker_ptr mk_simple_type_checker(environment const & env, name_predicate const & pred) {
return std::unique_ptr<old_type_checker>(new old_type_checker(env,
std::unique_ptr<old_converter>(new hint_old_converter<old_default_converter>(env, pred))));
}
bool is_internal_name(name const & n) {
return !n.is_anonymous() && n.is_string() && n.get_string() && n.get_string()[0] == '_';
}
}

205
src/library/old_util.h Normal file
View file

@ -0,0 +1,205 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/environment.h"
#include "library/old_type_checker.h"
namespace lean {
typedef std::unique_ptr<old_type_checker> old_type_checker_ptr;
/** \brief Similar to previous procedure, but puts \c type in whnf */
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope,
optional<binder_info> const & binfo = optional<binder_info>());
/** \brief Similar to previous procedure, but also accumulates constraints generated while
normalizing type.
\remark Constraints are generated only if \c type constains metavariables.
*/
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo,
constraint_seq & cs);
expr mk_true();
bool is_true(expr const & e);
expr mk_true_intro();
bool is_and(expr const & e, expr & arg1, expr & arg2);
bool is_and(expr const & e);
expr mk_and(expr const & a, expr const & b);
expr mk_and_intro(old_type_checker & tc, expr const & Ha, expr const & Hb);
expr mk_and_elim_left(old_type_checker & tc, expr const & H);
expr mk_and_elim_right(old_type_checker & tc, expr const & H);
expr mk_poly_unit(level const & l);
expr mk_poly_unit_mk(level const & l);
expr mk_prod(old_type_checker & tc, expr const & A, expr const & B);
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b);
expr mk_pr1(old_type_checker & tc, expr const & p);
expr mk_pr2(old_type_checker & tc, expr const & p);
expr mk_unit(level const & l, bool prop);
expr mk_unit_mk(level const & l, bool prop);
expr mk_prod(old_type_checker & tc, expr const & a, expr const & b, bool prop);
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b, bool prop);
expr mk_pr1(old_type_checker & tc, expr const & p, bool prop);
expr mk_pr2(old_type_checker & tc, expr const & p, bool prop);
expr mk_false();
expr mk_empty();
/** \brief Return false (in standard mode) and empty (in HoTT) mode */
expr mk_false(environment const & env);
bool is_false(expr const & e);
bool is_empty(expr const & e);
/** \brief Return true iff \c e is false (in standard mode) or empty (in HoTT) mode */
bool is_false(environment const & env, expr const & e);
/** \brief Return an element of type t given an element \c f : false (in standard mode) and empty (in HoTT) mode */
expr mk_false_rec(old_type_checker & tc, expr const & f, expr const & t);
bool is_or(expr const & e);
bool is_or(expr const & e, expr & A, expr & B);
/** \brief Return true if \c e is of the form <tt>(not arg)</tt>, and store \c arg in \c a.
Return false otherwise */
bool is_not(environment const & env, expr const & e, expr & a);
bool is_not(environment const & env, expr const & e);
expr mk_not(old_type_checker & tc, expr const & e);
/** \brief Create the term <tt>absurd e not_e : t</tt>. */
expr mk_absurd(old_type_checker & tc, expr const & t, expr const & e, expr const & not_e);
expr mk_eq(old_type_checker & tc, expr const & lhs, expr const & rhs);
expr mk_refl(old_type_checker & tc, expr const & a);
expr mk_symm(old_type_checker & tc, expr const & H);
expr mk_trans(old_type_checker & tc, expr const & H1, expr const & H2);
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & x, expr const & y, expr const & xeqy, expr const & h);
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & xeqy, expr const & h);
/** \brief Create an proof for x = y using subsingleton.elim (in standard mode) and is_trunc.is_prop.elim (in HoTT mode) */
expr mk_subsingleton_elim(old_type_checker & tc, expr const & h, expr const & x, expr const & y);
/** \brief Return true iff \c e is a term of the form (eq.rec ....) */
bool is_eq_rec_core(expr const & e);
/** \brief Return true iff \c e is a term of the form (eq.rec ....) in the standard library,
and (eq.nrec ...) in the HoTT library. */
bool is_eq_rec(environment const & env, expr const & e);
/** \brief Return true iff \c e is a term of the form (eq.drec ....) in the standard library,
and (eq.rec ...) in the HoTT library. */
bool is_eq_drec(environment const & env, expr const & e);
bool is_eq(expr const & e);
bool is_eq(expr const & e, expr & lhs, expr & rhs);
bool is_eq(expr const & e, expr & A, expr & lhs, expr & rhs);
/** \brief Return true iff \c e is of the form (eq A a a) */
bool is_eq_a_a(expr const & e);
/** \brief Return true iff \c e is of the form (eq A a a') where \c a and \c a' are definitionally equal */
bool is_eq_a_a(old_type_checker & tc, expr const & e);
bool is_heq(expr const & e);
bool is_heq(expr const & e, expr & A, expr & lhs, expr & B, expr & rhs);
bool is_ite(expr const & e, expr & c, expr & H, expr & A, expr & t, expr & f);
bool is_ite(expr const & e);
bool is_iff(expr const & e);
bool is_iff(expr const & e, expr & lhs, expr & rhs);
expr mk_iff(expr const & lhs, expr const & rhs);
expr mk_iff_refl(expr const & a);
/** \brief Given <tt>iff_pr : iff_term</tt>, where \c iff_term is of the form <tt>l <-> r</tt>,
return the term <tt>propext l r iff_pr</tt>
*/
expr apply_propext(expr const & iff_pr, expr const & iff_term);
/** \brief If in HoTT mode, apply lift.down.
The no_confusion constructions uses lifts in the proof relevant version (aka HoTT mode).
We must apply lift.down to eliminate the auxiliary lift.
*/
optional<expr> lift_down_if_hott(old_type_checker & tc, expr const & v);
/** \brief Create a telescope equality for HoTT library.
This procedure assumes eq supports dependent elimination.
For HoTT, we can't use heterogeneous equality.
*/
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> const & s, buffer<expr> & eqs);
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> & eqs);
level mk_max(levels const & ls);
expr mk_sigma_mk(old_type_checker & tc, buffer<expr> const & ts, buffer<expr> const & as, constraint_seq & cs);
/** \brief Return true iff \c e is of the form (@option.none A), and update \c A */
bool is_none(expr const & e, expr & A);
/** \brief Return true iff \c e is of the form (@option.some A a), and update \c A and \c a */
bool is_some(expr const & e, expr & A, expr & a);
enum class implicit_infer_kind { Implicit, RelaxedImplicit, None };
/** \brief Infer implicit parameter annotations for the first \c nparams using mode
specified by \c k.
*/
expr infer_implicit_params(expr const & type, unsigned nparams, implicit_infer_kind k);
/** \brief Similar to has_expr_metavar, but ignores metavariables occurring in the type
of local constants */
bool has_expr_metavar_relaxed(expr const & e);
/** \brief Instantiate metavariables occurring in the expressions nested in \c c.
\remark The justification associated with each assignment are *not* propagaged.
We assume this is not a problem since we only used this procedure when connecting the
elaborator with the tactic framework. */
constraint instantiate_metavars(constraint const & c, substitution & s);
/** \brief Check whether the given term is type correct or not, undefined universe levels are ignored,
and untrusted macros are unfolded before performing the test.
These procedures are useful for checking whether intermediate results produced by
tactics and automation are type correct.
*/
void check_term(old_type_checker & tc, expr const & e);
void check_term(environment const & env, expr const & e);
/** \brief Return a justification for \c v_type being definitionally equal to \c t,
<tt> v : v_type</tt>, the expressiong \c src is used to extract position information.
*/
format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_type, expr const & t);
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src);
inline justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t) {
return mk_type_mismatch_jst(v, v_type, t, v);
}
/** \brief Create a type checker and normalizer that treats any constant named \c n as opaque when pred(n) is true.
Projections are reduced using the projection converter */
old_type_checker_ptr mk_type_checker(environment const & env, name_predicate const & pred);
/** \brief Create a type checker and normalizer that treats any constant named \c n as opaque when pred(n) is true.
No special support for projections is used */
old_type_checker_ptr mk_simple_type_checker(environment const & env, name_predicate const & pred);
/**
\brief Generate the format object for <tt>hyps |- conclusion</tt>.
The given substitution is applied to all elements.
*/
format format_goal(formatter const & fmt, buffer<expr> const & hyps, expr const & conclusion, substitution const & s);
/** \brief Given a metavariable application (?m l_1 ... l_n), apply \c s to the types of
?m and local constants l_i
Return the updated expression and a justification for all substitutions.
*/
pair<expr, justification> update_meta(expr const & meta, substitution s);
/** \brief Instantiate metavariable application \c meta (?M ...) using \c subst */
expr instantiate_meta(expr const & meta, substitution & subst);
/** \brief Return a 'failed to synthesize placholder' justification for the given
metavariable application \c m of the form (?m l_1 ... l_k) */
justification mk_failed_to_synthesize_jst(environment const & env, expr const & m);
/** \brief Return true if it is a lean internal name, i.e., the name starts with a `_` */
bool is_internal_name(name const & n);
void initialize_library_old_util();
void finalize_library_old_util();
}

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/projection.h"
#include "library/module.h"
#include "library/kernel_serializer.h"

View file

@ -6,7 +6,7 @@ Author: Leonardo de Moura
*/
#pragma once
#include <memory>
#include "library/util.h"
#include "library/old_util.h"
namespace lean {
enum class reducible_status { Reducible, Semireducible, Irreducible };

View file

@ -15,6 +15,7 @@ Author: Leonardo de Moura
#include "kernel/type_checker.h"
#include "library/metavar.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/tactic/goal.h"
namespace lean {

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/user_recursors.h"
#include "library/constants.h"
#include "library/reducible.h"

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "kernel/inductive/inductive.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/reducible.h"
#include "library/tactic/elaborate.h"
#include "library/tactic/expr_to_tactic.h"

View file

@ -17,6 +17,7 @@ Author: Leonardo de Moura
#include "kernel/replace_fn.h"
#include "library/normalize.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/tactic/tactic.h"
#include "library/io_state_stream.h"

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/old_type_checker.h"
#include "library/replace_visitor.h"
#include "library/constants.h"

View file

@ -8,7 +8,7 @@ Author: Leonardo de Moura
#include "library/tc_multigraph.h"
#include "library/old_type_checker.h"
#include "library/composition_manager.h"
#include "library/util.h"
#include "library/old_util.h"
namespace lean {
struct add_edge_fn {

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#include <string>
#include "kernel/kernel_exception.h"
#include "kernel/abstract_type_context.h"
#include "library/util.h"
#include "library/kernel_serializer.h"

View file

@ -9,8 +9,10 @@ Author: Leonardo de Moura
#include "util/sstream.h"
#include "kernel/find_fn.h"
#include "kernel/inductive/inductive.h"
#include "library/scoped_ext.h"
#include "library/util.h"
#include "library/old_util.h"
#include "library/scoped_ext.h"
#include "library/old_type_checker.h"
#include "library/kernel_serializer.h"
#include "library/user_recursors.h"
#include "library/attribute_manager.h"

View file

@ -34,18 +34,6 @@ bool is_standard(environment const & env) {
return env.prop_proof_irrel() && env.impredicative();
}
bool is_norm_pi(old_type_checker & tc, expr & e, constraint_seq & cs) {
constraint_seq new_cs = cs;
expr new_e = tc.whnf(e, new_cs);
if (is_pi(new_e)) {
e = new_e;
cs = new_cs;
return true;
} else {
return false;
}
}
optional<expr> unfold_term(environment const & env, expr const & e) {
expr const & f = get_app_fn(e);
if (!is_constant(f))
@ -90,8 +78,7 @@ optional<level> dec_level(level const & l) {
}
/** \brief Return true if environment has a constructor named \c c that returns
an element of the inductive datatype named \c I, and \c c must have \c nparams parameters.
*/
an element of the inductive datatype named \c I, and \c c must have \c nparams parameters. */
bool has_constructor(environment const & env, name const & c, name const & I, unsigned nparams) {
auto d = env.find(c);
if (!d || d->is_definition())
@ -128,11 +115,11 @@ bool has_lift_decls(environment const & env) {
return has_constructor(env, get_lift_up_name(), get_lift_name(), 2);
}
// n is considered to be recursive if it is an inductive datatype and
// 1) It has a constructor that takes n as an argument
// 2) It is part of a mutually recursive declaration, and some constructor
// of an inductive datatype takes another inductive datatype from the
// same declaration as an argument.
/* n is considered to be recursive if it is an inductive datatype and
1) It has a constructor that takes n as an argument
2) It is part of a mutually recursive declaration, and some constructor
of an inductive datatype takes another inductive datatype from the
same declaration as an argument. */
bool is_recursive_datatype(environment const & env, name const & n) {
optional<inductive::inductive_decls> decls = inductive::is_inductive_decl(env, n);
if (!decls)
@ -160,7 +147,7 @@ bool is_recursive_datatype(environment const & env, name const & n) {
return false;
}
bool is_reflexive_datatype(old_type_checker & tc, name const & n) {
bool is_reflexive_datatype(abstract_type_context & tc, name const & n) {
environment const & env = tc.env();
optional<inductive::inductive_decls> decls = inductive::is_inductive_decl(env, n);
if (!decls)
@ -169,7 +156,7 @@ bool is_reflexive_datatype(old_type_checker & tc, name const & n) {
for (inductive::intro_rule const & intro : inductive::inductive_decl_intros(decl)) {
expr type = inductive::intro_rule_type(intro);
while (is_pi(type)) {
expr arg = tc.whnf(binding_domain(type)).first;
expr arg = tc.whnf(binding_domain(type));
if (is_pi(arg) && find(arg, [&](expr const & e, unsigned) { return is_constant(e) && const_name(e) == n; })) {
return true;
}
@ -257,663 +244,6 @@ expr fun_to_telescope(expr const & e, buffer<expr> & telescope,
return to_telescope(false, e, telescope, binfo);
}
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo,
constraint_seq & cs) {
expr new_type = tc.whnf(type, cs);
while (is_pi(new_type)) {
type = new_type;
expr local;
if (binfo)
local = mk_local(mk_fresh_name(), binding_name(type), binding_domain(type), *binfo);
else
local = mk_local(mk_fresh_name(), binding_name(type), binding_domain(type), binding_info(type));
telescope.push_back(local);
type = instantiate(binding_body(type), local);
new_type = tc.whnf(type, cs);
}
return type;
}
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo) {
constraint_seq cs;
return to_telescope(tc, type, telescope, binfo, cs);
}
expr mk_false() {
return mk_constant(get_false_name());
}
expr mk_empty() {
return mk_constant(get_empty_name());
}
expr mk_false(environment const & env) {
return is_standard(env) ? mk_false() : mk_empty();
}
bool is_false(expr const & e) {
return is_constant(e) && const_name(e) == get_false_name();
}
bool is_empty(expr const & e) {
return is_constant(e) && const_name(e) == get_empty_name();
}
bool is_false(environment const & env, expr const & e) {
return is_standard(env) ? is_false(e) : is_empty(e);
}
expr mk_false_rec(old_type_checker & tc, expr const & f, expr const & t) {
level t_lvl = sort_level(tc.ensure_type(t).first);
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_false_rec_name(), {t_lvl}), t, f);
} else {
expr f_type = tc.infer(f).first;
return mk_app(mk_constant(get_empty_rec_name(), {t_lvl}), mk_lambda("e", f_type, t), f);
}
}
bool is_or(expr const & e) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_or_name() && args.size() == 2) return true;
else return false;
}
bool is_or(expr const & e, expr & A, expr & B) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_or_name() && args.size() == 2) {
A = args[0];
B = args[1];
return true;
} else {
return false;
}
}
bool is_not(environment const & env, expr const & e, expr & a) {
if (is_app(e)) {
expr const & f = app_fn(e);
if (!is_constant(f) || const_name(f) != get_not_name())
return false;
a = app_arg(e);
return true;
} else if (is_pi(e)) {
if (!is_false(env, binding_body(e)))
return false;
a = binding_domain(e);
return true;
} else {
return false;
}
}
bool is_not(environment const & env, expr const & e) {
if (is_app(e)) {
expr const & f = app_fn(e);
if (!is_constant(f) || const_name(f) != get_not_name())
return false;
return true;
} else if (is_pi(e)) {
if (!is_false(env, binding_body(e))) return false;
return true;
} else {
return false;
}
}
expr mk_not(old_type_checker & tc, expr const & e) {
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_not_name()), e);
} else {
level l = sort_level(tc.ensure_type(e).first);
return mk_app(mk_constant(get_not_name(), {l}), e);
}
}
expr mk_absurd(old_type_checker & tc, expr const & t, expr const & e, expr const & not_e) {
level t_lvl = sort_level(tc.ensure_type(t).first);
expr e_type = tc.infer(e).first;
if (is_standard(tc.env())) {
return mk_app(mk_constant(get_absurd_name(), {t_lvl}), e_type, t, e, not_e);
} else {
level e_lvl = sort_level(tc.ensure_type(e_type).first);
return mk_app(mk_constant(get_absurd_name(), {e_lvl, t_lvl}), e_type, t, e, not_e);
}
}
optional<expr> lift_down_if_hott(old_type_checker & tc, expr const & v) {
if (is_standard(tc.env())) {
return some_expr(v);
} else {
expr v_type = tc.whnf(tc.infer(v).first).first;
if (!is_app(v_type))
return none_expr();
expr const & lift = app_fn(v_type);
if (!is_constant(lift) || const_name(lift) != get_lift_name())
return none_expr();
return some_expr(mk_app(mk_constant(get_lift_down_name(), const_levels(lift)), app_arg(v_type), v));
}
}
static expr * g_true = nullptr;
static expr * g_true_intro = nullptr;
static expr * g_and = nullptr;
static expr * g_and_intro = nullptr;
static expr * g_and_elim_left = nullptr;
static expr * g_and_elim_right = nullptr;
void initialize_library_util() {
g_true = new expr(mk_constant(get_true_name()));
g_true_intro = new expr(mk_constant(get_true_intro_name()));
g_and = new expr(mk_constant(get_and_name()));
g_and_intro = new expr(mk_constant(get_and_intro_name()));
g_and_elim_left = new expr(mk_constant(get_and_elim_left_name()));
g_and_elim_right = new expr(mk_constant(get_and_elim_right_name()));
}
void finalize_library_util() {
delete g_true;
delete g_true_intro;
delete g_and;
delete g_and_intro;
delete g_and_elim_left;
delete g_and_elim_right;
}
expr mk_true() {
return *g_true;
}
bool is_true(expr const & e) {
return e == *g_true;
}
expr mk_true_intro() {
return *g_true_intro;
}
bool is_and(expr const & e, expr & arg1, expr & arg2) {
if (get_app_fn(e) == *g_and) {
buffer<expr> args; get_app_args(e, args);
if (args.size() == 2) {
arg1 = args[0];
arg2 = args[1];
return true;
} else {
return false;
}
} else {
return false;
}
}
bool is_and(expr const & e) {
if (get_app_fn(e) == *g_and) {
buffer<expr> args; get_app_args(e, args);
if (args.size() == 2) return true;
else return false;
} else {
return false;
}
}
expr mk_and(expr const & a, expr const & b) {
return mk_app(*g_and, a, b);
}
expr mk_and_intro(old_type_checker & tc, expr const & Ha, expr const & Hb) {
return mk_app(*g_and_intro, tc.infer(Ha).first, tc.infer(Hb).first, Ha, Hb);
}
expr mk_and_elim_left(old_type_checker & tc, expr const & H) {
expr a_and_b = tc.whnf(tc.infer(H).first).first;
return mk_app(*g_and_elim_left, app_arg(app_fn(a_and_b)), app_arg(a_and_b), H);
}
expr mk_and_elim_right(old_type_checker & tc, expr const & H) {
expr a_and_b = tc.whnf(tc.infer(H).first).first;
return mk_app(*g_and_elim_right, app_arg(app_fn(a_and_b)), app_arg(a_and_b), H);
}
expr mk_unit(level const & l) {
return mk_constant(get_poly_unit_name(), {l});
}
expr mk_unit_mk(level const & l) {
return mk_constant(get_poly_unit_star_name(), {l});
}
expr mk_prod(old_type_checker & tc, expr const & A, expr const & B) {
level l1 = sort_level(tc.ensure_type(A).first);
level l2 = sort_level(tc.ensure_type(B).first);
return mk_app(mk_constant(get_prod_name(), {l1, l2}), A, B);
}
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b) {
expr A = tc.infer(a).first;
expr B = tc.infer(b).first;
level l1 = sort_level(tc.ensure_type(A).first);
level l2 = sort_level(tc.ensure_type(B).first);
return mk_app(mk_constant(get_prod_mk_name(), {l1, l2}), A, B, a, b);
}
expr mk_pr1(old_type_checker & tc, expr const & p) {
expr AxB = tc.whnf(tc.infer(p).first).first;
expr const & A = app_arg(app_fn(AxB));
expr const & B = app_arg(AxB);
return mk_app(mk_constant(get_prod_pr1_name(), const_levels(get_app_fn(AxB))), A, B, p);
}
expr mk_pr2(old_type_checker & tc, expr const & p) {
expr AxB = tc.whnf(tc.infer(p).first).first;
expr const & A = app_arg(app_fn(AxB));
expr const & B = app_arg(AxB);
return mk_app(mk_constant(get_prod_pr2_name(), const_levels(get_app_fn(AxB))), A, B, p);
}
expr mk_unit(level const & l, bool prop) { return prop ? mk_true() : mk_unit(l); }
expr mk_unit_mk(level const & l, bool prop) { return prop ? mk_true_intro() : mk_unit_mk(l); }
expr mk_prod(old_type_checker & tc, expr const & a, expr const & b, bool prop) { return prop ? mk_and(a, b) : mk_prod(tc, a, b); }
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b, bool prop) {
return prop ? mk_and_intro(tc, a, b) : mk_pair(tc, a, b);
}
expr mk_pr1(old_type_checker & tc, expr const & p, bool prop) { return prop ? mk_and_elim_left(tc, p) : mk_pr1(tc, p); }
expr mk_pr2(old_type_checker & tc, expr const & p, bool prop) { return prop ? mk_and_elim_right(tc, p) : mk_pr2(tc, p); }
bool is_ite(expr const & e, expr & c, expr & H, expr & A, expr & t, expr & f) {
expr const & fn = get_app_fn(e);
if (is_constant(fn) && const_name(fn) == get_ite_name()) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() == 5) {
c = args[0]; H = args[1]; A = args[2]; t = args[3]; f = args[4];
return true;
} else {
return false;
}
} else {
return false;
}
}
bool is_ite(expr const & e) {
expr const & fn = get_app_fn(e);
if (is_constant(fn) && const_name(fn) == get_ite_name()) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() == 5) return true;
else return false;
} else {
return false;
}
}
bool is_iff(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_iff_name();
}
bool is_iff(expr const & e, expr & lhs, expr & rhs) {
if (!is_iff(e) || !is_app(app_fn(e)))
return false;
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
expr mk_iff(expr const & lhs, expr const & rhs) {
return mk_app(mk_constant(get_iff_name()), lhs, rhs);
}
expr mk_iff_refl(expr const & a) {
return mk_app(mk_constant(get_iff_refl_name()), a);
}
expr apply_propext(expr const & iff_pr, expr const & iff_term) {
lean_assert(is_iff(iff_term));
return mk_app(mk_constant(get_propext_name()), app_arg(app_fn(iff_term)), app_arg(iff_term), iff_pr);
}
expr mk_eq(old_type_checker & tc, expr const & lhs, expr const & rhs) {
expr A = tc.whnf(tc.infer(lhs).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_name(), {lvl}), A, lhs, rhs);
}
expr mk_refl(old_type_checker & tc, expr const & a) {
expr A = tc.whnf(tc.infer(a).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_refl_name(), {lvl}), A, a);
}
expr mk_symm(old_type_checker & tc, expr const & H) {
expr p = tc.whnf(tc.infer(H).first).first;
lean_assert(is_eq(p));
expr lhs = app_arg(app_fn(p));
expr rhs = app_arg(p);
expr A = tc.infer(lhs).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_eq_symm_name(), {lvl}), A, lhs, rhs, H);
}
expr mk_trans(old_type_checker & tc, expr const & H1, expr const & H2) {
expr p1 = tc.whnf(tc.infer(H1).first).first;
expr p2 = tc.whnf(tc.infer(H2).first).first;
lean_assert(is_eq(p1) && is_eq(p2));
expr lhs1 = app_arg(app_fn(p1));
expr rhs1 = app_arg(p1);
expr rhs2 = app_arg(p2);
expr A = tc.infer(lhs1).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app({mk_constant(get_eq_trans_name(), {lvl}), A, lhs1, rhs1, rhs2, H1, H2});
}
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & x, expr const & y, expr const & xeqy, expr const & h) {
expr A = tc.infer(x).first;
level l1 = sort_level(tc.ensure_type(A).first);
expr r;
if (is_standard(tc.env())) {
r = mk_constant(get_eq_subst_name(), {l1});
} else {
level l2 = sort_level(tc.ensure_type(tc.infer(h).first).first);
r = mk_constant(get_eq_subst_name(), {l1, l2});
}
return mk_app({r, A, x, y, motive, xeqy, h});
}
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & xeqy, expr const & h) {
expr xeqy_type = tc.whnf(tc.infer(xeqy).first).first;
return mk_subst(tc, motive, app_arg(app_fn(xeqy_type)), app_arg(xeqy_type), xeqy, h);
}
expr mk_subsingleton_elim(old_type_checker & tc, expr const & h, expr const & x, expr const & y) {
expr A = tc.infer(x).first;
level l = sort_level(tc.ensure_type(A).first);
expr r;
if (is_standard(tc.env())) {
r = mk_constant(get_subsingleton_elim_name(), {l});
} else {
r = mk_constant(get_is_trunc_is_prop_elim_name(), {l});
}
return mk_app({r, A, h, x, y});
}
expr mk_heq(old_type_checker & tc, expr const & lhs, expr const & rhs) {
expr A = tc.whnf(tc.infer(lhs).first).first;
expr B = tc.whnf(tc.infer(rhs).first).first;
level lvl = sort_level(tc.ensure_type(A).first);
return mk_app(mk_constant(get_heq_name(), {lvl}), A, lhs, B, rhs);
}
bool is_eq_rec_core(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_eq_rec_name();
}
bool is_eq_rec(environment const & env, expr const & e) {
expr const & fn = get_app_fn(e);
if (!is_constant(fn))
return false;
return is_standard(env) ? const_name(fn) == get_eq_rec_name() : const_name(fn) == get_eq_nrec_name();
}
bool is_eq_drec(environment const & env, expr const & e) {
expr const & fn = get_app_fn(e);
if (!is_constant(fn))
return false;
return is_standard(env) ? const_name(fn) == get_eq_drec_name() : const_name(fn) == get_eq_rec_name();
}
bool is_eq(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_eq_name();
}
bool is_eq(expr const & e, expr & lhs, expr & rhs) {
if (!is_eq(e) || get_app_num_args(e) != 3)
return false;
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
bool is_eq(expr const & e, expr & A, expr & lhs, expr & rhs) {
if (!is_eq(e) || get_app_num_args(e) != 3)
return false;
A = app_arg(app_fn(app_fn(e)));
lhs = app_arg(app_fn(e));
rhs = app_arg(e);
return true;
}
bool is_eq_a_a(expr const & e) {
if (!is_eq(e))
return false;
buffer<expr> args;
get_app_args(e, args);
return args.size() == 3 && args[1] == args[2];
}
bool is_eq_a_a(old_type_checker & tc, expr const & e) {
if (!is_eq(e))
return false;
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 3)
return false;
pair<bool, constraint_seq> d = tc.is_def_eq(args[1], args[2]);
return d.first && !d.second;
}
bool is_heq(expr const & e) {
expr const & fn = get_app_fn(e);
return is_constant(fn) && const_name(fn) == get_heq_name();
}
bool is_heq(expr const & e, expr & A, expr & lhs, expr & B, expr & rhs) {
if (is_heq(e)) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 4)
return false;
A = args[0]; lhs = args[1]; B = args[2]; rhs = args[3];
return true;
} else {
return false;
}
}
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> const & s, buffer<expr> & eqs) {
lean_assert(t.size() == s.size());
lean_assert(std::all_of(s.begin(), s.end(), is_local));
lean_assert(inductive::has_dep_elim(tc.env(), get_eq_name()));
buffer<buffer<expr>> t_aux;
name e_name("e");
for (unsigned i = 0; i < t.size(); i++) {
expr s_i = s[i];
expr s_i_ty = mlocal_type(s_i);
expr s_i_ty_a = abstract_locals(s_i_ty, i, s.data());
expr t_i = t[i];
t_aux.push_back(buffer<expr>());
t_aux.back().push_back(t_i);
for (unsigned j = 0; j < i; j++) {
if (depends_on(s_i_ty, s[j])) {
// we need to "cast"
buffer<expr> ty_inst_args;
for (unsigned k = 0; k <= j; k++)
ty_inst_args.push_back(s[k]);
for (unsigned k = j + 1; k < i; k++)
ty_inst_args.push_back(t_aux[k][j+1]);
lean_assert(ty_inst_args.size() == i);
expr s_i_ty = instantiate_rev(s_i_ty_a, i, ty_inst_args.data());
buffer<expr> rec_args;
rec_args.push_back(mlocal_type(s[j]));
rec_args.push_back(t_aux[j][j]);
rec_args.push_back(Fun(s[j], Fun(eqs[j], s_i_ty))); // type former ("promise")
rec_args.push_back(t_i); // minor premise
rec_args.push_back(s[j]);
rec_args.push_back(eqs[j]);
level rec_l1 = sort_level(tc.ensure_type(s_i_ty).first);
level rec_l2 = sort_level(tc.ensure_type(mlocal_type(s[j])).first);
t_i = mk_app(mk_constant(get_eq_rec_name(), {rec_l1, rec_l2}), rec_args.size(), rec_args.data());
}
t_aux.back().push_back(t_i);
}
expr eq = mk_local(mk_fresh_name(), e_name.append_after(i+1), mk_eq(tc, t_i, s_i), binder_info());
eqs.push_back(eq);
}
}
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> & eqs) {
lean_assert(std::all_of(t.begin(), t.end(), is_local));
lean_assert(inductive::has_dep_elim(tc.env(), get_eq_name()));
buffer<expr> s;
for (unsigned i = 0; i < t.size(); i++) {
expr ty = mlocal_type(t[i]);
ty = abstract_locals(ty, i, t.data());
ty = instantiate_rev(ty, i, s.data());
expr local = mk_local(mk_fresh_name(), local_pp_name(t[i]).append_after("'"), ty, local_info(t[i]));
s.push_back(local);
}
return mk_telescopic_eq(tc, t, s, eqs);
}
level mk_max(levels const & ls) {
if (!ls)
return mk_level_zero();
else if (!tail(ls))
return head(ls);
else
return mk_max(head(ls), mk_max(tail(ls)));
}
expr telescope_to_sigma(old_type_checker & tc, unsigned sz, expr const * ts, constraint_seq & cs) {
lean_assert(sz > 0);
unsigned i = sz - 1;
expr r = mlocal_type(ts[i]);
while (i > 0) {
--i;
expr const & a = ts[i];
expr const & A = mlocal_type(a);
expr const & Ba = r;
level l1 = sort_level(tc.ensure_type(A, cs));
level l2 = sort_level(tc.ensure_type(Ba, cs));
r = mk_app(mk_constant(get_sigma_name(), {l1, l2}), A, Fun(a, Ba));
}
return r;
}
expr mk_sigma_mk(old_type_checker & tc, unsigned sz, expr const * ts, expr const * as, constraint_seq & cs) {
lean_assert(sz > 0);
if (sz == 1)
return as[0];
buffer<expr> new_ts;
for (unsigned i = 1; i < sz; i++)
new_ts.push_back(instantiate(abstract_local(ts[i], ts[0]), as[0]));
expr arg1 = mlocal_type(ts[0]);
expr arg2_core = telescope_to_sigma(tc, sz-1, ts+1, cs);
expr arg2 = Fun(ts[0], arg2_core);
expr arg3 = as[0];
expr arg4 = mk_sigma_mk(tc, sz-1, new_ts.data(), as+1, cs);
level l1 = sort_level(tc.ensure_type(arg1, cs));
level l2 = sort_level(tc.ensure_type(arg2_core, cs));
return mk_app(mk_constant(get_sigma_mk_name(), {l1, l2}), arg1, arg2, arg3, arg4);
}
expr mk_sigma_mk(old_type_checker & tc, buffer<expr> const & ts, buffer<expr> const & as, constraint_seq & cs) {
lean_assert(ts.size() == as.size());
return mk_sigma_mk(tc, ts.size(), ts.data(), as.data(), cs);
}
bool is_none(expr const & e, expr & A) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_option_none_name() && args.size() == 1) {
A = args[0];
return true;
} else {
return false;
}
}
bool is_some(expr const & e, expr & A, expr & a) {
buffer<expr> args;
expr const & fn = get_app_args(e, args);
if (is_constant(fn) && const_name(fn) == get_option_some_name() && args.size() == 2) {
A = args[0];
a = args[1];
return true;
} else {
return false;
}
}
expr infer_implicit_params(expr const & type, unsigned nparams, implicit_infer_kind k) {
switch (k) {
case implicit_infer_kind::Implicit: {
bool strict = true;
return infer_implicit(type, nparams, strict);
}
case implicit_infer_kind::RelaxedImplicit: {
bool strict = false;
return infer_implicit(type, nparams, strict);
}
case implicit_infer_kind::None:
return type;
}
lean_unreachable(); // LCOV_EXCL_LINE
}
bool has_expr_metavar_relaxed(expr const & e) {
if (!has_expr_metavar(e))
return false;
bool found = false;
for_each(e, [&](expr const & e, unsigned) {
if (found || !has_expr_metavar(e))
return false;
if (is_metavar(e)) {
found = true;
return false;
}
if (is_local(e))
return false; // do not visit type
return true;
});
return found;
}
constraint instantiate_metavars(constraint const & c, substitution & s) {
switch (c.kind()) {
case constraint_kind::Eq:
return mk_eq_cnstr(s.instantiate_all(cnstr_lhs_expr(c)),
s.instantiate_all(cnstr_rhs_expr(c)),
c.get_justification());
case constraint_kind::LevelEq:
return mk_level_eq_cnstr(s.instantiate(cnstr_lhs_level(c)), s.instantiate(cnstr_rhs_level(c)), c.get_justification());
case constraint_kind::Choice: {
expr m = cnstr_expr(c);
lean_assert(is_meta(m));
buffer<expr> args;
expr mvar = get_app_args(m, args);
mvar = update_mlocal(mvar, s.instantiate_all(mlocal_type(mvar)));
for (expr & arg : args)
arg = s.instantiate_all(arg);
return mk_choice_cnstr(mk_app(mvar, args),
cnstr_choice_fn(c),
cnstr_delay_factor_core(c),
cnstr_is_owner(c), c.get_justification());
}}
lean_unreachable(); // LCOV_EXCL_LINE
}
void check_term(old_type_checker & tc, expr const & e) {
expr tmp = unfold_untrusted_macros(tc.env(), e);
tc.check_ignore_undefined_universes(tmp);
}
void check_term(environment const & env, expr const & e) {
expr tmp = unfold_untrusted_macros(env, e);
old_type_checker(env).check_ignore_undefined_universes(tmp);
}
format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_type, expr const & t) {
format expected_fmt, given_fmt;
std::tie(expected_fmt, given_fmt) = pp_until_different(fmt, t, v_type);
@ -926,103 +256,9 @@ format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_ty
return r;
}
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src) {
return mk_justification(src, [=](formatter const & fmt, substitution const & subst, bool) {
substitution s(subst);
return pp_type_mismatch(fmt, s.instantiate(v), s.instantiate(v_type), s.instantiate(t));
});
void initialize_library_util() {
}
format format_goal(formatter const & _fmt, buffer<expr> const & hyps, expr const & conclusion, substitution const & s) {
substitution tmp_subst(s);
options opts = _fmt.get_options();
opts = opts.update_if_undef(get_pp_purify_locals_name(), false);
formatter fmt = _fmt.update_options(opts);
unsigned indent = get_pp_indent(opts);
bool unicode = get_pp_unicode(opts);
bool compact = get_pp_goal_compact(opts);
unsigned max_hs = get_pp_goal_max_hyps(opts);
format turnstile = unicode ? format("\u22A2") /* ⊢ */ : format("|-");
format r;
unsigned i = std::min(max_hs, hyps.size());
bool first = true;
while (i > 0) {
i--;
expr l = hyps[i];
format ids = fmt(l);
expr t = tmp_subst.instantiate(mlocal_type(l));
lean_assert(hyps.size() > 0);
while (i > 0) {
expr l2 = hyps[i-1];
expr t2 = tmp_subst.instantiate(mlocal_type(l2));
if (t2 != t)
break;
ids = fmt(l2) + space() + ids;
i--;
}
if (first)
first = false;
else
r = compose(comma(), line()) + r;
r = group(ids + space() + colon() + nest(indent, line() + fmt(t))) + r;
}
if (hyps.size() > max_hs)
r = r + compose(comma(), line()) + format("... (set pp.goal.max_hypotheses to display remaining hypotheses)");
if (compact)
r = group(r);
r += line() + turnstile + space() + nest(indent, fmt(tmp_subst.instantiate(conclusion)));
if (compact)
r = group(r);
return r;
}
pair<expr, justification> update_meta(expr const & meta, substitution s) {
buffer<expr> args;
expr mvar = get_app_args(meta, args);
justification j;
auto p = s.instantiate_metavars(mlocal_type(mvar));
mvar = update_mlocal(mvar, p.first);
j = p.second;
for (expr & arg : args) {
auto p = s.instantiate_metavars(mlocal_type(arg));
arg = update_mlocal(arg, p.first);
j = mk_composite1(j, p.second);
}
return mk_pair(mk_app(mvar, args), j);
}
expr instantiate_meta(expr const & meta, substitution & subst) {
lean_assert(is_meta(meta));
buffer<expr> locals;
expr mvar = get_app_args(meta, locals);
mvar = update_mlocal(mvar, subst.instantiate_all(mlocal_type(mvar)));
for (auto & local : locals)
local = subst.instantiate_all(local);
return mk_app(mvar, locals);
}
justification mk_failed_to_synthesize_jst(environment const & env, expr const & m) {
return mk_justification(m, [=](formatter const & fmt, substitution const & subst, bool) {
substitution tmp(subst);
expr new_m = instantiate_meta(m, tmp);
expr new_type = old_type_checker(env).infer(new_m).first;
buffer<expr> hyps;
get_app_args(new_m, hyps);
return format("failed to synthesize placeholder") + line() + format_goal(fmt, hyps, new_type, subst);
});
}
old_type_checker_ptr mk_type_checker(environment const & env, name_predicate const & pred) {
return std::unique_ptr<old_type_checker>(new old_type_checker(env,
std::unique_ptr<old_converter>(new hint_old_converter<projection_converter>(env, pred))));
}
old_type_checker_ptr mk_simple_type_checker(environment const & env, name_predicate const & pred) {
return std::unique_ptr<old_type_checker>(new old_type_checker(env,
std::unique_ptr<old_converter>(new hint_old_converter<old_default_converter>(env, pred))));
}
bool is_internal_name(name const & n) {
return !n.is_anonymous() && n.is_string() && n.get_string() && n.get_string()[0] == '_';
void finalize_library_util() {
}
}

View file

@ -6,7 +6,6 @@ Author: Leonardo de Moura
*/
#pragma once
#include "kernel/environment.h"
#include "library/old_type_checker.h"
namespace lean {
/** \brief Return true iff t is a constant named f_name or an application of the form (f_name a_1 ... a_k) */
@ -14,51 +13,41 @@ bool is_app_of(expr const & t, name const & f_name);
/** \brief Return true iff t is a constant named f_name or an application of the form (f_name a_1 ... a_nargs) */
bool is_app_of(expr const & t, name const & f_name, unsigned nargs);
typedef std::unique_ptr<old_type_checker> old_type_checker_ptr;
/** \brief Unfold constant \c e or constant application (i.e., \c e is of the form (f ....),
where \c f is a constant */
optional<expr> unfold_term(environment const & env, expr const & e);
/** \brief If \c e is of the form <tt>(f a_1 ... a_n)</tt>, where \c f is
a non-opaque definition, then unfold \c f, and beta reduce.
Otherwise, return none.
*/
Otherwise, return none. */
optional<expr> unfold_app(environment const & env, expr const & e);
/** \brief Reduce (if possible) universe level by 1.
\pre is_not_zero(l)
*/
\pre is_not_zero(l) */
optional<level> dec_level(level const & l);
/** \brief Return true iff \c env has been configured with an impredicative and proof irrelevant Prop. */
bool is_standard(environment const & env);
/** Return true if \c e can be normalized into a Pi type,
If the result is true, then \c e and \c cs are updated.
*/
bool is_norm_pi(type_checker & tc, expr & e, constraint_seq & cs);
bool has_poly_unit_decls(environment const & env);
bool has_eq_decls(environment const & env);
bool has_heq_decls(environment const & env);
bool has_prod_decls(environment const & env);
bool has_lift_decls(environment const & env);
/** \brief Return true iff \c n is the name of a recursive datatype in \c env.
That is, it must be an inductive datatype AND contain a recursive constructor.
\remark Records are inductive datatypes, but they are not recursive.
\remark For mutually indutive datatypes, \c n is considered recursive
if there is a constructor taking \c n.
*/
if there is a constructor taking \c n. */
bool is_recursive_datatype(environment const & env, name const & n);
/** \brief Return true if \c n is a recursive *and* reflexive datatype.
We say an inductive type T is reflexive if it contains at least one constructor that
takes as an argument a function returning T.
*/
bool is_reflexive_datatype(old_type_checker & tc, name const & n);
takes as an argument a function returning T. */
bool is_reflexive_datatype(abstract_type_context & tc, name const & n);
/** \brief Return true iff \c n is an inductive predicate, i.e., an inductive datatype that is in Prop.
@ -89,16 +78,6 @@ optional<name> is_constructor_app_ext(environment const & env, expr const & e);
*/
expr to_telescope(expr const & type, buffer<expr> & telescope,
optional<binder_info> const & binfo = optional<binder_info>());
/** \brief Similar to previous procedure, but puts \c type in whnf */
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope,
optional<binder_info> const & binfo = optional<binder_info>());
/** \brief Similar to previous procedure, but also accumulates constraints generated while
normalizing type.
\remark Constraints are generated only if \c type constains metavariables.
*/
expr to_telescope(old_type_checker & tc, expr type, buffer<expr> & telescope, optional<binder_info> const & binfo,
constraint_seq & cs);
/** \brief "Consume" fun/lambda. This procedure creates local constants based on the arguments of \c e
and store them in telescope. If \c binfo is provided, then the local constants are annoted with the given
@ -114,183 +93,9 @@ level get_datatype_level(expr ind_type);
expr instantiate_univ_param (expr const & e, name const & p, level const & l);
expr mk_true();
bool is_true(expr const & e);
expr mk_true_intro();
bool is_and(expr const & e, expr & arg1, expr & arg2);
bool is_and(expr const & e);
expr mk_and(expr const & a, expr const & b);
expr mk_and_intro(old_type_checker & tc, expr const & Ha, expr const & Hb);
expr mk_and_elim_left(old_type_checker & tc, expr const & H);
expr mk_and_elim_right(old_type_checker & tc, expr const & H);
expr mk_poly_unit(level const & l);
expr mk_poly_unit_mk(level const & l);
expr mk_prod(old_type_checker & tc, expr const & A, expr const & B);
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b);
expr mk_pr1(old_type_checker & tc, expr const & p);
expr mk_pr2(old_type_checker & tc, expr const & p);
expr mk_unit(level const & l, bool prop);
expr mk_unit_mk(level const & l, bool prop);
expr mk_prod(old_type_checker & tc, expr const & a, expr const & b, bool prop);
expr mk_pair(old_type_checker & tc, expr const & a, expr const & b, bool prop);
expr mk_pr1(old_type_checker & tc, expr const & p, bool prop);
expr mk_pr2(old_type_checker & tc, expr const & p, bool prop);
expr mk_false();
expr mk_empty();
/** \brief Return false (in standard mode) and empty (in HoTT) mode */
expr mk_false(environment const & env);
bool is_false(expr const & e);
bool is_empty(expr const & e);
/** \brief Return true iff \c e is false (in standard mode) or empty (in HoTT) mode */
bool is_false(environment const & env, expr const & e);
/** \brief Return an element of type t given an element \c f : false (in standard mode) and empty (in HoTT) mode */
expr mk_false_rec(old_type_checker & tc, expr const & f, expr const & t);
bool is_or(expr const & e);
bool is_or(expr const & e, expr & A, expr & B);
/** \brief Return true if \c e is of the form <tt>(not arg)</tt>, and store \c arg in \c a.
Return false otherwise */
bool is_not(environment const & env, expr const & e, expr & a);
bool is_not(environment const & env, expr const & e);
expr mk_not(old_type_checker & tc, expr const & e);
/** \brief Create the term <tt>absurd e not_e : t</tt>. */
expr mk_absurd(old_type_checker & tc, expr const & t, expr const & e, expr const & not_e);
expr mk_eq(old_type_checker & tc, expr const & lhs, expr const & rhs);
expr mk_refl(old_type_checker & tc, expr const & a);
expr mk_symm(old_type_checker & tc, expr const & H);
expr mk_trans(old_type_checker & tc, expr const & H1, expr const & H2);
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & x, expr const & y, expr const & xeqy, expr const & h);
expr mk_subst(old_type_checker & tc, expr const & motive, expr const & xeqy, expr const & h);
/** \brief Create an proof for x = y using subsingleton.elim (in standard mode) and is_trunc.is_prop.elim (in HoTT mode) */
expr mk_subsingleton_elim(old_type_checker & tc, expr const & h, expr const & x, expr const & y);
/** \brief Return true iff \c e is a term of the form (eq.rec ....) */
bool is_eq_rec_core(expr const & e);
/** \brief Return true iff \c e is a term of the form (eq.rec ....) in the standard library,
and (eq.nrec ...) in the HoTT library. */
bool is_eq_rec(environment const & env, expr const & e);
/** \brief Return true iff \c e is a term of the form (eq.drec ....) in the standard library,
and (eq.rec ...) in the HoTT library. */
bool is_eq_drec(environment const & env, expr const & e);
bool is_eq(expr const & e);
bool is_eq(expr const & e, expr & lhs, expr & rhs);
bool is_eq(expr const & e, expr & A, expr & lhs, expr & rhs);
/** \brief Return true iff \c e is of the form (eq A a a) */
bool is_eq_a_a(expr const & e);
/** \brief Return true iff \c e is of the form (eq A a a') where \c a and \c a' are definitionally equal */
bool is_eq_a_a(old_type_checker & tc, expr const & e);
bool is_heq(expr const & e);
bool is_heq(expr const & e, expr & A, expr & lhs, expr & B, expr & rhs);
bool is_ite(expr const & e, expr & c, expr & H, expr & A, expr & t, expr & f);
bool is_ite(expr const & e);
bool is_iff(expr const & e);
bool is_iff(expr const & e, expr & lhs, expr & rhs);
expr mk_iff(expr const & lhs, expr const & rhs);
expr mk_iff_refl(expr const & a);
/** \brief Given <tt>iff_pr : iff_term</tt>, where \c iff_term is of the form <tt>l <-> r</tt>,
return the term <tt>propext l r iff_pr</tt>
*/
expr apply_propext(expr const & iff_pr, expr const & iff_term);
/** \brief If in HoTT mode, apply lift.down.
The no_confusion constructions uses lifts in the proof relevant version (aka HoTT mode).
We must apply lift.down to eliminate the auxiliary lift.
*/
optional<expr> lift_down_if_hott(old_type_checker & tc, expr const & v);
/** \brief Create a telescope equality for HoTT library.
This procedure assumes eq supports dependent elimination.
For HoTT, we can't use heterogeneous equality.
*/
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> const & s, buffer<expr> & eqs);
void mk_telescopic_eq(old_type_checker & tc, buffer<expr> const & t, buffer<expr> & eqs);
level mk_max(levels const & ls);
expr mk_sigma_mk(old_type_checker & tc, buffer<expr> const & ts, buffer<expr> const & as, constraint_seq & cs);
/** \brief Return true iff \c e is of the form (@option.none A), and update \c A */
bool is_none(expr const & e, expr & A);
/** \brief Return true iff \c e is of the form (@option.some A a), and update \c A and \c a */
bool is_some(expr const & e, expr & A, expr & a);
enum class implicit_infer_kind { Implicit, RelaxedImplicit, None };
/** \brief Infer implicit parameter annotations for the first \c nparams using mode
specified by \c k.
*/
expr infer_implicit_params(expr const & type, unsigned nparams, implicit_infer_kind k);
/** \brief Similar to has_expr_metavar, but ignores metavariables occurring in the type
of local constants */
bool has_expr_metavar_relaxed(expr const & e);
/** \brief Instantiate metavariables occurring in the expressions nested in \c c.
\remark The justification associated with each assignment are *not* propagaged.
We assume this is not a problem since we only used this procedure when connecting the
elaborator with the tactic framework. */
constraint instantiate_metavars(constraint const & c, substitution & s);
/** \brief Check whether the given term is type correct or not, undefined universe levels are ignored,
and untrusted macros are unfolded before performing the test.
These procedures are useful for checking whether intermediate results produced by
tactics and automation are type correct.
*/
void check_term(old_type_checker & tc, expr const & e);
void check_term(environment const & env, expr const & e);
/** \brief Return a justification for \c v_type being definitionally equal to \c t,
<tt> v : v_type</tt>, the expressiong \c src is used to extract position information.
*/
/** \brief Create a format object for a type mismatch where typeof(v) (i.e., v_type) does not match
expected type \c t. */
format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_type, expr const & t);
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src);
inline justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t) {
return mk_type_mismatch_jst(v, v_type, t, v);
}
/** \brief Create a type checker and normalizer that treats any constant named \c n as opaque when pred(n) is true.
Projections are reduced using the projection converter */
old_type_checker_ptr mk_type_checker(environment const & env, name_predicate const & pred);
/** \brief Create a type checker and normalizer that treats any constant named \c n as opaque when pred(n) is true.
No special support for projections is used */
old_type_checker_ptr mk_simple_type_checker(environment const & env, name_predicate const & pred);
/**
\brief Generate the format object for <tt>hyps |- conclusion</tt>.
The given substitution is applied to all elements.
*/
format format_goal(formatter const & fmt, buffer<expr> const & hyps, expr const & conclusion, substitution const & s);
/** \brief Given a metavariable application (?m l_1 ... l_n), apply \c s to the types of
?m and local constants l_i
Return the updated expression and a justification for all substitutions.
*/
pair<expr, justification> update_meta(expr const & meta, substitution s);
/** \brief Instantiate metavariable application \c meta (?M ...) using \c subst */
expr instantiate_meta(expr const & meta, substitution & subst);
/** \brief Return a 'failed to synthesize placholder' justification for the given
metavariable application \c m of the form (?m l_1 ... l_k) */
justification mk_failed_to_synthesize_jst(environment const & env, expr const & m);
/** \brief Return true if it is a lean internal name, i.e., the name starts with a `_` */
bool is_internal_name(name const & n);
void initialize_library_util();
void finalize_library_util();