Merge pull request #10066 from 9999years/print-all-frames

Do not skip any stack frames when `--show-trace` is given
This commit is contained in:
Robert Hensing 2024-02-23 18:53:11 +01:00 committed by GitHub
commit 0b47783d0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 44 additions and 34 deletions

View file

@ -28,15 +28,7 @@ template<class T>
EvalErrorBuilder<T> & EvalErrorBuilder<T>::withTrace(PosIdx pos, const std::string_view text) EvalErrorBuilder<T> & EvalErrorBuilder<T>::withTrace(PosIdx pos, const std::string_view text)
{ {
error.err.traces.push_front( error.err.traces.push_front(
Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text)), .frame = false}); Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text))});
return *this;
}
template<class T>
EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrameTrace(PosIdx pos, const std::string_view text)
{
error.err.traces.push_front(
Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text)), .frame = true});
return *this; return *this;
} }
@ -63,9 +55,9 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrame(const Env & env, const Expr
} }
template<class T> template<class T>
EvalErrorBuilder<T> & EvalErrorBuilder<T>::addTrace(PosIdx pos, HintFmt hint, bool frame) EvalErrorBuilder<T> & EvalErrorBuilder<T>::addTrace(PosIdx pos, HintFmt hint)
{ {
error.addTrace(error.state.positions[pos], hint, frame); error.addTrace(error.state.positions[pos], hint);
return *this; return *this;
} }

View file

@ -89,7 +89,7 @@ public:
[[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & withFrame(const Env & e, const Expr & ex); [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & withFrame(const Env & e, const Expr & ex);
[[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & addTrace(PosIdx pos, HintFmt hint, bool frame = false); [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & addTrace(PosIdx pos, HintFmt hint);
template<typename... Args> template<typename... Args>
[[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> &

View file

@ -806,14 +806,16 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
} }
} }
void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2) const template<typename... Args>
void EvalState::addErrorTrace(Error & e, const Args & ... formatArgs) const
{ {
e.addTrace(nullptr, s, s2); e.addTrace(nullptr, HintFmt(formatArgs...));
} }
void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2, bool frame) const template<typename... Args>
void EvalState::addErrorTrace(Error & e, const PosIdx pos, const Args & ... formatArgs) const
{ {
e.addTrace(positions[pos], HintFmt(s, s2), frame); e.addTrace(positions[pos], HintFmt(formatArgs...));
} }
template<typename... Args> template<typename... Args>
@ -1587,9 +1589,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
"while calling %s", "while calling %s",
lambda.name lambda.name
? concatStrings("'", symbols[lambda.name], "'") ? concatStrings("'", symbols[lambda.name], "'")
: "anonymous lambda", : "anonymous lambda");
true); if (pos) addErrorTrace(e, pos, "from call site");
if (pos) addErrorTrace(e, pos, "from call site%s", "", true);
} }
throw; throw;
} }

View file

