feat(frontends/lean/coercion_elaborator): implement "coercion lifting"
closes #644
This commit is contained in:
parent
b76445df39
commit
ea9c810fca
4 changed files with 82 additions and 13 deletions
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
||||||
#include "kernel/type_checker.h"
|
#include "kernel/type_checker.h"
|
||||||
#include "kernel/metavar.h"
|
#include "kernel/metavar.h"
|
||||||
#include "kernel/constraint.h"
|
#include "kernel/constraint.h"
|
||||||
|
#include "kernel/abstract.h"
|
||||||
#include "library/coercion.h"
|
#include "library/coercion.h"
|
||||||
#include "library/unifier.h"
|
#include "library/unifier.h"
|
||||||
#include "library/choice_iterator.h"
|
#include "library/choice_iterator.h"
|
||||||
|
@ -21,23 +22,45 @@ coercion_elaborator::coercion_elaborator(coercion_info_manager & info, expr cons
|
||||||
lean_assert(use_id || length(m_coercions) == length(m_choices));
|
lean_assert(use_id || length(m_coercions) == length(m_choices));
|
||||||
}
|
}
|
||||||
|
|
||||||
list<expr> get_coercions_from_to(type_checker & /* from_tc */, type_checker & to_tc,
|
list<expr> get_coercions_from_to(type_checker & from_tc, type_checker & to_tc,
|
||||||
expr const & from_type, expr const & to_type, constraint_seq & cs) {
|
expr const & from_type, expr const & to_type, constraint_seq & cs) {
|
||||||
constraint_seq new_cs;
|
constraint_seq new_cs;
|
||||||
environment const & env = to_tc.env();
|
environment const & env = to_tc.env();
|
||||||
expr whnf_to_type = to_tc.whnf(to_type, new_cs);
|
expr whnf_from_type = from_tc.whnf(from_type, new_cs);
|
||||||
expr const & fn = get_app_fn(whnf_to_type);
|
expr whnf_to_type = to_tc.whnf(to_type, new_cs);
|
||||||
list<expr> r;
|
if (is_arrow(whnf_from_type)) {
|
||||||
if (is_constant(fn)) {
|
// Try to lift coercions.
|
||||||
r = get_coercions(env, from_type, const_name(fn));
|
// The idea is to convert a coercion from A to B, into a coercion from D->A to D->B
|
||||||
} else if (is_pi(whnf_to_type)) {
|
if (!is_arrow(whnf_to_type))
|
||||||
r = get_coercions_to_fun(env, from_type);
|
return list<expr>(); // failed
|
||||||
} else if (is_sort(whnf_to_type)) {
|
if (!from_tc.is_def_eq(binding_domain(whnf_from_type), binding_domain(whnf_to_type), justification(), new_cs))
|
||||||
r = get_coercions_to_sort(env, from_type);
|
return list<expr>(); // failed, the domains must be definitionally equal
|
||||||
|
list<expr> coe = get_coercions_from_to(from_tc, to_tc, binding_body(whnf_from_type), binding_body(whnf_to_type), new_cs);
|
||||||
|
if (coe) {
|
||||||
|
cs += new_cs;
|
||||||
|
// Remark: each coercion c in coe is a function from A to B
|
||||||
|
// We create a new list: (fun (f : D -> A) (x : D), c (f x))
|
||||||
|
expr f = mk_local(from_tc.mk_fresh_name(), "f", whnf_from_type, binder_info());
|
||||||
|
expr x = mk_local(from_tc.mk_fresh_name(), "x", binding_domain(whnf_from_type), binder_info());
|
||||||
|
expr fx = mk_app(f, x);
|
||||||
|
return map(coe, [&](expr const & c) { return Fun(f, Fun(x, mk_app(c, fx))); });
|
||||||
|
} else {
|
||||||
|
return list<expr>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expr const & fn = get_app_fn(whnf_to_type);
|
||||||
|
list<expr> r;
|
||||||
|
if (is_constant(fn)) {
|
||||||
|
r = get_coercions(env, whnf_from_type, const_name(fn));
|
||||||
|
} else if (is_pi(whnf_to_type)) {
|
||||||
|
r = get_coercions_to_fun(env, whnf_from_type);
|
||||||
|
} else if (is_sort(whnf_to_type)) {
|
||||||
|
r = get_coercions_to_sort(env, whnf_from_type);
|
||||||
|
}
|
||||||
|
if (r)
|
||||||
|
cs += new_cs;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
if (r)
|
|
||||||
cs += new_cs;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<constraints> coercion_elaborator::next() {
|
optional<constraints> coercion_elaborator::next() {
|
||||||
|
|
|
@ -481,6 +481,10 @@ pair<expr, expr> elaborator::ensure_fun(expr f, constraint_seq & cs) {
|
||||||
bool elaborator::has_coercions_from(expr const & a_type) {
|
bool elaborator::has_coercions_from(expr const & a_type) {
|
||||||
try {
|
try {
|
||||||
expr a_cls = get_app_fn(m_coercion_from_tc->whnf(a_type).first);
|
expr a_cls = get_app_fn(m_coercion_from_tc->whnf(a_type).first);
|
||||||
|
while (is_pi(a_cls)) {
|
||||||
|
expr local = mk_local(binding_name(a_cls), binding_domain(a_cls), binding_info(a_cls));
|
||||||
|
a_cls = get_app_fn(m_coercion_from_tc->whnf(instantiate(binding_body(a_cls), local)).first);
|
||||||
|
}
|
||||||
return is_constant(a_cls) && ::lean::has_coercions_from(env(), const_name(a_cls));
|
return is_constant(a_cls) && ::lean::has_coercions_from(env(), const_name(a_cls));
|
||||||
} catch (exception&) {
|
} catch (exception&) {
|
||||||
return false;
|
return false;
|
||||||
|
|
38
tests/lean/644.lean
Normal file
38
tests/lean/644.lean
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import data.list
|
||||||
|
|
||||||
|
constant A : Type₁
|
||||||
|
constant B : Type₁
|
||||||
|
constant coe : A → B
|
||||||
|
attribute coe [coercion]
|
||||||
|
variable f : B → B
|
||||||
|
variable a : A
|
||||||
|
set_option pp.coercions true
|
||||||
|
check f a
|
||||||
|
|
||||||
|
constant C : Type₁
|
||||||
|
variable g : (C → B) → B
|
||||||
|
variable h : C → A
|
||||||
|
check g h
|
||||||
|
|
||||||
|
definition tst (g : C → B) : Prop := g = h
|
||||||
|
|
||||||
|
open bool list
|
||||||
|
|
||||||
|
definition bool_to_Prop [coercion] [reducible] (b : bool) : Prop := b = tt
|
||||||
|
|
||||||
|
definition bpred_dec [instance] {A : Type} (p : A → bool) : ∀ a, decidable (p a = tt) :=
|
||||||
|
begin
|
||||||
|
intro a,
|
||||||
|
eapply (bool.rec_on (p a)),
|
||||||
|
right, contradiction,
|
||||||
|
left, reflexivity
|
||||||
|
end
|
||||||
|
|
||||||
|
definition negb : bool → bool := bool.rec tt ff
|
||||||
|
|
||||||
|
check filter negb [tt, ff, tt, ff]
|
||||||
|
|
||||||
|
eval filter negb [tt, ff, tt, ff]
|
||||||
|
|
||||||
|
example : filter negb [tt, ff, tt, ff] = [ff, ff] :=
|
||||||
|
rfl
|
4
tests/lean/644.lean.expected.out
Normal file
4
tests/lean/644.lean.expected.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
f (coe a) : B
|
||||||
|
g (λ (x : C), coe (h x)) : B
|
||||||
|
filter (λ (x : bool), bool_to_Prop (negb x)) [tt, ff, tt, ff] : list bool
|
||||||
|
[ff, ff]
|
Loading…
Reference in a new issue