1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-06 05:01:48 +02:00

Add a ListBuilder helper for constructing list values

Previously, `state.mkList()` would set the type of the value to tList
and allocate the list vector, but it would not initialize the values
in the list. This has two problems:

* If an exception occurs, the list is left in an undefined state.

* More importantly, for multithreaded evaluation, if a value
  transitions from thunk to non-thunk, it should be final (i.e. other
  threads should be able to access the value safely).

To address this, there now is a `ListBuilder` class (analogous to
`BindingsBuilder`) to build the list vector prior to the call to
`Value::mkList()`. Typical usage:

   auto list = state.buildList(size);
   for (auto & v : list)
       v = ... set value ...;
   vRes.mkList(list);
This commit is contained in:
Eelco Dolstra 2024-03-14 19:10:31 +01:00
parent bff5c94184
commit fecff520d7
10 changed files with 228 additions and 157 deletions

View file

@ -172,7 +172,7 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v
directory). */
else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.buildBindings(maxAttrs);
state.mkList(attrs.alloc("_combineChannels"), 0);
attrs.insert(state.symbols.create("_combineChannels"), &state.vEmptyList);
StringSet seen;
getAllExprs(state, path, seen, attrs);
v.mkAttrs(attrs);

View file

@ -49,10 +49,8 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
/* Construct the whole top level derivation. */
StorePathSet references;
Value manifest;
state.mkList(manifest, elems.size());
size_t n = 0;
for (auto & i : elems) {
auto list = state.buildList(elems.size());
for (const auto & [n, i] : enumerate(elems)) {
/* Create a pseudo-derivation containing the name, system,
output paths, and optionally the derivation path, as well
as the meta attributes. */
@ -72,10 +70,9 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
// Copy each output meant for installation.
auto & vOutputs = attrs.alloc(state.sOutputs);
state.mkList(vOutputs, outputs.size());
auto outputsList = state.buildList(outputs.size());
for (const auto & [m, j] : enumerate(outputs)) {
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
(outputsList[m] = state.allocValue())->mkString(j.first);
auto outputAttrs = state.buildBindings(2);
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
attrs.alloc(j.first).mkAttrs(outputAttrs);
@ -87,6 +84,7 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
references.insert(*j.second);
}
attrs.alloc(state.sOutputs).mkList(outputsList);
// Copy the meta attributes.
auto meta = state.buildBindings(metaNames.size());
@ -98,11 +96,14 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
attrs.alloc(state.sMeta).mkAttrs(meta);
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
(list[n] = state.allocValue())->mkAttrs(attrs);
if (drvPath) references.insert(*drvPath);
}
Value manifest;
manifest.mkList(list);
/* Also write a copy of the list of user environment elements to
the store; we need it for future modifications of the
environment. */