Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print the value in error: cannot coerce messages #9553

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions doc/manual/rl-next/print-value-in-coercion-error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
synopsis: Coercion errors include the failing value
issues: #561
prs: #9553
description: {

The `error: cannot coerce a <TYPE> to a string` message now includes the value which caused the error.

Previously, a failed string coercion produced a confusing error message if the trace didn't show where the offending value was defined:

```bash
$ nix-instantiate --eval --expr '
let x = { a = 1; }; in

"${x}"
'
error:
… while evaluating a path segment

at «string»:4:2:

3|
4| "${x}"
| ^
5|

error: cannot coerce a set to a string
```

Now, the error message includes the value itself:

```bash
$ nix-instantiate --eval --expr '
let x = { a = 1; }; in

"${x}"
'
error:
… while evaluating a path segment

at «string»:4:2:

3|
4| "${x}"
| ^
5|

error: cannot coerce a set to a string: { a = 1; }
```

}
2 changes: 1 addition & 1 deletion doc/manual/src/language/string-interpolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ If neither is present, an error is thrown.
> "${a}"
> ```
>
> error: cannot coerce a set to a string
> error: cannot coerce a set to a string: { }
>
> at «string»:4:2:
>
Expand Down
10 changes: 6 additions & 4 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <fstream>
#include <functional>
#include <strstream>

#include <sys/resource.h>
#include <nlohmann/json.hpp>
Expand Down Expand Up @@ -2286,7 +2286,7 @@ BackedStringView EvalState::coerceToString(
return std::move(*maybeString);
auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) {
error("cannot coerce %1% to a string", showType(v))
error("cannot coerce %1% to a string: %2%", showType(v), printValue(*this, v))
.withTrace(pos, errorCtx)
.debugThrow<TypeError>();
}
Expand Down Expand Up @@ -2332,7 +2332,7 @@ BackedStringView EvalState::coerceToString(
}
}

error("cannot coerce %1% to a string", showType(v))
error("cannot coerce %1% to a string: %2%", showType(v), printValue(*this, v))
.withTrace(pos, errorCtx)
.debugThrow<TypeError>();
}
Expand Down Expand Up @@ -2691,8 +2691,10 @@ void EvalState::printStatistics()

std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
{
std::strstream printed;
print(printed);
throw TypeError({
.msg = hintfmt("cannot coerce %1% to a string", showType())
.msg = hintfmt("cannot coerce %1% to a string: %2%", showType(), printed.str())
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ error:
| ^
2|

error: cannot coerce a function to a string
error: cannot coerce a function to a string: <LAMBDA>
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ error:
| ^
2|

error: cannot coerce a function to a string
error: cannot coerce a function to a string: <LAMBDA>
28 changes: 14 additions & 14 deletions tests/unit/libexpr/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 string", "a list"),
hintfmt("cannot coerce %s to a string: %s", "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 string", "a Boolean"),
hintfmt("cannot coerce %s to a string: %s", "a Boolean", "true"),
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 string", "a list"),
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
hintfmt("while realising the context of a path"));

ASSERT_TRACE2("pathExists \"zorglub\"",
Expand All @@ -332,7 +332,7 @@ namespace nix {
TEST_F(ErrorTraceTest, baseNameOf) {
ASSERT_TRACE2("baseNameOf []",
TypeError,
hintfmt("cannot coerce %s to a string", "a list"),
hintfmt("cannot coerce %s to a string: %s", "a list", "[ ]"),
hintfmt("while evaluating the first argument passed to builtins.baseNameOf"));

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

ASSERT_TRACE2("filterSource [] \"foo\"",
Expand Down Expand Up @@ -1038,7 +1038,7 @@ namespace nix {
TEST_F(ErrorTraceTest, toString) {
ASSERT_TRACE2("toString { a = 1; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ a = 1; }"),
hintfmt("while evaluating the first argument passed to builtins.toString"));

}
Expand All @@ -1057,7 +1057,7 @@ namespace nix {

ASSERT_TRACE2("substring 0 3 {}",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating the third argument (the string) passed to builtins.substring"));

ASSERT_TRACE1("substring (-3) 3 \"sometext\"",
Expand All @@ -1070,7 +1070,7 @@ namespace nix {
TEST_F(ErrorTraceTest, stringLength) {
ASSERT_TRACE2("stringLength {} # TODO: context is missing ???",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating the argument passed to builtins.stringLength"));

}
Expand Down Expand Up @@ -1143,7 +1143,7 @@ namespace nix {

ASSERT_TRACE2("concatStringsSep \"foo\" [ 1 2 {} ] # TODO: coerce to string is buggy",
TypeError,
hintfmt("cannot coerce %s to a string", "an integer"),
hintfmt("cannot coerce %s to a string: %s", "an integer", "1"),
hintfmt("while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep"));

}
Expand Down Expand Up @@ -1229,12 +1229,12 @@ namespace nix {

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = {}; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating the attribute 'system' of derivation 'foo'"));

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = {}; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'"));

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"drv\"; }",
Expand Down Expand Up @@ -1279,17 +1279,17 @@ namespace nix {

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ {} ]; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating an element of the argument list"));

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ \"a\" {} ]; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating an element of the argument list"));

ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; FOO = {}; }",
TypeError,
hintfmt("cannot coerce %s to a string", "a set"),
hintfmt("cannot coerce %s to a string: %s", "a set", "{ }"),
hintfmt("while evaluating the attribute 'FOO' of derivation 'foo'"));

}
Expand Down
Loading