From 59b94ee18ac0cba5c7b261ee72550a4d3db0acb5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 5 Apr 2004 22:27:41 +0000 Subject: [PATCH] * When something goes wrong in the evaluation of a Nix expression, print a nice backtrace of the stack, rather than vomiting a gigantic (and useless) aterm on the screen. Example: error: while evaluating file `.../pkgs/system/test.nix': while evaluating attribute `subversion' at `.../pkgs/system/all-packages-generic.nix', line 533: while evaluating function at `.../pkgs/applications/version-management/subversion/default.nix', line 1: assertion failed at `.../pkgs/applications/version-management/subversion/default.nix', line 13 Since the Nix expression language is lazy, the trace may be misleading. The purpose is to provide a hint as to the location of the problem. --- src/libexpr/eval.cc | 86 ++++++++++++++++++++++++------------- src/libexpr/nixexpr.cc | 74 ++++++++++++++++++++++++------- src/libexpr/nixexpr.hh | 6 ++- src/libexpr/parser.cc | 27 +++++++----- src/libexpr/parser.y | 19 +++++--- src/libexpr/primops.cc | 38 ++++++++-------- src/nix-env/main.cc | 39 ++++++++++++----- src/nix-instantiate/main.cc | 2 +- 8 files changed, 201 insertions(+), 90 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5ae4d6de8e..af0ab913ca 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -77,16 +77,16 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg) Expr key = *i; Expr cur = subs.get(key); if (!cur) - throw badTerm(format("function has no formal argument `%1%'") - % aterm2String(key), arg); + throw Error(format("unexpected function argument `%1%'") + % aterm2String(key)); subs.set(key, args.get(key)); } /* Check that all arguments are defined. */ for (ATermIterator i(subs.keys()); i; ++i) if (subs.get(*i) == undefined) - throw badTerm(format("formal argument `%1%' missing") - % aterm2String(*i), arg); + throw Error(format("required function argument `%1%' missing") + % aterm2String(*i)); return substitute(subs, body); } @@ -119,16 +119,18 @@ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) /* Create the non-recursive set. */ ATermMap as; for (ATermIterator i(rbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) + ATerm pos; + if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) abort(); /* can't happen */ - as.set(name, substitute(subs, e2)); + as.set(name, ATmake("(, )", substitute(subs, e2), pos)); } /* Copy the non-recursive bindings. !!! inefficient */ for (ATermIterator i(nrbnds); i; ++i) { - if (!(atMatch(m, *i) >> "Bind" >> name >> e2)) + ATerm pos; + if (!(atMatch(m, *i) >> "Bind" >> name >> e2 >> pos)) abort(); /* can't happen */ - as.set(name, e2); + as.set(name, ATmake("(, )", e2, pos)); } return makeAttrs(as); @@ -140,8 +142,8 @@ static Expr updateAttrs(Expr e1, Expr e2) /* Note: e1 and e2 should be in normal form. */ ATermMap attrs; - queryAllAttrs(e1, attrs); - queryAllAttrs(e2, attrs); + queryAllAttrs(e1, attrs, true); + queryAllAttrs(e2, attrs, true); return makeAttrs(attrs); } @@ -153,7 +155,7 @@ string evalString(EvalState & state, Expr e) ATMatcher m; string s; if (!(atMatch(m, e) >> "Str" >> s)) - throw badTerm("string expected", e); + throw Error("string expected"); return s; } @@ -164,7 +166,7 @@ Path evalPath(EvalState & state, Expr e) ATMatcher m; string s; if (!(atMatch(m, e) >> "Path" >> s)) - throw badTerm("path expected", e); + throw Error("path expected"); return s; } @@ -175,7 +177,7 @@ bool evalBool(EvalState & state, Expr e) ATMatcher m; if (atMatch(m, e) >> "Bool" >> "True") return true; else if (atMatch(m, e) >> "Bool" >> "False") return false; - else throw badTerm("expecting a boolean", e); + else throw Error("boolean expected"); } @@ -183,7 +185,7 @@ Expr evalExpr2(EvalState & state, Expr e) { ATMatcher m; Expr e1, e2, e3, e4; - ATerm name; + ATerm name, pos; /* Normal forms. */ string cons; @@ -219,6 +221,7 @@ Expr evalExpr2(EvalState & state, Expr e) if (atMatch(m, e) >> "Call" >> e1 >> e2) { ATermList formals; + ATerm pos; /* Evaluate the left-hand side. */ e1 = evalExpr(state, e1); @@ -229,25 +232,42 @@ Expr evalExpr2(EvalState & state, Expr e) if (primOp) return primOp(state, e2); else abort(); } - else if (atMatch(m, e1) >> "Function" >> formals >> e4) - return evalExpr(state, - substArgs(e4, formals, evalExpr(state, e2))); - - else if (atMatch(m, e1) >> "Function1" >> name >> e4) { - ATermMap subs; - subs.set(name, e2); - return evalExpr(state, substitute(subs, e4)); + else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) { + e2 = evalExpr(state, e2); + try { + return evalExpr(state, substArgs(e4, formals, e2)); + } catch (Error & e) { + throw Error(format("while evaluating function at %1%:\n%2%") + % showPos(pos) % e.msg()); + } } - else throw badTerm("expecting a function or primop", e1); + else if (atMatch(m, e1) >> "Function1" >> name >> e4 >> pos) { + try { + ATermMap subs; + subs.set(name, e2); + return evalExpr(state, substitute(subs, e4)); + } catch (Error & e) { + throw Error(format("while evaluating function at %1%:\n%2%") + % showPos(pos) % e.msg()); + } + } + + else throw Error("function or primop expected in function call"); } /* Attribute selection. */ string s1; if (atMatch(m, e) >> "Select" >> e1 >> s1) { - Expr a = queryAttr(evalExpr(state, e1), s1); - if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); - return evalExpr(state, a); + ATerm pos; + Expr a = queryAttr(evalExpr(state, e1), s1, pos); + if (!a) throw Error(format("attribute `%1%' missing") % s1); + try { + return evalExpr(state, a); + } catch (Error & e) { + throw Error(format("while evaluating attribute `%1%' at %2%:\n%3%") + % s1 % showPos(pos) % e.msg()); + } } /* Mutually recursive sets. */ @@ -264,8 +284,9 @@ Expr evalExpr2(EvalState & state, Expr e) } /* Assertions. */ - if (atMatch(m, e) >> "Assert" >> e1 >> e2) { - if (!evalBool(state, e1)) throw badTerm("guard failed", e); + if (atMatch(m, e) >> "Assert" >> e1 >> e2 >> pos) { + if (!evalBool(state, e1)) + throw Error(format("assertion failed at %1%") % showPos(pos)); return evalExpr(state, e2); } @@ -323,7 +344,7 @@ Expr evalExpr(EvalState & state, Expr e) Expr nf = state.normalForms.get(e); if (nf) { if (nf == state.blackHole) - throw badTerm("infinite recursion", e); + throw Error("infinite recursion encountered"); state.nrCached++; return nf; } @@ -340,7 +361,12 @@ Expr evalFile(EvalState & state, const Path & path) { startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); Expr e = parseExprFromFile(state, path); - return evalExpr(state, e); + try { + return evalExpr(state, e); + } catch (Error & e) { + throw Error(format("while evaluating file `%1%':\n%2%") + % path % e.msg()); + } } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 2736daf323..dec734e466 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -104,6 +104,19 @@ string aterm2String(ATerm t) { return ATgetName(ATgetAFun(t)); } + + +string showPos(ATerm pos) +{ + ATMatcher m; + Path path; + int line, column; + if (atMatch(m, pos) >> "NoPos") + return "undefined position"; + if (!(atMatch(m, pos) >> "Pos" >> path >> line >> column)) + throw badTerm("position expected", pos); + return (format("`%1%', line %2%") % path % line).str(); +} ATerm bottomupRewrite(TermFun & f, ATerm e) @@ -135,37 +148,66 @@ ATerm bottomupRewrite(TermFun & f, ATerm e) } -void queryAllAttrs(Expr e, ATermMap & attrs) +void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos) { ATMatcher m; ATermList bnds; if (!(atMatch(m, e) >> "Attrs" >> bnds)) - throw badTerm("expected attribute set", e); + throw Error("attribute set expected"); for (ATermIterator i(bnds); i; ++i) { string s; Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + ATerm pos; + if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos)) abort(); /* can't happen */ - attrs.set(s, e); + attrs.set(s, withPos ? ATmake("(, )", e, pos) : e); } } Expr queryAttr(Expr e, const string & name) { - ATermMap attrs; - queryAllAttrs(e, attrs); - return attrs.get(name); + ATerm dummy; + return queryAttr(e, name, dummy); +} + + +Expr queryAttr(Expr e, const string & name, ATerm & pos) +{ + ATMatcher m; + ATermList bnds; + if (!(atMatch(m, e) >> "Attrs" >> bnds)) + throw Error("attribute set expected"); + + for (ATermIterator i(bnds); i; ++i) { + string s; + Expr e; + ATerm pos2; + if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos2)) + abort(); /* can't happen */ + if (s == name) { + pos = pos2; + return e; + } + } + + return 0; } Expr makeAttrs(const ATermMap & attrs) { + ATMatcher m; ATermList bnds = ATempty; - for (ATermIterator i(attrs.keys()); i; ++i) + for (ATermIterator i(attrs.keys()); i; ++i) { + Expr e; + ATerm pos; + if (!(atMatch(m, attrs.get(*i)) >> "" >> e >> pos)) + abort(); /* can't happen */ bnds = ATinsert(bnds, - ATmake("Bind(, )", *i, attrs.get(*i))); + ATmake("Bind(, , )", *i, e, pos)); + } return ATmake("Attrs()", ATreverse(bnds)); } @@ -175,7 +217,7 @@ Expr substitute(const ATermMap & subs, Expr e) checkInterrupt(); ATMatcher m; - ATerm name; + ATerm name, pos; /* As an optimisation, don't substitute in subterms known to be closed. */ @@ -190,7 +232,7 @@ Expr substitute(const ATermMap & subs, Expr e) function. */ ATermList formals; ATerm body; - if (atMatch(m, e) >> "Function" >> formals >> body) { + if (atMatch(m, e) >> "Function" >> formals >> body >> pos) { ATermMap subs2(subs); for (ATermIterator i(formals); i; ++i) { if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && @@ -198,16 +240,16 @@ Expr substitute(const ATermMap & subs, Expr e) abort(); subs2.remove(name); } - return ATmake("Function(, )", + return ATmake("Function(, , )", substitute(subs, (ATerm) formals), - substitute(subs2, body)); + substitute(subs2, body), pos); } - if (atMatch(m, e) >> "Function1" >> name >> body) { + if (atMatch(m, e) >> "Function1" >> name >> body >> pos) { ATermMap subs2(subs); subs2.remove(name); - return ATmake("Function1(, )", name, - substitute(subs2, body)); + return ATmake("Function1(, , )", name, + substitute(subs2, body), pos); } /* Idem for a mutually recursive attribute set. */ diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 924f8b912f..ecd2534088 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -52,6 +52,9 @@ private: ATerm string2ATerm(const string & s); string aterm2String(ATerm t); +/* Show a position. */ +string showPos(ATerm pos); + /* Generic bottomup traversal over ATerms. The traversal first recursively descends into subterms, and then applies the given term function to the resulting term. */ @@ -63,11 +66,12 @@ ATerm bottomupRewrite(TermFun & f, ATerm e); /* Query all attributes in an attribute set expression. The expression must be in normal form. */ -void queryAllAttrs(Expr e, ATermMap & attrs); +void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false); /* Query a specific attribute from an attribute set expression. The expression must be in normal form. */ Expr queryAttr(Expr e, const string & name); +Expr queryAttr(Expr e, const string & name, ATerm & pos); /* Create an attribute set expression from an Attrs value. */ Expr makeAttrs(const ATermMap & attrs); diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index c300a0d07b..2e561c95ea 100644 --- a/src/libexpr/parser.cc +++ b/src/libexpr/parser.cc @@ -12,8 +12,8 @@ struct ParseData { Expr result; - string basePath; - string location; + Path basePath; + Path path; string error; }; @@ -39,8 +39,8 @@ ATerm absParsedPath(ParseData * data, ATerm t) void parseError(ParseData * data, char * error, int line, int column) { - data->error = (format("%1%, at line %2%, column %3%, of %4%") - % error % line % column % data->location).str(); + data->error = (format("%1%, at `%2%':%3%:%4%") + % error % data->path % line % column).str(); } ATerm fixAttrs(int recursive, ATermList as) @@ -51,13 +51,15 @@ ATerm fixAttrs(int recursive, ATermList as) for (ATermIterator i(as); i; ++i) { ATermList names; Expr src; - if (atMatch(m, *i) >> "Inherit" >> src >> names) { + ATerm pos; + if (atMatch(m, *i) >> "Inherit" >> src >> names >> pos) { bool fromScope = atMatch(m, src) >> "Scope"; for (ATermIterator j(names); j; ++j) { Expr rhs = fromScope ? ATmake("Var()", *j) : ATmake("Select(, )", src, *j); - *is = ATinsert(*is, ATmake("Bind(, )", *j, rhs)); + *is = ATinsert(*is, ATmake("Bind(, , )", + *j, rhs, pos)); } } else bs = ATinsert(bs, *i); } @@ -67,18 +69,23 @@ ATerm fixAttrs(int recursive, ATermList as) return ATmake("Attrs()", bs); } +const char * getPath(ParseData * data) +{ + return data->path.c_str(); +} + int yyparse(yyscan_t scanner, ParseData * data); } static Expr parse(EvalState & state, - const char * text, const string & location, + const char * text, const Path & path, const Path & basePath) { yyscan_t scanner; ParseData data; data.basePath = basePath; - data.location = location; + data.path = path; yylex_init(&scanner); yy_scan_string(text, scanner); @@ -90,7 +97,7 @@ static Expr parse(EvalState & state, try { checkVarDefs(state.primOpsAll, data.result); } catch (Error & e) { - throw Error(format("%1%, in %2%") % e.msg() % location); + throw Error(format("%1%, in `%2%'") % e.msg() % path); } return data.result; @@ -133,7 +140,7 @@ Expr parseExprFromFile(EvalState & state, Path path) readFull(fd, (unsigned char *) text, st.st_size); text[st.st_size] = 0; - return parse(state, text, "`" + path + "'", dirOf(path)); + return parse(state, text, path, dirOf(path)); } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index cfcbc589f6..347516f692 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -19,11 +19,20 @@ void setParseResult(void * data, ATerm t); void parseError(void * data, char * error, int line, int column); ATerm absParsedPath(void * data, ATerm t); ATerm fixAttrs(int recursive, ATermList as); +const char * getPath(void * data); void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s) { parseError(data, s, loc->first_line, loc->first_column); } + +ATerm makePos(YYLTYPE * loc, void * data) +{ + return ATmake("Pos(, , )", + getPath(data), loc->first_line, loc->first_column); +} + +#define CUR_POS makePos(yylocp, data) %} @@ -55,15 +64,15 @@ expr: expr_function; expr_function : '{' formals '}' ':' expr_function - { $$ = ATmake("Function(, )", $2, $5); } + { $$ = ATmake("Function(, , )", $2, $5, CUR_POS); } | ID ':' expr_function - { $$ = ATmake("Function1(, )", $1, $3); } + { $$ = ATmake("Function1(, , )", $1, $3, CUR_POS); } | expr_assert ; expr_assert : ASSERT expr ';' expr_assert - { $$ = ATmake("Assert(, )", $2, $4); } + { $$ = ATmake("Assert(, , )", $2, $4, CUR_POS); } | expr_if ; @@ -123,9 +132,9 @@ binds bind : ID '=' expr ';' - { $$ = ATmake("Bind(, )", $1, $3); } + { $$ = ATmake("Bind(, , )", $1, $3, CUR_POS); } | INHERIT inheritsrc ids ';' - { $$ = ATmake("Inherit(, )", $2, $3); } + { $$ = ATmake("Inherit(, , )", $2, $3, CUR_POS); } ; inheritsrc diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 835a3217f3..b0a0a27615 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -8,7 +8,7 @@ Expr primImport(EvalState & state, Expr arg) ATMatcher m; string path; if (!(atMatch(m, arg) >> "Path" >> path)) - throw badTerm("path expected", arg); + throw Error("path expected"); return evalFile(state, path); } @@ -102,18 +102,18 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, Expr a = queryAttr(e, "type"); if (a && evalString(state, a) == "derivation") { a = queryAttr(e, "drvPath"); - if (!a) throw badTerm("derivation name missing", e); + if (!a) throw Error("derivation name missing"); Path drvPath = evalPath(state, a); a = queryAttr(e, "drvHash"); - if (!a) throw badTerm("derivation hash missing", e); + if (!a) throw Error("derivation hash missing"); Hash drvHash = parseHash(evalString(state, a)); state.drvHashes[drvPath] = drvHash; ss.push_back(addInput(state, drvPath, ne)); } else - throw badTerm("invalid derivation binding", e); + throw Error("invalid derivation attribute"); } else if (atMatch(m, e) >> "Path" >> s) { @@ -142,7 +142,7 @@ static void processBinding(EvalState & state, Expr e, StoreExpr & ne, ss.push_back(canonPath(ss2.front() + "/" + s)); } - else throw badTerm("invalid derivation binding", e); + else throw Error("invalid derivation attribute"); } @@ -164,7 +164,7 @@ Expr primDerivation(EvalState & state, Expr args) ATermMap attrs; args = evalExpr(state, args); - queryAllAttrs(args, attrs); + queryAllAttrs(args, attrs, true); /* Build the derivation expression by processing the attributes. */ StoreExpr ne; @@ -177,15 +177,19 @@ Expr primDerivation(EvalState & state, Expr args) for (ATermIterator i(attrs.keys()); i; ++i) { string key = aterm2String(*i); - Expr value = attrs.get(key); + ATerm value; + Expr pos; + ATerm rhs = attrs.get(key); + ATMatcher m; + if (!(atMatch(m, rhs) >> "" >> value >> pos)) abort(); startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); Strings ss; try { processBinding(state, value, ne, ss); } catch (Error & e) { - throw Error(format("while processing derivation binding `%1%': %2%") - % key % e.msg()); + throw Error(format("while processing derivation attribute `%1%' at %2%:\n%3%") + % key % showPos(pos) % e.msg()); } /* The `args' attribute is special: it supplies the @@ -213,11 +217,11 @@ Expr primDerivation(EvalState & state, Expr args) /* Do we have all required attributes? */ if (ne.derivation.builder == "") - throw badTerm("required attribute `builder' missing", args); + throw Error("required attribute `builder' missing"); if (ne.derivation.platform == "") - throw badTerm("required attribute `system' missing", args); + throw Error("required attribute `system' missing"); if (drvName == "") - throw badTerm("required attribute `name' missing", args); + throw Error("required attribute `name' missing"); /* Determine the output path. */ if (!outHashGiven) outHash = hashDerivation(state, ne); @@ -238,10 +242,10 @@ Expr primDerivation(EvalState & state, Expr args) printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") % drvName % drvPath); - attrs.set("outPath", ATmake("Path()", outPath.c_str())); - attrs.set("drvPath", ATmake("Path()", drvPath.c_str())); - attrs.set("drvHash", ATmake("Str()", ((string) drvHash).c_str())); - attrs.set("type", ATmake("Str(\"derivation\")")); + attrs.set("outPath", ATmake("(Path(), NoPos)", outPath.c_str())); + attrs.set("drvPath", ATmake("(Path(), NoPos)", drvPath.c_str())); + attrs.set("drvHash", ATmake("(Str(), NoPos)", ((string) drvHash).c_str())); + attrs.set("type", ATmake("(Str(\"derivation\"), NoPos)")); return makeAttrs(attrs); } @@ -263,7 +267,7 @@ Expr primToString(EvalState & state, Expr arg) atMatch(m, arg) >> "Path" >> s || atMatch(m, arg) >> "Uri" >> s) return ATmake("Str()", s.c_str()); - else throw badTerm("cannot coerce to string", arg); + else throw Error("cannot coerce value to string"); } diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index 07a49a122c..51bf7ffc3b 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -108,7 +108,7 @@ void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs) { Expr e = parseExprFromFile(state, absPath(nePath)); if (!parseDerivations(state, e, drvs)) - throw badTerm("expected set of derivations", e); + throw Error("set of derivations expected"); } @@ -126,6 +126,21 @@ static Path getDefNixExprPath() } +struct AddPos : TermFun +{ + ATerm operator () (ATerm e) + { + ATMatcher m; + ATerm x, y, z; + if (atMatch(m, e) >> "Bind" >> x >> y >> z) + return e; + if (atMatch(m, e) >> "Bind" >> x >> y) + return ATmake("Bind(, , NoPos)", x, y); + return e; + } +}; + + void queryInstalled(EvalState & state, DrvInfos & drvs, const Path & userEnv) { @@ -136,8 +151,12 @@ void queryInstalled(EvalState & state, DrvInfos & drvs, Expr e = ATreadFromNamedFile(path.c_str()); if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path); + /* Compatibility: Bind(x, y) -> Bind(x, y, NoPos). */ + AddPos addPos; + e = bottomupRewrite(addPos, e); + if (!parseDerivations(state, e, drvs)) - throw badTerm(format("expected set of derivations in `%1%'") % path, e); + throw badTerm(format("set of derivations expected in `%1%'") % path, e); } @@ -155,11 +174,11 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, { ATerm t = ATmake( "Attrs([" - "Bind(\"type\", Str(\"derivation\")), " - "Bind(\"name\", Str()), " - "Bind(\"drvPath\", Path()), " - "Bind(\"drvHash\", Str()), " - "Bind(\"outPath\", Path())" + "Bind(\"type\", Str(\"derivation\"), NoPos), " + "Bind(\"name\", Str(), NoPos), " + "Bind(\"drvPath\", Path(), NoPos), " + "Bind(\"drvHash\", Str(), NoPos), " + "Bind(\"outPath\", Path(), NoPos)" "])", i->second.name.c_str(), i->second.drvPath.c_str(), @@ -176,9 +195,9 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, Expr topLevel = ATmake( "Call(, Attrs([" - "Bind(\"system\", Str()), " - "Bind(\"derivations\", ), " // !!! redundant - "Bind(\"manifest\", Path())" + "Bind(\"system\", Str(), NoPos), " + "Bind(\"derivations\", , NoPos), " // !!! redundant + "Bind(\"manifest\", Path(), NoPos)" "]))", envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str()); diff --git a/src/nix-instantiate/main.cc b/src/nix-instantiate/main.cc index cc3444837c..5ef6bd7d1b 100644 --- a/src/nix-instantiate/main.cc +++ b/src/nix-instantiate/main.cc @@ -47,7 +47,7 @@ static void printNixExpr(EvalState & state, Expr e) return; } - throw badTerm("top level does not evaluate to one or more Nix expressions", e); + throw Error("expression does not evaluate to one or more derivations"); }