/* Copyright (c) 2013 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #pragma once #include #include "util/debug.h" #include "util/rc.h" #include "util/buffer.h" #include "util/sexpr/format.h" #include "kernel/expr.h" #include "kernel/formatter.h" #include "kernel/pos_info_provider.h" namespace lean { class substitution; struct justification_cell; /** \brief When a set of constraints cannot be solved, we must print some "error" message to the user. The pp_jst_fn is a generic funciton that produces these messages. We can associate these functions to justification objects. */ typedef std::function pp_jst_fn; /** \brief Objects used to justify unification (and level) constraints and metavariable assignments. There are 4 basic kinds of justification: - None: the null justification. - Asserted: a justification produced by the type checker. - Assumption: for case-splits inside the elaborator and other constraint solvers. - Composite: the combination of two other justification objects. A composite justification is used, for example, to justify a constraint produced by replacing a metavariable ?M by its assignment in a constraint C. */ class justification { justification_cell * m_ptr; justification(justification_cell * ptr); public: justification(); justification(justification const & s); justification(justification && s); ~justification(); friend void swap(justification & a, justification & b) { std::swap(a.m_ptr, b.m_ptr); } bool is_none() const; bool is_asserted() const; bool is_assumption() const; bool is_composite() const; justification_cell * raw() const { return m_ptr; } justification & operator=(justification const & s); justification & operator=(justification && s); /** \brief Convert this justification into a format object. This method is usually used to report "error" messages to users. */ format pp(formatter const & fmt, pos_info_provider const * p, substitution const & s) const; /** \brief Return an expression associated with the justification object. */ optional get_main_expr() const; friend justification mk_composite(justification const & j1, justification const & j2, optional const & s, pp_jst_fn const & fn); friend justification mk_composite1(justification const & j1, justification const & j2); friend justification mk_assumption_justification(unsigned idx, optional const & s, pp_jst_fn const & fn); friend justification mk_assumption_justification(unsigned idx); friend justification mk_justification(optional const & s, pp_jst_fn const & fn); friend bool is_eqp(justification const & j1, justification const & j2) { return j1.raw() == j2.raw(); } }; /** \brief Simpler version of pp_jst_fn */ typedef std::function pp_jst_sfn; /** \brief Return a format object containing position information for the given expression (if available) */ format to_pos(optional const & e, pos_info_provider const * p); /** \brief Combine the two given justifications into a new justification object, and use the given function to convert the justification into a format object. */ justification mk_composite(justification const & j1, justification const & j2, optional const & s, pp_jst_fn const & fn); /** \brief Similar to \c mk_composite, but uses \c j1.pp to convert the resulting justification into a format object. */ justification mk_composite1(justification const & j1, justification const & j2); /** \brief Alias for \c mk_composite1 */ justification mk_substitution_justification(justification const & j1, justification const & j2); /** \brief Create a "case-split" justification with the given \c idx. */ justification mk_assumption_justification(unsigned idx, optional const & s, pp_jst_fn const & fn); /** \brief Similar to the previous function, but fn just returns the format object "assumption idx", and s is the none. */ justification mk_assumption_justification(unsigned idx); /** \brief Create a justification for constraints produced by the type checker. */ justification mk_justification(optional const & s, pp_jst_fn const & fn); justification mk_justification(char const * msg, optional const & s = none_expr()); /** \brief Create a justification for constraints produced by the type checker. It is similar to the previous function, but the position of \c s will be automatically included. */ justification mk_justification(optional const & s, pp_jst_sfn const & fn); inline justification mk_justification(expr const & s, pp_jst_sfn const & fn) { return mk_justification(some_expr(s), fn); } /** \brief Return the first child of a composite justification. \pre j.is_composite() */ justification const & composite_child1(justification const & j); /** \brief Return the second child of a composite justification. \pre j.is_composite() */ justification const & composite_child2(justification const & j); /** \brief Return the index of an assumption justification. \pre j.is_assumption() */ unsigned assumption_idx(justification const & j); /** \brief Return true iff \c j depends on the assumption with index \c i. */ bool depends_on(justification const & j, unsigned i); /** \brief Printer for debugging purposes */ std::ostream & operator<<(std::ostream & out, justification const & j); /** \brief Object to simulate delayed justification creation. */ class delayed_justification { public: virtual ~delayed_justification() {} virtual justification get() = 0; }; class no_delayed_justification : public delayed_justification { public: virtual justification get() { return justification(); } }; class simple_delayed_justification : public delayed_justification { optional m_jst; std::function m_mk; public: template simple_delayed_justification(Mk && mk):m_mk(mk) {} virtual justification get() { if (!m_jst) { m_jst = m_mk(); } return *m_jst; } }; class as_delayed_justification : public delayed_justification { justification m_jst; public: as_delayed_justification(justification const & j):m_jst(j) {} virtual justification get() { return m_jst; } }; }