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();
    }
}
Exemple #2
0
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();
}
Exemple #3
0
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();
    }
}
Exemple #4
0
 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));
 }
Exemple #6
0
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];
}
Exemple #8
0
/** \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);
}
Exemple #10
0
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;
}
Exemple #11
0
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));
}
Exemple #12
0
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();
        });
}
Exemple #14
0
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();
}
Exemple #15
0
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);
        };
    };
}
Exemple #17
0
 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()));
     }
 }
Exemple #18
0
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);
        });
}
Exemple #19
0
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
}
Exemple #20
0
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()));
}
Exemple #21
0
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(); }
Exemple #23
0
optional<expr> placeholder_type(expr const & e) {
    if (is_local(e) && is_placeholder(e))
        return some_expr(mlocal_type(e));
    else
        return none_expr();
}
Exemple #24
0
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));
}
Exemple #25
0
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());
}
Exemple #29
0
optional<expr> substitution::get_expr(name const & m) const {
    auto it = m_expr_subst.find(m);
    return it ? some_expr(*it) : none_expr();
}
Exemple #30
0
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();
}