about summary refs log tree commit diff
path: root/third_party
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2020-05-22T00·58+0100
committerVincent Ambo <tazjin@google.com>2020-05-22T00·59+0100
commit986a8f6b75ffa51682cbe730c5c2907296082cd4 (patch)
tree32c266920223bbfbf0beb49689dc05cb8eb1f2b7 /third_party
parent42205f27fc820ddc64616d55c04e2ffde1948043 (diff)
fix(3p/nix): Update for usage of new attribute set API r/802
The new attribute set API uses the iterators of the btree_map
directly. This requires changes in various files because the internals
of libexpr are very entangled.

This code runs and compiles, but there is a bug causing empty
attribute sets to be assigned incorrectly.
Diffstat (limited to 'third_party')
-rw-r--r--third_party/nix/src/libexpr/attr-set.cc8
-rw-r--r--third_party/nix/src/libexpr/eval.cc64
-rw-r--r--third_party/nix/src/libexpr/get-drvs.cc59
-rw-r--r--third_party/nix/src/libexpr/primops.cc97
-rw-r--r--third_party/nix/src/libexpr/primops/context.cc51
-rw-r--r--third_party/nix/src/libexpr/primops/fetchGit.cc3
-rw-r--r--third_party/nix/src/libexpr/primops/fetchMercurial.cc3
-rw-r--r--third_party/nix/src/libexpr/value-to-json.cc6
-rw-r--r--third_party/nix/src/libexpr/value-to-xml.cc18
-rw-r--r--third_party/nix/src/nix-env/nix-env.cc5
-rw-r--r--third_party/nix/src/nix-env/user-env.cc4
-rw-r--r--third_party/nix/src/nix-prefetch-url/nix-prefetch-url.cc16
-rw-r--r--third_party/nix/src/nix/repl.cc13
-rw-r--r--third_party/nix/src/nix/search.cc16
14 files changed, 187 insertions, 176 deletions
diff --git a/third_party/nix/src/libexpr/attr-set.cc b/third_party/nix/src/libexpr/attr-set.cc
index 2df6bc9a21..a74292666b 100644
--- a/third_party/nix/src/libexpr/attr-set.cc
+++ b/third_party/nix/src/libexpr/attr-set.cc
@@ -34,13 +34,9 @@ Bindings::iterator Bindings::find(const Symbol& name) {
   return attributes_.find(name);
 }
 
-Bindings::iterator Bindings::begin() {
-  return attributes_.begin();
-}
+Bindings::iterator Bindings::begin() { return attributes_.begin(); }
 
-Bindings::iterator Bindings::end() {
-  return attributes_.end();
-}
+Bindings::iterator Bindings::end() { return attributes_.end(); }
 
 void Bindings::merge(Bindings* other) {
   // We want the values from the other attribute set to take
diff --git a/third_party/nix/src/libexpr/eval.cc b/third_party/nix/src/libexpr/eval.cc
index dcaaadbd08..dbf02134a2 100644
--- a/third_party/nix/src/libexpr/eval.cc
+++ b/third_party/nix/src/libexpr/eval.cc
@@ -493,7 +493,7 @@ Value* EvalState::addPrimOp(const std::string& name, size_t arity,
 }
 
 Value& EvalState::getBuiltin(const std::string& name) {
-  return *baseEnv.values[0]->attrs->find(symbols.Create(name))->value;
+  return *baseEnv.values[0]->attrs->find(symbols.Create(name))->second.value;
 }
 
 /* Every "format" object (even temporary) takes up a few hundred bytes
@@ -607,10 +607,10 @@ inline Value* EvalState::lookupVar(Env* env, const ExprVar& var, bool noEval) {
     }
     Bindings::iterator j = env->values[0]->attrs->find(var.name);
     if (j != env->values[0]->attrs->end()) {
-      if (countCalls && (j->pos != nullptr)) {
-        attrSelects[*j->pos]++;
+      if (countCalls && (j->second.pos != nullptr)) {
+        attrSelects[*j->second.pos]++;
       }
-      return j->value;
+      return j->second.value;
     }
     if (env->prevWith == 0u) {
       throwUndefinedVarError("undefined variable '%1%' at %2%", var.name,
@@ -857,21 +857,21 @@ void ExprAttrs::eval(EvalState& state, Env& env, Value& v) {
        Hence we need __overrides.) */
     if (hasOverrides) {
       Value* vOverrides =
-          v.attrs->find(overrides->first)
-              ->value;  //(*v.attrs)[overrides->second.displ].value;
+          //(*v.attrs)[overrides->second.displ].value;
+          v.attrs->find(overrides->first)->second.value;
       state.forceAttrs(*vOverrides);
       Bindings* newBnds = state.allocBindings(/* capacity = */ 0);
       for (auto& i : *v.attrs) {  // TODO(tazjin): copy constructor?
-        newBnds->push_back(i);
+        newBnds->push_back(i.second);
       }
       for (auto& i : *vOverrides->attrs) {
-        auto j = attrs.find(i.name);
+        auto j = attrs.find(i.second.name);
         if (j != attrs.end()) {
-          newBnds->push_back(i);
+          newBnds->push_back(i.second);
           // (*newBnds)[j->second.displ] = i;
-          env2.values[j->second.displ] = i.value;
+          env2.values[j->second.displ] = i.second.value;
         } else {
-          newBnds->push_back(i);
+          newBnds->push_back(i.second);
         }
       }
       newBnds->sort();
@@ -898,7 +898,7 @@ void ExprAttrs::eval(EvalState& state, Env& env, Value& v) {
     Bindings::iterator j = v.attrs->find(nameSym);
     if (j != v.attrs->end()) {
       throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%",
-                     nameSym, i.pos, *j->pos);
+                     nameSym, i.pos, *j->second.pos);
     }
 
     i.valueExpr->setName(nameSym);
@@ -987,8 +987,8 @@ void ExprSelect::eval(EvalState& state, Env& env, Value& v) {
           throwEvalError("attribute '%1%' missing, at %2%", name, pos);
         }
       }
