refactor(frontends/lean/elaborator): move placeholder_elaborator to its own module
This commit is contained in:
parent
9ce356e515
commit
6bc41f8dde
6 changed files with 317 additions and 180 deletions
|
@ -6,6 +6,6 @@ decl_cmds.cpp util.cpp inductive_cmd.cpp elaborator.cpp
|
|||
dependencies.cpp parser_bindings.cpp begin_end_ext.cpp
|
||||
class.cpp pp_options.cpp tactic_hint.cpp pp.cpp theorem_queue.cpp
|
||||
structure_cmd.cpp info_manager.cpp no_info.cpp extra_info.cpp
|
||||
local_context.cpp choice_iterator.cpp)
|
||||
local_context.cpp choice_iterator.cpp placeholder_elaborator.cpp)
|
||||
|
||||
target_link_libraries(lean_frontend ${LEAN_LIBS})
|
||||
|
|
|
@ -42,6 +42,7 @@ Author: Leonardo de Moura
|
|||
#include "frontends/lean/extra_info.h"
|
||||
#include "frontends/lean/local_context.h"
|
||||
#include "frontends/lean/choice_iterator.h"
|
||||
#include "frontends/lean/placeholder_elaborator.h"
|
||||
|
||||
#ifndef LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES
|
||||
#define LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES true
|
||||
|
@ -63,8 +64,6 @@ elaborator_context::elaborator_context(environment const & env, io_state const &
|
|||
m_use_local_instances = get_elaborator_local_instances(ios.get_options());
|
||||
}
|
||||
|
||||
typedef std::unique_ptr<type_checker> type_checker_ptr;
|
||||
|
||||
/** \brief Helper class for implementing the \c elaborate functions. */
|
||||
class elaborator {
|
||||
typedef name_map<expr> local_tactic_hints;
|
||||
|
@ -168,138 +167,6 @@ class elaborator {
|
|||
}
|
||||
};
|
||||
|
||||
/** \brief Whenever the elaborator finds a placeholder '_' or introduces an implicit argument, it creates
|
||||
a metavariable \c ?m. It also creates a delayed choice constraint (?m in fn).
|
||||
|
||||
The function \c fn produces a stream of alternative solutions for ?m.
|
||||
In this case, \c fn will do the following:
|
||||
1) if the elaborated type of ?m is a 'class' C, then the stream will start with
|
||||
a) all local instances of class C (if elaborator.local_instances == true)
|
||||
b) solutions produced by tactic_hints for class C
|
||||
2) if the elaborated type of ?m is not a class, then the stream will only contain
|
||||
the solutions produced by tactic_hints.
|
||||
|
||||
The unifier only process delayed choice constraints when there are no other kind of constraint to be
|
||||
processed.
|
||||
|
||||
This is a helper class for implementing this choice function.
|
||||
*/
|
||||
struct placeholder_elaborator : public choice_iterator {
|
||||
elaborator & m_elab;
|
||||
expr m_meta;
|
||||
expr m_meta_type; // elaborated type of the metavariable
|
||||
list<expr> m_local_instances; // local instances that should also be included in the class-instance resolution.
|
||||
list<name> m_instances; // global declaration names that are class instances.
|
||||
// This information is retrieved using #get_class_instances.
|
||||
list<tactic_hint_entry> m_tactics;
|
||||
proof_state_seq m_tactic_result; // result produce by last executed tactic.
|
||||
buffer<expr> m_mvars_in_meta_type; // metavariables that occur in m_meta_type, the tactics may instantiate some of them
|
||||
saved_state m_state;
|
||||
justification m_jst;
|
||||
bool m_relax_main_opaque;
|
||||
|
||||
placeholder_elaborator(elaborator & elab, expr const & meta, expr const & meta_type,
|
||||
list<expr> const & local_insts, list<name> const & instances, list<tactic_hint_entry> const & tacs,
|
||||
saved_state const & s, justification const & j, bool ignore_failure, bool relax):
|
||||
choice_iterator(ignore_failure),
|
||||
m_elab(elab), m_meta(meta), m_meta_type(meta_type), m_local_instances(local_insts), m_instances(instances),
|
||||
m_tactics(tacs), m_state(s), m_jst(j), m_relax_main_opaque(relax) {
|
||||
collect_metavars(meta_type, m_mvars_in_meta_type);
|
||||
}
|
||||
|
||||
optional<constraints> try_instance(expr const & inst, expr const & inst_type) {
|
||||
expr type = inst_type;
|
||||
// create the term pre (inst _ ... _)
|
||||
expr pre = copy_tag(m_meta, mk_explicit(inst));
|
||||
while (true) {
|
||||
type = m_elab.whnf(type).first;
|
||||
if (!is_pi(type))
|
||||
break;
|
||||
type = instantiate(binding_body(type), ::lean::mk_local(m_elab.m_ngen.next(), binding_domain(type)));
|
||||
pre = copy_tag(m_meta, ::lean::mk_app(pre, copy_tag(m_meta, mk_strict_expr_placeholder())));
|
||||
}
|
||||
try {
|
||||
bool no_info = true;
|
||||
new_scope s(m_elab, m_state, no_info);
|
||||
expr type = m_meta_type;
|
||||
buffer<expr> locals;
|
||||
while (true) {
|
||||
type = m_elab.whnf(type).first;
|
||||
if (!is_pi(type))
|
||||
break;
|
||||
expr local = ::lean::mk_local(m_elab.m_ngen.next(), binding_name(type), binding_domain(type),
|
||||
binding_info(type));
|
||||
if (binding_info(type).is_contextual())
|
||||
m_elab.m_context.add_local(local);
|
||||
m_elab.m_full_context.add_local(local);
|
||||
locals.push_back(local);
|
||||
type = instantiate(binding_body(type), local);
|
||||
}
|
||||
pair<expr, constraint_seq> rcs = m_elab.visit(pre); // use elaborator to create metavariables, levels, etc.
|
||||
expr r = Fun(locals, rcs.first);
|
||||
buffer<constraint> cs;
|
||||
to_buffer(rcs.second, m_jst, cs);
|
||||
return optional<constraints>(cons(mk_eq_cnstr(m_meta, r, m_jst, m_relax_main_opaque),
|
||||
to_list(cs.begin(), cs.end())));
|
||||
} catch (exception &) {
|
||||
return optional<constraints>();
|
||||
}
|
||||
}
|
||||
|
||||
optional<constraints> try_instance(name const & inst) {
|
||||
auto decl = m_elab.env().find(inst);
|
||||
if (!decl)
|
||||
return optional<constraints>();
|
||||
return try_instance(copy_tag(m_meta, mk_constant(inst)), decl->get_type());
|
||||
}
|
||||
|
||||
optional<constraints> get_next_tactic_result() {
|
||||
while (auto next = m_tactic_result.pull()) {
|
||||
m_tactic_result = next->second;
|
||||
if (!empty(next->first.get_goals()))
|
||||
continue; // has unsolved goals
|
||||
substitution subst = next->first.get_subst();
|
||||
buffer<constraint> cs;
|
||||
expr const & mvar = get_app_fn(m_meta);
|
||||
cs.push_back(mk_eq_cnstr(mvar, subst.instantiate(mvar), m_jst, m_relax_main_opaque));
|
||||
for (auto const & mvar : m_mvars_in_meta_type)
|
||||
cs.push_back(mk_eq_cnstr(mvar, subst.instantiate(mvar), m_jst, m_relax_main_opaque));
|
||||
return optional<constraints>(to_list(cs.begin(), cs.end()));
|
||||
}
|
||||
return optional<constraints>();
|
||||
}
|
||||
|
||||
virtual optional<constraints> next() {
|
||||
while (!empty(m_local_instances)) {
|
||||
expr inst = head(m_local_instances);
|
||||
m_local_instances = tail(m_local_instances);
|
||||
if (!is_local(inst))
|
||||
continue;
|
||||
if (auto r = try_instance(inst, mlocal_type(inst)))
|
||||
return r;
|
||||
}
|
||||
while (!empty(m_instances)) {
|
||||
name inst = head(m_instances);
|
||||
m_instances = tail(m_instances);
|
||||
if (auto cs = try_instance(inst))
|
||||
return cs;
|
||||
}
|
||||
if (auto cs = get_next_tactic_result())
|
||||
return cs;
|
||||
while (!empty(m_tactics)) {
|
||||
tactic const & tac = head(m_tactics).get_tactic();
|
||||
m_tactics = tail(m_tactics);
|
||||
proof_state ps(goals(goal(m_meta, m_meta_type)), substitution(), m_elab.m_ngen.mk_child());
|
||||
try {
|
||||
m_tactic_result = tac(m_elab.env(), m_elab.ios(), ps);
|
||||
if (auto cs = get_next_tactic_result())
|
||||
return cs;
|
||||
} catch (exception &) {}
|
||||
}
|
||||
return optional<constraints>();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
elaborator(elaborator_context & env, list<expr> const & ctx, name_generator const & ngen):
|
||||
m_env(env),
|
||||
|
@ -418,40 +285,11 @@ public:
|
|||
solutions using class-instances and tactic-hints.
|
||||
*/
|
||||
expr mk_placeholder_meta(optional<expr> const & type, tag g, bool is_strict, constraint_seq & cs) {
|
||||
expr m = m_context.mk_meta(type, g);
|
||||
saved_state st(*this);
|
||||
justification j = mk_failed_to_synthesize_jst(env(), m);
|
||||
bool relax = m_relax_main_opaque;
|
||||
auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
|
||||
name_generator const & /* ngen */) {
|
||||
expr const & mvar = get_app_fn(meta);
|
||||
if (auto cls_name_it = is_ext_class(*m_tc[relax], meta_type)) {
|
||||
name cls_name = *cls_name_it;
|
||||
list<expr> local_insts;
|
||||
if (use_local_instances())
|
||||
local_insts = get_local_instances(*m_tc[relax], st.m_ctx, cls_name);
|
||||
list<name> insts = get_class_instances(env(), cls_name);
|
||||
list<tactic_hint_entry> tacs;
|
||||
if (!s.is_assigned(mvar))
|
||||
tacs = get_tactic_hints(env(), cls_name);
|
||||
if (empty(local_insts) && empty(insts) && empty(tacs))
|
||||
return lazy_list<constraints>(); // nothing to be done
|
||||
bool ignore_failure = false; // we are always strict with placeholders associated with classes
|
||||
return choose(std::make_shared<placeholder_elaborator>(*this, meta, meta_type, local_insts, insts, tacs, st,
|
||||
j, ignore_failure, m_relax_main_opaque));
|
||||
} else if (s.is_assigned(mvar)) {
|
||||
// if the metavariable is assigned and it is not a class, then we just ignore it, and return
|
||||
// the an empty set of constraints.
|
||||
return lazy_list<constraints>(constraints());
|
||||
} else {
|
||||
list<tactic_hint_entry> tacs = get_tactic_hints(env());
|
||||
bool ignore_failure = !is_strict;
|
||||
return choose(std::make_shared<placeholder_elaborator>(*this, meta, meta_type, list<expr>(), list<name>(),
|
||||
tacs, st, j, ignore_failure, m_relax_main_opaque));
|
||||
}
|
||||
};
|
||||
cs += mk_choice_cnstr(m, choice_fn, to_delay_factor(cnstr_group::ClassInstance), false, j, m_relax_main_opaque);
|
||||
return m;
|
||||
auto ec = mk_placeholder_elaborator(env(), ios(), m_context.get_data(),
|
||||
m_ngen.next(), m_relax_main_opaque, use_local_instances(),
|
||||
is_strict, type, g);
|
||||
cs += ec.second;
|
||||
return ec.first;
|
||||
}
|
||||
|
||||
expr visit_expecting_type(expr const & e, constraint_seq & cs) {
|
||||
|
@ -484,7 +322,8 @@ public:
|
|||
expr m = m_full_context.mk_meta(t, e.get_tag());
|
||||
saved_state s(*this);
|
||||
bool relax = m_relax_main_opaque;
|
||||
auto fn = [=](expr const & mvar, expr const & /* type */, substitution const & /* s */, name_generator const & /* ngen */) {
|
||||
auto fn = [=](expr const & mvar, expr const & /* type */, substitution const & /* s */,
|
||||
name_generator const & /* ngen */) {
|
||||
return choose(std::make_shared<choice_expr_elaborator>(*this, mvar, e, s, relax));
|
||||
};
|
||||
justification j = mk_justification("none of the overloads is applicable", some_expr(e));
|
||||
|
@ -1014,16 +853,6 @@ public:
|
|||
return unify(env(), tmp.size(), tmp.data(), m_ngen.mk_child(), unifier_config(ios().get_options(), true));
|
||||
}
|
||||
|
||||
static void collect_metavars(expr const & e, buffer<expr> & mvars) {
|
||||
for_each(e, [&](expr const & e, unsigned) {
|
||||
if (is_metavar(e)) {
|
||||
mvars.push_back(e);
|
||||
return false; /* do not visit its type */
|
||||
}
|
||||
return has_metavar(e);
|
||||
});
|
||||
}
|
||||
|
||||
void display_unsolved_proof_state(expr const & mvar, proof_state const & ps, char const * msg) {
|
||||
lean_assert(is_metavar(mvar));
|
||||
if (!m_displayed_errors.contains(mlocal_name(mvar))) {
|
||||
|
|
261
src/frontends/lean/placeholder_elaborator.cpp
Normal file
261
src/frontends/lean/placeholder_elaborator.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "library/unifier.h"
|
||||
#include "library/opaque_hints.h"
|
||||
#include "frontends/lean/util.h"
|
||||
#include "frontends/lean/class.h"
|
||||
#include "frontends/lean/tactic_hint.h"
|
||||
#include "frontends/lean/local_context.h"
|
||||
#include "frontends/lean/choice_iterator.h"
|
||||
|
||||
namespace lean {
|
||||
/** \brief Context for handling placeholder metavariable choice constraint */
|
||||
struct placeholder_context {
|
||||
io_state m_ios;
|
||||
name_generator m_ngen;
|
||||
type_checker_ptr m_tc;
|
||||
local_context m_ctx;
|
||||
bool m_relax;
|
||||
bool m_use_local_instances;
|
||||
placeholder_context(environment const & env, io_state const & ios, list<expr> const & ctx,
|
||||
name const & prefix, bool relax, bool use_local_instances):
|
||||
m_ios(ios),
|
||||
m_ngen(prefix),
|
||||
m_tc(mk_type_checker_with_hints(env, m_ngen.mk_child(), relax)),
|
||||
m_ctx(m_ngen.next(), ctx),
|
||||
m_relax(relax),
|
||||
m_use_local_instances(use_local_instances) {
|
||||
}
|
||||
|
||||
environment const & env() const { return m_tc->env(); }
|
||||
io_state const & ios() const { return m_ios; }
|
||||
bool use_local_instances() const { return m_use_local_instances; }
|
||||
type_checker & tc() const { return *m_tc; }
|
||||
};
|
||||
|
||||
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
||||
bool is_strict, optional<expr> const & type, tag g);
|
||||
|
||||
/** \brief Whenever the elaborator finds a placeholder '_' or introduces an
|
||||
implicit argument, it creates a metavariable \c ?m. It also creates a
|
||||
delayed choice constraint (?m in fn).
|
||||
|
||||
The function \c fn produces a stream of alternative solutions for ?m.
|
||||
In this case, \c fn will do the following:
|
||||
1) if the elaborated type of ?m is a 'class' C, then the stream will start with
|
||||
a) all local instances of class C (if elaborator.local_instances == true)
|
||||
b) solutions produced by tactic_hints for class C
|
||||
|
||||
2) if the elaborated type of ?m is not a class, then the stream will only contain
|
||||
the solutions produced by tactic_hints.
|
||||
|
||||
The unifier only process delayed choice constraints when there are no other kind
|
||||
of constraint to be processed.
|
||||
|
||||
This is a helper class for implementing this choice function.
|
||||
*/
|
||||
struct placeholder_elaborator : public choice_iterator {
|
||||
std::shared_ptr<placeholder_context> m_C;
|
||||
expr m_meta;
|
||||
// elaborated type of the metavariable
|
||||
expr m_meta_type;
|
||||
// local instances that should also be included in the
|
||||
// class-instance resolution.
|
||||
// This information is retrieved from the local context
|
||||
list<expr> m_local_instances;
|
||||
// global declaration names that are class instances.
|
||||
// This information is retrieved using #get_class_instances.
|
||||
list<name> m_instances;
|
||||
// Tactic hints for the class
|
||||
list<tactic_hint_entry> m_tactics;
|
||||
// result produce by last executed tactic.
|
||||
proof_state_seq m_tactic_result;
|
||||
// metavariables that occur in m_meta_type, the tactics may instantiate some of them
|
||||
buffer<expr> m_mvars_in_meta_type;
|
||||
justification m_jst;
|
||||
|
||||
placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
||||
expr const & meta, expr const & meta_type,
|
||||
list<expr> const & local_insts, list<name> const & instances,
|
||||
list<tactic_hint_entry> const & tacs,
|
||||
justification const & j, bool ignore_failure):
|
||||
choice_iterator(ignore_failure), m_C(C),
|
||||
m_meta(meta), m_meta_type(meta_type),
|
||||
m_local_instances(local_insts), m_instances(instances),
|
||||
m_tactics(tacs),
|
||||
m_jst(j) {
|
||||
collect_metavars(meta_type, m_mvars_in_meta_type);
|
||||
}
|
||||
|
||||
constraints mk_constraints(constraint const & c, buffer<constraint> const & cs) {
|
||||
return cons(c, to_list(cs.begin(), cs.end()));
|
||||
}
|
||||
|
||||
optional<constraints> try_instance(expr const & inst, expr const & inst_type) {
|
||||
type_checker & tc = m_C->tc();
|
||||
name_generator & ngen = m_C->m_ngen;
|
||||
tag g = inst.get_tag();
|
||||
local_context & ctx = m_C->m_ctx;
|
||||
try {
|
||||
local_context::scope scope(ctx);
|
||||
buffer<expr> locals;
|
||||
expr meta_type = m_meta_type;
|
||||
while (true) {
|
||||
meta_type = tc.whnf(meta_type).first;
|
||||
if (!is_pi(meta_type))
|
||||
break;
|
||||
expr local = mk_local(ngen.next(), binding_name(meta_type),
|
||||
binding_domain(meta_type), binding_info(meta_type));
|
||||
ctx.add_local(local);
|
||||
locals.push_back(local);
|
||||
meta_type = instantiate(binding_body(meta_type), local);
|
||||
}
|
||||
expr type = inst_type;
|
||||
expr r = inst;
|
||||
buffer<constraint> cs;
|
||||
while (true) {
|
||||
type = tc.whnf(type).first;
|
||||
if (!is_pi(type))
|
||||
break;
|
||||
bool is_strict = true;
|
||||
pair<expr, constraint> ac = mk_placeholder_elaborator(m_C, is_strict,
|
||||
some_expr(binding_domain(type)), g);
|
||||
expr arg = ac.first;
|
||||
cs.push_back(ac.second);
|
||||
r = mk_app(r, arg).set_tag(g);
|
||||
type = instantiate(binding_body(type), arg);
|
||||
}
|
||||
r = Fun(locals, r);
|
||||
bool relax = m_C->m_relax;
|
||||
constraint c = mk_eq_cnstr(m_meta, r, m_jst, relax);
|
||||
return optional<constraints>(mk_constraints(c, cs));
|
||||
} catch (exception &) {
|
||||
return optional<constraints>();
|
||||
}
|
||||
}
|
||||
|
||||
optional<constraints> try_instance(name const & inst) {
|
||||
environment const & env = m_C->env();
|
||||
if (auto decl = env.find(inst)) {
|
||||
name_generator & ngen = m_C->m_ngen;
|
||||
buffer<level> ls_buffer;
|
||||
unsigned num_univ_ps = length(decl->get_univ_params());
|
||||
for (unsigned i = 0; i < num_univ_ps; i++)
|
||||
ls_buffer.push_back(mk_meta_univ(ngen.next()));
|
||||
levels ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
||||
expr inst_cnst = copy_tag(m_meta, mk_constant(inst, ls));
|
||||
expr inst_type = instantiate_type_univ_params(*decl, ls);
|
||||
return try_instance(inst_cnst, inst_type);
|
||||
} else {
|
||||
return optional<constraints>();
|
||||
}
|
||||
}
|
||||
|
||||
optional<constraints> get_next_tactic_result() {
|
||||
while (auto next = m_tactic_result.pull()) {
|
||||
m_tactic_result = next->second;
|
||||
if (!empty(next->first.get_goals()))
|
||||
continue; // has unsolved goals
|
||||
substitution subst = next->first.get_subst();
|
||||
buffer<constraint> cs;
|
||||
expr const & mvar = get_app_fn(m_meta);
|
||||
bool relax = m_C->m_relax;
|
||||
cs.push_back(mk_eq_cnstr(mvar, subst.instantiate(mvar), m_jst, relax));
|
||||
for (auto const & mvar : m_mvars_in_meta_type)
|
||||
cs.push_back(mk_eq_cnstr(mvar, subst.instantiate(mvar), m_jst, relax));
|
||||
return optional<constraints>(to_list(cs.begin(), cs.end()));
|
||||
}
|
||||
return optional<constraints>();
|
||||
}
|
||||
|
||||
virtual optional<constraints> next() {
|
||||
while (!empty(m_local_instances)) {
|
||||
expr inst = head(m_local_instances);
|
||||
m_local_instances = tail(m_local_instances);
|
||||
if (!is_local(inst))
|
||||
continue;
|
||||
if (auto r = try_instance(inst, mlocal_type(inst)))
|
||||
return r;
|
||||
}
|
||||
while (!empty(m_instances)) {
|
||||
name inst = head(m_instances);
|
||||
m_instances = tail(m_instances);
|
||||
if (auto cs = try_instance(inst))
|
||||
return cs;
|
||||
}
|
||||
if (auto cs = get_next_tactic_result())
|
||||
return cs;
|
||||
while (!empty(m_tactics)) {
|
||||
tactic const & tac = head(m_tactics).get_tactic();
|
||||
m_tactics = tail(m_tactics);
|
||||
proof_state ps(goals(goal(m_meta, m_meta_type)), substitution(), m_C->m_ngen.mk_child());
|
||||
try {
|
||||
m_tactic_result = tac(m_C->env(), m_C->ios(), ps);
|
||||
if (auto cs = get_next_tactic_result())
|
||||
return cs;
|
||||
} catch (exception &) {}
|
||||
}
|
||||
return optional<constraints>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
||||
bool is_strict, optional<expr> const & type, tag g) {
|
||||
expr m = C->m_ctx.mk_meta(type, g);
|
||||
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 */) {
|
||||
expr const & mvar = get_app_fn(meta);
|
||||
if (auto cls_name_it = is_ext_class(C->tc(), meta_type)) {
|
||||
name cls_name = *cls_name_it;
|
||||
list<expr> const & ctx = C->m_ctx.get_data();
|
||||
list<expr> local_insts;
|
||||
if (C->use_local_instances())
|
||||
local_insts = get_local_instances(C->tc(), ctx, cls_name);
|
||||
list<name> insts = get_class_instances(env, cls_name);
|
||||
list<tactic_hint_entry> tacs;
|
||||
if (!s.is_assigned(mvar))
|
||||
tacs = get_tactic_hints(env, cls_name);
|
||||
if (empty(local_insts) && empty(insts) && empty(tacs))
|
||||
return lazy_list<constraints>(); // nothing to be done
|
||||
// we are always strict with placeholders associated with classes
|
||||
bool ignore_failure = false;
|
||||
return choose(std::make_shared<placeholder_elaborator>(C, meta, meta_type, local_insts, insts, tacs,
|
||||
j, ignore_failure));
|
||||
} else if (s.is_assigned(mvar)) {
|
||||
// if the metavariable is assigned and it is not a class, then we just ignore it, and return
|
||||
// the an empty set of constraints.
|
||||
return lazy_list<constraints>(constraints());
|
||||
} else {
|
||||
list<tactic_hint_entry> tacs = get_tactic_hints(env);
|
||||
bool ignore_failure = !is_strict;
|
||||
return choose(std::make_shared<placeholder_elaborator>(C, meta, meta_type, list<expr>(), list<name>(),
|
||||
tacs, j, ignore_failure));
|
||||
}
|
||||
};
|
||||
bool owner = false;
|
||||
bool relax = C->m_relax;
|
||||
constraint c = mk_choice_cnstr(m, choice_fn, to_delay_factor(cnstr_group::ClassInstance),
|
||||
owner, j, relax);
|
||||
return mk_pair(m, c);
|
||||
}
|
||||
|
||||
/** \brief Create a metavariable, and attach choice constraint for generating
|
||||
solutions using class-instances and tactic-hints.
|
||||
*/
|
||||
pair<expr, constraint> mk_placeholder_elaborator(
|
||||
environment const & env, io_state const & ios, list<expr> const & ctx,
|
||||
name const & prefix, bool relax, bool use_local_instances,
|
||||
bool is_strict, optional<expr> const & type, tag g) {
|
||||
auto C = std::make_shared<placeholder_context>(env, ios, ctx, prefix, relax, use_local_instances);
|
||||
return mk_placeholder_elaborator(C, is_strict, type, g);
|
||||
}
|
||||
}
|
30
src/frontends/lean/placeholder_elaborator.h
Normal file
30
src/frontends/lean/placeholder_elaborator.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "kernel/expr.h"
|
||||
#include "library/io_state.h"
|
||||
|
||||
namespace lean {
|
||||
/** \brief Create a metavariable, and attach choice constraint for generating
|
||||
solutions using class-instances and tactic-hints.
|
||||
|
||||
\param ctx Local context where placeholder is located
|
||||
\param prefix Prefix for metavariables that will be created by this procedure
|
||||
\param relax True if opaque constants in the current module should be treated
|
||||
as transparent
|
||||
\param use_local_instances If instances in the local context should be used
|
||||
in the class-instance resolution
|
||||
\param is_strict True if constraint should fail if not solution is found,
|
||||
False if empty solution should be returned if there is no solution
|
||||
\param type Expected type for the placeholder (if known)
|
||||
\param tag To be associated with new metavariables and expressions (for error localization).
|
||||
*/
|
||||
pair<expr, constraint> mk_placeholder_elaborator(
|
||||
environment const & env, io_state const & ios, list<expr> const & ctx,
|
||||
name const & prefix, bool relax_opaque, bool use_local_instances,
|
||||
bool is_strict, optional<expr> const & type, tag g);
|
||||
}
|
|
@ -9,6 +9,7 @@ Author: Leonardo de Moura
|
|||
#include "kernel/abstract.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/replace_fn.h"
|
||||
#include "kernel/for_each_fn.h"
|
||||
#include "library/scoped_ext.h"
|
||||
#include "library/locals.h"
|
||||
#include "library/explicit.h"
|
||||
|
@ -225,4 +226,14 @@ justification mk_failed_to_synthesize_jst(environment const & env, expr const &
|
|||
return format("failed to synthesize placeholder") + line() + ps.pp(fmt);
|
||||
});
|
||||
}
|
||||
|
||||
void collect_metavars(expr const & e, buffer<expr> & mvars) {
|
||||
for_each(e, [&](expr const & e, unsigned) {
|
||||
if (is_metavar(e)) {
|
||||
mvars.push_back(e);
|
||||
return false; /* do not visit its type */
|
||||
}
|
||||
return has_metavar(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@ Author: Leonardo de Moura
|
|||
#pragma once
|
||||
#include "kernel/expr.h"
|
||||
#include "kernel/expr_sets.h"
|
||||
#include "kernel/type_checker.h"
|
||||
#include "frontends/lean/local_decls.h"
|
||||
namespace lean {
|
||||
class parser;
|
||||
typedef std::unique_ptr<type_checker> type_checker_ptr;
|
||||
void check_atomic(name const & n);
|
||||
void check_in_section_or_context(parser const & p);
|
||||
bool is_root_namespace(name const & n);
|
||||
|
@ -47,4 +49,8 @@ expr instantiate_meta(expr const & meta, substitution & subst);
|
|||
/** \brief Return a 'failed to synthesize placholder' justification for the given
|
||||
metavariable application \c m of the form (?m l_1 ... l_k) */
|
||||
justification mk_failed_to_synthesize_jst(environment const & env, expr const & m);
|
||||
|
||||
/** \brief Copy the metavariables occurring in \c e to \c mvars,
|
||||
this procedure ignores metavariables occurring in the type of metavariables. */
|
||||
void collect_metavars(expr const & e, buffer<expr> & mvars);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue