diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c927db2c10..76bace1d4b 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -310,6 +310,10 @@ inline Value * EvalState::lookupVar(Env * env, const VarRef & var) if (var.fromWith) { while (1) { + if (env->values[0] == NULL) { + env->values[0] = allocValue(); + evalAttrs(*env->up, env->withAttrs, *env->values[0]); + } Bindings::iterator j = env->values[0]->attrs->find(var.name); if (j != env->values[0]->attrs->end()) { if (countCalls && j->pos) attrSelects[*j->pos]++; @@ -337,7 +341,7 @@ Env & EvalState::allocEnv(unsigned int size) nrValuesInEnvs += size; Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *)); - /* Clear the values because maybeThunk() expects this. */ + /* Clear the values because maybeThunk() and lookupVar fromWith expects this. */ for (unsigned i = 0; i < size; ++i) env->values[i] = 0; @@ -405,10 +409,12 @@ unsigned long nrAvoided = 0; Value * ExprVar::maybeThunk(EvalState & state, Env & env) { - Value * v = state.lookupVar(&env, info); - /* The value might not be initialised in the environment yet. - In that case, ignore it. */ - if (v) { nrAvoided++; return v; } + if (!info.fromWith) { + Value * v = state.lookupVar(&env, info); + /* The value might not be initialised in the environment yet. + In that case, ignore it. */ + if (v) { nrAvoided++; return v; } + } return Expr::maybeThunk(state, env); } @@ -825,8 +831,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.up = &env; env2.prevWith = prevWith; - env2.values[0] = state.allocValue(); - state.evalAttrs(env, attrs, *env2.values[0]); + env2.withAttrs = attrs; body->eval(state, env2, v); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index a57efa08f1..0e4ad3db23 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -53,6 +53,7 @@ struct Env { Env * up; unsigned int prevWith; // nr of levels up to next `with' environment + Expr * withAttrs; Value * values[0]; }; diff --git a/tests/lang/eval-okay-delayed-with.exp b/tests/lang/eval-okay-delayed-with.exp new file mode 100644 index 0000000000..eaacb55c1a --- /dev/null +++ b/tests/lang/eval-okay-delayed-with.exp @@ -0,0 +1 @@ +"b-overridden" diff --git a/tests/lang/eval-okay-delayed-with.nix b/tests/lang/eval-okay-delayed-with.nix new file mode 100644 index 0000000000..82934d6a9d --- /dev/null +++ b/tests/lang/eval-okay-delayed-with.nix @@ -0,0 +1,26 @@ +let + pkgs_ = with pkgs; { + a = derivation { + name = "a"; + system = builtins.currentSystem; + builder = "/bin/sh"; + args = [ "-c" "touch $out" ]; + inherit b; + }; + + b = derivation { + name = "b"; + system = builtins.currentSystem; + builder = "/bin/sh"; + args = [ "-c" "touch $out" ]; + }; + + c = b; + }; + + packageOverrides = p: { + b = derivation (p.b.drvAttrs // { name = "b-overridden"; }); + }; + + pkgs = pkgs_ // (packageOverrides pkgs_); +in pkgs.a.b.name