-      vAttrs = j->value;
-      pos2 = j->pos;
+      vAttrs = j->second.value;
+      pos2 = j->second.pos;
       if (state.countCalls && (pos2 != nullptr)) {
         state.attrSelects[*pos2]++;
       }
@@ -1022,7 +1022,7 @@ void ExprOpHasAttr::eval(EvalState& state, Env& env, Value& v) {
       mkBool(v, false);
       return;
     }
-    vAttrs = j->value;
+    vAttrs = j->second.value;
   }
 
   mkBool(v, true);
@@ -1103,7 +1103,7 @@ void EvalState::callFunction(Value& fun, Value& arg, Value& v, const Pos& pos) {
       fun2 = fun;
       /* !!! Should we use the attr pos here? */
       Value v2;
-      callFunction(*found->value, fun2, v2, pos);
+      callFunction(*found->second.value, fun2, v2, pos);
       return callFunction(v2, arg, v, pos);
     }
   }
@@ -1147,7 +1147,7 @@ void EvalState::callFunction(Value& fun, Value& arg, Value& v, const Pos& pos) {
         env2.values[displ++] = i.def->maybeThunk(*this, env2);
       } else {
         attrsUsed++;
-        env2.values[displ++] = j->value;
+        env2.values[displ++] = j->second.value;
       }
     }
 
