#pragma once #include #include "error.hh" #include "pos-idx.hh" namespace nix { struct Env; struct Expr; struct Value; class EvalState; template class EvalErrorBuilder; class EvalError : public Error { template friend class EvalErrorBuilder; public: EvalState & state; EvalError(EvalState & state, ErrorInfo && errorInfo) : Error(errorInfo) , state(state) { } template explicit EvalError(EvalState & state, const std::string & formatString, const Args &... formatArgs) : Error(formatString, formatArgs...) , state(state) { } }; MakeError(ParseError, Error); MakeError(AssertionError, EvalError); MakeError(ThrownError, AssertionError); MakeError(Abort, EvalError); MakeError(TypeError, EvalError); MakeError(UndefinedVarError, EvalError); MakeError(MissingArgumentError, EvalError); MakeError(CachedEvalError, EvalError); MakeError(InfiniteRecursionError, EvalError); struct InvalidPathError : public EvalError { public: Path path; InvalidPathError(EvalState & state, const Path & path) : EvalError(state, "path '%s' is not valid", path) { } }; template class EvalErrorBuilder final { friend class EvalState; template explicit EvalErrorBuilder(EvalState & state, const Args &... args) : error(T(state, args...)) { } public: T error; [[nodiscard, gnu::noinline]] EvalErrorBuilder & withExitStatus(unsigned int exitStatus); [[nodiscard, gnu::noinline]] EvalErrorBuilder & atPos(PosIdx pos); [[nodiscard, gnu::noinline]] EvalErrorBuilder & atPos(Value & value, PosIdx fallback = noPos); [[nodiscard, gnu::noinline]] EvalErrorBuilder & withTrace(PosIdx pos, const std::string_view text); [[nodiscard, gnu::noinline]] EvalErrorBuilder & withFrameTrace(PosIdx pos, const std::string_view text); [[nodiscard, gnu::noinline]] EvalErrorBuilder & withSuggestions(Suggestions & s); [[nodiscard, gnu::noinline]] EvalErrorBuilder & withFrame(const Env & e, const Expr & ex); [[nodiscard, gnu::noinline]] EvalErrorBuilder & addTrace(PosIdx pos, hintformat hint, bool frame = false); template [[nodiscard, gnu::noinline]] EvalErrorBuilder & addTrace(PosIdx pos, std::string_view formatString, const Args &... formatArgs); [[gnu::noinline, gnu::noreturn]] void debugThrow(); }; /** * The size needed to allocate any `EvalErrorBuilder`. * * The list of classes here needs to be kept in sync with the list of `template * class` declarations in `eval-error.cc`. * * This is used by `EvalState` to preallocate a buffer of sufficient size for * any `EvalErrorBuilder` to avoid allocating while evaluating Nix code. */ constexpr size_t EVAL_ERROR_BUILDER_SIZE = std::max({ sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), sizeof(EvalErrorBuilder), }); }