/* 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 #include "kernel/metavar.h" #include "kernel/free_vars.h" #include "kernel/replace_visitor.h" #include "kernel/justification.h" #include "kernel/instantiate.h" #include "kernel/find_fn.h" #include "kernel/level.h" namespace lean { substitution::substitution(expr_map const & em, level_map const & lm): m_expr_subst(em), m_level_subst(lm) {} substitution::substitution() {} bool substitution::is_expr_assigned(name const & m) const { return m_expr_subst.contains(m); } optional> substitution::get_expr_assignment(name const & m) const { auto it = m_expr_subst.find(m); if (it) return optional>(*it); else return optional>(); } bool substitution::is_level_assigned(name const & m) const { return m_level_subst.contains(m); } optional> substitution::get_level_assignment(name const & m) const { auto it = m_level_subst.find(m); if (it) return opt_level_jst(*it); else return opt_level_jst(); } optional substitution::get_expr(name const & m) const { auto it = m_expr_subst.find(m); if (it) return some_expr(it->first); else return none_expr(); } optional substitution::get_level(name const & m) const { auto it = m_level_subst.find(m); if (it) return some_level(it->first); else return none_level(); } void substitution::d_assign(name const & m, expr const & t, justification const & j) { lean_assert(closed(t)); m_expr_subst.insert(m, mk_pair(t, j)); } void substitution::d_assign(name const & m, expr const & t) { assign(m, t, justification()); } void substitution::d_assign(name const & m, level const & l, justification const & j) { m_level_subst.insert(m, mk_pair(l, j)); } void substitution::d_assign(name const & m, level const & l) { assign(m, l, justification()); } substitution substitution::assign(name const & m, expr const & t, justification const & j) const { lean_assert(closed(t)); return substitution(insert(m_expr_subst, m, mk_pair(t, j)), m_level_subst); } substitution substitution::assign(name const & m, expr const & t) const { return assign(m, t, justification()); } substitution substitution::assign(name const & m, level const & l, justification const & j) const { return substitution(m_expr_subst, insert(m_level_subst, m, mk_pair(l, j))); } substitution substitution::assign(name const & m, level const & l) const { return assign(m, l, justification()); } std::pair substitution::d_instantiate_metavars(level const & l, bool use_jst, bool updt, name_set * unassigned) { if (!has_meta(l)) return mk_pair(l, justification()); justification j; auto save_jst = [&](justification const & j2) { j = mk_composite1(j, j2); }; level r = replace(l, [&](level const & l) { if (!has_meta(l)) { return some_level(l); } else if (is_meta(l)) { auto p1 = get_assignment(l); if (p1) { auto p2 = d_instantiate_metavars(p1->first, use_jst, updt, unassigned); if (use_jst) { justification new_jst = mk_composite1(p1->second, p2.second); if (updt) d_assign(meta_id(l), p2.first, new_jst); save_jst(new_jst); } else if (updt) { d_assign(meta_id(l), p2.first); } return some_level(p2.first); } else if (unassigned) { unassigned->insert(meta_id(l)); } } return none_level(); }); return mk_pair(r, j); } class instantiate_metavars_fn : public replace_visitor { protected: substitution & m_subst; justification m_jst; bool m_use_jst; bool m_update; name_set * m_unassigned_lvls; name_set * m_unassigned_exprs; void save_jst(justification const & j) { m_jst = mk_composite1(m_jst, j); } level visit_level(level const & l) { auto p1 = m_subst.d_instantiate_metavars(l, m_use_jst, m_update, m_unassigned_lvls); if (m_use_jst) save_jst(p1.second); return p1.first; } levels visit_levels(levels const & ls) { return map_reuse(ls, [&](level const & l) { return visit_level(l); }, [](level const & l1, level const & l2) { return is_eqp(l1, l2); }); } virtual expr visit_sort(expr const & s) { return update_sort(s, visit_level(sort_level(s))); } virtual expr visit_constant(expr const & c) { return update_constant(c, visit_levels(const_levels(c))); } virtual expr visit_meta(expr const & m) { name const & m_name = mlocal_name(m); auto p1 = m_subst.get_expr_assignment(m_name); if (p1) { if (!has_metavar(p1->first)) { if (m_use_jst) save_jst(p1->second); return p1->first; } else if (m_use_jst) { if (m_update) { auto p2 = m_subst.d_instantiate_metavars(p1->first, m_unassigned_lvls, m_unassigned_exprs); justification new_jst = mk_composite1(p1->second, p2.second); m_subst.d_assign(m_name, p2.first, new_jst); save_jst(new_jst); return p2.first; } else { auto p2 = m_subst.instantiate_metavars(p1->first, m_unassigned_lvls, m_unassigned_exprs); save_jst(mk_composite1(p1->second, p2.second)); return p2.first; } } else { lean_assert(m_unassigned_exprs == nullptr); lean_assert(m_unassigned_lvls == nullptr); if (m_update) { expr r = m_subst.d_instantiate_metavars_wo_jst(p1->first); m_subst.d_assign(m_name, r); return r; } else { return m_subst.instantiate(p1->first); } } } else { if (m_unassigned_exprs) m_unassigned_exprs->insert(m_name); return m; } } virtual expr visit_app(expr const & e) { buffer args; expr const * it = &e; while (is_app(*it)) { args.push_back(visit(app_arg(*it))); it = &app_fn(*it); } expr const & f = *it; if (is_metavar(f) && m_subst.is_expr_assigned(mlocal_name(f))) { expr new_f = visit_meta(f); return apply_beta(new_f, args.size(), args.data()); } else { args.push_back(visit(f)); return update_rev_app(e, args); } } virtual expr visit(expr const & e) { if (!has_metavar(e)) { return e; } else { return replace_visitor::visit(e); } } public: instantiate_metavars_fn(substitution & s, bool use_jst, bool updt, name_set * unassigned_lvls, name_set * unassigned_exprs): m_subst(s), m_use_jst(use_jst), m_update(updt), m_unassigned_lvls(unassigned_lvls), m_unassigned_exprs(unassigned_exprs) {} justification const & get_justification() const { return m_jst; } }; std::pair substitution::instantiate_metavars(expr const & e, name_set * unassigned_lvls, name_set * unassigned_exprs) const { substitution s(*this); instantiate_metavars_fn fn(s, true, false, unassigned_lvls, unassigned_exprs); expr r = fn(e); return mk_pair(r, fn.get_justification()); } std::pair substitution::d_instantiate_metavars(expr const & e, name_set * unassigned_lvls, name_set * unassigned_exprs) { instantiate_metavars_fn fn(*this, true, true, unassigned_lvls, unassigned_exprs); expr r = fn(e); return mk_pair(r, fn.get_justification()); } std::tuple substitution::updt_instantiate_metavars(expr const & e, name_set * unassigned_lvls, name_set * unassigned_exprs) const { substitution s(*this); instantiate_metavars_fn fn(s, true, true, unassigned_lvls, unassigned_exprs); expr r = fn(e); return std::make_tuple(r, fn.get_justification(), s); } std::pair substitution::instantiate_metavars(level const & l, name_set * unassigned) const { substitution s(*this); return s.d_instantiate_metavars(l, true, false, unassigned); } expr substitution::instantiate_metavars_wo_jst(expr const & e) const { substitution s(*this); return instantiate_metavars_fn(s, false, false, nullptr, nullptr)(e); } expr substitution::d_instantiate_metavars_wo_jst(expr const & e) { return instantiate_metavars_fn(*this, false, true, nullptr, nullptr)(e); } std::pair substitution::updt_instantiate_metavars_wo_jst(expr const & e) const { substitution s(*this); return mk_pair(instantiate_metavars_fn(s, false, true, nullptr, nullptr)(e), s); } level substitution::instantiate_metavars_wo_jst(level const & l) const { substitution s(*this); return s.d_instantiate_metavars(l, false, false, nullptr).first; } bool substitution::occurs_expr(name const & m, expr const & e) const { if (!has_metavar(e)) return false; auto it = find(e, [&](expr const & e, unsigned) { if (is_metavar(e)) { if (mlocal_name(e) == m) return true; auto s = get_expr(e); return s && occurs_expr(m, *s); } else { return false; } }); return static_cast(it); } }