1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-19 08:49:35 +01:00

Evaluate more lazily in findAlongAttrPath

This commit is contained in:
regnat 2021-06-04 16:45:38 +02:00
parent fbaee9b8fb
commit 30d14b772f
4 changed files with 73 additions and 8 deletions

View file

@ -58,23 +58,17 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
Value * vNew = state.allocValue(); Value * vNew = state.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew); state.autoCallFunction(autoArgs, *v, *vNew);
v = vNew; v = vNew;
state.forceValue(*v);
/* It should evaluate to either a set or an expression, /* It should evaluate to either a set or an expression,
according to what is specified in the attrPath. */ according to what is specified in the attrPath. */
if (!attrIndex) { if (!attrIndex) {
if (v->type() != nAttrs)
throw TypeError(
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v));
if (attr.empty()) if (attr.empty())
throw Error("empty attribute name in selection path '%1%'", attrPath); throw Error("empty attribute name in selection path '%1%'", attrPath);
auto v2 = state.allocValue(); auto v2 = state.allocValue();
auto gotField = state.getAttrField(*v, {state.symbols.create(attr)}, pos, *v2); auto gotField = state.lazyGetAttrField(*v, {state.symbols.create(attr)}, pos, *v2);
if (!gotField) if (!gotField)
throw AttrPathNotFound("attribute '%1%' in selection path '%2%' not found", attr, attrPath); throw AttrPathNotFound("attribute '%1%' in selection path '%2%' not found", attr, attrPath);
v = v2; v = v2;

View file

@ -1189,6 +1189,54 @@ void EvalState::updateCacheStats(ValueCache::CacheResult cacheResult)
}; };
} }
struct ExprCastedVar : Expr
{
Value * v;
ExprCastedVar(Value * v) : v(v) {};
void show(std::ostream & str) const override {
std::set<const Value*> active;
printValue(str, active, *v);
}
void bindVars(const StaticEnv & env) override {}
void eval(EvalState & state, Env & env, Value & v) override {
v = std::move(*this->v);
}
Value * maybeThunk(EvalState & state, Env & env) override {
return v;
}
};
bool EvalState::lazyGetAttrField(Value & attrs, const std::vector<Symbol> & selector, const Pos & pos, Value & dest)
{
forceValue(attrs, pos);
auto eval_cache = attrs.getEvalCache();
auto [ cacheResult, resultingCursor ] = eval_cache.getValue(*this, selector, dest);
updateCacheStats(cacheResult);
switch (cacheResult.returnCode) {
case ValueCache::CacheHit:
if (cacheResult.lastQueriedSymbolIfMissing)
return false;
return true;
case ValueCache::Forward: {
auto recordAsVar = new ExprCastedVar(&attrs);
auto accessExpr = new ExprSelect(pos, recordAsVar, selector);
auto thunk = (Thunk*)allocBytes(sizeof(Thunk));
thunk->expr = accessExpr;
thunk->env = &baseEnv;
dest.mkCachedThunk(
thunk,
new ValueCache(resultingCursor)
);
return true;
}
default:
return getAttrField(attrs, selector, pos, dest);
;
}
}
bool EvalState::getAttrField(Value & attrs, const std::vector<Symbol> & selector, const Pos & pos, Value & dest) bool EvalState::getAttrField(Value & attrs, const std::vector<Symbol> & selector, const Pos & pos, Value & dest)
{ {
@ -1449,9 +1497,24 @@ void EvalState::incrFunctionCall(ExprLambda * fun)
functionCalls[fun]++; functionCalls[fun]++;
} }
std::optional<tree_cache::AttrValue> ValueCache::getRawValue()
{
if (!rawCache)
return std::nullopt;
return rawCache->getCachedValue();
}
void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
{ {
if (auto evalCache = fun.getEvalCache(); !evalCache.isEmpty()) {
if (auto cacheValue = evalCache.getRawValue()) {
if (std::holds_alternative<tree_cache::attributeSet_t>(*cacheValue)) {
res = fun;
return;
}
}
}
forceValue(fun); forceValue(fun);
if (fun.type() == nAttrs) { if (fun.type() == nAttrs) {

View file

@ -356,6 +356,9 @@ private:
public: public:
bool getAttrField(Value & attrs, const std::vector<Symbol> & selector, const Pos & pos, Value & dest); bool getAttrField(Value & attrs, const std::vector<Symbol> & selector, const Pos & pos, Value & dest);
// 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<Symbol> & selector, const Pos & pos, Value & dest);
}; };

View file

@ -165,7 +165,12 @@ struct ExprSelect : Expr
Expr * e, * def; Expr * e, * def;
AttrPath attrPath; AttrPath attrPath;
ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; ExprSelect(const Pos & pos, Expr * e, const Symbol & name)
: ExprSelect(pos, e, std::vector{name}) {};
ExprSelect(const Pos & pos, Expr * e, const std::vector<Symbol> & symbolicAttrPath) : pos(pos), e(e), def(0) {
for (auto & name : symbolicAttrPath)
attrPath.push_back(AttrName(name));
};
COMMON_METHODS COMMON_METHODS
}; };