From 75837651f15fc3c451ae54afbb5927c1abe329c5 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Fri, 31 Jul 2015 17:32:25 +0200 Subject: [PATCH] Output line number on infinite recursion --- src/libexpr/eval-inline.hh | 9 +++++---- src/libexpr/eval.cc | 16 ++++++++-------- src/libexpr/eval.hh | 2 +- tests/misc.sh | 3 +++ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 178e06c80..4abc485aa 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -1,15 +1,16 @@ #pragma once #include "eval.hh" +#include "shared.hh" #define LocalNoInline(f) static f __attribute__((noinline)); f #define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f namespace nix { -LocalNoInlineNoReturn(void throwEvalError(const char * s)) +LocalNoInlineNoReturn(void throwEvalError(const FormatOrString & fs)) { - throw EvalError(s); + throw EvalError(fs); } LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v)) @@ -24,7 +25,7 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const } -void EvalState::forceValue(Value & v) +void EvalState::forceValue(Value & v, const Pos & pos) { if (v.type == tThunk) { Env * env = v.thunk.env; @@ -43,7 +44,7 @@ void EvalState::forceValue(Value & v) else if (v.type == tApp) callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.type == tBlackhole) - throwEvalError("infinite recursion encountered"); + throwEvalError(format("infinite recursion encountered, at %1%") % pos); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 769aae0a9..ec02e61b0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -746,7 +746,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) for (auto & i : dynamicAttrs) { Value nameVal; i.nameExpr->eval(state, *dynamicEnv, nameVal); - state.forceValue(nameVal); + state.forceValue(nameVal, i.pos); if (nameVal.type == tNull) continue; state.forceStringNoCtx(nameVal); @@ -792,7 +792,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) void ExprVar::eval(EvalState & state, Env & env, Value & v) { Value * v2 = state.lookupVar(&env, *this, false); - state.forceValue(*v2); + state.forceValue(*v2, pos); v = *v2; } @@ -831,7 +831,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) Bindings::iterator j; Symbol name = getName(i, state, env); if (def) { - state.forceValue(*vAttrs); + state.forceValue(*vAttrs, pos); if (vAttrs->type != tAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { @@ -848,7 +848,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (state.countCalls && pos2) state.attrSelects[*pos2]++; } - state.forceValue(*vAttrs); + state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) ); } catch (Error & e) { if (pos2 && pos2->file != state.sDerivationNix) @@ -950,10 +950,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po if (fun.type == tAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { - forceValue(*found->value); + forceValue(*found->value, pos); Value * v2 = allocValue(); callFunction(*found->value, fun, *v2, pos); - forceValue(*v2); + forceValue(*v2, pos); return callFunction(*v2, arg, v, pos); } } @@ -1280,7 +1280,7 @@ void EvalState::forceValueDeep(Value & v) NixInt EvalState::forceInt(Value & v, const Pos & pos) { - forceValue(v); + forceValue(v, pos); if (v.type != tInt) throwTypeError("value is %1% while an integer was expected, at %2%", v, pos); return v.integer; @@ -1306,7 +1306,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) string EvalState::forceString(Value & v, const Pos & pos) { - forceValue(v); + forceValue(v, pos); if (v.type != tString) { if (pos) throwTypeError("value is %1% while a string was expected, at %2%", v, pos); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 74a273b54..8df0084fd 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -136,7 +136,7 @@ public: of the evaluation of the thunk. If `v' is a delayed function application, call the function and overwrite `v' with the result. Otherwise, this is a no-op. */ - inline void forceValue(Value & v); + inline void forceValue(Value & v, const Pos & pos = noPos); /* Force a value, then recursively force list elements and attributes. */ diff --git a/tests/misc.sh b/tests/misc.sh index 1b4d8f2cf..6d0ab3adc 100644 --- a/tests/misc.sh +++ b/tests/misc.sh @@ -14,3 +14,6 @@ nix-env --version | grep "$version" # Usage errors. nix-env --foo 2>&1 | grep "no operation" nix-env -q --foo 2>&1 | grep "unknown flag" + +# Eval Errors. +nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 | grep "infinite recursion encountered, at (string):1:15$"