libexpr: associate error creation and debugging with EvalContext

Change-Id: I80beedd0c58361ebc67cebcee97d64879baed050
This commit is contained in:
eldritch horrors 2024-12-03 20:38:41 +01:00
parent 2f2bc90d92
commit d30027a37a
12 changed files with 142 additions and 142 deletions

View file

@ -56,7 +56,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
if (!attrIndex) { if (!attrIndex) {
if (v->type() != nAttrs) if (v->type() != nAttrs)
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"the expression selected by the selection path '%1%' should be a set but is %2%", "the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath, attrPath,
showType(*v)).debugThrow(); showType(*v)).debugThrow();
@ -79,7 +79,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
else { else {
if (!v->isList()) if (!v->isList())
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"the expression selected by the selection path '%1%' should be a list but is %2%", "the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath, attrPath,
showType(*v)).debugThrow(); showType(*v)).debugThrow();

View file

@ -552,14 +552,14 @@ std::string AttrCursor::getString(EvalState & state)
debug("using cached string attribute '%s'", getAttrPathStr(state)); debug("using cached string attribute '%s'", getAttrPathStr(state));
return s->first; return s->first;
} else } else
state.errors.make<TypeError>("'%s' is not a string", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a string", getAttrPathStr(state)).debugThrow();
} }
} }
auto & v = forceValue(state); auto & v = forceValue(state);
if (v.type() != nString && v.type() != nPath) { if (v.type() != nString && v.type() != nPath) {
state.errors.make<TypeError>("'%s' is not a string but %s", getAttrPathStr(state), v.type()).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a string but %s", getAttrPathStr(state), v.type()).debugThrow();
} }
return v.type() == nString ? v.string.s : v.path().to_string(); return v.type() == nString ? v.string.s : v.path().to_string();
@ -595,7 +595,7 @@ string_t AttrCursor::getStringWithContext(EvalState & state)
return *s; return *s;
} }
} else } else
state.errors.make<TypeError>("'%s' is not a string", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a string", getAttrPathStr(state)).debugThrow();
} }
} }
@ -608,7 +608,7 @@ string_t AttrCursor::getStringWithContext(EvalState & state)
} else if (v.type() == nPath) { } else if (v.type() == nPath) {
return {v.path().to_string(), {}}; return {v.path().to_string(), {}};
} else { } else {
state.errors.make<TypeError>("'%s' is not a string but %s", getAttrPathStr(state), v.type()).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a string but %s", getAttrPathStr(state), v.type()).debugThrow();
} }
} }
@ -622,14 +622,14 @@ bool AttrCursor::getBool(EvalState & state)
debug("using cached Boolean attribute '%s'", getAttrPathStr(state)); debug("using cached Boolean attribute '%s'", getAttrPathStr(state));
return *b; return *b;
} else } else
state.errors.make<TypeError>("'%s' is not a Boolean", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a Boolean", getAttrPathStr(state)).debugThrow();
} }
} }
auto & v = forceValue(state); auto & v = forceValue(state);
if (v.type() != nBool) if (v.type() != nBool)
state.errors.make<TypeError>("'%s' is not a Boolean", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a Boolean", getAttrPathStr(state)).debugThrow();
return v.boolean; return v.boolean;
} }
@ -644,14 +644,14 @@ NixInt AttrCursor::getInt(EvalState & state)
debug("using cached integer attribute '%s'", getAttrPathStr(state)); debug("using cached integer attribute '%s'", getAttrPathStr(state));
return i->x; return i->x;
} else } else
state.errors.make<TypeError>("'%s' is not an integer", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not an integer", getAttrPathStr(state)).debugThrow();
} }
} }
auto & v = forceValue(state); auto & v = forceValue(state);
if (v.type() != nInt) if (v.type() != nInt)
state.errors.make<TypeError>("'%s' is not an integer", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not an integer", getAttrPathStr(state)).debugThrow();
return v.integer; return v.integer;
} }
@ -666,7 +666,7 @@ std::vector<std::string> AttrCursor::getListOfStrings(EvalState & state)
debug("using cached list of strings attribute '%s'", getAttrPathStr(state)); debug("using cached list of strings attribute '%s'", getAttrPathStr(state));
return *l; return *l;
} else } else
state.errors.make<TypeError>("'%s' is not a list of strings", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a list of strings", getAttrPathStr(state)).debugThrow();
} }
} }
@ -676,7 +676,7 @@ std::vector<std::string> AttrCursor::getListOfStrings(EvalState & state)
state.forceValue(v, noPos); state.forceValue(v, noPos);
if (v.type() != nList) if (v.type() != nList)
state.errors.make<TypeError>("'%s' is not a list", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not a list", getAttrPathStr(state)).debugThrow();
std::vector<std::string> res; std::vector<std::string> res;
@ -699,14 +699,14 @@ std::vector<std::string> AttrCursor::getAttrs(EvalState & state)
debug("using cached attrset attribute '%s'", getAttrPathStr(state)); debug("using cached attrset attribute '%s'", getAttrPathStr(state));
return attrs->p; return attrs->p;
} else } else
state.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr(state)).debugThrow();
} }
} }
auto & v = forceValue(state); auto & v = forceValue(state);
if (v.type() != nAttrs) if (v.type() != nAttrs)
state.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr(state)).debugThrow(); state.ctx.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr(state)).debugThrow();
fullattr_t attrs; fullattr_t attrs;
for (auto & attr : *getValue(state).attrs) for (auto & attr : *getValue(state).attrs)

View file

