diff --git a/src/frontends/lean/elaborator.cpp b/src/frontends/lean/elaborator.cpp index fceda5e2fa..ef3a49254c 100644 --- a/src/frontends/lean/elaborator.cpp +++ b/src/frontends/lean/elaborator.cpp @@ -336,6 +336,35 @@ public: return mc.first; } + static bool is_implicit_pi(expr const & e) { + if (!is_pi(e)) + return false; + binder_info bi = binding_info(e); + return bi.is_strict_implicit() || bi.is_implicit(); + } + + expr add_implict_args(expr e, constraint_seq & cs, bool relax) { + type_checker & tc = *m_tc[relax]; + constraint_seq new_cs; + expr type = tc.whnf(tc.infer(e, new_cs), new_cs); + if (!is_implicit_pi(type)) + return e; + cs += new_cs; + while (true) { + lean_assert(is_pi(type)); + tag g = e.get_tag(); + bool is_strict = false; + expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(type)), g, is_strict, cs); + e = mk_app(e, imp_arg, g); + type = instantiate(binding_body(type), imp_arg); + constraint_seq new_cs; + type = tc.whnf(type, new_cs); + if (!is_implicit_pi(type)) + return e; + cs += new_cs; + } + } + /** \brief Make sure \c f is really a function, if it is not, try to apply coercions. The result is a pair new_f, f_type, where new_f is the new value for \c f, and \c f_type is its type (and a Pi-expression) @@ -362,7 +391,9 @@ public: throw_kernel_exception(env(), f, [=](formatter const & fmt) { return pp_function_expected(fmt, f); }); } else if (is_nil(tail(coes))) { expr old_f = f; + bool relax = m_relax_main_opaque; f = mk_app(head(coes), f, f.get_tag()); + f = add_implict_args(f, cs, relax); f_type = infer_type(f, cs); save_coercion_info(old_f, f); lean_assert(is_pi(f_type)); @@ -375,18 +406,7 @@ public: list choices = map2(coes, [&](expr const & coe) { expr new_f = copy_tag(f, ::lean::mk_app(coe, f)); constraint_seq cs; - while (true) { - expr new_f_type = m_tc[relax]->infer(new_f, cs); - if (!is_pi(new_f_type)) - break; - binder_info bi = binding_info(new_f_type); - if (!bi.is_strict_implicit() && !bi.is_implicit()) - break; - tag g = f.get_tag(); - bool is_strict = false; - expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(new_f_type)), g, is_strict, cs); - new_f = mk_app(new_f, imp_arg, g); - } + new_f = add_implict_args(new_f, cs, relax); cs += mk_eq_cnstr(meta, new_f, j, relax); return cs.to_list(); }); diff --git a/tests/lean/run/coe12.lean b/tests/lean/run/coe12.lean new file mode 100644 index 0000000000..5a81051a9c --- /dev/null +++ b/tests/lean/run/coe12.lean @@ -0,0 +1,10 @@ +import data.nat +inductive foo (A B : Type) : Type := +mk : (Π {C : Type}, A → C → B) → foo A B + +definition to_fun [coercion] {A B : Type} (f : foo A B) : Π {C : Type}, A → C → B := +foo.rec (λf, f) f + +variable f : foo nat nat +variable a : nat +check f a true