2014-06-24 21:55:06 +00:00
|
|
|
/*
|
|
|
|
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 <utility>
|
|
|
|
#include <vector>
|
|
|
|
#include "util/flet.h"
|
|
|
|
#include "util/list_fn.h"
|
2014-06-25 15:30:09 +00:00
|
|
|
#include "util/lazy_list_fn.h"
|
2014-06-24 21:55:06 +00:00
|
|
|
#include "util/sstream.h"
|
2014-07-02 03:43:53 +00:00
|
|
|
#include "util/name_map.h"
|
2014-06-24 21:55:06 +00:00
|
|
|
#include "kernel/abstract.h"
|
|
|
|
#include "kernel/instantiate.h"
|
|
|
|
#include "kernel/type_checker.h"
|
2014-06-29 16:47:25 +00:00
|
|
|
#include "kernel/for_each_fn.h"
|
2014-07-06 23:46:34 +00:00
|
|
|
#include "kernel/replace_fn.h"
|
2014-06-24 21:55:06 +00:00
|
|
|
#include "kernel/kernel_exception.h"
|
|
|
|
#include "kernel/error_msgs.h"
|
|
|
|
#include "kernel/expr_maps.h"
|
|
|
|
#include "library/coercion.h"
|
|
|
|
#include "library/placeholder.h"
|
|
|
|
#include "library/choice.h"
|
|
|
|
#include "library/explicit.h"
|
|
|
|
#include "library/unifier.h"
|
2014-07-06 01:58:20 +00:00
|
|
|
#include "library/opaque_hints.h"
|
2014-07-06 23:46:34 +00:00
|
|
|
#include "library/locals.h"
|
2014-08-29 16:58:11 +00:00
|
|
|
#include "library/let.h"
|
2014-08-01 02:54:21 +00:00
|
|
|
#include "library/deep_copy.h"
|
2014-09-11 16:58:44 +00:00
|
|
|
#include "library/metavar_closure.h"
|
2014-08-22 18:26:00 +00:00
|
|
|
#include "library/typed_expr.h"
|
2014-06-29 16:47:25 +00:00
|
|
|
#include "library/tactic/tactic.h"
|
2014-07-02 03:43:53 +00:00
|
|
|
#include "library/tactic/expr_to_tactic.h"
|
2014-06-29 16:47:25 +00:00
|
|
|
#include "library/error_handling/error_handling.h"
|
2014-07-06 23:46:34 +00:00
|
|
|
#include "frontends/lean/local_decls.h"
|
2014-07-04 22:45:50 +00:00
|
|
|
#include "frontends/lean/class.h"
|
2014-09-10 17:24:35 +00:00
|
|
|
#include "frontends/lean/util.h"
|
2014-07-08 21:28:33 +00:00
|
|
|
#include "frontends/lean/tactic_hint.h"
|
2014-08-07 02:35:26 +00:00
|
|
|
#include "frontends/lean/info_manager.h"
|
2014-08-13 01:43:56 +00:00
|
|
|
#include "frontends/lean/elaborator.h"
|
2014-09-04 16:59:24 +00:00
|
|
|
#include "frontends/lean/no_info.h"
|
2014-09-04 16:56:27 +00:00
|
|
|
#include "frontends/lean/extra_info.h"
|
2014-09-10 17:24:35 +00:00
|
|
|
#include "frontends/lean/local_context.h"
|
2014-09-10 18:19:14 +00:00
|
|
|
#include "frontends/lean/choice_iterator.h"
|
2014-09-10 22:20:45 +00:00
|
|
|
#include "frontends/lean/placeholder_elaborator.h"
|
2014-09-10 23:07:41 +00:00
|
|
|
#include "frontends/lean/coercion_elaborator.h"
|
2014-06-24 21:55:06 +00:00
|
|
|
|
2014-07-05 01:03:13 +00:00
|
|
|
#ifndef LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES
|
|
|
|
#define LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES true
|
|
|
|
#endif
|
|
|
|
|
2014-06-24 21:55:06 +00:00
|
|
|
namespace lean {
|
2014-07-05 01:03:13 +00:00
|
|
|
// ==========================================
|
|
|
|
// elaborator configuration options
|
2014-07-13 13:03:47 +00:00
|
|
|
static name g_elaborator_local_instances{"elaborator", "local_instances"};
|
2014-07-05 01:03:13 +00:00
|
|
|
RegisterBoolOption(g_elaborator_local_instances, LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES, "(lean elaborator) use local declarates as class instances");
|
|
|
|
bool get_elaborator_local_instances(options const & opts) {
|
|
|
|
return opts.get_bool(g_elaborator_local_instances, LEAN_DEFAULT_ELABORATOR_LOCAL_INSTANCES);
|
|
|
|
}
|
|
|
|
// ==========================================
|
|
|
|
|
2014-08-13 19:45:57 +00:00
|
|
|
elaborator_context::elaborator_context(environment const & env, io_state const & ios, local_decls<level> const & lls,
|
|
|
|
pos_info_provider const * pp, info_manager * info, bool check_unassigned):
|
2014-08-13 01:43:56 +00:00
|
|
|
m_env(env), m_ios(ios), m_lls(lls), m_pos_provider(pp), m_info_manager(info), m_check_unassigned(check_unassigned) {
|
|
|
|
m_use_local_instances = get_elaborator_local_instances(ios.get_options());
|
|
|
|
}
|
|
|
|
|
2014-07-06 23:46:34 +00:00
|
|
|
/** \brief Helper class for implementing the \c elaborate functions. */
|
2014-09-10 23:07:41 +00:00
|
|
|
class elaborator : public coercion_info_manager {
|
2014-07-08 21:28:33 +00:00
|
|
|
typedef name_map<expr> local_tactic_hints;
|
2014-08-28 23:27:52 +00:00
|
|
|
typedef rb_map<expr, pair<expr, constraint_seq>, expr_quick_cmp> cache;
|
2014-06-24 21:55:06 +00:00
|
|
|
|
2014-08-13 19:45:57 +00:00
|
|
|
elaborator_context & m_env;
|
|
|
|
name_generator m_ngen;
|
|
|
|
type_checker_ptr m_tc[2];
|
2014-09-10 17:24:35 +00:00
|
|
|
// mapping from metavariable ?m to the (?m l_1 ... l_n) where [l_1 ... l_n] are the local constants
|
|
|
|
// representing the context where ?m was created.
|
|
|
|
local_context m_context; // current local context: a list of local constants
|
|
|
|
local_context m_full_context; // superset of m_context, it also contains non-contextual locals.
|
2014-08-28 23:27:52 +00:00
|
|
|
cache m_cache;
|
2014-08-05 23:25:54 +00:00
|
|
|
|
2014-09-10 17:24:35 +00:00
|
|
|
// mapping from metavariable name ?m to tactic expression that should be used to solve it.
|
|
|
|
// this mapping is populated by the 'by tactic-expr' expression.
|
|
|
|
local_tactic_hints m_local_tactic_hints;
|
|
|
|
// set of metavariables that we already reported unsolved/unassigned
|
|
|
|
name_set m_displayed_errors;
|
|
|
|
// if m_relax_main_opaque is true, then treat opaque definitions from the main module as transparent.
|
|
|
|
bool m_relax_main_opaque;
|
|
|
|
// if m_no_info is true, we do not collect information when true,
|
|
|
|
// we set is to true whenever we find no_info annotation.
|
|
|
|
bool m_no_info;
|
2014-08-17 19:14:42 +00:00
|
|
|
info_manager m_pre_info_data;
|
2014-06-24 21:55:06 +00:00
|
|
|
|
2014-08-28 23:27:52 +00:00
|
|
|
// Auxiliary object to "saving" elaborator state
|
|
|
|
struct saved_state {
|
|
|
|
list<expr> m_ctx;
|
|
|
|
list<expr> m_full_ctx;
|
|
|
|
cache m_cache;
|
|
|
|
saved_state(elaborator & e):
|
|
|
|
m_ctx(e.m_context.get_data()), m_full_ctx(e.m_full_context.get_data()), m_cache(e.m_cache) {}
|
|
|
|
};
|
|
|
|
|
2014-08-05 23:25:54 +00:00
|
|
|
struct scope_ctx {
|
2014-09-10 17:24:35 +00:00
|
|
|
elaborator & m_main;
|
|
|
|
local_context::scope m_scope1;
|
|
|
|
local_context::scope m_scope2;
|
|
|
|
cache m_old_cache;
|
2014-08-28 23:27:52 +00:00
|
|
|
scope_ctx(elaborator & e):m_main(e), m_scope1(e.m_context), m_scope2(e.m_full_context), m_old_cache(e.m_cache) {}
|
|
|
|
~scope_ctx() { m_main.m_cache = m_old_cache; }
|
2014-08-05 23:25:54 +00:00
|
|
|
};
|
2014-07-12 16:49:14 +00:00
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
/** \brief Auxiliary object for creating backtracking points, and replacing the local scopes. */
|
2014-08-05 23:25:54 +00:00
|
|
|
struct new_scope {
|
2014-09-10 17:24:35 +00:00
|
|
|
elaborator & m_main;
|
|
|
|
bool m_old_no_info;
|
|
|
|
local_context::scope_replace m_context_scope;
|
|
|
|
local_context::scope_replace m_full_context_scope;
|
|
|
|
cache m_old_cache;
|
2014-09-04 16:59:24 +00:00
|
|
|
new_scope(elaborator & e, saved_state const & s, bool no_info = false):
|
2014-08-28 23:27:52 +00:00
|
|
|
m_main(e),
|
|
|
|
m_context_scope(e.m_context, s.m_ctx),
|
|
|
|
m_full_context_scope(e.m_full_context, s.m_full_ctx){
|
2014-09-04 16:59:24 +00:00
|
|
|
m_old_no_info = m_main.m_no_info;
|
|
|
|
m_main.m_no_info = no_info;
|
2014-08-28 23:27:52 +00:00
|
|
|
m_old_cache = m_main.m_cache;
|
|
|
|
m_main.m_cache = s.m_cache;
|
2014-08-23 00:07:12 +00:00
|
|
|
}
|
|
|
|
~new_scope() {
|
2014-09-04 16:59:24 +00:00
|
|
|
m_main.m_no_info = m_old_no_info;
|
2014-08-28 23:27:52 +00:00
|
|
|
m_main.m_cache = m_old_cache;
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-07-06 23:46:34 +00:00
|
|
|
/** \brief 'Choice' expressions <tt>(choice e_1 ... e_n)</tt> are mapped into a metavariable \c ?m
|
|
|
|
and a choice constraints <tt>(?m in fn)</tt> where \c fn is a choice function.
|
|
|
|
The choice function produces a stream of alternatives. In this case, it produces a stream of
|
|
|
|
size \c n, one alternative for each \c e_i.
|
|
|
|
This is a helper class for implementing this choice functions.
|
|
|
|
*/
|
2014-09-10 18:19:14 +00:00
|
|
|
struct choice_expr_elaborator : public choice_iterator {
|
2014-06-25 15:30:09 +00:00
|
|
|
elaborator & m_elab;
|
2014-07-04 19:47:33 +00:00
|
|
|
expr m_mvar;
|
2014-06-25 15:30:09 +00:00
|
|
|
expr m_choice;
|
2014-08-28 23:27:52 +00:00
|
|
|
saved_state m_state;
|
2014-06-25 15:30:09 +00:00
|
|
|
unsigned m_idx;
|
2014-07-27 19:01:06 +00:00
|
|
|
bool m_relax_main_opaque;
|
2014-08-05 23:46:43 +00:00
|
|
|
choice_expr_elaborator(elaborator & elab, expr const & mvar, expr const & c,
|
2014-08-28 23:27:52 +00:00
|
|
|
saved_state const & s, bool relax):
|
|
|
|
m_elab(elab), m_mvar(mvar), m_choice(c), m_state(s),
|
2014-08-19 01:24:08 +00:00
|
|
|
m_idx(get_num_choices(m_choice)), m_relax_main_opaque(relax) {
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-07-04 22:45:50 +00:00
|
|
|
virtual optional<constraints> next() {
|
2014-08-19 01:24:08 +00:00
|
|
|
while (m_idx > 0) {
|
|
|
|
--m_idx;
|
2014-06-25 15:30:09 +00:00
|
|
|
expr const & c = get_choice(m_choice, m_idx);
|
2014-08-17 22:18:22 +00:00
|
|
|
expr const & f = get_app_fn(c);
|
|
|
|
m_elab.save_identifier_info(f);
|
2014-06-25 15:30:09 +00:00
|
|
|
try {
|
2014-08-28 23:27:52 +00:00
|
|
|
new_scope s(m_elab, m_state);
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, constraint_seq> rcs = m_elab.visit(c);
|
|
|
|
expr r = rcs.first;
|
|
|
|
constraint_seq cs = mk_eq_cnstr(m_mvar, r, justification(), m_relax_main_opaque) + rcs.second;
|
|
|
|
return optional<constraints>(cs.to_list());
|
2014-06-25 15:30:09 +00:00
|
|
|
} catch (exception &) {}
|
|
|
|
}
|
2014-07-04 19:47:33 +00:00
|
|
|
return optional<constraints>();
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2014-08-13 19:45:57 +00:00
|
|
|
elaborator(elaborator_context & env, list<expr> const & ctx, name_generator const & ngen):
|
2014-08-13 01:43:56 +00:00
|
|
|
m_env(env),
|
2014-07-27 19:01:06 +00:00
|
|
|
m_ngen(ngen),
|
2014-09-10 19:49:35 +00:00
|
|
|
m_context(m_ngen.next(), ctx),
|
|
|
|
m_full_context(m_ngen.next(), ctx) {
|
2014-07-27 19:01:06 +00:00
|
|
|
m_relax_main_opaque = false;
|
2014-09-04 16:59:24 +00:00
|
|
|
m_no_info = false;
|
2014-08-15 23:37:24 +00:00
|
|
|
m_tc[0] = mk_type_checker_with_hints(env.m_env, m_ngen.mk_child(), false);
|
|
|
|
m_tc[1] = mk_type_checker_with_hints(env.m_env, m_ngen.mk_child(), true);
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-08-13 01:43:56 +00:00
|
|
|
environment const & env() const { return m_env.m_env; }
|
|
|
|
io_state const & ios() const { return m_env.m_ios; }
|
|
|
|
local_decls<level> const & lls() const { return m_env.m_lls; }
|
|
|
|
bool use_local_instances() const { return m_env.m_use_local_instances; }
|
|
|
|
info_manager * infom() const { return m_env.m_info_manager; }
|
|
|
|
pos_info_provider const * pip() const { return m_env.m_pos_provider; }
|
|
|
|
bool check_unassigned() const { return m_env.m_check_unassigned; }
|
|
|
|
|
2014-06-30 16:14:55 +00:00
|
|
|
expr mk_local(name const & n, expr const & t, binder_info const & bi) {
|
|
|
|
return ::lean::mk_local(m_ngen.next(), n, t, bi);
|
2014-06-25 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, constraint_seq> infer_type(expr const & e) { return m_tc[m_relax_main_opaque]->infer(e); }
|
|
|
|
pair<expr, constraint_seq> whnf(expr const & e) { return m_tc[m_relax_main_opaque]->whnf(e); }
|
|
|
|
expr infer_type(expr const & e, constraint_seq & s) { return m_tc[m_relax_main_opaque]->infer(e, s); }
|
|
|
|
expr whnf(expr const & e, constraint_seq & s) { return m_tc[m_relax_main_opaque]->whnf(e, s); }
|
2014-09-10 17:24:35 +00:00
|
|
|
expr mk_app(expr const & f, expr const & a, tag g) { return ::lean::mk_app(f, a).set_tag(g); }
|
2014-06-25 18:04:50 +00:00
|
|
|
|
2014-09-10 19:49:35 +00:00
|
|
|
/** \brief Convert the metavariable to the metavariable application that captures
|
|
|
|
the context where it was defined.
|
|
|
|
*/
|
|
|
|
optional<expr> mvar_to_meta(expr const & mvar) {
|
|
|
|
lean_assert(is_metavar(mvar));
|
|
|
|
name const & m = mlocal_name(mvar);
|
|
|
|
if (auto it = m_context.find_meta(m))
|
|
|
|
return it;
|
|
|
|
else
|
|
|
|
return m_full_context.find_meta(m);
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
/** \brief Store the pair (pos(e), type(r)) in the info_data if m_info_manager is available. */
|
2014-09-03 18:52:35 +00:00
|
|
|
void save_type_data(expr const & e, expr const & r) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip() && (is_constant(e) || is_local(e) || is_placeholder(e))) {
|
2014-08-20 05:31:26 +00:00
|
|
|
if (auto p = pip()->get_pos_info(e)) {
|
|
|
|
expr t = m_tc[m_relax_main_opaque]->infer(r).first;
|
|
|
|
m_pre_info_data.add_type_info(p->first, p->second, t);
|
|
|
|
}
|
|
|
|
}
|
2014-06-25 18:04:50 +00:00
|
|
|
}
|
2014-06-25 15:30:09 +00:00
|
|
|
|
2014-09-03 18:52:35 +00:00
|
|
|
/** \brief Store type information at pos(e) for r if \c e is marked as "extra" in the info_manager */
|
|
|
|
void save_extra_type_data(expr const & e, expr const & r) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip()) {
|
2014-09-03 18:52:35 +00:00
|
|
|
if (auto p = pip()->get_pos_info(e)) {
|
|
|
|
expr t = m_tc[m_relax_main_opaque]->infer(r).first;
|
|
|
|
m_pre_info_data.add_extra_type_info(p->first, p->second, r, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
/** \brief Auxiliary function for saving information about which overloaded identifier was used by the elaborator. */
|
|
|
|
void save_identifier_info(expr const & f) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip() && is_constant(f)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
if (auto p = pip()->get_pos_info(f))
|
|
|
|
m_pre_info_data.add_identifier_info(p->first, p->second, const_name(f));
|
|
|
|
}
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
/** \brief Store actual term that was synthesized for an explicit placeholders */
|
|
|
|
void save_synth_data(expr const & e, expr const & r) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip() && is_placeholder(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
if (auto p = pip()->get_pos_info(e))
|
|
|
|
m_pre_info_data.add_synth_info(p->first, p->second, r);
|
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
void save_placeholder_info(expr const & e, expr const & r) {
|
|
|
|
if (is_explicit_placeholder(e)) {
|
2014-09-03 18:52:35 +00:00
|
|
|
save_type_data(e, r);
|
2014-08-20 05:31:26 +00:00
|
|
|
save_synth_data(e, r);
|
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-09-03 01:39:06 +00:00
|
|
|
/** \brief Auxiliary function for saving information about which coercion was used by the elaborator.
|
|
|
|
It marks that coercion c was used on e.
|
|
|
|
*/
|
2014-09-10 23:07:41 +00:00
|
|
|
virtual void save_coercion_info(expr const & e, expr const & c) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip()) {
|
2014-09-03 16:34:13 +00:00
|
|
|
if (auto p = pip()->get_pos_info(e)) {
|
|
|
|
expr t = m_tc[m_relax_main_opaque]->infer(c).first;
|
|
|
|
m_pre_info_data.add_coercion_info(p->first, p->second, c, t);
|
|
|
|
}
|
2014-09-03 01:39:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Remove coercion information associated with \c e */
|
2014-09-10 23:07:41 +00:00
|
|
|
virtual void erase_coercion_info(expr const & e) {
|
2014-09-04 16:59:24 +00:00
|
|
|
if (!m_no_info && infom() && pip()) {
|
2014-09-03 01:39:06 +00:00
|
|
|
if (auto p = pip()->get_pos_info(e))
|
|
|
|
m_pre_info_data.erase_coercion_info(p->first, p->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
void copy_info_to_manager(substitution s) {
|
|
|
|
if (!infom())
|
|
|
|
return;
|
|
|
|
m_pre_info_data.instantiate(s);
|
2014-08-27 01:06:37 +00:00
|
|
|
bool overwrite = true;
|
|
|
|
infom()->merge(m_pre_info_data, overwrite);
|
2014-08-20 05:31:26 +00:00
|
|
|
m_pre_info_data.clear();
|
2014-07-12 16:49:14 +00:00
|
|
|
}
|
|
|
|
|
2014-07-14 01:53:02 +00:00
|
|
|
/** \brief Create a metavariable, and attach choice constraint for generating
|
|
|
|
solutions using class-instances and tactic-hints.
|
2014-07-04 22:45:50 +00:00
|
|
|
*/
|
2014-08-20 05:31:26 +00:00
|
|
|
expr mk_placeholder_meta(optional<expr> const & type, tag g, bool is_strict, constraint_seq & cs) {
|
2014-09-10 22:20:45 +00:00
|
|
|
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;
|
2014-07-04 22:45:50 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_expecting_type(expr const & e, constraint_seq & cs) {
|
2014-08-14 15:49:43 +00:00
|
|
|
if (is_placeholder(e) && !placeholder_type(e)) {
|
|
|
|
expr r = m_context.mk_type_meta(e.get_tag());
|
2014-08-15 19:45:54 +00:00
|
|
|
save_placeholder_info(e, r);
|
2014-08-14 15:49:43 +00:00
|
|
|
return r;
|
|
|
|
} else {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit(e, cs);
|
2014-08-14 15:49:43 +00:00
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_expecting_type_of(expr const & e, expr const & t, constraint_seq & cs) {
|
2014-08-14 15:49:43 +00:00
|
|
|
if (is_placeholder(e) && !placeholder_type(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
expr r = mk_placeholder_meta(some_expr(t), e.get_tag(), is_strict_placeholder(e), cs);
|
2014-08-15 19:45:54 +00:00
|
|
|
save_placeholder_info(e, r);
|
2014-08-14 15:49:43 +00:00
|
|
|
return r;
|
|
|
|
} else if (is_choice(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_choice(e, some_expr(t), cs);
|
2014-08-14 15:49:43 +00:00
|
|
|
} else if (is_by(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_by(e, some_expr(t), cs);
|
2014-08-14 15:49:43 +00:00
|
|
|
} else {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit(e, cs);
|
2014-08-14 15:49:43 +00:00
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_choice(expr const & e, optional<expr> const & t, constraint_seq & cs) {
|
2014-06-24 21:55:06 +00:00
|
|
|
lean_assert(is_choice(e));
|
|
|
|
// Possible optimization: try to lookahead and discard some of the alternatives.
|
2014-08-05 23:46:43 +00:00
|
|
|
expr m = m_full_context.mk_meta(t, e.get_tag());
|
2014-08-28 23:27:52 +00:00
|
|
|
saved_state s(*this);
|
2014-08-05 23:46:43 +00:00
|
|
|
bool relax = m_relax_main_opaque;
|
2014-09-10 22:20:45 +00:00
|
|
|
auto fn = [=](expr const & mvar, expr const & /* type */, substitution const & /* s */,
|
|
|
|
name_generator const & /* ngen */) {
|
2014-08-28 23:27:52 +00:00
|
|
|
return choose(std::make_shared<choice_expr_elaborator>(*this, mvar, e, s, relax));
|
2014-06-24 21:55:06 +00:00
|
|
|
};
|
2014-06-26 15:52:40 +00:00
|
|
|
justification j = mk_justification("none of the overloads is applicable", some_expr(e));
|
2014-08-20 05:31:26 +00:00
|
|
|
cs += mk_choice_cnstr(m, fn, to_delay_factor(cnstr_group::Basic), true, j, m_relax_main_opaque);
|
2014-06-24 21:55:06 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_by(expr const & e, optional<expr> const & t, constraint_seq & cs) {
|
2014-07-02 03:43:53 +00:00
|
|
|
lean_assert(is_by(e));
|
2014-08-20 05:31:26 +00:00
|
|
|
expr tac = visit(get_by_arg(e), cs);
|
2014-08-05 23:25:54 +00:00
|
|
|
expr m = m_context.mk_meta(t, e.get_tag());
|
2014-07-08 21:28:33 +00:00
|
|
|
m_local_tactic_hints.insert(mlocal_name(get_app_fn(m)), tac);
|
2014-07-02 03:43:53 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2014-07-06 23:46:34 +00:00
|
|
|
/** \brief Make sure \c f is really a function, if it is not, try to apply coercions.
|
2014-06-24 21:55:06 +00:00
|
|
|
The result is a pair <tt>new_f, f_type</tt>, where new_f is the new value for \c f,
|
|
|
|
and \c f_type is its type (and a Pi-expression)
|
|
|
|
*/
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, expr> ensure_fun(expr f, constraint_seq & cs) {
|
|
|
|
expr f_type = infer_type(f, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (!is_pi(f_type))
|
2014-08-20 05:31:26 +00:00
|
|
|
f_type = whnf(f_type, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (!is_pi(f_type) && has_metavar(f_type)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq saved_cs = cs;
|
2014-09-09 02:09:18 +00:00
|
|
|
expr new_f_type = whnf(f_type, cs);
|
|
|
|
if (!is_pi(new_f_type) && is_meta(new_f_type)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
cs = saved_cs;
|
2014-06-24 21:55:06 +00:00
|
|
|
// let type checker add constraint
|
2014-08-20 05:31:26 +00:00
|
|
|
f_type = m_tc[m_relax_main_opaque]->ensure_pi(f_type, f, cs);
|
2014-09-09 02:09:18 +00:00
|
|
|
} else {
|
|
|
|
f_type = new_f_type;
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!is_pi(f_type)) {
|
|
|
|
// try coercion to function-class
|
2014-08-13 01:43:56 +00:00
|
|
|
optional<expr> c = get_coercion_to_fun(env(), f_type);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (c) {
|
2014-09-03 16:34:13 +00:00
|
|
|
expr old_f = f;
|
2014-06-24 21:55:06 +00:00
|
|
|
f = mk_app(*c, f, f.get_tag());
|
2014-08-20 05:31:26 +00:00
|
|
|
f_type = infer_type(f, cs);
|
2014-09-03 16:34:13 +00:00
|
|
|
save_coercion_info(old_f, f);
|
2014-06-24 21:55:06 +00:00
|
|
|
lean_assert(is_pi(f_type));
|
|
|
|
} else {
|
2014-08-13 01:43:56 +00:00
|
|
|
throw_kernel_exception(env(), f, [=](formatter const & fmt) { return pp_function_expected(fmt, f); });
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
2014-09-03 01:39:06 +00:00
|
|
|
} else {
|
|
|
|
erase_coercion_info(f);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
lean_assert(is_pi(f_type));
|
|
|
|
return mk_pair(f, f_type);
|
|
|
|
}
|
|
|
|
|
2014-06-27 01:39:23 +00:00
|
|
|
bool has_coercions_from(expr const & a_type) {
|
2014-08-20 05:31:26 +00:00
|
|
|
expr const & a_cls = get_app_fn(whnf(a_type).first);
|
2014-08-13 01:43:56 +00:00
|
|
|
return is_constant(a_cls) && ::lean::has_coercions_from(env(), const_name(a_cls));
|
2014-06-27 01:39:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool has_coercions_to(expr const & d_type) {
|
2014-08-20 05:31:26 +00:00
|
|
|
expr const & d_cls = get_app_fn(whnf(d_type).first);
|
2014-08-13 01:43:56 +00:00
|
|
|
return is_constant(d_cls) && ::lean::has_coercions_to(env(), const_name(d_cls));
|
2014-06-27 01:39:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr apply_coercion(expr const & a, expr a_type, expr d_type) {
|
2014-08-20 05:31:26 +00:00
|
|
|
a_type = whnf(a_type).first;
|
|
|
|
d_type = whnf(d_type).first;
|
2014-06-24 21:55:06 +00:00
|
|
|
expr const & d_cls = get_app_fn(d_type);
|
2014-06-27 01:39:23 +00:00
|
|
|
if (is_constant(d_cls)) {
|
2014-09-03 01:39:06 +00:00
|
|
|
if (auto c = get_coercion(env(), a_type, const_name(d_cls))) {
|
2014-09-03 16:34:13 +00:00
|
|
|
expr r = mk_app(*c, a, a.get_tag());
|
|
|
|
save_coercion_info(a, r);
|
|
|
|
return r;
|
2014-09-03 01:39:06 +00:00
|
|
|
} else {
|
|
|
|
erase_coercion_info(a);
|
|
|
|
}
|
2014-06-27 01:39:23 +00:00
|
|
|
}
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2014-07-29 20:55:39 +00:00
|
|
|
/** \brief Given a term <tt>a : a_type</tt>, and an expected type generate a metavariable with a delayed coercion. */
|
2014-09-10 19:49:35 +00:00
|
|
|
pair<expr, constraint_seq> mk_delayed_coercion(expr const & a, expr const & a_type, expr const & expected_type,
|
|
|
|
justification const & j) {
|
2014-09-10 23:07:41 +00:00
|
|
|
bool relax = m_relax_main_opaque;
|
|
|
|
type_checker & tc = *m_tc[relax];
|
|
|
|
pair<expr, constraint> ec = mk_coercion_elaborator(tc, *this, m_full_context, relax,
|
|
|
|
a, a_type, expected_type, j);
|
|
|
|
return to_ecs(ec.first, ec.second);
|
2014-07-29 20:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Given a term <tt>a : a_type</tt>, ensure it has type \c expected_type. Apply coercions if needed
|
|
|
|
|
|
|
|
\remark relax == true affects how opaque definitions in the main module are treated.
|
|
|
|
*/
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, constraint_seq> ensure_has_type(expr const & a, expr const & a_type, expr const & expected_type,
|
|
|
|
justification const & j, bool relax) {
|
2014-07-29 20:55:39 +00:00
|
|
|
if (is_meta(expected_type) && has_coercions_from(a_type)) {
|
|
|
|
return mk_delayed_coercion(a, a_type, expected_type, j);
|
|
|
|
} else if (is_meta(a_type) && has_coercions_to(expected_type)) {
|
|
|
|
return mk_delayed_coercion(a, a_type, expected_type, j);
|
|
|
|
} else {
|
2014-08-20 05:31:26 +00:00
|
|
|
auto dcs = m_tc[relax]->is_def_eq(a_type, expected_type, j);
|
|
|
|
if (dcs.first) {
|
|
|
|
return to_ecs(a, dcs.second);
|
2014-07-29 20:55:39 +00:00
|
|
|
} else {
|
2014-08-20 05:31:26 +00:00
|
|
|
expr new_a = apply_coercion(a, a_type, expected_type);
|
|
|
|
bool coercion_worked = false;
|
|
|
|
constraint_seq cs;
|
|
|
|
if (!is_eqp(a, new_a)) {
|
|
|
|
expr new_a_type = infer_type(new_a, cs);
|
|
|
|
coercion_worked = m_tc[relax]->is_def_eq(new_a_type, expected_type, j, cs);
|
|
|
|
}
|
|
|
|
if (coercion_worked) {
|
|
|
|
return to_ecs(new_a, cs);
|
|
|
|
} else if (has_metavar(a_type) || has_metavar(expected_type)) {
|
|
|
|
// rely on unification hints to solve this constraint
|
|
|
|
return to_ecs(a, mk_eq_cnstr(a_type, expected_type, j, relax));
|
|
|
|
} else {
|
|
|
|
throw unifier_exception(j, substitution());
|
|
|
|
}
|
2014-07-29 20:55:39 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-07-25 06:43:40 +00:00
|
|
|
bool is_choice_app(expr const & e) {
|
|
|
|
expr const & f = get_app_fn(e);
|
2014-09-04 18:18:16 +00:00
|
|
|
return is_choice(f) || (is_annotation(f) && is_choice(get_nested_annotation_arg(f)));
|
2014-07-25 06:43:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Process ((choice f_1 ... f_n) a_1 ... a_k) as
|
|
|
|
(choice (f_1 a_1 ... a_k) ... (f_n a_1 ... a_k))
|
|
|
|
*/
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_choice_app(expr const & e, constraint_seq & cs) {
|
2014-07-25 06:43:40 +00:00
|
|
|
buffer<expr> args;
|
2014-09-04 18:18:16 +00:00
|
|
|
expr r = get_app_rev_args(e, args);
|
|
|
|
expr f = get_nested_annotation_arg(r);
|
2014-07-25 06:43:40 +00:00
|
|
|
lean_assert(is_choice(f));
|
|
|
|
buffer<expr> new_choices;
|
|
|
|
unsigned num = get_num_choices(f);
|
|
|
|
for (unsigned i = 0; i < num; i++) {
|
|
|
|
expr f_i = get_choice(f, i);
|
2014-09-04 18:18:16 +00:00
|
|
|
f_i = copy_annotations(r, f_i);
|
2014-07-25 06:43:40 +00:00
|
|
|
new_choices.push_back(mk_rev_app(f_i, args));
|
|
|
|
}
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_choice(copy_tag(e, mk_choice(new_choices.size(), new_choices.data())), none_expr(), cs);
|
2014-07-25 06:43:40 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_app(expr const & e, constraint_seq & cs) {
|
2014-07-25 06:43:40 +00:00
|
|
|
if (is_choice_app(e))
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_choice_app(e, cs);
|
|
|
|
constraint_seq f_cs;
|
2014-09-04 18:18:16 +00:00
|
|
|
bool expl = is_nested_explicit(get_app_fn(e));
|
2014-08-20 05:31:26 +00:00
|
|
|
expr f = visit(app_fn(e), f_cs);
|
|
|
|
auto f_t = ensure_fun(f, f_cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
f = f_t.first;
|
2014-06-26 00:47:38 +00:00
|
|
|
expr f_type = f_t.second;
|
|
|
|
lean_assert(is_pi(f_type));
|
2014-06-28 14:30:36 +00:00
|
|
|
if (!expl) {
|
2014-08-01 17:58:20 +00:00
|
|
|
bool first = true;
|
|
|
|
while (binding_info(f_type).is_strict_implicit() || (!first && binding_info(f_type).is_implicit())) {
|
2014-08-20 05:31:26 +00:00
|
|
|
tag g = f.get_tag();
|
|
|
|
bool is_strict = false;
|
|
|
|
expr imp_arg = mk_placeholder_meta(some_expr(binding_domain(f_type)), g, is_strict, f_cs);
|
|
|
|
f = mk_app(f, imp_arg, g);
|
|
|
|
auto f_t = ensure_fun(f, f_cs);
|
|
|
|
f = f_t.first;
|
|
|
|
f_type = f_t.second;
|
|
|
|
first = false;
|
2014-06-28 14:30:36 +00:00
|
|
|
}
|
2014-08-02 03:57:24 +00:00
|
|
|
if (!first) {
|
2014-08-07 02:35:26 +00:00
|
|
|
// we save the info data again for application of functions with strict implicit arguments
|
2014-09-03 18:52:35 +00:00
|
|
|
save_type_data(get_app_fn(e), f);
|
2014-08-02 03:57:24 +00:00
|
|
|
}
|
2014-06-26 00:47:38 +00:00
|
|
|
}
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq a_cs;
|
2014-06-26 00:47:38 +00:00
|
|
|
expr d_type = binding_domain(f_type);
|
2014-08-20 05:31:26 +00:00
|
|
|
expr a = visit_expecting_type_of(app_arg(e), d_type, a_cs);
|
|
|
|
expr a_type = infer_type(a, a_cs);
|
2014-06-25 18:04:50 +00:00
|
|
|
expr r = mk_app(f, a, e.get_tag());
|
2014-06-27 01:39:23 +00:00
|
|
|
|
2014-07-29 21:24:12 +00:00
|
|
|
justification j = mk_app_justification(r, a, d_type, a_type);
|
2014-08-20 05:31:26 +00:00
|
|
|
auto new_a_cs = ensure_has_type(a, a_type, d_type, j, m_relax_main_opaque);
|
|
|
|
expr new_a = new_a_cs.first;
|
|
|
|
cs += f_cs + new_a_cs.second + a_cs;
|
2014-07-29 20:55:39 +00:00
|
|
|
return update_app(r, app_fn(r), new_a);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_placeholder(expr const & e, constraint_seq & cs) {
|
|
|
|
expr r = mk_placeholder_meta(placeholder_type(e), e.get_tag(), is_strict_placeholder(e), cs);
|
2014-08-15 19:45:54 +00:00
|
|
|
save_placeholder_info(e, r);
|
2014-08-14 15:49:43 +00:00
|
|
|
return r;
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
level replace_univ_placeholder(level const & l) {
|
|
|
|
return replace(l, [&](level const & l) {
|
|
|
|
if (is_placeholder(l))
|
|
|
|
return some_level(mk_meta_univ(m_ngen.next()));
|
|
|
|
else
|
|
|
|
return none_level();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
expr visit_sort(expr const & e) {
|
2014-08-12 22:00:32 +00:00
|
|
|
return update_sort(e, replace_univ_placeholder(sort_level(e)));
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_macro(expr const & e, constraint_seq & cs) {
|
2014-07-14 05:27:36 +00:00
|
|
|
if (is_as_is(e)) {
|
|
|
|
return get_as_is_arg(e);
|
|
|
|
} else {
|
|
|
|
// Remark: Macros are not meant to be used in the front end.
|
|
|
|
// Perhaps, we should throw error.
|
|
|
|
buffer<expr> args;
|
|
|
|
for (unsigned i = 0; i < macro_num_args(e); i++)
|
2014-08-20 05:31:26 +00:00
|
|
|
args.push_back(visit(macro_arg(e, i), cs));
|
2014-07-14 05:27:36 +00:00
|
|
|
return update_macro(e, args.size(), args.data());
|
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr visit_constant(expr const & e) {
|
2014-08-13 01:43:56 +00:00
|
|
|
declaration d = env().get(const_name(e));
|
2014-08-12 22:00:32 +00:00
|
|
|
buffer<level> ls;
|
|
|
|
for (level const & l : const_levels(e))
|
|
|
|
ls.push_back(replace_univ_placeholder(l));
|
|
|
|
unsigned num_univ_params = length(d.get_univ_params());
|
|
|
|
if (num_univ_params < ls.size())
|
2014-08-13 01:43:56 +00:00
|
|
|
throw_kernel_exception(env(), sstream() << "incorrect number of universe levels parameters for '"
|
2014-08-12 22:00:32 +00:00
|
|
|
<< const_name(e) << "', #" << num_univ_params
|
|
|
|
<< " expected, #" << ls.size() << " provided");
|
|
|
|
// "fill" with meta universe parameters
|
|
|
|
for (unsigned i = ls.size(); i < num_univ_params; i++)
|
|
|
|
ls.push_back(mk_meta_univ(m_ngen.next()));
|
|
|
|
lean_assert(num_univ_params == ls.size());
|
|
|
|
return update_constant(e, to_list(ls.begin(), ls.end()));
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Make sure \c e is a type. If it is not, then try to apply coercions. */
|
2014-08-20 05:31:26 +00:00
|
|
|
expr ensure_type(expr const & e, constraint_seq & cs) {
|
|
|
|
expr t = infer_type(e, cs);
|
2014-09-03 01:39:06 +00:00
|
|
|
erase_coercion_info(e);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (is_sort(t))
|
|
|
|
return e;
|
2014-08-20 05:31:26 +00:00
|
|
|
t = whnf(t, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (is_sort(t))
|
|
|
|
return e;
|
|
|
|
if (has_metavar(t)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
t = whnf(t, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
if (is_sort(t))
|
|
|
|
return e;
|
|
|
|
if (is_meta(t)) {
|
|
|
|
// let type checker add constraint
|
2014-08-20 05:31:26 +00:00
|
|
|
m_tc[m_relax_main_opaque]->ensure_sort(t, e, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 01:43:56 +00:00
|
|
|
optional<expr> c = get_coercion_to_sort(env(), t);
|
2014-09-03 01:39:06 +00:00
|
|
|
if (c) {
|
2014-09-03 16:34:13 +00:00
|
|
|
expr r = mk_app(*c, e, e.get_tag());
|
|
|
|
save_coercion_info(e, r);
|
|
|
|
return r;
|
2014-09-03 01:39:06 +00:00
|
|
|
}
|
2014-08-13 01:43:56 +00:00
|
|
|
throw_kernel_exception(env(), e, [=](formatter const & fmt) { return pp_type_expected(fmt, e); });
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-01 02:54:21 +00:00
|
|
|
/** \brief Similar to instantiate_rev, but assumes that subst contains only local constants.
|
|
|
|
When replacing a variable with a local, we copy the local constant and inherit the tag
|
|
|
|
associated with the variable. This is a trick for getter better error messages */
|
|
|
|
expr instantiate_rev_locals(expr const & a, unsigned n, expr const * subst) {
|
|
|
|
if (closed(a))
|
|
|
|
return a;
|
|
|
|
return replace(a, [=](expr const & m, unsigned offset) -> optional<expr> {
|
|
|
|
if (offset >= get_free_var_range(m))
|
|
|
|
return some_expr(m); // expression m does not contain free variables with idx >= offset
|
|
|
|
if (is_var(m)) {
|
|
|
|
unsigned vidx = var_idx(m);
|
|
|
|
if (vidx >= offset) {
|
|
|
|
unsigned h = offset + n;
|
|
|
|
if (h < offset /* overflow, h is bigger than any vidx */ || vidx < h) {
|
|
|
|
expr local = subst[n - (vidx - offset) - 1];
|
|
|
|
lean_assert(is_local(local));
|
|
|
|
return some_expr(copy_tag(m, copy(local)));
|
|
|
|
} else {
|
|
|
|
return some_expr(copy_tag(m, mk_var(vidx - n)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none_expr();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_binding(expr e, expr_kind k, constraint_seq & cs) {
|
2014-07-14 15:57:20 +00:00
|
|
|
scope_ctx scope(*this);
|
|
|
|
buffer<expr> ds, ls, es;
|
|
|
|
while (e.kind() == k) {
|
|
|
|
es.push_back(e);
|
|
|
|
expr d = binding_domain(e);
|
2014-08-01 02:54:21 +00:00
|
|
|
d = instantiate_rev_locals(d, ls.size(), ls.data());
|
2014-08-20 05:31:26 +00:00
|
|
|
d = ensure_type(visit_expecting_type(d, cs), cs);
|
2014-07-14 15:57:20 +00:00
|
|
|
ds.push_back(d);
|
|
|
|
expr l = mk_local(binding_name(e), d, binding_info(e));
|
|
|
|
if (binding_info(e).is_contextual())
|
2014-08-05 23:25:54 +00:00
|
|
|
m_context.add_local(l);
|
2014-08-05 23:46:43 +00:00
|
|
|
m_full_context.add_local(l);
|
2014-07-14 15:57:20 +00:00
|
|
|
ls.push_back(l);
|
|
|
|
e = binding_body(e);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
2014-07-14 15:57:20 +00:00
|
|
|
lean_assert(ls.size() == es.size() && ls.size() == ds.size());
|
2014-08-01 02:54:21 +00:00
|
|
|
e = instantiate_rev_locals(e, ls.size(), ls.data());
|
2014-08-20 05:31:26 +00:00
|
|
|
e = (k == expr_kind::Pi) ? ensure_type(visit_expecting_type(e, cs), cs) : visit(e, cs);
|
2014-07-14 15:57:20 +00:00
|
|
|
e = abstract_locals(e, ls.size(), ls.data());
|
|
|
|
unsigned i = ls.size();
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
e = update_binding(es[i], abstract_locals(ds[i], i, ls.data()), e);
|
|
|
|
}
|
|
|
|
return e;
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_pi(expr const & e, constraint_seq & cs) { return visit_binding(e, expr_kind::Pi, cs); }
|
|
|
|
expr visit_lambda(expr const & e, constraint_seq & cs) { return visit_binding(e, expr_kind::Lambda, cs); }
|
2014-06-24 21:55:06 +00:00
|
|
|
|
2014-08-22 18:26:00 +00:00
|
|
|
expr visit_typed_expr(expr const & e, constraint_seq & cs) {
|
|
|
|
constraint_seq t_cs;
|
|
|
|
expr t = visit(get_typed_expr_type(e), t_cs);
|
|
|
|
constraint_seq v_cs;
|
|
|
|
expr v = visit(get_typed_expr_expr(e), v_cs);
|
|
|
|
expr v_type = infer_type(v, v_cs);
|
|
|
|
justification j = mk_justification(e, [=](formatter const & fmt, substitution const & subst) {
|
|
|
|
substitution s(subst);
|
|
|
|
format expected_fmt, given_fmt;
|
|
|
|
std::tie(expected_fmt, given_fmt) = pp_until_different(fmt, s.instantiate(t), s.instantiate(v_type));
|
|
|
|
format r("type mismatch at term");
|
|
|
|
r += pp_indent_expr(fmt, s.instantiate(v));
|
2014-08-29 01:16:53 +00:00
|
|
|
r += compose(line(), format("has type"));
|
2014-08-22 18:26:00 +00:00
|
|
|
r += given_fmt;
|
|
|
|
r += compose(line(), format("but is expected to have type"));
|
|
|
|
r += expected_fmt;
|
|
|
|
return r;
|
|
|
|
});
|
|
|
|
auto new_vcs = ensure_has_type(v, v_type, t, j, m_relax_main_opaque);
|
|
|
|
v = new_vcs.first;
|
|
|
|
cs += t_cs + new_vcs.second + v_cs;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2014-08-28 23:27:52 +00:00
|
|
|
expr visit_let_value(expr const & e, constraint_seq & cs) {
|
|
|
|
if (auto p = m_cache.find(e)) {
|
|
|
|
cs += p->second;
|
|
|
|
return p->first;
|
|
|
|
} else {
|
2014-08-29 16:58:11 +00:00
|
|
|
auto ecs = visit(get_let_value_expr(e));
|
|
|
|
expr r = copy_tag(ecs.first, mk_let_value(ecs.first));
|
2014-08-29 14:46:40 +00:00
|
|
|
m_cache.insert(e, mk_pair(r, ecs.second));
|
2014-08-28 23:27:52 +00:00
|
|
|
cs += ecs.second;
|
2014-08-29 14:46:40 +00:00
|
|
|
return r;
|
2014-08-28 23:27:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit_core(expr const & e, constraint_seq & cs) {
|
2014-06-24 21:55:06 +00:00
|
|
|
if (is_placeholder(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_placeholder(e, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
} else if (is_choice(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_choice(e, none_expr(), cs);
|
2014-08-29 16:58:11 +00:00
|
|
|
} else if (is_let_value(e)) {
|
2014-08-28 23:27:52 +00:00
|
|
|
return visit_let_value(e, cs);
|
2014-07-02 03:43:53 +00:00
|
|
|
} else if (is_by(e)) {
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit_by(e, none_expr(), cs);
|
2014-09-04 16:59:24 +00:00
|
|
|
} else if (is_no_info(e)) {
|
|
|
|
flet<bool> let(m_no_info, true);
|
2014-08-20 05:31:26 +00:00
|
|
|
return visit(get_annotation_arg(e), cs);
|
2014-08-22 18:26:00 +00:00
|
|
|
} else if (is_typed_expr(e)) {
|
|
|
|
return visit_typed_expr(e, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
} else {
|
|
|
|
switch (e.kind()) {
|
|
|
|
case expr_kind::Local: return e;
|
|
|
|
case expr_kind::Meta: return e;
|
|
|
|
case expr_kind::Sort: return visit_sort(e);
|
|
|
|
case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
case expr_kind::Constant: return visit_constant(e);
|
2014-08-20 05:31:26 +00:00
|
|
|
case expr_kind::Macro: return visit_macro(e, cs);
|
|
|
|
case expr_kind::Lambda: return visit_lambda(e, cs);
|
|
|
|
case expr_kind::Pi: return visit_pi(e, cs);
|
|
|
|
case expr_kind::App: return visit_app(e, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, constraint_seq> visit(expr const & e) {
|
2014-09-04 18:18:16 +00:00
|
|
|
if (is_extra_info(e)) {
|
|
|
|
auto ecs = visit(get_annotation_arg(e));
|
|
|
|
save_extra_type_data(e, ecs.first);
|
|
|
|
return ecs;
|
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
expr r;
|
2014-08-02 03:57:24 +00:00
|
|
|
expr b = e;
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq cs;
|
2014-06-24 21:55:06 +00:00
|
|
|
if (is_explicit(e)) {
|
2014-08-02 03:57:24 +00:00
|
|
|
b = get_explicit_arg(e);
|
2014-08-20 05:31:26 +00:00
|
|
|
r = visit_core(get_explicit_arg(e), cs);
|
2014-06-28 14:30:36 +00:00
|
|
|
} else if (is_explicit(get_app_fn(e))) {
|
2014-08-20 05:31:26 +00:00
|
|
|
r = visit_core(e, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
} else {
|
2014-07-19 08:55:34 +00:00
|
|
|
if (is_implicit(e)) {
|
|
|
|
r = get_implicit_arg(e);
|
|
|
|
if (is_explicit(r)) r = get_explicit_arg(r);
|
2014-08-02 03:57:24 +00:00
|
|
|
b = r;
|
2014-08-20 05:31:26 +00:00
|
|
|
r = visit_core(r, cs);
|
2014-07-19 08:55:34 +00:00
|
|
|
} else {
|
2014-08-20 05:31:26 +00:00
|
|
|
r = visit_core(e, cs);
|
2014-07-19 08:55:34 +00:00
|
|
|
}
|
2014-09-07 19:28:58 +00:00
|
|
|
tag g = e.get_tag();
|
|
|
|
expr r_type = whnf(infer_type(r, cs), cs);
|
|
|
|
expr imp_arg;
|
|
|
|
bool is_strict = false;
|
|
|
|
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);
|
|
|
|
r = mk_app(r, imp_arg, g);
|
|
|
|
r_type = whnf(instantiate(binding_body(r_type), imp_arg), cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-03 18:52:35 +00:00
|
|
|
save_type_data(b, r);
|
2014-08-20 05:31:26 +00:00
|
|
|
return mk_pair(r, cs);
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|
2014-06-25 15:30:09 +00:00
|
|
|
|
2014-08-20 05:31:26 +00:00
|
|
|
expr visit(expr const & e, constraint_seq & cs) {
|
|
|
|
auto r = visit(e);
|
|
|
|
cs += r.second;
|
|
|
|
return r.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
lazy_list<substitution> solve(constraint_seq const & cs) {
|
|
|
|
buffer<constraint> tmp;
|
|
|
|
cs.linearize(tmp);
|
2014-08-21 00:30:08 +00:00
|
|
|
return unify(env(), tmp.size(), tmp.data(), m_ngen.mk_child(), unifier_config(ios().get_options(), true));
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-07-03 00:32:13 +00:00
|
|
|
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))) {
|
|
|
|
m_displayed_errors.insert(mlocal_name(mvar));
|
2014-08-13 01:43:56 +00:00
|
|
|
auto out = regular(env(), ios());
|
2014-08-01 00:41:39 +00:00
|
|
|
flycheck_error err(out);
|
2014-08-13 01:43:56 +00:00
|
|
|
display_error_pos(out, pip(), mvar);
|
2014-07-31 19:45:54 +00:00
|
|
|
out << " unsolved placeholder, " << msg << "\n" << ps << endl;
|
2014-07-03 00:32:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 01:58:32 +00:00
|
|
|
// For each occurrence of \c exact_tac in \c pre_tac, display its unassigned metavariables.
|
|
|
|
// This is a trick to improve the quality of the error messages.
|
|
|
|
void check_exact_tacs(expr const & pre_tac, substitution const & s) {
|
|
|
|
for_each(pre_tac, [&](expr const & e, unsigned) {
|
|
|
|
expr const & f = get_app_fn(e);
|
2014-07-03 03:45:10 +00:00
|
|
|
if (is_constant(f) && const_name(f) == const_name(get_exact_tac_fn())) {
|
2014-07-03 01:58:32 +00:00
|
|
|
display_unassigned_mvars(e, s);
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:32:13 +00:00
|
|
|
optional<expr> get_pre_tactic_for(substitution & subst, expr const & mvar, name_set & visited) {
|
2014-07-08 21:28:33 +00:00
|
|
|
if (auto it = m_local_tactic_hints.find(mlocal_name(mvar))) {
|
2014-07-03 00:32:13 +00:00
|
|
|
expr pre_tac = subst.instantiate(*it);
|
|
|
|
pre_tac = solve_unassigned_mvars(subst, pre_tac, visited);
|
2014-07-03 01:58:32 +00:00
|
|
|
check_exact_tacs(pre_tac, subst);
|
2014-07-03 00:32:13 +00:00
|
|
|
return some_expr(pre_tac);
|
2014-06-29 16:47:25 +00:00
|
|
|
} else {
|
2014-07-03 00:32:13 +00:00
|
|
|
return none_expr();
|
2014-06-29 16:47:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:32:13 +00:00
|
|
|
optional<tactic> pre_tactic_to_tactic(expr const & pre_tac, expr const & mvar) {
|
|
|
|
try {
|
2014-08-13 01:43:56 +00:00
|
|
|
return optional<tactic>(expr_to_tactic(env(), pre_tac, pip()));
|
2014-07-03 00:32:13 +00:00
|
|
|
} catch (expr_to_tactic_exception & ex) {
|
2014-08-13 01:43:56 +00:00
|
|
|
auto out = regular(env(), ios());
|
|
|
|
display_error_pos(out, pip(), mvar);
|
2014-07-03 00:32:13 +00:00
|
|
|
out << " " << ex.what();
|
2014-07-10 17:32:00 +00:00
|
|
|
out << pp_indent_expr(out.get_formatter(), pre_tac) << endl << "failed at:"
|
|
|
|
<< pp_indent_expr(out.get_formatter(), ex.get_expr()) << endl;
|
2014-07-03 00:32:13 +00:00
|
|
|
return optional<tactic>();
|
2014-07-02 23:26:06 +00:00
|
|
|
}
|
2014-06-29 16:47:25 +00:00
|
|
|
}
|
|
|
|
|
2014-07-08 21:28:33 +00:00
|
|
|
optional<tactic> get_local_tactic_hint(substitution & subst, expr const & mvar, name_set & visited) {
|
|
|
|
if (auto pre_tac = get_pre_tactic_for(subst, mvar, visited)) {
|
|
|
|
return pre_tactic_to_tactic(*pre_tac, mvar);
|
|
|
|
} else {
|
|
|
|
return optional<tactic>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Try to instantiate meta-variable \c mvar (modulo its state ps) using the given tactic.
|
|
|
|
If it succeeds, then update subst with the solution.
|
|
|
|
Return true iff the metavariable \c mvar has been assigned.
|
|
|
|
*/
|
2014-07-14 01:53:02 +00:00
|
|
|
bool try_using(substitution & subst, expr const & mvar, proof_state const & ps, tactic const & tac) {
|
2014-07-08 21:28:33 +00:00
|
|
|
lean_assert(length(ps.get_goals()) == 1);
|
2014-07-14 01:53:02 +00:00
|
|
|
// make sure ps is a really a proof state for mvar.
|
|
|
|
lean_assert(mlocal_name(get_app_fn(head(ps.get_goals()).get_meta())) == mlocal_name(mvar));
|
2014-07-08 21:28:33 +00:00
|
|
|
try {
|
2014-08-13 01:43:56 +00:00
|
|
|
proof_state_seq seq = tac(env(), ios(), ps);
|
2014-07-08 21:28:33 +00:00
|
|
|
auto r = seq.pull();
|
|
|
|
if (!r) {
|
|
|
|
// tactic failed to produce any result
|
2014-07-14 01:53:02 +00:00
|
|
|
display_unsolved_proof_state(mvar, ps, "tactic failed");
|
2014-07-08 21:28:33 +00:00
|
|
|
return false;
|
|
|
|
} else if (!empty(r->first.get_goals())) {
|
|
|
|
// tactic contains unsolved subgoals
|
2014-07-14 01:53:02 +00:00
|
|
|
display_unsolved_proof_state(mvar, r->first, "unsolved subgoals");
|
2014-07-08 21:28:33 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
subst = r->first.get_subst();
|
|
|
|
expr v = subst.instantiate(mvar);
|
2014-07-23 15:51:24 +00:00
|
|
|
subst.assign(mlocal_name(mvar), v);
|
2014-07-08 21:28:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (tactic_exception & ex) {
|
2014-08-13 01:43:56 +00:00
|
|
|
auto out = regular(env(), ios());
|
|
|
|
display_error_pos(out, pip(), ex.get_expr());
|
2014-07-14 01:53:02 +00:00
|
|
|
out << " tactic failed: " << ex.what() << "\n";
|
2014-07-08 21:28:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:32:13 +00:00
|
|
|
void solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited) {
|
|
|
|
if (visited.contains(mlocal_name(mvar)))
|
|
|
|
return;
|
|
|
|
visited.insert(mlocal_name(mvar));
|
2014-07-08 21:28:33 +00:00
|
|
|
if (auto local_hint = get_local_tactic_hint(subst, mvar, visited)) {
|
2014-07-14 01:53:02 +00:00
|
|
|
auto meta = mvar_to_meta(mvar);
|
|
|
|
if (!meta)
|
|
|
|
return;
|
|
|
|
meta = instantiate_meta(*meta, subst);
|
2014-08-20 05:31:26 +00:00
|
|
|
// TODO(Leo): we are discarding constraints here
|
|
|
|
expr type = m_tc[m_relax_main_opaque]->infer(*meta).first;
|
2014-07-14 01:53:02 +00:00
|
|
|
// first solve unassigned metavariables in type
|
|
|
|
type = solve_unassigned_mvars(subst, type, visited);
|
|
|
|
proof_state ps(goals(goal(*meta, type)), subst, m_ngen.mk_child());
|
|
|
|
try_using(subst, mvar, ps, *local_hint);
|
2014-07-03 00:32:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-25 22:02:33 +00:00
|
|
|
expr solve_unassigned_mvars(substitution & subst, expr e, name_set & visited) {
|
|
|
|
e = subst.instantiate(e);
|
2014-09-11 16:58:44 +00:00
|
|
|
metavar_closure mvars(e);
|
|
|
|
mvars.for_each_expr_mvar([&](expr const & mvar) {
|
|
|
|
check_interrupted();
|
|
|
|
solve_unassigned_mvar(subst, mvar, visited);
|
|
|
|
});
|
2014-07-02 22:39:25 +00:00
|
|
|
return subst.instantiate(e);
|
2014-06-29 16:47:25 +00:00
|
|
|
}
|
|
|
|
|
2014-07-03 00:32:13 +00:00
|
|
|
expr solve_unassigned_mvars(substitution & subst, expr const & e) {
|
|
|
|
name_set visited;
|
|
|
|
return solve_unassigned_mvars(subst, e, visited);
|
|
|
|
}
|
|
|
|
|
2014-07-03 01:07:11 +00:00
|
|
|
void display_unassigned_mvars(expr const & e, substitution const & s) {
|
2014-08-13 01:43:56 +00:00
|
|
|
if (check_unassigned() && has_metavar(e)) {
|
2014-07-23 15:51:24 +00:00
|
|
|
substitution tmp_s(s);
|
2014-07-02 23:26:06 +00:00
|
|
|
for_each(e, [&](expr const & e, unsigned) {
|
|
|
|
if (!is_metavar(e))
|
|
|
|
return has_metavar(e);
|
2014-09-10 19:49:35 +00:00
|
|
|
if (auto it = mvar_to_meta(e)) {
|
2014-07-23 15:51:24 +00:00
|
|
|
expr meta = tmp_s.instantiate(*it);
|
2014-08-20 05:31:26 +00:00
|
|
|
expr meta_type = tmp_s.instantiate(type_checker(env()).infer(meta).first);
|
2014-07-02 23:26:06 +00:00
|
|
|
goal g(meta, meta_type);
|
|
|
|
display_unsolved_proof_state(e, proof_state(goals(g), substitution(), m_ngen),
|
|
|
|
"don't know how to synthesize it");
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:47:25 +00:00
|
|
|
/** \brief Apply substitution and solve remaining metavariables using tactics. */
|
2014-07-06 23:46:34 +00:00
|
|
|
expr apply(substitution & s, expr const & e, name_set & univ_params, buffer<name> & new_params) {
|
2014-07-23 15:51:24 +00:00
|
|
|
expr r = s.instantiate(e);
|
2014-07-06 23:46:34 +00:00
|
|
|
if (has_univ_metavar(r))
|
2014-09-10 17:24:35 +00:00
|
|
|
r = univ_metavars_to_params(env(), lls(), s, univ_params, new_params, r);
|
2014-07-02 23:26:06 +00:00
|
|
|
r = solve_unassigned_mvars(s, r);
|
2014-07-03 01:07:11 +00:00
|
|
|
display_unassigned_mvars(r, s);
|
2014-07-02 23:26:06 +00:00
|
|
|
return r;
|
2014-06-29 16:47:25 +00:00
|
|
|
}
|
|
|
|
|
2014-07-06 23:46:34 +00:00
|
|
|
std::tuple<expr, level_param_names> apply(substitution & s, expr const & e) {
|
|
|
|
auto ps = collect_univ_params(e);
|
|
|
|
buffer<name> new_ps;
|
|
|
|
expr r = apply(s, e, ps, new_ps);
|
|
|
|
return std::make_tuple(r, to_list(new_ps.begin(), new_ps.end()));
|
|
|
|
}
|
|
|
|
|
2014-07-27 19:01:06 +00:00
|
|
|
std::tuple<expr, level_param_names> operator()(expr const & e, bool _ensure_type, bool relax_main_opaque) {
|
2014-08-13 01:43:56 +00:00
|
|
|
flet<bool> set_relax(m_relax_main_opaque, relax_main_opaque && !get_hide_main_opaque(env()));
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq cs;
|
|
|
|
expr r = visit(e, cs);
|
2014-07-07 04:54:16 +00:00
|
|
|
if (_ensure_type)
|
2014-08-20 05:31:26 +00:00
|
|
|
r = ensure_type(r, cs);
|
|
|
|
auto p = solve(cs).pull();
|
2014-06-25 15:30:09 +00:00
|
|
|
lean_assert(p);
|
|
|
|
substitution s = p->first;
|
2014-08-01 02:54:21 +00:00
|
|
|
auto result = apply(s, r);
|
2014-08-07 02:35:26 +00:00
|
|
|
copy_info_to_manager(s);
|
2014-08-01 02:54:21 +00:00
|
|
|
return result;
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-07-27 19:01:06 +00:00
|
|
|
std::tuple<expr, expr, level_param_names> operator()(expr const & t, expr const & v, name const & n, bool is_opaque) {
|
2014-07-14 04:04:01 +00:00
|
|
|
lean_assert(!has_local(t)); lean_assert(!has_local(v));
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq t_cs;
|
|
|
|
expr r_t = ensure_type(visit(t, t_cs), t_cs);
|
2014-07-27 19:01:06 +00:00
|
|
|
// Opaque definitions in the main module may treat other opaque definitions (in the main module) as transparent.
|
2014-08-13 01:43:56 +00:00
|
|
|
flet<bool> set_relax(m_relax_main_opaque, is_opaque && !get_hide_main_opaque(env()));
|
2014-08-20 05:31:26 +00:00
|
|
|
constraint_seq v_cs;
|
|
|
|
expr r_v = visit(v, v_cs);
|
|
|
|
expr r_v_type = infer_type(r_v, v_cs);
|
2014-07-29 21:24:12 +00:00
|
|
|
justification j = mk_justification(r_v, [=](formatter const & fmt, substitution const & subst) {
|
2014-07-23 15:51:24 +00:00
|
|
|
substitution s(subst);
|
|
|
|
return pp_def_type_mismatch(fmt, n, s.instantiate(r_t), s.instantiate(r_v_type));
|
2014-06-25 15:30:09 +00:00
|
|
|
});
|
2014-08-20 05:31:26 +00:00
|
|
|
pair<expr, constraint_seq> r_v_cs = ensure_has_type(r_v, r_v_type, r_t, j, is_opaque);
|
|
|
|
r_v = r_v_cs.first;
|
|
|
|
constraint_seq cs = t_cs + r_v_cs.second + v_cs;
|
|
|
|
auto p = solve(cs).pull();
|
2014-06-25 15:30:09 +00:00
|
|
|
lean_assert(p);
|
|
|
|
substitution s = p->first;
|
2014-07-06 23:46:34 +00:00
|
|
|
name_set univ_params = collect_univ_params(r_v, collect_univ_params(r_t));
|
|
|
|
buffer<name> new_params;
|
|
|
|
expr new_r_t = apply(s, r_t, univ_params, new_params);
|
|
|
|
expr new_r_v = apply(s, r_v, univ_params, new_params);
|
2014-08-07 02:35:26 +00:00
|
|
|
copy_info_to_manager(s);
|
2014-07-06 23:46:34 +00:00
|
|
|
return std::make_tuple(new_r_t, new_r_v, to_list(new_params.begin(), new_params.end()));
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
};
|
2014-06-25 15:30:09 +00:00
|
|
|
|
|
|
|
static name g_tmp_prefix = name::mk_internal_unique_name();
|
|
|
|
|
2014-08-13 19:45:57 +00:00
|
|
|
std::tuple<expr, level_param_names> elaborate(elaborator_context & env, list<expr> const & ctx, expr const & e,
|
2014-08-13 01:43:56 +00:00
|
|
|
bool relax_main_opaque, bool ensure_type) {
|
|
|
|
return elaborator(env, ctx, name_generator(g_tmp_prefix))(e, ensure_type, relax_main_opaque);
|
2014-06-25 15:30:09 +00:00
|
|
|
}
|
|
|
|
|
2014-08-13 19:45:57 +00:00
|
|
|
std::tuple<expr, expr, level_param_names> elaborate(elaborator_context & env, name const & n, expr const & t, expr const & v,
|
2014-08-13 01:43:56 +00:00
|
|
|
bool is_opaque) {
|
|
|
|
return elaborator(env, list<expr>(), name_generator(g_tmp_prefix))(t, v, n, is_opaque);
|
2014-06-30 07:51:11 +00:00
|
|
|
}
|
2014-06-24 21:55:06 +00:00
|
|
|
}
|