feat(frontends/lean/elaborator): discard partial solution during
class-instance resolution, use only tactic_hints associated with classes, enforce is_strict
This commit is contained in:
parent
318fec43a4
commit
c775da16ec
4 changed files with 70 additions and 53 deletions
|
@ -351,7 +351,7 @@ public:
|
||||||
while (true) {
|
while (true) {
|
||||||
lean_assert(is_pi(type));
|
lean_assert(is_pi(type));
|
||||||
tag g = e.get_tag();
|
tag g = e.get_tag();
|
||||||
bool is_strict = false;
|
bool is_strict = true;
|
||||||
expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(type)), g, is_strict, cs);
|
expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(type)), g, is_strict, cs);
|
||||||
e = mk_app(e, imp_arg, g);
|
e = mk_app(e, imp_arg, g);
|
||||||
type = instantiate(binding_body(type), imp_arg);
|
type = instantiate(binding_body(type), imp_arg);
|
||||||
|
@ -556,7 +556,7 @@ public:
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while (binding_info(f_type).is_strict_implicit() || (!first && binding_info(f_type).is_implicit())) {
|
while (binding_info(f_type).is_strict_implicit() || (!first && binding_info(f_type).is_implicit())) {
|
||||||
tag g = f.get_tag();
|
tag g = f.get_tag();
|
||||||
bool is_strict = false;
|
bool is_strict = true;
|
||||||
expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(f_type)), g, is_strict, f_cs);
|
expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(f_type)), g, is_strict, f_cs);
|
||||||
f = mk_app(f, imp_arg, g);
|
f = mk_app(f, imp_arg, g);
|
||||||
auto f_t = ensure_fun(f, f_cs);
|
auto f_t = ensure_fun(f, f_cs);
|
||||||
|
@ -804,7 +804,7 @@ public:
|
||||||
tag g = e.get_tag();
|
tag g = e.get_tag();
|
||||||
expr r_type = whnf(infer_type(r, cs), cs);
|
expr r_type = whnf(infer_type(r, cs), cs);
|
||||||
expr imp_arg;
|
expr imp_arg;
|
||||||
bool is_strict = false;
|
bool is_strict = true;
|
||||||
while (is_pi(r_type) && binding_info(r_type).is_implicit()) {
|
while (is_pi(r_type) && binding_info(r_type).is_implicit()) {
|
||||||
imp_arg = mk_placeholder_meta(some_expr(binding_domain(r_type)), g, is_strict, cs);
|
imp_arg = mk_placeholder_meta(some_expr(binding_domain(r_type)), g, is_strict, cs);
|
||||||
r = mk_app(r, imp_arg, g);
|
r = mk_app(r, imp_arg, g);
|
||||||
|
|
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
||||||
#include "util/lazy_list_fn.h"
|
#include "util/lazy_list_fn.h"
|
||||||
#include "util/flet.h"
|
#include "util/flet.h"
|
||||||
#include "kernel/instantiate.h"
|
#include "kernel/instantiate.h"
|
||||||
|
#include "kernel/for_each_fn.h"
|
||||||
#include "kernel/abstract.h"
|
#include "kernel/abstract.h"
|
||||||
#include "library/unifier.h"
|
#include "library/unifier.h"
|
||||||
#include "library/reducible.h"
|
#include "library/reducible.h"
|
||||||
|
@ -44,7 +45,7 @@ struct placeholder_context {
|
||||||
};
|
};
|
||||||
|
|
||||||
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
||||||
bool is_strict, optional<expr> const & type, tag g);
|
optional<expr> const & type, tag g);
|
||||||
|
|
||||||
/** \brief Whenever the elaborator finds a placeholder '_' or introduces an
|
/** \brief Whenever the elaborator finds a placeholder '_' or introduces an
|
||||||
implicit argument, it creates a metavariable \c ?m. It also creates a
|
implicit argument, it creates a metavariable \c ?m. It also creates a
|
||||||
|
@ -86,8 +87,8 @@ struct placeholder_elaborator : public choice_iterator {
|
||||||
expr const & meta, expr const & meta_type,
|
expr const & meta, expr const & meta_type,
|
||||||
list<expr> const & local_insts, list<name> const & instances,
|
list<expr> const & local_insts, list<name> const & instances,
|
||||||
list<tactic_hint_entry> const & tacs,
|
list<tactic_hint_entry> const & tacs,
|
||||||
justification const & j, bool ignore_failure):
|
justification const & j):
|
||||||
choice_iterator(ignore_failure), m_C(C),
|
choice_iterator(), m_C(C),
|
||||||
m_meta(meta), m_meta_type(meta_type),
|
m_meta(meta), m_meta_type(meta_type),
|
||||||
m_local_instances(local_insts), m_instances(instances),
|
m_local_instances(local_insts), m_instances(instances),
|
||||||
m_tactics(tacs),
|
m_tactics(tacs),
|
||||||
|
@ -124,9 +125,7 @@ struct placeholder_elaborator : public choice_iterator {
|
||||||
type = tc.whnf(type).first;
|
type = tc.whnf(type).first;
|
||||||
if (!is_pi(type))
|
if (!is_pi(type))
|
||||||
break;
|
break;
|
||||||
bool is_strict = true;
|
pair<expr, constraint> ac = mk_placeholder_elaborator(m_C, some_expr(binding_domain(type)), g);
|
||||||
pair<expr, constraint> ac = mk_placeholder_elaborator(m_C, is_strict,
|
|
||||||
some_expr(binding_domain(type)), g);
|
|
||||||
expr arg = ac.first;
|
expr arg = ac.first;
|
||||||
cs.push_back(ac.second);
|
cs.push_back(ac.second);
|
||||||
r = mk_app(r, arg).set_tag(g);
|
r = mk_app(r, arg).set_tag(g);
|
||||||
|
@ -205,7 +204,7 @@ struct placeholder_elaborator : public choice_iterator {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
constraint mk_placeholder_cnstr(std::shared_ptr<placeholder_context> const & C, expr const & m, bool is_strict) {
|
constraint mk_placeholder_cnstr(std::shared_ptr<placeholder_context> const & C, expr const & m) {
|
||||||
environment const & env = C->env();
|
environment const & env = C->env();
|
||||||
justification j = mk_failed_to_synthesize_jst(env, m);
|
justification j = mk_failed_to_synthesize_jst(env, m);
|
||||||
auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
|
auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
|
||||||
|
@ -224,18 +223,10 @@ constraint mk_placeholder_cnstr(std::shared_ptr<placeholder_context> const & C,
|
||||||
if (empty(local_insts) && empty(insts) && empty(tacs))
|
if (empty(local_insts) && empty(insts) && empty(tacs))
|
||||||
return lazy_list<constraints>(); // nothing to be done
|
return lazy_list<constraints>(); // nothing to be done
|
||||||
// we are always strict with placeholders associated with classes
|
// 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));
|
||||||
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 {
|
} else {
|
||||||
list<tactic_hint_entry> tacs = get_tactic_hints(env);
|
// do nothing, type is not a class...
|
||||||
bool ignore_failure = !is_strict;
|
return lazy_list<constraints>(constraints());
|
||||||
return choose(std::make_shared<placeholder_elaborator>(C, meta, meta_type, list<expr>(), list<name>(),
|
|
||||||
tacs, j, ignore_failure));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bool owner = false;
|
bool owner = false;
|
||||||
|
@ -245,52 +236,82 @@ constraint mk_placeholder_cnstr(std::shared_ptr<placeholder_context> const & C,
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
pair<expr, constraint> mk_placeholder_elaborator(std::shared_ptr<placeholder_context> const & C,
|
||||||
bool is_strict, optional<expr> const & type, tag g) {
|
optional<expr> const & type, tag g) {
|
||||||
expr m = C->m_ctx.mk_meta(C->m_ngen, type, g);
|
expr m = C->m_ctx.mk_meta(C->m_ngen, type, g);
|
||||||
constraint c = mk_placeholder_cnstr(C, m, is_strict);
|
constraint c = mk_placeholder_cnstr(C, m);
|
||||||
return mk_pair(m, c);
|
return mk_pair(m, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Similar to has_expr_metavar, but ignores metavariables occurring in the type
|
||||||
|
of local constants */
|
||||||
|
static bool has_expr_metavar_relaxed(expr const & e) {
|
||||||
|
if (!has_expr_metavar(e))
|
||||||
|
return false;
|
||||||
|
bool found = false;
|
||||||
|
for_each(e, [&](expr const & e, unsigned) {
|
||||||
|
if (found || !has_expr_metavar(e))
|
||||||
|
return false;
|
||||||
|
if (is_metavar(e)) {
|
||||||
|
found = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (is_local(e))
|
||||||
|
return false; // do not visit type
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
constraint mk_placeholder_root_cnstr(std::shared_ptr<placeholder_context> const & C, expr const & m, bool is_strict,
|
constraint mk_placeholder_root_cnstr(std::shared_ptr<placeholder_context> const & C, expr const & m, bool is_strict,
|
||||||
unifier_config const & cfg, unsigned delay_factor) {
|
unifier_config const & cfg, unsigned delay_factor) {
|
||||||
environment const & env = C->env();
|
environment const & env = C->env();
|
||||||
justification j = mk_failed_to_synthesize_jst(env, m);
|
justification j = mk_failed_to_synthesize_jst(env, m);
|
||||||
auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
|
auto choice_fn = [=](expr const & meta, expr const & meta_type, substitution const & s,
|
||||||
name_generator const & ngen) {
|
name_generator const & ngen) {
|
||||||
if (has_expr_metavar(meta_type)) {
|
if (has_expr_metavar_relaxed(meta_type)) {
|
||||||
if (delay_factor < to_delay_factor(cnstr_group::ClassInstance)) {
|
if (delay_factor < to_delay_factor(cnstr_group::ClassInstance)) {
|
||||||
constraint delayed_c = mk_placeholder_root_cnstr(C, m, is_strict, cfg, delay_factor+1);
|
constraint delayed_c = mk_placeholder_root_cnstr(C, m, is_strict, cfg, delay_factor+1);
|
||||||
return lazy_list<constraints>(constraints(delayed_c));
|
return lazy_list<constraints>(constraints(delayed_c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr const & mvar = get_app_fn(meta);
|
if (!is_ext_class(C->tc(), meta_type)) {
|
||||||
if (!is_ext_class(C->tc(), meta_type) && s.is_assigned(mvar)) {
|
// do nothing, since type is not a class.
|
||||||
// see mk_placeholder_cnstr
|
|
||||||
return lazy_list<constraints>(constraints());
|
return lazy_list<constraints>(constraints());
|
||||||
}
|
}
|
||||||
pair<expr, justification> mj = update_meta(meta, s);
|
pair<expr, justification> mj = update_meta(meta, s);
|
||||||
expr new_meta = mj.first;
|
expr new_meta = mj.first;
|
||||||
justification new_j = mj.second;
|
justification new_j = mj.second;
|
||||||
constraint c = mk_placeholder_cnstr(C, new_meta, is_strict);
|
constraint c = mk_placeholder_cnstr(C, new_meta);
|
||||||
unifier_config new_cfg(cfg);
|
unifier_config new_cfg(cfg);
|
||||||
new_cfg.m_discard = false;
|
new_cfg.m_discard = false;
|
||||||
new_cfg.m_use_exceptions = false;
|
new_cfg.m_use_exceptions = false;
|
||||||
unify_result_seq seq = unify(env, 1, &c, ngen, new_cfg);
|
unify_result_seq seq1 = unify(env, 1, &c, ngen, new_cfg);
|
||||||
return map2<constraints>(seq, [=](pair<substitution, constraints> const & p) {
|
unify_result_seq seq2 = filter(seq1, [=](pair<substitution, constraints> const & p) {
|
||||||
substitution new_s = p.first;
|
substitution new_s = p.first;
|
||||||
if (!new_s.is_expr_assigned(mlocal_name(get_app_fn(new_meta))))
|
expr result = new_s.instantiate(new_meta);
|
||||||
return constraints();
|
// We only keep complete solution (modulo universe metavariables)
|
||||||
constraints postponed = map(p.second,
|
return !has_expr_metavar_relaxed(result);
|
||||||
[&](constraint const & c) {
|
|
||||||
// we erase internal justifications
|
|
||||||
return update_justification(c, 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);
|
|
||||||
});
|
});
|
||||||
|
lazy_list<constraints> seq3 = map2<constraints>(seq2, [=](pair<substitution, constraints> const & p) {
|
||||||
|
substitution new_s = p.first;
|
||||||
|
// some constraints may have been postponed (example: universe level constraints)
|
||||||
|
constraints postponed = map(p.second,
|
||||||
|
[&](constraint const & c) {
|
||||||
|
// we erase internal justifications
|
||||||
|
return update_justification(c, 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);
|
||||||
|
});
|
||||||
|
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()));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
bool owner = false;
|
bool owner = false;
|
||||||
bool relax = C->m_relax;
|
bool relax = C->m_relax;
|
||||||
|
|
|
@ -4,22 +4,15 @@ open tactic
|
||||||
inductive inh (A : Type) : Type :=
|
inductive inh (A : Type) : Type :=
|
||||||
intro : A -> inh A
|
intro : A -> inh A
|
||||||
|
|
||||||
instance inh.intro
|
|
||||||
|
|
||||||
theorem inh_bool [instance] : inh Prop
|
theorem inh_bool [instance] : inh Prop
|
||||||
:= inh.intro true
|
:= inh.intro true
|
||||||
|
|
||||||
theorem inh_fun [instance] {A B : Type} (H : inh B) : inh (A → B)
|
theorem inh_fun [instance] {A B : Type} (H : inh B) : inh (A → B)
|
||||||
:= inh.rec (λ b, inh.intro (λ a : A, b)) H
|
:= inh.rec (λ b, inh.intro (λ a : A, b)) H
|
||||||
|
|
||||||
definition assump := eassumption; now
|
|
||||||
|
|
||||||
set_option elaborator.local_instances false
|
|
||||||
tactic_hint [inh] assump
|
|
||||||
tactic_hint assump
|
|
||||||
|
|
||||||
theorem tst {A B : Type} (H : inh B) : inh (A → B → B)
|
theorem tst {A B : Type} (H : inh B) : inh (A → B → B)
|
||||||
|
|
||||||
theorem T1 {A : Type} (a : A) : inh A
|
theorem T1 {A : Type} (a : A) : inh A :=
|
||||||
|
by repeat [apply @inh.intro | eassumption]
|
||||||
|
|
||||||
theorem T2 : inh Prop
|
theorem T2 : inh Prop
|
||||||
|
|
|
@ -9,7 +9,7 @@ instance inh.intro
|
||||||
theorem inh_elim {A : Type} {B : Prop} (H1 : inh A) (H2 : A → B) : B
|
theorem inh_elim {A : Type} {B : Prop} (H1 : inh A) (H2 : A → B) : B
|
||||||
:= inh.rec H2 H1
|
:= inh.rec H2 H1
|
||||||
|
|
||||||
theorem inh_exists [instance] {A : Type} {P : A → Prop} (H : ∃x, P x) : inh A
|
theorem inh_exists {A : Type} {P : A → Prop} (H : ∃x, P x) : inh A
|
||||||
:= obtain w Hw, from H, inh.intro w
|
:= obtain w Hw, from H, inh.intro w
|
||||||
|
|
||||||
theorem inh_bool [instance] : inh Prop
|
theorem inh_bool [instance] : inh Prop
|
||||||
|
@ -26,7 +26,10 @@ tactic_hint assump
|
||||||
|
|
||||||
theorem tst {A B : Type} (H : inh B) : inh (A → B → B)
|
theorem tst {A B : Type} (H : inh B) : inh (A → B → B)
|
||||||
|
|
||||||
theorem T1 {A B C D : Type} {P : C → Prop} (a : A) (H1 : inh B) (H2 : ∃x, P x) : inh ((A → A) × B × (D → C) × Prop)
|
theorem T1 {A B C D : Type} {P : C → Prop} (a : A) (H1 : inh B) (H2 : ∃x, P x) : inh ((A → A) × B × (D → C) × Prop) :=
|
||||||
|
have h1 [visible] : inh A, from inh.intro a,
|
||||||
|
have h2 [visible] : inh C, from inh_exists H2,
|
||||||
|
_
|
||||||
|
|
||||||
(*
|
(*
|
||||||
print(get_env():find("T1"):value())
|
print(get_env():find("T1"):value())
|
||||||
|
|
Loading…
Reference in a new issue