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(); }); }
tactic intros_tactic(list<name> _ns, bool relax_main_opaque) { auto fn = [=](environment const & env, io_state const &, proof_state const & s) { list<name> ns = _ns; goals const & gs = s.get_goals(); if (empty(gs)) { throw_no_goal_if_enabled(s); return optional<proof_state>(); } goal const & g = head(gs); name_generator ngen = s.get_ngen(); auto tc = mk_type_checker(env, ngen.mk_child(), relax_main_opaque); expr t = g.get_type(); expr m = g.get_meta(); bool gen_names = empty(ns); try { while (true) { if (!gen_names && is_nil(ns)) break; if (!is_pi(t)) { if (!is_nil(ns)) { t = tc->ensure_pi(t).first; } else { expr new_t = tc->whnf(t).first; if (!is_pi(new_t)) break; t = new_t; } } name new_name; if (!is_nil(ns)) { new_name = head(ns); ns = tail(ns); } else { new_name = get_unused_name(binding_name(t), m); } expr new_local = mk_local(ngen.next(), new_name, binding_domain(t), binding_info(t)); t = instantiate(binding_body(t), new_local); m = mk_app(m, new_local); } goal new_g(m, t); return some(proof_state(s, goals(new_g, tail(gs)), ngen)); } catch (exception &) { return optional<proof_state>(); } }; return tactic01(fn); }
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); }); }
tactic contradiction_tactic() { auto fn = [=](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 optional<proof_state>(); } goal const & g = head(gs); expr const & t = g.get_type(); substitution subst = s.get_subst(); auto tc = mk_type_checker(env); auto conserv_tc = mk_type_checker(env, UnfoldReducible); buffer<expr> hyps; g.get_hyps(hyps); for (expr const & h : hyps) { expr h_type = mlocal_type(h); h_type = tc->whnf(h_type).first; expr lhs, rhs, arg; if (is_false(env, h_type)) { assign(subst, g, mk_false_rec(*tc, h, t)); return some_proof_state(proof_state(s, tail(gs), subst)); } else if (is_not(env, h_type, arg)) { optional<expr> h_pos; for (expr const & h_prime : hyps) { constraint_seq cs; if (conserv_tc->is_def_eq(arg, mlocal_type(h_prime), justification(), cs) && !cs) { h_pos = h_prime; break; } } if (h_pos) { assign(subst, g, mk_absurd(*tc, t, *h_pos, h)); return some_proof_state(proof_state(s, tail(gs), subst)); } } else if (is_eq(h_type, lhs, rhs)) { lhs = tc->whnf(lhs).first; rhs = tc->whnf(rhs).first; optional<name> lhs_c = is_constructor_app(env, lhs); optional<name> rhs_c = is_constructor_app(env, rhs); if (lhs_c && rhs_c && *lhs_c != *rhs_c) { if (optional<name> I_name = inductive::is_intro_rule(env, *lhs_c)) { name no_confusion(*I_name, "no_confusion"); try { expr I = tc->whnf(tc->infer(lhs).first).first; buffer<expr> args; expr I_fn = get_app_args(I, args); if (is_constant(I_fn)) { level t_lvl = sort_level(tc->ensure_type(t).first); expr V = mk_app(mk_app(mk_constant(no_confusion, cons(t_lvl, const_levels(I_fn))), args), t, lhs, rhs, h); if (auto r = lift_down_if_hott(*tc, V)) { check_term(*tc, *r); assign(subst, g, *r); return some_proof_state(proof_state(s, tail(gs), subst)); } } } catch (kernel_exception & ex) { regular(env, ios) << ex << "\n"; } } } } } return none_proof_state(); }; return tactic01(fn); }