diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 715608ad2..903eacf5e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1998,6 +1998,11 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else if (firstType == nPath) { if (!first) { auto part = state.coerceToString(i_pos, *vTmp, context, false, false); + if (sSize <= 1 && !hasPrefix(*part, "/")) + state.throwEvalError(i_pos, + "cannot append non-absolute path '%1%' to '%2%' (hint: change it to '/%1%')", + (std::string) *part, accessor->root().to_string(), + env, *this); sSize += part->size(); s.emplace_back(std::move(part)); } diff --git a/tests/toString-path.sh b/tests/toString-path.sh index c17dc262e..1c469ace6 100644 --- a/tests/toString-path.sh +++ b/tests/toString-path.sh @@ -3,6 +3,10 @@ source common.sh mkdir -p $TEST_ROOT/foo echo bla > $TEST_ROOT/foo/bar -[[ $(nix eval --raw --impure --expr "builtins.readFile (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"bar\"))") = bla ]] +[[ $(nix eval --raw --impure --expr "builtins.readFile (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"/bar\"))") = bla ]] + +[[ $(nix eval --raw --impure --expr "builtins.readFile (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"/b\" + \"ar\"))") = bla ]] + +(! nix eval --raw --impure --expr "builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"bar\"") [[ $(nix eval --json --impure --expr "builtins.readDir (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; }))") = '{"bar":"regular"}' ]]