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 }
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const { environment const & env = ctx.env(); check_num_args(env, m); if (!infer_only) infer_type(macro_arg(m, 0), ctx, infer_only); expr l = whnf(macro_arg(m, 0), ctx); expr not_l = whnf(mk_app(*g_not, l), ctx); expr C1 = infer_type(macro_arg(m, 1), ctx, infer_only); expr C2 = infer_type(macro_arg(m, 2), ctx, infer_only); return mk_pair(mk_resolvent(env, ctx, m, l, not_l, C1, C2), constraint_seq()); }
virtual optional<expr> expand(expr const & m, extension_context & ctx) const { environment const & env = ctx.env(); check_num_args(env, m); expr l = whnf(macro_arg(m, 0), ctx); expr not_l = whnf(mk_app(*g_not, l), ctx); expr H1 = macro_arg(m, 1); expr H2 = macro_arg(m, 2); expr C1 = infer_type(H1, ctx, true); expr C2 = infer_type(H2, ctx, true); expr R = mk_resolvent(env, ctx, m, l, not_l, C1, C2); return some_expr(mk_or_elim_tree1(l, not_l, C1, H1, C2, H2, R, ctx)); }
void destruct_structure_instance(expr const & e, expr & t, buffer<name> & field_names, buffer<expr> & field_values, buffer<expr> & using_exprs) { lean_assert(is_structure_instance(e)); t = macro_arg(e, 0); list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names(); unsigned num_fileds = length(fns); to_buffer(fns, field_names); for (unsigned i = 1; i < num_fileds+1; i++) field_values.push_back(macro_arg(e, i)); for (unsigned i = num_fileds+1; i < macro_num_args(e); i++) using_exprs.push_back(macro_arg(e, i)); }
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 check_type(expr const & m, abstract_type_context & ctx, bool infer_only) const { check_macro(m); expr given_type = macro_arg(m, 0); if (!infer_only) { ctx.check(given_type, infer_only); expr inferred_type = ctx.check(macro_arg(m, 1), infer_only); if (!ctx.is_def_eq(inferred_type, given_type)) { throw_kernel_exception(ctx.env(), m, [=](formatter const & fmt) { return format("type mismatch at term") + pp_type_mismatch(fmt, macro_arg(m, 1), inferred_type, given_type); }); } } return given_type; }
expr apply(expr const & a) { check_system("max_sharing"); auto r = m_expr_cache.find(a); if (r != m_expr_cache.end()) return *r; expr res; switch (a.kind()) { case expr_kind::Var: res = a; break; case expr_kind::Constant: res = update_constant(a, map(const_levels(a), [&](level const & l) { return apply(l); })); break; case expr_kind::Sort: res = update_sort(a, apply(sort_level(a))); break; case expr_kind::App: res = update_app(a, apply(app_fn(a)), apply(app_arg(a))); break; case expr_kind::Lambda: case expr_kind::Pi: res = update_binding(a, apply(binding_domain(a)), apply(binding_body(a))); break; case expr_kind::Meta: case expr_kind::Local: res = update_mlocal(a, apply(mlocal_type(a))); break; case expr_kind::Macro: { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(a); i++) new_args.push_back(macro_arg(a, i)); res = update_macro(a, new_args.size(), new_args.data()); break; }} m_expr_cache.insert(res); return res; }
expr replace_visitor::visit_macro(expr const & e) { lean_assert(is_macro(e)); buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); return update_macro(e, new_args.size(), new_args.data()); }
/** \brief Return true iff all recursive applications in \c e are structurally smaller than \c m_pattern. */ bool check_rhs(expr const & e) { switch (e.kind()) { case expr_kind::Var: case expr_kind::Meta: case expr_kind::Local: case expr_kind::Constant: case expr_kind::Sort: return true; case expr_kind::Macro: for (unsigned i = 0; i < macro_num_args(e); i++) if (!check_rhs(macro_arg(e, i))) return false; return true; case expr_kind::App: { buffer<expr> args; expr const & fn = get_app_args(e, args); if (!check_rhs(fn)) return false; for (unsigned i = 0; i < args.size(); i++) if (!check_rhs(args[i])) return false; if (is_local(fn) && mlocal_name(fn) == mlocal_name(m_fn)) { /* recusive application */ if (m_arg_idx < args.size()) { expr const & arg = args[m_arg_idx]; /* arg must be structurally smaller than m_pattern */ if (!is_lt(arg, m_pattern)) { trace_struct_aux(tout() << "structural recursion on argument #" << (m_arg_idx+1) << " was not used " << "for '" << m_fn << "'\nargument #" << (m_arg_idx+1) << " in the application\n " << e << "\nis not structurally smaller than the one occurring in " << "the equation left-hand-side\n " << m_lhs << "\n";); return false; } } else {
void get_structure_instance_info(expr const & e, name & struct_name, optional<expr> & source, buffer<name> & field_names, buffer<expr> & field_values) { lean_assert(is_structure_instance(e)); struct_name = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_struct(); list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names(); to_buffer(fns, field_names); unsigned num_fields = field_names.size(); lean_assert(macro_num_args(e) == num_fields || macro_num_args(e) == num_fields+1); if (num_fields < macro_num_args(e)) source = macro_arg(e, num_fields); for (unsigned i = 0; i < num_fields; i++) field_values.push_back(macro_arg(e, i)); }
void visit_macro(expr const & e) { if (is_expr_quote(e) || is_pexpr_quote(e)) return; if (should_visit(e)) { for (unsigned i = 0; i < macro_num_args(e); i++) visit(macro_arg(e, i)); } }
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const { constraint_seq cseq; check_macro(m); expr given_type = macro_arg(m, 0); if (!infer_only) { cseq += ctx.check_type(given_type, infer_only).second; auto p = ctx.check_type(macro_arg(m, 1), infer_only); expr inferred_type = p.first; cseq += p.second; justification jst = mk_type_mismatch_jst(macro_arg(m, 1), inferred_type, given_type, m); as_delayed_justification djst(jst); if (!ctx.is_def_eq(inferred_type, given_type, djst, cseq)) { throw_kernel_exception(ctx.env(), m, [=](formatter const & fmt) { return pp_type_mismatch(fmt, macro_arg(m, 1), inferred_type, given_type); }); } } return mk_pair(given_type, cseq); }
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()); }
static bool is_permutation(expr const & lhs, expr const & rhs, unsigned offset, buffer<optional<unsigned>> & p) { if (lhs.kind() != rhs.kind()) return false; switch (lhs.kind()) { case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Meta: case expr_kind::Local: return lhs == rhs; case expr_kind::Var: if (var_idx(lhs) < offset) { return lhs == rhs; // locally bound variable } else if (var_idx(lhs) - offset < p.size()) { if (p[var_idx(lhs) - offset]) { return *(p[var_idx(lhs) - offset]) == var_idx(rhs); } else { p[var_idx(lhs) - offset] = var_idx(rhs); return true; } } else { return lhs == rhs; // free variable } case expr_kind::Lambda: case expr_kind::Pi: return is_permutation(binding_domain(lhs), binding_domain(rhs), offset, p) && is_permutation(binding_body(lhs), binding_body(rhs), offset+1, p); case expr_kind::App: return is_permutation(app_fn(lhs), app_fn(rhs), offset, p) && is_permutation(app_arg(lhs), app_arg(rhs), offset, p); case expr_kind::Macro: if (macro_def(lhs) != macro_def(rhs) || macro_num_args(lhs) != macro_num_args(rhs)) return false; for (unsigned i = 0; i < macro_num_args(lhs); i++) { if (!is_permutation(macro_arg(lhs, i), macro_arg(rhs, i), offset, p)) return false; } return true; } lean_unreachable(); }
virtual expr visit_macro(expr const & e) override { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); auto def = macro_def(e); expr r = update_macro(e, new_args.size(), new_args.data()); if (!m_trust_lvl || def.trust_level() >= *m_trust_lvl) { if (optional<expr> new_r = m_ctx.expand_macro(r)) { return visit(*new_r); } else { throw generic_exception(e, "failed to expand macro"); } } else { return r; } }
expr visit_macro(expr const & e) { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); auto def = macro_def(e); expr r = update_macro(e, new_args.size(), new_args.data()); if (def.trust_level() >= m_trust_lvl) { if (optional<expr> new_r = m_tc.expand_macro(r)) { return *new_r; } else { throw_generic_exception("failed to expand macro", e); } } else { return r; } }
void collect_locals(expr const & e, collected_locals & ls, bool restricted) { if (!has_local(e)) return; expr_set visited; std::function<void(expr const & e)> visit = [&](expr const & e) { if (!has_local(e)) return; if (restricted && is_meta(e)) return; if (visited.find(e) != visited.end()) return; visited.insert(e); switch (e.kind()) { case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort: break; // do nothing case expr_kind::Local: if (!restricted) visit(mlocal_type(e)); ls.insert(e); break; case expr_kind::Meta: lean_assert(!restricted); visit(mlocal_type(e)); break; case expr_kind::Macro: for (unsigned i = 0; i < macro_num_args(e); i++) visit(macro_arg(e, i)); break; case expr_kind::App: visit(app_fn(e)); visit(app_arg(e)); break; case expr_kind::Lambda: case expr_kind::Pi: visit(binding_domain(e)); visit(binding_body(e)); break; case expr_kind::Let: visit(let_type(e)); visit(let_value(e)); visit(let_body(e)); break; } }; visit(e); }
virtual optional<expr> expand(expr const & m, abstract_type_context & ctx) const { check_macro(m); expr const & s = macro_arg(m, 0); expr new_s = ctx.whnf(s); buffer<expr> c_args; expr const & c = get_app_args(new_s, c_args); if (is_constant(c) && const_name(c) == m_constructor_name && m_idx < c_args.size()) { return some_expr(c_args[m_idx]); } else { // expand into recursor expr s_type = ctx.whnf(ctx.infer(s)); buffer<expr> args; expr const & I = get_app_args(s_type, args); if (!is_constant(I) || length(m_ps) != length(const_levels(I))) return none_expr(); expr r = instantiate_univ_params(m_val, m_ps, const_levels(I)); args.push_back(new_s); return some(instantiate_rev(r, args.size(), args.data())); } }
virtual expr check_type(expr const & m, abstract_type_context & ctx, bool infer_only) const { check_macro(m); environment const & env = ctx.env(); expr s = macro_arg(m, 0); expr s_t = ctx.whnf(ctx.check(s, infer_only)); buffer<expr> I_args; expr const & I = get_app_args(s_t, I_args); if (!is_constant(I)) { // remark: this is not an issue since this macro should not be used during elaboration. throw_kernel_exception(env, sstream() << "projection macros do not support arbitrary terms " << "containing metavariables yet (solution: use trust-level 0)", m); } if (length(const_levels(I)) != length(m_ps)) throw_kernel_exception(env, sstream() << "invalid projection application '" << m_proj_name << "', incorrect number of universe parameters", m); expr t = instantiate_univ_params(m_type, m_ps, const_levels(I)); I_args.push_back(s); return instantiate_rev(t, I_args.size(), I_args.data()); }
expr apply(expr const & e, unsigned offset) { bool shared = false; if (m_use_cache && is_shared(e)) { if (auto r = m_cache->find(e, offset)) return *r; shared = true; } check_interrupted(); check_memory("replace"); if (optional<expr> r = m_f(e, offset)) { return save_result(e, offset, *r, shared); } else { switch (e.kind()) { case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Var: return save_result(e, offset, e, shared); case expr_kind::Meta: case expr_kind::Local: { expr new_t = apply(mlocal_type(e), offset); return save_result(e, offset, update_mlocal(e, new_t), shared); } case expr_kind::App: { expr new_f = apply(app_fn(e), offset); expr new_a = apply(app_arg(e), offset); return save_result(e, offset, update_app(e, new_f, new_a), shared); } case expr_kind::Pi: case expr_kind::Lambda: { expr new_d = apply(binding_domain(e), offset); expr new_b = apply(binding_body(e), offset+1); return save_result(e, offset, update_binding(e, new_d, new_b), shared); } case expr_kind::Macro: { buffer<expr> new_args; unsigned nargs = macro_num_args(e); for (unsigned i = 0; i < nargs; i++) new_args.push_back(apply(macro_arg(e, i), offset)); return save_result(e, offset, update_macro(e, new_args.size(), new_args.data()), shared); }} lean_unreachable(); } }
expr const & get_let_body(expr const & e) { lean_assert(is_let_macro(e)); return macro_arg(e, 1); }
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 get_nested_declaration_arg(expr const & e) { lean_assert(is_nested_declaration(e)); return macro_arg(e, 0); }
virtual optional<expr> expand(expr const & m, extension_context &) const { check_macro(m); return some_expr(macro_arg(m, 1)); }
expr dsimplify_core_fn::visit_macro(expr const & e) { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); return update_macro(e, new_args.size(), new_args.data()); }
expr get_let_value_expr(expr const e) { lean_assert(is_let_value(e)); return macro_arg(e, 0); }
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 }
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const { check_macro(m); return ctx.check_type(macro_arg(m, 1), infer_only); }