aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-03-04 21:47:58 +0100
committerGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-03-04 21:47:58 +0100
commit3a5855353e5dc2986c38bb66eaff5538dea70da1 (patch)
treef21f14e5e959b8ce68cc8045db3e98911587d8fb /src
parentbe1f0697468bd6c0f2be4f7e058270c161098e9f (diff)
Add detailed error mesage for coerceTo{String,Path}
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc34
-rw-r--r--src/libexpr/eval.hh7
-rw-r--r--src/libexpr/flake/flake.cc2
-rw-r--r--src/libexpr/get-drvs.cc6
-rw-r--r--src/libexpr/primops.cc66
-rw-r--r--src/libexpr/primops/context.cc4
-rw-r--r--src/libexpr/primops/fetchMercurial.cc4
-rw-r--r--src/libexpr/primops/fetchTree.cc4
-rw-r--r--src/libexpr/value.hh2
-rw-r--r--src/nix-env/user-env.cc4
-rw-r--r--src/nix/bundle.cc4
-rw-r--r--src/nix/eval.cc2
-rw-r--r--src/nix/flake.cc2
-rw-r--r--src/nix/repl.cc4
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<std::string> 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<StorePath> 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 << "»";