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:
parent
fbaee9b8fb
commit
30d14b772f
4 changed files with 73 additions and 8 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue