libexpr: add set-to-string error frame

this is much more useful than a frame pointing to the set but claiming
it as a function being called. if the function is actually at fault we
will now point to its attribute, although the position may be slightly
wrong if __toString was defined from set updates or builtin functions.

Change-Id: Ib3eb237a276d94426d9c6fc0e26eea72382d34a2
This commit is contained in:
eldritch horrors
2025-04-27 11:01:22 +00:00
parent 9d761ed5c1
commit eb0280f715
4 changed files with 84 additions and 4 deletions
+60
View File
@@ -0,0 +1,60 @@
---
synopsis: 'Implicit `__toString` now have stack trace entries'
issues: []
cls: [3055]
category: Improvements
credits: [horrors]
---
Coercion of attribute sets to strings via their `__toString` attribute now produce stack
frames pointing to the coercion site and the attribute definition. This makes locating a
coercion function error easier as the fault location is now more likely to be presented.
Previously:
```
nix-repl> builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
error:
… while calling the 'substring' builtin
at «string»:1:1:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… caused by explicit throw
at «string»:1:48:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
error: bar
```
Now:
```
nix-repl> builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
error:
… while calling the 'substring' builtin
at «string»:1:1:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… while converting a set to string
at «string»:1:25:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… from call site
at «string»:1:29:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… while calling '__toString'
at «string»:1:42:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… caused by explicit throw
at «string»:1:48:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
error: bar
```
+9 -4
View File
@@ -2309,10 +2309,15 @@ std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value &
auto i = v.attrs->find(ctx.s.toString);
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(pos, v1, context,
"while evaluating the result of the `__toString` attribute",
coerceMore, copyToStore).toOwned();
try {
callFunction(*i->value, v, v1, i->pos);
return coerceToString(pos, v1, context,
"while evaluating the result of the `__toString` attribute",
coerceMore, copyToStore).toOwned();
} catch (EvalError & e) {
e.addTrace(ctx.positions[pos], "while converting a set to string");
throw;
}
}
return {};
@@ -0,0 +1,14 @@
error:
… while calling the 'toString' builtin
at /pwd/lang/eval-fail-toString.nix:1:1:
1| toString { __toString = 1; }
| ^
2|
… while converting a set to string
error: attempt to call something which is not a function but an integer: 1
at /pwd/lang/eval-fail-toString.nix:1:12:
1| toString { __toString = 1; }
| ^
2|
@@ -0,0 +1 @@
toString { __toString = 1; }