libexpr: replace BindingsBuilder::alloc with insert

Progress towards #744
`alloc` default constructed a `Value` which is a problem because the
defaut constructor of `Value` is deprecated

Change-Id: I789cba20bd98728758395080a3a9cf6e6a6a6964
This commit is contained in:
skye
2026-03-17 15:48:12 -04:00
parent f0891b440f
commit 810a3bad11
12 changed files with 107 additions and 116 deletions
+1 -1
View File
@@ -213,7 +213,7 @@ static int main_nix_build(AsyncIoRoot & aio, std::string programName, Strings ar
auto autoArgsWithInNixShell = autoArgs;
if (runEnv) {
auto newArgs = evaluator->buildBindings(autoArgsWithInNixShell->size() + 1);
newArgs.alloc("inNixShell") = {NewValueAs::boolean, true};
newArgs.insert("inNixShell", {NewValueAs::boolean, true});
for (auto & i : *autoArgs) newArgs.insert(i);
autoArgsWithInNixShell = newArgs.finish();
}
+2 -3
View File
@@ -154,8 +154,7 @@ static void getAllExprs(Evaluator & state,
Value vArg = {NewValueAs::string, path2.canonical().abs()};
if (seen.size() == maxAttrs)
throw Error("too many Nix expressions in directory '%1%'", path);
attrs.alloc(attrName
) = {NewValueAs::app, state.mem, state.builtins.get("import"), vArg};
attrs.insert(attrName, {NewValueAs::app, state.mem, state.builtins.get("import"), vArg});
}
else if (st.type == InputAccessor::tDirectory)
/* `path2' is a directory (with no default.nix in it);
@@ -180,7 +179,7 @@ static Value loadSourceExpr(EvalState & state, const SourcePath & path_)
directory). */
else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.ctx.buildBindings(maxAttrs);
attrs.alloc("_combineChannels") = Value::EMPTY_LIST;
attrs.insert("_combineChannels", Value::EMPTY_LIST);
StringSet seen;
getAllExprs(state.ctx, path, seen, attrs);
return {NewValueAs::attrs, attrs};
+18 -17
View File
@@ -46,30 +46,31 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
auto attrs = state.ctx.buildBindings(7 + outputs.size());
attrs.alloc(state.ctx.symbols.sym_type) = {NewValueAs::string, "derivation"};
attrs.alloc(state.ctx.symbols.sym_name) = {NewValueAs::string, i.queryName(state)};
attrs.insert(state.ctx.symbols.sym_type, {NewValueAs::string, "derivation"});
attrs.insert(state.ctx.symbols.sym_name, {NewValueAs::string, i.queryName(state)});
auto system = i.querySystem(state);
if (!system.empty())
attrs.alloc(state.ctx.symbols.sym_system) = {NewValueAs::string, system};
attrs.alloc(state.ctx.symbols.sym_outPath) = {
NewValueAs::string, state.ctx.store->printStorePath(i.queryOutPath(state))
};
attrs.insert(state.ctx.symbols.sym_system, {NewValueAs::string, system});
attrs.insert(
state.ctx.symbols.sym_outPath,
{NewValueAs::string, state.ctx.store->printStorePath(i.queryOutPath(state))}
);
if (drvPath)
attrs.alloc(state.ctx.symbols.sym_drvPath) = {
NewValueAs::string, state.ctx.store->printStorePath(*drvPath)
};
attrs.insert(
state.ctx.symbols.sym_drvPath, {NewValueAs::string, state.ctx.store->printStorePath(*drvPath)}
);
// Copy each output meant for installation.
auto & vOutputs = attrs.alloc(state.ctx.symbols.sym_outputs);
auto outputsList = state.ctx.mem.newList(outputs.size());
vOutputs = {NewValueAs::list, outputsList};
attrs.insert(state.ctx.symbols.sym_outputs, {NewValueAs::list, outputsList});
for (const auto & [m, j] : enumerate(outputs)) {
outputsList->elems[m] = {NewValueAs::string, j.first};
auto outputAttrs = state.ctx.buildBindings(2);
outputAttrs.alloc(state.ctx.symbols.sym_outPath) = {
NewValueAs::string, state.ctx.store->printStorePath(*j.second)
};
attrs.alloc(j.first) = {NewValueAs::attrs, outputAttrs};
outputAttrs.insert(
state.ctx.symbols.sym_outPath,
{NewValueAs::string, state.ctx.store->printStorePath(*j.second)}
);
attrs.insert(j.first, {NewValueAs::attrs, outputAttrs});
/* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */
@@ -87,7 +88,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
meta.insert(state.ctx.symbols.create(j), *v);
}
attrs.alloc(state.ctx.symbols.sym_meta) = {NewValueAs::attrs, meta};
attrs.insert(state.ctx.symbols.sym_meta, {NewValueAs::attrs, meta});
manifest->elems[n++] = {NewValueAs::attrs, attrs};
@@ -111,7 +112,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* Construct a Nix expression that calls the user environment
builder with the manifest as argument. */
auto attrs = state.ctx.buildBindings(3);
attrs.alloc("manifest") = state.ctx.paths.mkStorePathString(manifestFile);
attrs.insert("manifest", state.ctx.paths.mkStorePathString(manifestFile));
attrs.insert(state.ctx.symbols.create("derivations"), vManifest);
Value args = {NewValueAs::attrs, attrs};
+2 -11
View File
@@ -23,20 +23,11 @@ Bindings * EvalMemory::allocBindings(size_t capacity)
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings();
}
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
void BindingsBuilder::insert(std::string_view name, Value value, PosIdx pos)
{
bindings->push_back(Attr(name, {}, pos));
return (bindings->end() - 1)->value;
return insert(symbols.create(name), value, pos);
}
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
{
return alloc(symbols.create(name), pos);
}
void Bindings::sort()
{
if (size_) std::sort(begin(), end());
+2 -4
View File
@@ -140,6 +140,8 @@ public:
insert(Attr(name, value, pos));
}
void insert(std::string_view name, Value value, PosIdx pos = noPos);
void insert(const Attr & attr)
{
push_back(attr);
@@ -151,10 +153,6 @@ public:
bindings->push_back(attr);
}
Value & alloc(Symbol name, PosIdx pos = noPos);
Value & alloc(std::string_view name, PosIdx pos = noPos);
[[nodiscard("must use created bindings")]]
Bindings * finish()
{
+4 -4
View File
@@ -856,10 +856,10 @@ void EvalState::mkPos(Value & v, PosIdx p)
auto origin = ctx.positions.originOf(p);
if (auto path = std::get_if<CheckedSourcePath>(&origin)) {
auto attrs = ctx.buildBindings(3);
attrs.alloc(ctx.symbols.sym_file) = {NewValueAs::string, path->to_string()};
Value & line = attrs.alloc(ctx.symbols.sym_line);
Value & col = attrs.alloc(ctx.symbols.sym_column);
std::tie(line, col) = makePositionThunks(*this, p);
attrs.insert(ctx.symbols.sym_file, {NewValueAs::string, path->to_string()});
auto [line, col] = makePositionThunks(*this, p);
attrs.insert(ctx.symbols.sym_line, line);
attrs.insert(ctx.symbols.sym_column, col);
v = {NewValueAs::attrs, attrs};
} else
v = Value::VNULL;
+5 -5
View File
@@ -1003,15 +1003,15 @@ void prim_parseFlakeRef(
auto binds = state.ctx.buildBindings(attrs.size());
for (const auto & [key, value] : attrs) {
auto s = state.ctx.symbols.create(key);
auto & vv = binds.alloc(s);
std::visit(
Value vv = std::visit(
overloaded{
[&vv](const std::string & value) { vv = {NewValueAs::string, value}; },
[&vv](const uint64_t & value) { vv = {NewValueAs::integer, NixInt::Inner(value)}; },
[&vv](const Explicit<bool> & value) { vv = {NewValueAs::boolean, value.t}; }
[](const std::string & value) -> Value { return {NewValueAs::string, value}; },
[](const uint64_t & value) -> Value { return {NewValueAs::integer, NixInt::Inner(value)}; },
[](const Explicit<bool> & value) -> Value { return {NewValueAs::boolean, value.t}; }
},
value
);
binds.insert(s, vv);
}
v = {NewValueAs::attrs, binds};
}
+31 -30
View File
@@ -159,12 +159,15 @@ static void mkOutputString(
const StorePath & drvPath,
const std::pair<std::string, DerivationOutput> & o)
{
attrs.alloc(o.first) = state.mkOutputString(
attrs.insert(
o.first,
state.mkOutputString(
SingleDerivedPath::Built{
.drvPath = makeConstantStorePath(drvPath),
.output = o.first,
},
o.second.path(*state.ctx.store, Derivation::nameFromPath(drvPath), o.first)
)
);
}
@@ -188,17 +191,17 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v)
if (auto storePath = isValidDerivationInStore()) {
Derivation drv = state.aio.blockOn(state.ctx.store->readDerivation(*storePath));
auto attrs = state.ctx.buildBindings(3 + drv.outputs.size());
attrs.alloc(state.ctx.symbols.sym_drvPath) = {
NewValueAs::string,
attrs.insert(
state.ctx.symbols.sym_drvPath,
{NewValueAs::string,
path2,
{
NixStringContextElem::DrvDeep{.drvPath = *storePath},
}
};
attrs.alloc(state.ctx.symbols.sym_name) = {NewValueAs::string, drv.env["name"]};
auto & outputsVal = attrs.alloc(state.ctx.symbols.sym_outputs);
}}
);
attrs.insert(state.ctx.symbols.sym_name, {NewValueAs::string, drv.env["name"]});
auto outputsList = state.ctx.mem.newList(drv.outputs.size());
outputsVal = {NewValueAs::list, outputsList};
attrs.insert(state.ctx.symbols.sym_outputs, {NewValueAs::list, outputsList});
for (const auto & [i, o] : enumerate(drv.outputs)) {
mkOutputString(state, attrs, *storePath, o);
@@ -733,8 +736,8 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v)
if (success)
attrs.insert(state.ctx.symbols.sym_value, *args[0]);
else
attrs.alloc(state.ctx.symbols.sym_value) = {NewValueAs::boolean, false};
attrs.alloc("success") = {NewValueAs::boolean, success};
attrs.insert(state.ctx.symbols.sym_value, {NewValueAs::boolean, false});
attrs.insert("success", {NewValueAs::boolean, success});
v = {NewValueAs::attrs, attrs};
}
@@ -1272,13 +1275,14 @@ drvName, Bindings * attrs, Value & v)
}
auto result = state.ctx.buildBindings(1 + drv.outputs.size());
result.alloc(state.ctx.symbols.sym_drvPath) = {
NewValueAs::string,
result.insert(
state.ctx.symbols.sym_drvPath,
{NewValueAs::string,
drvPathS,
{
NixStringContextElem::DrvDeep{.drvPath = drvPath},
}
};
}}
);
for (auto & i : drv.outputs)
mkOutputString(state, result, drvPath, i);
@@ -1564,7 +1568,6 @@ static void prim_readDir(EvalState & state, Value * * args, Value & v)
Value * readFileType = nullptr;
for (auto & [name, type] : entries) {
auto & attr = attrs.alloc(name);
if (!type) {
// Some filesystems or operating systems may not be able to return
// detailed node info quickly in this case we produce a thunk to
@@ -1572,11 +1575,13 @@ static void prim_readDir(EvalState & state, Value * * args, Value & v)
Value epath = {NewValueAs::path, path + name};
if (!readFileType)
readFileType = &state.ctx.builtins.get("readFileType");
attr = {NewValueAs::app, state.ctx.mem, *readFileType, epath};
Value attr = {NewValueAs::app, state.ctx.mem, *readFileType, epath};
attrs.insert(name, attr);
} else {
// This branch of the conditional is much more likely.
// Here we just stringize the directory entry type.
attr = {NewValueAs::string, fileTypeToString(*type)};
Value attr = {NewValueAs::string, fileTypeToString(*type)};
attrs.insert(name, attr);
}
}
@@ -2144,8 +2149,7 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v)
auto attrs = state.ctx.buildBindings(formals->formals.size());
for (auto & i : formals->formals)
// !!! should optimise booleans (allocate only once)
attrs.alloc(i.name, i.pos) = {NewValueAs::boolean, i.def != nullptr};
attrs.insert(i.name, {NewValueAs::boolean, i.def != nullptr}, i.pos);
v = {NewValueAs::attrs, attrs};
}
@@ -2159,7 +2163,7 @@ static void prim_mapAttrs(EvalState & state, Value * * args, Value & v)
for (auto & i : *args[1]->attrs()) {
auto vName = state.ctx.symbols[i.name].toValue();
Value appArgs[] = {vName, i.value};
attrs.alloc(i.name) = {NewValueAs::app, state.ctx.mem, *args[0], appArgs};
attrs.insert(i.name, {NewValueAs::app, state.ctx.mem, *args[0], appArgs});
}
v = {NewValueAs::attrs, attrs.alreadySorted()};
@@ -2511,18 +2515,16 @@ static void prim_partition(EvalState & state, Value * * args, Value & v)
auto attrs = state.ctx.buildBindings(2);
auto & vRight = attrs.alloc(state.ctx.symbols.sym_right);
auto rsize = right.size();
auto rlist = state.ctx.mem.newList(rsize);
vRight = {NewValueAs::list, rlist};
attrs.insert(state.ctx.symbols.sym_right, {NewValueAs::list, rlist});
for (auto [i, idx] : enumerate(right)) {
rlist->elems[i] = elems[idx];
}
auto & vWrong = attrs.alloc(state.ctx.symbols.sym_wrong);
auto wsize = wrong.size();
auto wlist = state.ctx.mem.newList(wsize);
vWrong = {NewValueAs::list, wlist};
attrs.insert(state.ctx.symbols.sym_wrong, {NewValueAs::list, wlist});
for (auto [i, idx] : enumerate(wrong)) {
wlist->elems[i] = elems[idx];
}
@@ -2550,10 +2552,9 @@ static void prim_groupBy(EvalState & state, Value * * args, Value & v)
auto attrs2 = state.ctx.buildBindings(attrs.size());
for (auto & i : attrs) {
auto & list = attrs2.alloc(i.first);
auto size = i.second.size();
auto content = state.ctx.mem.newList(size);
list = {NewValueAs::list, content};
attrs2.insert(i.first, {NewValueAs::list, content});
for (auto [i, idx] : enumerate(i.second)) {
content->elems[i] = elems[idx];
}
@@ -3040,8 +3041,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v)
auto name = state.forceStringNoCtx(*args[0], noPos, "while evaluating the first argument passed to builtins.parseDrvName");
DrvName parsed(name);
auto attrs = state.ctx.buildBindings(2);
attrs.alloc(state.ctx.symbols.sym_name) = {NewValueAs::string, parsed.name};
attrs.alloc("version") = {NewValueAs::string, parsed.version};
attrs.insert(state.ctx.symbols.sym_name, {NewValueAs::string, parsed.name});
attrs.insert("version", {NewValueAs::string, parsed.version});
v = {NewValueAs::attrs, attrs};
}
@@ -3090,8 +3091,8 @@ Value EvalBuiltins::prepareNixPath(const SearchPath & searchPath)
int n = 0;
for (auto & i : searchPath.elements) {
auto attrs = mem.buildBindings(symbols, 2);
attrs.alloc("path") = {NewValueAs::string, i.path.s};
attrs.alloc("prefix") = {NewValueAs::string, i.prefix.s};
attrs.insert("path", {NewValueAs::string, i.path.s});
attrs.insert("prefix", {NewValueAs::string, i.prefix.s});
v->elems[n++] = {NewValueAs::attrs, attrs};
}
return {NewValueAs::list, v};
+4 -5
View File
@@ -136,17 +136,16 @@ void prim_getContext(EvalState & state, Value * * args, Value & v)
for (const auto & info : contextInfos) {
auto infoAttrs = state.ctx.buildBindings(3);
if (info.second.path)
infoAttrs.alloc(state.ctx.symbols.sym_path) = {NewValueAs::boolean, true};
infoAttrs.insert(state.ctx.symbols.sym_path, {NewValueAs::boolean, true});
if (info.second.allOutputs)
infoAttrs.alloc(sAllOutputs) = {NewValueAs::boolean, true};
infoAttrs.insert(sAllOutputs, {NewValueAs::boolean, true});
if (!info.second.outputs.empty()) {
auto & outputsVal = infoAttrs.alloc(state.ctx.symbols.sym_outputs);
auto content = state.ctx.mem.newList(info.second.outputs.size());
outputsVal = {NewValueAs::list, content};
infoAttrs.insert(state.ctx.symbols.sym_outputs, {NewValueAs::list, content});
for (const auto & [i, output] : enumerate(info.second.outputs))
content->elems[i] = {NewValueAs::string, output};
}
attrs.alloc(state.ctx.store->printStorePath(info.first)) = {NewValueAs::attrs, infoAttrs};
attrs.insert(state.ctx.store->printStorePath(info.first), {NewValueAs::attrs, infoAttrs});
}
v = {NewValueAs::attrs, attrs};
+5 -5
View File
@@ -88,16 +88,16 @@ void prim_fetchMercurial(EvalState & state, Value ** args, Value & v)
auto [tree, input2] = state.aio.blockOn(input.fetch(state.ctx.store));
auto attrs2 = state.ctx.buildBindings(8);
attrs2.alloc(state.ctx.symbols.sym_outPath) = state.ctx.paths.mkStorePathString(tree.storePath);
attrs2.insert(state.ctx.symbols.sym_outPath, state.ctx.paths.mkStorePathString(tree.storePath));
if (input2.getRef())
attrs2.alloc("branch") = {NewValueAs::string, *input2.getRef()};
attrs2.insert("branch", {NewValueAs::string, *input2.getRef()});
// Backward compatibility: set 'rev' to
// 0000000000000000000000000000000000000000 for a dirty tree.
auto rev2 = input2.getRev().value_or(Hash(HashType::SHA1));
attrs2.alloc("rev") = {NewValueAs::string, rev2.gitRev()};
attrs2.alloc("shortRev") = {NewValueAs::string, rev2.gitRev().substr(0, 12)};
attrs2.insert("rev", {NewValueAs::string, rev2.gitRev()});
attrs2.insert("shortRev", {NewValueAs::string, rev2.gitRev().substr(0, 12)});
if (auto revCount = input2.getRevCount())
attrs2.alloc("revCount") = {NewValueAs::integer, NixInt::Inner(*revCount)};
attrs2.insert("revCount", {NewValueAs::integer, NixInt::Inner(*revCount)});
v = {NewValueAs::attrs, attrs2};
state.ctx.paths.allowPath(tree.storePath);
+21 -19
View File
@@ -26,49 +26,51 @@ Value emitTreeAttrs(
auto attrs = state.buildBindings(10);
attrs.alloc(state.symbols.sym_outPath) = state.paths.mkStorePathString(tree.storePath);
attrs.insert(state.symbols.sym_outPath, state.paths.mkStorePathString(tree.storePath));
// FIXME: support arbitrary input attributes.
auto narHash = input.getNarHash();
assert(narHash);
attrs.alloc("narHash") = {NewValueAs::string, narHash->to_string()};
attrs.insert("narHash", {NewValueAs::string, narHash->to_string()});
if (input.getType() == "git")
attrs.alloc("submodules") = {
NewValueAs::boolean, fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false)
};
attrs.insert(
"submodules",
{NewValueAs::boolean, fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false)}
);
if (!forceDirty) {
if (auto rev = input.getRev()) {
attrs.alloc("rev") = {NewValueAs::string, rev->gitRev()};
attrs.alloc("shortRev") = {NewValueAs::string, rev->gitShortRev()};
attrs.insert("rev", {NewValueAs::string, rev->gitRev()});
attrs.insert("shortRev", {NewValueAs::string, rev->gitShortRev()});
} else if (emptyRevFallback) {
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
auto emptyHash = Hash(HashType::SHA1);
attrs.alloc("rev") = {NewValueAs::string, emptyHash.gitRev()};
attrs.alloc("shortRev") = {NewValueAs::string, emptyHash.gitShortRev()};
attrs.insert("rev", {NewValueAs::string, emptyHash.gitRev()});
attrs.insert("shortRev", {NewValueAs::string, emptyHash.gitShortRev()});
}
if (auto revCount = input.getRevCount())
attrs.alloc("revCount") = {NewValueAs::integer, NixInt::Inner(*revCount)};
attrs.insert("revCount", {NewValueAs::integer, NixInt::Inner(*revCount)});
else if (emptyRevFallback)
attrs.alloc("revCount") = {NewValueAs::integer, 0};
attrs.insert("revCount", {NewValueAs::integer, 0});
}
if (auto dirtyRev = fetchers::maybeGetStrAttr(input.attrs, "dirtyRev")) {
attrs.alloc("dirtyRev") = {NewValueAs::string, *dirtyRev};
attrs.alloc("dirtyShortRev") = {
NewValueAs::string, *fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev")
};
attrs.insert("dirtyRev", {NewValueAs::string, *dirtyRev});
attrs.insert(
"dirtyShortRev", {NewValueAs::string, *fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev")}
);
}
if (auto lastModified = input.getLastModified()) {
attrs.alloc("lastModified") = {NewValueAs::integer, *lastModified};
attrs.alloc("lastModifiedDate") = {
NewValueAs::string, fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S"))
};
attrs.insert("lastModified", {NewValueAs::integer, *lastModified});
attrs.insert(
"lastModifiedDate",
{NewValueAs::string, fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S"))}
);
}
return {NewValueAs::attrs, attrs};
+1 -1
View File
@@ -22,7 +22,7 @@ void prim_fromTOML(EvalState & state, Value ** args, Value & val)
auto attrs = state.ctx.buildBindings(table.size());
for (auto & elem : table) {
attrs.alloc(elem.first) = self(elem.second);
attrs.insert(elem.first, self(elem.second));
}
return {NewValueAs::attrs, attrs};