@ -432,10 +432,12 @@ public:
std::string_view forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx); std::string_view forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx);
std::string_view forceStringNoCtx(Value & v, const PosIdx pos, std::string_view errorCtx); std::string_view forceStringNoCtx(Value & v, const PosIdx pos, std::string_view errorCtx);
template<typename... Args>
[[gnu::noinline]] [[gnu::noinline]]
void addErrorTrace(Error & e, const char * s, const std::string & s2) const; void addErrorTrace(Error & e, const Args & ... formatArgs) const;
template<typename... Args>
[[gnu::noinline]] [[gnu::noinline]]
void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2, bool frame = false) const; void addErrorTrace(Error & e, const PosIdx pos, const Args & ... formatArgs) const;
public: public:
/** /**

View file

@ -811,7 +811,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * *
auto message = state.coerceToString(pos, *args[0], context, auto message = state.coerceToString(pos, *args[0], context,
"while evaluating the error message passed to builtins.addErrorContext", "while evaluating the error message passed to builtins.addErrorContext",
false, false).toOwned(); false, false).toOwned();
e.addTrace(nullptr, HintFmt(message), true); e.addTrace(nullptr, HintFmt(message));
throw; throw;
} }
} }
@ -1075,7 +1075,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
e.addTrace(nullptr, HintFmt( e.addTrace(nullptr, HintFmt(
"while evaluating derivation '%s'\n" "while evaluating derivation '%s'\n"
" whose name attribute is located at %s", " whose name attribute is located at %s",
drvName, pos), true); drvName, pos));
throw; throw;
} }
} }
@ -1233,8 +1233,7 @@ drvName, Bindings * attrs, Value & v)
} catch (Error & e) { } catch (Error & e) {
e.addTrace(state.positions[i->pos], e.addTrace(state.positions[i->pos],
HintFmt("while evaluating attribute '%1%' of derivation '%2%'", key, drvName), HintFmt("while evaluating attribute '%1%' of derivation '%2%'", key, drvName));
true);
throw; throw;
} }
} }

View file

@ -11,9 +11,9 @@
namespace nix { namespace nix {
void BaseError::addTrace(std::shared_ptr<Pos> && e, HintFmt hint, bool frame) void BaseError::addTrace(std::shared_ptr<Pos> && e, HintFmt hint)
{ {
err.traces.push_front(Trace { .pos = std::move(e), .hint = hint, .frame = frame }); err.traces.push_front(Trace { .pos = std::move(e), .hint = hint });
} }
void throwExceptionSelfCheck(){ void throwExceptionSelfCheck(){
@ -61,8 +61,7 @@ inline bool operator<(const Trace& lhs, const Trace& rhs)
// This formats a freshly formatted hint string and then throws it away, which // This formats a freshly formatted hint string and then throws it away, which
// shouldn't be much of a problem because it only runs when pos is equal, and this function is // shouldn't be much of a problem because it only runs when pos is equal, and this function is
// used for trace printing, which is infrequent. // used for trace printing, which is infrequent.
return std::forward_as_tuple(lhs.hint.str(), lhs.frame) return lhs.hint.str() < rhs.hint.str();
< std::forward_as_tuple(rhs.hint.str(), rhs.frame);
} }
inline bool operator> (const Trace& lhs, const Trace& rhs) { return rhs < lhs; } inline bool operator> (const Trace& lhs, const Trace& rhs) { return rhs < lhs; }
inline bool operator<=(const Trace& lhs, const Trace& rhs) { return !(lhs > rhs); } inline bool operator<=(const Trace& lhs, const Trace& rhs) { return !(lhs > rhs); }
@ -373,7 +372,6 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
// prepended to each element of the trace // prepended to each element of the trace
auto ellipsisIndent = " "; auto ellipsisIndent = " ";
bool frameOnly = false;
if (!einfo.traces.empty()) { if (!einfo.traces.empty()) {
// Stack traces seen since we last printed a chunk of `duplicate frames // Stack traces seen since we last printed a chunk of `duplicate frames
// omitted`. // omitted`.
@ -384,7 +382,6 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
for (const auto & trace : einfo.traces) { for (const auto & trace : einfo.traces) {
if (trace.hint.str().empty()) continue; if (trace.hint.str().empty()) continue;
if (frameOnly && !trace.frame) continue;
if (!showTrace && count > 3) { if (!showTrace && count > 3) {
oss << "\n" << ANSI_WARNING "(stack trace truncated; use '--show-trace' to show the full trace)" ANSI_NORMAL << "\n"; oss << "\n" << ANSI_WARNING "(stack trace truncated; use '--show-trace' to show the full trace)" ANSI_NORMAL << "\n";
@ -400,7 +397,6 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
printSkippedTracesMaybe(oss, ellipsisIndent, count, skippedTraces, tracesSeen); printSkippedTracesMaybe(oss, ellipsisIndent, count, skippedTraces, tracesSeen);
count++; count++;
frameOnly = trace.frame;
printTrace(oss, ellipsisIndent, count, trace); printTrace(oss, ellipsisIndent, count, trace);
} }

View file

@ -64,7 +64,6 @@ void printCodeLines(std::ostream & out,
struct Trace { struct Trace {
std::shared_ptr<Pos> pos; std::shared_ptr<Pos> pos;
HintFmt hint; HintFmt hint;
bool frame;
}; };
inline bool operator<(const Trace& lhs, const Trace& rhs); inline bool operator<(const Trace& lhs, const Trace& rhs);
@ -162,7 +161,7 @@ public:
addTrace(std::move(e), HintFmt(std::string(fs), args...)); addTrace(std::move(e), HintFmt(std::string(fs), args...));
} }
void addTrace(std::shared_ptr<Pos> && e, HintFmt hint, bool frame = false); void addTrace(std::shared_ptr<Pos> && e, HintFmt hint);
bool hasTrace() const { return !err.traces.empty(); } bool hasTrace() const { return !err.traces.empty(); }

View file

@ -41,4 +41,11 @@ error:
| ^ | ^
5| if n > 0 5| if n > 0
… while calling the 'throw' builtin
at /pwd/lang/eval-fail-duplicate-traces.nix:7:10:
6| then throwAfter (n - 1)
7| else throw "Uh oh!";
| ^
8| in
error: Uh oh! error: Uh oh!

View file

@ -27,4 +27,11 @@ error:
| ^ | ^
6| 6|
… while calling the 'throw' builtin
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:5:9:
4| null
5| [ (_: throw "Not the final value, but is still forced!") (_: 23) ]
| ^
6|
error: Not the final value, but is still forced! error: Not the final value, but is still forced!

View file

@ -54,4 +54,11 @@ error:
(21 duplicate frames omitted) (21 duplicate frames omitted)
… while calling the 'throw' builtin
at /pwd/lang/eval-fail-mutual-recursion.nix:34:10:
33| then throwAfterB true 10
34| else throw "Uh oh!";
| ^
35| in
error: Uh oh! error: Uh oh!