diff options
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r-- | src/libexpr/eval.cc | 92 |
1 files changed, 67 insertions, 25 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index b90a64357..7a2f55504 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -199,6 +199,18 @@ string showType(const Value & v) } +bool Value::isTrivial() const +{ + return + type != tApp + && type != tPrimOpApp + && (type != tThunk + || (dynamic_cast<ExprAttrs *>(thunk.expr) + && ((ExprAttrs *) thunk.expr)->dynamicAttrs.empty()) + || dynamic_cast<ExprLambda *>(thunk.expr)); +} + + #if HAVE_BOEHMGC /* Called when the Boehm GC runs out of memory. */ static void * oomHandler(size_t requested) @@ -337,6 +349,9 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store) , sOutputHashAlgo(symbols.create("outputHashAlgo")) , sOutputHashMode(symbols.create("outputHashMode")) , sRecurseForDerivations(symbols.create("recurseForDerivations")) + , sDescription(symbols.create("description")) + , sSelf(symbols.create("self")) + , sEpsilon(symbols.create("")) , repair(NoRepair) , store(store) , baseEnv(allocEnv(128)) @@ -366,7 +381,7 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store) if (store->isInStore(r.second)) { StorePathSet closure; - store->computeFSClosure(store->parseStorePath(store->toStorePath(r.second)), closure); + store->computeFSClosure(store->toStorePath(r.second).first, closure); for (auto & path : closure) allowedPaths->insert(store->printStorePath(path)); } else @@ -529,7 +544,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const { throw EvalError({ .hint = hintfmt(s, s2), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } @@ -542,7 +557,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const { throw EvalError({ .hint = hintfmt(s, s2, s3), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } @@ -551,7 +566,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const // p1 is where the error occurred; p2 is a position mentioned in the message. throw EvalError({ .hint = hintfmt(s, sym, p2), - .nixCode = NixCode { .errPos = p1 } + .errPos = p1 }); } @@ -559,7 +574,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s)) { throw TypeError({ .hint = hintfmt(s), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } @@ -572,7 +587,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const { throw TypeError({ .hint = hintfmt(s, fun.showNamePos(), s2), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } @@ -580,7 +595,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, { throw AssertionError({ .hint = hintfmt(s, s1), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } @@ -588,23 +603,18 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * { throw UndefinedVarError({ .hint = hintfmt(s, s1), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } -LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2)) +LocalNoInline(void addErrorTrace(Error & e, const char * s, const string & s2)) { - e.addPrefix(format(s) % s2); + e.addTrace(std::nullopt, s, s2); } -LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun, const Pos & pos)) +LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, const string & s2)) { - e.addPrefix(format(s) % fun.showNamePos() % pos); -} - -LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos)) -{ - e.addPrefix(format(s) % s2 % pos); + e.addTrace(pos, s, s2); } @@ -787,7 +797,7 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env) } -void EvalState::evalFile(const Path & path_, Value & v) +void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial) { auto path = checkSourcePath(path_); @@ -816,9 +826,14 @@ void EvalState::evalFile(const Path & path_, Value & v) fileParseCache[path2] = e; try { + // Enforce that 'flake.nix' is a direct attrset, not a + // computation. + if (mustBeTrivial && + !(dynamic_cast<ExprAttrs *>(e))) + throw Error("file '%s' must be an attribute set", path); eval(e, v); } catch (Error & e) { - addErrorPrefix(e, "while evaluating the file '%1%':\n", path2); + addErrorTrace(e, "while evaluating the file '%1%':", path2); throw; } @@ -1068,8 +1083,8 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) } catch (Error & e) { if (pos2 && pos2->file != state.sDerivationNix) - addErrorPrefix(e, "while evaluating the attribute '%1%' at %2%:\n", - showAttrPath(state, env, attrPath), *pos2); + addErrorTrace(e, *pos2, "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)); throw; } @@ -1237,11 +1252,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po /* Evaluate the body. This is conditional on showTrace, because catching exceptions makes this function not tail-recursive. */ - if (settings.showTrace) + if (loggerSettings.showTrace.get()) try { lambda.body->eval(*this, env2, v); } catch (Error & e) { - addErrorPrefix(e, "while evaluating %1%, called from %2%:\n", lambda, pos); + addErrorTrace(e, lambda.pos, "while evaluating %s", + (lambda.name.set() + ? "'" + (string) lambda.name + "'" + : "anonymous lambdaction")); + addErrorTrace(e, pos, "from call site%s", ""); throw; } else @@ -1516,7 +1535,7 @@ void EvalState::forceValueDeep(Value & v) try { recurse(*i.value); } catch (Error & e) { - addErrorPrefix(e, "while evaluating the attribute '%1%' at %2%:\n", i.name, *i.pos); + addErrorTrace(e, *i.pos, "while evaluating the attribute '%1%'", i.name); throw; } } @@ -1587,6 +1606,18 @@ string EvalState::forceString(Value & v, const Pos & pos) } +/* Decode a context string ‘!<name>!<path>’ into a pair <path, + name>. */ +std::pair<string, string> decodeContext(std::string_view s) +{ + if (s.at(0) == '!') { + size_t index = s.find("!", 1); + return {std::string(s.substr(index + 1)), std::string(s.substr(1, index - 1))}; + } else + return {s.at(0) == '/' ? std::string(s) : std::string(s.substr(1)), ""}; +} + + void copyContext(const Value & v, PathSet & context) { if (v.string.context) @@ -1595,6 +1626,17 @@ void copyContext(const Value & v, PathSet & context) } +std::vector<std::pair<Path, std::string>> Value::getContext() +{ + std::vector<std::pair<Path, std::string>> res; + assert(type == tString); + if (string.context) + for (const char * * p = string.context; *p; ++p) + res.push_back(decodeContext(*p)); + return res; +} + + string EvalState::forceString(Value & v, PathSet & context, const Pos & pos) { string s = forceString(v, pos); @@ -1936,7 +1978,7 @@ string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, boo { throw TypeError({ .hint = hintfmt("cannot coerce %1% to a string", showType()), - .nixCode = NixCode { .errPos = pos } + .errPos = pos }); } |