Skip to content

Commit

Permalink
Show function names in error messages
Browse files Browse the repository at this point in the history
Functions in Nix are anonymous, but if they're assigned to a
variable/attribute, we can use the variable/attribute name in error
messages, e.g.

while evaluating `concatMapStrings' at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/strings.nix:18:25':
...
  • Loading branch information
edolstra committed May 16, 2013
1 parent 1b3a03f commit 18a48d8
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 8 deletions.
13 changes: 9 additions & 4 deletions src/libexpr/eval.cc
Expand Up @@ -247,6 +247,11 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const
throw TypeError(format(s) % pos % s2);
}

LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
{
throw TypeError(format(s) % s1 % s2);
}

LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
{
throw TypeError(format(s) % pos);
Expand Down Expand Up @@ -755,8 +760,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
Bindings::iterator j = arg.attrs->find(i->name);
if (j == arg.attrs->end()) {
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
fun.lambda.fun->pos, i->name);
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
fun.lambda.fun->showNamePos(), i->name);
env2.values[displ++] = i->def->maybeThunk(*this, env2);
} else {
attrsUsed++;
Expand All @@ -771,7 +776,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
user. */
foreach (Bindings::iterator, i, *arg.attrs)
if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end())
throwTypeError("function at %1% called with unexpected argument `%2%'", fun.lambda.fun->pos, i->name);
throwTypeError("%1% called with unexpected argument `%2%'", fun.lambda.fun->showNamePos(), i->name);
abort(); // can't happen
}
}
Expand All @@ -782,7 +787,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
try {
fun.lambda.fun->body->eval(*this, env2, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos);
addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos());
throw;
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/libexpr/nixexpr.cc
Expand Up @@ -324,4 +324,24 @@ void ExprConcatStrings::bindVars(const StaticEnv & env)
}


/* Storing function names. */

void Expr::setName(Symbol & name)
{
}


void ExprLambda::setName(Symbol & name)
{
this->name = name;
body->setName(name);
}


string ExprLambda::showNamePos()
{
return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str();
}


}
4 changes: 4 additions & 0 deletions src/libexpr/nixexpr.hh
Expand Up @@ -63,6 +63,7 @@ struct Expr
virtual void bindVars(const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
};

std::ostream & operator << (std::ostream & str, Expr & e);
Expand Down Expand Up @@ -197,6 +198,7 @@ struct Formals
struct ExprLambda : Expr
{
Pos pos;
Symbol name;
Symbol arg;
bool matchAttrs;
Formals * formals;
Expand All @@ -208,6 +210,8 @@ struct ExprLambda : Expr
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% arg % pos);
};
void setName(Symbol & name);
string showNamePos();
COMMON_METHODS
};

Expand Down
1 change: 1 addition & 0 deletions src/libexpr/parser.y
Expand Up @@ -104,6 +104,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
}
}
}
e->setName(attrPath.back());
}


Expand Down
13 changes: 9 additions & 4 deletions src/libexpr/symbol-table.hh
Expand Up @@ -28,17 +28,17 @@ private:

public:
Symbol() : s(0) { };

bool operator == (const Symbol & s2) const
{
return s == s2.s;
}

bool operator != (const Symbol & s2) const
{
return s != s2.s;
}

bool operator < (const Symbol & s2) const
{
return s < s2.s;
Expand All @@ -49,6 +49,11 @@ public:
return *s;
}

bool set() const
{
return s;
}

bool empty() const
{
return s->empty();
Expand All @@ -66,7 +71,7 @@ inline std::ostream & operator << (std::ostream & str, const Symbol & sym)
class SymbolTable
{
private:
#if HAVE_TR1_UNORDERED_SET
#if HAVE_TR1_UNORDERED_SET
typedef std::tr1::unordered_set<string> Symbols;
#else
typedef std::set<string> Symbols;
Expand Down

0 comments on commit 18a48d8

Please sign in to comment.