Make Env self-describing

If the Env denotes a 'with', then values[0] may be an Expr* cast to a
Value*. For code that generically traverses Values/Envs, it's useful
to know this.
This commit is contained in:
Eelco Dolstra 2018-05-22 16:02:32 +02:00
parent 9fd7cf98db
commit 4bb8741b98
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
2 changed files with 12 additions and 8 deletions

View file

@ -307,6 +307,8 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
assert(gcInitialised); assert(gcInitialised);
static_assert(sizeof(Env) == 16);
/* Initialise the Nix expression search path. */ /* Initialise the Nix expression search path. */
if (!settings.pureEval) { if (!settings.pureEval) {
Strings paths = parseNixPath(getEnv("NIX_PATH", "")); Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
@ -568,12 +570,12 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
if (!var.fromWith) return env->values[var.displ]; if (!var.fromWith) return env->values[var.displ];
while (1) { while (1) {
if (!env->haveWithAttrs) { if (env->type == Env::HasWithExpr) {
if (noEval) return 0; if (noEval) return 0;
Value * v = allocValue(); Value * v = allocValue();
evalAttrs(*env->up, (Expr *) env->values[0], *v); evalAttrs(*env->up, (Expr *) env->values[0], *v);
env->values[0] = v; env->values[0] = v;
env->haveWithAttrs = true; env->type = Env::HasWithAttrs;
} }
Bindings::iterator j = env->values[0]->attrs->find(var.name); Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) { if (j != env->values[0]->attrs->end()) {
@ -603,6 +605,7 @@ Env & EvalState::allocEnv(size_t size)
nrValuesInEnvs += size; nrValuesInEnvs += size;
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *)); Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
env->size = (decltype(Env::size)) size; env->size = (decltype(Env::size)) size;
env->type = Env::Plain;
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */ /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
@ -1205,7 +1208,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(1)); Env & env2(state.allocEnv(1));
env2.up = &env; env2.up = &env;
env2.prevWith = prevWith; env2.prevWith = prevWith;
env2.haveWithAttrs = false; env2.type = Env::HasWithExpr;
env2.values[0] = (Value *) attrs; env2.values[0] = (Value *) attrs;
body->eval(state, env2, v); body->eval(state, env2, v);
@ -1863,6 +1866,7 @@ size_t valueSize(Value & v)
size_t sz = sizeof(Env) + sizeof(Value *) * env.size; size_t sz = sizeof(Env) + sizeof(Value *) * env.size;
if (env.type != Env::HasWithExpr)
for (size_t i = 0; i < env.size; ++i) for (size_t i = 0; i < env.size; ++i)
if (env.values[i]) if (env.values[i])
sz += doValue(*env.values[i]); sz += doValue(*env.values[i]);

View file

@ -35,8 +35,8 @@ struct Env
{ {
Env * up; Env * up;
unsigned short size; // used by valueSize unsigned short size; // used by valueSize
unsigned short prevWith:15; // nr of levels up to next `with' environment unsigned short prevWith:14; // nr of levels up to next `with' environment
unsigned short haveWithAttrs:1; enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2;
Value * values[0]; Value * values[0];
}; };