@@ -1157,10 +1157,10 @@ void EvalState::callFunction(Value& fun, Value& arg, Value& v, const Pos& pos) {
       /* Nope, so show the first unexpected argument to the
          user. */
       for (auto& i : *arg.attrs) {
-        if (lambda.formals->argNames.find(i.name) ==
+        if (lambda.formals->argNames.find(i.second.name) ==
             lambda.formals->argNames.end()) {
           throwTypeError("%1% called with unexpected argument '%2%', at %3%",
-                         lambda, i.name, pos);
+                         lambda, i.second.name, pos);
         }
       }
       abort();  // can't happen
@@ -1198,7 +1198,7 @@ void EvalState::autoCallFunction(Bindings& args, Value& fun, Value& res) {
     auto found = fun.attrs->find(sFunctor);
     if (found != fun.attrs->end()) {
       Value* v = allocValue();
-      callFunction(*found->value, fun, *v, noPos);
+      callFunction(*found->second.value, fun, *v, noPos);
       forceValue(*v);
       return autoCallFunction(args, *v, res);
     }
@@ -1215,7 +1215,7 @@ void EvalState::autoCallFunction(Bindings& args, Value& fun, Value& res) {
   for (auto& i : fun.lambda.fun->formals->formals) {
     Bindings::iterator j = args.find(i.name);
     if (j != args.end()) {
-      actualArgs->attrs->push_back(*j);
+      actualArgs->attrs->push_back(j->second);
     } else if (i.def == nullptr) {
       throwTypeError(
           "cannot auto-call a function that has an argument without a default "
@@ -1438,10 +1438,10 @@ void EvalState::forceValueDeep(Value& v) {
     if (v.type == tAttrs) {
       for (auto& i : *v.attrs) {
         try {
-          recurse(*i.value);
+          recurse(*i.second.value);
         } catch (Error& e) {
           addErrorPrefix(e, "while evaluating the attribute '%1%' at %2%:\n",
-                         i.name, *i.pos);
+                         i.second.name, *i.second.pos);
           throw;
         }
       }
@@ -1549,11 +1549,11 @@ bool EvalState::isDerivation(Value& v) {
   if (i == v.attrs->end()) {
     return false;
   }
-  forceValue(*i->value);
-  if (i->value->type != tString) {
+  forceValue(*i->second.value);
+  if (i->second.value->type != tString) {
     return false;
   }
-  return strcmp(i->value->string.s, "derivation") == 0;
+  return strcmp(i->second.value->string.s, "derivation") == 0;
 }
 
 std::optional<string> EvalState::tryAttrsToString(const Pos& pos, Value& v,
@@ -1563,7 +1563,7 @@ std::optional<string> EvalState::tryAttrsToString(const Pos& pos, Value& v,
   auto i = v.attrs->find(sToString);
   if (i != v.attrs->end()) {
     Value v1;
-    callFunction(*i->value, v, v1, pos);
+    callFunction(*i->second.value, v, v1, pos);
     return coerceToString(pos, v1, context, coerceMore, copyToStore);
   }
 
@@ -1596,7 +1596,8 @@ string EvalState::coerceToString(const Pos& pos, Value& v, PathSet& context,
     if (i == v.attrs->end()) {
       throwTypeError("cannot coerce a set to a string, at %1%", pos);
     }
-    return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
+    return coerceToString(pos, *i->second.value, context, coerceMore,
+                          copyToStore);
   }
 
   if (v.type == tExternal) {
@@ -1735,7 +1736,7 @@ bool EvalState::eqValues(Value& v1, Value& v2) {
         Bindings::iterator i = v1.attrs->find(sOutPath);
         Bindings::iterator j = v2.attrs->find(sOutPath);
         if (i != v1.attrs->end() && j != v2.attrs->end()) {
-          return eqValues(*i->value, *j->value);
+          return eqValues(*i->second.value, *j->second.value);
         }
       }
 
@@ -1748,7 +1749,8 @@ bool EvalState::eqValues(Value& v1, Value& v2) {
       Bindings::iterator j;
       for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end();
            ++i, ++j) {
-        if (i->name != j->name || !eqValues(*i->value, *j->value)) {
+        if (i->second.name != j->second.name ||
+            !eqValues(*i->second.value, *j->second.value)) {
           return false;
         }
       }
@@ -1934,7 +1936,7 @@ size_t valueSize(Value& v) {
           seen.insert(v.attrs);
           sz += sizeof(Bindings) + sizeof(Attr) * v.attrs->capacity();
           for (auto& i : *v.attrs) {
-            sz += doValue(*i.value);
+            sz += doValue(*i.second.value);
           }
         }
         break;
diff --git a/third_party/nix/src/libexpr/get-drvs.cc b/third_party/nix/src/libexpr/get-drvs.cc
index 733ee5a1ff..5b33afdba9 100644
--- a/third_party/nix/src/libexpr/get-drvs.cc
+++ b/third_party/nix/src/libexpr/get-drvs.cc
@@ -50,7 +50,7 @@ string DrvInfo::queryName() const {
     if (i == attrs->end()) {
       throw TypeError("derivation name missing");
     }
-    name = state->forceStringNoCtx(*i->value);
+    name = state->forceStringNoCtx(*i->second.value);
   }
   return name;
 }
@@ -58,8 +58,9 @@ string DrvInfo::queryName() const {
 string DrvInfo::querySystem() const {
   if (system.empty() && (attrs != nullptr)) {
     auto i = attrs->find(state->sSystem);
-    system = i == attrs->end() ? "unknown"
-                               : state->forceStringNoCtx(*i->value, *i->pos);
+    system = i == attrs->end()
+                 ? "unknown"
+                 : state->forceStringNoCtx(*i->second.value, *i->second.pos);
   }
   return system;
 }
@@ -68,9 +69,9 @@ string DrvInfo::queryDrvPath() const {
   if (drvPath.empty() && (attrs != nullptr)) {
     Bindings::iterator i = attrs->find(state->sDrvPath);
     PathSet context;
-    drvPath = i != attrs->end()
-                  ? state->coerceToPath(*i->pos, *i->value, context)
-                  : "";
+    drvPath = i != attrs->end() ? state->coerceToPath(*i->second.pos,
+                                                      *i->second.value, context)
+                                : "";
   }
   return drvPath;
 }
@@ -79,9 +80,9 @@ string DrvInfo::queryOutPath() const {
   if (outPath.empty() && (attrs != nullptr)) {
     Bindings::iterator i = attrs->find(state->sOutPath);
     PathSet context;
-    outPath = i != attrs->end()
-                  ? state->coerceToPath(*i->pos, *i->value, context)
-                  : "";
+    outPath = i != attrs->end() ? state->coerceToPath(*i->second.pos,
+                                                      *i->second.value, context)
+                                : "";
   }
   return outPath;
 }
@@ -92,27 +93,28 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) {
     Bindings::iterator i;
     if ((attrs != nullptr) &&
         (i = attrs->find(state->sOutputs)) != attrs->end()) {
-      state->forceList(*i->value, *i->pos);
+      state->forceList(*i->second.value, *i->second.pos);
 
       /* For each output... */
-      for (unsigned int j = 0; j < i->value->listSize(); ++j) {
+      for (unsigned int j = 0; j < i->second.value->listSize(); ++j) {
         /* Evaluate the corresponding set. */
-        std::string name =
-            state->forceStringNoCtx(*i->value->listElems()[j], *i->pos);
+        std::string name = state->forceStringNoCtx(
+            *i->second.value->listElems()[j], *i->second.pos);
         Bindings::iterator out = attrs->find(state->symbols.Create(name));
         if (out == attrs->end()) {
           continue;  // FIXME: throw error?
         }
-        state->forceAttrs(*out->value);
+        state->forceAttrs(*out->second.value);
 
         /* And evaluate its ‘outPath’ attribute. */
-        Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
-        if (outPath == out->value->attrs->end()) {
+        Bindings::iterator outPath =
+            out->second.value->attrs->find(state->sOutPath);
+        if (outPath == out->second.value->attrs->end()) {
           continue;  // FIXME: throw error?
         }
         PathSet context;
-        outputs[name] =
-            state->coerceToPath(*outPath->pos, *outPath->value, context);
+        outputs[name] = state->coerceToPath(*outPath->second.pos,
+                                            *outPath->second.value, context);
       }
     } else {
       outputs["out"] = queryOutPath();
@@ -150,7 +152,8 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) {
 string DrvInfo::queryOutputName() const {
   if (outputName.empty() && (attrs != nullptr)) {
     Bindings::iterator i = attrs->find(state->sOutputName);
-    outputName = i != attrs->end() ? state->forceStringNoCtx(*i->value) : "";
+    outputName =
+        i != attrs->end() ? state->forceStringNoCtx(*i->second.value) : "";
   }
   return outputName;
 }
@@ -166,8 +169,8 @@ Bindings* DrvInfo::getMeta() {
   if (a == attrs->end()) {
     return nullptr;
   }
-  state->forceAttrs(*a->value, *a->pos);
-  meta = a->value->attrs;
+  state->forceAttrs(*a->second.value, *a->second.pos);
+  meta = a->second.value->attrs;
   return meta;
 }
 
@@ -177,7 +180,7 @@ StringSet DrvInfo::queryMetaNames() {
     return res;
   }
   for (auto& i : *meta) {
-    res.insert(i.name);
+    res.insert(i.second.name);
   }
   return res;
 }
@@ -198,7 +201,7 @@ bool DrvInfo::checkMeta(Value& v) {
       return false;
     }
     for (auto& i : *v.attrs) {
-      if (!checkMeta(*i.value)) {
+      if (!checkMeta(*i.second.value)) {
         return false;
       }
     }
@@ -214,10 +217,10 @@ Value* DrvInfo::queryMeta(const std::string& name) {
     return nullptr;
   }
   Bindings::iterator a = meta->find(state->symbols.Create(name));
-  if (a == meta->end() || !checkMeta(*a->value)) {
+  if (a == meta->end() || !checkMeta(*a->second.value)) {
     return nullptr;
   }
-  return a->value;
+  return a->second.value;
 }
 
 string DrvInfo::queryMetaString(const std::string& name) {
@@ -294,8 +297,8 @@ void DrvInfo::setMeta(const std::string& name, Value* v) {
   Symbol sym = state->symbols.Create(name);
   if (old != nullptr) {
     for (auto i : *old) {
-      if (i.name != sym) {
-        meta->push_back(i);
+      if (i.second.name != sym) {
+        meta->push_back(i.second);
       }
     }
   }
@@ -403,7 +406,7 @@ static void getDerivations(EvalState& state, Value& vIn,
           Bindings::iterator j = i->value->attrs->find(
               state.symbols.Create("recurseForDerivations"));
           if (j != i->value->attrs->end() &&
-              state.forceBool(*j->value, *j->pos)) {
+              state.forceBool(*j->second.value, *j->second.pos)) {
             getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done,
                            ignoreAssertionFailures);
           }
diff --git a/third_party/nix/src/libexpr/primops.cc b/third_party/nix/src/libexpr/primops.cc
index 1cbe554968..608d6d0413 100644
--- a/third_party/nix/src/libexpr/primops.cc
+++ b/third_party/nix/src/libexpr/primops.cc
@@ -148,8 +148,8 @@ static void prim_scopedImport(EvalState& state, const Pos& pos, Value** args,
 
       unsigned int displ = 0;
       for (auto& attr : *args[0]->attrs) {
-        staticEnv.vars[attr.name] = displ;
-        env->values[displ++] = attr.value;
+        staticEnv.vars[attr.second.name] = displ;
+        env->values[displ++] = attr.second.value;
       }
 
       DLOG(INFO) << "evaluating file '" << realPath << "'";
@@ -398,11 +398,11 @@ static void prim_genericClosure(EvalState& state, const Pos& pos, Value** args,
   if (startSet == args[0]->attrs->end()) {
     throw EvalError(format("attribute 'startSet' required, at %1%") % pos);
   }
-  state.forceList(*startSet->value, pos);
+  state.forceList(*startSet->second.value, pos);
 
   ValueList workSet;
-  for (unsigned int n = 0; n < startSet->value->listSize(); ++n) {
-    workSet.push_back(startSet->value->listElems()[n]);
+  for (unsigned int n = 0; n < startSet->second.value->listSize(); ++n) {
+    workSet.push_back(startSet->second.value->listElems()[n]);
   }
 
   /* Get the operator. */
@@ -411,7 +411,7 @@ static void prim_genericClosure(EvalState& state, const Pos& pos, Value** args,
   if (op == args[0]->attrs->end()) {
     throw EvalError(format("attribute 'operator' required, at %1%") % pos);
   }
-  state.forceValue(*op->value);
+  state.forceValue(*op->second.value);
 
   /* Construct the closure by applying the operator to element of
      `workSet', adding the result to `workSet', continuing until
@@ -430,17 +430,17 @@ static void prim_genericClosure(EvalState& state, const Pos& pos, Value** args,
     if (key == e->attrs->end()) {
       throw EvalError(format("attribute 'key' required, at %1%") % pos);
     }
-    state.forceValue(*key->value);
+    state.forceValue(*key->second.value);
 
-    if (doneKeys.find(key->value) != doneKeys.end()) {
+    if (doneKeys.find(key->second.value) != doneKeys.end()) {
       continue;
     }
-    doneKeys.insert(key->value);
+    doneKeys.insert(key->second.value);
     res.push_back(e);
 
     /* Call the `operator' function with `e' as argument. */
     Value call;
-    mkApp(call, *op->value, *e);
+    mkApp(call, *op->second.value, *e);
     state.forceList(call, pos);
 
     /* Add the values returned by the operator to the work set. */
@@ -566,9 +566,9 @@ static void prim_derivationStrict(EvalState& state, const Pos& pos,
     throw EvalError(format("required attribute 'name' missing, at %1%") % pos);
   }
   std::string drvName;
-  Pos& posDrvName(*attr->pos);
+  Pos& posDrvName(*attr->second.pos);
   try {
-    drvName = state.forceStringNoCtx(*attr->value, pos);
+    drvName = state.forceStringNoCtx(*attr->second.value, pos);
   } catch (Error& e) {
     e.addPrefix(
         format("while evaluating the derivation attribute 'name' at %1%:\n") %
@@ -580,7 +580,8 @@ static void prim_derivationStrict(EvalState& state, const Pos& pos,
   std::ostringstream jsonBuf;
   std::unique_ptr<JSONObject> jsonObject;
   attr = args[0]->attrs->find(state.sStructuredAttrs);
-  if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos)) {
+  if (attr != args[0]->attrs->end() &&
+      state.forceBool(*attr->second.value, pos)) {
     jsonObject = std::make_unique<JSONObject>(jsonBuf);
   }
 
@@ -588,7 +589,7 @@ static void prim_derivationStrict(EvalState& state, const Pos& pos,
   bool ignoreNulls = false;
   attr = args[0]->attrs->find(state.sIgnoreNulls);
   if (attr != args[0]->attrs->end()) {
-    ignoreNulls = state.forceBool(*attr->value, pos);
+    ignoreNulls = state.forceBool(*attr->second.value, pos);
   }
 
   /* Build the derivation expression by processing the attributes. */
@@ -990,7 +991,7 @@ static void prim_findFile(EvalState& state, const Pos& pos, Value** args,
     std::string prefix;
     Bindings::iterator i = v2.attrs->find(state.symbols.Create("prefix"));
     if (i != v2.attrs->end()) {
-      prefix = state.forceStringNoCtx(*i->value, pos);
+      prefix = state.forceStringNoCtx(*i->second.value, pos);
     }
 
     i = v2.attrs->find(state.symbols.Create("path"));
@@ -1000,7 +1001,7 @@ static void prim_findFile(EvalState& state, const Pos& pos, Value** args,
 
     PathSet context;
     std::string path =
-        state.coerceToString(pos, *i->value, context, false, false);
+        state.coerceToString(pos, *i->second.value, context, false, false);
 
     try {
       state.realiseContext(context);
@@ -1219,29 +1220,30 @@ static void prim_path(EvalState& state, const Pos& pos, Value** args,
   Hash expectedHash;
 
   for (auto& attr : *args[0]->attrs) {
-    const std::string& n(attr.name);
+    const std::string& n(attr.second.name);
     if (n == "path") {
       PathSet context;
-      path = state.coerceToPath(*attr.pos, *attr.value, context);
+      path = state.coerceToPath(*attr.second.pos, *attr.second.value, context);
       if (!context.empty()) {
         throw EvalError(
             format("string '%1%' cannot refer to other paths, at %2%") % path %
-            *attr.pos);
+            *attr.second.pos);
       }
-    } else if (attr.name == state.sName) {
-      name = state.forceStringNoCtx(*attr.value, *attr.pos);
+    } else if (attr.second.name == state.sName) {
+      name = state.forceStringNoCtx(*attr.second.value, *attr.second.pos);
     } else if (n == "filter") {
-      state.forceValue(*attr.value);
-      filterFun = attr.value;
+      state.forceValue(*attr.second.value);
+      filterFun = attr.second.value;
     } else if (n == "recursive") {
-      recursive = state.forceBool(*attr.value, *attr.pos);
+      recursive = state.forceBool(*attr.second.value, *attr.second.pos);
     } else if (n == "sha256") {
       expectedHash =
-          Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
+          Hash(state.forceStringNoCtx(*attr.second.value, *attr.second.pos),
+               htSHA256);
     } else {
       throw EvalError(
           format("unsupported argument '%1%' to 'addPath', at %2%") %
-          attr.name % *attr.pos);
+          attr.second.name % *attr.second.pos);
     }
   }
   if (path.empty()) {
@@ -1268,7 +1270,7 @@ static void prim_attrNames(EvalState& state, const Pos& pos, Value** args,
 
   size_t n = 0;
   for (auto& i : *args[0]->attrs) {
-    mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
+    mkString(*(v.listElems()[n++] = state.allocValue()), i.second.name);
   }
 
   std::sort(v.listElems(), v.listElems() + n, [](Value* v1, Value* v2) {
@@ -1308,11 +1310,11 @@ void prim_getAttr(EvalState& state, const Pos& pos, Value** args, Value& v) {
     throw EvalError(format("attribute '%1%' missing, at %2%") % attr % pos);
   }
   // !!! add to stack trace?
-  if (state.countCalls && (i->pos != nullptr)) {
-    state.attrSelects[*i->pos]++;
+  if (state.countCalls && (i->second.pos != nullptr)) {
+    state.attrSelects[*i->second.pos]++;
   }
-  state.forceValue(*i->value);
-  v = *i->value;
+  state.forceValue(*i->second.value);
+  v = *i->second.value;
 }
 
 /* Return position information of the specified attribute. */
@@ -1324,7 +1326,7 @@ void prim_unsafeGetAttrPos(EvalState& state, const Pos& pos, Value** args,
   if (i == args[1]->attrs->end()) {
     mkNull(v);
   } else {
-    state.mkPos(v, i->pos);
+    state.mkPos(v, i->second.pos);
   }
 }
 
@@ -1361,8 +1363,8 @@ static void prim_removeAttrs(EvalState& state, const Pos& pos, Value** args,
      vector. */
   state.mkAttrs(v, args[0]->attrs->size());
   for (auto& i : *args[0]->attrs) {
-    if (names.find(i.name) == names.end()) {
-      v.attrs->push_back(i);
+    if (names.find(i.second.name) == names.end()) {
+      v.attrs->push_back(i.second);
     }
   }
 }
@@ -1391,7 +1393,7 @@ static void prim_listToAttrs(EvalState& state, const Pos& pos, Value** args,
               "'name' attribute missing in a call to 'listToAttrs', at %1%") %
           pos);
     }
-    std::string name = state.forceStringNoCtx(*j->value, pos);
+    std::string name = state.forceStringNoCtx(*j->second.value, pos);
 
     Symbol sym = state.symbols.Create(name);
     if (seen.find(sym) == seen.end()) {
@@ -1406,7 +1408,7 @@ static void prim_listToAttrs(EvalState& state, const Pos& pos, Value** args,
                         pos);
       }
 
-      v.attrs->push_back(Attr(sym, j2->value, j2->pos));
+      v.attrs->push_back(Attr(sym, j2->second.value, j2->second.pos));
       seen.insert(sym);
     }
   }
@@ -1425,9 +1427,9 @@ static void prim_intersectAttrs(EvalState& state, const Pos& pos, Value** args,
   state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
 
   for (auto& i : *args[0]->attrs) {
-    Bindings::iterator j = args[1]->attrs->find(i.name);
+    Bindings::iterator j = args[1]->attrs->find(i.second.name);
     if (j != args[1]->attrs->end()) {
-      v.attrs->push_back(*j);
+      v.attrs->push_back(j->second);
     }
   }
 }
@@ -1452,7 +1454,7 @@ static void prim_catAttrs(EvalState& state, const Pos& pos, Value** args,
     state.forceAttrs(v2, pos);
     Bindings::iterator i = v2.attrs->find(attrName);
     if (i != v2.attrs->end()) {
-      res[found++] = i->value;
+      res[found++] = i->second.value;
     }
   }
 
@@ -1506,9 +1508,9 @@ static void prim_mapAttrs(EvalState& state, const Pos& pos, Value** args,
   for (auto& i : *args[1]->attrs) {
     Value* vName = state.allocValue();
     Value* vFun2 = state.allocValue();
-    mkString(*vName, i.name);
+    mkString(*vName, i.second.name);
     mkApp(*vFun2, *args[0], *vName);
-    mkApp(*state.allocAttr(v, i.name), *vFun2, *i.value);
+    mkApp(*state.allocAttr(v, i.second.name), *vFun2, *i.second.value);
   }
 }
 
@@ -2198,17 +2200,20 @@ void fetch(EvalState& state, const Pos& pos, Value** args, Value& v,
     state.forceAttrs(*args[0], pos);
 
     for (auto& attr : *args[0]->attrs) {
-      std::string n(attr.name);
+      std::string n(attr.second.name);
       if (n == "url") {
-        request.uri = state.forceStringNoCtx(*attr.value, *attr.pos);
+        request.uri =
+            state.forceStringNoCtx(*attr.second.value, *attr.second.pos);
       } else if (n == "sha256") {
         request.expectedHash =
-            Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
+            Hash(state.forceStringNoCtx(*attr.second.value, *attr.second.pos),
+                 htSHA256);
       } else if (n == "name") {
-        request.name = state.forceStringNoCtx(*attr.value, *attr.pos);
+        request.name =
+            state.forceStringNoCtx(*attr.second.value, *attr.second.pos);
       } else {
         throw EvalError(format("unsupported argument '%1%' to '%2%', at %3%") %
-                        attr.name % who % attr.pos);
+                        attr.second.name % who % attr.second.pos);
       }
     }
 
diff --git a/third_party/nix/src/libexpr/primops/context.cc b/third_party/nix/src/libexpr/primops/context.cc
index efc94d91ce..1661ffbe2e 100644
--- a/third_party/nix/src/libexpr/primops/context.cc
+++ b/third_party/nix/src/libexpr/primops/context.cc
@@ -147,47 +147,48 @@ static void prim_appendContext(EvalState& state, const Pos& pos, Value** args,
 
   auto sPath = state.symbols.Create("path");
   auto sAllOutputs = state.symbols.Create("allOutputs");
-  for (auto& i : *args[1]->attrs) {
-    if (!state.store->isStorePath(i.name))
-      throw EvalError("Context key '%s' is not a store path, at %s", i.name,
-                      i.pos);
+  for (const auto& attr_iter : *args[1]->attrs) {
+    const Attr* i = &attr_iter.second;  // TODO(tazjin): get rid of this
+    if (!state.store->isStorePath(i->name))
+      throw EvalError("Context key '%s' is not a store path, at %s", i->name,
+                      i->pos);
     if (!settings.readOnlyMode) {
-      state.store->ensurePath(i.name);
+      state.store->ensurePath(i->name);
     }
-    state.forceAttrs(*i.value, *i.pos);
-    auto iter = i.value->attrs->find(sPath);
-    if (iter != i.value->attrs->end()) {
-      if (state.forceBool(*iter->value, *iter->pos)) {
-        context.insert(i.name);
+    state.forceAttrs(*i->value, *i->pos);
+    auto iter = i->value->attrs->find(sPath);
+    if (iter != i->value->attrs->end()) {
+      if (state.forceBool(*iter->second.value, *iter->second.pos)) {
+        context.insert(i->name);
       }
     }
 
-    iter = i.value->attrs->find(sAllOutputs);
-    if (iter != i.value->attrs->end()) {
-      if (state.forceBool(*iter->value, *iter->pos)) {
-        if (!isDerivation(i.name)) {
+    iter = i->value->attrs->find(sAllOutputs);
+    if (iter != i->value->attrs->end()) {
+      if (state.forceBool(*iter->second.value, *iter->second.pos)) {
+        if (!isDerivation(i->name)) {
           throw EvalError(
               "Tried to add all-outputs context of %s, which is not a "
               "derivation, to a string, at %s",
-              i.name, i.pos);
+              i->name, i->pos);
         }
-        context.insert("=" + string(i.name));
+        context.insert("=" + string(i->name));
       }
     }
 
-    iter = i.value->attrs->find(state.sOutputs);
-    if (iter != i.value->attrs->end()) {
-      state.forceList(*iter->value, *iter->pos);
-      if (iter->value->listSize() && !isDerivation(i.name)) {
+    iter = i->value->attrs->find(state.sOutputs);
+    if (iter != i->value->attrs->end()) {
+      state.forceList(*iter->second.value, *iter->second.pos);
+      if (iter->second.value->listSize() && !isDerivation(i->name)) {
         throw EvalError(
             "Tried to add derivation output context of %s, which is not a "
             "derivation, to a string, at %s",
-            i.name, i.pos);
+            i->name, i->pos);
       }
-      for (unsigned int n = 0; n < iter->value->listSize(); ++n) {
-        auto name =
-            state.forceStringNoCtx(*iter->value->listElems()[n], *iter->pos);
-        context.insert("!" + name + "!" + string(i.name));
+      for (unsigned int n = 0; n < iter->second.value->listSize(); ++n) {
+        auto name = state.forceStringNoCtx(*iter->second.value->listElems()[n],
+                                           *iter->second.pos);
+        context.insert("!" + name + "!" + string(i->name));
       }
     }
   }
diff --git a/third_party/nix/src/libexpr/primops/fetchGit.cc b/third_party/nix/src/libexpr/primops/fetchGit.cc
index 7ef3dea8ee..cb4c008cdd 100644
--- a/third_party/nix/src/libexpr/primops/fetchGit.cc
+++ b/third_party/nix/src/libexpr/primops/fetchGit.cc
@@ -214,7 +214,8 @@ static void prim_fetchGit(EvalState& state, const Pos& pos, Value** args,
   if (args[0]->type == tAttrs) {
     state.forceAttrs(*args[0], pos);
 
-    for (auto& attr : *args[0]->attrs) {
+    for (auto& attr_iter : *args[0]->attrs) {
+      auto& attr = attr_iter.second;
       std::string n(attr.name);
       if (n == "url")
         url =
diff --git a/third_party/nix/src/libexpr/primops/fetchMercurial.cc b/third_party/nix/src/libexpr/primops/fetchMercurial.cc
index 4205442c73..1e7064f97d 100644
--- a/third_party/nix/src/libexpr/primops/fetchMercurial.cc
+++ b/third_party/nix/src/libexpr/primops/fetchMercurial.cc
@@ -190,7 +190,8 @@ static void prim_fetchMercurial(EvalState& state, const Pos& pos, Value** args,
   if (args[0]->type == tAttrs) {
     state.forceAttrs(*args[0], pos);
 
-    for (auto& attr : *args[0]->attrs) {
+    for (auto& attr_iter : *args[0]->attrs) {
+      auto& attr = attr_iter.second;
       std::string n(attr.name);
       if (n == "url")
         url =
diff --git a/third_party/nix/src/libexpr/value-to-json.cc b/third_party/nix/src/libexpr/value-to-json.cc
index 52ab44083b..0b641a41b5 100644
--- a/third_party/nix/src/libexpr/value-to-json.cc
+++ b/third_party/nix/src/libexpr/value-to-json.cc
@@ -51,15 +51,15 @@ void printValueAsJSON(EvalState& state, bool strict, Value& v,
         auto obj(out.object());
         StringSet names;
         for (auto& j : *v.attrs) {
-          names.insert(j.name);
+          names.insert(j.second.name);
         }
         for (auto& j : names) {
-          Attr& a(*v.attrs->find(state.symbols.Create(j)));
+          auto [_, a] = *v.attrs->find(state.symbols.Create(j));
           auto placeholder(obj.placeholder(j));
           printValueAsJSON(state, strict, *a.value, placeholder, context);
         }
       } else {
-        printValueAsJSON(state, strict, *i->value, out, context);
+        printValueAsJSON(state, strict, *i->second.value, out, context);
       }
       break;
     }
diff --git a/third_party/nix/src/libexpr/value-to-xml.cc b/third_party/nix/src/libexpr/value-to-xml.cc
index d2b5c66f1f..149bf764f0 100644
--- a/third_party/nix/src/libexpr/value-to-xml.cc
+++ b/third_party/nix/src/libexpr/value-to-xml.cc
@@ -31,11 +31,11 @@ static void showAttrs(EvalState& state, bool strict, bool location,
   StringSet names;
 
   for (auto& i : attrs) {
-    names.insert(i.name);
+    names.insert(i.second.name);
   }
 
   for (auto& i : names) {
-    Attr& a(*attrs.find(state.symbols.Create(i)));
+    auto& [_, a] = *attrs.find(state.symbols.Create(i));
 
     XMLAttrs xmlAttrs;
     xmlAttrs["name"] = i;
@@ -43,7 +43,7 @@ static void showAttrs(EvalState& state, bool strict, bool location,
       posToXML(xmlAttrs, *a.pos);
     }
 
-    XMLOpenElement _(doc, "attr", xmlAttrs);
+    XMLOpenElement elem(doc, "attr", xmlAttrs);
     printValueAsXML(state, strict, location, *a.value, doc, context, drvsSeen);
   }
 }
@@ -93,20 +93,20 @@ static void printValueAsXML(EvalState& state, bool strict, bool location,
         a = v.attrs->find(state.sDrvPath);
         if (a != v.attrs->end()) {
           if (strict) {
-            state.forceValue(*a->value);
+            state.forceValue(*a->second.value);
           }
-          if (a->value->type == tString) {
-            xmlAttrs["drvPath"] = drvPath = a->value->string.s;
+          if (a->second.value->type == tString) {
+            xmlAttrs["drvPath"] = drvPath = a->second.value->string.s;
           }
         }
 
         a = v.attrs->find(state.sOutPath);
         if (a != v.attrs->end()) {
           if (strict) {
-            state.forceValue(*a->value);
+            state.forceValue(*a->second.value);
           }
-          if (a->value->type == tString) {
-            xmlAttrs["outPath"] = a->value->string.s;
+          if (a->second.value->type == tString) {
+            xmlAttrs["outPath"] = a->second.value->string.s;
           }
         }
 
diff --git a/third_party/nix/src/nix-env/nix-env.cc b/third_party/nix/src/nix-env/nix-env.cc
index 93a8e4c1ec..a645fa3148 100644
--- a/third_party/nix/src/nix-env/nix-env.cc
+++ b/third_party/nix/src/nix-env/nix-env.cc
@@ -1209,13 +1209,12 @@ static void opQuery(Globals& globals, Strings opFlags, Strings opArgs) {
                   attrs2["type"] = "strings";
                   XMLOpenElement m(xml, "meta", attrs2);
                   Bindings& attrs = *v->attrs;
-                  for (auto& i : attrs) {
-                    Attr& a(*attrs.find(i.name));
+                  for (auto& [name, a] : attrs) {
                     if (a.value->type != tString) {
                       continue;
                     }
                     XMLAttrs attrs3;
-                    attrs3["type"] = i.name;
+                    attrs3["type"] = name;
                     attrs3["value"] = a.value->string.s;
                     xml.writeEmptyElement("string", attrs3);
                   }
diff --git a/third_party/nix/src/nix-env/user-env.cc b/third_party/nix/src/nix-env/user-env.cc
index adff263ff4..21e7d42e88 100644
--- a/third_party/nix/src/nix-env/user-env.cc
+++ b/third_party/nix/src/nix-env/user-env.cc
@@ -129,11 +129,11 @@ bool createUserEnv(EvalState& state, DrvInfos& elems, const Path& profile,
   DLOG(INFO) << "evaluating user environment builder";
   state.forceValue(topLevel);
   PathSet context;
-  Attr& aDrvPath(*topLevel.attrs->find(state.sDrvPath));
+  Attr& aDrvPath(topLevel.attrs->find(state.sDrvPath)->second);
   Path topLevelDrv =
       state.coerceToPath(aDrvPath.pos != nullptr ? *(aDrvPath.pos) : noPos,
                          *(aDrvPath.value), context);
-  Attr& aOutPath(*topLevel.attrs->find(state.sOutPath));
+  Attr& aOutPath(topLevel.attrs->find(state.sOutPath)->second);
   Path topLevelOut =
       state.coerceToPath(aOutPath.pos != nullptr ? *(aOutPath.pos) : noPos,
                          *(aOutPath.value), context);
diff --git a/third_party/nix/src/nix-prefetch-url/nix-prefetch-url.cc b/third_party/nix/src/nix-prefetch-url/nix-prefetch-url.cc
index 17341e382d..fa88dc9bc6 100644
--- a/third_party/nix/src/nix-prefetch-url/nix-prefetch-url.cc
+++ b/third_party/nix/src/nix-prefetch-url/nix-prefetch-url.cc
@@ -43,13 +43,13 @@ string resolveMirrorUri(EvalState& state, string uri) {
   if (mirrorList == vMirrors.attrs->end()) {
     throw Error(format("unknown mirror name '%1%'") % mirrorName);
   }
-  state.forceList(*mirrorList->value);
+  state.forceList(*mirrorList->second.value);
 
-  if (mirrorList->value->listSize() < 1) {
+  if (mirrorList->second.value->listSize() < 1) {
     throw Error(format("mirror URI '%1%' did not expand to anything") % uri);
   }
 
-  string mirror = state.forceString(*mirrorList->value->listElems()[0]);
+  string mirror = state.forceString(*mirrorList->second.value->listElems()[0]);
   return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
 }
 
@@ -130,25 +130,25 @@ static int _main(int argc, char** argv) {
       if (attr == v.attrs->end()) {
         throw Error("attribute set does not contain a 'urls' attribute");
       }
-      state->forceList(*attr->value);
-      if (attr->value->listSize() < 1) {
+      state->forceList(*attr->second.value);
+      if (attr->second.value->listSize() < 1) {
         throw Error("'urls' list is empty");
       }
-      uri = state->forceString(*attr->value->listElems()[0]);
+      uri = state->forceString(*attr->second.value->listElems()[0]);
 
       /* Extract the hash mode. */
       attr = v.attrs->find(state->symbols.Create("outputHashMode"));
       if (attr == v.attrs->end()) {
         LOG(WARNING) << "this does not look like a fetchurl call";
       } else {
-        unpack = state->forceString(*attr->value) == "recursive";
+        unpack = state->forceString(*attr->second.value) == "recursive";
       }
 
       /* Extract the name. */
       if (name.empty()) {
         attr = v.attrs->find(state->symbols.Create("name"));
         if (attr != v.attrs->end()) {
-          name = state->forceString(*attr->value);
+          name = state->forceString(*attr->second.value);
         }
       }
     }
diff --git a/third_party/nix/src/nix/repl.cc b/third_party/nix/src/nix/repl.cc
index e60ef89652..87caf9dd3f 100644
--- a/third_party/nix/src/nix/repl.cc
+++ b/third_party/nix/src/nix/repl.cc
@@ -385,7 +385,7 @@ StringSet NixRepl::completePrefix(const string& prefix) {
       state.forceAttrs(v);
 
       for (auto& i : *v.attrs) {
-        string name = i.name;
+        string name = i.second.name;
         if (string(name, 0, cur2.size()) != cur2) {
           continue;
         }
@@ -627,7 +627,7 @@ void NixRepl::reloadFiles() {
 void NixRepl::addAttrsToScope(Value& attrs) {
   state.forceAttrs(attrs);
   for (auto& i : *attrs.attrs) {
-    addVarToScope(i.name, *i.value);
+    addVarToScope(i.second.name, *i.second.value);
   }
   std::cout << format("Added %1% variables.") % attrs.attrs->size()
             << std::endl;
@@ -718,9 +718,10 @@ std::ostream& NixRepl::printValue(std::ostream& str, Value& v,
         str << "«derivation ";
         Bindings::iterator i = v.attrs->find(state.sDrvPath);
         PathSet context;
-        Path drvPath = i != v.attrs->end()
-                           ? state.coerceToPath(*i->pos, *i->value, context)
-                           : "???";
+        Path drvPath =
+            i != v.attrs->end()
+                ? state.coerceToPath(*i->second.pos, *i->second.value, context)
+                : "???";
         str << drvPath << "»";
       }
 
@@ -730,7 +731,7 @@ std::ostream& NixRepl::printValue(std::ostream& str, Value& v,
         typedef std::map<string, Value*> Sorted;
         Sorted sorted;
         for (auto& i : *v.attrs) {
-          sorted[i.name] = i.value;
+          sorted[i.second.name] = i.second.value;
         }
 
         for (auto& i : sorted) {
diff --git a/third_party/nix/src/nix/search.cc b/third_party/nix/src/nix/search.cc
index 169daf7a32..97c5122d60 100644
--- a/third_party/nix/src/nix/search.cc
+++ b/third_party/nix/src/nix/search.cc
@@ -175,7 +175,8 @@ struct CmdSearch : SourceExprCommand, MixJSON {
           if (!toplevel) {
             auto attrs = v->attrs;
             Bindings::iterator j = attrs->find(sRecurse);
-            if (j == attrs->end() || !state->forceBool(*j->value, *j->pos)) {
+            if (j == attrs->end() ||
+                !state->forceBool(*j->second.value, *j->second.pos)) {
               DLOG(INFO) << "skip attribute '" << attrPath << "'";
               return;
             }
@@ -184,18 +185,19 @@ struct CmdSearch : SourceExprCommand, MixJSON {
           bool toplevel2 = false;
           if (!fromCache) {
             Bindings::iterator j = v->attrs->find(sToplevel);
-            toplevel2 =
-                j != v->attrs->end() && state->forceBool(*j->value, *j->pos);
+            toplevel2 = j != v->attrs->end() &&
+                        state->forceBool(*j->second.value, *j->second.pos);
           }
 
           for (auto& i : *v->attrs) {
             auto cache2 =
                 cache != nullptr
-                    ? std::make_unique<JSONObject>(cache->object(i.name))
+                    ? std::make_unique<JSONObject>(cache->object(i.second.name))
                     : nullptr;
-            doExpr(i.value,
-                   attrPath.empty() ? (std::string)i.name
-                                    : attrPath + "." + (std::string)i.name,
+            doExpr(i.second.value,
+                   attrPath.empty()
+                       ? (std::string)i.second.name
+                       : attrPath + "." + (std::string)i.second.name,
                    toplevel2 || fromCache, cache2 ? cache2.get() : nullptr);
           }
         }