aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc43
-rw-r--r--src/libexpr/eval.hh15
-rw-r--r--src/libexpr/primops.cc6
-rw-r--r--src/libutil/error.cc9
-rw-r--r--src/libutil/error.hh3
5 files changed, 63 insertions, 13 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 27b333807..050b49833 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -837,6 +837,37 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
exceptions. */
template <typename ErrorType>
+void EvalState::throwFrameErrorWithTrace(
+ PosIdx pos, const char* format,
+ const std::string_view s1, const std::string_view s2,
+ const Symbol * sym1, const Symbol * sym2,
+ Value * val1, Value * val2,
+ PosIdx pos1,
+ const std::string_view s3,
+ const Suggestions * suggestions,
+ PosIdx tracePos, const std::string_view traceStr,
+ Env * env, Expr * expr)
+{
+ hintformat f(format);
+ if (!s1.empty()) { f = f % s1; }
+ if (!s2.empty()) { f = f % s2; }
+ if (sym1) { f = f % symbols[*sym1]; }
+ if (sym2) { f = f % symbols[*sym2]; }
+ if (val1) { f = f % showType(*val1); }
+ if (val2) { f = f % showType(*val2); }
+ if (pos1) { f = f % positions[pos1]; }
+ if (!s3.empty()) { f = f % s3; }
+
+ auto e = ErrorType(ErrorInfo {
+ .msg = f,
+ .errPos = positions[pos],
+ .suggestions = suggestions ? *suggestions : Suggestions(),
+ });
+ e.addTrace(positions[tracePos], traceStr, true);
+ debugThrow(e, env, expr);
+}
+
+template <typename ErrorType>
void EvalState::throwErrorWithTrace(
PosIdx pos, const char* format,
const std::string_view s1, const std::string_view s2,
@@ -901,9 +932,9 @@ void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2)
e.addTrace(std::nullopt, s, s2);
}
-void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const
+void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2, bool frame) const
{
- e.addTrace(positions[pos], s, s2);
+ e.addTrace(positions[pos], hintfmt(s, s2), frame);
}
static std::unique_ptr<DebugTraceStacker> makeDebugTraceStacker(
@@ -1164,7 +1195,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos, std::stri
Value v;
e->eval(*this, env, v);
if (v.type() != nBool)
- throwError<TypeError>(pos, "value is %1% while a Boolean was expected", "", "", 0, 0, &v, 0, noPos, "", 0, &env, e);
+ throwError<TypeError>(noPos, "value is %1% while a Boolean was expected", "", "", 0, 0, &v, 0, noPos, "", 0, &env, e);
return v.boolean;
} catch (Error & e) {
e.addTrace(positions[pos], errorCtx);
@@ -1178,7 +1209,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const PosIdx po
try {
e->eval(*this, env, v);
if (v.type() != nAttrs)
- throwError<TypeError>(pos, "value is %1% while a set was expected", "", "", 0, 0, &v, 0, noPos, "", 0, &env, e);
+ throwError<TypeError>(noPos, "value is %1% while a set was expected", "", "", 0, 0, &v, 0, noPos, "", 0, &env, e);
} catch (Error & e) {
e.addTrace(positions[pos], errorCtx);
throw;
@@ -1502,7 +1533,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
auto j = args[0]->attrs->get(i.name);
if (!j) {
if (!i.def) {
- throwErrorWithTrace<TypeError>(lambda.pos,
+ throwFrameErrorWithTrace<TypeError>(lambda.pos,
"function '%1%' called without required argument '%2%'",
(lambda.name ? std::string(symbols[lambda.name]) : "anonymous lambda"), "",
&i.name, 0, 0, 0, noPos, "", 0, pos, "from call site", fun.lambda.env, &lambda);
@@ -1525,7 +1556,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
for (auto & formal : lambda.formals->formals)
formalNames.insert(symbols[formal.name]);
auto suggestions = Suggestions::bestMatches(formalNames, symbols[i.name]);
- throwErrorWithTrace<TypeError>(lambda.pos,
+ throwFrameErrorWithTrace<TypeError>(lambda.pos,
"function '%1%' called with unexpected argument '%2%'",
(lambda.name ? std::string(symbols[lambda.name]) : "anonymous lambda"), "",
&i.name, 0, 0, 0, noPos, "", &suggestions, pos, "from call site", fun.lambda.env, &lambda);
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index fd5ac3e77..3d72d3fe1 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -314,6 +314,19 @@ public:
template <typename ErrorType>
[[gnu::noinline, gnu::noreturn]]
+ void throwFrameErrorWithTrace(
+ PosIdx pos, const char* format,
+ const std::string_view s1, const std::string_view s2,
+ const Symbol * sym1, const Symbol * sym2,
+ Value * val1, Value * val2,
+ PosIdx pos1,
+ const std::string_view s3,
+ const Suggestions * suggestions,
+ PosIdx tracePos, const std::string_view traceStr,
+ Env * env, Expr * expr);
+
+ template <typename ErrorType>
+ [[gnu::noinline, gnu::noreturn]]
void throwErrorWithTrace(
PosIdx pos, const char* format,
const std::string_view s1, const std::string_view s2,
@@ -340,7 +353,7 @@ public:
[[gnu::noinline]]
void addErrorTrace(Error & e, const char * s, const std::string & s2) const;
[[gnu::noinline]]
- void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const;
+ void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2, bool frame = false) const;
public:
/* Return true iff the value `v' denotes a derivation (i.e. a
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 9be4bbf6a..625b0aa4a 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1171,9 +1171,9 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
}
} catch (Error & e) {
- e.addTrace(state.positions[posDrvName],
- "while evaluating the attribute '%1%' of the derivation '%2%'",
- key, drvName);
+ e.addTrace(state.positions[noPos],
+ hintfmt("while evaluating the attribute '%1%' of the derivation '%2%'", key, drvName),
+ true);
throw;
}
}
diff --git a/src/libutil/error.cc b/src/libutil/error.cc
index 5f86e1e76..cf4f4a56f 100644
--- a/src/libutil/error.cc
+++ b/src/libutil/error.cc
@@ -9,9 +9,9 @@ namespace nix {
const std::string nativeSystem = SYSTEM;
-void BaseError::addTrace(std::optional<ErrPos> e, hintformat hint)
+void BaseError::addTrace(std::optional<ErrPos> e, hintformat hint, bool frame)
{
- err.traces.push_front(Trace { .pos = e, .hint = hint });
+ err.traces.push_front(Trace { .pos = e, .hint = hint, .frame = frame });
}
// c++ std::exception descendants must have a 'const char* what()' function.
@@ -382,6 +382,7 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
*
*/
+ bool frameOnly = false;
if (!einfo.traces.empty()) {
unsigned int count = 0;
for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) {
@@ -391,7 +392,11 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
}
if (iter->hint.str().empty()) continue;
+ if (frameOnly && !iter->frame) continue;
+
count++;
+ frameOnly = iter->frame;
+
oss << "\n" << "… " << iter->hint.str() << "\n";
if (iter->pos.has_value() && (*iter->pos)) {
diff --git a/src/libutil/error.hh b/src/libutil/error.hh
index 50335676e..bf99581e2 100644
--- a/src/libutil/error.hh
+++ b/src/libutil/error.hh
@@ -110,6 +110,7 @@ void printAtPos(const ErrPos & pos, std::ostream & out);
struct Trace {
std::optional<ErrPos> pos;
hintformat hint;
+ bool frame;
};
struct ErrorInfo {
@@ -188,7 +189,7 @@ public:
addTrace(e, hintfmt(std::string(fs), args...));
}
- void addTrace(std::optional<ErrPos> e, hintformat hint);
+ void addTrace(std::optional<ErrPos> e, hintformat hint, bool frame = false);
bool hasTrace() const { return !err.traces.empty(); }
};