static declaration update_declaration(declaration d, optional<level_param_names> const & ps, optional<expr> const & type, optional<expr> const & value) { level_param_names _ps = ps ? *ps : d.get_univ_params(); expr _type = type ? *type : d.get_type(); expr _value; if (d.is_definition()) { _value = value ? *value : d.get_value(); } else { lean_assert(!value); } if (d.is_constant_assumption()) { if (is_eqp(d.get_type(), _type) && is_eqp(d.get_univ_params(), _ps)) return d; if (d.is_axiom()) return mk_axiom(d.get_name(), _ps, _type); else return mk_constant_assumption(d.get_name(), _ps, _type); } else { if (is_eqp(d.get_type(), _type) && is_eqp(d.get_value(), _value) && is_eqp(d.get_univ_params(), _ps)) return d; if (d.is_theorem()) return mk_theorem(d.get_name(), _ps, _type, _value, d.get_height()); else return mk_definition(d.get_name(), _ps, _type, _value, d.get_height(), d.use_conv_opt()); } }
expr dsimplify_core_fn::visit_let(expr const & e) { if (m_cfg.m_zeta) { return visit(instantiate(let_body(e), let_value(e))); } else { type_context::tmp_locals locals(m_ctx); expr b = e; bool modified = false; while (is_let(b)) { expr t = instantiate_rev(let_type(b), locals.size(), locals.data()); expr v = instantiate_rev(let_value(b), locals.size(), locals.data()); expr new_t = visit(t); expr new_v = visit(v); if (!is_eqp(t, new_t) || !is_eqp(v, new_v)) modified = true; locals.push_let(let_name(b), new_t, new_v); b = let_body(b); } b = instantiate_rev(b, locals.size(), locals.data()); expr new_b = visit(b); if (!is_eqp(b, new_b)) modified = true; if (modified) return locals.mk_lambda(new_b); else return e; } }
virtual expr visit_app(expr const & e) { buffer<expr> args; expr const & f = get_app_rev_args(e, args); if (is_metavar(f)) { if (auto p1 = m_subst.get_expr_assignment(mlocal_name(f))) { if (m_use_jst) save_jst(p1->second); expr new_app = apply_beta(p1->first, args.size(), args.data()); return visit(new_app); } } expr new_f = visit(f); buffer<expr> new_args; bool modified = !is_eqp(new_f, f); for (expr const & arg : args) { expr new_arg = visit(arg); if (!is_eqp(arg, new_arg)) modified = true; new_args.push_back(new_arg); } if (!modified) return e; else return mk_rev_app(new_f, new_args); }
level update_max(level const & l, level const & new_lhs, level const & new_rhs) { if (is_eqp(to_max_core(l).m_lhs, new_lhs) && is_eqp(to_max_core(l).m_rhs, new_rhs)) return l; else if (is_max(l)) return mk_max(new_lhs, new_rhs); else return mk_imax(new_lhs, new_rhs); }
bool operator==(level const & l1, level const & l2) { if (kind(l1) != kind(l2)) return false; if (hash(l1) != hash(l2)) return false; if (is_eqp(l1, l2)) return true; switch (kind(l1)) { case level_kind::Zero: return true; case level_kind::Param: case level_kind::Global: case level_kind::Meta: return to_param_core(l1).m_id == to_param_core(l2).m_id; case level_kind::Max: case level_kind::IMax: case level_kind::Succ: if (to_composite(l1).m_depth != to_composite(l2).m_depth) return false; break; } switch (kind(l1)) { case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Max: case level_kind::IMax: return to_max_core(l1).m_lhs == to_max_core(l2).m_lhs && to_max_core(l1).m_rhs == to_max_core(l2).m_rhs; case level_kind::Succ: if (is_explicit(l1) != is_explicit(l2)) { return false; } else if (is_explicit(l1)) { lean_assert(get_depth(l1) == get_depth(l2)); // the depths are equal, then l1 and l2 must be the same universe return true; } else { return succ_of(l1) == succ_of(l2); } } lean_unreachable(); // LCOV_EXCL_LINE }
expr compiler_step_visitor::visit_app(expr const & e) { buffer<expr> args; expr const & fn = get_app_args(e, args); expr new_fn = visit(fn); bool modified = !is_eqp(fn, new_fn); for (expr & arg : args) { expr new_arg = visit(arg); if (!is_eqp(new_arg, arg)) modified = true; arg = new_arg; } if (!modified) return e; else return copy_tag(e, mk_app(new_fn, args)); }
bool is_lt_no_level_params(level const & a, level const & b) { if (is_eqp(a, b)) return false; if (kind(a) != kind(b)) { if (kind(a) == level_kind::Param || kind(b) == level_kind::Param) return false; return kind(a) < kind(b); } switch (kind(a)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: return false; case level_kind::Global: return global_id(a) < global_id(b); case level_kind::Meta: return meta_id(a) < meta_id(b); case level_kind::Max: if (is_lt_no_level_params(max_lhs(a), max_lhs(b))) return true; else if (is_lt_no_level_params(max_lhs(b), max_lhs(a))) return false; else return is_lt_no_level_params(max_rhs(a), max_rhs(b)); case level_kind::IMax: if (is_lt_no_level_params(imax_lhs(a), imax_lhs(b))) return true; else if (is_lt_no_level_params(imax_lhs(b), imax_lhs(a))) return false; else return is_lt_no_level_params(imax_rhs(a), imax_rhs(b)); case level_kind::Succ: return is_lt_no_level_params(succ_of(a), succ_of(b)); } lean_unreachable(); }
// Monotonic total order on universe level terms. bool is_lt(level const & a, level const & b, bool use_hash) { if (is_eqp(a, b)) return false; unsigned da = get_depth(a); unsigned db = get_depth(b); if (da < db) return true; if (da > db) return false; if (kind(a) != kind(b)) return kind(a) < kind(b); if (use_hash) { if (hash(a) < hash(b)) return true; if (hash(a) > hash(b)) return false; } if (a == b) return false; switch (kind(a)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: case level_kind::Global: case level_kind::Meta: return to_param_core(a).m_id < to_param_core(b).m_id; case level_kind::Max: case level_kind::IMax: if (to_max_core(a).m_lhs != to_max_core(b).m_lhs) return is_lt(to_max_core(a).m_lhs, to_max_core(b).m_lhs, use_hash); else return is_lt(to_max_core(a).m_rhs, to_max_core(b).m_rhs, use_hash); case level_kind::Succ: return is_lt(succ_of(a), succ_of(b), use_hash); } lean_unreachable(); // LCOV_EXCL_LINE }
expr update_mlocal(expr const & e, expr const & new_type) { if (is_eqp(mlocal_type(e), new_type)) return e; else if (is_metavar(e)) return mk_metavar(mlocal_name(e), new_type, e.get_tag()); else return mk_local(mlocal_name(e), local_pp_name(e), new_type, local_info(e), e.get_tag()); }
bool is_lt(expr const & a, expr const & b, bool use_hash) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (a.kind() != b.kind()) return a.kind() < b.kind(); if (use_hash) { if (a.hash() < b.hash()) return true; if (a.hash() > b.hash()) return false; } if (a == b) return false; switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return is_lt(const_levels(a), const_levels(b), use_hash); case expr_kind::App: if (app_fn(a) != app_fn(b)) return is_lt(app_fn(a), app_fn(b), use_hash); else return is_lt(app_arg(a), app_arg(b), use_hash); case expr_kind::Lambda: case expr_kind::Pi: if (binding_domain(a) != binding_domain(b)) return is_lt(binding_domain(a), binding_domain(b), use_hash); else return is_lt(binding_body(a), binding_body(b), use_hash); case expr_kind::Let: if (let_type(a) != let_type(b)) return is_lt(let_type(a), let_type(b), use_hash); else if (let_value(a) != let_value(b)) return is_lt(let_value(a), let_value(b), use_hash); else return is_lt(let_body(a), let_body(b), use_hash); case expr_kind::Sort: return is_lt(sort_level(a), sort_level(b), use_hash); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt(mlocal_type(a), mlocal_type(b), use_hash); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (macro_arg(a, i) != macro_arg(b, i)) return is_lt(macro_arg(a, i), macro_arg(b, i), use_hash); } return false; } lean_unreachable(); // LCOV_EXCL_LINE }
bool apply(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.hash() != b.hash()) return false; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); if (m_cache.check(a, b)) return true; switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: return const_name(a) == const_name(b) && compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; }); case expr_kind::Meta: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)); case expr_kind::Local: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)) && (!CompareBinderInfo || local_pp_name(a) == local_pp_name(b)) && (!CompareBinderInfo || local_info(a) == local_info(b)); case expr_kind::App: check_system(); return apply(app_fn(a), app_fn(b)) && apply(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: check_system(); return apply(binding_domain(a), binding_domain(b)) && apply(binding_body(a), binding_body(b)) && (!CompareBinderInfo || binding_name(a) == binding_name(b)) && (!CompareBinderInfo || binding_info(a) == binding_info(b)); case expr_kind::Let: check_system(); return apply(let_type(a), let_type(b)) && apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b)) && (!CompareBinderInfo || let_name(a) == let_name(b)); case expr_kind::Sort: return sort_level(a) == sort_level(b); case expr_kind::Macro: check_system(); if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!apply(macro_arg(a, i), macro_arg(b, i))) return false; } return true; } lean_unreachable(); // LCOV_EXCL_LINE }
bool expr_eq_fn::apply(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.hash() != b.hash()) return false; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); if (m_counter >= LEAN_EQ_CACHE_THRESHOLD && is_shared(a) && is_shared(b)) { auto p = std::make_pair(a.raw(), b.raw()); if (!m_eq_visited) m_eq_visited.reset(new expr_cell_pair_set); if (m_eq_visited->find(p) != m_eq_visited->end()) return true; m_eq_visited->insert(p); } check_system("expression equality test"); switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: return const_name(a) == const_name(b) && compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; }); case expr_kind::Local: case expr_kind::Meta: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)); case expr_kind::App: m_counter++; return apply(app_fn(a), app_fn(b)) && apply(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: m_counter++; return apply(binding_domain(a), binding_domain(b)) && apply(binding_body(a), binding_body(b)) && (!m_compare_binder_info || binding_info(a) == binding_info(b)); case expr_kind::Sort: return sort_level(a) == sort_level(b); case expr_kind::Macro: m_counter++; if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!apply(macro_arg(a, i), macro_arg(b, i))) return false; } return true; case expr_kind::Let: m_counter++; return apply(let_type(a), let_type(b)) && apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b)); } lean_unreachable(); // LCOV_EXCL_LINE }
expr dsimplify_core_fn::visit_binding(expr const & e) { expr_kind k = e.kind(); type_context::tmp_locals locals(m_ctx); expr b = e; bool modified = false; while (b.kind() == k) { expr d = instantiate_rev(binding_domain(b), locals.size(), locals.data()); expr new_d = visit(d); if (!is_eqp(d, new_d)) modified = true; locals.push_local(binding_name(b), new_d, binding_info(b)); b = binding_body(b); } b = instantiate_rev(b, locals.size(), locals.data()); expr new_b = visit(b); if (!is_eqp(b, new_b)) modified = true; if (modified) return k == expr_kind::Pi ? locals.mk_pi(new_b) : locals.mk_lambda(new_b); else return e; }
expr update_macro(expr const & e, unsigned num, expr const * args) { if (num == macro_num_args(e)) { unsigned i = 0; for (i = 0; i < num; i++) { if (!is_eqp(macro_arg(e, i), args[i])) break; } if (i == num) return e; } return mk_macro(to_macro(e)->m_definition, num, args, e.get_tag()); }
bool is_lt_no_level_params(expr const & a, expr const & b) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (a.kind() != b.kind()) return a.kind() < b.kind(); switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return is_lt_no_level_params(const_levels(a), const_levels(b)); case expr_kind::App: if (is_lt_no_level_params(app_fn(a), app_fn(b))) return true; else if (is_lt_no_level_params(app_fn(b), app_fn(a))) return false; else return is_lt_no_level_params(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: if (is_lt_no_level_params(binding_domain(a), binding_domain(b))) return true; else if (is_lt_no_level_params(binding_domain(b), binding_domain(a))) return false; else return is_lt_no_level_params(binding_body(a), binding_body(b)); case expr_kind::Sort: return is_lt_no_level_params(sort_level(a), sort_level(b)); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt_no_level_params(mlocal_type(a), mlocal_type(b)); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (is_lt_no_level_params(macro_arg(a, i), macro_arg(b, i))) return true; else if (is_lt_no_level_params(macro_arg(b, i), macro_arg(a, i))) return false; } return false; } lean_unreachable(); }
virtual expr visit_app(expr const & e) override { if (auto r = expand_core(e)) { return *r; } else { buffer<expr> args; expr f = get_app_args(e, args); bool modified = false; for (unsigned i = 0; i < args.size(); i++) { expr arg = args[i]; expr new_arg = visit(arg); if (!is_eqp(arg, new_arg)) modified = true; args[i] = new_arg; } if (!modified) return e; else return mk_app(f, args); } }
// A total order on level expressions that has the following properties // - succ(l) is an immediate successor of l. // - zero is the minimal element. // This total order is used in the normalization procedure. static bool is_norm_lt(level const & a, level const & b) { if (is_eqp(a, b)) return false; auto p1 = to_offset(a); auto p2 = to_offset(b); level const & l1 = p1.first; level const & l2 = p2.first; if (l1 != l2) { if (kind(l1) != kind(l2)) return kind(l1) < kind(l2); switch (kind(l1)) { case level_kind::Zero: case level_kind::Succ: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: case level_kind::Global: case level_kind::Meta: return to_param_core(l1).m_id < to_param_core(l2).m_id; case level_kind::Max: case level_kind::IMax: if (to_max_core(l1).m_lhs != to_max_core(l2).m_lhs) return is_norm_lt(to_max_core(l1).m_lhs, to_max_core(l2).m_lhs); else return is_norm_lt(to_max_core(l1).m_rhs, to_max_core(l2).m_rhs); } lean_unreachable(); // LCOV_EXCL_LINE } else { return p1.second < p2.second; } }
bool already_processed(expr const & a) const { auto r = m_expr_cache.find(a); return r != m_expr_cache.end() && is_eqp(*r, a); }
level normalize(level const & l) { auto p = to_offset(l); level const & r = p.first; switch (kind(r)) { case level_kind::Succ: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: return l; case level_kind::IMax: { auto l1 = normalize(imax_lhs(r)); auto l2 = normalize(imax_rhs(r)); if (!is_eqp(l1, imax_lhs(r)) || !is_eqp(l2, imax_rhs(r))) return mk_succ(mk_imax(l1, l2), p.second); else return l; } case level_kind::Max: { buffer<level> todo; buffer<level> args; push_max_args(r, todo); for (level const & a : todo) push_max_args(normalize(a), args); std::sort(args.begin(), args.end(), is_norm_lt); buffer<level> & rargs = todo; rargs.clear(); unsigned i = 0; if (is_explicit(args[i])) { // find max explicit univierse while (i+1 < args.size() && is_explicit(args[i+1])) i++; lean_assert(is_explicit(args[i])); unsigned k = to_offset(args[i]).second; // an explicit universe k is subsumed by succ^k(l) unsigned j = i+1; for (; j < args.size(); j++) { if (to_offset(args[j]).second >= k) break; } if (j < args.size()) { // explicit universe was subsumed by succ^k'(l) where k' >= k i++; } } rargs.push_back(args[i]); auto p_prev = to_offset(args[i]); i++; for (; i < args.size(); i++) { auto p_curr = to_offset(args[i]); if (p_prev.first == p_curr.first) { if (p_prev.second < p_curr.second) { p_prev = p_curr; rargs.pop_back(); rargs.push_back(args[i]); } } else { p_prev = p_curr; rargs.push_back(args[i]); } } for (level & a : rargs) a = mk_succ(a, p.second); return mk_max(rargs); }} lean_unreachable(); // LCOV_EXCL_LINE }
bool abstract_expr_manager::is_equal(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); bool is_eq; switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: case expr_kind::Sort: return a == b; case expr_kind::Meta: case expr_kind::Local: return mlocal_name(a) == mlocal_name(b) && is_equal(mlocal_type(a), mlocal_type(b)); case expr_kind::Lambda: case expr_kind::Pi: if (!is_equal(binding_domain(a), binding_domain(b))) return false; // see comment at abstract_expr_manager::hash m_locals.push_back(instantiate_rev(m_tctx.mk_tmp_local(binding_domain(a)), m_locals.size(), m_locals.data())); is_eq = is_equal(binding_body(a), binding_body(b)); m_locals.pop_back(); return is_eq; case expr_kind::Macro: if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!is_equal(macro_arg(a, i), macro_arg(b, i))) return false; } return true; case expr_kind::App: buffer<expr> a_args, b_args; expr const & f_a = get_app_args(a, a_args); expr const & f_b = get_app_args(b, b_args); if (!is_equal(f_a, f_b)) return false; if (a_args.size() != b_args.size()) return false; unsigned prefix_sz = m_congr_lemma_manager.get_specialization_prefix_size(instantiate_rev(f_a, m_locals.size(), m_locals.data()), a_args.size()); for (unsigned i = 0; i < prefix_sz; i++) { if (!is_equal(a_args[i], b_args[i])) return false; } expr new_f_a = a; unsigned rest_sz = a_args.size() - prefix_sz; for (unsigned i = 0; i < rest_sz; i++) { new_f_a = app_fn(new_f_a); } new_f_a = instantiate_rev(new_f_a, m_locals.size(), m_locals.data()); optional<congr_lemma> congr = m_congr_lemma_manager.mk_congr(new_f_a, rest_sz); bool not_equal = false; if (!congr) { for (unsigned i = prefix_sz; i < a_args.size(); ++i) { if (!is_equal(a_args[i], b_args[i])) { not_equal = true; break; } } } else { lean_assert(length(congr->get_arg_kinds()) == rest_sz); unsigned i = prefix_sz; for_each(congr->get_arg_kinds(), [&](congr_arg_kind const & c_kind) { if (not_equal) return; if (c_kind != congr_arg_kind::Cast && !is_equal(a_args[i], b_args[i])) { not_equal = true; } i++; }); } return !not_equal; } lean_unreachable(); // LCOV_EXCL_LINE }
expr update_constant(expr const & e, levels const & new_levels) { if (!is_eqp(const_levels(e), new_levels)) return mk_constant(const_name(e), new_levels, e.get_tag()); else return e; }
expr update_sort(expr const & e, level const & new_level) { if (!is_eqp(sort_level(e), new_level)) return mk_sort(new_level, e.get_tag()); else return e; }
static bool is_lt(optional<expr> const & a, optional<expr> const & b, bool use_hash) { if (is_eqp(a, b)) return false; else if (!a && b) return true; else if (a && !b) return false; else return is_lt(*a, *b, use_hash); }
bool is_lt(expr const & a, expr const & b, bool use_hash) { if (is_eqp(a, b)) return false; unsigned da = get_depth(a); unsigned db = get_depth(b); if (da < db) return true; if (da > db) return false; if (a.kind() != b.kind()) return a.kind() < b.kind(); if (use_hash) { if (a.hash() < b.hash()) return true; if (a.hash() > b.hash()) return false; } if (a == b) return false; if (is_var(a)) return var_idx(a) < var_idx(b); switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: return const_name(a) < const_name(b); case expr_kind::App: if (num_args(a) != num_args(b)) return num_args(a) < num_args(b); for (unsigned i = 0; i < num_args(a); i++) { if (arg(a, i) != arg(b, i)) return is_lt(arg(a, i), arg(b, i), use_hash); } lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Lambda: // Remark: we ignore get_abs_name because we want alpha-equivalence case expr_kind::Pi: if (abst_domain(a) != abst_domain(b)) return is_lt(abst_domain(a), abst_domain(b), use_hash); else return is_lt(abst_body(a), abst_body(b), use_hash); 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::Let: if (let_type(a) != let_type(b)) { return is_lt(let_type(a), let_type(b), use_hash); } else if (let_value(a) != let_value(b)){ return is_lt(let_value(a), let_value(b), use_hash); } else { return is_lt(let_body(a), let_body(b), use_hash); } case expr_kind::MetaVar: if (metavar_name(a) != metavar_name(b)) { return metavar_name(a) < metavar_name(b); } else { auto it1 = metavar_lctx(a).begin(); auto it2 = metavar_lctx(b).begin(); auto end1 = metavar_lctx(a).end(); auto end2 = metavar_lctx(b).end(); for (; it1 != end1 && it2 != end2; ++it1, ++it2) { if (it1->kind() != it2->kind()) { return it1->kind() < it2->kind(); } else if (it1->s() != it2->s()) { return it1->s() < it2->s(); } else if (it1->is_inst()) { if (it1->v() != it2->v()) return is_lt(it1->v(), it2->v(), use_hash); } else { if (it1->n() != it2->n()) return it1->n() < it2->n(); } } return it1 == end1 && it2 != end2; } } lean_unreachable(); // LCOV_EXCL_LINE }
expr update_binding(expr const & e, expr const & new_domain, expr const & new_body, binder_info const & bi) { if (!is_eqp(binding_domain(e), new_domain) || !is_eqp(binding_body(e), new_body) || bi != binding_info(e)) return mk_binding(e.kind(), binding_name(e), new_domain, new_body, bi, e.get_tag()); else return e; }
expr update_app(expr const & e, expr const & new_fn, expr const & new_arg) { if (!is_eqp(app_fn(e), new_fn) || !is_eqp(app_arg(e), new_arg)) return mk_app(new_fn, new_arg, e.get_tag()); else return e; }
levels visit_levels(levels const & ls) { return map_reuse(ls, [&](level const & l) { return visit_level(l); }, [](level const & l1, level const & l2) { return is_eqp(l1, l2); }); }
expr update_let(expr const & e, expr const & new_type, expr const & new_value, expr const & new_body) { if (!is_eqp(let_type(e), new_type) || !is_eqp(let_value(e), new_value) || !is_eqp(let_body(e), new_body)) return mk_let(let_name(e), new_type, new_value, new_body); else return e; }
bool light_lt_manager::is_lt(expr const & a, expr const & b) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (is_constant(get_app_fn(a))) { unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(a))); if (light_arg) { buffer<expr> args; get_app_args(a, args); if (args.size() > *light_arg) return is_lt(args[*light_arg], b); } } if (is_constant(get_app_fn(b))) { unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(b))); if (light_arg) { buffer<expr> args; get_app_args(b, args); if (args.size() > *light_arg) return !is_lt(args[*light_arg], a); } } if (a.kind() != b.kind()) return a.kind() < b.kind(); if (a == b) return false; switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return ::lean::is_lt(const_levels(a), const_levels(b), false); case expr_kind::App: if (app_fn(a) != app_fn(b)) return is_lt(app_fn(a), app_fn(b)); else return is_lt(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: if (binding_domain(a) != binding_domain(b)) return is_lt(binding_domain(a), binding_domain(b)); else return is_lt(binding_body(a), binding_body(b)); case expr_kind::Sort: return ::lean::is_lt(sort_level(a), sort_level(b), false); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt(mlocal_type(a), mlocal_type(b)); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (macro_arg(a, i) != macro_arg(b, i)) return is_lt(macro_arg(a, i), macro_arg(b, i)); } return false; } lean_unreachable(); // LCOV_EXCL_LINE }
expr update_local(expr const & e, expr const & new_type, binder_info const & bi) { if (is_eqp(mlocal_type(e), new_type) && local_info(e) == bi) return e; else return mk_local(mlocal_name(e), local_pp_name(e), new_type, bi, e.get_tag()); }