From 3a5855353e5dc2986c38bb66eaff5538dea70da1 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Fri, 4 Mar 2022 21:47:58 +0100 Subject: [PATCH] Add detailed error mesage for coerceTo{String,Path} --- src/libexpr/eval.cc | 34 +++++++------- src/libexpr/eval.hh | 7 +-- src/libexpr/flake/flake.cc | 2 +- src/libexpr/get-drvs.cc | 6 +-- src/libexpr/primops.cc | 66 +++++++++++++++------------ src/libexpr/primops/context.cc | 4 +- src/libexpr/primops/fetchMercurial.cc | 4 +- src/libexpr/primops/fetchTree.cc | 4 +- src/libexpr/value.hh | 2 +- src/nix-env/user-env.cc | 4 +- src/nix/bundle.cc | 4 +- src/nix/eval.cc | 2 +- src/nix/flake.cc | 2 +- src/nix/repl.cc | 4 +- 14 files changed, 79 insertions(+), 66 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 6a21701f3..b2a8651d9 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1775,7 +1775,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) /* skip canonization of first path, which would only be not canonized in the first place if it's coming from a ./${foo} type path */ - auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first); + auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first, ""); sSize += part->size(); s.emplace_back(std::move(part)); } @@ -1958,14 +1958,15 @@ std::optional EvalState::tryAttrsToString(const Pos & pos, Value & if (i != v.attrs->end()) { Value v1; callFunction(*i->value, v, v1, pos); - return coerceToString(pos, v1, context, coerceMore, copyToStore).toOwned(); + return coerceToString(pos, v1, context, coerceMore, copyToStore, + "While evaluating the result of the `toString` attribute").toOwned(); } return {}; } BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, - bool coerceMore, bool copyToStore, bool canonicalizePath) + bool coerceMore, bool copyToStore, bool canonicalizePath, const std::string & errorCtx) { forceValue(v, pos); @@ -1988,12 +1989,12 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & if (maybeString) return std::move(*maybeString); auto i = v.attrs->find(sOutPath); - if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string"); - return coerceToString(pos, *i->value, context, coerceMore, copyToStore); + if (i == v.attrs->end()) throwTypeError(pos, "%2%: cannot coerce %1% to a string", v, errorCtx); + return coerceToString(pos, *i->value, context, coerceMore, copyToStore, canonicalizePath, errorCtx); } if (v.type() == nExternal) - return v.external->coerceToString(pos, context, coerceMore, copyToStore); + return v.external->coerceToString(pos, context, coerceMore, copyToStore, errorCtx); if (coerceMore) { @@ -2008,7 +2009,8 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & if (v.isList()) { std::string result; for (auto [n, v2] : enumerate(v.listItems())) { - result += *coerceToString(pos, *v2, context, coerceMore, copyToStore); + result += *coerceToString(pos, *v2, context, coerceMore, copyToStore, canonicalizePath, + errorCtx + ": While evaluating one element of the list"); if (n < v.listSize() - 1 /* !!! not quite correct */ && (!v2->isList() || v2->listSize() != 0)) @@ -2018,7 +2020,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & } } - throwTypeError(pos, "cannot coerce %1% to a string", v); + throwTypeError(pos, "%2%: cannot coerce %1% to a string", v, errorCtx); } @@ -2046,22 +2048,22 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path) } -Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) +Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx) { - auto path = coerceToString(pos, v, context, false, false).toOwned(); + auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned(); if (path == "" || path[0] != '/') - throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); + throwEvalError(pos, "%2%: string '%1%' doesn't represent an absolute path", path, errorCtx); return path; } -StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context) +StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx) { - auto path = coerceToString(pos, v, context, false, false).toOwned(); + auto path = coerceToString(pos, v, context, false, false, errorCtx).toOwned(); if (auto storePath = store->maybeParseStorePath(path)) return *storePath; throw EvalError({ - .msg = hintfmt("path '%1%' is not in the Nix store", path), + .msg = hintfmt("%2%: path '%1%' is not in the Nix store", path, errorCtx), .errPos = pos }); } @@ -2263,10 +2265,10 @@ void EvalState::printStats() } -std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const +std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const { throw TypeError({ - .msg = hintfmt("cannot coerce %1% to a string", showType()), + .msg = hintfmt("%2%: cannot coerce %1% to a string", showType(), errorCtx), .errPos = pos }); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ae2a5f4f1..9e8ac4926 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -262,17 +262,18 @@ public: referenced paths are copied to the Nix store as a side effect. */ BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context, bool coerceMore = false, bool copyToStore = true, - bool canonicalizePath = true); + bool canonicalizePath = true, + const std::string & errorCtx = ""); std::string copyPathToStore(PathSet & context, const Path & path); /* Path coercion. Converts strings, paths and derivations to a path. The result is guaranteed to be a canonicalised, absolute path. Nothing is copied to the store. */ - Path coerceToPath(const Pos & pos, Value & v, PathSet & context); + Path coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx); /* Like coerceToPath, but the result must be a store path. */ - StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context); + StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx); public: diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index b0f087b11..fe2daaf21 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -260,7 +260,7 @@ static Flake getFlake( PathSet emptyContext = {}; flake.config.settings.emplace( setting.name, - state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true) .toOwned()); + state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true, "") .toOwned()); } else if (setting.value->type() == nInt) flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos, "")}); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 975490d36..9bb545430 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -74,7 +74,7 @@ std::optional DrvInfo::queryDrvPath() const if (i == attrs->end()) drvPath = {std::nullopt}; else - drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)}; + drvPath = {state->coerceToStorePath(*i->pos, *i->value, context, "Whyle evaluating the drv path of a DrvInfo")}; } return drvPath.value_or(std::nullopt); } @@ -94,7 +94,7 @@ StorePath DrvInfo::queryOutPath() const Bindings::iterator i = attrs->find(state->sOutPath); PathSet context; if (i != attrs->end()) - outPath = state->coerceToStorePath(*i->pos, *i->value, context); + outPath = state->coerceToStorePath(*i->pos, *i->value, context, "While evaluating the output path of a DrvInfo"); } if (!outPath) throw UnimplementedError("CA derivations are not yet supported"); @@ -122,7 +122,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); if (outPath == out->value->attrs->end()) continue; // FIXME: throw error? PathSet context; - outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context)); + outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context, "While evaluating the outPath of an output path of a DrvInfo")); } } else outputs.emplace("out", queryOutPath()); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e05e6d45a..14db24f68 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -103,7 +103,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea auto path = [&]() { try { - return state.coerceToPath(pos, v, context); + return state.coerceToPath(pos, v, context, "While realising the context of a path"); } catch (Error & e) { e.addTrace(pos, "while realising the context of a path"); throw; @@ -350,10 +350,12 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) }); } PathSet context; - auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); + auto program = state.coerceToString(pos, *elems[0], context, false, false, + "While evaluating the first element of the argument passed to builtins.exec").toOwned(); Strings commandArgs; for (unsigned int i = 1; i < args[0]->listSize(); ++i) { - commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false).toOwned()); + commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false, + "While evaluating an element of the argument passed to builtins.exec").toOwned()); } try { auto _ = state.realiseContext(context); // FIXME: Handle CA derivations @@ -714,7 +716,8 @@ static RegisterPrimOp primop_abort({ .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); + auto s = state.coerceToString(pos, *args[0], context, + "While evaluating the error message passed to builtins.abort").toOwned(); throw Abort("evaluation aborted with the following error message: '%1%'", s); } }); @@ -732,7 +735,8 @@ static RegisterPrimOp primop_throw({ .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); + auto s = state.coerceToString(pos, *args[0], context, + "While evaluating the error message passed to builtin.throw").toOwned(); throw ThrownError(s); } }); @@ -744,7 +748,8 @@ static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * a v = *args[1]; } catch (Error & e) { PathSet context; - e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context).toOwned()); + e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context, + "While evaluating the error message passed to builtins.addErrorContext").toOwned()); throw; } } @@ -757,7 +762,8 @@ static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info { static void prim_ceil(EvalState & state, const Pos & pos, Value * * args, Value & v) { - auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "While evaluating the first argument passed to builtins.ceil"); + auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), + "While evaluating the first argument passed to builtins.ceil"); v.mkInt(ceil(value)); } @@ -1028,7 +1034,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } if (i->name == state.sContentAddressed) { - contentAddressed = state.forceBool(*i->value, pos, "While evaluating the `__contentAddressed` attribute passed to builtins.derivationStrict"); + contentAddressed = state.forceBool(*i->value, pos, + "While evaluating the `__contentAddressed` attribute passed to builtins.derivationStrict"); if (contentAddressed) settings.requireExperimentalFeature(Xp::CaDerivations); } @@ -1036,9 +1043,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* The `args' attribute is special: it supplies the command-line arguments to the builder. */ else if (i->name == state.sArgs) { - state.forceList(*i->value, pos, "While evaluating the `args` attribute passed to builtins.derivationStrict"); + state.forceList(*i->value, pos, + "While evaluating the `args` attribute passed to builtins.derivationStrict"); for (auto elem : i->value->listItems()) { - auto s = state.coerceToString(posDrvName, *elem, context, true).toOwned(); + auto s = state.coerceToString(posDrvName, *elem, context, true, + "While evaluating an element of the `args` argument passed to builtins.derivationStrict").toOwned(); drv.args.push_back(s); } } @@ -1074,7 +1083,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } } else { - auto s = state.coerceToString(*i->pos, *i->value, context, true).toOwned(); + auto s = state.coerceToString(*i->pos, *i->value, context, true, "While evaluating an attribute passed to builtins.derivationStrict").toOwned(); drv.env.emplace(key, s); if (i->name == state.sBuilder) drv.builder = std::move(s); else if (i->name == state.sSystem) drv.platform = std::move(s); @@ -1306,7 +1315,7 @@ static RegisterPrimOp primop_placeholder({ static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(pos, *args[0], context); + Path path = state.coerceToPath(pos, *args[0], context, "While evaluating the first argument passed to builtins.toPath"); v.mkString(canonPath(path), context); } @@ -1337,7 +1346,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V }); PathSet context; - Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); + Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "While evaluating the first argument passed to builtins.storePath")); /* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink directly in the store. The latter condition is necessary so e.g. nix-push does the right thing. */ @@ -1407,7 +1416,7 @@ static RegisterPrimOp primop_pathExists({ static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context); + v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.baseNameOf")), context); } static RegisterPrimOp primop_baseNameOf({ @@ -1427,7 +1436,7 @@ static RegisterPrimOp primop_baseNameOf({ static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto path = state.coerceToString(pos, *args[0], context, false, false); + auto path = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.dirOf"); auto dir = dirOf(*path); if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context); } @@ -1484,7 +1493,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va std::string prefix; Bindings::iterator i = v2->attrs->find(state.sPrefix); if (i != v2->attrs->end()) - prefix = state.forceStringNoCtx(*i->value, pos, "While evaluating the `prefix` attribute passed to an element of the list passed to builtins.findFile"); + prefix = state.forceStringNoCtx(*i->value, pos, "While evaluating the `prefix` attribute of an element of the list passed to builtins.findFile"); i = getAttr( state, @@ -1495,7 +1504,8 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va ); PathSet context; - auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned(); + auto path = state.coerceToString(pos, *i->value, context, false, false, + "While evaluating the `path` attribute of an element of the list passed to builtins.findFile").toOwned(); try { auto rewrites = state.realiseContext(context); @@ -1945,7 +1955,7 @@ static void addPath( static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(pos, *args[1], context); + Path path = state.coerceToPath(pos, *args[1], context, "While evaluating the second argument (the path to filter) passed to builtins.filterSource"); state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) @@ -2027,7 +2037,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value for (auto & attr : *args[0]->attrs) { auto & n(attr.name); if (n == "path") - path = state.coerceToPath(*attr.pos, *attr.value, context); + path = state.coerceToPath(*attr.pos, *attr.value, context, "While evaluating the `path` attribute passed to builtins.path"); else if (attr.name == state.sName) name = state.forceStringNoCtx(*attr.value, *attr.pos, "while evaluating the `name` attribute passed to builtins.path"); else if (n == "filter") { @@ -2045,7 +2055,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value } if (path.empty()) throw EvalError({ - .msg = hintfmt("'path' required"), + .msg = hintfmt("Missing required 'path' attribute in the first argument to builtins.path"), .errPos = pos }); if (name.empty()) @@ -3318,7 +3328,7 @@ static RegisterPrimOp primop_lessThan({ static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context, true, false); + auto s = state.coerceToString(pos, *args[0], context, true, false, "While evaluating the first argument passed to builtins.toString"); v.mkString(*s, context); } @@ -3352,10 +3362,10 @@ static RegisterPrimOp primop_toString({ non-negative. */ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v) { - int start = state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.substring"); - int len = state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.substring"); + int start = state.forceInt(*args[0], pos, "While evaluating the first argument (the start offset) passed to builtins.substring"); + int len = state.forceInt(*args[1], pos, "While evaluating the second argument (the substring length) passed to builtins.substring"); PathSet context; - auto s = state.coerceToString(pos, *args[2], context); + auto s = state.coerceToString(pos, *args[2], context, "While evaluating the third argument (the string) passed to builtins.substring"); if (start < 0) throw EvalError({ @@ -3389,7 +3399,7 @@ static RegisterPrimOp primop_substring({ static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context); + auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.stringLength"); v.mkInt(s->size()); } @@ -3641,8 +3651,8 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * * { PathSet context; - auto sep = state.forceString(*args[0], context, pos, "While evaluating the first argument passed to builtins.concatStringsSep"); - state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.concatStringsSep"); + auto sep = state.forceString(*args[0], context, pos, "While evaluating the first argument (the separator string) passed to builtins.concatStringsSep"); + state.forceList(*args[1], pos, "While evaluating the second argument (the list of strings to concat) passed to builtins.concatStringsSep"); std::string res; res.reserve((args[1]->listSize() + 32) * sep.size()); @@ -3650,7 +3660,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * * for (auto elem : args[1]->listItems()) { if (first) first = false; else res += sep; - res += *state.coerceToString(pos, *elem, context); + res += *state.coerceToString(pos, *elem, context, "While evaluating one element of the list of strings to concat passed to builtins.concatStringsSep"); } v.mkString(res, context); diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index f1feb4dc6..78320dc09 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -7,7 +7,7 @@ namespace nix { static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context); + auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.unsafeDiscardStringContext"); v.mkString(*s); } @@ -33,7 +33,7 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext); static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context); + auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.unsafeDiscardOutputDependency"); PathSet context2; for (auto & p : context) diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index 199f7508e..dcaf3d362 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -22,7 +22,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar for (auto & attr : *args[0]->attrs) { std::string_view n(attr.name); if (n == "url") - url = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned(); + url = state.coerceToString(*attr.pos, *attr.value, context, false, false, "While evaluating the `url` attribute passed to builtins.fetchMercurial").toOwned(); else if (n == "rev") { // Ugly: unlike fetchGit, here the "rev" attribute can // be both a revision or a branch/tag name. @@ -48,7 +48,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar }); } else - url = state.coerceToString(pos, *args[0], context, false, false).toOwned(); + url = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.fetchMercurial").toOwned(); // FIXME: git externals probably can be used to bypass the URI // whitelist. Ah well. diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index a40eddfca..2baa272cb 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -125,7 +125,7 @@ static void fetchTree( if (attr.name == state.sType) continue; state.forceValue(*attr.value, *attr.pos); if (attr.value->type() == nPath || attr.value->type() == nString) { - auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned(); + auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false, "").toOwned(); attrs.emplace(attr.name, attr.name == "url" ? type == "git" @@ -151,7 +151,7 @@ static void fetchTree( input = fetchers::Input::fromAttrs(std::move(attrs)); } else { - auto url = state.coerceToString(pos, *args[0], context, false, false).toOwned(); + auto url = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to the fetcher").toOwned(); if (type == "git") { fetchers::Attrs attrs; diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index d0fa93e92..858227018 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -85,7 +85,7 @@ class ExternalValueBase /* Coerce the value to a string. Defaults to uncoercable, i.e. throws an * error. */ - virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const; + virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const; /* Compare to another value of the same type. Defaults to uncomparable, * i.e. always false. diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index af4f350ff..b30ccc7f6 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -132,9 +132,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); }); PathSet context; Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath)); - auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context); + auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context, ""); Attr & aOutPath(*topLevel.attrs->find(state.sOutPath)); - auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context); + auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context, ""); /* Realise the resulting store expression. */ debug("building user environment"); diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index aa074edc2..9ff66899e 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -97,13 +97,13 @@ struct CmdBundle : InstallableCommand throw Error("the bundler '%s' does not produce a derivation", bundler.what()); PathSet context2; - auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2); + auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2, ""); auto attr2 = vRes->attrs->get(evalState->sOutPath); if (!attr2) throw Error("the bundler '%s' does not produce a derivation", bundler.what()); - auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2); + auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2, ""); store->buildPaths({ DerivedPath::Built { drvPath } }); diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 8cd04d5fe..8ee3ba45b 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -107,7 +107,7 @@ struct CmdEval : MixJSON, InstallableCommand else if (raw) { stopProgressBar(); - std::cout << *state->coerceToString(noPos, *v, context); + std::cout << *state->coerceToString(noPos, *v, context, "While generating the eval command output"); } else if (json) { diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 703c3beb2..356f89713 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -448,7 +448,7 @@ struct CmdFlakeCheck : FlakeCommand if (auto attr = v.attrs->get(state->symbols.create("path"))) { if (attr->name == state->symbols.create("path")) { PathSet context; - auto path = state->coerceToPath(*attr->pos, *attr->value, context); + auto path = state->coerceToPath(*attr->pos, *attr->value, context, ""); if (!store->isInStore(path)) throw Error("template '%s' has a bad 'path' attribute"); // TODO: recursively check the flake in 'path'. diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 7011ff939..0cb68552c 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -461,7 +461,7 @@ bool NixRepl::processLine(std::string line) if (v.type() == nPath || v.type() == nString) { PathSet context; - auto filename = state->coerceToString(noPos, v, context); + auto filename = state->coerceToString(noPos, v, context, "While evaluating the filename to edit"); pos.file = state->symbols.create(*filename); } else if (v.isLambda()) { pos = v.lambda.fun->pos; @@ -780,7 +780,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m Bindings::iterator i = v.attrs->find(state->sDrvPath); PathSet context; if (i != v.attrs->end()) - str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context)); + str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context, "While evaluating the drvPath of a derivation")); else str << "???"; str << "»";