forked from lix-project/lix
Make function calls show up in stack traces again
Note that adding --show-trace prevents functions calls from being tail-recursive, so an expression that evaluates without --show-trace may fail with a stack overflow if --show-trace is given.
This commit is contained in:
parent
2bcb384e95
commit
89e6781cc5
|
@ -279,6 +279,11 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
|
||||||
e.addPrefix(format(s) % s2);
|
e.addPrefix(format(s) % s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun))
|
||||||
|
{
|
||||||
|
e.addPrefix(format(s) % fun.showNamePos());
|
||||||
|
}
|
||||||
|
|
||||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos))
|
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos))
|
||||||
{
|
{
|
||||||
e.addPrefix(format(s) % s2 % pos);
|
e.addPrefix(format(s) % s2 % pos);
|
||||||
|
@ -757,32 +762,34 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
if (fun.type != tLambda)
|
if (fun.type != tLambda)
|
||||||
throwTypeError("attempt to call something which is not a function but %1%", fun);
|
throwTypeError("attempt to call something which is not a function but %1%", fun);
|
||||||
|
|
||||||
|
ExprLambda & lambda(*fun.lambda.fun);
|
||||||
|
|
||||||
unsigned int size =
|
unsigned int size =
|
||||||
(fun.lambda.fun->arg.empty() ? 0 : 1) +
|
(lambda.arg.empty() ? 0 : 1) +
|
||||||
(fun.lambda.fun->matchAttrs ? fun.lambda.fun->formals->formals.size() : 0);
|
(lambda.matchAttrs ? lambda.formals->formals.size() : 0);
|
||||||
Env & env2(allocEnv(size));
|
Env & env2(allocEnv(size));
|
||||||
env2.up = fun.lambda.env;
|
env2.up = fun.lambda.env;
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
|
|
||||||
if (!fun.lambda.fun->matchAttrs)
|
if (!lambda.matchAttrs)
|
||||||
env2.values[displ++] = &arg;
|
env2.values[displ++] = &arg;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
forceAttrs(arg);
|
forceAttrs(arg);
|
||||||
|
|
||||||
if (!fun.lambda.fun->arg.empty())
|
if (!lambda.arg.empty())
|
||||||
env2.values[displ++] = &arg;
|
env2.values[displ++] = &arg;
|
||||||
|
|
||||||
/* For each formal argument, get the actual argument. If
|
/* For each formal argument, get the actual argument. If
|
||||||
there is no matching actual argument but the formal
|
there is no matching actual argument but the formal
|
||||||
argument has a default, use the default. */
|
argument has a default, use the default. */
|
||||||
unsigned int attrsUsed = 0;
|
unsigned int attrsUsed = 0;
|
||||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
foreach (Formals::Formals_::iterator, i, lambda.formals->formals) {
|
||||||
Bindings::iterator j = arg.attrs->find(i->name);
|
Bindings::iterator j = arg.attrs->find(i->name);
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
|
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
|
||||||
*fun.lambda.fun, i->name);
|
lambda, i->name);
|
||||||
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
|
@ -792,29 +799,30 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
|
|
||||||
/* Check that each actual argument is listed as a formal
|
/* Check that each actual argument is listed as a formal
|
||||||
argument (unless the attribute match specifies a `...'). */
|
argument (unless the attribute match specifies a `...'). */
|
||||||
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
||||||
/* Nope, so show the first unexpected argument to the
|
/* Nope, so show the first unexpected argument to the
|
||||||
user. */
|
user. */
|
||||||
foreach (Bindings::iterator, i, *arg.attrs)
|
foreach (Bindings::iterator, i, *arg.attrs)
|
||||||
if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end())
|
if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end())
|
||||||
throwTypeError("%1% called with unexpected argument `%2%'", *fun.lambda.fun, i->name);
|
throwTypeError("%1% called with unexpected argument `%2%'", lambda, i->name);
|
||||||
abort(); // can't happen
|
abort(); // can't happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nrFunctionCalls++;
|
nrFunctionCalls++;
|
||||||
if (countCalls) incrFunctionCall(fun.lambda.fun);
|
if (countCalls) incrFunctionCall(&lambda);
|
||||||
|
|
||||||
fun.lambda.fun->body->eval(*this, env2, v);
|
/* Evaluate the body. This is conditional on showTrace, because
|
||||||
|
catching exceptions makes this function not tail-recursive. */
|
||||||
#if 0
|
if (settings.showTrace)
|
||||||
try {
|
try {
|
||||||
|
lambda.body->eval(*this, env2, v);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorPrefix(e, "while evaluating %1%:\n", lambda);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
else
|
||||||
fun.lambda.fun->body->eval(*this, env2, v);
|
fun.lambda.fun->body->eval(*this, env2, v);
|
||||||
} catch (Error & e) {
|
|
||||||
addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos());
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -89,9 +89,6 @@ static void setLogType(string lt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool showTrace = false;
|
|
||||||
|
|
||||||
|
|
||||||
string getArg(const string & opt,
|
string getArg(const string & opt,
|
||||||
Strings::iterator & i, const Strings::iterator & end)
|
Strings::iterator & i, const Strings::iterator & end)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +211,7 @@ static void initAndRun(int argc, char * * argv)
|
||||||
else if (arg == "--no-build-hook")
|
else if (arg == "--no-build-hook")
|
||||||
settings.useBuildHook = false;
|
settings.useBuildHook = false;
|
||||||
else if (arg == "--show-trace")
|
else if (arg == "--show-trace")
|
||||||
showTrace = true;
|
settings.showTrace = true;
|
||||||
else if (arg == "--option") {
|
else if (arg == "--option") {
|
||||||
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
||||||
string name = *i;
|
string name = *i;
|
||||||
|
@ -299,8 +296,8 @@ int main(int argc, char * * argv)
|
||||||
% e.what() % programId);
|
% e.what() % programId);
|
||||||
return 1;
|
return 1;
|
||||||
} catch (BaseError & e) {
|
} catch (BaseError & e) {
|
||||||
printMsg(lvlError, format("error: %1%%2%") % (showTrace ? e.prefix() : "") % e.msg());
|
printMsg(lvlError, format("error: %1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
|
||||||
if (e.prefix() != "" && !showTrace)
|
if (e.prefix() != "" && !settings.showTrace)
|
||||||
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
|
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
|
||||||
return e.status;
|
return e.status;
|
||||||
} catch (std::bad_alloc & e) {
|
} catch (std::bad_alloc & e) {
|
||||||
|
|
|
@ -55,6 +55,7 @@ Settings::Settings()
|
||||||
autoOptimiseStore = false;
|
autoOptimiseStore = false;
|
||||||
envKeepDerivations = false;
|
envKeepDerivations = false;
|
||||||
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
|
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
|
||||||
|
showTrace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,9 @@ struct Settings {
|
||||||
/* Whether to lock the Nix client and worker to the same CPU. */
|
/* Whether to lock the Nix client and worker to the same CPU. */
|
||||||
bool lockCPU;
|
bool lockCPU;
|
||||||
|
|
||||||
|
/* Whether to show a stack trace if Nix evaluation fails. */
|
||||||
|
bool showTrace;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SettingsMap settings, overrides;
|
SettingsMap settings, overrides;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue