From 1de04fdc2e84b474982bc24532d21b4ae43f69f0 Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Fri, 9 Feb 2024 09:17:33 -0800 Subject: [PATCH] Add TypeError --- src/libexpr/attr-path.cc | 19 ++- src/libexpr/eval-cache.cc | 29 ++-- src/libexpr/eval-error.cc | 13 ++ src/libexpr/eval-error.hh | 36 ++++- src/libexpr/eval-inline.hh | 12 +- src/libexpr/eval.cc | 106 ++---------- src/libexpr/eval.hh | 11 +- src/libexpr/flake/flake.cc | 6 +- src/libexpr/get-drvs.cc | 8 +- src/libexpr/primops.cc | 6 +- src/libexpr/primops/fetchTree.cc | 3 +- src/libexpr/value-to-json.cc | 4 +- src/libexpr/value.cc | 54 +++++++ src/libexpr/value.hh | 8 + src/nix/eval.cc | 3 +- src/nix/flake.cc | 2 +- src/nix/profile.cc | 8 +- tests/functional/misc.sh | 4 +- tests/unit/libexpr/error_traces.cc | 252 ++++++++++++++--------------- tests/unit/libexpr/primops.cc | 2 +- 20 files changed, 300 insertions(+), 286 deletions(-) create mode 100644 src/libexpr/value.cc diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index d6befd362e4..2b3e8becb2b 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -57,18 +57,18 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin Value * vNew = state.allocValue(); state.autoCallFunction(autoArgs, *v, *vNew); v = vNew; - state.forceValue(*v, noPos); + state.forceValue(*v, pos); /* It should evaluate to either a set or an expression, according to what is specified in the attrPath. */ if (!attrIndex) { - if (v->type() != nAttrs) - state.error( - "the expression selected by the selection path '%1%' should be a set but is %2%", - attrPath, - showType(*v)).debugThrow(); + if (v->type() != nAttrs) { + state.error(nAttrs, *v) + .addTrace(pos, HintFmt("while evaluating the selection path %1%", attrPath)) + .debugThrow(); + } if (attr.empty()) throw Error("empty attribute name in selection path '%1%'", attrPath); @@ -88,10 +88,9 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin else { if (!v->isList()) - state.error( - "the expression selected by the selection path '%1%' should be a list but is %2%", - attrPath, - showType(*v)).debugThrow(); + state.error(nList, *v) + .addTrace(pos, HintFmt("while evaluating the selection path %1%", attrPath)) + .debugThrow(); if (*attrIndex >= v->listSize()) throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath); diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 2fc69e79674..36018c9299f 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -500,7 +500,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro // evaluate to see whether 'name' exists } else return nullptr; - //error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); + //error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); } } @@ -508,7 +508,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro if (v.type() != nAttrs) return nullptr; - //error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); + //error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); auto attr = v.attrs->get(name); @@ -574,14 +574,15 @@ std::string AttrCursor::getString() debug("using cached string attribute '%s'", getAttrPathStr()); return s->first; } else - root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow(); + // TODO: Is this an internal error? Where is literally any documentation for the eval cache? + root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow(); } } auto & v = forceValue(); if (v.type() != nString && v.type() != nPath) - root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow(); return v.type() == nString ? v.c_str() : v.path().to_string(); } @@ -616,7 +617,7 @@ string_t AttrCursor::getStringWithContext() return *s; } } else - root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow(); } } @@ -630,7 +631,7 @@ string_t AttrCursor::getStringWithContext() else if (v.type() == nPath) return {v.path().to_string(), {}}; else - root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow(); } bool AttrCursor::getBool() @@ -643,14 +644,14 @@ bool AttrCursor::getBool() debug("using cached Boolean attribute '%s'", getAttrPathStr()); return *b; } else - root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow(); } } auto & v = forceValue(); if (v.type() != nBool) - root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow(); return v.boolean; } @@ -665,14 +666,14 @@ NixInt AttrCursor::getInt() debug("using cached integer attribute '%s'", getAttrPathStr()); return i->x; } else - root->state.error("'%s' is not an integer", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not an integer", getAttrPathStr()).debugThrow(); } } auto & v = forceValue(); if (v.type() != nInt) - root->state.error("'%s' is not an integer", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not an integer", getAttrPathStr()).debugThrow(); return v.integer; } @@ -687,7 +688,7 @@ std::vector AttrCursor::getListOfStrings() debug("using cached list of strings attribute '%s'", getAttrPathStr()); return *l; } else - root->state.error("'%s' is not a list of strings", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a list of strings", getAttrPathStr()).debugThrow(); } } @@ -697,7 +698,7 @@ std::vector AttrCursor::getListOfStrings() root->state.forceValue(v, noPos); if (v.type() != nList) - root->state.error("'%s' is not a list", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not a list", getAttrPathStr()).debugThrow(); std::vector res; @@ -720,14 +721,14 @@ std::vector AttrCursor::getAttrs() debug("using cached attrset attribute '%s'", getAttrPathStr()); return *attrs; } else - root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); } } auto & v = forceValue(); if (v.type() != nAttrs) - root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); + root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow(); std::vector attrs; for (auto & attr : *getValue().attrs) diff --git a/src/libexpr/eval-error.cc b/src/libexpr/eval-error.cc index 8db03610b14..79e41c22d3f 100644 --- a/src/libexpr/eval-error.cc +++ b/src/libexpr/eval-error.cc @@ -101,5 +101,18 @@ template class EvalErrorBuilder; template class EvalErrorBuilder; template class EvalErrorBuilder; template class EvalErrorBuilder; +template class EvalErrorBuilder; + + +MissingAttrError::MissingAttrError(EvalState & state, Symbol attr, Value & actual) + : EvalError( + state, + "attribute '%1%' missing: %2%", + state.symbols[attr], + ValuePrinter(state, actual, errorPrintOptions)) + , attr(attr) + , actual(actual) +{ +} } diff --git a/src/libexpr/eval-error.hh b/src/libexpr/eval-error.hh index 7e0cbe982ec..d2b1520c7f4 100644 --- a/src/libexpr/eval-error.hh +++ b/src/libexpr/eval-error.hh @@ -4,6 +4,9 @@ #include "error.hh" #include "pos-idx.hh" +#include "print-options.hh" +#include "print.hh" +#include "value.hh" namespace nix { @@ -40,12 +43,39 @@ MakeError(ParseError, Error); MakeError(AssertionError, EvalError); MakeError(ThrownError, AssertionError); MakeError(Abort, EvalError); -MakeError(TypeError, EvalError); MakeError(UndefinedVarError, EvalError); MakeError(MissingArgumentError, EvalError); MakeError(CachedEvalError, EvalError); MakeError(InfiniteRecursionError, EvalError); +std::string_view showType(ValueType type, bool article); + +struct TypeError : public EvalError +{ + ValueType expected; + Value & actual; + + TypeError(EvalState & state, ValueType expected, Value & actual) + : EvalError( + state, + "expected %1% but found %2%: %3%", + showType(expected), + showType(actual), + ValuePrinter(state, actual, errorPrintOptions)) + , expected(expected) + , actual(actual) + { + } +}; + +struct MissingAttrError : public EvalError +{ + Symbol attr; + Value & actual; + + MissingAttrError(EvalState & state, Symbol attr, Value & actual); +}; + struct InvalidPathError : public EvalError { public: @@ -67,7 +97,7 @@ class EvalErrorBuilder final friend class EvalState; template - explicit EvalErrorBuilder(EvalState & state, const Args &... args) + explicit EvalErrorBuilder(EvalState & state, Args && ... args) : error(T(state, args...)) { } @@ -83,8 +113,6 @@ public: [[nodiscard, gnu::noinline]] EvalErrorBuilder & withTrace(PosIdx pos, const std::string_view text); - [[nodiscard, gnu::noinline]] EvalErrorBuilder & withFrameTrace(PosIdx pos, const std::string_view text); - [[nodiscard, gnu::noinline]] EvalErrorBuilder & withSuggestions(Suggestions & s); [[nodiscard, gnu::noinline]] EvalErrorBuilder & withFrame(const Env & e, const Expr & ex); diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 03320c7c977..3b830888fa5 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -116,11 +116,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos, std::string_view e PosIdx pos = getPos(); forceValue(v, pos); if (v.type() != nAttrs) { - error( - "expected a set but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).withTrace(pos, errorCtx).debugThrow(); + error(nAttrs, v).withTrace(pos, errorCtx).debugThrow(); } } @@ -130,11 +126,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos, std::string_view e { forceValue(v, pos); if (!v.isList()) { - error( - "expected a list but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).withTrace(pos, errorCtx).debugThrow(); + error(nList, v).withTrace(pos, errorCtx).debugThrow(); } } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bbccfcd295f..bb750c09907 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -128,55 +128,6 @@ void Value::print(EvalState & state, std::ostream & str, PrintOptions options) printValue(state, str, *this, options); } -const Value * getPrimOp(const Value &v) { - const Value * primOp = &v; - while (primOp->isPrimOpApp()) { - primOp = primOp->primOpApp.left; - } - assert(primOp->isPrimOp()); - return primOp; -} - -std::string_view showType(ValueType type, bool withArticle) -{ - #define WA(a, w) withArticle ? a " " w : w - switch (type) { - case nInt: return WA("an", "integer"); - case nBool: return WA("a", "Boolean"); - case nString: return WA("a", "string"); - case nPath: return WA("a", "path"); - case nNull: return "null"; - case nAttrs: return WA("a", "set"); - case nList: return WA("a", "list"); - case nFunction: return WA("a", "function"); - case nExternal: return WA("an", "external value"); - case nFloat: return WA("a", "float"); - case nThunk: return WA("a", "thunk"); - } - abort(); -} - - -std::string showType(const Value & v) -{ - // Allow selecting a subset of enum values - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch-enum" - switch (v.internalType) { - case tString: return v.string.context ? "a string with context" : "a string"; - case tPrimOp: - return fmt("the built-in function '%s'", std::string(v.primOp->name)); - case tPrimOpApp: - return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name)); - case tExternal: return v.external->showType(); - case tThunk: return v.isBlackhole() ? "a black hole" : "a thunk"; - case tApp: return "a function application"; - default: - return std::string(showType(v.type())); - } - #pragma GCC diagnostic pop -} - PosIdx Value::determinePos(const PosIdx pos) const { // Allow selecting a subset of enum values @@ -1153,11 +1104,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) - error( - "expected a Boolean but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).withFrame(env, *e).debugThrow(); + error(nBool, v).atPos(pos).withFrame(env, *e).debugThrow(); return v.boolean; } catch (Error & e) { e.addTrace(positions[pos], errorCtx); @@ -1171,11 +1118,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const PosIdx po try { e->eval(*this, env, v); if (v.type() != nAttrs) - error( - "expected a set but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).withFrame(env, *e).debugThrow(); + error(nAttrs, v).withFrame(env, *e).debugThrow(); } catch (Error & e) { e.addTrace(positions[pos], errorCtx); throw; @@ -1565,7 +1508,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) { - error("function '%1%' called without required argument '%2%'", + error("function '%1%' called without required argument '%2%'", (lambda.name ? std::string(symbols[lambda.name]) : "anonymous lambda"), symbols[i.name]) .atPos(lambda.pos) @@ -1591,7 +1534,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]); - error("function '%1%' called with unexpected argument '%2%'", + error("function '%1%' called with unexpected argument '%2%'", (lambda.name ? std::string(symbols[lambda.name]) : "anonymous lambda"), symbols[i.name]) .atPos(lambda.pos) @@ -1729,10 +1672,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } else - error( - "attempt to call something which is not a function but %1%: %2%", - showType(vCur), - ValuePrinter(*this, vCur, errorPrintOptions)) + error(nFunction, vCur) .atPos(pos) .debugThrow(); } @@ -2138,11 +2078,7 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos, std::string_view errorCt try { forceValue(v, pos); if (v.type() != nInt) - error( - "expected an integer but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).debugThrow(); + error(nInt, v).atPos(pos).debugThrow(); return v.integer; } catch (Error & e) { e.addTrace(positions[pos], errorCtx); @@ -2160,11 +2096,7 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos, std::string_view err if (v.type() == nInt) return v.integer; else if (v.type() != nFloat) - error( - "expected a float but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).debugThrow(); + error(nFloat, v).atPos(pos).debugThrow(); return v.fpoint; } catch (Error & e) { e.addTrace(positions[pos], errorCtx); @@ -2178,11 +2110,7 @@ bool EvalState::forceBool(Value & v, const PosIdx pos, std::string_view errorCtx try { forceValue(v, pos); if (v.type() != nBool) - error( - "expected a Boolean but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).debugThrow(); + error(nBool, v).atPos(pos).debugThrow(); return v.boolean; } catch (Error & e) { e.addTrace(positions[pos], errorCtx); @@ -2204,11 +2132,7 @@ void EvalState::forceFunction(Value & v, const PosIdx pos, std::string_view erro try { forceValue(v, pos); if (v.type() != nFunction && !isFunctor(v)) - error( - "expected a function but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).debugThrow(); + error(nFunction, v).atPos(pos).debugThrow(); } catch (Error & e) { e.addTrace(positions[pos], errorCtx); throw; @@ -2221,11 +2145,7 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos, std::string try { forceValue(v, pos); if (v.type() != nString) - error( - "expected a string but found %1%: %2%", - showType(v), - ValuePrinter(*this, v, errorPrintOptions) - ).atPos(pos).debugThrow(); + error(nString, v).atPos(pos).debugThrow(); return v.string_view(); } catch (Error & e) { e.addTrace(positions[pos], errorCtx); @@ -2319,7 +2239,7 @@ BackedStringView EvalState::coerceToString( return std::move(*maybeString); auto i = v.attrs->find(sOutPath); if (i == v.attrs->end()) { - error( + error( "cannot coerce %1% to a string: %2%", showType(v), ValuePrinter(*this, v, errorPrintOptions) @@ -2369,7 +2289,7 @@ BackedStringView EvalState::coerceToString( } } - error("cannot coerce %1% to a string: %2%", + error("cannot coerce %1% to a string: %2%", showType(v), ValuePrinter(*this, v, errorPrintOptions) ) @@ -2921,7 +2841,7 @@ Expr * EvalState::parse( std::string ExternalValueBase::coerceToString(EvalState & state, const PosIdx & pos, NixStringContext & context, bool copyMore, bool copyToStore) const { - state.error( + state.error( "cannot coerce %1% to a string: %2%", showType(), *this ).atPos(pos).debugThrow(); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 368bb17b328..c9755503461 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -240,7 +240,7 @@ public: template [[nodiscard, gnu::noinline]] - EvalErrorBuilder & error(const Args & ... args) { + EvalErrorBuilder & error(Args && ... args) { // `EvalErrorBuilder::debugThrow` performs the corresponding `delete`. return *new EvalErrorBuilder(*this, args...); } @@ -768,15 +768,6 @@ struct DebugTraceStacker { DebugTrace trace; }; -/** - * @return A string representing the type of the value `v`. - * - * @param withArticle Whether to begin with an english article, e.g. "an - * integer" vs "integer". - */ -std::string_view showType(ValueType type, bool withArticle = true); -std::string showType(const Value & v); - /** * If `path` refers to a directory, then append "/default.nix". */ diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index bca473453f3..7f9936e7746 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -147,7 +147,7 @@ static FlakeInput parseFlakeInput(EvalState & state, NixStringContext emptyContext = {}; attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, emptyContext).dump()); } else - state.error("flake input attribute '%s' is %s while a string, Boolean, or integer is expected", + state.error("flake input attribute '%s' is %s while a string, Boolean, or integer is expected", state.symbols[attr.name], showType(*attr.value)).debugThrow(); } #pragma GCC diagnostic pop @@ -279,14 +279,14 @@ static Flake readFlake( std::vector ss; for (auto elem : setting.value->listItems()) { if (elem->type() != nString) - state.error("list element in flake configuration setting '%s' is %s while a string is expected", + state.error("list element in flake configuration setting '%s' is %s while a string is expected", state.symbols[setting.name], showType(*setting.value)).debugThrow(); ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos, "")); } flake.config.settings.emplace(state.symbols[setting.name], ss); } else - state.error("flake configuration setting '%s' is %s", + state.error("flake configuration setting '%s' is %s", state.symbols[setting.name], showType(*setting.value)).debugThrow(); } } diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index e9ed1ef0891..7ab0c4776a1 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -49,7 +49,11 @@ std::string PackageInfo::queryName() const { if (name == "" && attrs) { auto i = attrs->find(state->sName); - if (i == attrs->end()) state->error("derivation name missing").debugThrow(); + if (i == attrs->end()) { + Value v; + v.mkAttrs(attrs); + state->error(state->sName, v).debugThrow(); + } name = state->forceStringNoCtx(*i->value, noPos, "while evaluating the 'name' attribute of a derivation"); } return name; @@ -397,7 +401,7 @@ static void getDerivations(EvalState & state, Value & vIn, } else - state.error("expression does not evaluate to a derivation (or a set or list of those)").debugThrow(); + state.error("expression does not evaluate to a derivation (or a set or list of those)").debugThrow(); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index a7687fa062d..eb97af31740 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -634,7 +634,9 @@ static Bindings::iterator getAttr( { Bindings::iterator value = attrSet->find(attrSym); if (value == attrSet->end()) { - state.error("attribute '%s' missing", state.symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow(); + Value v; + v.mkAttrs(attrSet); + state.error(attrSym, v).withTrace(noPos, errorCtx).debugThrow(); } return value; } @@ -2835,7 +2837,7 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg return; } if (!args[0]->isLambda()) - state.error("'functionArgs' requires a function").atPos(pos).debugThrow(); + state.error(nFunction, *args[0]).atPos(pos).debugThrow(); if (!args[0]->lambda.fun->hasFormals()) { v.mkAttrs(&state.emptyBindings); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 5061e40fdf2..050cfaf8c8e 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -129,7 +129,8 @@ static void fetchTree( attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, context).dump()); } else - state.error("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", + // TODO: This should be a TypeError. + state.error("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", state.symbols[attr.name], showType(*attr.value)).debugThrow(); } diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 3f877a7fd4f..1b3aed5be80 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -99,7 +99,7 @@ json printValueAsJSON(EvalState & state, bool strict, case nThunk: case nFunction: - state.error( + state.error( "cannot convert %1% to JSON", showType(v) ) @@ -118,7 +118,7 @@ void printValueAsJSON(EvalState & state, bool strict, json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, NixStringContext & context, bool copyToStore) const { - state.error("cannot convert %1% to JSON", showType()) + state.error("cannot convert %1% to JSON", showType()) .debugThrow(); } diff --git a/src/libexpr/value.cc b/src/libexpr/value.cc new file mode 100644 index 00000000000..ae9b3eb519b --- /dev/null +++ b/src/libexpr/value.cc @@ -0,0 +1,54 @@ +#include "value.hh" +#include "eval.hh" + +namespace nix { + +const Value * getPrimOp(const Value &v) { + const Value * primOp = &v; + while (primOp->isPrimOpApp()) { + primOp = primOp->primOpApp.left; + } + assert(primOp->isPrimOp()); + return primOp; +} + +std::string_view showType(ValueType type, bool withArticle) +{ + #define WA(a, w) withArticle ? a " " w : w + switch (type) { + case nInt: return WA("an", "integer"); + case nBool: return WA("a", "Boolean"); + case nString: return WA("a", "string"); + case nPath: return WA("a", "path"); + case nNull: return "null"; + case nAttrs: return WA("a", "set"); + case nList: return WA("a", "list"); + case nFunction: return WA("a", "function"); + case nExternal: return WA("an", "external value"); + case nFloat: return WA("a", "float"); + case nThunk: return WA("a", "thunk"); + } + abort(); +} + +std::string showType(const Value & v) +{ + // Allow selecting a subset of enum values + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wswitch-enum" + switch (v.internalType) { + case tString: return v.string.context ? "a string with context" : "a string"; + case tPrimOp: + return fmt("the built-in function '%s'", std::string(v.primOp->name)); + case tPrimOpApp: + return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name)); + case tExternal: return v.external->showType(); + case tThunk: return v.isBlackhole() ? "a black hole" : "a thunk"; + case tApp: return "a function application"; + default: + return std::string(showType(v.type())); + } + #pragma GCC diagnostic pop +} + +} diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index e7aea49492a..be1ef3ffe0b 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -448,6 +448,14 @@ public: } }; +/** + * @return A string representing the type of the value `v`. + * + * @param withArticle Whether to begin with an english article, e.g. "an + * integer" vs "integer". + */ +std::string_view showType(ValueType type, bool withArticle = true); +std::string showType(const Value & v); extern ExprBlackHole eBlackHole; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 2044c8c2b40..9dab0721d6a 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -104,7 +104,8 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption } } else - state->error("value at '%s' is not a string or an attribute set", state->positions[pos]).debugThrow(); + // TODO: This should be a `TypeError`. + state->error("value at '%s' is not a string or an attribute set", state->positions[pos]).debugThrow(); }; recurse(*v, pos, *writeTo); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index a846f637114..0adfe2f9b9a 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -858,7 +858,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto templateDir = templateDirAttr->getString(); if (!store->isInStore(templateDir)) - evalState->error( + evalState->error( "'%s' was not found in the Nix store\n" "If you've set '%s' to a string, try using a path instead.", templateDir, templateDirAttr->getAttrPathStr()).debugThrow(); diff --git a/src/nix/profile.cc b/src/nix/profile.cc index b5ffc7cc616..c0f80579419 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -485,7 +485,7 @@ struct Matcher virtual bool matches(const std::string & name, const ProfileElement & element) = 0; }; -struct RegexMatcher : public Matcher +struct RegexMatcher final : public Matcher { std::regex regex; std::string pattern; @@ -504,7 +504,7 @@ struct RegexMatcher : public Matcher } }; -struct StorePathMatcher : public Matcher +struct StorePathMatcher final : public Matcher { nix::StorePath storePath; @@ -522,7 +522,7 @@ struct StorePathMatcher : public Matcher } }; -struct NameMatcher : public Matcher +struct NameMatcher final : public Matcher { std::string name; @@ -540,7 +540,7 @@ struct NameMatcher : public Matcher } }; -struct AllMatcher : public Matcher +struct AllMatcher final : public Matcher { std::string getTitle() override { diff --git a/tests/functional/misc.sh b/tests/functional/misc.sh index af96d20bd4a..4d289a46353 100644 --- a/tests/functional/misc.sh +++ b/tests/functional/misc.sh @@ -26,7 +26,7 @@ echo $eval_stdin_res | grep "infinite recursion encountered" # Attribute path errors expectStderr 1 nix-instantiate --eval -E '{}' -A '"x' | grepQuiet "missing closing quote in selection path" -expectStderr 1 nix-instantiate --eval -E '[]' -A 'x' | grepQuiet "should be a set" -expectStderr 1 nix-instantiate --eval -E '{}' -A '1' | grepQuiet "should be a list" +expectStderr 1 nix-instantiate --eval -E '[]' -A 'x' | grepQuiet "expected a set but found a list" +expectStderr 1 nix-instantiate --eval -E '{}' -A '1' | grepQuiet "expected a list but found a set" expectStderr 1 nix-instantiate --eval -E '{}' -A '.' | grepQuiet "empty attribute name" expectStderr 1 nix-instantiate --eval -E '[]' -A '1' | grepQuiet "out of range" diff --git a/tests/unit/libexpr/error_traces.cc b/tests/unit/libexpr/error_traces.cc index 7b32b320bac..b7d71a2c78d 100644 --- a/tests/unit/libexpr/error_traces.cc +++ b/tests/unit/libexpr/error_traces.cc @@ -105,37 +105,37 @@ namespace nix { TEST_F(ErrorTraceTest, genericClosure) { ASSERT_TRACE2("genericClosure 1", TypeError, - HintFmt("expected a set but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.genericClosure")); ASSERT_TRACE2("genericClosure {}", - TypeError, - HintFmt("attribute '%s' missing", "startSet"), + MissingAttrError, + HintFmt("attribute '%s' missing: %s", "startSet", Uncolored("{ }")), HintFmt("in the attrset passed as argument to builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = 1; }", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = true; }", TypeError, - HintFmt("expected a function but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating the 'operator' attribute passed as argument to builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: true; }", TypeError, - HintFmt("expected a list but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating the return value of the `operator` passed to builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [ true ]; }", TypeError, - HintFmt("expected a set but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [ {} ]; }", - TypeError, - HintFmt("attribute '%s' missing", "key"), + EvalError, + HintFmt("attribute '%s' missing: %s", "key", Uncolored("{ }")), HintFmt("in one of the attrsets generated by (or initially passed to) builtins.genericClosure")); ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [{ key = ''a''; }]; }", @@ -145,7 +145,7 @@ namespace nix { ASSERT_TRACE2("genericClosure { startSet = [ true ]; operator = item: [{ key = ''a''; }]; }", TypeError, - HintFmt("expected a set but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure")); } @@ -154,12 +154,12 @@ namespace nix { TEST_F(ErrorTraceTest, replaceStrings) { ASSERT_TRACE2("replaceStrings 0 0 {}", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "0" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "0" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.replaceStrings")); ASSERT_TRACE2("replaceStrings [] 0 {}", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "0" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "0" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.replaceStrings")); ASSERT_TRACE1("replaceStrings [ 0 ] [] {}", @@ -168,17 +168,17 @@ namespace nix { ASSERT_TRACE2("replaceStrings [ 1 ] [ \"new\" ] {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating one of the strings to replace passed to builtins.replaceStrings")); ASSERT_TRACE2("replaceStrings [ \"oo\" ] [ true ] \"foo\"", TypeError, - HintFmt("expected a string but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating one of the replacement strings passed to builtins.replaceStrings")); ASSERT_TRACE2("replaceStrings [ \"old\" ] [ \"new\" ] {}", TypeError, - HintFmt("expected a string but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a string", "a set", Uncolored("{ }")), HintFmt("while evaluating the third argument passed to builtins.replaceStrings")); } @@ -243,7 +243,7 @@ namespace nix { TEST_F(ErrorTraceTest, ceil) { ASSERT_TRACE2("ceil \"foo\"", TypeError, - HintFmt("expected a float but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a float", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.ceil")); } @@ -252,7 +252,7 @@ namespace nix { TEST_F(ErrorTraceTest, floor) { ASSERT_TRACE2("floor \"foo\"", TypeError, - HintFmt("expected a float but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a float", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.floor")); } @@ -265,7 +265,7 @@ namespace nix { TEST_F(ErrorTraceTest, getEnv) { ASSERT_TRACE2("getEnv [ ]", TypeError, - HintFmt("expected a string but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a string", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.getEnv")); } @@ -286,7 +286,7 @@ namespace nix { TEST_F(ErrorTraceTest, placeholder) { ASSERT_TRACE2("placeholder []", TypeError, - HintFmt("expected a string but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a string", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.placeholder")); } @@ -294,7 +294,7 @@ namespace nix { TEST_F(ErrorTraceTest, toPath) { ASSERT_TRACE2("toPath []", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.toPath")); @@ -308,7 +308,7 @@ namespace nix { TEST_F(ErrorTraceTest, storePath) { ASSERT_TRACE2("storePath true", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to 'builtins.storePath'")); @@ -317,7 +317,7 @@ namespace nix { TEST_F(ErrorTraceTest, pathExists) { ASSERT_TRACE2("pathExists []", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a list", Uncolored("[ ]")), HintFmt("while realising the context of a path")); @@ -331,7 +331,7 @@ namespace nix { TEST_F(ErrorTraceTest, baseNameOf) { ASSERT_TRACE2("baseNameOf []", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.baseNameOf")); @@ -376,7 +376,7 @@ namespace nix { TEST_F(ErrorTraceTest, filterSource) { ASSERT_TRACE2("filterSource [] []", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a list", Uncolored("[ ]")), HintFmt("while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'")); @@ -387,7 +387,7 @@ namespace nix { ASSERT_TRACE2("filterSource [] ./.", TypeError, - HintFmt("expected a function but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a function", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.filterSource")); // Usupported by store "dummy" @@ -399,7 +399,7 @@ namespace nix { // ASSERT_TRACE2("filterSource (_: _: 1) ./.", // TypeError, - // HintFmt("expected a Boolean but found %s: %s", "an integer", "1"), + // HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", "1"), // HintFmt("while evaluating the return value of the path filter function")); } @@ -412,7 +412,7 @@ namespace nix { TEST_F(ErrorTraceTest, attrNames) { ASSERT_TRACE2("attrNames []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the argument passed to builtins.attrNames")); } @@ -421,7 +421,7 @@ namespace nix { TEST_F(ErrorTraceTest, attrValues) { ASSERT_TRACE2("attrValues []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the argument passed to builtins.attrValues")); } @@ -430,17 +430,17 @@ namespace nix { TEST_F(ErrorTraceTest, getAttr) { ASSERT_TRACE2("getAttr [] []", TypeError, - HintFmt("expected a string but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a string", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.getAttr")); ASSERT_TRACE2("getAttr \"foo\" []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the second argument passed to builtins.getAttr")); ASSERT_TRACE2("getAttr \"foo\" {}", - TypeError, - HintFmt("attribute '%s' missing", "foo"), + EvalError, + HintFmt("attribute '%s' missing: %s", "foo", Uncolored("{ }")), HintFmt("in the attribute set under consideration")); } @@ -453,12 +453,12 @@ namespace nix { TEST_F(ErrorTraceTest, hasAttr) { ASSERT_TRACE2("hasAttr [] []", TypeError, - HintFmt("expected a string but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a string", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.hasAttr")); ASSERT_TRACE2("hasAttr \"foo\" []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the second argument passed to builtins.hasAttr")); } @@ -471,17 +471,17 @@ namespace nix { TEST_F(ErrorTraceTest, removeAttrs) { ASSERT_TRACE2("removeAttrs \"\" \"\"", TypeError, - HintFmt("expected a set but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.removeAttrs")); ASSERT_TRACE2("removeAttrs \"\" [ 1 ]", TypeError, - HintFmt("expected a set but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.removeAttrs")); ASSERT_TRACE2("removeAttrs \"\" [ \"1\" ]", TypeError, - HintFmt("expected a set but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "a string", Uncolored(ANSI_MAGENTA "\"\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.removeAttrs")); } @@ -490,27 +490,27 @@ namespace nix { TEST_F(ErrorTraceTest, listToAttrs) { ASSERT_TRACE2("listToAttrs 1", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the argument passed to builtins.listToAttrs")); ASSERT_TRACE2("listToAttrs [ 1 ]", TypeError, - HintFmt("expected a set but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating an element of the list passed to builtins.listToAttrs")); ASSERT_TRACE2("listToAttrs [ {} ]", - TypeError, - HintFmt("attribute '%s' missing", "name"), + EvalError, + HintFmt("attribute '%s' missing: %s", "name", Uncolored("{ }")), HintFmt("in a {name=...; value=...;} pair")); ASSERT_TRACE2("listToAttrs [ { name = 1; } ]", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the `name` attribute of an element of the list passed to builtins.listToAttrs")); ASSERT_TRACE2("listToAttrs [ { name = \"foo\"; } ]", - TypeError, - HintFmt("attribute '%s' missing", "value"), + EvalError, + HintFmt("attribute '%s' missing: %s", "value", Uncolored("{ name = " ANSI_MAGENTA "\"foo\"" ANSI_NORMAL "; }")), HintFmt("in a {name=...; value=...;} pair")); } @@ -519,12 +519,12 @@ namespace nix { TEST_F(ErrorTraceTest, intersectAttrs) { ASSERT_TRACE2("intersectAttrs [] []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.intersectAttrs")); ASSERT_TRACE2("intersectAttrs {} []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the second argument passed to builtins.intersectAttrs")); } @@ -533,22 +533,22 @@ namespace nix { TEST_F(ErrorTraceTest, catAttrs) { ASSERT_TRACE2("catAttrs [] {}", TypeError, - HintFmt("expected a string but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a string", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.catAttrs")); ASSERT_TRACE2("catAttrs \"foo\" {}", TypeError, - HintFmt("expected a list but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a list", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument passed to builtins.catAttrs")); ASSERT_TRACE2("catAttrs \"foo\" [ 1 ]", TypeError, - HintFmt("expected a set but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating an element in the list passed as second argument to builtins.catAttrs")); ASSERT_TRACE2("catAttrs \"foo\" [ { foo = 1; } 1 { bar = 5;} ]", TypeError, - HintFmt("expected a set but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating an element in the list passed as second argument to builtins.catAttrs")); } @@ -557,7 +557,7 @@ namespace nix { TEST_F(ErrorTraceTest, functionArgs) { ASSERT_TRACE1("functionArgs {}", TypeError, - HintFmt("'functionArgs' requires a function")); + HintFmt("expected %s but found %s: %s", "a function", "a set", Uncolored("{ }"))); } @@ -565,7 +565,7 @@ namespace nix { TEST_F(ErrorTraceTest, mapAttrs) { ASSERT_TRACE2("mapAttrs [] []", TypeError, - HintFmt("expected a set but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a set", "a list", Uncolored("[ ]")), HintFmt("while evaluating the second argument passed to builtins.mapAttrs")); // XXX: defered @@ -590,12 +590,12 @@ namespace nix { TEST_F(ErrorTraceTest, zipAttrsWith) { ASSERT_TRACE2("zipAttrsWith [] [ 1 ]", TypeError, - HintFmt("expected a function but found %s: %s", "a list", Uncolored("[ ]")), + HintFmt("expected %s but found %s: %s", "a function", "a list", Uncolored("[ ]")), HintFmt("while evaluating the first argument passed to builtins.zipAttrsWith")); ASSERT_TRACE2("zipAttrsWith (_: 1) [ 1 ]", TypeError, - HintFmt("expected a set but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a set", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating a value of the list passed as second argument to builtins.zipAttrsWith")); // XXX: How to properly tell that the fucntion takes two arguments ? @@ -622,7 +622,7 @@ namespace nix { TEST_F(ErrorTraceTest, elemAt) { ASSERT_TRACE2("elemAt \"foo\" (-1)", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.elemAt")); ASSERT_TRACE1("elemAt [] (-1)", @@ -639,7 +639,7 @@ namespace nix { TEST_F(ErrorTraceTest, head) { ASSERT_TRACE2("head 1", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.elemAt")); ASSERT_TRACE1("head []", @@ -652,7 +652,7 @@ namespace nix { TEST_F(ErrorTraceTest, tail) { ASSERT_TRACE2("tail 1", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.tail")); ASSERT_TRACE1("tail []", @@ -665,12 +665,12 @@ namespace nix { TEST_F(ErrorTraceTest, map) { ASSERT_TRACE2("map 1 \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.map")); ASSERT_TRACE2("map 1 [ 1 ]", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.map")); } @@ -679,17 +679,17 @@ namespace nix { TEST_F(ErrorTraceTest, filter) { ASSERT_TRACE2("filter 1 \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.filter")); ASSERT_TRACE2("filter 1 [ \"foo\" ]", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.filter")); ASSERT_TRACE2("filter (_: 5) [ \"foo\" ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "an integer", Uncolored(ANSI_CYAN "5" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", Uncolored(ANSI_CYAN "5" ANSI_NORMAL)), HintFmt("while evaluating the return value of the filtering function passed to builtins.filter")); } @@ -698,7 +698,7 @@ namespace nix { TEST_F(ErrorTraceTest, elem) { ASSERT_TRACE2("elem 1 \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.elem")); } @@ -707,17 +707,17 @@ namespace nix { TEST_F(ErrorTraceTest, concatLists) { ASSERT_TRACE2("concatLists 1", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.concatLists")); ASSERT_TRACE2("concatLists [ 1 ]", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating a value of the list passed to builtins.concatLists")); ASSERT_TRACE2("concatLists [ [1] \"foo\" ]", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating a value of the list passed to builtins.concatLists")); } @@ -726,12 +726,12 @@ namespace nix { TEST_F(ErrorTraceTest, length) { ASSERT_TRACE2("length 1", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.length")); ASSERT_TRACE2("length \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.length")); } @@ -740,21 +740,21 @@ namespace nix { TEST_F(ErrorTraceTest, foldlPrime) { ASSERT_TRACE2("foldl' 1 \"foo\" true", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.foldlStrict")); ASSERT_TRACE2("foldl' (_: 1) \"foo\" true", TypeError, - HintFmt("expected a list but found %s: %s", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a Boolean", Uncolored(ANSI_CYAN "true" ANSI_NORMAL)), HintFmt("while evaluating the third argument passed to builtins.foldlStrict")); ASSERT_TRACE1("foldl' (_: 1) \"foo\" [ true ]", TypeError, - HintFmt("attempt to call something which is not a function but %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL))); + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL))); ASSERT_TRACE2("foldl' (a: b: a && b) \"foo\" [ true ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("in the left operand of the AND (&&) operator")); } @@ -763,17 +763,17 @@ namespace nix { TEST_F(ErrorTraceTest, any) { ASSERT_TRACE2("any 1 \"foo\"", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.any")); ASSERT_TRACE2("any (_: 1) \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.any")); ASSERT_TRACE2("any (_: 1) [ \"foo\" ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the function passed to builtins.any")); } @@ -782,17 +782,17 @@ namespace nix { TEST_F(ErrorTraceTest, all) { ASSERT_TRACE2("all 1 \"foo\"", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.all")); ASSERT_TRACE2("all (_: 1) \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.all")); ASSERT_TRACE2("all (_: 1) [ \"foo\" ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the function passed to builtins.all")); } @@ -801,12 +801,12 @@ namespace nix { TEST_F(ErrorTraceTest, genList) { ASSERT_TRACE2("genList 1 \"foo\"", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.genList")); ASSERT_TRACE2("genList 1 2", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.genList")); // XXX: defered @@ -825,21 +825,21 @@ namespace nix { TEST_F(ErrorTraceTest, sort) { ASSERT_TRACE2("sort 1 \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.sort")); ASSERT_TRACE2("sort 1 [ \"foo\" ]", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.sort")); ASSERT_TRACE1("sort (_: 1) [ \"foo\" \"bar\" ]", TypeError, - HintFmt("attempt to call something which is not a function but %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL))); + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL))); ASSERT_TRACE2("sort (_: _: 1) [ \"foo\" \"bar\" ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the sorting function passed to builtins.sort")); // XXX: Trace too deep, need better asserts @@ -857,17 +857,17 @@ namespace nix { TEST_F(ErrorTraceTest, partition) { ASSERT_TRACE2("partition 1 \"foo\"", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.partition")); ASSERT_TRACE2("partition (_: 1) \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.partition")); ASSERT_TRACE2("partition (_: 1) [ \"foo\" ]", TypeError, - HintFmt("expected a Boolean but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a Boolean", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the partition function passed to builtins.partition")); } @@ -876,17 +876,17 @@ namespace nix { TEST_F(ErrorTraceTest, groupBy) { ASSERT_TRACE2("groupBy 1 \"foo\"", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.groupBy")); ASSERT_TRACE2("groupBy (_: 1) \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.groupBy")); ASSERT_TRACE2("groupBy (x: x) [ \"foo\" \"bar\" 1 ]", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the grouping function passed to builtins.groupBy")); } @@ -895,22 +895,22 @@ namespace nix { TEST_F(ErrorTraceTest, concatMap) { ASSERT_TRACE2("concatMap 1 \"foo\"", TypeError, - HintFmt("expected a function but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a function", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.concatMap")); ASSERT_TRACE2("concatMap (x: 1) \"foo\"", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.concatMap")); ASSERT_TRACE2("concatMap (x: 1) [ \"foo\" ] # TODO", TypeError, - HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the return value of the function passed to builtins.concatMap")); ASSERT_TRACE2("concatMap (x: \"foo\") [ 1 2 ] # TODO", TypeError, - HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a list", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the return value of the function passed to builtins.concatMap")); } @@ -919,12 +919,12 @@ namespace nix { TEST_F(ErrorTraceTest, add) { ASSERT_TRACE2("add \"foo\" 1", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument of the addition")); ASSERT_TRACE2("add 1 \"foo\"", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument of the addition")); } @@ -933,12 +933,12 @@ namespace nix { TEST_F(ErrorTraceTest, sub) { ASSERT_TRACE2("sub \"foo\" 1", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument of the subtraction")); ASSERT_TRACE2("sub 1 \"foo\"", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument of the subtraction")); } @@ -947,12 +947,12 @@ namespace nix { TEST_F(ErrorTraceTest, mul) { ASSERT_TRACE2("mul \"foo\" 1", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first argument of the multiplication")); ASSERT_TRACE2("mul 1 \"foo\"", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument of the multiplication")); } @@ -961,12 +961,12 @@ namespace nix { TEST_F(ErrorTraceTest, div) { ASSERT_TRACE2("div \"foo\" 1 # TODO: an integer was expected -> a number", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the first operand of the division")); ASSERT_TRACE2("div 1 \"foo\"", TypeError, - HintFmt("expected a float but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a float", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second operand of the division")); ASSERT_TRACE1("div \"foo\" 0", @@ -979,12 +979,12 @@ namespace nix { TEST_F(ErrorTraceTest, bitAnd) { ASSERT_TRACE2("bitAnd 1.1 2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.bitAnd")); ASSERT_TRACE2("bitAnd 1 2.2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.bitAnd")); } @@ -993,12 +993,12 @@ namespace nix { TEST_F(ErrorTraceTest, bitOr) { ASSERT_TRACE2("bitOr 1.1 2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.bitOr")); ASSERT_TRACE2("bitOr 1 2.2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.bitOr")); } @@ -1007,12 +1007,12 @@ namespace nix { TEST_F(ErrorTraceTest, bitXor) { ASSERT_TRACE2("bitXor 1.1 2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "1.1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.bitXor")); ASSERT_TRACE2("bitXor 1 2.2", TypeError, - HintFmt("expected an integer but found %s: %s", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a float", Uncolored(ANSI_CYAN "2.2" ANSI_NORMAL)), HintFmt("while evaluating the second argument passed to builtins.bitXor")); } @@ -1037,7 +1037,7 @@ namespace nix { TEST_F(ErrorTraceTest, toString) { ASSERT_TRACE2("toString { a = 1; }", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a set", Uncolored("{ a = " ANSI_CYAN "1" ANSI_NORMAL "; }")), HintFmt("while evaluating the first argument passed to builtins.toString")); @@ -1047,16 +1047,16 @@ namespace nix { TEST_F(ErrorTraceTest, substring) { ASSERT_TRACE2("substring {} \"foo\" true", TypeError, - HintFmt("expected an integer but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "an integer", "a set", Uncolored("{ }")), HintFmt("while evaluating the first argument (the start offset) passed to builtins.substring")); ASSERT_TRACE2("substring 3 \"foo\" true", TypeError, - HintFmt("expected an integer but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "an integer", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)), HintFmt("while evaluating the second argument (the substring length) passed to builtins.substring")); ASSERT_TRACE2("substring 0 3 {}", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a set", Uncolored("{ }")), HintFmt("while evaluating the third argument (the string) passed to builtins.substring")); @@ -1069,7 +1069,7 @@ namespace nix { TEST_F(ErrorTraceTest, stringLength) { ASSERT_TRACE2("stringLength {} # TODO: context is missing ???", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "a set", Uncolored("{ }")), HintFmt("while evaluating the argument passed to builtins.stringLength")); @@ -1079,7 +1079,7 @@ namespace nix { TEST_F(ErrorTraceTest, hashString) { ASSERT_TRACE2("hashString 1 {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.hashString")); ASSERT_TRACE1("hashString \"foo\" \"content\"", @@ -1088,7 +1088,7 @@ namespace nix { ASSERT_TRACE2("hashString \"sha256\" {}", TypeError, - HintFmt("expected a string but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a string", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument passed to builtins.hashString")); } @@ -1097,12 +1097,12 @@ namespace nix { TEST_F(ErrorTraceTest, match) { ASSERT_TRACE2("match 1 {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.match")); ASSERT_TRACE2("match \"foo\" {}", TypeError, - HintFmt("expected a string but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a string", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument passed to builtins.match")); ASSERT_TRACE1("match \"(.*\" \"\"", @@ -1115,12 +1115,12 @@ namespace nix { TEST_F(ErrorTraceTest, split) { ASSERT_TRACE2("split 1 {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.split")); ASSERT_TRACE2("split \"foo\" {}", TypeError, - HintFmt("expected a string but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a string", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument passed to builtins.split")); ASSERT_TRACE1("split \"f(o*o\" \"1foo2\"", @@ -1133,16 +1133,16 @@ namespace nix { TEST_F(ErrorTraceTest, concatStringsSep) { ASSERT_TRACE2("concatStringsSep 1 {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument (the separator string) passed to builtins.concatStringsSep")); ASSERT_TRACE2("concatStringsSep \"foo\" {}", TypeError, - HintFmt("expected a list but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a list", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument (the list of strings to concat) passed to builtins.concatStringsSep")); ASSERT_TRACE2("concatStringsSep \"foo\" [ 1 2 {} ] # TODO: coerce to string is buggy", - TypeError, + EvalError, HintFmt("cannot coerce %s to a string: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep")); @@ -1152,7 +1152,7 @@ namespace nix { TEST_F(ErrorTraceTest, parseDrvName) { ASSERT_TRACE2("parseDrvName 1", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.parseDrvName")); } @@ -1161,12 +1161,12 @@ namespace nix { TEST_F(ErrorTraceTest, compareVersions) { ASSERT_TRACE2("compareVersions 1 {}", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.compareVersions")); ASSERT_TRACE2("compareVersions \"abd\" {}", TypeError, - HintFmt("expected a string but found %s: %s", "a set", Uncolored("{ }")), + HintFmt("expected %s but found %s: %s", "a string", "a set", Uncolored("{ }")), HintFmt("while evaluating the second argument passed to builtins.compareVersions")); } @@ -1175,7 +1175,7 @@ namespace nix { TEST_F(ErrorTraceTest, splitVersion) { ASSERT_TRACE2("splitVersion 1", TypeError, - HintFmt("expected a string but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), + HintFmt("expected %s but found %s: %s", "a string", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)), HintFmt("while evaluating the first argument passed to builtins.splitVersion")); } diff --git a/tests/unit/libexpr/primops.cc b/tests/unit/libexpr/primops.cc index b1426edaeee..87276784d0f 100644 --- a/tests/unit/libexpr/primops.cc +++ b/tests/unit/libexpr/primops.cc @@ -147,7 +147,7 @@ namespace nix { TEST_F(PrimOpTest, getAttrNotFound) { // FIXME: TypeError is really bad here, also the error wording is worse // than on Nix <=2.3 - ASSERT_THROW(eval("builtins.getAttr \"y\" { }"), TypeError); + ASSERT_THROW(eval("builtins.getAttr \"y\" { }"), EvalError); } TEST_F(PrimOpTest, unsafeGetAttrPos) {