@ -91,7 +91,7 @@ inline void EvalState::forceAttrs(Value & v, const PosIdx pos, std::string_view
{ {
forceValue(v, pos); forceValue(v, pos);
if (v.type() != nAttrs) { if (v.type() != nAttrs) {
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a set but found %1%: %2%", "expected a set but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -105,7 +105,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos, std::string_view e
{ {
forceValue(v, pos); forceValue(v, pos);
if (!v.isList()) { if (!v.isList()) {
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a list but found %1%: %2%", "expected a list but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)

View file

@ -618,7 +618,7 @@ void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env &
void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env) void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env)
{ {
// just print the names for now // just print the names for now
auto se = es.debug->staticEnvFor(expr); auto se = es.ctx.debug->staticEnvFor(expr);
if (se) if (se)
printEnvBindings(es.ctx.symbols, *se, env, 0); printEnvBindings(es.ctx.symbols, *se, env, 0);
} }
@ -739,15 +739,15 @@ static DebugState::TraceFrame makeDebugTraceStacker(
std::shared_ptr<Pos> && pos, std::shared_ptr<Pos> && pos,
const Args & ... formatArgs) const Args & ... formatArgs)
{ {
auto trace = state.debug->addTrace(DebugTrace{ auto trace = state.ctx.debug->addTrace(DebugTrace{
.pos = std::move(pos), .pos = std::move(pos),
.expr = expr, .expr = expr,
.env = env, .env = env,
.hint = HintFmt(formatArgs...), .hint = HintFmt(formatArgs...),
.isError = false, .isError = false,
}); });
if (state.debug->stop && state.debug->errorCallback) if (state.ctx.debug->stop && state.ctx.debug->errorCallback)
state.debug->onEvalError(nullptr, env, expr); state.ctx.debug->onEvalError(nullptr, env, expr);
return trace; return trace;
} }
@ -771,7 +771,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
return j->value; return j->value;
} }
if (!fromWith->parentWith) if (!fromWith->parentWith)
errors.make<UndefinedVarError>("undefined variable '%1%'", ctx.symbols[var.name]).atPos(var.pos).withFrame(*env, var).debugThrow(); ctx.errors.make<UndefinedVarError>("undefined variable '%1%'", ctx.symbols[var.name]).atPos(var.pos).withFrame(*env, var).debugThrow();
for (size_t l = fromWith->prevWith; l; --l, env = env->up) ; for (size_t l = fromWith->prevWith; l; --l, env = env->up) ;
fromWith = fromWith->parentWith; fromWith = fromWith->parentWith;
} }
@ -956,7 +956,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v)
Expr & e = parseExprFromFile(paths.checkSourcePath(resolvedPath)); Expr & e = parseExprFromFile(paths.checkSourcePath(resolvedPath));
try { try {
auto dts = debug auto dts = ctx.debug
? makeDebugTraceStacker( ? makeDebugTraceStacker(
*this, *this,
e, e,
@ -995,7 +995,7 @@ inline bool EvalState::evalBool(Env & env, Expr & e, const PosIdx pos, std::stri
Value v; Value v;
e.eval(*this, env, v); e.eval(*this, env, v);
if (v.type() != nBool) if (v.type() != nBool)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a Boolean but found %1%: %2%", "expected a Boolean but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -1013,7 +1013,7 @@ inline void EvalState::evalAttrs(Env & env, Expr & e, Value & v, const PosIdx po
try { try {
e.eval(*this, env, v); e.eval(*this, env, v);
if (v.type() != nAttrs) if (v.type() != nAttrs)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a set but found %1%: %2%", "expected a set but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -1146,7 +1146,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
auto nameSym = state.ctx.symbols.create(nameVal.string.s); auto nameSym = state.ctx.symbols.create(nameVal.string.s);
Bindings::iterator j = v.attrs->find(nameSym); Bindings::iterator j = v.attrs->find(nameSym);
if (j != v.attrs->end()) if (j != v.attrs->end())
state.errors.make<EvalError>("dynamic attribute '%1%' already defined at %2%", state.ctx.symbols[nameSym], state.ctx.positions[j->pos]).atPos(i.pos).withFrame(env, *this).debugThrow(); state.ctx.errors.make<EvalError>("dynamic attribute '%1%' already defined at %2%", state.ctx.symbols[nameSym], state.ctx.positions[j->pos]).atPos(i.pos).withFrame(env, *this).debugThrow();
i.valueExpr->setName(nameSym); i.valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */ /* Keep sorted order so find can catch duplicates */
@ -1177,7 +1177,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
*i.second.chooseByKind(&env2, &env, inheritEnv)); *i.second.chooseByKind(&env2, &env, inheritEnv));
} }
auto dts = state.debug auto dts = state.ctx.debug
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -1261,7 +1261,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} }
try { try {
auto dts = state.debug auto dts = state.ctx.debug
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -1321,7 +1321,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} }
// Otherwise, we must type error. // Otherwise, we must type error.
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"expected a set but found %s: %s", "expected a set but found %s: %s",
showType(*vCurrent), showType(*vCurrent),
ValuePrinter(state, *vCurrent, errorPrintOptions) ValuePrinter(state, *vCurrent, errorPrintOptions)
@ -1348,7 +1348,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
allAttrNames.insert(state.ctx.symbols[attr.name]); allAttrNames.insert(state.ctx.symbols[attr.name]);
} }
auto suggestions = Suggestions::bestMatches(allAttrNames, state.ctx.symbols[name]); auto suggestions = Suggestions::bestMatches(allAttrNames, state.ctx.symbols[name]);
state.errors.make<EvalError>("attribute '%s' missing", state.ctx.symbols[name]) state.ctx.errors.make<EvalError>("attribute '%s' missing", state.ctx.symbols[name])
.atPos(pos) .atPos(pos)
.withSuggestions(suggestions) .withSuggestions(suggestions)
.withFrame(env, *this) .withFrame(env, *this)
@ -1484,7 +1484,7 @@ FormalsMatch matchupFormals(EvalState & state, Env & env, Displacement & displ,
void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos) void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos)
{ {
if (callDepth > evalSettings.maxCallDepth) if (callDepth > evalSettings.maxCallDepth)
errors.make<EvalError>("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow(); ctx.errors.make<EvalError>("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow();
CallDepth _level(callDepth); CallDepth _level(callDepth);
auto trace = evalSettings.traceFunctionCalls auto trace = evalSettings.traceFunctionCalls
@ -1546,7 +1546,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
); );
for (auto const & missingArg : formalsMatch.missing) { for (auto const & missingArg : formalsMatch.missing) {
auto const missing = ctx.symbols[missingArg]; auto const missing = ctx.symbols[missingArg];
errors.make<TypeError>("function '%s' called without required argument '%s'", lambda.getName(ctx.symbols), missing) ctx.errors.make<TypeError>("function '%s' called without required argument '%s'", lambda.getName(ctx.symbols), missing)
.atPos(lambda.pos) .atPos(lambda.pos)
.withTrace(pos, "from call site") .withTrace(pos, "from call site")
.withFrame(*fun.lambda.env, lambda) .withFrame(*fun.lambda.env, lambda)
@ -1559,7 +1559,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
formalNames.insert(ctx.symbols[formal.name]); formalNames.insert(ctx.symbols[formal.name]);
} }
auto sug = Suggestions::bestMatches(formalNames, unex); auto sug = Suggestions::bestMatches(formalNames, unex);
errors.make<TypeError>("function '%s' called with unexpected argument '%s'", lambda.getName(ctx.symbols), unex) ctx.errors.make<TypeError>("function '%s' called with unexpected argument '%s'", lambda.getName(ctx.symbols), unex)
.atPos(lambda.pos) .atPos(lambda.pos)
.withTrace(pos, "from call site") .withTrace(pos, "from call site")
.withSuggestions(sug) .withSuggestions(sug)
@ -1575,7 +1575,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
/* Evaluate the body. */ /* Evaluate the body. */
try { try {
auto dts = debug auto dts = ctx.debug
? makeDebugTraceStacker( ? makeDebugTraceStacker(
*this, *lambda.body, env2, ctx.positions[lambda.pos], *this, *lambda.body, env2, ctx.positions[lambda.pos],
"while calling %s", "while calling %s",
@ -1700,7 +1700,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
} }
else else
errors.make<TypeError>( ctx.errors.make<TypeError>(
"attempt to call something which is not a function but %1%: %2%", "attempt to call something which is not a function but %1%: %2%",
showType(vCur), showType(vCur),
ValuePrinter(*this, vCur, errorPrintOptions)) ValuePrinter(*this, vCur, errorPrintOptions))
@ -1714,7 +1714,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
void ExprCall::eval(EvalState & state, Env & env, Value & v) void ExprCall::eval(EvalState & state, Env & env, Value & v)
{ {
auto dts = state.debug auto dts = state.ctx.debug
? makeDebugTraceStacker( ? makeDebugTraceStacker(
state, state,
*this, *this,
@ -1787,7 +1787,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
if (j != args.end()) { if (j != args.end()) {
attrs.insert(*j); attrs.insert(*j);
} else if (!i.def) { } else if (!i.def) {
errors.make<MissingArgumentError>(R"(cannot evaluate a function that has an argument without a value ('%1%') ctx.errors.make<MissingArgumentError>(R"(cannot evaluate a function that has an argument without a value ('%1%')
Nix attempted to evaluate a function as a top level expression; in Nix attempted to evaluate a function as a top level expression; in
this case it must have its arguments supplied either by default this case it must have its arguments supplied either by default
values, or passed explicitly with '--arg' or '--argstr'. See values, or passed explicitly with '--arg' or '--argstr'. See
@ -1823,7 +1823,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
if (!state.evalBool(env, *cond, pos, "in the condition of the assert statement")) { if (!state.evalBool(env, *cond, pos, "in the condition of the assert statement")) {
std::ostringstream out; std::ostringstream out;
cond->show(state.ctx.symbols, out); cond->show(state.ctx.symbols, out);
state.errors.make<AssertionError>("assertion '%1%' failed", out.str()).atPos(pos).withFrame(env, *this).debugThrow(); state.ctx.errors.make<AssertionError>("assertion '%1%' failed", out.str()).atPos(pos).withFrame(env, *this).debugThrow();
} }
body->eval(state, env, v); body->eval(state, env, v);
} }
@ -1998,7 +1998,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
if (auto checked = newN.valueChecked(); checked.has_value()) { if (auto checked = newN.valueChecked(); checked.has_value()) {
n = NixInt(*checked); n = NixInt(*checked);
} else { } else {
state.errors.make<EvalError>("integer overflow in adding %1% + %2%", n, vTmp.integer).atPos(i_pos).debugThrow(); state.ctx.errors.make<EvalError>("integer overflow in adding %1% + %2%", n, vTmp.integer).atPos(i_pos).debugThrow();
} }
} else if (vTmp.type() == nFloat) { } else if (vTmp.type() == nFloat) {
// Upgrade the type from int to float; // Upgrade the type from int to float;
@ -2006,14 +2006,14 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
nf = n.value; nf = n.value;
nf += vTmp.fpoint; nf += vTmp.fpoint;
} else } else
state.errors.make<EvalError>("cannot add %1% to an integer", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow(); state.ctx.errors.make<EvalError>("cannot add %1% to an integer", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
} else if (firstType == nFloat) { } else if (firstType == nFloat) {
if (vTmp.type() == nInt) { if (vTmp.type() == nInt) {
nf += vTmp.integer.value; nf += vTmp.integer.value;
} else if (vTmp.type() == nFloat) { } else if (vTmp.type() == nFloat) {
nf += vTmp.fpoint; nf += vTmp.fpoint;
} else } else
state.errors.make<EvalError>("cannot add %1% to a float", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow(); state.ctx.errors.make<EvalError>("cannot add %1% to a float", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
} else { } else {
if (s.empty()) s.reserve(es.size()); if (s.empty()) s.reserve(es.size());
/* skip canonization of first path, which would only be not /* skip canonization of first path, which would only be not
@ -2035,7 +2035,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
v.mkFloat(nf); v.mkFloat(nf);
else if (firstType == nPath) { else if (firstType == nPath) {
if (!context.empty()) if (!context.empty())
state.errors.make<EvalError>("a string that refers to a store path cannot be appended to a path").atPos(pos).withFrame(env, *this).debugThrow(); state.ctx.errors.make<EvalError>("a string that refers to a store path cannot be appended to a path").atPos(pos).withFrame(env, *this).debugThrow();
v.mkPath(CanonPath(canonPath(str()))); v.mkPath(CanonPath(canonPath(str())));
} else } else
v.mkStringMove(c_str(), context); v.mkStringMove(c_str(), context);
@ -2050,7 +2050,7 @@ void ExprPos::eval(EvalState & state, Env & env, Value & v)
void ExprBlackHole::eval(EvalState & state, Env & env, Value & v) void ExprBlackHole::eval(EvalState & state, Env & env, Value & v)
{ {
state.errors.make<InfiniteRecursionError>("infinite recursion encountered") state.ctx.errors.make<InfiniteRecursionError>("infinite recursion encountered")
.atPos(v.determinePos(noPos)) .atPos(v.determinePos(noPos))
.debugThrow(); .debugThrow();
} }
@ -2087,7 +2087,7 @@ void EvalState::forceValueDeep(Value & v)
for (auto & i : *v.attrs) for (auto & i : *v.attrs)
try { try {
// If the value is a thunk, we're evaling. Otherwise no trace necessary. // If the value is a thunk, we're evaling. Otherwise no trace necessary.
auto dts = debug && i.value->isThunk() auto dts = ctx.debug && i.value->isThunk()
? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, ctx.positions[i.pos], ? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, ctx.positions[i.pos],
"while evaluating the attribute '%1%'", ctx.symbols[i.name]) "while evaluating the attribute '%1%'", ctx.symbols[i.name])
: nullptr; : nullptr;
@ -2114,7 +2114,7 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos, std::string_view errorCt
try { try {
forceValue(v, pos); forceValue(v, pos);
if (v.type() != nInt) if (v.type() != nInt)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected an integer but found %1%: %2%", "expected an integer but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2136,7 +2136,7 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos, std::string_view err
if (v.type() == nInt) if (v.type() == nInt)
return v.integer.value; return v.integer.value;
else if (v.type() != nFloat) else if (v.type() != nFloat)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a float but found %1%: %2%", "expected a float but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2154,7 +2154,7 @@ bool EvalState::forceBool(Value & v, const PosIdx pos, std::string_view errorCtx
try { try {
forceValue(v, pos); forceValue(v, pos);
if (v.type() != nBool) if (v.type() != nBool)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a Boolean but found %1%: %2%", "expected a Boolean but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2180,7 +2180,7 @@ void EvalState::forceFunction(Value & v, const PosIdx pos, std::string_view erro
try { try {
forceValue(v, pos); forceValue(v, pos);
if (v.type() != nFunction && !isFunctor(v)) if (v.type() != nFunction && !isFunctor(v))
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a function but found %1%: %2%", "expected a function but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2197,7 +2197,7 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos, std::string
try { try {
forceValue(v, pos); forceValue(v, pos);
if (v.type() != nString) if (v.type() != nString)
errors.make<TypeError>( ctx.errors.make<TypeError>(
"expected a string but found %1%: %2%", "expected a string but found %1%: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2230,7 +2230,7 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
{ {
auto s = forceString(v, pos, errorCtx); auto s = forceString(v, pos, errorCtx);
if (v.string.context) { if (v.string.context) {
errors.make<EvalError>("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0]).withTrace(pos, errorCtx).debugThrow(); ctx.errors.make<EvalError>("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, v.string.context[0]).withTrace(pos, errorCtx).debugThrow();
} }
return s; return s;
} }
@ -2295,7 +2295,7 @@ BackedStringView EvalState::coerceToString(
return std::move(*maybeString); return std::move(*maybeString);
auto i = v.attrs->find(ctx.s.outPath); auto i = v.attrs->find(ctx.s.outPath);
if (i == v.attrs->end()) { if (i == v.attrs->end()) {
errors.make<TypeError>( ctx.errors.make<TypeError>(
"cannot coerce %1% to a string: %2%", "cannot coerce %1% to a string: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
@ -2345,7 +2345,7 @@ BackedStringView EvalState::coerceToString(
} }
} }
errors.make<TypeError>("cannot coerce %1% to a string: %2%", ctx.errors.make<TypeError>("cannot coerce %1% to a string: %2%",
showType(v), showType(v),
ValuePrinter(*this, v, errorPrintOptions) ValuePrinter(*this, v, errorPrintOptions)
) )
@ -2382,7 +2382,7 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
{ {
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned(); auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (path == "" || path[0] != '/') if (path == "" || path[0] != '/')
errors.make<EvalError>("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow(); ctx.errors.make<EvalError>("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow();
return CanonPath(path); return CanonPath(path);
} }
@ -2392,7 +2392,7 @@ StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, NixStringCon
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned(); auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (auto storePath = store->maybeParseStorePath(path)) if (auto storePath = store->maybeParseStorePath(path))
return *storePath; return *storePath;
errors.make<EvalError>("path '%1%' is not in the Nix store", path).withTrace(pos, errorCtx).debugThrow(); ctx.errors.make<EvalError>("path '%1%' is not in the Nix store", path).withTrace(pos, errorCtx).debugThrow();
} }
@ -2402,7 +2402,7 @@ std::pair<SingleDerivedPath, std::string_view> EvalState::coerceToSingleDerivedP
auto s = forceString(v, context, pos, errorCtx); auto s = forceString(v, context, pos, errorCtx);
auto csize = context.size(); auto csize = context.size();
if (csize != 1) if (csize != 1)
errors.make<EvalError>( ctx.errors.make<EvalError>(
"string '%s' has %d entries in its context. It should only have exactly one entry", "string '%s' has %d entries in its context. It should only have exactly one entry",
s, csize) s, csize)
.withTrace(pos, errorCtx).debugThrow(); .withTrace(pos, errorCtx).debugThrow();
@ -2411,7 +2411,7 @@ std::pair<SingleDerivedPath, std::string_view> EvalState::coerceToSingleDerivedP
return std::move(o); return std::move(o);
}, },
[&](NixStringContextElem::DrvDeep &&) -> SingleDerivedPath { [&](NixStringContextElem::DrvDeep &&) -> SingleDerivedPath {
errors.make<EvalError>( ctx.errors.make<EvalError>(
"string '%s' has a context which refers to a complete source and binary closure. This is not supported at this time", "string '%s' has a context which refers to a complete source and binary closure. This is not supported at this time",
s).withTrace(pos, errorCtx).debugThrow(); s).withTrace(pos, errorCtx).debugThrow();
}, },
@ -2436,13 +2436,13 @@ SingleDerivedPath EvalState::coerceToSingleDerivedPath(const PosIdx pos, Value &
error message. */ error message. */
std::visit(overloaded { std::visit(overloaded {
[&](const SingleDerivedPath::Opaque & o) { [&](const SingleDerivedPath::Opaque & o) {
errors.make<EvalError>( ctx.errors.make<EvalError>(
"path string '%s' has context with the different path '%s'", "path string '%s' has context with the different path '%s'",
s, sExpected) s, sExpected)
.withTrace(pos, errorCtx).debugThrow(); .withTrace(pos, errorCtx).debugThrow();
}, },
[&](const SingleDerivedPath::Built & b) { [&](const SingleDerivedPath::Built & b) {
errors.make<EvalError>( ctx.errors.make<EvalError>(
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'", "string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
s, b.output, b.drvPath->to_string(*store), sExpected) s, b.output, b.drvPath->to_string(*store), sExpected)
.withTrace(pos, errorCtx).debugThrow(); .withTrace(pos, errorCtx).debugThrow();
@ -2527,7 +2527,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
case nThunk: // Must not be left by forceValue case nThunk: // Must not be left by forceValue
default: default:
errors.make<EvalError>("cannot compare %1% with %2%", showType(v1), showType(v2)).withTrace(pos, errorCtx).debugThrow(); ctx.errors.make<EvalError>("cannot compare %1% with %2%", showType(v1), showType(v2)).withTrace(pos, errorCtx).debugThrow();
} }
} }
@ -2832,7 +2832,7 @@ std::optional<std::string> EvalPaths::resolveSearchPathPath(const SearchPath::Pa
std::string ExternalValueBase::coerceToString(EvalState & state, const PosIdx & pos, NixStringContext & context, bool copyMore, bool copyToStore) const std::string ExternalValueBase::coerceToString(EvalState & state, const PosIdx & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
{ {
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"cannot coerce %1% to a string: %2%", showType(), *this "cannot coerce %1% to a string: %2%", showType(), *this
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
} }

View file

@ -142,14 +142,14 @@ static FlakeInput parseFlakeInput(EvalState & state,
auto intValue = attr.value->integer.value; auto intValue = attr.value->integer.value;
if (intValue < 0) { if (intValue < 0) {
state.errors.make<EvalError>("negative value given for flake input attribute %1%: %2%", state.ctx.symbols[attr.name], intValue).debugThrow(); state.ctx.errors.make<EvalError>("negative value given for flake input attribute %1%: %2%", state.ctx.symbols[attr.name], intValue).debugThrow();
} }
uint64_t asUnsigned = intValue; uint64_t asUnsigned = intValue;
attrs.emplace(state.ctx.symbols[attr.name], asUnsigned); attrs.emplace(state.ctx.symbols[attr.name], asUnsigned);
break; break;
} }
default: default:
state.errors.make<TypeError>("flake input attribute '%s' is %s while a string, Boolean, or integer is expected", state.ctx.errors.make<TypeError>("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
state.ctx.symbols[attr.name], showType(*attr.value)).debugThrow(); state.ctx.symbols[attr.name], showType(*attr.value)).debugThrow();
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -247,7 +247,7 @@ static Flake getFlake(
// Enforce that 'flake.nix' is a direct attrset, not a computation. // Enforce that 'flake.nix' is a direct attrset, not a computation.
if (!(dynamic_cast<ExprAttrs *>(&flakeExpr))) { if (!(dynamic_cast<ExprAttrs *>(&flakeExpr))) {
state.errors.make<EvalError>("file '%s' must be an attribute set", resolvedFlakeFile).debugThrow(); state.ctx.errors.make<EvalError>("file '%s' must be an attribute set", resolvedFlakeFile).debugThrow();
} }
Value vInfo; Value vInfo;
@ -307,14 +307,14 @@ static Flake getFlake(
std::vector<std::string> ss; std::vector<std::string> ss;
for (auto elem : setting.value->listItems()) { for (auto elem : setting.value->listItems()) {
if (elem->type() != nString) if (elem->type() != nString)
state.errors.make<TypeError>("list element in flake configuration setting '%s' is %s while a string is expected", state.ctx.errors.make<TypeError>("list element in flake configuration setting '%s' is %s while a string is expected",
state.ctx.symbols[setting.name], showType(*setting.value)).debugThrow(); state.ctx.symbols[setting.name], showType(*setting.value)).debugThrow();
ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos, "")); ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos, ""));
} }
flake.config.settings.emplace(state.ctx.symbols[setting.name], ss); flake.config.settings.emplace(state.ctx.symbols[setting.name], ss);
} }
else else
state.errors.make<TypeError>("flake configuration setting '%s' is %s", state.ctx.errors.make<TypeError>("flake configuration setting '%s' is %s",
state.ctx.symbols[setting.name], showType(*setting.value)).debugThrow(); state.ctx.symbols[setting.name], showType(*setting.value)).debugThrow();
} }
} }
@ -858,7 +858,7 @@ void prim_flakeRefToString(
auto intValue = attr.value->integer.value; auto intValue = attr.value->integer.value;
if (intValue < 0) { if (intValue < 0) {
state.errors.make<EvalError>("negative value given for flake ref attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("negative value given for flake ref attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow();
} }
uint64_t asUnsigned = intValue; uint64_t asUnsigned = intValue;
@ -870,7 +870,7 @@ void prim_flakeRefToString(
attrs.emplace(state.ctx.symbols[attr.name], attrs.emplace(state.ctx.symbols[attr.name],
std::string(attr.value->str())); std::string(attr.value->str()));
} else { } else {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"flake reference attribute sets may only contain integers, Booleans, " "flake reference attribute sets may only contain integers, Booleans, "
"and strings, but attribute '%s' is %s", "and strings, but attribute '%s' is %s",
state.ctx.symbols[attr.name], state.ctx.symbols[attr.name],

View file

@ -50,7 +50,7 @@ std::string DrvInfo::queryName(EvalState & state)
{ {
if (name == "" && attrs) { if (name == "" && attrs) {
auto i = attrs->find(state.ctx.s.name); auto i = attrs->find(state.ctx.s.name);
if (i == attrs->end()) state.errors.make<TypeError>("derivation name missing").debugThrow(); if (i == attrs->end()) state.ctx.errors.make<TypeError>("derivation name missing").debugThrow();
name = state.forceStringNoCtx(*i->value, noPos, "while evaluating the 'name' attribute of a derivation"); name = state.forceStringNoCtx(*i->value, noPos, "while evaluating the 'name' attribute of a derivation");
} }
return name; return name;
@ -431,7 +431,7 @@ static void getDerivations(EvalState & state, Value & vIn,
return; return;
} else if (v.type() != nAttrs) { } else if (v.type() != nAttrs) {
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"expression was expected to be a derivation or collection of derivations, but instead was %s", "expression was expected to be a derivation or collection of derivations, but instead was %s",
showType(v.type(), true) showType(v.type(), true)
).debugThrow(); ).debugThrow();

View file

@ -285,16 +285,16 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu
void *handle = dlopen(path.path.c_str(), RTLD_LAZY | RTLD_LOCAL); void *handle = dlopen(path.path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) if (!handle)
state.errors.make<EvalError>("could not open '%1%': %2%", path, dlerror()).debugThrow(); state.ctx.errors.make<EvalError>("could not open '%1%': %2%", path, dlerror()).debugThrow();
dlerror(); dlerror();
ValueInitializer func = reinterpret_cast<ValueInitializer>(dlsym(handle, sym.c_str())); ValueInitializer func = reinterpret_cast<ValueInitializer>(dlsym(handle, sym.c_str()));
if(!func) { if(!func) {
char *message = dlerror(); char *message = dlerror();
if (message) if (message)
state.errors.make<EvalError>("could not load symbol '%1%' from '%2%': %3%", sym, path, message).debugThrow(); state.ctx.errors.make<EvalError>("could not load symbol '%1%' from '%2%': %3%", sym, path, message).debugThrow();
else else
state.errors.make<EvalError>("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path).debugThrow(); state.ctx.errors.make<EvalError>("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path).debugThrow();
} }
(func)(state, v); (func)(state, v);
@ -310,7 +310,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
auto elems = args[0]->listElems(); auto elems = args[0]->listElems();
auto count = args[0]->listSize(); auto count = args[0]->listSize();
if (count == 0) if (count == 0)
state.errors.make<EvalError>("at least one argument to 'exec' required").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("at least one argument to 'exec' required").atPos(pos).debugThrow();
NixStringContext context; NixStringContext context;
auto program = state.coerceToString(pos, *elems[0], context, auto program = state.coerceToString(pos, *elems[0], context,
"while evaluating the first element of the argument passed to builtins.exec", "while evaluating the first element of the argument passed to builtins.exec",
@ -452,7 +452,7 @@ struct CompareValues
if (v1->type() == nInt && v2->type() == nFloat) if (v1->type() == nInt && v2->type() == nFloat)
return v1->integer.value < v2->fpoint; return v1->integer.value < v2->fpoint;
if (v1->type() != v2->type()) if (v1->type() != v2->type())
state.errors.make<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow(); state.ctx.errors.make<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow();
// Allow selecting a subset of enum values // Allow selecting a subset of enum values
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum" #pragma GCC diagnostic ignored "-Wswitch-enum"
@ -477,7 +477,7 @@ struct CompareValues
} }
} }
default: default:
state.errors.make<EvalError>("cannot compare %s with %s; values of that type are incomparable", showType(*v1), showType(*v2)).debugThrow(); state.ctx.errors.make<EvalError>("cannot compare %s with %s; values of that type are incomparable", showType(*v1), showType(*v2)).debugThrow();
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
} }
} catch (Error & e) { } catch (Error & e) {
@ -503,7 +503,7 @@ static Bindings::iterator getAttr(
{ {
Bindings::iterator value = attrSet->find(attrSym); Bindings::iterator value = attrSet->find(attrSym);
if (value == attrSet->end()) { if (value == attrSet->end()) {
state.errors.make<TypeError>("attribute '%s' missing", state.ctx.symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow(); state.ctx.errors.make<TypeError>("attribute '%s' missing", state.ctx.symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow();
} }
return value; return value;
} }
@ -572,14 +572,14 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
static void prim_break(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_break(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
if (auto trace = state.debug ? state.debug->traces().next() : std::nullopt) { if (auto trace = state.ctx.debug ? state.ctx.debug->traces().next() : std::nullopt) {
auto error = EvalError(ErrorInfo { auto error = EvalError(ErrorInfo {
.level = lvlInfo, .level = lvlInfo,
.msg = HintFmt("breakpoint reached"), .msg = HintFmt("breakpoint reached"),
.pos = state.ctx.positions[pos], .pos = state.ctx.positions[pos],
}); });
state.debug->onEvalError(&error, (*trace)->env, (*trace)->expr); state.ctx.debug->onEvalError(&error, (*trace)->env, (*trace)->expr);
} }
// Return the value we were passed. // Return the value we were passed.
@ -591,7 +591,7 @@ static void prim_abort(EvalState & state, const PosIdx pos, Value * * args, Valu
NixStringContext context; NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context, auto s = state.coerceToString(pos, *args[0], context,
"while evaluating the error message passed to builtins.abort").toOwned(); "while evaluating the error message passed to builtins.abort").toOwned();
state.errors.make<Abort>("evaluation aborted with the following error message: '%1%'", s).debugThrow(); state.ctx.errors.make<Abort>("evaluation aborted with the following error message: '%1%'", s).debugThrow();
} }
static void prim_throw(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_throw(EvalState & state, const PosIdx pos, Value * * args, Value & v)
@ -599,7 +599,7 @@ static void prim_throw(EvalState & state, const PosIdx pos, Value * * args, Valu
NixStringContext context; NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context, auto s = state.coerceToString(pos, *args[0], context,
"while evaluating the error message passed to builtin.throw").toOwned(); "while evaluating the error message passed to builtin.throw").toOwned();
state.errors.make<ThrownError>(s).debugThrow(); state.ctx.errors.make<ThrownError>(s).debugThrow();
} }
static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
@ -644,11 +644,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
std::optional<MaintainCount<int>> trylevel; std::optional<MaintainCount<int>> trylevel;
std::unique_ptr<DebugState> savedDebug; std::unique_ptr<DebugState> savedDebug;
if (state.debug) { if (state.ctx.debug) {
trylevel.emplace(state.debug->trylevel); trylevel.emplace(state.ctx.debug->trylevel);
if (evalSettings.ignoreExceptionsDuringTry) { if (evalSettings.ignoreExceptionsDuringTry) {
/* to prevent starting the repl from exceptions withing a tryEval, null it. */ /* to prevent starting the repl from exceptions withing a tryEval, null it. */
savedDebug = std::move(state.debug); savedDebug = std::move(state.ctx.debug);
} }
} }
@ -663,7 +663,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
// restore the debugRepl pointer if we saved it earlier. // restore the debugRepl pointer if we saved it earlier.
if (savedDebug) if (savedDebug)
state.debug = std::move(savedDebug); state.ctx.debug = std::move(savedDebug);
v.mkAttrs(attrs); v.mkAttrs(attrs);
} }
@ -701,11 +701,11 @@ static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Valu
printError("trace: %1%", args[0]->string.s); printError("trace: %1%", args[0]->string.s);
else else
printError("trace: %1%", ValuePrinter(state, *args[0])); printError("trace: %1%", ValuePrinter(state, *args[0]));
if (auto last = evalSettings.builtinsTraceDebugger && state.debug if (auto last = evalSettings.builtinsTraceDebugger && state.ctx.debug
? state.debug->traces().next() ? state.ctx.debug->traces().next()
: std::nullopt) : std::nullopt)
{ {
state.debug->onEvalError(nullptr, (*last)->env, (*last)->expr); state.ctx.debug->onEvalError(nullptr, (*last)->env, (*last)->expr);
} }
state.forceValue(*args[1], pos); state.forceValue(*args[1], pos);
v = *args[1]; v = *args[1];
@ -827,7 +827,7 @@ drvName, Bindings * attrs, Value & v)
experimentalFeatureSettings.require(Xp::DynamicDerivations); experimentalFeatureSettings.require(Xp::DynamicDerivations);
ingestionMethod = TextIngestionMethod {}; ingestionMethod = TextIngestionMethod {};
} else } else
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"invalid value '%s' for 'outputHashMode' attribute", s "invalid value '%s' for 'outputHashMode' attribute", s
).atPos(v).debugThrow(); ).atPos(v).debugThrow();
}; };
@ -836,7 +836,7 @@ drvName, Bindings * attrs, Value & v)
outputs.clear(); outputs.clear();
for (auto & j : ss) { for (auto & j : ss) {
if (outputs.find(j) != outputs.end()) if (outputs.find(j) != outputs.end())
state.errors.make<EvalError>("duplicate derivation output '%1%'", j) state.ctx.errors.make<EvalError>("duplicate derivation output '%1%'", j)
.atPos(v) .atPos(v)
.debugThrow(); .debugThrow();
/* !!! Check whether j is a valid attribute /* !!! Check whether j is a valid attribute
@ -845,13 +845,13 @@ drvName, Bindings * attrs, Value & v)
then we'd have an attribute drvPath in then we'd have an attribute drvPath in
the resulting set. */ the resulting set. */
if (j == "drv") if (j == "drv")
state.errors.make<EvalError>("invalid derivation output name 'drv'") state.ctx.errors.make<EvalError>("invalid derivation output name 'drv'")
.atPos(v) .atPos(v)
.debugThrow(); .debugThrow();
outputs.insert(j); outputs.insert(j);
} }
if (outputs.empty()) if (outputs.empty())
state.errors.make<EvalError>("derivation cannot have an empty set of outputs") state.ctx.errors.make<EvalError>("derivation cannot have an empty set of outputs")
.atPos(v) .atPos(v)
.debugThrow(); .debugThrow();
}; };
@ -989,12 +989,12 @@ drvName, Bindings * attrs, Value & v)
/* Do we have all required attributes? */ /* Do we have all required attributes? */
if (drv.builder == "") if (drv.builder == "")
state.errors.make<EvalError>("required attribute 'builder' missing") state.ctx.errors.make<EvalError>("required attribute 'builder' missing")
.atPos(v) .atPos(v)
.debugThrow(); .debugThrow();
if (drv.platform == "") if (drv.platform == "")
state.errors.make<EvalError>("required attribute 'system' missing") state.ctx.errors.make<EvalError>("required attribute 'system' missing")
.atPos(v) .atPos(v)
.debugThrow(); .debugThrow();
@ -1004,7 +1004,7 @@ drvName, Bindings * attrs, Value & v)
outputs.size() == 1 && outputs.size() == 1 &&
*(outputs.begin()) == "out")) *(outputs.begin()) == "out"))
{ {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"derivation names are allowed to end in '%s' only if they produce a single derivation file", "derivation names are allowed to end in '%s' only if they produce a single derivation file",
drvExtension drvExtension
).atPos(v).debugThrow(); ).atPos(v).debugThrow();
@ -1016,7 +1016,7 @@ drvName, Bindings * attrs, Value & v)
Ignore `__contentAddressed` because fixed output derivations are Ignore `__contentAddressed` because fixed output derivations are
already content addressed. */ already content addressed. */
if (outputs.size() != 1 || *(outputs.begin()) != "out") if (outputs.size() != 1 || *(outputs.begin()) != "out")
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"multiple outputs are not supported in fixed-output derivations" "multiple outputs are not supported in fixed-output derivations"
).atPos(v).debugThrow(); ).atPos(v).debugThrow();
@ -1037,7 +1037,7 @@ drvName, Bindings * attrs, Value & v)
else if (contentAddressed || isImpure) { else if (contentAddressed || isImpure) {
if (contentAddressed && isImpure) if (contentAddressed && isImpure)
state.errors.make<EvalError>("derivation cannot be both content-addressed and impure") state.ctx.errors.make<EvalError>("derivation cannot be both content-addressed and impure")
.atPos(v).debugThrow(); .atPos(v).debugThrow();
auto ht = parseHashTypeOpt(outputHashAlgo).value_or(HashType::SHA256); auto ht = parseHashTypeOpt(outputHashAlgo).value_or(HashType::SHA256);
@ -1079,7 +1079,7 @@ drvName, Bindings * attrs, Value & v)
for (auto & i : outputs) { for (auto & i : outputs) {
auto h = get(hashModulo.hashes, i); auto h = get(hashModulo.hashes, i);
if (!h) if (!h)
state.errors.make<AssertionError>( state.ctx.errors.make<AssertionError>(
"derivation produced no hash for output '%s'", "derivation produced no hash for output '%s'",
i i
).atPos(v).debugThrow(); ).atPos(v).debugThrow();
@ -1167,7 +1167,7 @@ static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Val
static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
if (evalSettings.pureEval) if (evalSettings.pureEval)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"'%s' is not allowed in pure evaluation mode", "'%s' is not allowed in pure evaluation mode",
"builtins.storePath" "builtins.storePath"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -1180,7 +1180,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
if (!state.store->isStorePath(path.abs())) if (!state.store->isStorePath(path.abs()))
path = CanonPath(canonPath(path.abs(), true)); path = CanonPath(canonPath(path.abs(), true));
if (!state.store->isInStore(path.abs())) if (!state.store->isInStore(path.abs()))
state.errors.make<EvalError>("path '%1%' is not in the Nix store", path) state.ctx.errors.make<EvalError>("path '%1%' is not in the Nix store", path)
.atPos(pos).debugThrow(); .atPos(pos).debugThrow();
auto path2 = state.store->toStorePath(path.abs()).first; auto path2 = state.store->toStorePath(path.abs()).first;
if (!settings.readOnlyMode) if (!settings.readOnlyMode)
@ -1258,7 +1258,7 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V
auto path = realisePath(state, pos, *args[0]); auto path = realisePath(state, pos, *args[0]);
auto s = path.readFile(); auto s = path.readFile();
if (s.find((char) 0) != std::string::npos) if (s.find((char) 0) != std::string::npos)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"the contents of the file '%1%' cannot be represented as a Nix string", "the contents of the file '%1%' cannot be represented as a Nix string",
path path
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -1309,7 +1309,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
auto rewrites = state.paths.realiseContext(context); auto rewrites = state.paths.realiseContext(context);
path = rewriteStrings(path, rewrites); path = rewriteStrings(path, rewrites);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"cannot find '%1%', since path '%2%' is not valid", "cannot find '%1%', since path '%2%' is not valid",
path, path,
e.path e.path
@ -1333,7 +1333,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, V
auto type = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashFile"); auto type = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashFile");
std::optional<HashType> ht = parseHashType(type); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
state.errors.make<EvalError>("unknown hash type '%1%'", type).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("unknown hash type '%1%'", type).atPos(pos).debugThrow();
auto path = realisePath(state, pos, *args[1]); auto path = realisePath(state, pos, *args[1]);
@ -1462,7 +1462,7 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Val
if (auto p = std::get_if<NixStringContextElem::Opaque>(&c.raw)) if (auto p = std::get_if<NixStringContextElem::Opaque>(&c.raw))
refs.insert(p->path); refs.insert(p->path);
else else
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"files created by %1% may not reference derivations, but %2% references %3%", "files created by %1% may not reference derivations, but %2% references %3%",
"builtins.toFile", "builtins.toFile",
name, name,
@ -1549,7 +1549,7 @@ static void addPath(
auto dstPath = fetchToStore( auto dstPath = fetchToStore(
*state.store, CanonPath(path), name, method, &filter, state.repair); *state.store, CanonPath(path), name, method, &filter, state.repair);
if (expectedHash && expectedStorePath != dstPath) if (expectedHash && expectedStorePath != dstPath)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"store path mismatch in (possibly filtered) path added from '%s'", "store path mismatch in (possibly filtered) path added from '%s'",
path path
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -1596,13 +1596,13 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value
else if (n == "sha256") else if (n == "sha256")
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `sha256` attribute passed to builtins.path"), HashType::SHA256); expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `sha256` attribute passed to builtins.path"), HashType::SHA256);
else else
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"unsupported argument '%1%' to 'addPath'", "unsupported argument '%1%' to 'addPath'",
state.ctx.symbols[attr.name] state.ctx.symbols[attr.name]
).atPos(attr.pos).debugThrow(); ).atPos(attr.pos).debugThrow();
} }
if (!path) if (!path)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"missing required 'path' attribute in the first argument to builtins.path" "missing required 'path' attribute in the first argument to builtins.path"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
if (name.empty()) if (name.empty())
@ -1909,7 +1909,7 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg
return; return;
} }
if (!args[0]->isLambda()) if (!args[0]->isLambda())
state.errors.make<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow(); state.ctx.errors.make<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
if (!args[0]->lambda.fun->hasFormals()) { if (!args[0]->lambda.fun->hasFormals()) {
v.mkAttrs(&Bindings::EMPTY); v.mkAttrs(&Bindings::EMPTY);
@ -2006,7 +2006,7 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val
{ {
state.forceList(list, pos, "while evaluating the first argument passed to builtins.elemAt"); state.forceList(list, pos, "while evaluating the first argument passed to builtins.elemAt");
if (n < 0 || (unsigned int) n >= list.listSize()) if (n < 0 || (unsigned int) n >= list.listSize())
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"list index %1% is out of bounds", "list index %1% is out of bounds",
n n
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -2034,7 +2034,7 @@ static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value
{ {
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.tail"); state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.tail");
if (args[0]->listSize() == 0) if (args[0]->listSize() == 0)
state.errors.make<EvalError>("'tail' called on an empty list").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("'tail' called on an empty list").atPos(pos).debugThrow();
v = state.mem.newList(args[0]->listSize() - 1); v = state.mem.newList(args[0]->listSize() - 1);
for (unsigned int n = 0; n < v.listSize(); ++n) for (unsigned int n = 0; n < v.listSize(); ++n)
@ -2181,7 +2181,7 @@ static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Va
auto len_ = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.genList").value; auto len_ = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.genList").value;
if (len_ < 0) if (len_ < 0)
state.errors.make<EvalError>("cannot create list of size %1%", len_).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("cannot create list of size %1%", len_).atPos(pos).debugThrow();
size_t len = len_; size_t len = len_;
@ -2354,7 +2354,7 @@ static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value
if (auto result = result_.valueChecked(); result.has_value()) { if (auto result = result_.valueChecked(); result.has_value()) {
v.mkInt(*result); v.mkInt(*result);
} else { } else {
state.errors.make<EvalError>("integer overflow in adding %1% + %2%", i1, i2).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("integer overflow in adding %1% + %2%", i1, i2).atPos(pos).debugThrow();
} }
} }
} }
@ -2375,7 +2375,7 @@ static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value
if (auto result = result_.valueChecked(); result.has_value()) { if (auto result = result_.valueChecked(); result.has_value()) {
v.mkInt(*result); v.mkInt(*result);
} else { } else {
state.errors.make<EvalError>("integer overflow in subtracting %1% - %2%", i1, i2).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("integer overflow in subtracting %1% - %2%", i1, i2).atPos(pos).debugThrow();
} }
} }
} }
@ -2396,7 +2396,7 @@ static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value
if (auto result = result_.valueChecked(); result.has_value()) { if (auto result = result_.valueChecked(); result.has_value()) {
v.mkInt(*result); v.mkInt(*result);
} else { } else {
state.errors.make<EvalError>("integer overflow in multiplying %1% * %2%", i1, i2).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("integer overflow in multiplying %1% * %2%", i1, i2).atPos(pos).debugThrow();
} }
} }
} }
@ -2408,7 +2408,7 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value
NixFloat f2 = state.forceFloat(*args[1], pos, "while evaluating the second operand of the division"); NixFloat f2 = state.forceFloat(*args[1], pos, "while evaluating the second operand of the division");
if (f2 == 0) if (f2 == 0)
state.errors.make<EvalError>("division by zero").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("division by zero").atPos(pos).debugThrow();
if (args[0]->type() == nFloat || args[1]->type() == nFloat) { if (args[0]->type() == nFloat || args[1]->type() == nFloat) {
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first operand of the division") / f2); v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first operand of the division") / f2);
@ -2420,7 +2420,7 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value
if (auto result = result_.valueChecked(); result.has_value()) { if (auto result = result_.valueChecked(); result.has_value()) {
v.mkInt(*result); v.mkInt(*result);
} else { } else {
state.errors.make<EvalError>("integer overflow in dividing %1% / %2%", i1, i2).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("integer overflow in dividing %1% / %2%", i1, i2).atPos(pos).debugThrow();
} }
} }
} }
@ -2484,7 +2484,7 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args,
NixInt::Inner start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring").value; NixInt::Inner start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring").value;
if (start < 0) if (start < 0)
state.errors.make<EvalError>("negative start position in 'substring'").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("negative start position in 'substring'").atPos(pos).debugThrow();
NixInt::Inner len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring").value; NixInt::Inner len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring").value;
@ -2524,7 +2524,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args,
auto type = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashString"); auto type = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashString");
std::optional<HashType> ht = parseHashType(type); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
state.errors.make<EvalError>("unknown hash algorithm '%1%'", type).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("unknown hash algorithm '%1%'", type).atPos(pos).debugThrow();
NixStringContext context; // discarded NixStringContext context; // discarded
auto s = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString"); auto s = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString");
@ -2586,11 +2586,11 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v)
} catch (std::regex_error & e) { } catch (std::regex_error & e) {
if (e.code() == std::regex_constants::error_space) { if (e.code() == std::regex_constants::error_space) {
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
state.errors.make<EvalError>("memory limit exceeded by regular expression '%s'", re) state.ctx.errors.make<EvalError>("memory limit exceeded by regular expression '%s'", re)
.atPos(pos) .atPos(pos)
.debugThrow(); .debugThrow();
} else } else
state.errors.make<EvalError>("invalid regular expression '%s'", re) state.ctx.errors.make<EvalError>("invalid regular expression '%s'", re)
.atPos(pos) .atPos(pos)
.debugThrow(); .debugThrow();
} }
@ -2652,11 +2652,11 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
} catch (std::regex_error & e) { } catch (std::regex_error & e) {
if (e.code() == std::regex_constants::error_space) { if (e.code() == std::regex_constants::error_space) {
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
state.errors.make<EvalError>("memory limit exceeded by regular expression '%s'", re) state.ctx.errors.make<EvalError>("memory limit exceeded by regular expression '%s'", re)
.atPos(pos) .atPos(pos)
.debugThrow(); .debugThrow();
} else } else
state.errors.make<EvalError>("invalid regular expression '%s'", re) state.ctx.errors.make<EvalError>("invalid regular expression '%s'", re)
.atPos(pos) .atPos(pos)
.debugThrow(); .debugThrow();
} }
@ -2686,7 +2686,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.replaceStrings"); state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.replaceStrings");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.replaceStrings"); state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.replaceStrings");
if (args[0]->listSize() != args[1]->listSize()) if (args[0]->listSize() != args[1]->listSize())
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"'from' and 'to' arguments passed to builtins.replaceStrings have different lengths" "'from' and 'to' arguments passed to builtins.replaceStrings have different lengths"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();

