Beispiel #1
0
format pp_def_type_mismatch(formatter const & fmt, environment const & env, options const & opts, name const & n,
                            expr const & expected_type, expr const & given_type) {
    format r("type mismatch at definition '");
    r += format(n);
    r += format("', expected type");
    r += pp_indent_expr(fmt, env, opts, expected_type);
    r += compose(line(), format("given type:"));
    r += pp_indent_expr(fmt, env, opts, given_type);
    return r;
}
Beispiel #2
0
format pp_app_type_mismatch(formatter const & fmt, environment const & env, options const & opts, expr const & app,
                            expr const & expected_type, expr const & given_type) {
    format r;
    r += format("type mismatch at application");
    r += pp_indent_expr(fmt, env, opts, app);
    r += compose(line(), format("expected type:"));
    r += pp_indent_expr(fmt, env, opts, expected_type);
    r += compose(line(), format("given type:"));
    r += pp_indent_expr(fmt, env, opts, given_type);
    return r;
}
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();
        });
}
Beispiel #4
0
format pp_def_lvl_cnstrs_satisfied(formatter const & fmt, environment const & env, options const & opts, expr const & e,
                                   level const & lhs, level const & rhs) {
    format r("constand definition level constraints are not satisfied");
    r += pp_indent_expr(fmt, env, opts, e);
    r += format("level constraint:");
    r += pp(lhs, rhs, opts);
    return r;
}
Beispiel #5
0
format pp_function_expected(formatter const & fmt, environment const & env, options const & opts, expr const & e) {
    return compose(format("function expected at"), pp_indent_expr(fmt, env, opts, e));
}
Beispiel #6
0
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);
        });
}
constraint mk_class_instance_root_cnstr(std::shared_ptr<class_instance_context> const & C, local_context const & _ctx,
                                        expr const & m, bool is_strict, unifier_config const & cfg, delay_factor const & factor) {
    environment const & env = C->env();
    justification j         = mk_failed_to_synthesize_jst(env, m);

    auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
                         name_generator const & ngen) {
        environment const & env  = C->env();
        auto cls_name_it = is_ext_class(C->tc(), meta_type);
        if (!cls_name_it) {
            // do nothing, since type is not a class.
            return lazy_list<constraints>(constraints());
        }
        local_context ctx        = _ctx.instantiate(substitution(s));
        pair<expr, justification> mj = update_meta(meta, s);
        expr new_meta            = mj.first;
        justification new_j      = mj.second;
        unsigned depth           = 0;
        constraint c             = mk_class_instance_cnstr(C, ctx, new_meta, depth);
        unifier_config new_cfg(cfg);
        new_cfg.m_discard        = false;
        new_cfg.m_use_exceptions = false;
        new_cfg.m_pattern        = true;
        new_cfg.m_kind           = C->m_conservative ? unifier_kind::VeryConservative : unifier_kind::Liberal;

        auto to_cnstrs_fn = [=](substitution const & subst, constraints const & cnstrs) -> constraints {
            substitution new_s = subst;
            // some constraints may have been postponed (example: universe level constraints)
            constraints  postponed = map(cnstrs,
                                         [&](constraint const & c) {
                                             // we erase internal justifications
                                             return update_justification(c, mk_composite1(j, new_j));
                                         });
            metavar_closure cls(new_meta);
            cls.add(meta_type);
            bool relax     = C->m_relax;
            constraints cs = cls.mk_constraints(new_s, new_j, relax);
            return append(cs, postponed);
        };

        auto no_solution_fn = [=]() {
            if (is_strict)
                return lazy_list<constraints>();
            else
                return lazy_list<constraints>(constraints());
        };

        unify_result_seq seq1    = unify(env, 1, &c, ngen, substitution(), new_cfg);
        unify_result_seq seq2    = filter(seq1, [=](pair<substitution, constraints> const & p) {
                substitution new_s = p.first;
                expr result = new_s.instantiate(new_meta);
                // We only keep complete solutions (modulo universe metavariables)
                return !has_expr_metavar_relaxed(result);
            });

        if (get_class_unique_class_instances(C->m_ios.get_options())) {
            optional<expr> solution;
            substitution subst;
            constraints  cnstrs;
            for_each(seq2, [&](pair<substitution, constraints> const & p) {
                    subst  = p.first;
                    cnstrs = p.second;
                    expr next_solution = subst.instantiate(new_meta);
                    if (solution) {
                        throw_class_exception(m, [=](formatter const & fmt) {
                                format r = format("ambiguous class-instance resolution, "
                                                  "there is more than one solution");
                                r += pp_indent_expr(fmt, *solution);
                                r += compose(line(), format("and"));
                                r += pp_indent_expr(fmt, next_solution);
                                return r;
                            });
                    } else {
                        solution = next_solution;
                    }
                });
            if (!solution) {
                return no_solution_fn();
            } else {
                // some constraints may have been postponed (example: universe level constraints)
                return lazy_list<constraints>(to_cnstrs_fn(subst, cnstrs));
            }
        } else {
            if (try_multiple_instances(env, *cls_name_it)) {
                lazy_list<constraints> seq3 = map2<constraints>(seq2, [=](pair<substitution, constraints> const & p) {
                        return to_cnstrs_fn(p.first, p.second);
                    });
                if (is_strict) {
                    return seq3;
                } else {
                    // make sure it does not fail by appending empty set of constraints
                    return append(seq3, lazy_list<constraints>(constraints()));
                }
            } else {
                auto p  = seq2.pull();
                if (!p)
                    return no_solution_fn();
                else
                    return lazy_list<constraints>(to_cnstrs_fn(p->first.first, p->first.second));
            }
        }
    };
    bool owner = false;
    bool relax = C->m_relax;
    return mk_choice_cnstr(m, choice_fn, factor, owner, j, relax);
}