Skip to content

Commit

Permalink
coerceToPath(): Handle __toString, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
edolstra committed Oct 20, 2023
1 parent bacceae commit 173abec
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 16 deletions.
27 changes: 15 additions & 12 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2335,29 +2335,32 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
{
try {
forceValue(v, pos);

if (v.type() == nString) {
copyContext(v, context);
auto s = v.string_view();
if (!hasPrefix(s, "/"))
error("string '%s' doesn't represent an absolute path", s).atPos(pos).debugThrow<EvalError>();
return rootPath(CanonPath(s));
}
} catch (Error & e) {
e.addTrace(positions[pos], errorCtx);
throw;
}

/* Handle path values directly, without coercing to a string. */
if (v.type() == nPath)
return v.path();

/* Similarly, handle __toString where the result may be a path
value. */
if (v.type() == nAttrs) {
auto i = v.attrs->find(sOutPath);
if (i != v.attrs->end())
return coerceToPath(pos, *i->value, context, errorCtx);
auto i = v.attrs->find(sToString);
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToPath(pos, v1, context, errorCtx);
}
}

error("cannot coerce %1% to a path", showType(v)).withTrace(pos, errorCtx).debugThrow<TypeError>();
/* Any other value should be coercable to a string, interpreted
relative to the root filesystem. */
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (path == "" || path[0] != '/')
error("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow<EvalError>();
return rootPath(CanonPath(path));
}


Expand Down
8 changes: 4 additions & 4 deletions src/libexpr/tests/error_traces.cc
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ namespace nix {
TEST_F(ErrorTraceTest, toPath) {
ASSERT_TRACE2("toPath []",
TypeError,
hintfmt("cannot coerce %s to a path", "a list"),
hintfmt("cannot coerce %s to a string", "a list"),
hintfmt("while evaluating the first argument passed to builtins.toPath"));

ASSERT_TRACE2("toPath \"foo\"",
Expand All @@ -309,7 +309,7 @@ namespace nix {
TEST_F(ErrorTraceTest, storePath) {
ASSERT_TRACE2("storePath true",
TypeError,
hintfmt("cannot coerce %s to a path", "a Boolean"),
hintfmt("cannot coerce %s to a string", "a Boolean"),
hintfmt("while evaluating the first argument passed to 'builtins.storePath'"));

}
Expand All @@ -318,7 +318,7 @@ namespace nix {
TEST_F(ErrorTraceTest, pathExists) {
ASSERT_TRACE2("pathExists []",
TypeError,
hintfmt("cannot coerce %s to a path", "a list"),
hintfmt("cannot coerce %s to a string", "a list"),
hintfmt("while realising the context of a path"));

ASSERT_TRACE2("pathExists \"zorglub\"",
Expand Down Expand Up @@ -377,7 +377,7 @@ namespace nix {
TEST_F(ErrorTraceTest, filterSource) {
ASSERT_TRACE2("filterSource [] []",
TypeError,
hintfmt("cannot coerce %s to a path", "a list"),
hintfmt("cannot coerce %s to a string", "a list"),
hintfmt("while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'"));

ASSERT_TRACE2("filterSource [] \"foo\"",
Expand Down
2 changes: 2 additions & 0 deletions tests/functional/lang/eval-okay-pathexists.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ builtins.pathExists (./lib.nix)
&& builtins.pathExists (builtins.toString ./. + "/../lang/..//")
&& builtins.pathExists (builtins.toPath (builtins.toString ./lib.nix))
&& !builtins.pathExists (builtins.toPath (builtins.toString ./bla.nix))
&& builtins.pathExists (builtins.toPath { __toString = x: builtins.toString ./lib.nix; })
&& builtins.pathExists (builtins.toPath { outPath = builtins.toString ./lib.nix; })
&& builtins.pathExists ./lib.nix
&& !builtins.pathExists ./bla.nix

0 comments on commit 173abec

Please sign in to comment.