From af775bdcf97bd065505af2ea5f6e292166f05d32 Mon Sep 17 00:00:00 2001 From: regnat Date: Wed, 9 Jun 2021 18:39:55 +0200 Subject: [PATCH] Make lazyGetAttrField return something more informative --- src/libcmd/installables.cc | 2 +- src/libexpr/attr-path.cc | 2 +- src/libexpr/eval.cc | 16 +++++++++------- src/libexpr/eval.hh | 9 ++++++++- src/nix/search.cc | 3 ++- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 4206c70ce..e5f479974 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -438,7 +438,7 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked auto vRes = state.allocValue(); auto gotField = state.lazyGetAttrField(*vFlake, {state.symbols.create("outputs")}, noPos, *vRes); - assert(gotField); + assert(gotField != EvalState::LazyValueType::Missing); return vRes; } diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index defecb008..ffa887d33 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -68,7 +68,7 @@ std::pair findAlongAttrPath(EvalState & state, const string & attr throw Error("empty attribute name in selection path '%1%'", attrPath); auto v2 = state.allocValue(); - auto gotField = state.lazyGetAttrField(*v, {state.symbols.create(attr)}, pos, *v2); + auto gotField = state.lazyGetAttrField(*v, {state.symbols.create(attr)}, pos, *v2) != EvalState::LazyValueType::Missing; if (!gotField) throw AttrPathNotFound("attribute '%1%' in selection path '%2%' not found", attr, attrPath); v = v2; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 48752a925..c659b513a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1189,7 +1189,7 @@ void EvalState::updateCacheStats(ValueCache::CacheResult cacheResult) }; } -bool EvalState::lazyGetAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest) +EvalState::LazyValueType EvalState::lazyGetAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest) { auto eval_cache = attrs.getEvalCache(); if (eval_cache.isEmpty()) { @@ -1201,8 +1201,8 @@ bool EvalState::lazyGetAttrField(Value & attrs, const std::vector & sele switch (cacheResult.returnCode) { case ValueCache::CacheHit: if (cacheResult.lastQueriedSymbolIfMissing) - return false; - return true; + return LazyValueType::Missing; + return LazyValueType::PlainValue; case ValueCache::Forward: { auto recordAsVar = new ExprCastedVar(&attrs); auto accessExpr = new ExprSelect(pos, recordAsVar, selector); @@ -1214,11 +1214,13 @@ bool EvalState::lazyGetAttrField(Value & attrs, const std::vector & sele thunk, new ValueCache(resultingCursor) ); - return true; + return LazyValueType::DelayedAttrSet; } default: - return getAttrField(attrs, selector, pos, dest); - ; + if(getAttrField(attrs, selector, pos, dest)) + return LazyValueType::PlainValue; + else + return LazyValueType::Missing; } } @@ -1308,7 +1310,7 @@ std::vector EvalState::getFields(Value & attrs, const Pos & pos) for (auto & attrName : *attrNames) { auto newValue = allocValue(); try { - if (lazyGetAttrField(attrs, {attrName}, pos, *newValue)) { + if (lazyGetAttrField(attrs, {attrName}, pos, *newValue) != LazyValueType::Missing) { res.push_back(Attr(attrName, newValue)); } else { everythingCached = false; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index f421e8dd2..73ef7f598 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -356,9 +356,16 @@ private: public: bool getAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest); + + enum struct LazyValueType { + PlainValue, + DelayedAttrSet, + Missing, + }; + // Similar to `getAttrField`, but if the cache says that the result is an // attribute set, just return a thunk to it rather than forcing it. - bool lazyGetAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest); + LazyValueType lazyGetAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest); // Similar to `getAttrField`, but throws an `Error` if the field can’t be // found diff --git a/src/nix/search.cc b/src/nix/search.cc index 0b8655117..b865073ad 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -154,7 +154,8 @@ struct CmdSearch : InstallableCommand, MixJSON recurse(); else if (attrPath[0] == "legacyPackages" && attrPath.size() > 2) { - auto hasRecurse = state->getAttrField(current, {state->sRecurseForDerivations}, noPos, *vTmp); + auto recurseFieldInfo = state->lazyGetAttrField(current, {state->sRecurseForDerivations}, noPos, *vTmp); + auto hasRecurse = recurseFieldInfo == EvalState::LazyValueType::PlainValue; if (hasRecurse && state->forceBool(*vTmp, noPos)) recurse(); }