View file

@ -56,7 +56,7 @@ void prim_addDrvOutputDependencies(EvalState & state, const PosIdx pos, Value *
auto contextSize = context.size(); auto contextSize = context.size();
if (contextSize != 1) { if (contextSize != 1) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"context of string '%s' must have exactly one element, but has %d", "context of string '%s' must have exactly one element, but has %d",
*s, *s,
contextSize contextSize
@ -66,7 +66,7 @@ void prim_addDrvOutputDependencies(EvalState & state, const PosIdx pos, Value *
(NixStringContextElem { std::visit(overloaded { (NixStringContextElem { std::visit(overloaded {
[&](const NixStringContextElem::Opaque & c) -> NixStringContextElem::DrvDeep { [&](const NixStringContextElem::Opaque & c) -> NixStringContextElem::DrvDeep {
if (!c.path.isDerivation()) { if (!c.path.isDerivation()) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"path '%s' is not a derivation", "path '%s' is not a derivation",
state.store->printStorePath(c.path) state.store->printStorePath(c.path)
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -76,7 +76,7 @@ void prim_addDrvOutputDependencies(EvalState & state, const PosIdx pos, Value *
}; };
}, },
[&](const NixStringContextElem::Built & c) -> NixStringContextElem::DrvDeep { [&](const NixStringContextElem::Built & c) -> NixStringContextElem::DrvDeep {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"`addDrvOutputDependencies` can only act on derivations, not on a derivation output such as '%1%'", "`addDrvOutputDependencies` can only act on derivations, not on a derivation output such as '%1%'",
c.output c.output
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -176,7 +176,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
for (auto & i : *args[1]->attrs) { for (auto & i : *args[1]->attrs) {
const auto & name = state.ctx.symbols[i.name]; const auto & name = state.ctx.symbols[i.name];
if (!state.store->isStorePath(name)) if (!state.store->isStorePath(name))
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"context key '%s' is not a store path", "context key '%s' is not a store path",
name name
).atPos(i.pos).debugThrow(); ).atPos(i.pos).debugThrow();
@ -196,7 +196,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
if (iter != i.value->attrs->end()) { if (iter != i.value->attrs->end()) {
if (state.forceBool(*iter->value, iter->pos, "while evaluating the `allOutputs` attribute of a string context")) { if (state.forceBool(*iter->value, iter->pos, "while evaluating the `allOutputs` attribute of a string context")) {
if (!isDerivation(name)) { if (!isDerivation(name)) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"tried to add all-outputs context of %s, which is not a derivation, to a string", "tried to add all-outputs context of %s, which is not a derivation, to a string",
name name
).atPos(i.pos).debugThrow(); ).atPos(i.pos).debugThrow();
@ -211,7 +211,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
if (iter != i.value->attrs->end()) { if (iter != i.value->attrs->end()) {
state.forceList(*iter->value, iter->pos, "while evaluating the `outputs` attribute of a string context"); state.forceList(*iter->value, iter->pos, "while evaluating the `outputs` attribute of a string context");
if (iter->value->listSize() && !isDerivation(name)) { if (iter->value->listSize() && !isDerivation(name)) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"tried to add derivation output context of %s, which is not a derivation, to a string", "tried to add derivation output context of %s, which is not a derivation, to a string",
name name
).atPos(i.pos).debugThrow(); ).atPos(i.pos).debugThrow();

View file

@ -38,11 +38,11 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
else if (n == "name") else if (n == "name")
name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.fetchMercurial"); name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.fetchMercurial");
else else
state.errors.make<EvalError>("unsupported argument '%s' to 'fetchMercurial'", state.ctx.symbols[attr.name]).atPos(attr.pos).debugThrow(); state.ctx.errors.make<EvalError>("unsupported argument '%s' to 'fetchMercurial'", state.ctx.symbols[attr.name]).atPos(attr.pos).debugThrow();
} }
if (url.empty()) if (url.empty())
state.errors.make<EvalError>("'url' argument required").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("'url' argument required").atPos(pos).debugThrow();
} else } else
url = state.coerceToString(pos, *args[0], context, url = state.coerceToString(pos, *args[0], context,

View file

@ -124,12 +124,12 @@ static void fetchTree(
if (auto aType = args[0]->attrs->get(state.ctx.s.type)) { if (auto aType = args[0]->attrs->get(state.ctx.s.type)) {
if (type) if (type)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"unexpected attribute 'type'" "unexpected attribute 'type'"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
type = state.forceStringNoCtx(*aType->value, aType->pos, "while evaluating the `type` attribute passed to builtins.fetchTree"); type = state.forceStringNoCtx(*aType->value, aType->pos, "while evaluating the `type` attribute passed to builtins.fetchTree");
} else if (!type) } else if (!type)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"attribute 'type' is missing in call to 'fetchTree'" "attribute 'type' is missing in call to 'fetchTree'"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -153,19 +153,19 @@ static void fetchTree(
auto intValue = attr.value->integer.value; auto intValue = attr.value->integer.value;
if (intValue < 0) { if (intValue < 0) {
state.errors.make<EvalError>("negative value given for fetchTree attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("negative value given for fetchTree attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow();
} }
unsigned long asUnsigned = intValue; unsigned long asUnsigned = intValue;
attrs.emplace(state.ctx.symbols[attr.name], asUnsigned); attrs.emplace(state.ctx.symbols[attr.name], asUnsigned);
} else } else
state.errors.make<TypeError>("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", state.ctx.errors.make<TypeError>("fetchTree argument '%s' is %s while a string, Boolean or integer is expected",
state.ctx.symbols[attr.name], showType(*attr.value)).debugThrow(); state.ctx.symbols[attr.name], showType(*attr.value)).debugThrow();
} }
if (!params.allowNameArgument) if (!params.allowNameArgument)
if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) if (auto nameIter = attrs.find("name"); nameIter != attrs.end())
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"attribute 'name' isnt supported in call to 'fetchTree'" "attribute 'name' isnt supported in call to 'fetchTree'"
).atPos(pos).debugThrow(); ).atPos(pos).debugThrow();
@ -189,7 +189,7 @@ static void fetchTree(
input = lookupInRegistries(state.store, input).first; input = lookupInRegistries(state.store, input).first;
if (evalSettings.pureEval && !input.isLocked()) { if (evalSettings.pureEval && !input.isLocked()) {
state.errors.make<EvalError>("in pure evaluation mode, 'fetchTree' requires a locked input").atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("in pure evaluation mode, 'fetchTree' requires a locked input").atPos(pos).debugThrow();
} }
auto [tree, input2] = input.fetch(state.store); auto [tree, input2] = input.fetch(state.store);
@ -231,12 +231,12 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
else if (n == "name") else if (n == "name")
name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the name of the content we should fetch"); name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the name of the content we should fetch");
else else
state.errors.make<EvalError>("unsupported argument '%s' to '%s'", n, who) state.ctx.errors.make<EvalError>("unsupported argument '%s' to '%s'", n, who)
.atPos(pos).debugThrow(); .atPos(pos).debugThrow();
} }
if (!url) if (!url)
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"'url' argument required").atPos(pos).debugThrow(); "'url' argument required").atPos(pos).debugThrow();
} else } else
url = state.forceStringNoCtx(*args[0], pos, "while evaluating the url we should fetch"); url = state.forceStringNoCtx(*args[0], pos, "while evaluating the url we should fetch");
@ -250,7 +250,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
name = baseNameOf(*url); name = baseNameOf(*url);
if (evalSettings.pureEval && !expectedHash) if (evalSettings.pureEval && !expectedHash)
state.errors.make<EvalError>("in pure evaluation mode, '%s' requires a 'sha256' argument", who).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("in pure evaluation mode, '%s' requires a 'sha256' argument", who).atPos(pos).debugThrow();
// early exit if pinned and already in the store // early exit if pinned and already in the store
if (expectedHash && expectedHash->type == HashType::SHA256) { if (expectedHash && expectedHash->type == HashType::SHA256) {
@ -280,7 +280,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
? state.store->queryPathInfo(storePath)->narHash ? state.store->queryPathInfo(storePath)->narHash
: hashFile(HashType::SHA256, state.store->toRealPath(storePath)); : hashFile(HashType::SHA256, state.store->toRealPath(storePath));
if (hash != *expectedHash) { if (hash != *expectedHash) {
state.errors.make<EvalError>( state.ctx.errors.make<EvalError>(
"hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s",
*url, *url,
expectedHash->to_string(Base::Base32, true), expectedHash->to_string(Base::Base32, true),

View file

@ -83,7 +83,7 @@ void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, Value &
try { try {
visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */)); visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
} catch (std::exception & e) { // TODO: toml::syntax_error } catch (std::exception & e) { // TODO: toml::syntax_error
state.errors.make<EvalError>("while parsing TOML: %s", e.what()).atPos(pos).debugThrow(); state.ctx.errors.make<EvalError>("while parsing TOML: %s", e.what()).atPos(pos).debugThrow();
} }
} }

View file

@ -99,7 +99,7 @@ json printValueAsJSON(EvalState & state, bool strict,
case nThunk: case nThunk:
case nFunction: case nFunction:
state.errors.make<TypeError>( state.ctx.errors.make<TypeError>(
"cannot convert %1% to JSON", "cannot convert %1% to JSON",
showType(v) showType(v)
) )
@ -118,7 +118,7 @@ void printValueAsJSON(EvalState & state, bool strict,
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
NixStringContext & context, bool copyToStore) const NixStringContext & context, bool copyToStore) const
{ {
state.errors.make<TypeError>("cannot convert %1% to JSON", showType()) state.ctx.errors.make<TypeError>("cannot convert %1% to JSON", showType())
.debugThrow(); .debugThrow();
} }