bool match_pattern(type_checker & tc, expr const & pattern, declaration const & d, unsigned max_steps, bool cheap) { name_generator ngen = tc.mk_ngen(); buffer<level> ls; unsigned num_ls = d.get_num_univ_params(); for (unsigned i = 0; i < num_ls; i++) ls.push_back(mk_meta_univ(ngen.next())); expr dt = instantiate_type_univ_params(d, to_list(ls.begin(), ls.end())); unsigned num_e = get_expect_num_args(tc, pattern); unsigned num_d = get_expect_num_args(tc, dt); if (num_e > num_d) return false; for (unsigned i = 0; i < num_d - num_e; i++) { dt = tc.whnf(dt).first; expr local = mk_local(ngen.next(), binding_domain(dt)); dt = instantiate(binding_body(dt), local); } try { unifier_config cfg; cfg.m_max_steps = max_steps; cfg.m_kind = cheap ? unifier_kind::Cheap : unifier_kind::Liberal; cfg.m_ignore_context_check = true; auto r = unify(tc.env(), pattern, dt, tc.mk_ngen(), substitution(), cfg); return static_cast<bool>(r.pull()); } catch (exception&) { return false; } }
static proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & _e, buffer<constraint> & cs, add_meta_kind add_meta, subgoals_action_kind subgoals_action, optional<unifier_kind> const & uk = optional<unifier_kind>()) { goals const & gs = s.get_goals(); if (empty(gs)) { throw_no_goal_if_enabled(s); return proof_state_seq(); } bool class_inst = get_apply_class_instance(ios.get_options()); name_generator ngen = s.get_ngen(); std::shared_ptr<type_checker> tc(mk_type_checker(env, ngen.mk_child())); goal g = head(gs); goals tail_gs = tail(gs); expr t = g.get_type(); expr e = _e; auto e_t_cs = tc->infer(e); e_t_cs.second.linearize(cs); expr e_t = e_t_cs.first; buffer<expr> metas; local_context ctx; bool initialized_ctx = false; unifier_config cfg(ios.get_options()); if (uk) cfg.m_kind = *uk; if (add_meta != DoNotAdd) { unsigned num_e_t = get_expect_num_args(*tc, e_t); if (add_meta == AddDiff) { unsigned num_t = get_expect_num_args(*tc, t); if (num_t <= num_e_t) num_e_t -= num_t; else num_e_t = 0; } else { lean_assert(add_meta == AddAll); } for (unsigned i = 0; i < num_e_t; i++) { auto e_t_cs = tc->whnf(e_t); e_t_cs.second.linearize(cs); e_t = e_t_cs.first; expr meta; if (class_inst && binding_info(e_t).is_inst_implicit()) { if (!initialized_ctx) { ctx = g.to_local_context(); initialized_ctx = true; } bool use_local_insts = true; bool is_strict = false; auto mc = mk_class_instance_elaborator( env, ios, ctx, ngen.next(), optional<name>(), use_local_insts, is_strict, some_expr(head_beta_reduce(binding_domain(e_t))), e.get_tag(), cfg, nullptr); meta = mc.first; cs.push_back(mc.second); } else { meta = g.mk_meta(ngen.next(), head_beta_reduce(binding_domain(e_t))); } e = mk_app(e, meta); e_t = instantiate(binding_body(e_t), meta); metas.push_back(meta); } } metavar_closure cls(t); cls.mk_constraints(s.get_subst(), justification()); pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t); if (!dcs.first) { throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) { format r = format("invalid 'apply' tactic, failed to unify"); r += pp_indent_expr(fmt, t); r += compose(line(), format("with")); r += pp_indent_expr(fmt, e_t); return r; }); return proof_state_seq(); } dcs.second.linearize(cs); unify_result_seq rseq = unify(env, cs.size(), cs.data(), ngen.mk_child(), s.get_subst(), cfg); list<expr> meta_lst = to_list(metas.begin(), metas.end()); return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state { substitution const & subst = p.first; constraints const & postponed = p.second; name_generator new_ngen(ngen); substitution new_subst = subst; expr new_e = new_subst.instantiate_all(e); assign(new_subst, g, new_e); goals new_gs = tail_gs; if (subgoals_action != IgnoreSubgoals) { buffer<expr> metas; for (auto m : meta_lst) { if (!new_subst.is_assigned(get_app_fn(m))) metas.push_back(m); } if (subgoals_action == AddRevSubgoals) { for (unsigned i = 0; i < metas.size(); i++) new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs); } else { lean_assert(subgoals_action == AddSubgoals || subgoals_action == AddAllSubgoals); if (subgoals_action == AddSubgoals) remove_redundant_metas(metas); unsigned i = metas.size(); while (i > 0) { --i; new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs); } } } return proof_state(s, new_gs, new_subst, new_ngen, postponed); }); }