/* Store parameter info for fn in \c pinfos and return the dependencies of the resulting type (if compute_resulting_deps == true). */ static list<unsigned> get_core(type_context & ctx, expr const & fn, buffer<param_info> & pinfos, unsigned max_args, bool compute_resulting_deps) { expr type = ctx.relaxed_try_to_pi(ctx.infer(fn)); type_context::tmp_locals locals(ctx); unsigned i = 0; while (is_pi(type)) { if (i == max_args) break; expr local = locals.push_local_from_binding(type); expr local_type = ctx.infer(local); expr new_type = ctx.relaxed_try_to_pi(instantiate(binding_body(type), local)); bool is_prop = ctx.is_prop(local_type); bool is_dep = !closed(binding_body(type)); pinfos.emplace_back(binding_info(type).is_implicit(), binding_info(type).is_inst_implicit(), is_prop, is_dep, collect_deps(local_type, locals.as_buffer())); type = new_type; i++; } if (compute_resulting_deps) return collect_deps(type, locals.as_buffer()); else return list<unsigned>(); }
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(); } }
backward_lemma_index::backward_lemma_index(type_context & ctx): m_index(get_intro_attribute().get_instances_by_prio(ctx.env())) { buffer<name> lemmas; get_intro_attribute().get_instances(ctx.env(), lemmas); unsigned i = lemmas.size(); while (i > 0) { --i; optional<head_index> target = get_backward_target(ctx, lemmas[i]); if (!target || target->kind() != expr_kind::Constant) { lean_trace(name({"tactic", "back_chaining"}), tout() << "discarding [intro] lemma '" << lemmas[i] << "', failed to find target type\n";); } else {
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; } }
static void trace_if_unsupported(type_context & ctx, expr const & fn, buffer<expr> const & args, unsigned prefix_sz, ss_param_infos const & result) { lean_assert(args.size() >= length(result)); if (!is_fun_info_trace_enabled()) return; fun_info info = get_fun_info(ctx, fn, args.size()); buffer<param_info> pinfos; to_buffer(info.get_params_info(), pinfos); buffer<ss_param_info> ssinfos; to_buffer(get_subsingleton_info(ctx, fn, args.size()), ssinfos); lean_assert(pinfos.size() == ssinfos.size()); /* Check if all remaining arguments are nondependent or dependent (but all forward dependencies are subsingletons) */ unsigned i = prefix_sz; for (; i < pinfos.size(); i++) { param_info const & pinfo = pinfos[i]; if (!pinfo.has_fwd_deps()) continue; /* nondependent argument */ if (has_nonsubsingleton_fwd_dep(i, pinfos, ssinfos)) break; /* failed i-th argument has a forward dependent that is not a prop nor a subsingleton */ } if (i == pinfos.size()) return; // It is *cheap* case /* Expensive case */ /* We generate a trace message IF it would be possible to compute more precise information. That is, there is an argument that is a proposition and/or subsingleton, but the corresponding pinfo is not a marked a prop/subsingleton. */ i = 0; for (ss_param_info const & ssinfo : result) { if (ssinfo.is_subsingleton()) continue; expr arg_type = ctx.infer(args[i]); if (ctx.mk_subsingleton_instance(arg_type)) { lean_trace_fun_info( tout() << "approximating function information for '" << fn << "', this may affect the effectiveness of the simplifier and congruence closure modules, " << "more precise information can be efficiently computed if all parameters are moved to the " << "beginning of the function\n";); return; }
/* Store subsingleton parameter info for fn in \c ssinfos */ static void get_ss_core(type_context & ctx, expr const & fn, buffer<ss_param_info> & ssinfos, unsigned max_args) { expr type = ctx.relaxed_try_to_pi(ctx.infer(fn)); type_context::tmp_locals locals(ctx); unsigned i = 0; while (is_pi(type)) { if (i == max_args) break; expr local = locals.push_local_from_binding(type); expr local_type = ctx.infer(local); expr new_type = ctx.relaxed_try_to_pi(instantiate(binding_body(type), local)); bool spec = false; bool is_prop = ctx.is_prop(local_type); bool is_sub = is_prop; if (!is_sub) { // TODO(Leo): check if the following line is a performance bottleneck. is_sub = static_cast<bool>(ctx.mk_subsingleton_instance(local_type)); } ssinfos.emplace_back(spec, is_sub); type = new_type; i++; } }
bool is_comp_irrelevant(type_context & ctx, expr const & e) { expr type = ctx.whnf(ctx.infer(e)); return is_sort(type) || ctx.is_prop(type); }
static optional<head_index> get_backward_target(type_context & ctx, name const & c) { declaration const & d = ctx.env().get(c); list<level> us = param_names_to_levels(d.get_univ_params()); expr type = ctx.try_to_pi(instantiate_type_univ_params(d, us)); return get_backward_target(ctx, type); }
expr whnf_inductive(type_context & ctx, expr const & e) { if (m_unfold_ginductive) return ctx.relaxed_whnf(e); else return ::lean::whnf_ginductive(ctx, e); }