optional<expr> mk_class_instance(environment const & env, io_state const & ios, local_context const & ctx, name const & prefix, expr const & type, bool relax_opaque, bool use_local_instances, unifier_config const & cfg) { auto C = std::make_shared<class_instance_context>(env, ios, prefix, relax_opaque, use_local_instances); if (!is_ext_class(C->tc(), type)) return none_expr(); expr meta = ctx.mk_meta(C->m_ngen, some_expr(type), type.get_tag()); unsigned depth = 0; constraint c = mk_class_instance_cnstr(C, ctx, meta, depth); unifier_config new_cfg(cfg); new_cfg.m_discard = true; new_cfg.m_use_exceptions = true; new_cfg.m_pattern = true; new_cfg.m_kind = C->m_conservative ? unifier_kind::VeryConservative : unifier_kind::Liberal; try { auto seq = unify(env, 1, &c, C->m_ngen.mk_child(), substitution(), new_cfg); while (true) { auto p = seq.pull(); lean_assert(p); substitution s = p->first.first; expr r = s.instantiate_all(meta); if (!has_expr_metavar_relaxed(r)) return some_expr(r); seq = p->second; } } catch (exception &) { return none_expr(); } }
optional<expr> defeq_canonizer::find_defeq(name const & h, expr const & e) { list<expr> const * lst = m_state.m_M.find(h); if (!lst) return none_expr(); for (expr const & e1 : *lst) { if (locals_subset(e1, e) && m_ctx.is_def_eq(e1, e)) return some_expr(e1); } return none_expr(); }
optional<expr> unfold_num_app(environment const & env, expr const & e) { if (is_zero(e) || is_one(e) || is_bit0(e) || is_bit1(e)) { return unfold_app(env, e); } else { return none_expr(); } }
expr collect(expr const & e) { return replace(e, [&](expr const & e, unsigned) { if (is_metavar(e)) { name const & id = mlocal_name(e); if (auto r = m_meta_to_param.find(id)) { return some_expr(*r); } else { expr type = m_ctx.infer(e); expr x = m_ctx.push_local("_x", type); m_meta_to_param.insert(id, x); m_meta_to_param_inv.insert(mlocal_name(x), e); m_params.push_back(x); return some_expr(x); } } else if (is_local(e)) { name const & id = mlocal_name(e); if (!m_found_local.contains(id)) { m_found_local.insert(id); m_params.push_back(e); } } else if (is_sort(e)) { return some_expr(update_sort(e, collect(sort_level(e)))); } else if (is_constant(e)) { return some_expr(update_constant(e, collect(const_levels(e)))); } return none_expr(); }); }
optional<expr> expand_core(expr const & e) { lean_assert(!is_lambda(e)); expr t = ctx().whnf(ctx().infer(e)); if (!is_pi(t)) return none_expr(); expr r = mk_lambda(name("x"), binding_domain(t), mk_app(e, mk_var(0))); return some_expr(visit(r)); }
action mk_exprs_action(name const & sep, expr const & rec, optional<expr> const & ini, optional<name> const & terminator, bool right, unsigned rbp) { if (get_free_var_range(rec) > 2) throw exception("invalid notation, the expression used to combine a sequence of expressions " "must not contain free variables with de Bruijn indices greater than 1"); expr new_rec = annotate_macro_subterms(rec); optional<expr> new_ini = ini ? some_expr(annotate_macro_subterms(*ini)) : none_expr(); return action(new exprs_action_cell(sep, new_rec, new_ini, terminator, right, rbp)); }
optional<expr> tmp_type_context::get_assignment(expr const & m) const { unsigned idx = to_meta_idx(m); // if the following assetion is violated, we have two options: // 1- We should create the meta-variable using mk_mvar // 2- We create using mk_idx_metavar, and notify this object using // set_next_mvar_idx if (idx >= m_eassignment.size()) return none_expr(); return m_eassignment[idx]; }
/** \brief Given \c a, an expression that is the denotation of an expression, if \c a is a variable, then use the actions in the transitions \c ts to expand \c a. The idea is to produce a head symbol we can use to decide whether the notation should be considered during pretty printing. \see get_head_index */ static expr expand_pp_pattern(unsigned num, transition const * ts, expr const & a) { lean_assert(is_simple(num, ts)); if (!is_var(a)) return a; return replace(a, [&](expr const & e) { if (is_var(e)) { unsigned vidx = var_idx(e); unsigned i = num; unsigned offset = 0; while (i > 0) { --i; action const & act = ts[i].get_action(); switch (act.kind()) { case action_kind::Binder: case action_kind::Binders: case action_kind::Skip: break; case action_kind::Ext: case action_kind::LuaExt: lean_unreachable(); case action_kind::Expr: if (vidx == 0) return none_expr(); offset++; vidx--; break; case action_kind::Exprs: if (vidx == 0) return some_expr(lift_free_vars(act.get_rec(), offset)); offset++; vidx--; break; case action_kind::ScopedExpr: if (vidx == 0) return some_expr(lift_free_vars(act.get_rec(), offset)); offset++; vidx--; break; } } return none_expr(); } else { return none_expr(); } }); }
optional<expr> projection_converter::is_stuck(expr const & e, type_checker & c) { projection_info const * info = is_projection(e); if (!info) return default_converter::is_stuck(e, c); buffer<expr> args; get_app_args(e, args); if (args.size() <= info->m_nparams) return none_expr(); expr mk = whnf(args[info->m_nparams], c).first; return c.is_stuck(mk); }
optional<expr> has_expr_metavar_strict(expr const & e) { if (!has_expr_metavar(e)) return none_expr(); optional<expr> r; for_each(e, [&](expr const & e, unsigned) { if (r || !has_expr_metavar(e)) return false; if (is_meta(e)) { r = e; return false; } if (is_local(e)) return false; // do not visit type return true; }); return r; }
static int mk_exprs_action(lua_State * L) { int nargs = lua_gettop(L); unsigned rbp = nargs <= 5 ? 0 : lua_tonumber(L, 6); optional<name> terminator; if (nargs >= 4) terminator = to_optional_name(L, 4); return push_notation_action(L, mk_exprs_action(to_name_ext(L, 1), to_expr(L, 2), lua_isnil(L, 3) ? none_expr() : some_expr(to_expr(L, 3)), terminator, lua_toboolean(L, 5), rbp)); }
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(); } }
tactic change_goal_tactic(elaborate_fn const & elab, expr const & e) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { proof_state new_s = s; goals const & gs = new_s.get_goals(); if (!gs) { throw_no_goal_if_enabled(s); return proof_state_seq(); } expr t = head(gs).get_type(); bool report_unassigned = true; if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(), report_unassigned)) { goals const & gs = new_s.get_goals(); goal const & g = head(gs); substitution subst = new_s.get_subst(); auto tc = mk_type_checker(env); constraint_seq cs; if (tc->is_def_eq(t, *new_e, justification(), cs)) { if (cs) { unifier_config cfg(ios.get_options()); buffer<constraint> cs_buf; cs.linearize(cs_buf); to_buffer(new_s.get_postponed(), cs_buf); unify_result_seq rseq = unify(env, cs_buf.size(), cs_buf.data(), subst, cfg); return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state { substitution const & subst = p.first; constraints const & postponed = p.second; substitution new_subst = subst; expr final_e = new_subst.instantiate_all(*new_e); expr M = g.mk_meta(mk_fresh_name(), final_e); goal new_g(M, final_e); assign(new_subst, g, M); return proof_state(new_s, cons(new_g, tail(gs)), new_subst, postponed); }); } expr M = g.mk_meta(mk_fresh_name(), *new_e); goal new_g(M, *new_e); assign(subst, g, M); return proof_state_seq(proof_state(new_s, cons(new_g, tail(gs)), subst)); } else { throw_tactic_exception_if_enabled(new_s, [=](formatter const & fmt) { format r = format("invalid 'change' tactic, the given type"); r += pp_indent_expr(fmt, *new_e); r += compose(line(), format("does not match the goal type")); r += pp_indent_expr(fmt, t); return r; }); return proof_state_seq(); } } return proof_state_seq(); }); }
void tmp_type_context::pop_core() { lean_assert(!m_scopes.empty()); scope const & s = m_scopes.back(); unsigned old_sz = s.m_trail_sz; unsigned i = m_trail.size(); while (i > old_sz) { --i; pair<trail_kind, unsigned> const & p = m_trail.back(); switch (p.first) { case trail_kind::Level: m_uassignment[p.second] = none_level(); break; case trail_kind::Expr: m_eassignment[p.second] = none_expr(); break; } m_trail.pop_back(); } lean_assert(m_trail.size() == old_sz); m_uassignment.resize(s.m_uassignment_sz); m_eassignment.resize(s.m_eassignment_sz); m_scopes.pop_back(); }
tactic apply_tactic_core(elaborate_fn const & elab, expr const & e, add_meta_kind add_meta, subgoals_action_kind k) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) { goals const & gs = s.get_goals(); if (empty(gs)) { throw_no_goal_if_enabled(s); return proof_state_seq(); } goal const & g = head(gs); name_generator ngen = s.get_ngen(); expr new_e; substitution new_subst; constraints cs_; auto ecs = elab(g, ngen.mk_child(), e, none_expr(), s.get_subst(), false); std::tie(new_e, new_subst, cs_) = ecs; buffer<constraint> cs; to_buffer(cs_, cs); to_buffer(s.get_postponed(), cs); proof_state new_s(s, new_subst, ngen, constraints()); return apply_tactic_core(env, ios, new_s, new_e, cs, add_meta, k); }); }
strategy iterative_deepening(strategy const & S, unsigned init, unsigned inc, unsigned max) { return [=]() { // NOLINT state s = curr_state(); unsigned ncs = get_num_choice_points(); unsigned d = init; while (true) { flet<unsigned> set_depth(get_config().m_max_depth, d); if (auto r = S()) return r; d += inc; if (d > max) { if (get_config().m_show_failure) display_curr_state(); return none_expr(); } curr_state() = s; shrink_choice_points(ncs); }; }; }
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())); } }
tactic check_expr_tactic(elaborate_fn const & elab, expr const & e, std::string const & fname, pair<unsigned, unsigned> const & pos) { return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) { goals const & gs = s.get_goals(); if (empty(gs)) { throw_no_goal_if_enabled(s); return none_proof_state(); } goal const & g = head(gs); name_generator ngen = s.get_ngen(); expr new_e = std::get<0>(elab(g, ios.get_options(), ngen.mk_child(), e, none_expr(), s.get_subst(), false)); auto tc = mk_type_checker(env, ngen.mk_child()); expr new_t = tc->infer(new_e).first; auto out = regular(env, ios); flycheck_information info(out); if (info.enabled()) { out << fname << ":" << pos.first << ":" << pos.second << ": information: "; out << "check result:\n"; } out << new_e << " : " << new_t << endl; return some_proof_state(s); }); }
action replace(action const & a, std::function<expr(expr const &)> const & f) { switch (a.kind()) { case action_kind::Skip: case action_kind::Binder: case action_kind::Binders: case action_kind::Ext: case action_kind::LuaExt: case action_kind::Expr: return a; case action_kind::Exprs: return mk_exprs_action(a.get_sep(), f(a.get_rec()), a.get_initial() ? some_expr(f(*a.get_initial())) : none_expr(), a.get_terminator(), a.is_fold_right(), a.rbp()); case action_kind::ScopedExpr: return mk_scoped_expr_action(f(a.get_rec()), a.rbp(), a.use_lambda_abstraction()); } lean_unreachable(); // LCOV_EXCL_LINE }
optional<expr> expand_string_macro(expr const & e) { if (!is_string_macro(e)) return none_expr(); return some_expr(from_string_core(to_string_macro(e).get_value())); }
expr tmp_type_context::mk_mvar(expr const & type) { unsigned idx = m_eassignment.size(); m_eassignment.push_back(none_expr()); return mk_idx_metavar(idx, type); }
virtual optional<expr> is_stuck(expr const &, extension_context &) const { return none_expr(); }
optional<expr> placeholder_type(expr const & e) { if (is_local(e) && is_placeholder(e)) return some_expr(mlocal_type(e)); else return none_expr(); }
optional<expr> is_neg(expr const & e) { if (!is_const_app(e, get_has_neg_neg_name(), 3)) return none_expr(); return some_expr(app_arg(e)); }
optional<expr> is_bit1(expr const & e) { if (!is_const_app(e, get_bit1_name(), 4)) return none_expr(); return some_expr(app_arg(e)); }
declaration update_declaration_univ_params(declaration const & d, level_param_names const & ps) { return update_declaration(d, optional<level_param_names>(ps), none_expr(), none_expr()); }
declaration update_declaration_value(declaration const & d, expr const & value) { return update_declaration(d, optional<level_param_names>(), none_expr(), some_expr(value)); }
declaration update_declaration(declaration const & d, level_param_names const & ps, expr const & type) { return update_declaration(d, optional<level_param_names>(ps), some_expr(type), none_expr()); }
optional<expr> substitution::get_expr(name const & m) const { auto it = m_expr_subst.find(m); return it ? some_expr(*it) : none_expr(); }
optional<expr> depends_on(unsigned sz, expr const * es, expr const & h) { for (unsigned i = 0; i < sz; i++) if (depends_on(es[i], h)) return some_expr(es[i]); return none_expr(); }