aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-03-08 09:52:15 +0100
committereldritch horrors <pennae@lix.systems>2024-03-10 03:18:32 -0600
commitb667b4cded1b9d974157f27761d8648b372d27bf (patch)
treebe37e4ecd58fee0a88664db5516b877d7683a0ab /src/libexpr/eval.cc
parent71e0114708d406fdc0d9ca34d4b67cb190881439 (diff)
evaluate inherit (from) exprs only once per directive
desugaring inherit-from to syntactic duplication of the source expr also duplicates side effects of the source expr (such as trace calls) and expensive computations (such as derivationStrict). (cherry picked from commit cefd0302b55b3360dbca59cfcb4bf6a750d6cdcf) Change-Id: Iff519f991adef2e51683ba2c552d37a3df7a179e
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc24
1 files changed, 20 insertions, 4 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index e30c32d92..9fa036d6c 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1217,6 +1217,18 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
}
+Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
+{
+ Env & inheritEnv = state.allocEnv(inheritFromExprs->size());
+ inheritEnv.up = &up;
+
+ Displacement displ = 0;
+ for (auto from : *inheritFromExprs)
+ inheritEnv.values[displ++] = from->maybeThunk(state, up);
+
+ return &inheritEnv;
+}
+
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
{
v.mkAttrs(state.buildBindings(attrs.size() + dynamicAttrs.size()).finish());
@@ -1228,6 +1240,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(attrs.size()));
env2.up = &env;
dynamicEnv = &env2;
+ Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env2) : nullptr;
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
bool hasOverrides = overrides != attrs.end();
@@ -1240,9 +1253,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
Value * vAttr;
if (hasOverrides && !i.second.inherited()) {
vAttr = state.allocValue();
- mkThunk(*vAttr, *i.second.chooseByKind(&env2, &env, &env2), i.second.e);
+ mkThunk(*vAttr, *i.second.chooseByKind(&env2, &env, inheritEnv), i.second.e);
} else
- vAttr = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, &env2));
+ vAttr = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i.first, vAttr, i.second.pos));
}
@@ -1275,10 +1288,11 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
}
else {
+ Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env) : nullptr;
for (auto & i : attrs) {
v.attrs->push_back(Attr(
i.first,
- i.second.e->maybeThunk(state, *i.second.chooseByKind(&env, &env, &env)),
+ i.second.e->maybeThunk(state, *i.second.chooseByKind(&env, &env, inheritEnv)),
i.second.pos));
}
}
@@ -1313,6 +1327,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(attrs->attrs.size()));
env2.up = &env;
+ Env * inheritEnv = attrs->inheritFromExprs ? attrs->buildInheritFromEnv(state, env2) : nullptr;
+
/* The recursive attributes are evaluated in the new environment,
while the inherited attributes are evaluated in the original
environment. */
@@ -1320,7 +1336,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
for (auto & i : attrs->attrs) {
env2.values[displ++] = i.second.e->maybeThunk(
state,
- *i.second.chooseByKind(&env2, &env, &env2));
+ *i.second.chooseByKind(&env2, &env, inheritEnv));
}
auto dts = state.debugRepl