diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 82b35d16f..3e789adba 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -126,7 +126,7 @@ ref EvalCommand::getEvalState() new DebugTraceStacker( *evalState, DebugTrace - {.pos = (error->info().errPos ? *error->info().errPos : *expr.getPos()), + {.pos = (error->info().errPos ? *error->info().errPos : evalState->positions[expr.getPos()]), .expr = expr, .env = env, .hint = error->info().msg, @@ -139,7 +139,7 @@ ref EvalCommand::getEvalState() if (expr.staticenv) { - std::unique_ptr vm(mapStaticEnvBindings(*expr.staticenv.get(), env)); + std::unique_ptr vm(mapStaticEnvBindings(evalState->symbols, *expr.staticenv.get(), env)); runRepl(evalState, expr, *vm); } }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index d9ba7e7a4..40299e910 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -203,7 +203,7 @@ namespace { } } -std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) +std::ostream& showDebugTrace(std::ostream &out, const PosTable &positions, const DebugTrace &dt) { if (dt.is_error) out << ANSI_RED "error: " << ANSI_NORMAL; @@ -211,7 +211,7 @@ std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt) // prefer direct pos, but if noPos then try the expr. auto pos = (*dt.pos ? *dt.pos : - (dt.expr.getPos() ? *dt.expr.getPos() : noPos)); + positions[(dt.expr.getPos() ? dt.expr.getPos() : noPos)]); if (pos) { printAtPos(pos, out); @@ -280,7 +280,7 @@ void NixRepl::mainLoop(const std::vector & files) // when that session returns the exception will land here. No need to show it again; // show the error for this repl session instead. if (debuggerHook && !this->state->debugTraces.empty()) - showDebugTrace(std::cout, this->state->debugTraces.front()); + showDebugTrace(std::cout, this->state->positions, this->state->debugTraces.front()); else printMsg(lvlError, e.msg()); } catch (Error & e) { @@ -443,7 +443,7 @@ void NixRepl::loadDebugTraceEnv(DebugTrace &dt) { initEnv(); - auto vm = std::make_unique(*(mapStaticEnvBindings(*dt.expr.staticenv.get(), dt.env))); + auto vm = std::make_unique(*(mapStaticEnvBindings(this->state->symbols, *dt.expr.staticenv.get(), dt.env))); // add staticenv vars. for (auto & [name, value] : *(vm.get())) { @@ -514,7 +514,7 @@ bool NixRepl::processLine(std::string line) iter != this->state->debugTraces.end(); ++iter, ++idx) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, *iter); + showDebugTrace(std::cout, this->state->positions, *iter); } } else if (arg == "env") { int idx = 0; @@ -523,7 +523,7 @@ bool NixRepl::processLine(std::string line) ++iter, ++idx) { if (idx == this->debugTraceIndex) { - printEnvBindings(iter->expr, iter->env); + printEnvBindings(state->symbols,iter->expr, iter->env); break; } } @@ -544,9 +544,9 @@ bool NixRepl::processLine(std::string line) if (idx == this->debugTraceIndex) { std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, *iter); + showDebugTrace(std::cout, this->state->positions, *iter); std::cout << std::endl; - printEnvBindings(iter->expr, iter->env); + printEnvBindings(state->symbols,iter->expr, iter->env); loadDebugTraceEnv(*iter); break; } diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 4e0826101..f2f4ba725 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -103,7 +103,7 @@ void EvalState::forceValue(Value & v, Callable getPos) else if (v.isApp()) callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.isBlackhole()) - throwEvalError(getPos(), "infinite recursion encountered", *this); + throwEvalError(getPos(), "infinite recursion encountered"); } @@ -120,7 +120,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos) { forceValue(v, getPos); if (v.type() != nAttrs) - throwTypeError(getPos(), "value is %1% while a set was expected", v, *this); + throwTypeError(getPos(), "value is %1% while a set was expected", v); } @@ -129,7 +129,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos) { forceValue(v, pos); if (!v.isList()) - throwTypeError(pos, "value is %1% while a list was expected", v, *this); + throwTypeError(pos, "value is %1% while a list was expected", v); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 896242e0c..7058d117f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -714,19 +714,19 @@ std::optional EvalState::getDoc(Value & v) // just for the current level of StaticEnv, not the whole chain. -void printStaticEnvBindings(const StaticEnv &se) +void printStaticEnvBindings(const SymbolTable &st, const StaticEnv &se) { std::cout << ANSI_MAGENTA; for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { - std::cout << i->first << " "; + std::cout << st[i->first] << " "; } std::cout << ANSI_NORMAL; std::cout << std::endl; } // just for the current level of Env, not the whole chain. -void printWithBindings(const Env &env) +void printWithBindings(const SymbolTable &st, const Env &env) { if (env.type == Env::HasWithAttrs) { @@ -734,7 +734,7 @@ void printWithBindings(const Env &env) std::cout << ANSI_MAGENTA; Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - std::cout << j->name << " "; + std::cout << st[j->name] << " "; ++j; } std::cout << ANSI_NORMAL; @@ -742,16 +742,16 @@ void printWithBindings(const Env &env) } } -void printEnvBindings(const StaticEnv &se, const Env &env, int lvl) +void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl) { std::cout << "Env level " << lvl << std::endl; if (se.up && env.up) { std::cout << "static: "; - printStaticEnvBindings(se); - printWithBindings(env); + printStaticEnvBindings(st, se); + printWithBindings(st, env); std::cout << std::endl; - printEnvBindings(*se.up, *env.up, ++lvl); + printEnvBindings(st, *se.up, *env.up, ++lvl); } else { @@ -759,41 +759,41 @@ void printEnvBindings(const StaticEnv &se, const Env &env, int lvl) // for the top level, don't print the double underscore ones; they are in builtins. for (auto i = se.vars.begin(); i != se.vars.end(); ++i) { - if (((std::string)i->first).substr(0,2) != "__") - std::cout << i->first << " "; + if (((std::string)st[i->first]).substr(0,2) != "__") + std::cout << st[i->first] << " "; } std::cout << ANSI_NORMAL; std::cout << std::endl; - printWithBindings(env); // probably nothing there for the top level. + printWithBindings(st, env); // probably nothing there for the top level. std::cout << std::endl; } } // TODO: add accompanying env for With stuff. -void printEnvBindings(const Expr &expr, const Env &env) +void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env) { // just print the names for now if (expr.staticenv) { - printEnvBindings(*expr.staticenv.get(), env, 0); + printEnvBindings(st, *expr.staticenv.get(), env, 0); } } -void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) +void mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, valmap & vm) { // add bindings for the next level up first, so that the bindings for this level // override the higher levels. // The top level bindings (builtins) are skipped since they are added for us by initEnv() if (env.up && se.up) { - mapStaticEnvBindings(*se.up, *env.up, vm); + mapStaticEnvBindings(st, *se.up, *env.up, vm); if (env.type == Env::HasWithAttrs) { // add 'with' bindings. Bindings::iterator j = env.values[0]->attrs->begin(); while (j != env.values[0]->attrs->end()) { - vm[j->name] = j->value; + vm[st[j->name]] = j->value; ++j; } } @@ -802,24 +802,45 @@ void mapStaticEnvBindings(const StaticEnv &se, const Env &env, valmap & vm) // iterate through staticenv bindings and add them. for (auto iter = se.vars.begin(); iter != se.vars.end(); ++iter) { - vm[iter->first] = env.values[iter->second]; + vm[st[iter->first]] = env.values[iter->second]; } } } } -valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env) +valmap * mapStaticEnvBindings(const SymbolTable &st,const StaticEnv &se, const Env &env) { auto vm = new valmap(); - mapStaticEnvBindings(se, env, *vm); + mapStaticEnvBindings(st, se, env, *vm); return vm; } +void EvalState::debugLastTrace(Error & e) const { + // call this in the situation where Expr and Env are inaccessible. The debugger will start in the last context + // that's in the DebugTrace stack. + if (debuggerHook && !debugTraces.empty()) { + const DebugTrace &last = debugTraces.front(); + debuggerHook(&e, last.env, last.expr); + } +} + /* Every "format" object (even temporary) takes up a few hundred bytes of stack space, which is a real killer in the recursive evaluator. So here are some helper functions for throwing exceptions. */ +void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr &expr) const +{ + auto error = EvalError({ + .msg = hintfmt(s), + .errPos = positions[pos] + }); + + if (debuggerHook) + debuggerHook(&error, env, expr); + + throw error; +} void EvalState::throwEvalError(const PosIdx pos, const char * s) const { @@ -828,25 +849,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s) const .errPos = positions[pos] }); - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } - - throw error; -} - -void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const -{ - auto error = TypeError({ - .msg = hintfmt(s, showType(v)), - .errPos = positions[pos] - }); - - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + debugLastTrace(error); throw error; } @@ -855,23 +858,11 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) const { auto error = EvalError(s, s2); - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&error, last.env, last.expr); - } + debugLastTrace(error); throw error; } -void EvalState::debugLastTrace(Error & e) { - // call this in the situation where Expr and Env are inaccessible. The debugger will start in the last context - // that's in the DebugTrace stack. - if (debuggerHook && !debugTraces.empty()) { - DebugTrace &last = debugTraces.front(); - debuggerHook(&e, last.env, last.expr); - } -} - void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr &expr) const { @@ -899,16 +890,43 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri throw error; } -void EvalState::throwEvalError(const char * s, const std::string & s2, const std::string & s3, Env & env, Expr &expr) const +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr &expr) const { auto error = EvalError({ - .msg = hintfmt(s), - .errPos = pos + .msg = hintfmt(s, s2), + .errPos = positions[pos] }); if (debuggerHook) debuggerHook(&error, env, expr); + + throw error; +} + +void EvalState::throwEvalError(const char * s, const std::string & s2, + const std::string & s3) const +{ + auto error = EvalError({ + .msg = hintfmt(s, s2), + .errPos = positions[noPos] + }); + + debugLastTrace(error); + + throw error; +} + +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, + const std::string & s3) const +{ + auto error = EvalError({ + .msg = hintfmt(s, s2), + .errPos = positions[pos] + }); + + debugLastTrace(error); + throw error; } @@ -917,7 +935,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri { auto error = EvalError({ .msg = hintfmt(s, s2), - .errPos = pos + .errPos = positions[pos] }); if (debuggerHook) @@ -966,6 +984,31 @@ void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym throw error; } +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) const +{ + auto error = TypeError({ + .msg = hintfmt(s, showType(v)), + .errPos = positions[pos] + }); + + debugLastTrace(error); + + throw error; +} + +void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr &expr) const +{ + auto error = TypeError({ + .msg = hintfmt(s, showType(v)), + .errPos = positions[pos] + }); + + if (debuggerHook) + debuggerHook(&error, env, expr); + + throw error; +} + void EvalState::throwTypeError(const PosIdx pos, const char * s) const { auto error = TypeError({ @@ -973,7 +1016,7 @@ void EvalState::throwTypeError(const PosIdx pos, const char * s) const .errPos = positions[pos] }); - evalState.debugLastTrace(error); + debugLastTrace(error); throw error; } @@ -1010,9 +1053,8 @@ void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) const { auto error = TypeError({ - .msg = hintfmt(s, fun.showNamePos(), s2), - .errPos = pos, - .suggestions = suggestions, + .msg = hintfmt(s, showType(v)), + .errPos = positions[expr.getPos()], }); if (debuggerHook) @@ -1070,8 +1112,8 @@ void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const e.addTrace(positions[pos], s, s2); } -LocalNoInline(std::unique_ptr - makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, std::optional pos, const char * s, const std::string & s2)) +std::unique_ptr makeDebugTraceStacker(EvalState &state, Expr &expr, Env &env, + std::optional pos, const char * s, const std::string & s2) { return std::unique_ptr( new DebugTraceStacker( @@ -1150,7 +1192,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name], *env, var); + throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name], *env, const_cast(var)); for (size_t l = env->prevWith; l; --l, env = env->up) ; } } @@ -1293,7 +1335,7 @@ void EvalState::cacheFile( *this, *e, this->baseEnv, - (e->getPos() ? std::optional(ErrPos(*e->getPos())) : std::nullopt), + (e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt), "while evaluating the file '%1%':", resolvedPath) : nullptr; @@ -1528,7 +1570,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) state, *this, env, - *pos2, + state.positions[pos2], "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)) : nullptr; @@ -1694,10 +1736,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & try { auto dts = debuggerHook ? - makeDebugTraceStacker(*this, *lambda.body, env2, lambda.pos, + makeDebugTraceStacker(*this, *lambda.body, env2, positions[lambda.pos], "while evaluating %s", - (lambda.name.set() - ? "'" + (std::string) lambda.name + "'" + (lambda.name + ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda")) : nullptr; @@ -1786,7 +1828,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } else - throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur, *this); + throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur); } vRes = vCur; @@ -1855,7 +1897,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/#ss-functions.)", symbols[i.name],, +https://nixos.org/manual/nix/stable/#ss-functions.)", symbols[i.name], *fun.lambda.env, *fun.lambda.fun); } } @@ -2092,7 +2134,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) v.mkFloat(nf); else if (firstType == nPath) { if (!context.empty()) - state.throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, *this);); + state.throwEvalError(pos, "a string that refers to a store path cannot be appended to a path", env, *this); v.mkPath(canonPath(str())); } else v.mkStringMove(c_str(), context); @@ -2124,8 +2166,8 @@ void EvalState::forceValueDeep(Value & v) debuggerHook ? // if the value is a thunk, we're evaling. otherwise no trace necessary. (i.value->isThunk() ? - makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, *i.pos, - "while evaluating the attribute '%1%'", i.name) + makeDebugTraceStacker(*this, *v.thunk.expr, *v.thunk.env, positions[i.pos], + "while evaluating the attribute '%1%'", symbols[i.name]) : nullptr) : nullptr; @@ -2150,7 +2192,7 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nInt) - throwTypeError(pos, "value is %1% while an integer was expected", v, *this); + throwTypeError(pos, "value is %1% while an integer was expected", v); return v.integer; } @@ -2162,7 +2204,7 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos) if (v.type() == nInt) return v.integer; else if (v.type() != nFloat) - throwTypeError(pos, "value is %1% while a float was expected", v, *this); + throwTypeError(pos, "value is %1% while a float was expected", v); return v.fpoint; } @@ -2171,7 +2213,7 @@ bool EvalState::forceBool(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nBool) - throwTypeError(pos, "value is %1% while a Boolean was expected", v, *this); + throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -2186,7 +2228,7 @@ void EvalState::forceFunction(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) - throwTypeError(pos, "value is %1% while a function was expected", v, *this); + throwTypeError(pos, "value is %1% while a function was expected", v); } @@ -2194,7 +2236,7 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos) { forceValue(v, pos); if (v.type() != nString) { - throwTypeError(pos, "value is %1% while a string was expected", v, *this); + throwTypeError(pos, "value is %1% while a string was expected", v); } return v.string.s; } @@ -2254,10 +2296,10 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos) if (v.string.context) { if (pos) throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], *this); + v.string.s, v.string.context[0]); else throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0], *this); + v.string.s, v.string.context[0]); } return s; } @@ -2312,7 +2354,7 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet return std::move(*maybeString); auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) - throwTypeError(pos, "cannot coerce a set to a string", *this); + throwTypeError(pos, "cannot coerce a set to a string"); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -2341,14 +2383,14 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet } } - throwTypeError(pos, "cannot coerce %1% to a string", v, *this); + throwTypeError(pos, "cannot coerce %1% to a string", v); } std::string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) - throwEvalError("file names are not allowed to end in '%1%'", drvExtension, *this); + throwEvalError("file names are not allowed to end in '%1%'", drvExtension); Path dstPath; auto i = srcToStore.find(path); @@ -2373,7 +2415,7 @@ Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context) { auto path = coerceToString(pos, v, context, false, false).toOwned(); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path, *this); + throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); return path; } @@ -2466,8 +2508,7 @@ bool EvalState::eqValues(Value & v1, Value & v2) default: throwEvalError("cannot compare %1% with %2%", showType(v1), - showType(v2), - *this); + showType(v2)); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 76bd63ca6..2e7df13fc 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -25,8 +25,8 @@ enum RepairFlag : bool; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); -void printEnvBindings(const Expr &expr, const Env &env); -void printEnvBindings(const StaticEnv &se, const Env &env, int lvl = 0); +void printEnvBindings(const SymbolTable &st, const Expr &expr, const Env &env); +void printEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env, int lvl = 0); struct PrimOp { @@ -47,7 +47,7 @@ struct Env Value * values[0]; }; -valmap * mapStaticEnvBindings(const StaticEnv &se, const Env &env); +valmap * mapStaticEnvBindings(const SymbolTable &st, const StaticEnv &se, const Env &env); void copyContext(const Value & v, PathSet & context); @@ -123,7 +123,7 @@ public: bool debugStop; bool debugQuit; std::list debugTraces; - void debugLastTrace(Error & e); + void debugLastTrace(Error & e) const; private: SrcToStore srcToStore; @@ -273,35 +273,66 @@ public: [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const Value & v) const; + void throwEvalError(const PosIdx pos, const char * s, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const char * s, const std::string & s2) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const std::string & s2) const; - [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; + void throwEvalError(const char * s, const std::string & s2, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const char * s, const std::string & s2, const std::string & s3, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) const; [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2) const; + void throwEvalError(const char * s, const std::string & s2, const std::string & s3) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, + Env & env, Expr &expr) const; + [[gnu::noinline, gnu::noreturn]] + void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, + Env & env, Expr & expr) const; + + [[gnu::noinline, gnu::noreturn]] + void throwTypeError(const PosIdx pos, const char * s, const Value & v) const; + [[gnu::noinline, gnu::noreturn]] + void throwTypeError(const PosIdx pos, const char * s, const Value & v, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2) const; + void throwTypeError(const PosIdx pos, const char * s, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol s2) const; + void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const char * s, const Value & v) const; + void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol s2, + Env & env, Expr & expr) const; [[gnu::noinline, gnu::noreturn]] - void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwTypeError(const char * s, const Value & v, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] - void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; + [[gnu::noinline, gnu::noreturn]] - void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1) const; + void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; + + [[gnu::noinline, gnu::noreturn]] + void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, + Env & env, Expr & expr) const; [[gnu::noinline]] void addErrorTrace(Error & e, const char * s, const std::string & s2) const; @@ -480,7 +511,7 @@ private: class DebugTraceStacker { public: DebugTraceStacker(EvalState &evalState, DebugTrace t); - ~DebugTraceStacker() + ~DebugTraceStacker() { // assert(evalState.debugTraces.front() == trace); evalState.debugTraces.pop_front(); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index efaeba7c6..c6e545729 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -437,11 +437,11 @@ void ExprLambda::bindVars(const EvalState & es, const std::shared_ptrformals.size() : 0) + - (!arg ? 0 : 1)); + (!arg ? 0 : 1))); Displacement displ = 0; - if (arg) newEnv.vars.emplace_back(arg, displ++); + if (arg) newEnv->vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) @@ -506,7 +506,7 @@ void ExprWith::bindVars(const EvalState & es, const std::shared_ptrbindVars(es, env); - StaticEnv newEnv(true, &env); + auto newEnv = std::shared_ptr(new StaticEnv(true, env.get())); body->bindVars(es, newEnv); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index d275a51e9..82fff6dcf 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -278,7 +278,12 @@ struct ExprList : Expr { std::vector elems; ExprList() { }; - const PosIdx getPos() const { return pos; } + const PosIdx getPos() const + { if (elems.empty()) + return noPos; + else + return elems.front()->getPos(); + } COMMON_METHODS }; @@ -389,7 +394,7 @@ struct ExprOpNot : Expr { Expr * e; ExprOpNot(Expr * e) : e(e) { }; - const Pos* getPos() const { return 0; } + const PosIdx getPos() const { return noPos; } COMMON_METHODS }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 212ce3de9..e2267d154 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -774,12 +774,14 @@ static RegisterPrimOp primop_break({ .doc = R"( In debug mode, pause Nix expression evaluation and enter the repl. )", - .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) + .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { + PathSet context; + auto s = state.coerceToString(pos, *args[0], context).toOwned(); auto error = Error(ErrorInfo{ .level = lvlInfo, - .msg = hintfmt("breakpoint reached; value was %1%", *args[0]), - .errPos = pos, + .msg = hintfmt("breakpoint reached; value was %1%", s), + .errPos = state.positions[pos], }); if (debuggerHook && !state.debugTraces.empty()) { @@ -791,7 +793,7 @@ static RegisterPrimOp primop_break({ throw Error(ErrorInfo{ .level = lvlInfo, .msg = hintfmt("quit from debugger"), - .errPos = noPos, + .errPos = state.positions[noPos], }); }