/* Try to reduce cases_on (and nonrecursive recursor) application if major became a constructor */ expr visit_cases_on_app(expr const & e_0) { expr e = default_visit_app(e_0); buffer<expr> args; expr const & fn = get_app_args(e, args); lean_assert(is_constant(fn)); bool is_cases_on = is_cases_on_recursor(env(), const_name(fn)); name const & rec_name = const_name(fn); name const & I_name = rec_name.get_prefix(); unsigned nparams = *inductive::get_num_params(env(), I_name); unsigned nindices = *inductive::get_num_indices(env(), I_name); unsigned major_idx; if (is_cases_on) { major_idx = nparams + 1 + nindices; } else { major_idx = *inductive::get_elim_major_idx(env(), rec_name); } expr major = beta_reduce(args[major_idx]); if (is_constructor_app(env(), major)) { /* Major premise became a constructor. So, we should reduce. */ expr new_e = e; if (is_cases_on) { /* unfold cases_on */ if (auto r = unfold_term(env(), new_e)) new_e = *r; else return e; } /* reduce */ if (auto r = ctx().norm_ext(new_e)) return compiler_step_visitor::visit(beta_reduce(*r)); } return e; }
optional<expr> unfold_step(type_context & ctx, expr const & e, name_set const & to_unfold, bool unfold_reducible) { if (!unfold_reducible && to_unfold.empty()) return none_expr(); if (!is_app(e) && !is_constant(e)) return none_expr(); expr const & fn = get_app_fn(e); if (!is_constant(fn)) return none_expr(); name const & fn_name = const_name(fn); bool in_to_unfold = to_unfold.contains(const_name(fn)); if (!in_to_unfold && !unfold_reducible) return none_expr(); if (is_projection(ctx.env(), const_name(fn))) { if (in_to_unfold) { type_context::transparency_scope scope(ctx, transparency_mode::Instances); return ctx.reduce_projection(e); } else { return none_expr(); } } else if (in_to_unfold) { return unfold_term(ctx.env(), e); } else if (unfold_reducible && is_reducible(ctx.env(), fn_name)) { type_context::transparency_scope scope(ctx, transparency_mode::Reducible); return unfold_term(ctx.env(), e); } else { return none_expr(); } }
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 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 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 }
action_result no_confusion_action(hypothesis_idx hidx) { try { state & s = curr_state(); app_builder & b = get_app_builder(); hypothesis const & h = s.get_hypothesis_decl(hidx); expr type = h.get_type(); expr lhs, rhs; if (!is_eq(type, lhs, rhs)) return action_result::failed(); lhs = whnf(lhs); rhs = whnf(rhs); optional<name> c1 = is_constructor_app(env(), lhs); optional<name> c2 = is_constructor_app(env(), rhs); if (!c1 || !c2) return action_result::failed(); expr A = whnf(infer_type(lhs)); expr I = get_app_fn(A); if (!is_constant(I) || !inductive::is_inductive_decl(env(), const_name(I))) return action_result::failed(); name nct_name(const_name(I), "no_confusion_type"); if (!env().find(nct_name)) return action_result::failed(); expr target = s.get_target(); expr nct = whnf(b.mk_app(nct_name, target, lhs, rhs)); if (c1 == c2) { if (!is_pi(nct)) return action_result::failed(); if (s.has_target_forward_deps(hidx)) { // TODO(Leo): we currently do not handle this case. // To avoid non-termination we remove the given hypothesis, if there // forward dependencies, we would also have to remove them. // Remark: this is a low priority refinement since it will not happen // very often in practice. return action_result::failed(); } unsigned num_params = *inductive::get_num_params(env(), const_name(I)); unsigned cnstr_arity = get_arity(env().get(*c1).get_type()); lean_assert(cnstr_arity >= num_params); unsigned num_new_eqs = cnstr_arity - num_params; s.push_proof_step(new no_confusion_proof_step_cell(const_name(I), target, h.get_self(), num_new_eqs)); s.set_target(binding_domain(nct)); s.del_hypothesis(hidx); trace_action("no_confusion"); return action_result::new_branch(); } else { name nc_name(const_name(I), "no_confusion"); expr pr = b.mk_app(nc_name, {target, lhs, rhs, h.get_self()}); trace_action("no_confusion"); return action_result::solved(pr); } } catch (app_builder_exception &) { return action_result::failed(); } }
bool is_simp_relation(environment const & env, expr const & e, expr & rel, expr & lhs, expr & rhs) { buffer<expr> args; rel = get_app_args(e, args); if (!is_constant(rel) || !is_simp_relation(env, const_name(rel))) return false; relation_info const * rel_info = get_relation_info(env, const_name(rel)); if (!rel_info || rel_info->get_lhs_pos() >= args.size() || rel_info->get_rhs_pos() >= args.size()) return false; lhs = args[rel_info->get_lhs_pos()]; rhs = args[rel_info->get_rhs_pos()]; return true; }
expr gexpr::to_expr(type_context & ctx) const { if (m_univ_poly) { declaration const & fdecl = ctx.env().get(const_name(m_expr)); buffer<level> ls_buffer; unsigned num_univ_ps = fdecl.get_num_univ_params(); for (unsigned i = 0; i < num_univ_ps; i++) ls_buffer.push_back(ctx.mk_uvar()); levels ls = to_list(ls_buffer.begin(), ls_buffer.end()); return mk_constant(const_name(m_expr), ls); } else { return m_expr; } }
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(); }
bool is_recursive_rec_app(environment const & env, expr const & e) { buffer<expr> args; name_generator ngen; expr const & f = get_app_args(e, args); if (!is_constant(f)) return false; auto I_name = inductive::is_elim_rule(env, const_name(f)); if (!I_name || !is_recursive_datatype(env, *I_name) || is_inductive_predicate(env, *I_name)) return false; unsigned nparams = *inductive::get_num_params(env, *I_name); unsigned nminors = *inductive::get_num_minor_premises(env, *I_name); unsigned ntypeformers = *inductive::get_num_type_formers(env, *I_name); buffer<buffer<bool>> is_rec_arg; get_rec_args(env, *I_name, is_rec_arg); for (unsigned i = nparams + ntypeformers, j = 0; i < nparams + ntypeformers + nminors; i++, j++) { buffer<bool> const & minor_is_rec_arg = is_rec_arg[j]; expr minor = args[i]; buffer<expr> minor_ctx; expr minor_body = fun_to_telescope(ngen, minor, minor_ctx, optional<binder_info>()); unsigned sz = std::min(minor_is_rec_arg.size(), minor_ctx.size()); if (find(minor_body, [&](expr const & e, unsigned) { if (!is_local(e)) return false; for (unsigned k = 0; k < sz; k++) { if (minor_is_rec_arg[k] && mlocal_name(e) == mlocal_name(minor_ctx[k])) return true; } return false; })) return false; } return true; }
optional<pair<expr, constraint_seq>> projection_converter::reduce_projection(expr const & t) { projection_info const * info = is_projection(t); if (!info) return optional<pair<expr, constraint_seq>>(); buffer<expr> args; get_app_args(t, args); if (args.size() <= info->m_nparams) { return optional<pair<expr, constraint_seq>>(); } unsigned mkidx = info->m_nparams; expr const & mk = args[mkidx]; pair<expr, constraint_seq> new_mk_cs = whnf(mk); expr new_mk = new_mk_cs.first; expr const & new_mk_fn = get_app_fn(new_mk); if (!is_constant(new_mk_fn) || const_name(new_mk_fn) != info->m_constructor) { return optional<pair<expr, constraint_seq>>(); } buffer<expr> mk_args; get_app_args(new_mk, mk_args); unsigned i = info->m_nparams + info->m_i; if (i >= mk_args.size()) { return optional<pair<expr, constraint_seq>>(); } expr r = mk_args[i]; r = mk_app(r, args.size() - mkidx - 1, args.data() + mkidx + 1); return optional<pair<expr, constraint_seq>>(r, new_mk_cs.second); }
optional<name> get_noncomputable_reason(environment const & env, name const & n) { declaration const & d = env.get(n); if (!d.is_definition()) return optional<name>(); type_checker tc(env); if (tc.is_prop(d.get_type())) return optional<name>(); // definition is a proposition, then do nothing expr const & v = d.get_value(); auto ext = get_extension(env); bool ok = true; /* quick check */ for_each(v, [&](expr const & e, unsigned) { if (!ok) return false; // stop the search if (is_constant(e) && is_noncomputable(tc, ext, const_name(e))) { ok = false; } return true; }); if (ok) { return optional<name>(); } /* expensive check */ try { get_noncomputable_reason_fn proc(tc); proc(v); return optional<name>(); } catch (get_noncomputable_reason_fn::found & r) { return optional<name>(r.m_reason); } }
environment coercion_cmd(parser & p) { auto pos = p.pos(); expr f = p.parse_expr(); if (!is_constant(f)) throw parser_error("invalid 'coercion' command, constant expected", pos); if (p.curr_is_token(g_colon)) { p.next(); pos = p.pos(); expr C = p.parse_expr(); if (!is_constant(C)) throw parser_error("invalid 'coercion' command, constant expected", pos); return add_coercion(p.env(), const_name(f), const_name(C), p.ios()); } else { return add_coercion(p.env(), const_name(f), p.ios()); } }
projection_info const * projection_converter::is_projection(expr const & e) const { expr const & f = get_app_fn(e); if (is_constant(f)) return m_proj_info.find(const_name(f)); else return nullptr; }
static bool is_num(expr const & e, bool first) { buffer<expr> args; expr const & f = get_app_args(e, args); if (!is_constant(f)) return false; if (const_name(f) == get_has_one_one_name()) return args.size() == 2; else if (const_name(f) == get_has_zero_zero_name()) return first && args.size() == 2; else if (const_name(f) == get_nat_zero_name()) return first && args.size() == 0; else if (const_name(f) == get_bit0_name()) return args.size() == 3 && is_num(args[2], false); else if (const_name(f) == get_bit1_name()) return args.size() == 4 && is_num(args[3], false); return false; }
// Apply lazy delta-reduction and then normalizer extensions lbool projection_converter::reduce_def_eq(expr & t_n, expr & s_n, constraint_seq & cs) { while (true) { // first, keep applying lazy delta-reduction while applicable lbool r = lazy_delta_reduction(t_n, s_n, cs); if (r != l_undef) return r; auto p_t = reduce_projection(t_n); auto p_s = reduce_projection(s_n); if (p_t && p_s) { t_n = whnf_core(p_t->first); s_n = whnf_core(p_s->first); cs += p_t->second; cs += p_s->second; } else if (p_t || p_s) { expr const & f_t = get_app_fn(t_n); expr const & f_s = get_app_fn(s_n); if (is_constant(f_t) && is_constant(f_s) && const_name(f_t) == const_name(f_s) && (p_t || is_stuck(t_n, *m_tc)) && (p_s || is_stuck(s_n, *m_tc))) { // treat it as a delta-delta step return l_undef; } if (p_t) { t_n = whnf_core(p_t->first); cs += p_t->second; } else if (p_s) { s_n = whnf_core(p_s->first); cs += p_s->second; } else { lean_unreachable(); } } else { auto new_t_n = d_norm_ext(t_n, cs); auto new_s_n = d_norm_ext(s_n, cs); if (!new_t_n && !new_s_n) return l_undef; if (new_t_n) { t_n = whnf_core(*new_t_n); } if (new_s_n) { s_n = whnf_core(*new_s_n); } } r = quick_is_def_eq(t_n, s_n, cs); if (r != l_undef) return r; } }
bool is_cases_applicable(expr const & mvar, expr const & H) { type_context ctx = mk_type_context_for(mvar); expr t = whnf_inductive(ctx, ctx.infer(H)); buffer<expr> args; expr const & fn = get_app_args(t, args); if (!is_constant(fn)) return false; if (!is_ginductive(m_env, const_name(fn))) return false; if (!m_env.find(name{const_name(fn), "cases_on"}) || !m_env.find(get_eq_name())) return false; if (!m_env.find(get_heq_name())) return false; init_inductive_info(const_name(fn)); if (args.size() != m_nindices + m_nparams) return false; lean_cases_trace(mvar, tout() << "inductive type: " << const_name(fn) << ", num. params: " << m_nparams << ", num. indices: " << m_nindices << "\n";);
virtual expr visit_constant(expr const & e) override { name const & n = const_name(e); if (is_vm_builtin_function(n)) { return e; } else if (inductive::is_intro_rule(env(), n)) { return mk_cnstr(get_constructor_idx(env(), n)); } else { return e; } }
static optional<unsigned> is_internal_symbol(expr const & e, name const & prefix) { if (!is_constant(e)) return optional<unsigned>(); name const & n = const_name(e); if (n.is_atomic() || !n.is_numeral()) return optional<unsigned>(); if (n.get_prefix() == prefix) return optional<unsigned>(n.get_numeral()); else return optional<unsigned>(); }
static unsigned get_max_height(environment const & env, expr const & v) { unsigned h = 0; for_each(v, [&](expr const & e, unsigned) { if (is_constant(e)) { auto d = env.find(const_name(e)); if (d && d->get_height() > h) h = d->get_height(); } return true; }); return h; }
action_result grinder_elim_action(hypothesis_idx hidx) { grinder_branch_extension & ext = get_ext(); state & s = curr_state(); hypothesis const & h = s.get_hypothesis_decl(hidx); expr const & f = get_app_fn(h.get_type()); if (!is_constant(f)) return action_result::failed(); auto R = ext.m_elim_lemmas.find(const_name(f)); if (!R) return action_result::failed(); return recursor_action(hidx, *R); }
edge(expr const & e, bool fn) { m_fn = fn; lean_assert(is_constant(e) || is_local(e)); if (is_constant(e)) { m_kind = edge_kind::Constant; m_name = const_name(e); } else { lean_assert(is_local(e)); m_kind = edge_kind::Local; m_name = mlocal_name(e); } }
static optional<pair<expr, expr>> apply_symmetry(environment const & env, old_local_context & ctx, type_checker_ptr & tc, expr const & e, expr const & e_type, constraint_seq & cs, tag g) { buffer<expr> args; expr const & op = get_app_args(e_type, args); if (is_constant(op)) { if (auto info = get_symm_extra_info(env, const_name(op))) { return mk_op(env, ctx, tc, info->m_name, info->m_num_univs, info->m_num_args-1, {e}, cs, g); } } return optional<pair<expr, expr>>(); }
optional<name> defeq_canonizer::get_head_symbol(expr type) { type = m_ctx.whnf(type); expr const & fn = get_app_fn(type); if (is_constant(fn)) { return optional<name>(const_name(fn)); } else if (is_pi(type)) { type_context::tmp_locals locals(m_ctx); expr l = locals.push_local_from_binding(type); return get_head_symbol(instantiate(binding_body(type), l)); } else { return optional<name>(); } }
// Return true if \c e is convertible to a term of the form (h ...). // If the result is true, update \c e and \c cs. bool try_normalize_to_head(environment const & env, name const & h, expr & e, constraint_seq & cs) { type_checker_ptr tc = mk_type_checker(env, [=](name const & n) { return n == h; }); constraint_seq new_cs; expr new_e = tc->whnf(e, new_cs); expr const & fn = get_app_fn(new_e); if (is_constant(fn) && const_name(fn) == h) { e = new_e; cs += new_cs; return true; } else { return false; } }
static optional<pair<expr, expr>> apply_subst(environment const & env, old_local_context & ctx, type_checker_ptr & tc, expr const & e, expr const & e_type, expr const & pred, constraint_seq & cs, tag g) { buffer<expr> pred_args; get_app_args(pred, pred_args); unsigned npargs = pred_args.size(); if (npargs < 2) return optional<pair<expr, expr>>(); buffer<expr> args; expr const & op = get_app_args(e_type, args); if (is_constant(op) && args.size() >= 2) { if (auto sinfo = get_subst_extra_info(env, const_name(op))) { if (auto rinfo = get_refl_extra_info(env, const_name(op))) { if (auto refl_pair = mk_op(env, ctx, tc, rinfo->m_name, rinfo->m_num_univs, rinfo->m_num_args-1, { pred_args[npargs-2] }, cs, g)) { return mk_op(env, ctx, tc, sinfo->m_name, sinfo->m_num_univs, sinfo->m_num_args-2, {e, refl_pair->first}, cs, g); } } } } return optional<pair<expr, expr>>(); }
void definition_cache::collect_dependencies(environment const & env, expr const & e, dependencies & deps) { for_each(e, [&](expr const & e, unsigned) { if (!is_constant(e)) return true; name const & n = const_name(e); if (deps.contains(n)) return true; auto d = env.find(n); if (!d) return true; deps.insert(n, hash_bi(d->get_type())); return true; }); }
expr copy(expr const & a) { switch (a.kind()) { case expr_kind::Var: return mk_var(var_idx(a)); case expr_kind::Constant: return mk_constant(const_name(a)); case expr_kind::Type: return mk_type(ty_level(a)); case expr_kind::Value: return mk_value(static_cast<expr_value*>(a.raw())->m_val); case expr_kind::App: return mk_app(num_args(a), begin_args(a)); case expr_kind::Eq: return mk_eq(eq_lhs(a), eq_rhs(a)); case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a)); case expr_kind::MetaVar: return mk_metavar(metavar_idx(a), metavar_ctx(a)); } lean_unreachable(); }
virtual expr visit_app(expr const & e) override { buffer<expr> args; expr const & fn = get_app_args(e, args); if (is_constant(fn)) { name const & n = const_name(fn); if (is_cases_on_recursor(env(), n)) { return visit_cases_on(n, args); } else if (inductive::is_intro_rule(env(), n)) { return visit_constructor(n, args); } else if (is_projection(env(), n)) { return visit_projection(n, args); } } return compiler_step_visitor::visit_app(e); }
void visit_app(expr const & e) { if (should_visit(e)) { buffer<expr> args; expr const & fn = get_app_args(e, args); if (is_constant(fn) && is_inline(m_tc.env(), const_name(fn))) { if (auto new_e = unfold_app(m_tc.env(), e)) { visit(*new_e); return; } } visit(fn); for (expr const & arg : args) visit(arg); } }