diff --git a/lix/legacy/nix-env.cc b/lix/legacy/nix-env.cc index 0cbfecbe1..a7a91e103 100644 --- a/lix/legacy/nix-env.cc +++ b/lix/legacy/nix-env.cc @@ -151,12 +151,12 @@ static void getAllExprs(Evaluator & state, continue; } /* Load the expression on demand. */ - auto vArg = state.mem.allocValue(); - vArg->mkString(path2.canonical().abs()); + Value vArg; + vArg.mkString(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}; + ) = {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); @@ -517,9 +517,9 @@ static bool keep(EvalState & state, DrvInfo & drv) static void setMetaFlag(EvalState & state, DrvInfo & drv, const std::string & name, const std::string & value) { - auto v = state.ctx.mem.allocValue(); - v->mkString(value); - drv.setMeta(state, name, *v); + Value v; + v.mkString(value); + drv.setMeta(state, name, v); } static void installDerivations(Globals & globals, @@ -1290,12 +1290,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) } else if (v->type() == nList) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); - for (auto elem : v->listItems()) { - if (elem->type() != nString) { + for (auto & elem : v->listItems()) { + if (elem.type() != nString) { continue; } XMLAttrs attrs3; - attrs3["value"] = elem->str(); + attrs3["value"] = elem.str(); xml.writeEmptyElement("string", attrs3); } } else if (v->type() == nAttrs) { @@ -1304,12 +1304,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) Bindings & attrs = *v->attrs(); for (auto &i : attrs) { const Attr & a(*attrs.get(i.name)); - if (a.value->type() != nString) { + if (a.value.type() != nString) { continue; } XMLAttrs attrs3; attrs3["type"] = globals.state->symbols[i.name]; - attrs3["value"] = a.value->str(); + attrs3["value"] = a.value.str(); xml.writeEmptyElement("string", attrs3); } } diff --git a/lix/legacy/user-env.cc b/lix/legacy/user-env.cc index 5a8d84350..95a8621ea 100644 --- a/lix/legacy/user-env.cc +++ b/lix/legacy/user-env.cc @@ -60,7 +60,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, auto outputsList = state.ctx.mem.newList(outputs.size()); vOutputs = {NewValueAs::list, outputsList}; for (const auto & [m, j] : enumerate(outputs)) { - (outputsList->elems[m] = state.ctx.mem.allocValue())->mkString(j.first); + outputsList->elems[m].mkString(j.first); auto outputAttrs = state.ctx.buildBindings(2); outputAttrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(*j.second)); attrs.alloc(j.first).mkAttrs(outputAttrs); @@ -78,12 +78,12 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, for (auto & j : metaNames) { Value * v = i.queryMeta(state, j); if (!v) continue; - meta.insert(state.ctx.symbols.create(j), v); + meta.insert(state.ctx.symbols.create(j), *v); } attrs.alloc(state.ctx.s.meta).mkAttrs(meta); - (manifest->elems[n++] = state.ctx.mem.allocValue())->mkAttrs(attrs); + manifest->elems[n++].mkAttrs(attrs); if (drvPath) references.insert(*drvPath); } @@ -106,7 +106,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, builder with the manifest as argument. */ auto attrs = state.ctx.buildBindings(3); state.ctx.paths.mkStorePathString(manifestFile, attrs.alloc("manifest")); - attrs.insert(state.ctx.symbols.create("derivations"), &vManifest); + attrs.insert(state.ctx.symbols.create("derivations"), vManifest); Value args; args.mkAttrs(attrs); @@ -117,9 +117,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, state.forceValue(topLevel, noPos); NixStringContext context; const Attr & aDrvPath(*topLevel.attrs()->get(state.ctx.s.drvPath)); - auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, ""); + auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, aDrvPath.value, context, ""); const Attr & aOutPath(*topLevel.attrs()->get(state.ctx.s.outPath)); - auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, ""); + auto topLevelOut = state.coerceToStorePath(aOutPath.pos, aOutPath.value, context, ""); /* Realise the resulting store expression. */ debug("building user environment"); diff --git a/lix/libcmd/common-eval-args.cc b/lix/libcmd/common-eval-args.cc index 2af059edf..4eff8f904 100644 --- a/lix/libcmd/common-eval-args.cc +++ b/lix/libcmd/common-eval-args.cc @@ -183,13 +183,13 @@ Bindings * MixEvalArgs::getAutoArgs(Evaluator & state) { auto res = state.buildBindings(autoArgs.size()); for (auto & i : autoArgs) { - auto v = state.mem.allocValue(); + Value v; if (i.second[0] == 'E') state.evalLazily( - state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), *v + state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), v ); else - v->mkString(((std::string_view) i.second).substr(1)); + v.mkString(((std::string_view) i.second).substr(1)); res.insert(state.symbols.create(i.first), v); } return res.finish(); diff --git a/lix/libcmd/installables.cc b/lix/libcmd/installables.cc index c77ae30e7..a18323f69 100644 --- a/lix/libcmd/installables.cc +++ b/lix/libcmd/installables.cc @@ -419,7 +419,7 @@ ref openEvalCache( auto aOutputs = vFlake.attrs()->get(state.ctx.symbols.create("outputs")); assert(aOutputs); - return *aOutputs->value; + return aOutputs->value; }; if (fingerprint) { @@ -449,23 +449,23 @@ Installables SourceExprCommand::parseInstallables( throw UsageError("'--file' and '--expr' are exclusive"); auto evaluator = getEvaluator(); - auto vFile = evaluator->mem.allocValue(); + Value vFile; if (file == "-") { auto & e = evaluator->parseStdin(); - state.eval(e, *vFile); + state.eval(e, vFile); } else if (file) - state.evalFile(state.aio.blockOn(lookupFileArg(*evaluator, *file)).unwrap(), *vFile); + state.evalFile(state.aio.blockOn(lookupFileArg(*evaluator, *file)).unwrap(), vFile); else { auto & e = evaluator->parseExprFromString(*expr, CanonPath::fromCwd()); - state.eval(e, *vFile); + state.eval(e, vFile); } for (auto & s : ss) { auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s); result.push_back(make_ref(InstallableAttrPath::parse( - evaluator, *this, *vFile, std::move(prefix), std::move(extendedOutputsSpec) + evaluator, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec) ))); } diff --git a/lix/libcmd/repl.cc b/lix/libcmd/repl.cc index 2b0a520d1..3cff251b3 100644 --- a/lix/libcmd/repl.cc +++ b/lix/libcmd/repl.cc @@ -174,35 +174,37 @@ struct NixRepl /** * Get a list of each of the `repl-overlays` (parsed and evaluated). */ - Value * replOverlays(); + Value replOverlays(); /** * Get the Nix function that composes the `repl-overlays` together. */ - Value * getReplOverlaysEvalFunction(); + Value getReplOverlaysEvalFunction(); /** * Cached return value of `getReplOverlaysEvalFunction`. * * Note: This is `shared_ptr` to avoid garbage collection. */ - std::shared_ptr replOverlaysEvalFunction = - std::allocate_shared(TraceableAllocator(), nullptr); + std::shared_ptr> replOverlaysEvalFunction = + std::allocate_shared>( + TraceableAllocator>(), std::nullopt + ); /** * Get the `info` AttrSet that's passed as the first argument to each * of the `repl-overlays`. */ - Value * replInitInfo(); + Value replInitInfo(); /** * Get the current top-level bindings as an AttrSet. */ - Value * bindingsToAttrs(); + Value bindingsToAttrs(); /** * Parse a file, evaluate its result, and force the resulting value. */ - Value * evalFile(SourcePath & path); + Value evalFile(SourcePath & path); void printValue(std::ostream & str, Value & v, @@ -863,10 +865,10 @@ ProcessLineResult NixRepl::processLine(std::string line) std::visit(overloaded { [&](ExprReplBindings & b) { for (auto & [name, e] : b.symbols) { - Value * v = state.ctx.mem.allocValue(); - e->eval(state, *env, *v); + Value v; + e->eval(state, *env, v); (void) e.release(); // NOLINT(bugprone-unused-return-value): leak because of thunk references - addVarToScope(name, *v); + addVarToScope(name, v); } }, [&](std::unique_ptr & e) { @@ -964,9 +966,9 @@ void NixRepl::loadReplOverlays() notice("Loading '%1%'...", "repl-overlays"); auto replInitFilesFunction = getReplOverlaysEvalFunction(); - Value &newAttrs(*evaluator.mem.allocValue()); - SmallValueVector<3> args = {replInitInfo(), bindingsToAttrs(), replOverlays()}; - state.callFunction(*replInitFilesFunction, args, newAttrs, noPos); + Value newAttrs; + Value args[] = {replInitInfo(), bindingsToAttrs(), replOverlays()}; + state.callFunction(replInitFilesFunction, args, newAttrs, noPos); // n.b. this does in fact load the stuff into the environment twice (once // from the superset of the environment returned by repl-overlays and once @@ -976,14 +978,14 @@ void NixRepl::loadReplOverlays() addAttrsToScope(newAttrs); } -Value * NixRepl::getReplOverlaysEvalFunction() +Value NixRepl::getReplOverlaysEvalFunction() { if (replOverlaysEvalFunction && *replOverlaysEvalFunction) { - return *replOverlaysEvalFunction; + return **replOverlaysEvalFunction; } auto evalReplInitFilesPath = CanonPath::root + "repl-overlays.nix"; - *replOverlaysEvalFunction = evaluator.mem.allocValue(); + *replOverlaysEvalFunction = Value{}; auto code = #include "repl-overlays.nix.gen.hh" ; @@ -995,14 +997,14 @@ Value * NixRepl::getReplOverlaysEvalFunction() state.eval(expr, **replOverlaysEvalFunction); - return *replOverlaysEvalFunction; + return **replOverlaysEvalFunction; } -Value * NixRepl::replOverlays() +Value NixRepl::replOverlays() { - Value * replInits(evaluator.mem.allocValue()); + Value replInits; auto replInitStorage = evaluator.mem.newList(evalSettings.replOverlays.get().size()); - *replInits = {NewValueAs::list, replInitStorage}; + replInits = {NewValueAs::list, replInitStorage}; size_t i = 0; for (auto path : evalSettings.replOverlays.get()) { @@ -1018,18 +1020,18 @@ Value * NixRepl::replOverlays() auto replInit = evalFile(sourcePath); evalSettings.pureEval.setDefault(prevPureEval); - if (!replInit->isLambda()) { + if (!replInit.isLambda()) { evaluator.errors .make( "Expected `repl-overlays` entry %s to be a lambda but found %s: %s", path, - showType(*replInit), - ValuePrinter(state, *replInit, errorPrintOptions) + showType(replInit), + ValuePrinter(state, replInit, errorPrintOptions) ) .debugThrow(); } - if (auto attrs = dynamic_cast(replInit->lambda().fun->pattern.get()); + if (auto attrs = dynamic_cast(replInit.lambda().fun->pattern.get()); attrs && !attrs->ellipsis) { evaluator.errors @@ -1039,7 +1041,7 @@ Value * NixRepl::replOverlays() "repl-overlays", "..." ) - .atPos(replInit->lambda().fun->pos) + .atPos(replInit.lambda().fun->pos) .debugThrow(); } @@ -1051,16 +1053,16 @@ Value * NixRepl::replOverlays() return replInits; } -Value * NixRepl::replInitInfo() +Value NixRepl::replInitInfo() { auto builder = evaluator.buildBindings(2); - Value * currentSystem(evaluator.mem.allocValue()); - currentSystem->mkString(evalSettings.getCurrentSystem()); + Value currentSystem; + currentSystem.mkString(evalSettings.getCurrentSystem()); builder.insert(evaluator.symbols.create("currentSystem"), currentSystem); - Value * info(evaluator.mem.allocValue()); - info->mkAttrs(builder.finish()); + Value info; + info.mkAttrs(builder.finish()); return info; } @@ -1118,19 +1120,19 @@ void NixRepl::addVarToScope(const Symbol name, Value & v) } else { notice("Added %s.", evaluator.symbols[name]); } - env->values[displ++] = &v; + env->values[displ++] = v; varNames.emplace(evaluator.symbols[name]); } -Value * NixRepl::bindingsToAttrs() +Value NixRepl::bindingsToAttrs() { auto builder = evaluator.buildBindings(staticEnv->vars.size()); for (auto & [symbol, displacement] : staticEnv->vars) { builder.insert(symbol, env->values[displacement]); } - Value * attrs(evaluator.mem.allocValue()); - attrs->mkAttrs(builder.finish()); + Value attrs; + attrs.mkAttrs(builder.finish()); return attrs; } @@ -1153,12 +1155,12 @@ void NixRepl::evalString(std::string s, Value & v) state.forceValue(v, noPos); } -Value * NixRepl::evalFile(SourcePath & path) +Value NixRepl::evalFile(SourcePath & path) { auto & expr = evaluator.parseExprFromFile(evaluator.paths.checkSourcePath(path), staticEnv); - Value * result(evaluator.mem.allocValue()); - expr.eval(state, *env, *result); - state.forceValue(*result, noPos); + Value result; + expr.eval(state, *env, result); + state.forceValue(result, noPos); return result; } diff --git a/lix/libexpr/attr-path.cc b/lix/libexpr/attr-path.cc index cde6e7a11..509bf88b3 100644 --- a/lix/libexpr/attr-path.cc +++ b/lix/libexpr/attr-path.cc @@ -130,7 +130,7 @@ findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & au ValuePrinter(state, v, errorPrintOptions) ); } - v = *a->value; + v = a->value; pos = a->pos; } else { if (!v.isList()) { @@ -153,7 +153,7 @@ findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & au ); } - v = *v.listElems()[*attrIndex]; + v = v.listElems()[*attrIndex]; pos = noPos; } diff --git a/lix/libexpr/attr-set.cc b/lix/libexpr/attr-set.cc index ec0c3ad5a..76455da1d 100644 --- a/lix/libexpr/attr-set.cc +++ b/lix/libexpr/attr-set.cc @@ -26,9 +26,8 @@ Bindings * EvalMemory::allocBindings(size_t capacity) Value & BindingsBuilder::alloc(Symbol name, PosIdx pos) { - auto value = mem.allocValue(); - bindings->push_back(Attr(name, value, pos)); - return *value; + bindings->push_back(Attr(name, {}, pos)); + return (bindings->end() - 1)->value; } diff --git a/lix/libexpr/attr-set.hh b/lix/libexpr/attr-set.hh index 81e031be7..7fb4ac6e9 100644 --- a/lix/libexpr/attr-set.hh +++ b/lix/libexpr/attr-set.hh @@ -23,8 +23,8 @@ struct Attr way we keep Attr size at two words with no wasted space. */ Symbol name; PosIdx pos; - Value * value; - Attr(Symbol name, Value * value, PosIdx pos = noPos) : name(name), pos(pos), value(value) {} + mutable Value value; + Attr(Symbol name, Value value, PosIdx pos = noPos) : name(name), pos(pos), value(value) {} Attr() { }; bool operator < (const Attr & a) const { @@ -72,7 +72,7 @@ public: const Attr * get(Symbol name) { - Attr key(name, 0); + Attr key(name, {}); iterator i = std::lower_bound(begin(), end(), key); if (i != end() && i->name == name) return &*i; return nullptr; @@ -135,7 +135,7 @@ public: { } - void insert(Symbol name, Value * value, PosIdx pos = noPos) + void insert(Symbol name, Value value, PosIdx pos = noPos) { insert(Attr(name, value, pos)); } diff --git a/lix/libexpr/eval-cache.cc b/lix/libexpr/eval-cache.cc index 881f8ac39..aa8937d5b 100644 --- a/lix/libexpr/eval-cache.cc +++ b/lix/libexpr/eval-cache.cc @@ -387,7 +387,7 @@ Value & AttrCursor::getValue(EvalState & state) auto attr = vParent.attrs()->get(state.ctx.symbols.create(parent->second)); if (!attr) throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr(state)); - _value = allocRootValue(*attr->value); + _value = allocRootValue(attr->value); } else _value = allocRootValue(root->getRootValue(state)); } @@ -520,7 +520,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(EvalState & state, const st } return make_ref( - root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2) + root, std::make_pair(shared_from_this(), name), &attr->value, std::move(cachedValue2) ); } @@ -686,7 +686,7 @@ std::vector AttrCursor::getListOfStrings(EvalState & state) for (auto & elem : v.listItems()) { res.push_back(std::string( - state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching") + state.forceStringNoCtx(elem, noPos, "while evaluating an attribute for caching") )); } diff --git a/lix/libexpr/eval-inline.hh b/lix/libexpr/eval-inline.hh index 3b23c6593..3d414928d 100644 --- a/lix/libexpr/eval-inline.hh +++ b/lix/libexpr/eval-inline.hh @@ -13,18 +13,18 @@ namespace nix { inline Value::Value(app_t, EvalMemory & mem, Value & lhs, Value & rhs) { auto app = static_cast(mem.allocBytes(sizeof(Value::App) + sizeof(Value *))); - app->_left = reinterpret_cast(&lhs); + app->_left = lhs; app->_n = 1; - app->_args[0] = &rhs; + app->_args[0] = rhs; raw = tag(tApp, app); } -inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span args) +inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span args) { auto app = static_cast(mem.allocBytes(sizeof(Value::App) + args.size_bytes())); - app->_left = reinterpret_cast(&lhs); + app->_left = lhs; app->_n = args.size(); - memcpy(app->_args, args.data(), args.size_bytes()); + std::copy(args.begin(), args.end(), app->_args); raw = tag(tApp, app); } @@ -85,14 +85,6 @@ T * EvalMemory::allocType(size_t n) return static_cast(allocBytes(checkedArrayAllocSize(sizeof(T), n))); } -[[gnu::always_inline]] -Value * EvalMemory::allocValue() -{ - static_assert(CACHES * CACHE_INCREMENT >= sizeof(Value)); - stats.nrValues++; - return static_cast(allocBytes(sizeof(Value))); -} - [[gnu::always_inline]] Env & EvalMemory::allocEnv(size_t size) { @@ -117,15 +109,15 @@ void EvalState::forceValue(Value & v, const PosIdx pos) if (thunk.resolved()) { v = thunk.result(); } else { - const auto backup = v; - Env * env = v.thunk().env(); - Expr & expr = *v.thunk().expr; - v = Value{NewValueAs::blackhole}; + const auto backup = thunk; + Env * env = thunk.env(); + Expr & expr = *thunk.expr; + thunk = Value::blackHole; try { expr.eval(*this, *env, v); - backup.thunk().resolve(v); + thunk.resolve(v); } catch (...) { - v = backup; + thunk = backup; tryFixupBlackHolePos(v, pos); throw; } @@ -136,8 +128,9 @@ void EvalState::forceValue(Value & v, const PosIdx pos) v = app.result(); } else { auto target = app.target(); - if (!target->isPrimOp() || target->primOp()->arity <= app.totalArgs()) { - callFunction(*v.app().left(), v.app().args(), v, pos); + if (!target.isPrimOp() || target.primOp()->arity <= app.totalArgs()) { + auto tmp = v.app().left(); + callFunction(tmp, v.app().args(), v, pos); app.resolve(v); } } diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index 2b2dad803..6f358e00b 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -135,7 +135,7 @@ std::string showType(const Value & v) case tApp: if (v.isPrimOpApp()) { return fmt( - "the partially applied built-in function '%s'", v.app().target()->primOp()->name + "the partially applied built-in function '%s'", v.app().target().primOp()->name ); } else { return "a function application"; @@ -563,11 +563,8 @@ Path EvalPaths::toRealPath(const Path & path, const NixStringContext & context) : path; } -void EvalBuiltins::addConstant(const std::string & name, const Value & v2, Constant info) +void EvalBuiltins::addConstant(const std::string & name, const Value & v, Constant info) { - Value * v = mem.allocValue(); - *v = v2; - auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name; constantInfos.push_back({name2, info}); @@ -577,14 +574,14 @@ void EvalBuiltins::addConstant(const std::string & name, const Value & v2, Const We might know the type of a thunk in advance, so be allowed to just write it down in that case. */ - if (auto gotType = v->type(true); gotType != nThunk) { + if (auto gotType = v.type(true); gotType != nThunk) { assert(info.type == gotType); } /* Install value the base environment. */ staticEnv->vars.insert_or_assign(symbols.create(name), baseEnvDispl); env.values[baseEnvDispl++] = v; - env.values[0]->attrs()->push_back(Attr(symbols.create(name2), v)); + env.values[0].attrs()->push_back(Attr(symbols.create(name2), v)); } } @@ -600,15 +597,14 @@ void EvalBuiltins::addPrimOp(PrimOpDetails primOp) the primop to a dummy value. */ if (primOp.arity == 0) { primOp.arity = 1; - auto vPrimOp = mem.allocValue(); - vPrimOp->mkPrimOp(new PrimOp(primOp)); - Value v{NewValueAs::app, mem, *vPrimOp, *vPrimOp}; + Value vPrimOp{NewValueAs::primop, *new PrimOp(primOp)}; + Value v{NewValueAs::app, mem, vPrimOp, vPrimOp}; addConstant( - primOp.name, + vPrimOp.primOp()->name, v, { .type = nFunction, - .doc = vPrimOp->primOp()->doc, + .doc = vPrimOp.primOp()->doc, } ); } @@ -617,17 +613,16 @@ void EvalBuiltins::addPrimOp(PrimOpDetails primOp) if (primOp.name.starts_with("__")) primOp.name = primOp.name.substr(2); - Value * v = mem.allocValue(); - v->mkPrimOp(new PrimOp(std::move(primOp))); + Value v{NewValueAs::primop, *new PrimOp(std::move(primOp))}; staticEnv->vars.insert_or_assign(auto(envName), baseEnvDispl); env.values[baseEnvDispl++] = v; - env.values[0]->attrs()->push_back(Attr(symbols.create(v->primOp()->name), v)); + env.values[0].attrs()->push_back(Attr(symbols.create(v.primOp()->name), v)); } Value & EvalBuiltins::get(const std::string & name) { - return *env.values[0]->attrs()->get(symbols.create(name))->value; + return env.values[0].attrs()->get(symbols.create(name))->value; } @@ -670,9 +665,9 @@ void printStaticEnvBindings(const SymbolTable & st, const StaticEnv & se) // just for the current level of Env, not the whole chain. void printWithBindings(const SymbolTable & st, const Env & env) { - if (env.values[0]->type() == nAttrs) { + if (env.values[0].type() == nAttrs) { std::set bindings; - for (const auto & attr : *env.values[0]->attrs()) { + for (const auto & attr : *env.values[0].attrs()) { bindings.emplace(st[attr.name]); } @@ -728,10 +723,10 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En if (env.up && se.up) { mapStaticEnvBindings(st, *se.up, *env.up, vm); - if (se.isWith && env.values[0]->type() == nAttrs) { + if (se.isWith && env.values[0].type() == nAttrs) { // add 'with' bindings. - Bindings::iterator j = env.values[0]->attrs()->begin(); - while (j != env.values[0]->attrs()->end()) { + Bindings::iterator j = env.values[0].attrs()->begin(); + while (j != env.values[0].attrs()->end()) { vm[std::string(st[j->name])] = j->value; ++j; } @@ -860,7 +855,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) for (auto l = var.level; l; --l, env = env->up) ; if (!var.fromWith) { - return env->values[var.displ]; + return &env->values[var.displ]; } // This early exit defeats the `maybeThunk` optimization for variables from `with`, @@ -871,14 +866,14 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) auto * fromWith = var.fromWith; while (1) { forceAttrs( - *env->values[0], + env->values[0], fromWith->pos, "while evaluating the first subexpression of a with expression" ); - auto j = env->values[0]->attrs()->get(var.name); + auto j = env->values[0].attrs()->get(var.name); if (j) { if (ctx.stats.countCalls) ctx.stats.attrSelects[j->pos]++; - return j->value; + return &j->value; } if (!fromWith->parentWith) ctx.errors.make("undefined variable '%1%'", ctx.symbols[var.name]).atPos(var.pos).withFrame(*env, var).debugThrow(); @@ -978,31 +973,28 @@ void EvalState::mkSingleDerivedPathString( in the given environment. But if the expression is a variable, then look it up right away. This significantly reduces the number of thunks allocated. */ -Value * Expr::maybeThunk(EvalState & state, Env & env) +Value Expr::maybeThunk(EvalState & state, Env & env) { - Value * v = state.ctx.mem.allocValue(); - *v = {NewValueAs::thunk, state.ctx.mem, env, *this}; state.ctx.stats.nrThunks++; - return v; + return {NewValueAs::thunk, state.ctx.mem, env, *this}; } - -Value * ExprVar::maybeThunk(EvalState & state, Env & env) +Value ExprVar::maybeThunk(EvalState & state, Env & env) { Value * v = state.lookupVar(&env, *this, true); /* The value might not be initialised in the environment yet. In that case, ignore it. */ - if (v) { + if (v && !v->isInvalid()) { state.ctx.stats.nrAvoided++; - return v; + return *v; } return Expr::maybeThunk(state, env); } -Value * ExprLiteral::maybeThunk(EvalState & state, Env & env) +Value ExprLiteral::maybeThunk(EvalState & state, Env & env) { state.ctx.stats.nrAvoided++; - return &v; + return v; } @@ -1140,10 +1132,9 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v) in the original environment. */ Displacement displ = 0; for (auto & i : attrs) { - Value * vAttr; + Value vAttr; if (hasOverrides && i.second.kind != ExprAttrs::AttrDef::Kind::Inherited) { - vAttr = state.ctx.mem.allocValue(); - *vAttr = { + vAttr = { NewValueAs::thunk, state.ctx.mem, *i.second.chooseByKind(&env2, &env, inheritEnv), @@ -1167,7 +1158,7 @@ void ExprSet::eval(EvalState & state, Env & env, Value & v) been substituted into the bodies of the other attributes. Hence we need __overrides.) */ if (hasOverrides) { - Value & vOverrides = *(*v.attrs())[overrides->second.displ].value; + Value & vOverrides = (*v.attrs())[overrides->second.displ].value; state.forceAttrs(vOverrides, noPos, "while evaluating the `__overrides` attribute"); Bindings * newBnds = state.ctx.mem.allocBindings(capacity + vOverrides.attrs()->size()); for (auto & i : *v.attrs()) @@ -1254,16 +1245,15 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) { auto result = state.ctx.mem.newList(elems.size()); v = {NewValueAs::list, result}; - for (auto [n, v2] : enumerate(result->span())) { - const_cast(v2) = elems[n]->maybeThunk(state, env); + for (auto && [n, v2] : enumerate(result->span())) { + v2 = elems[n]->maybeThunk(state, env); } } - -Value * ExprList::maybeThunk(EvalState & state, Env & env) +Value ExprList::maybeThunk(EvalState & state, Env & env) { if (elems.empty()) { - return &Value::EMPTY_LIST; + return Value::EMPTY_LIST; } return Expr::maybeThunk(state, env); } @@ -1291,9 +1281,9 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v) void ExprInheritFrom::eval(EvalState & state, Env & env, Value & v) { - Value * v2 = env.values[displ]; - state.forceValue(*v2, pos); - v = *v2; + Value & v2 = env.values[displ]; + state.forceValue(v2, pos); + v = v2; } @@ -1400,7 +1390,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) // If we're here, then we successfully found the attribute. // Set our currently operated-on attrset to this one, and keep going. - vCurrent = attrIt->value; + vCurrent = &attrIt->value; posCurrent = attrIt->pos; posCurrentSyntax = currentAttrName.pos; if (state.ctx.stats.countCalls) state.ctx.stats.attrSelects[posCurrent]++; @@ -1435,7 +1425,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) v.mkBool(false); return; } else { - vAttrs = j->value; + vAttrs = &j->value; } } @@ -1523,7 +1513,7 @@ Env & SimplePattern::match( { Env & env2(state.ctx.mem.allocEnv(1)); env2.up = &up; - env2.values[0] = &arg; + env2.values[0] = arg; return env2; } @@ -1547,7 +1537,7 @@ Env & AttrsPattern::match( } if (name) { - env2.values[displ++] = &arg; + env2.values[displ++] = arg; } ///* For each formal argument, get the actual argument. If @@ -1598,7 +1588,7 @@ Env & AttrsPattern::match( return env2; } -void EvalState::callFunction(Value & fun, std::span args, Value & vRes, const PosIdx pos) +void EvalState::callFunction(Value & fun, std::span args, Value & vRes, const PosIdx pos) { if (callDepth > evalSettings.maxCallDepth) ctx.errors.make("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow(); @@ -1612,11 +1602,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, Value vCur(fun); - auto makeAppChain = [&]() { - auto fun2 = ctx.mem.allocValue(); - *fun2 = vCur; - vRes = {NewValueAs::app, ctx.mem, *fun2, args}; - }; + auto makeAppChain = [&]() { vRes = {NewValueAs::app, ctx.mem, vCur, args}; }; const Attr * functor; @@ -1626,7 +1612,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, ExprLambda & lambda(*vCur.lambda().fun); - Env & env2 = lambda.pattern->match(lambda, *this, *vCur.lambda().env(), *args[0], pos); + Env & env2 = lambda.pattern->match(lambda, *this, *vCur.lambda().env(), args[0], pos); ctx.stats.nrFunctionCalls++; if (ctx.stats.countCalls) ctx.stats.addCall(lambda); @@ -1664,7 +1650,11 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, if (ctx.stats.countCalls) ctx.stats.primOpCalls[fn->name]++; try { - fn->fun(*this, args.data(), vCur); + SmallVector pargs(argsLeft); + for (unsigned i = 0; i < argsLeft; i++) { + pargs[i] = &args[i]; + } + fn->fun(*this, pargs.data(), vCur); } catch (ThrownError & e) { // Distinguish between an error that simply happened while "throw" // was being evaluated and an explicit thrown error. @@ -1684,13 +1674,16 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, } else if (vCur.isPrimOpApp()) { - /* Figure out the number of arguments still needed. */ - size_t argsDone = vCur.app().totalArgs(); - Value * primOp = vCur.app().target(); - auto arity = primOp->primOp()->arity; - auto argsLeft = arity - argsDone; + auto & app = vCur.app(); + auto prevArgs = app.args(); - if (args.size() < argsLeft) { + assert(!vCur.app().left().isApp()); + + /* Figure out the number of arguments still needed. */ + Value primOp = app.target(); + auto arity = primOp.primOp()->arity; + + if (args.size() < arity - prevArgs.size()) { /* We still don't have enough arguments, so extend the tPrimOpApp chain. */ makeAppChain(); return; @@ -1699,18 +1692,16 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, the previous and new arguments. */ // max arity as of writing is 3. even 4 seems excessive though. - SmallVector vArgs(arity); - auto n = argsDone; - for (Value * arg = &vCur; arg->isApp(); arg = arg->app().left()) { - auto curArgs = arg->app().args(); - memcpy(&vArgs[n] - curArgs.size(), curArgs.data(), curArgs.size_bytes()); - n -= curArgs.size(); + SmallVector vArgs; + for (auto & arg : prevArgs) { + vArgs.push_back(&arg); + } + while (vArgs.size() < arity) { + vArgs.push_back(&args[0]); + args = args.subspan(1); } - for (size_t i = 0; i < argsLeft; ++i) - vArgs[argsDone + i] = args[i]; - - auto fn = primOp->primOp(); + auto fn = primOp.primOp(); ctx.stats.nrPrimOpCalls++; if (ctx.stats.countCalls) ctx.stats.primOpCalls[fn->name]++; @@ -1724,8 +1715,6 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, e.addTrace(ctx.positions[pos], "while calling the '%1%' builtin", fn->name); throw; } - - args = args.subspan(argsLeft); } } @@ -1733,10 +1722,9 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, /* 'vCur' may be allocated on the stack of the calling function, but for functors we may keep a reference, so heap-allocate a copy and use that instead. */ - Value * args2[] = {ctx.mem.allocValue(), args[0]}; - *args2[0] = vCur; + Value args2[] = {vCur, args[0]}; try { - callFunction(*functor->value, args2, vCur, functor->pos); + callFunction(functor->value, args2, vCur, functor->pos); } catch (Error & e) { e.addTrace(ctx.positions[pos], "while calling a functor (an attribute set with a '__functor' attribute)"); throw; @@ -1792,7 +1780,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res, PosI auto found = fun.attrs()->get(ctx.s.functor); if (found) { Value v; - callFunction(*found->value, fun, v, pos); + callFunction(found->value, fun, v, pos); forceValue(v, pos); return autoCallFunction(args, v, res, pos); } @@ -1975,19 +1963,19 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) } void EvalState::concatLists( - Value & v, size_t nrLists, Value * const * lists, const PosIdx pos, std::string_view errorCtx + Value & v, std::span lists, const PosIdx pos, std::string_view errorCtx ) { ctx.stats.nrListConcats++; Value * nonEmpty = 0; size_t len = 0; - for (size_t n = 0; n < nrLists; ++n) { - forceList(*lists[n], pos, errorCtx); - auto l = lists[n]->listSize(); + for (size_t n = 0; n < lists.size(); ++n) { + forceList(lists[n], pos, errorCtx); + auto l = lists[n].listSize(); len += l; if (l) { - nonEmpty = lists[n]; + nonEmpty = &lists[n]; } } @@ -1999,10 +1987,10 @@ void EvalState::concatLists( auto list = ctx.mem.newList(len); v = {NewValueAs::list, list}; auto out = list->elems; - for (size_t n = 0, pos = 0; n < nrLists; ++n) { - auto l = lists[n]->listSize(); + for (size_t n = 0, pos = 0; n < lists.size(); ++n) { + auto l = lists[n].listSize(); if (l) { - memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *)); + std::copy(lists[n].listItems().begin(), lists[n].listItems().end(), out + pos); } pos += l; } @@ -2165,18 +2153,18 @@ void EvalState::forceValueDeep(Value & v) for (auto & i : *v.attrs()) try { // If the value is a thunk, we're evaling. Otherwise no trace necessary. - auto dts = ctx.debug && i.value->isThunk() + auto dts = ctx.debug && i.value.isThunk() ? makeDebugTraceStacker( *this, - *i.value->thunk().expr, - *i.value->thunk().env(), + *i.value.thunk().expr, + *i.value.thunk().env(), ctx.positions[i.pos], "while evaluating the attribute '%1%'", ctx.symbols[i.name] ) : nullptr; - recurse(*i.value); + recurse(i.value); } catch (Error & e) { e.addTrace(ctx.positions[i.pos], "while evaluating the attribute '%1%'", ctx.symbols[i.name]); throw; @@ -2184,8 +2172,8 @@ void EvalState::forceValueDeep(Value & v) } else if (v.isList()) { - for (auto v2 : v.listItems()) { - recurse(*v2); + for (auto & v2 : v.listItems()) { + recurse(v2); } } }; @@ -2335,11 +2323,11 @@ bool EvalState::isDerivation(Value & v) if (!i) { return false; } - forceValue(*i->value, i->pos); - if (i->value->type() != nString) { + forceValue(i->value, i->pos); + if (i->value.type() != nString) { return false; } - return i->value->str() == "derivation"; + return i->value.str() == "derivation"; } @@ -2350,7 +2338,7 @@ std::optional EvalState::tryAttrsToString(const PosIdx pos, Value & if (i) { Value v1; try { - callFunction(*i->value, v, v1, i->pos); + callFunction(i->value, v, v1, i->pos); return coerceToString(pos, v1, context, "while evaluating the result of the `__toString` attribute", mode, copyToStore).toOwned(); @@ -2406,7 +2394,7 @@ BackedStringView EvalState::coerceToString( .debugThrow(); } return coerceToString( - pos, *i->value, context, errorCtx, mode, copyToStore, canonicalizePath + pos, i->value, context, errorCtx, mode, copyToStore, canonicalizePath ); } @@ -2445,7 +2433,7 @@ BackedStringView EvalState::coerceToString( try { result += *coerceToString( pos, - *v2, + v2, context, "while evaluating one element of the list", mode, @@ -2458,7 +2446,7 @@ BackedStringView EvalState::coerceToString( } if (n < v.listSize() - 1 /* !!! not quite correct */ - && (!v2->isList() || v2->listSize() != 0)) + && (!v2.isList() || v2.listSize() != 0)) { result += " "; } @@ -2588,11 +2576,6 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v forceValue(v1, pos); forceValue(v2, pos); - /* !!! Hack to support some old broken code that relies on pointer - equality tests between sets. (Specifically, builderDefs calls - uniqList on a list of sets.) Will remove this eventually. */ - if (&v1 == &v2) return true; - // Special case type-compatibility between float and int if (v1.type() == nInt && v2.type() == nFloat) { return v1.integer().value == v2.fpoint(); @@ -2604,6 +2587,11 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v // All other types are not compatible with each other. if (v1.type() != v2.type()) return false; + /* !!! Hack to support some old broken code that relies on pointer + equality tests between sets. (Specifically, builderDefs calls + uniqList on a list of sets.) Will remove this eventually. */ + auto pointerEq = [&] { return v1.pointerEqProxy() == v2.pointerEqProxy(); }; + switch (v1.type()) { case nInt: return v1.integer() == v2.integer(); @@ -2621,22 +2609,24 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v return true; case nList: + if (pointerEq()) return true; if (v1.listSize() != v2.listSize()) return false; for (size_t n = 0; n < v1.listSize(); ++n) { - if (!eqValues(*v1.listElems()[n], *v2.listElems()[n], pos, errorCtx)) { + if (!eqValues(v1.listElems()[n], v2.listElems()[n], pos, errorCtx)) { return false; } } return true; case nAttrs: { + if (pointerEq()) return true; /* If both sets denote a derivation (type = "derivation"), then compare their outPaths. */ if (isDerivation(v1) && isDerivation(v2)) { auto i = v1.attrs()->get(ctx.s.outPath); auto j = v2.attrs()->get(ctx.s.outPath); if (i && j) { - return eqValues(*i->value, *j->value, pos, errorCtx); + return eqValues(i->value, j->value, pos, errorCtx); } } @@ -2646,7 +2636,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v Bindings::iterator i, 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, pos, errorCtx)) { + if (i->name != j->name || !eqValues(i->value, j->value, pos, errorCtx)) { return false; } } @@ -2659,6 +2649,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v return false; case nExternal: + if (pointerEq()) return true; return *v1.external() == *v2.external(); case nFloat: @@ -2708,7 +2699,6 @@ void Evaluator::printStatistics() uint64_t bEnvs = mem.nrEnvs * sizeof(Env) + mem.nrValuesInEnvs * sizeof(Value *); uint64_t bLists = mem.nrListElems * sizeof(Value *); - uint64_t bValues = mem.nrValues * sizeof(Value); uint64_t bAttrsets = mem.nrAttrsets * sizeof(Bindings) + mem.nrAttrsInAttrsets * sizeof(Attr); #if HAVE_BOEHMGC @@ -2732,9 +2722,10 @@ void Evaluator::printStatistics() {"bytes", bLists}, {"concats", stats.nrListConcats}, }; + // reported for compatibility, even though we no longer allocate these on the heap topObj["values"] = { - {"number", mem.nrValues}, - {"bytes", bValues}, + {"number", 0}, + {"bytes", 0}, }; topObj["symbols"] = { {"number", symbols.size()}, diff --git a/lix/libexpr/eval.hh b/lix/libexpr/eval.hh index 75ad9d5c3..22fa12723 100644 --- a/lix/libexpr/eval.hh +++ b/lix/libexpr/eval.hh @@ -61,12 +61,12 @@ struct Constant bool impureOnly = false; }; -using ValMap = GcMap; +using ValMap = GcMap; struct alignas(Value::Acb::TAG_ALIGN) Env { Env * up; - Value * values[0]; + Value values[0]; }; void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env); @@ -192,7 +192,6 @@ public: { unsigned long nrEnvs = 0; unsigned long nrValuesInEnvs = 0; - unsigned long nrValues = 0; unsigned long nrAttrsets = 0; unsigned long nrAttrsInAttrsets = 0; unsigned long nrListElems = 0; @@ -210,7 +209,6 @@ public: template inline T * allocType(size_t n = 1); - inline Value * allocValue(); inline Env & allocEnv(size_t size); Bindings * allocBindings(size_t capacity); @@ -795,12 +793,11 @@ public: bool isFunctor(Value & fun); - void callFunction(Value & fun, std::span args, Value & vRes, const PosIdx pos); + void callFunction(Value & fun, std::span args, Value & vRes, const PosIdx pos); void callFunction(Value & fun, Value & arg, Value & vRes, const PosIdx pos) { - Value * args[] = {&arg}; - callFunction(fun, args, vRes, pos); + callFunction(fun, {&arg, 1}, vRes, pos); } /** @@ -840,13 +837,8 @@ public: const SingleDerivedPath & p, Value & v); - void concatLists( - Value & v, - size_t nrLists, - Value * const * lists, - const PosIdx pos, - std::string_view errorCtx - ); + void + concatLists(Value & v, std::span lists, const PosIdx pos, std::string_view errorCtx); private: diff --git a/lix/libexpr/flake/flake.cc b/lix/libexpr/flake/flake.cc index 792f62cfe..044940abc 100644 --- a/lix/libexpr/flake/flake.cc +++ b/lix/libexpr/flake/flake.cc @@ -109,15 +109,15 @@ static void parseFlakeInputAttr(EvalState & state, const Attr & attr, fetchers:: // Allow selecting a subset of enum values #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch-enum" - switch (attr.value->type()) { + switch (attr.value.type()) { case nString: - attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value->str())); + attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value.str())); break; case nBool: - attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value->boolean()}); + attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value.boolean()}); break; case nInt: { - auto intValue = attr.value->integer().value; + auto intValue = attr.value.integer().value; if (intValue < 0) { state.ctx.errors @@ -137,7 +137,7 @@ static void parseFlakeInputAttr(EvalState & state, const Attr & attr, fetchers:: .make( "flake input attribute '%s' is %s while a string, Boolean, or integer is expected", state.ctx.symbols[attr.name], - showType(*attr.value) + showType(attr.value) ) .debugThrow(); } @@ -169,21 +169,21 @@ static FlakeInput parseFlakeInput( for (nix::Attr attr : *(value.attrs())) { try { if (attr.name == sUrl) { - expectType(state, nString, *attr.value, attr.pos); - url = attr.value->str(); + expectType(state, nString, attr.value, attr.pos); + url = attr.value.str(); attrs.emplace("url", *url); } else if (attr.name == sFlake) { - expectType(state, nBool, *attr.value, attr.pos); - input.isFlake = attr.value->boolean(); + expectType(state, nBool, attr.value, attr.pos); + input.isFlake = attr.value.boolean(); } else if (attr.name == sInputs) { input.overrides = parseFlakeInputs( - state, *attr.value, attr.pos, baseDir, lockRootPath, depth + 1, false + state, attr.value, attr.pos, baseDir, lockRootPath, depth + 1, false ) .first; } else if (attr.name == sFollows) { - expectType(state, nString, *attr.value, attr.pos); - auto follows(parseInputPath(attr.value->str())); + expectType(state, nString, attr.value, attr.pos); + auto follows(parseInputPath(attr.value.str())); follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end()); input.follows = follows; } else { @@ -247,17 +247,17 @@ static std::pair, std::optional> "'self' input attributes not allowed at %s", state.ctx.positions[inputAttr.pos] ); } - expectType(state, nAttrs, *inputAttr.value, inputAttr.pos); + expectType(state, nAttrs, inputAttr.value, inputAttr.pos); selfAttrs = selfAttrs.value_or(fetchers::Attrs{}); - for (auto & attr : *inputAttr.value->attrs()) { + for (auto & attr : *inputAttr.value.attrs()) { parseFlakeInputAttr(state, attr, *selfAttrs); } } else { inputs.emplace( inputName, parseFlakeInput( - state, inputName, *inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth + state, inputName, inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth ) ); } @@ -335,15 +335,15 @@ static Flake getFlake( state.eval(flakeExpr, vInfo); if (auto description = vInfo.attrs()->get(state.ctx.s.description)) { - expectType(state, nString, *description->value, description->pos); - flake.description = description->value->str(); + expectType(state, nString, description->value, description->pos); + flake.description = description->value.str(); } auto sInputs = state.ctx.symbols.create("inputs"); if (auto inputs = vInfo.attrs()->get(sInputs)) { auto [flakeInputs, selfAttrs] = - parseFlakeInputs(state, *inputs->value, inputs->pos, flakeDir, lockRootPath, 0, true); + parseFlakeInputs(state, inputs->value, inputs->pos, flakeDir, lockRootPath, 0, true); flake.inputs = std::move(flakeInputs); flake.selfAttrs = std::move(selfAttrs); } @@ -368,11 +368,11 @@ static Flake getFlake( } if (auto outputs = vInfo.attrs()->get(state.ctx.s.outputs)) { - expectType(state, nFunction, *outputs->value, outputs->pos); + expectType(state, nFunction, outputs->value, outputs->pos); - if (outputs->value->isLambda()) { + if (outputs->value.isLambda()) { if (auto pattern = - dynamic_cast(outputs->value->lambda().fun->pattern.get()); + dynamic_cast(outputs->value.lambda().fun->pattern.get()); pattern) { for (auto & formal : pattern->formals) { @@ -393,23 +393,23 @@ static Flake getFlake( auto sNixConfig = state.ctx.symbols.create("nixConfig"); if (auto nixConfig = vInfo.attrs()->get(sNixConfig)) { - expectType(state, nAttrs, *nixConfig->value, nixConfig->pos); + expectType(state, nAttrs, nixConfig->value, nixConfig->pos); - for (auto & setting : *nixConfig->value->attrs()) { - forceTrivialValue(state, *setting.value, setting.pos); - if (setting.value->type() == nString) { + for (auto & setting : *nixConfig->value.attrs()) { + forceTrivialValue(state, setting.value, setting.pos); + if (setting.value.type() == nString) { flake.config.settings.emplace( state.ctx.symbols[setting.name], - std::string(state.forceStringNoCtx(*setting.value, setting.pos, "")) + std::string(state.forceStringNoCtx(setting.value, setting.pos, "")) ); - } else if (setting.value->type() == nPath) { + } else if (setting.value.type() == nPath) { NixStringContext emptyContext = {}; flake.config.settings.emplace( state.ctx.symbols[setting.name], state .coerceToString( setting.pos, - *setting.value, + setting.value, emptyContext, "", StringCoercionMode::Strict, @@ -418,30 +418,30 @@ static Flake getFlake( ) .toOwned() ); - } else if (setting.value->type() == nInt) { + } else if (setting.value.type() == nInt) { flake.config.settings.emplace( state.ctx.symbols[setting.name], - state.forceInt(*setting.value, setting.pos, "").value + state.forceInt(setting.value, setting.pos, "").value ); - } else if (setting.value->type() == nBool) { + } else if (setting.value.type() == nBool) { flake.config.settings.emplace( state.ctx.symbols[setting.name], - Explicit{state.forceBool(*setting.value, setting.pos, "")} + Explicit{state.forceBool(setting.value, setting.pos, "")} ); - } else if (setting.value->type() == nList) { + } else if (setting.value.type() == nList) { std::vector ss; - for (auto elem : setting.value->listItems()) { - if (elem->type() != nString) { + for (auto & elem : setting.value.listItems()) { + if (elem.type() != nString) { state.ctx.errors .make( "list element in flake configuration setting '%s' is %s while a " "string is expected", state.ctx.symbols[setting.name], - showType(*setting.value) + showType(setting.value) ) .debugThrow(); } - ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos, "")); + ss.emplace_back(state.forceStringNoCtx(elem, setting.pos, "")); } flake.config.settings.emplace(state.ctx.symbols[setting.name], ss); } else { @@ -449,7 +449,7 @@ static Flake getFlake( .make( "flake configuration setting '%s' is %s", state.ctx.symbols[setting.name], - showType(*setting.value) + showType(setting.value) ) .debugThrow(); } @@ -941,24 +941,24 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes) { - auto vLocks = state.ctx.mem.allocValue(); - auto vRootSrc = state.ctx.mem.allocValue(); - auto vRootSubdir = state.ctx.mem.allocValue(); - auto vTmp1 = state.ctx.mem.allocValue(); - auto vTmp2 = state.ctx.mem.allocValue(); + Value vLocks; + Value vRootSrc; + Value vRootSubdir; + Value vTmp1; + Value vTmp2; - vLocks->mkString(lockedFlake.lockFile.to_string()); + vLocks.mkString(lockedFlake.lockFile.to_string()); emitTreeAttrs( state.ctx, *lockedFlake.flake.sourceInfo, lockedFlake.flake.lockedRef.input, - *vRootSrc, + vRootSrc, false, lockedFlake.flake.forceDirty ); - vRootSubdir->mkString(lockedFlake.flake.lockedRef.subdir); + vRootSubdir.mkString(lockedFlake.flake.lockedRef.subdir); if (!state.ctx.caches.vCallFlake) { state.ctx.caches.vCallFlake = allocRootValue({}); @@ -971,9 +971,9 @@ void callFlake(EvalState & state, ); } - state.callFunction(*state.ctx.caches.vCallFlake, *vLocks, *vTmp1, noPos); - state.callFunction(*vTmp1, *vRootSrc, *vTmp2, noPos); - state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos); + state.callFunction(*state.ctx.caches.vCallFlake, vLocks, vTmp1, noPos); + state.callFunction(vTmp1, vRootSrc, vTmp2, noPos); + state.callFunction(vTmp2, vRootSubdir, vRes, noPos); } void prim_getFlake(EvalState & state, Value * * args, Value & v) @@ -1024,9 +1024,9 @@ void prim_flakeRefToString( "while evaluating the argument passed to builtins.flakeRefToString"); fetchers::Attrs attrs; for (const auto & attr : *args[0]->attrs()) { - auto t = attr.value->type(); + auto t = attr.value.type(); if (t == nInt) { - auto intValue = attr.value->integer().value; + auto intValue = attr.value.integer().value; if (intValue < 0) { state.ctx.errors.make("negative value given for flake ref attr %1%: %2%", state.ctx.symbols[attr.name], intValue).debugThrow(); @@ -1035,16 +1035,16 @@ void prim_flakeRefToString( attrs.emplace(state.ctx.symbols[attr.name], asUnsigned); } else if (t == nBool) { - attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value->boolean()}); + attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value.boolean()}); } else if (t == nString) { - attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value->str())); + attrs.emplace(state.ctx.symbols[attr.name], std::string(attr.value.str())); } else { state.ctx.errors .make( "flake reference attribute sets may only contain integers, Booleans, " "and strings, but attribute '%s' is %s", state.ctx.symbols[attr.name], - showType(*attr.value) + showType(attr.value) ) .debugThrow(); } diff --git a/lix/libexpr/gc-small-vector.hh b/lix/libexpr/gc-small-vector.hh index bbb1aefc3..225daeaf7 100644 --- a/lix/libexpr/gc-small-vector.hh +++ b/lix/libexpr/gc-small-vector.hh @@ -17,8 +17,8 @@ using SmallVector = boost::container::small_vector -using SmallValueVector = SmallVector; +template +using SmallValueVector = SmallVector; /** * A vector of values that must not be referenced after the vector is destroyed. diff --git a/lix/libexpr/get-drvs.cc b/lix/libexpr/get-drvs.cc index 47360819d..51587cc62 100644 --- a/lix/libexpr/get-drvs.cc +++ b/lix/libexpr/get-drvs.cc @@ -69,7 +69,7 @@ std::string DrvInfo::queryName(EvalState & state) state.ctx.errors.make("derivation name missing").debugThrow(); } name = state.forceStringNoCtx( - *i->value, noPos, "while evaluating the 'name' attribute of a derivation" + i->value, noPos, "while evaluating the 'name' attribute of a derivation" ); } return name; @@ -83,7 +83,7 @@ std::string DrvInfo::querySystem(EvalState & state) system = !i ? "unknown" : state.forceStringNoCtx( - *i->value, i->pos, "while evaluating the 'system' attribute of a derivation" + i->value, i->pos, "while evaluating the 'system' attribute of a derivation" ); } return system; @@ -100,7 +100,7 @@ std::optional DrvInfo::queryDrvPath(EvalState & state) } else { drvPath = {state.coerceToStorePath( i->pos, - *i->value, + i->value, context, "while evaluating the 'drvPath' attribute of a derivation" )}; @@ -125,7 +125,7 @@ StorePath DrvInfo::queryOutPath(EvalState & state) NixStringContext context; if (i) { outPath = state.coerceToStorePath( - i->pos, *i->value, context, "while evaluating the output path of a derivation" + i->pos, i->value, context, "while evaluating the output path of a derivation" ); } } @@ -158,17 +158,17 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths) // NOTE(Qyriad): I don't think there is any codepath that can cause this to error. state.forceList( - *outputs->value, outputs->pos, "while evaluating the 'outputs' attribute of a derivation" + outputs->value, outputs->pos, "while evaluating the 'outputs' attribute of a derivation" ); - for (auto [idx, elem] : enumerate(outputs->value->listItems())) { + for (auto && [idx, elem] : enumerate(outputs->value.listItems())) { // NOTE(Qyriad): This error should be *extremely* rare in practice. // It is impossible to construct with `stdenv.mkDerivation`, // `builtins.derivation`, or even `derivationStrict`. As far as we can tell, // it is only possible by overriding a derivation attrset already created by // one of those with `//` to introduce the failing `outputs` entry. auto errMsg = fmt("while evaluating output %d of a derivation", idx); - std::string_view outputName = state.forceStringNoCtx(*elem, outputs->pos, errMsg); + std::string_view outputName = state.forceStringNoCtx(elem, outputs->pos, errMsg); if (withPaths) { // Find the attr with this output's name... @@ -180,10 +180,10 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths) // Meanwhile we couldn't figure out any circumstances // that cause this to error. - state.forceAttrs(*out->value, outputs->pos, errMsg); + state.forceAttrs(out->value, outputs->pos, errMsg); // ...and evaluate its `outPath` attribute. - const Attr * outPath = out->value->attrs()->get(state.ctx.s.outPath); + const Attr * outPath = out->value.attrs()->get(state.ctx.s.outPath); if (outPath == nullptr) { continue; // FIXME: throw error? @@ -192,8 +192,7 @@ void DrvInfo::fillOutputs(EvalState & state, bool withPaths) NixStringContext context; // And idk what could possibly cause this one to error // that wouldn't error before here. - auto storePath = - state.coerceToStorePath(outPath->pos, *outPath->value, context, errMsg); + auto storePath = state.coerceToStorePath(outPath->pos, outPath->value, context, errMsg); this->outputs.emplace(outputName, storePath); } else { this->outputs.emplace(outputName, std::nullopt); @@ -225,7 +224,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state, bool withPaths, bool o // explicitly selected-into output. if (const Attr * outSpecAttr = attrs->get(state.ctx.s.outputSpecified)) { bool outputSpecified = state.forceBool( - *outSpecAttr->value, + outSpecAttr->value, outSpecAttr->pos, "while evaluating the 'outputSpecified' attribute of a derivation" ); @@ -245,16 +244,16 @@ DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state, bool withPaths, bool o /* ^ this shows during `nix-env -i` right under the bad derivation */ if (!outTI->isList()) throw Error(errMsg + "expected a list but got %s", Uncolored(showType(outTI->type()))); Outputs result; - for (auto elem : outTI->listItems()) { - if (elem->type() != nString) { + for (auto & elem : outTI->listItems()) { + if (elem.type() != nString) { throw Error( errMsg + "element is %s where a string was expected", - Uncolored(showType(elem->type())) + Uncolored(showType(elem.type())) ); } - auto out = outputs.find(std::string(elem->str())); + auto out = outputs.find(std::string(elem.str())); if (out == outputs.end()) { - throw Error(errMsg + "output '%s' does not exist", elem->str()); + throw Error(errMsg + "output '%s' does not exist", elem.str()); } result.insert(*out); } @@ -267,7 +266,7 @@ std::string DrvInfo::queryOutputName(EvalState & state) if (outputName == "" && attrs) { auto i = attrs->get(state.ctx.s.outputName); outputName = i ? state.forceStringNoCtx( - *i->value, noPos, "while evaluating the output name of a derivation" + i->value, noPos, "while evaluating the output name of a derivation" ) : ""; } @@ -283,8 +282,8 @@ Bindings * DrvInfo::getMeta(EvalState & state) if (!a) { return 0; } - state.forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation"); - meta = a->value->attrs(); + state.forceAttrs(a->value, a->pos, "while evaluating the 'meta' attribute of a derivation"); + meta = a->value.attrs(); return meta; } @@ -303,8 +302,8 @@ bool DrvInfo::checkMeta(EvalState & state, Value & v) { state.forceValue(v, noPos); if (v.type() == nList) { - for (auto elem : v.listItems()) { - if (!checkMeta(state, *elem)) { + for (auto & elem : v.listItems()) { + if (!checkMeta(state, elem)) { return false; } } @@ -316,7 +315,7 @@ bool DrvInfo::checkMeta(EvalState & state, Value & v) return false; } for (auto & i : *v.attrs()) { - if (!checkMeta(state, *i.value)) { + if (!checkMeta(state, i.value)) { return false; } } @@ -331,10 +330,10 @@ Value * DrvInfo::queryMeta(EvalState & state, const std::string & name) { if (!getMeta(state)) return 0; auto a = meta->get(state.ctx.symbols.create(name)); - if (!a || !checkMeta(state, *a->value)) { + if (!a || !checkMeta(state, a->value)) { return 0; } - return a->value; + return &a->value; } @@ -392,7 +391,7 @@ void DrvInfo::setMeta(EvalState & state, const std::string & name, Value & v) for (auto i : *meta) if (i.name != sym) attrs.insert(i); - attrs.insert(sym, &v); + attrs.insert(sym, v); meta = attrs.finish(); } @@ -464,13 +463,13 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos, if (v.type() == nList) { // NOTE we can't really deduplicate here because small lists don't have stable addresses // and can cause spurious duplicate detections due to v being on the stack. - for (auto [n, elem] : enumerate(v.listItems())) { + for (auto && [n, elem] : enumerate(v.listItems())) { std::string joinedAttrPath = addToPath(pathPrefix, fmt("%d", n)); bool shouldRecurse = - getDerivation(state, *elem, joinedAttrPath, drvs, ignoreAssertionFailures); + getDerivation(state, elem, joinedAttrPath, drvs, ignoreAssertionFailures); if (shouldRecurse) { getDerivations( - state, *elem, pos, joinedAttrPath, autoArgs, drvs, done, ignoreAssertionFailures + state, elem, pos, joinedAttrPath, autoArgs, drvs, done, ignoreAssertionFailures ); } } @@ -510,7 +509,7 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos, if (combineChannels) { getDerivations( state, - *attr->value, + attr->value, attr->pos, joinedAttrPath, autoArgs, @@ -518,18 +517,19 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos, done, ignoreAssertionFailures ); - } else if (getDerivation(state, *attr->value, joinedAttrPath, drvs, ignoreAssertionFailures)) { + } else if (getDerivation(state, attr->value, joinedAttrPath, drvs, ignoreAssertionFailures)) + { /* If the value of this attribute is itself a set, should we recurse into it? => Only if it has a `recurseForDerivations = true' attribute. */ - if (attr->value->type() == nAttrs) { + if (attr->value.type() == nAttrs) { const Attr * recurseForDrvs = - attr->value->attrs()->get(state.ctx.s.recurseForDerivations); + attr->value.attrs()->get(state.ctx.s.recurseForDerivations); if (recurseForDrvs == nullptr) { continue; } bool shouldRecurse = state.forceBool( - *recurseForDrvs->value, + recurseForDrvs->value, attr->pos, fmt("while evaluating the '%s' attribute", Magenta("recurseForDerivations")) ); @@ -539,7 +539,7 @@ static void getDerivations(EvalState & state, Value & vIn, PosIdx pos, getDerivations( state, - *attr->value, + attr->value, attr->pos, joinedAttrPath, autoArgs, diff --git a/lix/libexpr/json-to-value.cc b/lix/libexpr/json-to-value.cc index 70003ef99..ea64d1884 100644 --- a/lix/libexpr/json-to-value.cc +++ b/lix/libexpr/json-to-value.cc @@ -23,7 +23,7 @@ class JSONSax : nlohmann::json_sax { explicit JSONState(std::unique_ptr && p) : parent(std::move(p)) {} JSONState() = default; JSONState(JSONState & p) = delete; - Value & value(EvalState & state) + Value & value() { if (!v) { v = allocRootValue({}); @@ -31,7 +31,7 @@ class JSONSax : nlohmann::json_sax { return *v; } virtual ~JSONState() {} - virtual void add(EvalState & state) {} + virtual void add() {} }; class JSONObjectState : public JSONState { @@ -41,17 +41,14 @@ class JSONSax : nlohmann::json_sax { std::unique_ptr resolve(EvalState & state) override { auto attrs2 = state.ctx.buildBindings(attrs.size()); - for (auto & i : attrs) { - auto v = state.ctx.mem.allocValue(); - *v = i.second; - attrs2.insert(i.first, v); - } - parent->value(state).mkAttrs(attrs2.alreadySorted()); + for (auto & i : attrs) + attrs2.insert(i.first, i.second); + parent->value().mkAttrs(attrs2.alreadySorted()); return std::move(parent); } - void add(EvalState & state) override + void add() override { - attrs.insert_or_assign(_key, value(state)); + attrs.insert_or_assign(_key, value()); v = nullptr; } public: @@ -66,13 +63,13 @@ class JSONSax : nlohmann::json_sax { std::unique_ptr resolve(EvalState & state) override { auto list = state.ctx.mem.newList(values.size()); - parent->value(state) = {NewValueAs::list, list}; + parent->value() = {NewValueAs::list, list}; for (size_t n = 0; n < values.size(); ++n) { - *(list->elems[n] = state.ctx.mem.allocValue()) = values[n]; + list->elems[n] = values[n]; } return std::move(parent); } - void add(EvalState & state) override + void add() override { values.push_back(*v); v = nullptr; @@ -92,27 +89,27 @@ public: Value result() { - return rs->value(state); + return rs->value(); } bool null() override { - rs->value(state).mkNull(); - rs->add(state); + rs->value().mkNull(); + rs->add(); return true; } bool boolean(bool val) override { - rs->value(state).mkBool(val); - rs->add(state); + rs->value().mkBool(val); + rs->add(); return true; } bool number_integer(number_integer_t val) override { - rs->value(state).mkInt(val); - rs->add(state); + rs->value().mkInt(val); + rs->add(); return true; } @@ -124,22 +121,22 @@ public: return number_float(static_cast(val_), ""); } NixInt::Inner val = val_; - rs->value(state).mkInt(val); - rs->add(state); + rs->value().mkInt(val); + rs->add(); return true; } bool number_float(number_float_t val, const string_t & s) override { - rs->value(state).mkFloat(val); - rs->add(state); + rs->value().mkFloat(val); + rs->add(); return true; } bool string(string_t & val) override { - rs->value(state).mkString(val); - rs->add(state); + rs->value().mkString(val); + rs->add(); return true; } @@ -166,7 +163,7 @@ public: bool end_object() override { rs = rs->resolve(state); - rs->add(state); + rs->add(); return true; } diff --git a/lix/libexpr/nixexpr.hh b/lix/libexpr/nixexpr.hh index d1b0c6509..1fc708a5e 100644 --- a/lix/libexpr/nixexpr.hh +++ b/lix/libexpr/nixexpr.hh @@ -127,7 +127,7 @@ public: virtual JSON toJSON(const SymbolTable & symbols) const; virtual void accept(ExprVisitor & ev, std::unique_ptr & ptr) = 0; virtual void eval(EvalState & state, Env & env, Value & v); - virtual Value * maybeThunk(EvalState & state, Env & env); + virtual Value maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); PosIdx getPos() const { return pos; } @@ -175,7 +175,7 @@ protected: Value v; ExprLiteral(const PosIdx pos) : Expr(pos) {}; public: - Value * maybeThunk(EvalState & state, Env & env) override; + Value maybeThunk(EvalState & state, Env & env) override; JSON toJSON(const SymbolTable & symbols) const override; void eval(EvalState & state, Env & env, Value & v) override; void accept(ExprVisitor & ev, std::unique_ptr & ptr) override { ev.visit(*this, ptr); } @@ -253,7 +253,7 @@ struct ExprVar : Expr ExprVar(Symbol name) : name(name), needsRoot(false) { }; ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : Expr(pos), name(name), needsRoot(needsRoot) { }; - Value * maybeThunk(EvalState & state, Env & env) override; + Value maybeThunk(EvalState & state, Env & env) override; JSON toJSON(const SymbolTable & symbols) const override; void eval(EvalState & state, Env & env, Value & v) override; void accept(ExprVisitor & ev, std::unique_ptr & ptr) override { ev.visit(*this, ptr); } @@ -395,7 +395,7 @@ struct ExprList : Expr JSON toJSON(const SymbolTable & symbols) const override; void eval(EvalState & state, Env & env, Value & v) override; void accept(ExprVisitor & ev, std::unique_ptr & ptr) override { ev.visit(*this, ptr); } - Value * maybeThunk(EvalState & state, Env & env) override; + Value maybeThunk(EvalState & state, Env & env) override; }; struct Pattern { diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 600c25188..b320987e0 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -189,11 +189,10 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v) for (const auto & [i, o] : enumerate(drv.outputs)) { mkOutputString(state, attrs, *storePath, o); - (outputsList->elems[i] = state.ctx.mem.allocValue())->mkString(o.first); + outputsList->elems[i].mkString(o.first); } - auto w = state.ctx.mem.allocValue(); - w->mkAttrs(attrs); + Value w{NewValueAs::attrs, attrs.finish()}; if (!state.ctx.caches.vImportedDrvToDerivation) { state.ctx.caches.vImportedDrvToDerivation = allocRootValue({}); @@ -211,7 +210,7 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v) noPos, "while evaluating imported-drv-to-derivation.nix.gen.hh" ); - v = {NewValueAs::app, state.ctx.mem, *state.ctx.caches.vImportedDrvToDerivation, *w}; + v = {NewValueAs::app, state.ctx.mem, *state.ctx.caches.vImportedDrvToDerivation, w}; state.forceAttrs(v, noPos, "while calling imported-drv-to-derivation.nix.gen.hh"); } @@ -307,7 +306,7 @@ void prim_exec(EvalState & state, Value * * args, Value & v) state .coerceToString( noPos, - *elems[0], + elems[0], context, "while evaluating the first element of the argument passed to builtins.exec", StringCoercionMode::Strict, @@ -320,7 +319,7 @@ void prim_exec(EvalState & state, Value * * args, Value & v) state .coerceToString( noPos, - *elems[i], + elems[i], context, "while evaluating an element of the argument passed to builtins.exec", StringCoercionMode::Strict, @@ -489,12 +488,12 @@ struct CompareValues : NeverAsync } else if (i == v1.listSize()) { return true; } else if (!state.eqValues( - *v1.listElems()[i], *v2.listElems()[i], noPos, errorCtx + v1.listElems()[i], v2.listElems()[i], noPos, errorCtx )) { return (*this)( - *v1.listElems()[i], - *v2.listElems()[i], + v1.listElems()[i], + v2.listElems()[i], "while comparing two list elements" ); } @@ -547,18 +546,18 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) ); state.forceList( - *startSet->value, + startSet->value, noPos, "while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure" ); UnsafeValueList workSet; - for (auto elem : startSet->value->listItems()) { - workSet.push_back(elem); + for (auto & elem : startSet->value.listItems()) { + workSet.push_back(&elem); } - if (startSet->value->listSize() == 0) { - v = *startSet->value; + if (startSet->value.listSize() == 0) { + v = startSet->value; return; } @@ -570,7 +569,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) "in the attrset passed as argument to builtins.genericClosure" ); state.forceFunction( - *op->value, + op->value, noPos, "while evaluating the 'operator' attribute passed as argument to builtins.genericClosure" ); @@ -595,22 +594,23 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) e->attrs(), "in one of the attrsets generated by (or initially passed to) builtins.genericClosure" ); - state.forceValue(*key->value, noPos); + state.forceValue(key->value, noPos); - if (!doneKeys.insert(key->value).second) { + if (!doneKeys.insert(&key->value).second) { continue; } res.push_back(e); /* Call the `operator' function with `e' as argument. */ Value newElements; - state.callFunction(*op->value, {&e, 1}, newElements, noPos); + state.callFunction(op->value, {e, 1}, newElements, noPos); state.forceList(newElements, noPos, "while evaluating the return value of the `operator` passed to builtins.genericClosure"); /* Add the values returned by the operator to the work set. */ - for (auto elem : newElements.listItems()) { - state.forceValue(*elem, noPos); // "while evaluating one one of the elements returned by the `operator` passed to builtins.genericClosure"); - workSet.push_back(elem); + for (auto & elem : newElements.listItems()) { + state.forceValue(elem, noPos); // "while evaluating one one of the elements returned by + // the `operator` passed to builtins.genericClosure"); + workSet.push_back(&elem); } } @@ -619,7 +619,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) v = {NewValueAs::list, result}; unsigned int n = 0; for (auto & i : res) - result->elems[n++] = i; + result->elems[n++] = *i; } @@ -719,7 +719,7 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v) return true; }(); if (success) - attrs.insert(state.ctx.s.value, args[0]); + attrs.insert(state.ctx.s.value, *args[0]); else attrs.alloc(state.ctx.s.value).mkBool(false); attrs.alloc("success").mkBool(success); @@ -810,7 +810,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) std::string drvName; try { drvName = state.forceStringNoCtx( - *nameAttr->value, + nameAttr->value, noPos, "while evaluating the `name` attribute passed to builtins.derivationStrict" ); @@ -858,7 +858,7 @@ drvName, Bindings * attrs, Value & v) auto attr = attrs->get(state.ctx.s.structuredAttrs); if (attr && state.forceBool( - *attr->value, + attr->value, attr->pos, "while evaluating the `__structuredAttrs` " "attribute passed to builtins.derivationStrict" @@ -872,7 +872,7 @@ drvName, Bindings * attrs, Value & v) attr = attrs->get(state.ctx.s.ignoreNulls); if (attr) { ignoreNulls = state.forceBool( - *attr->value, + attr->value, attr->pos, "while evaluating the `__ignoreNulls` attribute " "passed to builtins.derivationStrict" @@ -933,21 +933,21 @@ drvName, Bindings * attrs, Value & v) const std::string_view context_below(""); if (ignoreNulls) { - state.forceValue(*i->value, noPos); - if (i->value->type() == nNull) { + state.forceValue(i->value, noPos); + if (i->value.type() == nNull) { continue; } } if (i->name == state.ctx.s.contentAddressed - && state.forceBool(*i->value, noPos, context_below)) + && state.forceBool(i->value, noPos, context_below)) { state.ctx.errors.make("ca derivations are not supported in Lix") .debugThrow(); } else if (i->name == state.ctx.s.impure - && state.forceBool(*i->value, noPos, context_below)) + && state.forceBool(i->value, noPos, context_below)) { state.ctx.errors.make("impure derivations are not supported in Lix") .debugThrow(); @@ -957,12 +957,12 @@ drvName, Bindings * attrs, Value & v) command-line arguments to the builder. */ else if (i->name == state.ctx.s.args) { - state.forceList(*i->value, noPos, context_below); - for (auto elem : i->value->listItems()) { + state.forceList(i->value, noPos, context_below); + for (auto & elem : i->value.listItems()) { auto s = state .coerceToString( noPos, - *elem, + elem, context, "while evaluating an element of the argument list", StringCoercionMode::ToString @@ -982,24 +982,24 @@ drvName, Bindings * attrs, Value & v) if (i->name == state.ctx.s.structuredAttrs) continue; (*jsonObject)[std::string(key)] = - printValueAsJSON(state, true, *i->value, noPos, context); + printValueAsJSON(state, true, i->value, noPos, context); if (i->name == state.ctx.s.builder) - drv.builder = state.forceString(*i->value, context, noPos, context_below); + drv.builder = state.forceString(i->value, context, noPos, context_below); else if (i->name == state.ctx.s.system) - drv.platform = state.forceStringNoCtx(*i->value, noPos, context_below); + drv.platform = state.forceStringNoCtx(i->value, noPos, context_below); else if (i->name == state.ctx.s.outputHash) - outputHash = state.forceStringNoCtx(*i->value, noPos, context_below); + outputHash = state.forceStringNoCtx(i->value, noPos, context_below); else if (i->name == state.ctx.s.outputHashAlgo) - outputHashAlgo = state.forceStringNoCtx(*i->value, noPos, context_below); + outputHashAlgo = state.forceStringNoCtx(i->value, noPos, context_below); else if (i->name == state.ctx.s.outputHashMode) - handleHashMode(state.forceStringNoCtx(*i->value, noPos, context_below)); + handleHashMode(state.forceStringNoCtx(i->value, noPos, context_below)); else if (i->name == state.ctx.s.outputs) { /* Require ‘outputs’ to be a list of strings. */ - state.forceList(*i->value, noPos, context_below); + state.forceList(i->value, noPos, context_below); Strings ss; - for (auto elem : i->value->listItems()) { - ss.emplace_back(state.forceStringNoCtx(*elem, noPos, context_below)); + for (auto & elem : i->value.listItems()) { + ss.emplace_back(state.forceStringNoCtx(elem, noPos, context_below)); } handleOutputs(ss); } @@ -1051,7 +1051,7 @@ drvName, Bindings * attrs, Value & v) auto s = state .coerceToString( noPos, - *i->value, + i->value, context, context_below, StringCoercionMode::ToString @@ -1381,29 +1381,29 @@ static void prim_findFile(EvalState & state, Value * * args, Value & v) SearchPath searchPath; - for (auto v2 : args[0]->listItems()) { + for (auto & v2 : args[0]->listItems()) { state.forceAttrs( - *v2, noPos, "while evaluating an element of the list passed to builtins.findFile" + v2, noPos, "while evaluating an element of the list passed to builtins.findFile" ); std::string prefix; - auto i = v2->attrs()->get(state.ctx.s.prefix); + auto i = v2.attrs()->get(state.ctx.s.prefix); if (i) { prefix = state.forceStringNoCtx( - *i->value, + i->value, noPos, "while evaluating the `prefix` attribute of an element of the list passed to " "builtins.findFile" ); } - i = getAttr(state, state.ctx.s.path, v2->attrs(), "in an element of the __nixPath"); + i = getAttr(state, state.ctx.s.path, v2.attrs(), "in an element of the __nixPath"); NixStringContext context; auto path = state .coerceToString( noPos, - *i->value, + i->value, context, "while evaluating the `path` attribute of an element of the list " "passed to builtins.findFile", @@ -1488,11 +1488,11 @@ static void prim_readDir(EvalState & state, Value * * args, Value & v) // Some filesystems or operating systems may not be able to return // detailed node info quickly in this case we produce a thunk to // query the file type lazily. - auto epath = state.ctx.mem.allocValue(); - epath->mkPath(path + name); + Value epath; + epath.mkPath(path + name); if (!readFileType) readFileType = &state.ctx.builtins.get("readFileType"); - attr = {NewValueAs::app, state.ctx.mem, *readFileType, *epath}; + attr = {NewValueAs::app, state.ctx.mem, *readFileType, epath}; } else { // This branch of the conditional is much more likely. // Here we just stringize the directory entry type. @@ -1630,7 +1630,7 @@ static void addPath( S_ISLNK(st.st_mode) ? "symlink" : "unknown" /* not supported, will fail! */); - Value * args []{&arg1, &arg2}; + Value args[]{arg1, arg2}; Value res; state.callFunction(*filterFun, args, res, noPos); @@ -1697,32 +1697,32 @@ static void prim_path(EvalState & state, Value * * args, Value & v) if (n == "path") { path.emplace(state.coerceToPath( attr.pos, - *attr.value, + attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'" )); } else if (attr.name == state.ctx.s.name) { name = state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.path" ); } else if (n == "filter") { state.forceFunction( - *(filterFun = attr.value), + *(filterFun = &attr.value), attr.pos, "while evaluating the `filter` parameter passed to builtins.path" ); } else if (n == "recursive") { method = FileIngestionMethod{state.forceBool( - *attr.value, + attr.value, attr.pos, "while evaluating the `recursive` attribute passed to builtins.path" )}; } else if (n == "sha256") { expectedHash = newHashAllowEmpty( state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the `sha256` attribute passed to builtins.path" ), @@ -1764,10 +1764,10 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) size_t n = 0; for (auto & i : *args[0]->attrs()) - result->elems[n++] = const_cast(state.ctx.symbols[i.name].toValuePtr()); + result->elems[n++] = state.ctx.symbols[i.name].toValue(); - std::sort(result->elems, result->elems + n, [](Value * v1, Value * v2) { - return v1->str() < v2->str(); + std::sort(result->elems, result->elems + n, [](Value & v1, Value & v2) { + return v1.str() < v2.str(); }); } @@ -1809,8 +1809,8 @@ void prim_getAttr(EvalState & state, Value * * args, Value & v) ); // !!! add to stack trace? if (state.ctx.stats.countCalls && i->pos) state.ctx.stats.attrSelects[i->pos]++; - state.forceValue(*i->value, noPos); - v = *i->value; + state.forceValue(i->value, noPos); + v = i->value; } /* Return position information of the specified attribute. */ @@ -1859,10 +1859,9 @@ static struct LazyPosAcessors { void operator()(EvalState & state, const PosIdx pos, Value & line, Value & column) { - Value * posV = state.ctx.mem.allocValue(); - posV->mkInt(pos.id); - line = {NewValueAs::app, state.ctx.mem, lineOfPos, *posV}; - column = {NewValueAs::app, state.ctx.mem, columnOfPos, *posV}; + Value posV{NewValueAs::integer, NixInt{pos.id}}; + line = {NewValueAs::app, state.ctx.mem, lineOfPos, posV}; + column = {NewValueAs::app, state.ctx.mem, columnOfPos, posV}; } } makeLazyPosAccessors; @@ -1897,13 +1896,13 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) // 64: large enough to fit the attributes of a derivation boost::container::small_vector names; names.reserve(args[1]->listSize()); - for (auto elem : args[1]->listItems()) { + for (auto & elem : args[1]->listItems()) { state.forceStringNoCtx( - *elem, + elem, noPos, "while evaluating the values of the second argument passed to builtins.removeAttrs" ); - names.emplace_back(state.ctx.symbols.create(elem->str()), nullptr); + names.emplace_back(state.ctx.symbols.create(elem.str()), Value()); } std::sort(names.begin(), names.end()); @@ -1931,15 +1930,15 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) std::set seen; - for (auto v2 : args[0]->listItems()) { + for (auto & v2 : args[0]->listItems()) { state.forceAttrs( - *v2, noPos, "while evaluating an element of the list passed to builtins.listToAttrs" + v2, noPos, "while evaluating an element of the list passed to builtins.listToAttrs" ); - auto j = getAttr(state, state.ctx.s.name, v2->attrs(), "in a {name=...; value=...;} pair"); + auto j = getAttr(state, state.ctx.s.name, v2.attrs(), "in a {name=...; value=...;} pair"); auto name = state.forceStringNoCtx( - *j->value, + j->value, j->pos, "while evaluating the `name` attribute of an element of the list passed to " "builtins.listToAttrs" @@ -1948,7 +1947,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) auto sym = state.ctx.symbols.create(name); if (seen.insert(sym).second) { auto j2 = - getAttr(state, state.ctx.s.value, v2->attrs(), "in a {name=...; value=...;} pair"); + getAttr(state, state.ctx.s.value, v2.attrs(), "in a {name=...; value=...;} pair"); attrs.insert(sym, j2->value, j2->pos); } } @@ -2032,13 +2031,13 @@ static void prim_catAttrs(EvalState & state, Value * * args, Value & v) SmallValueVector res(args[1]->listSize()); size_t found = 0; - for (auto v2 : args[1]->listItems()) { + for (auto & v2 : args[1]->listItems()) { state.forceAttrs( - *v2, + v2, noPos, "while evaluating an element in the list passed as second argument to builtins.catAttrs" ); - auto i = v2->attrs()->get(attrName); + auto i = v2.attrs()->get(attrName); if (i) { res[found++] = i->value; } @@ -2082,8 +2081,8 @@ static void prim_mapAttrs(EvalState & state, Value * * args, Value & v) auto attrs = state.ctx.buildBindings(args[1]->attrs()->size()); for (auto & i : *args[1]->attrs()) { - auto vName = const_cast(state.ctx.symbols[i.name].toValuePtr()); - Value * appArgs[] = {vName, i.value}; + 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}; } @@ -2099,7 +2098,7 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v) // attribute with the merge function application. this way we need not // use (slightly slower) temporary storage the GC does not know about. - std::map> attrsSeen; + std::map> attrsSeen; state.forceFunction(*args[0], noPos, "while evaluating the first argument passed to builtins.zipAttrsWith"); state.forceList(*args[1], noPos, "while evaluating the second argument passed to builtins.zipAttrsWith"); @@ -2107,14 +2106,14 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v) const auto listElems = args[1]->listElems(); for (unsigned int n = 0; n < listSize; ++n) { - Value * vElem = listElems[n]; + Value & vElem = listElems[n]; state.forceAttrs( - *vElem, + vElem, noPos, "while evaluating a value of the list passed as second argument to " "builtins.zipAttrsWith" ); - for (auto & attr : *vElem->attrs()) { + for (auto & attr : *vElem.attrs()) { attrsSeen[attr.name].first++; } } @@ -2122,16 +2121,14 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v) auto attrs = state.ctx.buildBindings(attrsSeen.size()); for (auto & [sym, elem] : attrsSeen) { /* Take care of the returned lists. */ - auto list = state.ctx.mem.allocValue(); auto content = state.ctx.mem.newList(elem.first); - *list = {NewValueAs::list, content}; + Value list{NewValueAs::list, content}; elem.second = content->elems; /* Construct a `fn name list` function call value. */ - auto name = const_cast(state.ctx.symbols[sym].toValuePtr()); - Value * callArgs[] = {name, list}; - auto call = state.ctx.mem.allocValue(); - *call = {NewValueAs::app, state.ctx.mem, *args[0], callArgs}; + auto name = state.ctx.symbols[sym].toValue(); + Value callArgs[] = {name, list}; + Value call{NewValueAs::app, state.ctx.mem, *args[0], callArgs}; /* Insert it inside the returned attribute set. */ attrs.insert(sym, call); @@ -2139,8 +2136,8 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v) /* Populate the lists inside the attribute set */ for (unsigned int n = 0; n < listSize; ++n) { - Value * vElem = listElems[n]; - for (auto & attr : *vElem->attrs()) { + Value & vElem = listElems[n]; + for (auto & attr : *vElem.attrs()) { *attrsSeen[attr.name].second++ = attr.value; } } @@ -2167,8 +2164,8 @@ static void elemAt(EvalState & state, Value & list, NixInt::Inner n, Value & v) if (n < 0 || std::make_unsigned_t(n) >= list.listSize()) { state.ctx.errors.make("list index %1% is out of bounds", n).debugThrow(); } - state.forceValue(*list.listElems()[n], noPos); - v = *list.listElems()[n]; + state.forceValue(list.listElems()[n], noPos); + v = list.listElems()[n]; } /* Return the n-1'th element of a list. */ @@ -2214,8 +2211,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v) auto result = state.ctx.mem.newList(args[1]->listSize()); v = {NewValueAs::list, result}; for (unsigned int n = 0; n < v.listSize(); ++n) { - result->elems[n] = state.ctx.mem.allocValue(); - *result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], *args[1]->listElems()[n]}; + result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], args[1]->listElems()[n]}; } } @@ -2240,7 +2236,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v) bool same = true; for (size_t n = 0; n < len; ++n) { Value res; - state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos); + state.callFunction(*args[0], args[1]->listElems()[n], res, noPos); if (state.forceBool(res, noPos, "while evaluating the return value of the filtering function passed to builtins.filter")) vs[k++] = args[1]->listElems()[n]; else @@ -2263,10 +2259,10 @@ static void prim_elem(EvalState & state, Value * * args, Value & v) { bool res = false; state.forceList(*args[1], noPos, "while evaluating the second argument passed to builtins.elem"); - for (auto elem : args[1]->listItems()) { + for (auto & elem : args[1]->listItems()) { if (state.eqValues( *args[0], - *elem, + elem, noPos, "while searching for the presence of the given element in the list" )) @@ -2284,8 +2280,7 @@ static void prim_concatLists(EvalState & state, Value * * args, Value & v) state.forceList(*args[0], noPos, "while evaluating the first argument passed to builtins.concatLists"); state.concatLists( v, - args[0]->listSize(), - args[0]->listElems(), + std::span{args[0]->listElems(), args[0]->listSize()}, noPos, "while evaluating a value of the list passed to builtins.concatLists" ); @@ -2306,13 +2301,13 @@ static void prim_foldlStrict(EvalState & state, Value * * args, Value & v) state.forceList(*args[2], noPos, "while evaluating the third argument passed to builtins.foldlStrict"); if (args[2]->listSize()) { - Value * vCur = args[1]; + Value vCur = *args[1]; - for (auto [n, elem] : enumerate(args[2]->listItems())) { - Value * vs []{vCur, elem}; - vCur = n == args[2]->listSize() - 1 ? &v : state.ctx.mem.allocValue(); - state.callFunction(*args[0], vs, *vCur, noPos); + for (auto && [n, elem] : enumerate(args[2]->listItems())) { + Value vs[]{vCur, elem}; + state.callFunction(*args[0], vs, vCur, noPos); } + v = vCur; state.forceValue(v, noPos); } else { state.forceValue(*args[1], noPos); @@ -2330,8 +2325,8 @@ static void anyOrAll(bool any, EvalState & state, Value * * args, Value & v) : "while evaluating the return value of the function passed to builtins.all"; Value vTmp; - for (auto elem : args[1]->listItems()) { - state.callFunction(*args[0], *elem, vTmp, noPos); + for (auto & elem : args[1]->listItems()) { + state.callFunction(*args[0], elem, vTmp, noPos); bool res = state.forceBool(vTmp, noPos, errorCtx); if (res == any) { v.mkBool(any); @@ -2371,10 +2366,8 @@ static void prim_genList(EvalState & state, Value * * args, Value & v) auto result = state.ctx.mem.newList(len); v = {NewValueAs::list, result}; for (size_t n = 0; n < len; ++n) { - auto arg = state.ctx.mem.allocValue(); - arg->mkInt(n); - result->elems[n] = state.ctx.mem.allocValue(); - *result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], *arg}; + Value arg{NewValueAs::integer, NixInt{ssize_t(n)}}; + result->elems[n] = {NewValueAs::app, state.ctx.mem, *args[0], arg}; } } @@ -2396,11 +2389,11 @@ static void prim_sort(EvalState & state, Value * * args, Value & v) auto list = state.ctx.mem.newList(len); v = {NewValueAs::list, list}; for (unsigned int n = 0; n < len; ++n) { - state.forceValue(*args[1]->listElems()[n], noPos); + state.forceValue(args[1]->listElems()[n], noPos); list->elems[n] = args[1]->listElems()[n]; } - auto comparator = [&](Value * a, Value * b) { + auto comparator = [&](Value a, Value b) { /* Optimization: if the comparator is lessThan, bypass callFunction. */ /* TODO: (layus) this is absurd. An optimisation like this @@ -2408,10 +2401,10 @@ static void prim_sort(EvalState & state, Value * * args, Value & v) if (args[0]->isPrimOp()) { auto ptr = args[0]->primOp()->fun.target(); if (ptr && *ptr == prim_lessThan) - return CompareValues(state, "while evaluating the ordering function passed to builtins.sort")(*a, *b); + return CompareValues(state, "while evaluating the ordering function passed to builtins.sort")(a, b); } - Value * vs[] = {a, b}; + Value vs[] = {a, b}; Value vBool; state.callFunction(*args[0], vs, vBool, noPos); return state.forceBool(vBool, noPos, "while evaluating the return value of the sorting function passed to builtins.sort"); @@ -2434,10 +2427,10 @@ static void prim_partition(EvalState & state, Value * * args, Value & v) std::vector right, wrong; for (size_t n = 0; n < len; ++n) { - auto vElem = elems[n]; - state.forceValue(*vElem, noPos); + auto & vElem = args[1]->listElems()[n]; + state.forceValue(vElem, noPos); Value res; - state.callFunction(*args[0], *vElem, res, noPos); + state.callFunction(*args[0], vElem, res, noPos); if (state.forceBool(res, noPos, "while evaluating the return value of the partition function passed to builtins.partition")) right.push_back(n); else @@ -2476,7 +2469,7 @@ static void prim_groupBy(EvalState & state, Value * * args, Value & v) for (auto [i, vElem] : enumerate(args[1]->listItems())) { Value res; - state.callFunction(*args[0], *vElem, res, noPos); + state.callFunction(*args[0], vElem, res, noPos); auto name = state.forceStringNoCtx(res, noPos, "while evaluating the return value of the grouping function passed to builtins.groupBy"); auto sym = state.ctx.symbols.create(name); auto vector = attrs.try_emplace(sym, std::vector()).first; @@ -2509,8 +2502,8 @@ static void prim_concatMap(EvalState & state, Value * * args, Value & v) size_t len = 0; for (size_t n = 0; n < nrLists; ++n) { - Value * vElem = args[1]->listElems()[n]; - state.callFunction(*args[0], *vElem, lists[n], noPos); + Value & vElem = args[1]->listElems()[n]; + state.callFunction(*args[0], vElem, lists[n], noPos); state.forceList(lists[n], noPos, "while evaluating the return value of the function passed to builtins.concatMap"); len += lists[n].listSize(); } @@ -2521,7 +2514,7 @@ static void prim_concatMap(EvalState & state, Value * * args, Value & v) for (unsigned int n = 0, pos = 0; n < nrLists; ++n) { auto l = lists[n].listSize(); if (l) { - memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *)); + std::copy(lists[n].listItems().begin(), lists[n].listItems().end(), out + pos); } pos += l; } @@ -2785,9 +2778,9 @@ void prim_match(EvalState & state, Value * * args, Value & v) v = {NewValueAs::list, result}; for (size_t i = 0; i < len; ++i) { if (!match[i+1].matched) - (result->elems[i] = state.ctx.mem.allocValue())->mkNull(); + result->elems[i].mkNull(); else - (result->elems[i] = state.ctx.mem.allocValue())->mkString(match[i + 1].str()); + result->elems[i].mkString(match[i + 1].str()); } } catch (regex::Error & e) { @@ -2818,7 +2811,7 @@ void prim_split(EvalState & state, Value * * args, Value & v) size_t idx = 0; if (len == 0) { - result->elems[idx++] = args[1]; + result->elems[idx++] = *args[1]; return; } @@ -2827,26 +2820,25 @@ void prim_split(EvalState & state, Value * * args, Value & v) auto match = *i; // Add a string for non-matched characters. - (result->elems[idx++] = state.ctx.mem.allocValue())->mkString(match.prefix().str()); + result->elems[idx++].mkString(match.prefix().str()); // Add a list for matched substrings. const size_t slen = match.size() - 1; - auto elem = result->elems[idx++] = state.ctx.mem.allocValue(); + auto & elem = result->elems[idx++]; // Start at 1, beacause the first match is the whole string. auto content = state.ctx.mem.newList(slen); - *elem = {NewValueAs::list, content}; + elem = {NewValueAs::list, content}; for (size_t si = 0; si < slen; ++si) { if (!match[si + 1].matched) - (content->elems[si] = state.ctx.mem.allocValue())->mkNull(); + content->elems[si].mkNull(); else - (content->elems[si] = state.ctx.mem.allocValue()) - ->mkString(match[si + 1].str()); + content->elems[si].mkString(match[si + 1].str()); } // Add a string for non-matched suffix characters. if (idx == 2 * len) { - (result->elems[idx++] = state.ctx.mem.allocValue())->mkString(match.suffix().str()); + result->elems[idx++].mkString(match.suffix().str()); } } @@ -2868,11 +2860,11 @@ static void prim_concatStringsSep(EvalState & state, Value * * args, Value & v) res.reserve((args[1]->listSize() + 32) * sep.size()); bool first = true; - for (auto elem : args[1]->listItems()) { + for (auto & elem : args[1]->listItems()) { if (first) first = false; else res += sep; res += *state.coerceToString( noPos, - *elem, + elem, context, "while evaluating one element of the list of strings to concat passed to " "builtins.concatStringsSep" @@ -2893,9 +2885,9 @@ static void prim_replaceStrings(EvalState & state, Value * * args, Value & v) std::vector from; from.reserve(args[0]->listSize()); - for (auto elem : args[0]->listItems()) { + for (auto & elem : args[0]->listItems()) { from.emplace_back(state.forceString( - *elem, + elem, noPos, "while evaluating one of the strings to replace passed to builtins.replaceStrings" )); @@ -2921,7 +2913,7 @@ static void prim_replaceStrings(EvalState & state, Value * * args, Value & v) if (v == cache.end()) { NixStringContext ctx; auto ts = state.forceString( - **j, + *j, ctx, noPos, "while evaluating one of the replacement strings passed to " @@ -2990,7 +2982,7 @@ static void prim_splitVersion(EvalState & state, Value * * args, Value & v) auto result = state.ctx.mem.newList(components.size()); v = {NewValueAs::list, result}; for (const auto & [n, component] : enumerate(components)) - (result->elems[n] = state.ctx.mem.allocValue())->mkString(std::move(component)); + result->elems[n].mkString(std::move(component)); } @@ -3016,7 +3008,7 @@ Value EvalBuiltins::prepareNixPath(const SearchPath & searchPath) auto attrs = mem.buildBindings(symbols, 2); attrs.alloc("path").mkString(i.path.s); attrs.alloc("prefix").mkString(i.prefix.s); - (v->elems[n++] = mem.allocValue())->mkAttrs(attrs); + v->elems[n++].mkAttrs(attrs); } return {NewValueAs::list, v}; } @@ -3081,7 +3073,7 @@ void EvalBuiltins::createBaseEnv(const SearchPath & searchPath, const Path & sto /* Now that we've added all primops, sort the `builtins' set, because attribute lookups expect it to be sorted. */ - env.values[0]->attrs()->sort(); + env.values[0].attrs()->sort(); staticEnv->isRoot = true; } diff --git a/lix/libexpr/primops/context.cc b/lix/libexpr/primops/context.cc index cd577cca9..eafff763d 100644 --- a/lix/libexpr/primops/context.cc +++ b/lix/libexpr/primops/context.cc @@ -151,7 +151,7 @@ void prim_getContext(EvalState & state, Value * * args, Value & v) auto content = state.ctx.mem.newList(info.second.outputs.size()); outputsVal = {NewValueAs::list, content}; for (const auto & [i, output] : enumerate(info.second.outputs)) - (content->elems[i] = state.ctx.mem.allocValue())->mkString(output); + content->elems[i].mkString(output); } attrs.alloc(state.ctx.store->printStorePath(info.first)).mkAttrs(infoAttrs); } @@ -183,11 +183,11 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v) auto namePath = state.ctx.store->parseStorePath(name); if (!settings.readOnlyMode) state.aio.blockOn(state.ctx.store->ensurePath(namePath)); - state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context"); - auto a = i.value->attrs()->get(state.ctx.s.path); + state.forceAttrs(i.value, i.pos, "while evaluating the value of a string context"); + auto a = i.value.attrs()->get(state.ctx.s.path); if (a) { if (state.forceBool( - *a->value, a->pos, "while evaluating the `path` attribute of a string context" + a->value, a->pos, "while evaluating the `path` attribute of a string context" )) { context.emplace(NixStringContextElem::Opaque{ @@ -196,10 +196,10 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v) } } - a = i.value->attrs()->get(sAllOutputs); + a = i.value.attrs()->get(sAllOutputs); if (a) { if (state.forceBool( - *a->value, + a->value, a->pos, "while evaluating the `allOutputs` attribute of a string context" )) @@ -216,20 +216,20 @@ static void prim_appendContext(EvalState & state, Value * * args, Value & v) } } - a = i.value->attrs()->get(state.ctx.s.outputs); + a = i.value.attrs()->get(state.ctx.s.outputs); if (a) { state.forceList( - *a->value, a->pos, "while evaluating the `outputs` attribute of a string context" + a->value, a->pos, "while evaluating the `outputs` attribute of a string context" ); - if (a->value->listSize() && !isDerivation(name)) { + if (a->value.listSize() && !isDerivation(name)) { state.ctx.errors.make( "tried to add derivation output context of %s, which is not a derivation, to a string", name ).atPos(i.pos).debugThrow(); } - for (auto elem : a->value->listItems()) { + for (auto & elem : a->value.listItems()) { auto outputName = state.forceStringNoCtx( - *elem, a->pos, "while evaluating an output name within a string context" + elem, a->pos, "while evaluating an output name within a string context" ); context.emplace(NixStringContextElem::Built { .drvPath = makeConstantStorePath(namePath), diff --git a/lix/libexpr/primops/fetchClosure.cc b/lix/libexpr/primops/fetchClosure.cc index 94cbd973f..36d6094f4 100644 --- a/lix/libexpr/primops/fetchClosure.cc +++ b/lix/libexpr/primops/fetchClosure.cc @@ -126,26 +126,26 @@ void prim_fetchClosure(EvalState & state, Value * * args, Value & v) if (attrName == "fromPath") { NixStringContext context; - fromPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint()); + fromPath = state.coerceToStorePath(attr.pos, attr.value, context, attrHint()); } else if (attrName == "toPath") { - state.forceValue(*attr.value, attr.pos); - bool isEmptyString = attr.value->type() == nString && attr.value->str().empty(); + state.forceValue(attr.value, attr.pos); + bool isEmptyString = attr.value.type() == nString && attr.value.str().empty(); if (isEmptyString) { toPath = StorePathOrGap {}; } else { NixStringContext context; - toPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint()); + toPath = state.coerceToStorePath(attr.pos, attr.value, context, attrHint()); } } else if (attrName == "fromStore") - fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos, attrHint()); + fromStoreUrl = state.forceStringNoCtx(attr.value, attr.pos, attrHint()); else if (attrName == "inputAddressed") - inputAddressedMaybe = state.forceBool(*attr.value, attr.pos, attrHint()); + inputAddressedMaybe = state.forceBool(attr.value, attr.pos, attrHint()); else throw Error({ diff --git a/lix/libexpr/primops/fetchMercurial.cc b/lix/libexpr/primops/fetchMercurial.cc index 250e6cf39..6a7d75702 100644 --- a/lix/libexpr/primops/fetchMercurial.cc +++ b/lix/libexpr/primops/fetchMercurial.cc @@ -23,7 +23,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v) url = state .coerceToString( attr.pos, - *attr.value, + attr.value, context, "while evaluating the `url` attribute passed to " "builtins.fetchMercurial", @@ -35,7 +35,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v) // Ugly: unlike fetchGit, here the "rev" attribute can // be both a revision or a branch/tag name. auto value = state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the `rev` attribute passed to builtins.fetchMercurial" ); @@ -46,7 +46,7 @@ static void prim_fetchMercurial(EvalState & state, Value * * args, Value & v) } else if (n == "name") name = state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.fetchMercurial" ); diff --git a/lix/libexpr/primops/fetchTree.cc b/lix/libexpr/primops/fetchTree.cc index 2cabc5674..af1dd4d1e 100644 --- a/lix/libexpr/primops/fetchTree.cc +++ b/lix/libexpr/primops/fetchTree.cc @@ -128,7 +128,7 @@ static void fetchTree( "unexpected attribute 'type'" ).atPos(pos).debugThrow(); type = state.forceStringNoCtx( - *aType->value, + aType->value, aType->pos, "while evaluating the `type` attribute passed to builtins.fetchTree" ); @@ -142,12 +142,12 @@ static void fetchTree( for (auto & attr : *args[0]->attrs()) { if (attr.name == state.ctx.s.type) continue; - state.forceValue(*attr.value, attr.pos); - if (attr.value->type() == nPath || attr.value->type() == nString) { + state.forceValue(attr.value, attr.pos); + if (attr.value.type() == nPath || attr.value.type() == nString) { auto s = state .coerceToString( - attr.pos, *attr.value, context, "", StringCoercionMode::Strict, false + attr.pos, attr.value, context, "", StringCoercionMode::Strict, false ) .toOwned(); attrs.emplace(state.ctx.symbols[attr.name], @@ -156,10 +156,10 @@ static void fetchTree( ? fixURIForGit(s, state) : fixURI(s, state) : s); - } else if (attr.value->type() == nBool) { - attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value->boolean()}); - } else if (attr.value->type() == nInt) { - auto intValue = attr.value->integer().value; + } else if (attr.value.type() == nBool) { + attrs.emplace(state.ctx.symbols[attr.name], Explicit{attr.value.boolean()}); + } else if (attr.value.type() == nInt) { + auto intValue = attr.value.integer().value; if (intValue < 0) { state.ctx.errors.make("negative value given for fetchTree attr %1%: %2%", state.ctx.symbols[attr.name], intValue).atPos(pos).debugThrow(); @@ -173,7 +173,7 @@ static void fetchTree( "fetchTree argument '%s' is %s while a string, Boolean or integer is " "expected", state.ctx.symbols[attr.name], - showType(*attr.value) + showType(attr.value) ) .debugThrow(); } @@ -241,12 +241,12 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v std::string_view n(state.ctx.symbols[attr.name]); if (n == "url") url = state.forceStringNoCtx( - *attr.value, attr.pos, "while evaluating the url we should fetch" + attr.value, attr.pos, "while evaluating the url we should fetch" ); else if (n == "sha256") { expectedHash = newHashAllowEmpty( state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the sha256 of the content we should fetch" ), @@ -254,7 +254,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v ); } else if (n == "name") name = state.forceStringNoCtx( - *attr.value, + attr.value, attr.pos, "while evaluating the name of the content we should fetch" ); diff --git a/lix/libexpr/primops/fromTOML.cc b/lix/libexpr/primops/fromTOML.cc index d9d84cdd2..9e2ecce58 100644 --- a/lix/libexpr/primops/fromTOML.cc +++ b/lix/libexpr/primops/fromTOML.cc @@ -34,7 +34,7 @@ void prim_fromTOML(EvalState & state, Value ** args, Value & val) auto list = state.ctx.mem.newList(size); v = {NewValueAs::list, list}; for (size_t i = 0; i < size; ++i) { - self(*(list->elems[i] = state.ctx.mem.allocValue()), array[i]); + self(list->elems[i], array[i]); } } break; case toml::value_t::boolean: diff --git a/lix/libexpr/print-ambiguous.cc b/lix/libexpr/print-ambiguous.cc index bc5180c96..d2738614f 100644 --- a/lix/libexpr/print-ambiguous.cc +++ b/lix/libexpr/print-ambiguous.cc @@ -9,11 +9,12 @@ namespace nix { // See: https://github.com/NixOS/nix/issues/9730 void printAmbiguous( - Value &v, - const SymbolTable &symbols, - std::ostream &str, - std::set *seen, - int depth) + const Value & v, + const SymbolTable & symbols, + std::ostream & str, + std::set * seen, + int depth +) { checkInterrupt(); @@ -21,6 +22,10 @@ void printAmbiguous( str << "«too deep»"; return; } + if (v.isInvalid()) { + str << ""; + return; + } switch (v.type()) { case nInt: str << v.integer(); @@ -44,7 +49,7 @@ void printAmbiguous( str << "{ "; for (auto & i : v.attrs()->lexicographicOrder(symbols)) { str << symbols[i->name] << " = "; - printAmbiguous(*i->value, symbols, str, seen, depth - 1); + printAmbiguous(i->value, symbols, str, seen, depth - 1); str << "; "; } str << "}"; @@ -56,11 +61,8 @@ void printAmbiguous( str << "«repeated»"; else { str << "[ "; - for (auto v2 : v.listItems()) { - if (v2) - printAmbiguous(*v2, symbols, str, seen, depth - 1); - else - str << "(nullptr)"; + for (auto & v2 : v.listItems()) { + printAmbiguous(v2, symbols, str, seen, depth - 1); str << " "; } str << "]"; diff --git a/lix/libexpr/print-ambiguous.hh b/lix/libexpr/print-ambiguous.hh index b7bc59a35..d584dbe89 100644 --- a/lix/libexpr/print-ambiguous.hh +++ b/lix/libexpr/print-ambiguous.hh @@ -17,10 +17,10 @@ namespace nix { * See: https://github.com/NixOS/nix/issues/9730 */ void printAmbiguous( - Value &v, - const SymbolTable &symbols, - std::ostream &str, - std::set *seen, - int depth); - + const Value & v, + const SymbolTable & symbols, + std::ostream & str, + std::set * seen, + int depth +); } diff --git a/lix/libexpr/print.cc b/lix/libexpr/print.cc index 6f59b7894..1c7990cd8 100644 --- a/lix/libexpr/print.cc +++ b/lix/libexpr/print.cc @@ -237,7 +237,7 @@ private: std::string storePath; if (i) { storePath = state.ctx.store->printStorePath(state.coerceToStorePath( - i->pos, *i->value, context, "while evaluating the drvPath of a derivation" + i->pos, i->value, context, "while evaluating the drvPath of a derivation" )); } @@ -264,18 +264,18 @@ private: } auto item = v[0].second; - if (!item->value) { + if (item->value.isInvalid()) { return true; } if (options.force) { // The item is going to be forced during printing anyway, but we need its type now. - state.forceValue(*item->value, noPos); + state.forceValue(item->value, noPos); } // Pretty-print single-item attrsets only if they contain nested // structures. - auto itemType = item->value->type(); + auto itemType = item->value.type(); return itemType == nList || itemType == nAttrs; } @@ -324,7 +324,7 @@ private: } output << " = "; - print(*i.second->value, depth + 1); + print(i.second->value, depth + 1); output << ";"; attrsPrinted++; printedHere++; @@ -338,7 +338,7 @@ private: } } - bool shouldPrettyPrintList(std::span list) + bool shouldPrettyPrintList(std::span list) { if (!options.shouldPrettyPrint() || list.empty()) { return false; @@ -349,19 +349,19 @@ private: return true; } - auto item = list[0]; - if (!item) { + auto & item = list[0]; + if (item.isInvalid()) { return true; } if (options.force) { // The item is going to be forced during printing anyway, but we need its type now. - state.forceValue(*item, noPos); + state.forceValue(item, noPos); } // Pretty-print single-item lists only if they contain nested // structures. - auto itemType = item->type(); + auto itemType = item.type(); return itemType == nList || itemType == nAttrs; } @@ -378,7 +378,7 @@ private: auto listItems = v.listItems(); auto prettyPrint = shouldPrettyPrintList(listItems); size_t printedHere = 0; - for (auto elem : listItems) { + for (auto & elem : listItems) { printSpace(prettyPrint); if (listItemsPrinted >= options.maxListItems) { @@ -386,11 +386,7 @@ private: break; } - if (elem) { - print(*elem, depth + 1); - } else { - printNullptr(); - } + print(elem, depth + 1); listItemsPrinted++; printedHere++; } @@ -427,7 +423,7 @@ private: output << "primop"; } else if (v.isPrimOpApp()) { output << "partially applied "; - auto primOp = v.app().target()->primOp(); + auto primOp = v.app().target().primOp(); if (primOp) output << *primOp; else @@ -495,11 +491,22 @@ private: checkInterrupt(); try { + if (v.isInvalid()) { + if (options.ansiColors) { + output << ANSI_MAGENTA; + } + output << "«invalid»"; + if (options.ansiColors) { + output << ANSI_NORMAL; + } + return; + } + if (options.force) { state.forceValue(v, noPos); } - switch (v.type()) { + switch (v.type(true)) { case nInt: printInt(v); diff --git a/lix/libexpr/symbol-table.hh b/lix/libexpr/symbol-table.hh index a792c6610..60645194e 100644 --- a/lix/libexpr/symbol-table.hh +++ b/lix/libexpr/symbol-table.hh @@ -82,9 +82,9 @@ public: return contents; } - const Value * toValuePtr() const + Value toValue() const { - return &underlyingValue; + return underlyingValue; } friend std::ostream & operator<<(std::ostream & os, const InternedSymbol & symbol); diff --git a/lix/libexpr/value-to-json.cc b/lix/libexpr/value-to-json.cc index b90f68f1d..f32d35091 100644 --- a/lix/libexpr/value-to-json.cc +++ b/lix/libexpr/value-to-json.cc @@ -61,7 +61,7 @@ JSON printValueAsJSON(EvalState & state, bool strict, const Attr & a(*v.attrs()->get(state.ctx.symbols.create(j))); try { out[j] = - printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore); + printValueAsJSON(state, strict, a.value, a.pos, context, copyToStore); } catch (Error & e) { e.addTrace( state.ctx.positions[a.pos], @@ -71,7 +71,7 @@ JSON printValueAsJSON(EvalState & state, bool strict, } } } else { - return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore); + return printValueAsJSON(state, strict, i->value, i->pos, context, copyToStore); } break; } @@ -81,7 +81,7 @@ JSON printValueAsJSON(EvalState & state, bool strict, int i = 0; for (auto elem : v.listItems()) { try { - out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore)); + out.push_back(printValueAsJSON(state, strict, elem, pos, context, copyToStore)); } catch (Error & e) { e.addTrace(state.ctx.positions[pos], HintFmt("while evaluating list element at index %1%", i)); diff --git a/lix/libexpr/value-to-xml.cc b/lix/libexpr/value-to-xml.cc index 0d9b6d3b1..6b09439b1 100644 --- a/lix/libexpr/value-to-xml.cc +++ b/lix/libexpr/value-to-xml.cc @@ -43,7 +43,7 @@ static void showAttrs(EvalState & state, bool strict, bool location, if (location && a.pos) posToXML(state, xmlAttrs, state.ctx.positions[a.pos]); XMLOpenElement _(doc, "attr", xmlAttrs); - printValueAsXML(state, strict, location, *a.value, doc, context, drvsSeen, a.pos); + printValueAsXML(state, strict, location, a.value, doc, context, drvsSeen, a.pos); } } @@ -90,20 +90,20 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, a = v.attrs()->get(state.ctx.s.drvPath); if (a) { if (strict) { - state.forceValue(*a->value, a->pos); + state.forceValue(a->value, a->pos); } - if (a->value->type() == nString) { - xmlAttrs["drvPath"] = drvPath = a->value->str(); + if (a->value.type() == nString) { + xmlAttrs["drvPath"] = drvPath = a->value.str(); } } a = v.attrs()->get(state.ctx.s.outPath); if (a) { if (strict) { - state.forceValue(*a->value, a->pos); + state.forceValue(a->value, a->pos); } - if (a->value->type() == nString) { - xmlAttrs["outPath"] = a->value->str(); + if (a->value.type() == nString) { + xmlAttrs["outPath"] = a->value.str(); } } @@ -124,8 +124,8 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, case nList: { XMLOpenElement _(doc, "list"); - for (auto v2 : v.listItems()) { - printValueAsXML(state, strict, location, *v2, doc, context, drvsSeen, pos); + for (auto & v2 : v.listItems()) { + printValueAsXML(state, strict, location, v2, doc, context, drvsSeen, pos); } break; } diff --git a/lix/libexpr/value.hh b/lix/libexpr/value.hh index e01e9b70f..0970d6fab 100644 --- a/lix/libexpr/value.hh +++ b/lix/libexpr/value.hh @@ -75,13 +75,15 @@ struct PrimOpDetails // NOTE value.cc contains alignment assertions for pointers tagged thusly. // *always* ensure that these assertions match the tag types declared here typedef enum { + // NOTE: tThunk *must* be 0, otherwise invalid value detection breaks + // since invalid values are encoded as thunks with a null thunk state + tThunk = 0, + tApp, tInt, tBool, tString, tAttrs, tList, - tThunk, - tApp, tAuxiliary, } InternalType; @@ -483,29 +485,6 @@ public: /// allocating memory. Value(list_t, const List * items) : raw(tag(tList, items)) {} - /// Constructs a nix language value of type "list", with an element array - /// initialized by applying @ref transformer to each element in @ref items. - /// - /// This allows "in-place" construction of a nix list when some logic is - /// needed to get each Value pointer. This constructor dynamically (GC) - /// allocates memory for the size of @ref items, and the Value pointers - /// returned by @ref transformer are shallow copied into it. - template< - std::ranges::sized_range SizedIterableT, - InvocableR TransformerT - > - Value(list_t, SizedIterableT & items, TransformerT const & transformer) - { - auto list = - reinterpret_cast(gcAllocBytes(sizeof(List) + items.size() * sizeof(Value *))); - list->size = items.size(); - auto it = items.begin(); - for (size_t i = 0; i < items.size(); i++, it++) { - list->elems[i] = transformer(*it); - } - raw = tag(tList, list); - } - /// Constructs a nix language value of the singleton type "null". Value(null_t) : raw(tag(tAuxiliary, &NULL_ACB)) {} @@ -533,7 +512,7 @@ public: /// Constructs a nix language value of type "lambda", which represents a /// lazy and/or partial application of a function. - Value(app_t, EvalMemory & mem, Value & lhs, std::span args); + Value(app_t, EvalMemory & mem, Value & lhs, std::span args); /// Constructs a nix language value of type "external", which is only used /// by plugins. Do any existing plugins even use this mechanism? @@ -597,9 +576,10 @@ public: { return internalType() == tApp; } - inline bool isBlackhole() const + inline bool isBlackhole() const; + inline bool isInvalid() const { - return internalType() == tThunk && untag() == &blackHole; + return raw == 0; } // type() == nFunction @@ -611,21 +591,7 @@ public: { return internalType() == tAuxiliary && auxiliary()->type() == Acb::tPrimOp; } - inline bool isPrimOpApp() const - { - return internalType() == tApp && !app().resolved() && app().target()->isPrimOp(); - } - - struct alignas(TAG_ALIGN) List - { - size_t size; - Value * elems[0]; - - std::span span() - { - return {elems, elems + size}; - } - }; + inline bool isPrimOpApp() const; /** * Strings in the evaluator carry a so-called `context` which @@ -663,50 +629,7 @@ public: } }; - struct alignas(TAG_ALIGN) App - { - uintptr_t _left; - size_t _n; - Value * _args[0]; - - bool resolved() const - { - return _n == 0; - } - - void resolve(Value v) - { - _left = v.raw; - _n = 0; - } - - Value * left() const - { - return reinterpret_cast(_left); - } - - Value result() const - { - Value v; - v.raw = _left; - return v; - } - - Value * target() const - { - return left()->isApp() ? left()->app().target() : left(); - } - - std::span args() - { - return std::span{_args, _n}; - } - - size_t totalArgs() const - { - return _n + (left()->isApp() ? left()->app().totalArgs() : 0); - } - }; + struct App; /// auxiliary control block for values that require more space. /// these blocks are usually heap-allocated in GC memory space. @@ -861,15 +784,9 @@ public: return internalType() == tList; } - Value * const * listElems() const - { - return untag()->elems; - } + Value * listElems() const; - size_t listSize() const - { - return untag()->size; - } + size_t listSize() const; /** * Check whether forcing this value requires a trivial amount of @@ -878,11 +795,11 @@ public: */ bool isTrivial() const; - auto listItems() + auto listItems() const { struct ListIterable { - typedef Value * const * iterator; + typedef Value * iterator; iterator _begin, _end; iterator begin() const { return _begin; } iterator end() const { return _end; } @@ -892,20 +809,6 @@ public: return ListIterable { begin, begin + listSize() }; } - auto listItems() const - { - struct ConstListIterable - { - typedef const Value * const * iterator; - iterator _begin, _end; - iterator begin() const { return _begin; } - iterator end() const { return _end; } - }; - assert(isList()); - auto begin = listElems(); - return ConstListIterable { begin, begin + listSize() }; - } - SourcePath path() const { assert(internalType() == tString && untag()->isPath()); @@ -982,6 +885,11 @@ public: { return untag(); } + + uintptr_t pointerEqProxy() const + { + return raw; + } }; struct alignas(Value::TAG_ALIGN) Value::Thunk @@ -1014,6 +922,60 @@ struct alignas(Value::TAG_ALIGN) Value::Thunk } }; +struct alignas(Value::TAG_ALIGN) Value::List +{ + size_t size; + Value elems[0]; + + std::span span() + { + return {elems, elems + size}; + } +}; + +struct alignas(Value::TAG_ALIGN) Value::App +{ + Value _left; + size_t _n; + Value _args[0]; + + bool resolved() const + { + return _n == ~size_t(0); + } + + void resolve(Value v) + { + _left = v; + _n = ~size_t(0); + } + + Value left() const + { + return _left; + } + + Value result() const + { + return left(); + } + + Value target() const + { + return left().isApp() ? left().app().target() : left(); + } + + std::span args() + { + return std::span{_args, _n}; + } + + size_t totalArgs() const + { + return _n + (left().isApp() ? left().app().totalArgs() : 0); + } +}; + inline ValueType Value::type(bool invalidIsThunk) const { again: @@ -1043,7 +1005,13 @@ again: return nInt; } case tThunk: - if (thunk().resolved()) { + if (isInvalid()) { + if (invalidIsThunk) { + return nThunk; + } else { + abort(); + } + } else if (thunk().resolved()) { raw = thunk().result().raw; goto again; } @@ -1053,12 +1021,28 @@ again: raw = app().result().raw; goto again; } - return app().target()->isPrimOp() ? nFunction : nThunk; + return app().target().isPrimOp() ? nFunction : nThunk; } - if (invalidIsThunk) - return nThunk; - else - abort(); +} + +inline bool Value::isBlackhole() const +{ + return internalType() == tThunk && untag()->expr == blackHole.expr; +} + +inline bool Value::isPrimOpApp() const +{ + return internalType() == tApp && !app().resolved() && app().target().isPrimOp(); +} + +inline Value * Value::listElems() const +{ + return untag()->elems; +} + +inline size_t Value::listSize() const +{ + return untag()->size; } using PrimOp = Value::PrimOp; diff --git a/lix/nix/bundle.cc b/lix/nix/bundle.cc index 03a2dbcfb..fa9160c26 100644 --- a/lix/nix/bundle.cc +++ b/lix/nix/bundle.cc @@ -109,13 +109,13 @@ struct CmdBundle : InstallableCommand throw Error("the bundler '%s' does not produce a derivation", bundler.what()); NixStringContext context2; - auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, ""); + auto drvPath = evalState->coerceToStorePath(attr1->pos, attr1->value, context2, ""); auto attr2 = vRes.attrs()->get(evaluator->s.outPath); if (!attr2) throw Error("the bundler '%s' does not produce a derivation", bundler.what()); - auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2, ""); + auto outPath = evalState->coerceToStorePath(attr2->pos, attr2->value, context2, ""); aio().blockOn(store->buildPaths({ DerivedPath::Built { @@ -128,7 +128,7 @@ struct CmdBundle : InstallableCommand auto * attr = vRes.attrs()->get(evaluator->s.name); if (!attr) throw Error("attribute 'name' missing"); - outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, ""); + outLink = evalState->forceStringNoCtx(attr->value, attr->pos, ""); } // TODO: will crash if not a localFSStore? diff --git a/lix/nix/flake.cc b/lix/nix/flake.cc index f851ee3f3..3e9a9c846 100644 --- a/lix/nix/flake.cc +++ b/lix/nix/flake.cc @@ -185,20 +185,20 @@ static void enumerateOutputs( auto aOutputs = vFlake.attrs()->get(state.ctx.symbols.create("outputs")); assert(aOutputs); - state.forceAttrs(*aOutputs->value, noPos, "while evaluating the outputs of a flake"); + state.forceAttrs(aOutputs->value, noPos, "while evaluating the outputs of a flake"); auto sHydraJobs = state.ctx.symbols.create("hydraJobs"); /* Hack: ensure that hydraJobs is evaluated before anything else. This way we can disable IFD for hydraJobs and then enable it for other outputs. */ - if (auto attr = aOutputs->value->attrs()->get(sHydraJobs)) { - callback(state.ctx.symbols[attr->name], *attr->value, attr->pos); + if (auto attr = aOutputs->value.attrs()->get(sHydraJobs)) { + callback(state.ctx.symbols[attr->name], attr->value, attr->pos); } - for (auto & attr : *aOutputs->value->attrs()) { + for (auto & attr : *aOutputs->value.attrs()) { if (attr.name != sHydraJobs) { - callback(state.ctx.symbols[attr.name], *attr.value, attr.pos); + callback(state.ctx.symbols[attr.name], attr.value, attr.pos); } } } @@ -502,14 +502,14 @@ struct CmdFlakeCheck : FlakeCommand throw Error("jobset should not be a derivation at top-level"); for (auto & attr : *v.attrs()) { - state->forceAttrs(*attr.value, attr.pos, ""); + state->forceAttrs(attr.value, attr.pos, ""); auto attrPath2 = concatStrings(attrPath, ".", evaluator->symbols[attr.name]); - if (state->isDerivation(*attr.value)) { + if (state->isDerivation(attr.value)) { Activity act(*logger, lvlInfo, actUnknown, fmt("checking Hydra job '%s'", attrPath2)); - checkDerivation(attrPath2, *attr.value, attr.pos); + checkDerivation(attrPath2, attr.value, attr.pos); } else { - checkHydraJobs(attrPath2, *attr.value, attr.pos); + checkHydraJobs(attrPath2, attr.value, attr.pos); } } @@ -546,7 +546,7 @@ struct CmdFlakeCheck : FlakeCommand if (attr->name == evaluator->symbols.create("path")) { NixStringContext context; auto path = state->ctx.paths.checkSourcePath( - state->coerceToPath(attr->pos, *attr->value, context, "") + state->coerceToPath(attr->pos, attr->value, context, "") ); if (!path.pathExists()) throw Error("template '%s' refers to a non-existent path '%s'", attrPath, path); @@ -556,7 +556,7 @@ struct CmdFlakeCheck : FlakeCommand throw Error("template '%s' lacks attribute 'path'", attrPath); if (auto attr = v.attrs()->get(evaluator->symbols.create("description"))) - state->forceStringNoCtx(*attr->value, attr->pos, ""); + state->forceStringNoCtx(attr->value, attr->pos, ""); else throw Error("template '%s' lacks attribute 'description'", attrPath); @@ -625,18 +625,17 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { - state->forceAttrs(*attr.value, attr.pos, ""); - for (auto & attr2 : *attr.value->attrs()) { + state->forceAttrs(attr.value, attr.pos, ""); + for (auto & attr2 : *attr.value.attrs()) { auto drvPath = checkDerivation( fmt("%s.%s.%s", name, attr_name, evaluator->symbols[attr2.name]), - *attr2.value, + attr2.value, attr2.pos ); - if (drvPath && attr_name == evalSettings.getCurrentSystem()) - { + if (drvPath && attr_name == evalSettings.getCurrentSystem()) { drvPaths.push_back(DerivedPath::Built { .drvPath = makeConstantStorePath(*drvPath), .outputs = OutputsSpec::All { }, @@ -654,7 +653,7 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { - checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); + checkApp(fmt("%s.%s", name, attr_name), attr.value, attr.pos); }; } } @@ -666,14 +665,14 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { - state->forceAttrs(*attr.value, attr.pos, ""); - for (auto & attr2 : *attr.value->attrs()) { + state->forceAttrs(attr.value, attr.pos, ""); + for (auto & attr2 : *attr.value.attrs()) { checkDerivation( fmt("%s.%s.%s", name, attr_name, evaluator->symbols[attr2.name]), - *attr2.value, + attr2.value, attr2.pos ); } @@ -688,14 +687,14 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { - state->forceAttrs(*attr.value, attr.pos, ""); - for (auto & attr2 : *attr.value->attrs()) { + state->forceAttrs(attr.value, attr.pos, ""); + for (auto & attr2 : *attr.value.attrs()) { checkApp( fmt("%s.%s.%s", name, attr_name, evaluator->symbols[attr2.name]), - *attr2.value, + attr2.value, attr2.pos ); } @@ -711,7 +710,7 @@ struct CmdFlakeCheck : FlakeCommand checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { checkDerivation( - fmt("%s.%s", name, attr_name), *attr.value, attr.pos + fmt("%s.%s", name, attr_name), attr.value, attr.pos ); }; } @@ -724,7 +723,7 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos) ) { - checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); + checkApp(fmt("%s.%s", name, attr_name), attr.value, attr.pos); }; } } @@ -750,7 +749,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *vOutput.attrs()) checkOverlay( fmt("%s.%s", name, evaluator->symbols[attr.name]), - *attr.value, + attr.value, attr.pos ); } @@ -766,7 +765,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *vOutput.attrs()) checkModule( fmt("%s.%s", name, evaluator->symbols[attr.name]), - *attr.value, + attr.value, attr.pos ); } @@ -777,7 +776,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *vOutput.attrs()) checkNixOSConfiguration( fmt("%s.%s", name, evaluator->symbols[attr.name]), - *attr.value, + attr.value, attr.pos ); } @@ -798,7 +797,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *vOutput.attrs()) checkTemplate( fmt("%s.%s", name, evaluator->symbols[attr.name]), - *attr.value, + attr.value, attr.pos ); } @@ -811,7 +810,7 @@ struct CmdFlakeCheck : FlakeCommand checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { checkBundler( - fmt("%s.%s", name, attr_name), *attr.value, attr.pos + fmt("%s.%s", name, attr_name), attr.value, attr.pos ); }; } @@ -824,14 +823,14 @@ struct CmdFlakeCheck : FlakeCommand const auto & attr_name = evaluator->symbols[attr.name]; checkSystemName(attr_name, attr.pos); if (checkSystemType(attr_name, attr.pos)) { - state->forceAttrs(*attr.value, attr.pos, ""); - for (auto & attr2 : *attr.value->attrs()) { + state->forceAttrs(attr.value, attr.pos, ""); + for (auto & attr2 : *attr.value.attrs()) { checkBundler( fmt("%s.%s.%s", name, attr_name, evaluator->symbols[attr2.name]), - *attr2.value, + attr2.value, attr2.pos ); } diff --git a/lix/nix/main.cc b/lix/nix/main.cc index dc5b8256b..3ab140b58 100644 --- a/lix/nix/main.cc +++ b/lix/nix/main.cc @@ -378,7 +378,7 @@ static void showHelp(AsyncIoRoot & aio, std::vector subcommand, Nix throw UsageError("`nix` has no subcommand '%s'", concatStringsSep("", subcommand)); auto markdown = - state->forceString(*attr->value, noPos, "while evaluating the lowdown help text"); + state->forceString(attr->value, noPos, "while evaluating the lowdown help text"); RunPager pager; std::cout << renderMarkdownToTerminal(markdown) << "\n"; @@ -528,13 +528,13 @@ void mainWrapped(AsyncIoRoot & aio, int argc, char * * argv) auto res = JSON::object(); res["builtins"] = ({ auto builtinsJson = JSON::object(); - auto builtins = state.builtins.env.values[0]->attrs(); + auto builtins = state.builtins.env.values[0].attrs(); for (auto & builtin : *builtins) { auto b = JSON::object(); - if (!builtin.value->isPrimOp()) { + if (!builtin.value.isPrimOp()) { continue; } - auto primOp = builtin.value->primOp(); + auto primOp = builtin.value.primOp(); if (!primOp->doc) { continue; } diff --git a/lix/nix/prefetch.cc b/lix/nix/prefetch.cc index 17513ed11..bee701652 100644 --- a/lix/nix/prefetch.cc +++ b/lix/nix/prefetch.cc @@ -39,14 +39,14 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url) if (!mirrorList) { throw Error("unknown mirror name '%s'", mirrorName); } - state.forceList(*mirrorList->value, noPos, "while evaluating one mirror configuration"); + state.forceList(mirrorList->value, noPos, "while evaluating one mirror configuration"); - if (mirrorList->value->listSize() < 1) { + if (mirrorList->value.listSize() < 1) { throw Error("mirror URL '%s' did not expand to anything", url); } std::string mirror(state.forceString( - *mirrorList->value->listElems()[0], noPos, "while evaluating the first available mirror" + mirrorList->value.listElems()[0], noPos, "while evaluating the first available mirror" )); return mirror + (mirror.ends_with("/") ? "" : "/") + s.substr(p + 1); } @@ -217,12 +217,12 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str auto * attr = v.attrs()->get(evaluator->symbols.create("urls")); if (!attr) throw Error("attribute 'urls' missing"); - state->forceList(*attr->value, noPos, "while evaluating the urls to prefetch"); - if (attr->value->listSize() < 1) { + state->forceList(attr->value, noPos, "while evaluating the urls to prefetch"); + if (attr->value.listSize() < 1) { throw Error("'urls' list is empty"); } url = state->forceString( - *attr->value->listElems()[0], + attr->value.listElems()[0], noPos, "while evaluating the first url from the urls list" ); @@ -233,7 +233,7 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str printInfo("warning: this does not look like a fetchurl call"); else unpack = state->forceString( - *attr2->value, + attr2->value, noPos, "while evaluating the outputHashMode of the source to prefetch" ) @@ -244,7 +244,7 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str auto attr3 = v.attrs()->get(evaluator->symbols.create("name")); if (!attr3) name = state->forceString( - *attr3->value, noPos, "while evaluating the name of the source to prefetch" + attr3->value, noPos, "while evaluating the name of the source to prefetch" ); } } diff --git a/lix/nix/repl.cc b/lix/nix/repl.cc index d6e184721..2f46a9ea4 100644 --- a/lix/nix/repl.cc +++ b/lix/nix/repl.cc @@ -68,10 +68,10 @@ struct CmdRepl : RawInstallablesCommand auto what = installable.what(); state->forceValue(val, pos); auto autoArgs = getAutoArgs(*evaluator); - auto valPost = evaluator->mem.allocValue(); - state->autoCallFunction(*autoArgs, val, *valPost, pos); - state->forceValue(*valPost, pos); - values.push_back({*valPost, what}); + Value valPost; + state->autoCallFunction(*autoArgs, val, valPost, pos); + state->forceValue(valPost, pos); + values.push_back( {valPost, what }); } else { auto [val, pos] = installable.toValue(*state); values.push_back({val, what}); diff --git a/subprojects/nix-eval-jobs/src/worker.cc b/subprojects/nix-eval-jobs/src/worker.cc index ba551fcab..bdfab0db3 100644 --- a/subprojects/nix-eval-jobs/src/worker.cc +++ b/subprojects/nix-eval-jobs/src/worker.cc @@ -41,9 +41,9 @@ #include "buffered-io.hh" #include "eval-args.hh" -static nix::Value *releaseExprTopLevelValue(nix::EvalState &state, - nix::Bindings &autoArgs, - MyArgs &args) { +static nix::Value releaseExprTopLevelValue(nix::EvalState &state, + nix::Bindings &autoArgs, + MyArgs &args) { nix::Value vTop; if (args.fromArgs) { @@ -57,9 +57,9 @@ static nix::Value *releaseExprTopLevelValue(nix::EvalState &state, vTop); } - auto vRoot = state.ctx.mem.allocValue(); + nix::Value vRoot; - state.autoCallFunction(autoArgs, vTop, *vRoot, {}); + state.autoCallFunction(autoArgs, vTop, vRoot, {}); return vRoot; } @@ -79,7 +79,7 @@ static std::optional readConstituents(const nix::Value *v, nix::box_ptr &state, nix::ref &evaluator) { auto a = v->attrs()->get(state->ctx.symbols.create("_hydraAggregate")); - if (a && state->forceBool(*a->value, a->pos, + if (a && state->forceBool(a->value, a->pos, "while evaluating the " "`_hydraAggregate` attribute")) { std::vector constituents; @@ -92,7 +92,7 @@ readConstituents(const nix::Value *v, nix::box_ptr &state, .debugThrow(nix::always_progresses); // we can't have a debugger here nix::NixStringContext context; - state->coerceToString(a->pos, *a->value, context, + state->coerceToString(a->pos, a->value, context, "while evaluating the `constituents` attribute", nix::StringCoercionMode::ToString, false); for (auto &c : context) @@ -106,14 +106,14 @@ readConstituents(const nix::Value *v, nix::box_ptr &state, }, c.raw); - state->forceList(*a->value, a->pos, + state->forceList(a->value, a->pos, "while evaluating the " "`constituents` attribute"); - for (unsigned int n = 0; n < a->value->listSize(); ++n) { - auto v = a->value->listElems()[n]; - state->forceValue(*v, nix::noPos); - if (v->type() == nix::nString) - namedConstituents.emplace_back(v->str()); + for (unsigned int n = 0; n < a->value.listSize(); ++n) { + auto v = a->value.listElems()[n]; + state->forceValue(v, nix::noPos); + if (v.type() == nix::nString) + namedConstituents.emplace_back(v.str()); } return Constituents(constituents, namedConstituents); @@ -138,7 +138,7 @@ void worker(nix::ref evaluator, return flake.toValue(*state).first; } else { - return *releaseExprTopLevelValue(*state, autoArgs, args); + return releaseExprTopLevelValue(*state, autoArgs, args); } }(); @@ -171,15 +171,15 @@ void worker(nix::ref evaluator, nix::findAlongAttrPath(*state, attrPathS, autoArgs, vRoot) .first; - auto v = evaluator->mem.allocValue(); - state->autoCallFunction(autoArgs, vTmp, *v, {}); + nix::Value v; + state->autoCallFunction(autoArgs, vTmp, v, {}); - if (v->type() == nix::nAttrs) { - if (auto drvInfo = nix::getDerivation(*state, *v, false)) { + if (v.type() == nix::nAttrs) { + if (auto drvInfo = nix::getDerivation(*state, v, false)) { std::optional maybeConstituents; if (args.constituents) { maybeConstituents = - readConstituents(v, state, evaluator); + readConstituents(&v, state, evaluator); } auto drv = Drv(attrPathS, *state, *drvInfo, args, maybeConstituents); @@ -197,16 +197,16 @@ void worker(nix::ref evaluator, // = true;` for top-level attrset for (auto &i : - v->attrs()->lexicographicOrder(evaluator->symbols)) { + v.attrs()->lexicographicOrder(evaluator->symbols)) { const std::string_view name = evaluator->symbols[i->name]; attrs.emplace_back(name); if (name == "recurseForDerivations" && !args.forceRecurse) { - auto attrv = v->attrs()->get( + auto attrv = v.attrs()->get( evaluator->s.recurseForDerivations); recurse = state->forceBool( - *attrv->value, attrv->pos, + attrv->value, attrv->pos, "while evaluating recurseForDerivations"); } } diff --git a/tests/unit/libexpr/primops.cc b/tests/unit/libexpr/primops.cc index bdda6bc1f..6669d1cf1 100644 --- a/tests/unit/libexpr/primops.cc +++ b/tests/unit/libexpr/primops.cc @@ -73,7 +73,7 @@ namespace nix { auto s = createSymbol("success"); auto p = v.attrs()->get(s); ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsFalse()); + ASSERT_THAT(p->value, IsFalse()); } TEST_F(PrimOpTest, tryEvalSuccess) { @@ -82,11 +82,11 @@ namespace nix { auto s = createSymbol("success"); auto p = v.attrs()->get(s); ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsTrue()); + ASSERT_THAT(p->value, IsTrue()); s = createSymbol("value"); p = v.attrs()->get(s); ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsIntEq(123)); + ASSERT_THAT(p->value, IsIntEq(123)); } TEST_F(PrimOpTest, getEnv) { @@ -134,8 +134,8 @@ namespace nix { TEST_F(PrimOpTest, attrValues) { auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }"); ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsStringEq("foo")); + ASSERT_THAT(v.listElems()[0], IsIntEq(1)); + ASSERT_THAT(v.listElems()[1], IsStringEq("foo")); } TEST_F(PrimOpTest, getAttr) { @@ -203,7 +203,7 @@ namespace nix { ASSERT_THAT(v, IsAttrsOfSize(1)); auto key = v.attrs()->get(createSymbol("key")); ASSERT_NE(key, nullptr); - ASSERT_THAT(*key->value, IsIntEq(123)); + ASSERT_THAT(key->value, IsIntEq(123)); } TEST_F(PrimOpTest, intersectAttrs) { @@ -211,14 +211,14 @@ namespace nix { ASSERT_THAT(v, IsAttrsOfSize(1)); auto b = v.attrs()->get(createSymbol("b")); ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(3)); + ASSERT_THAT(b->value, IsIntEq(3)); } TEST_F(PrimOpTest, catAttrs) { auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]"); ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsIntEq(2)); + ASSERT_THAT(v.listElems()[0], IsIntEq(1)); + ASSERT_THAT(v.listElems()[1], IsIntEq(2)); } TEST_F(PrimOpTest, functionArgs) { @@ -227,11 +227,11 @@ namespace nix { auto x = v.attrs()->get(createSymbol("x")); ASSERT_NE(x, nullptr); - ASSERT_THAT(*x->value, IsFalse()); + ASSERT_THAT(x->value, IsFalse()); auto y = v.attrs()->get(createSymbol("y")); ASSERT_NE(y, nullptr); - ASSERT_THAT(*y->value, IsTrue()); + ASSERT_THAT(y->value, IsTrue()); } TEST_F(PrimOpTest, mapAttrs) { @@ -240,15 +240,15 @@ namespace nix { auto a = v.attrs()->get(createSymbol("a")); ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); - ASSERT_THAT(*a->value, IsIntEq(10)); + ASSERT_THAT(a->value, IsThunk()); + state.forceValue(a->value, noPos); + ASSERT_THAT(a->value, IsIntEq(10)); auto b = v.attrs()->get(createSymbol("b")); ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsThunk()); - state.forceValue(*b->value, noPos); - ASSERT_THAT(*b->value, IsIntEq(20)); + ASSERT_THAT(b->value, IsThunk()); + state.forceValue(b->value, noPos); + ASSERT_THAT(b->value, IsIntEq(20)); } TEST_F(PrimOpTest, isList) { @@ -288,7 +288,7 @@ namespace nix { auto v = eval("builtins.tail [ 3 2 1 0 ]"); ASSERT_THAT(v, IsListOfSize(3)); for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(2 - static_cast(n))); + ASSERT_THAT(elem, IsIntEq(2 - static_cast(n))); } TEST_F(PrimOpTest, tailEmpty) { @@ -299,26 +299,26 @@ namespace nix { auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]"); ASSERT_THAT(v, IsListOfSize(3)); auto elem = v.listElems()[0]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobar")); + ASSERT_THAT(elem, IsThunk()); + state.forceValue(elem, noPos); + ASSERT_THAT(elem, IsStringEq("foobar")); elem = v.listElems()[1]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobla")); + ASSERT_THAT(elem, IsThunk()); + state.forceValue(elem, noPos); + ASSERT_THAT(elem, IsStringEq("foobla")); elem = v.listElems()[2]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("fooabc")); + ASSERT_THAT(elem, IsThunk()); + state.forceValue(elem, noPos); + ASSERT_THAT(elem, IsStringEq("fooabc")); } TEST_F(PrimOpTest, filter) { auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]"); ASSERT_THAT(v, IsListOfSize(3)); for (const auto elem : v.listItems()) - ASSERT_THAT(*elem, IsIntEq(2)); + ASSERT_THAT(elem, IsIntEq(2)); } TEST_F(PrimOpTest, elemTrue) { @@ -335,7 +335,7 @@ namespace nix { auto v = eval("builtins.concatLists [[1 2] [3 4]]"); ASSERT_THAT(v, IsListOfSize(4)); for (const auto [i, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(static_cast(i)+1)); + ASSERT_THAT(elem, IsIntEq(static_cast(i) + 1)); } TEST_F(PrimOpTest, length) { @@ -373,9 +373,9 @@ namespace nix { ASSERT_EQ(v.type(), nList); ASSERT_EQ(v.listSize(), 3); for (const auto [i, elem] : enumerate(v.listItems())) { - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsIntEq(static_cast(i)+1)); + ASSERT_THAT(elem, IsThunk()); + state.forceValue(elem, noPos); + ASSERT_THAT(elem, IsIntEq(static_cast(i) + 1)); } } @@ -386,7 +386,7 @@ namespace nix { const std::vector numbers = { 42, 77, 147, 249, 483, 526 }; for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); + ASSERT_THAT(elem, IsIntEq(numbers[n])); } TEST_F(PrimOpTest, partition) { @@ -395,18 +395,18 @@ namespace nix { auto right = v.attrs()->get(createSymbol("right")); ASSERT_NE(right, nullptr); - ASSERT_THAT(*right->value, IsListOfSize(2)); - ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23)); - ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42)); + ASSERT_THAT(right->value, IsListOfSize(2)); + ASSERT_THAT(right->value.listElems()[0], IsIntEq(23)); + ASSERT_THAT(right->value.listElems()[1], IsIntEq(42)); auto wrong = v.attrs()->get(createSymbol("wrong")); ASSERT_NE(wrong, nullptr); - ASSERT_EQ(wrong->value->type(), nList); - ASSERT_EQ(wrong->value->listSize(), 3); - ASSERT_THAT(*wrong->value, IsListOfSize(3)); - ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1)); - ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9)); - ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3)); + ASSERT_EQ(wrong->value.type(), nList); + ASSERT_EQ(wrong->value.listSize(), 3); + ASSERT_THAT(wrong->value, IsListOfSize(3)); + ASSERT_THAT(wrong->value.listElems()[0], IsIntEq(1)); + ASSERT_THAT(wrong->value.listElems()[1], IsIntEq(9)); + ASSERT_THAT(wrong->value.listElems()[2], IsIntEq(3)); } TEST_F(PrimOpTest, concatMap) { @@ -416,7 +416,7 @@ namespace nix { const std::vector numbers = { 1, 2, 0, 3, 4, 0 }; for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); + ASSERT_THAT(elem, IsIntEq(numbers[n])); } TEST_F(PrimOpTest, addInt) { @@ -652,7 +652,7 @@ namespace nix { const std::vector strings = { "1", "2", "3", "git" }; for (const auto [n, p] : enumerate(v.listItems())) - ASSERT_THAT(*p, IsStringEq(strings[n])); + ASSERT_THAT(p, IsStringEq(strings[n])); } class CompareVersionsPrimOpTest : @@ -706,11 +706,11 @@ namespace nix { auto name = v.attrs()->get(createSymbol("name")); ASSERT_TRUE(name); - ASSERT_THAT(*name->value, IsStringEq(expectedName)); + ASSERT_THAT(name->value, IsStringEq(expectedName)); auto version = v.attrs()->get(createSymbol("version")); ASSERT_TRUE(version); - ASSERT_THAT(*version->value, IsStringEq(expectedVersion)); + ASSERT_THAT(version->value, IsStringEq(expectedVersion)); } INSTANTIATE_TEST_SUITE_P( @@ -741,12 +741,12 @@ namespace nix { auto v = eval("builtins.split \"(a)b\" \"abc\""); ASSERT_THAT(v, IsListOfSize(3)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + ASSERT_THAT(v.listElems()[0], IsStringEq("")); - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); + ASSERT_THAT(v.listElems()[1], IsListOfSize(1)); + ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a")); - ASSERT_THAT(*v.listElems()[2], IsStringEq("c")); + ASSERT_THAT(v.listElems()[2], IsStringEq("c")); } TEST_F(PrimOpTest, split2) { @@ -754,17 +754,17 @@ namespace nix { auto v = eval("builtins.split \"([ac])\" \"abc\""); ASSERT_THAT(v, IsListOfSize(5)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + ASSERT_THAT(v.listElems()[0], IsStringEq("")); - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); + ASSERT_THAT(v.listElems()[1], IsListOfSize(1)); + ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a")); - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); + ASSERT_THAT(v.listElems()[2], IsStringEq("b")); - ASSERT_THAT(*v.listElems()[3], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c")); + ASSERT_THAT(v.listElems()[3], IsListOfSize(1)); + ASSERT_THAT(v.listElems()[3].listElems()[0], IsStringEq("c")); - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); + ASSERT_THAT(v.listElems()[4], IsStringEq("")); } TEST_F(PrimOpTest, split3) { @@ -772,23 +772,23 @@ namespace nix { ASSERT_THAT(v, IsListOfSize(5)); // First list element - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + ASSERT_THAT(v.listElems()[0], IsStringEq("")); // 2nd list element is a list [ "" null ] - ASSERT_THAT(*v.listElems()[1], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull()); + ASSERT_THAT(v.listElems()[1], IsListOfSize(2)); + ASSERT_THAT(v.listElems()[1].listElems()[0], IsStringEq("a")); + ASSERT_THAT(v.listElems()[1].listElems()[1], IsNull()); // 3rd element - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); + ASSERT_THAT(v.listElems()[2], IsStringEq("b")); // 4th element is a list: [ null "c" ] - ASSERT_THAT(*v.listElems()[3], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull()); - ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c")); + ASSERT_THAT(v.listElems()[3], IsListOfSize(2)); + ASSERT_THAT(v.listElems()[3].listElems()[0], IsNull()); + ASSERT_THAT(v.listElems()[3].listElems()[1], IsStringEq("c")); // 5th element is the empty string - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); + ASSERT_THAT(v.listElems()[4], IsStringEq("")); } TEST_F(PrimOpTest, split4) { @@ -798,12 +798,12 @@ namespace nix { auto second = v.listElems()[1]; auto third = v.listElems()[2]; - ASSERT_THAT(*first, IsStringEq(" ")); + ASSERT_THAT(first, IsStringEq(" ")); - ASSERT_THAT(*second, IsListOfSize(1)); - ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO")); + ASSERT_THAT(second, IsListOfSize(1)); + ASSERT_THAT(second.listElems()[0], IsStringEq("FOO")); - ASSERT_THAT(*third, IsStringEq(" ")); + ASSERT_THAT(third, IsStringEq(" ")); } TEST_F(PrimOpTest, match1) { @@ -819,14 +819,14 @@ namespace nix { TEST_F(PrimOpTest, match3) { auto v = eval("builtins.match \"a(b)(c)\" \"abc\""); ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("b")); - ASSERT_THAT(*v.listElems()[1], IsStringEq("c")); + ASSERT_THAT(v.listElems()[0], IsStringEq("b")); + ASSERT_THAT(v.listElems()[1], IsStringEq("c")); } TEST_F(PrimOpTest, match4) { auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \""); ASSERT_THAT(v, IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO")); + ASSERT_THAT(v.listElems()[0], IsStringEq("FOO")); } TEST_F(PrimOpTest, attrNames) { @@ -836,7 +836,7 @@ namespace nix { // ensure that the list is sorted const std::vector expected { "a", "x", "y", "z" }; for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsStringEq(expected[n])); + ASSERT_THAT(elem, IsStringEq(expected[n])); } TEST_F(PrimOpTest, genericClosure_not_strict) { diff --git a/tests/unit/libexpr/trivial.cc b/tests/unit/libexpr/trivial.cc index 6f150478a..1b65789b4 100644 --- a/tests/unit/libexpr/trivial.cc +++ b/tests/unit/libexpr/trivial.cc @@ -69,11 +69,11 @@ namespace nix { ASSERT_THAT(v, IsAttrsOfSize(2)); auto a = v.attrs()->get(createSymbol("a")); ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsIntEq(3)); + ASSERT_THAT(a->value, IsIntEq(3)); auto b = v.attrs()->get(createSymbol("b")); ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(2)); + ASSERT_THAT(b->value, IsIntEq(2)); } TEST_F(TrivialExpressionTest, hasAttrOpFalse) { @@ -171,18 +171,18 @@ namespace nix { auto a = v.attrs()->get(createSymbol("a")); ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); + ASSERT_THAT(a->value, IsThunk()); + state.forceValue(a->value, noPos); - ASSERT_THAT(*a->value, IsAttrsOfSize(2)); + ASSERT_THAT(a->value, IsAttrsOfSize(2)); - auto b = a->value->attrs()->get(createSymbol("b")); + auto b = a->value.attrs()->get(createSymbol("b")); ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); + ASSERT_THAT(b->value, IsIntEq(1)); - auto c = a->value->attrs()->get(createSymbol("c")); + auto c = a->value.attrs()->get(createSymbol("c")); ASSERT_NE(c, nullptr); - ASSERT_THAT(*c->value, IsIntEq(2)); + ASSERT_THAT(c->value, IsIntEq(2)); } INSTANTIATE_TEST_SUITE_P( @@ -204,7 +204,7 @@ namespace nix { ASSERT_THAT(v, IsAttrsOfSize(1)); auto b = v.attrs()->get(createSymbol("or")); ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); + ASSERT_THAT(b->value, IsIntEq(1)); } TEST_F(TrivialExpressionTest, orCantBeUsed) { diff --git a/tests/unit/libexpr/value/print.cc b/tests/unit/libexpr/value/print.cc index d434a434c..70f4d3465 100644 --- a/tests/unit/libexpr/value/print.cc +++ b/tests/unit/libexpr/value/print.cc @@ -66,8 +66,8 @@ TEST_F(ValuePrintingTests, tAttrs) vTwo.mkInt(2); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("one"), &vOne); - builder.insert(evaluator.symbols.create("two"), &vTwo); + builder.insert(evaluator.symbols.create("one"), vOne); + builder.insert(evaluator.symbols.create("two"), vTwo); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -84,11 +84,11 @@ TEST_F(ValuePrintingTests, tList) vTwo.mkInt(2); auto vList = evaluator.mem.newList(5); - vList->elems[0] = &vOne; - vList->elems[1] = &vTwo; + vList->elems[0] = vOne; + vList->elems[1] = vTwo; vList->size = 3; - test(Value(NewValueAs::list, vList), "[ 1 2 «nullptr» ]"); + test(Value(NewValueAs::list, vList), "[ 1 2 «invalid» ]"); } TEST_F(ValuePrintingTests, vThunk) @@ -210,23 +210,23 @@ TEST_F(ValuePrintingTests, depthAttrs) vAttrsEmpty.mkAttrs(builderEmpty.finish()); BindingsBuilder builderNested = evaluator.buildBindings(1); - builderNested.insert(evaluator.symbols.create("zero"), &vZero); + builderNested.insert(evaluator.symbols.create("zero"), vZero); Value vAttrsNested; vAttrsNested.mkAttrs(builderNested.finish()); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("one"), &vOne); - builder.insert(evaluator.symbols.create("two"), &vTwo); - builder.insert(evaluator.symbols.create("empty"), &vAttrsEmpty); - builder.insert(evaluator.symbols.create("nested"), &vAttrsNested); + builder.insert(evaluator.symbols.create("one"), vOne); + builder.insert(evaluator.symbols.create("two"), vTwo); + builder.insert(evaluator.symbols.create("empty"), vAttrsEmpty); + builder.insert(evaluator.symbols.create("nested"), vAttrsNested); Value vAttrs; vAttrs.mkAttrs(builder.finish()); BindingsBuilder builder2 = evaluator.buildBindings(10); - builder2.insert(evaluator.symbols.create("one"), &vOne); - builder2.insert(evaluator.symbols.create("two"), &vTwo); - builder2.insert(evaluator.symbols.create("nested"), &vAttrs); + builder2.insert(evaluator.symbols.create("one"), vOne); + builder2.insert(evaluator.symbols.create("two"), vTwo); + builder2.insert(evaluator.symbols.create("nested"), vAttrs); Value vNested; vNested.mkAttrs(builder2.finish()); @@ -246,24 +246,24 @@ TEST_F(ValuePrintingTests, depthList) vTwo.mkInt(2); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("one"), &vOne); - builder.insert(evaluator.symbols.create("two"), &vTwo); + builder.insert(evaluator.symbols.create("one"), vOne); + builder.insert(evaluator.symbols.create("two"), vTwo); Value vAttrs; vAttrs.mkAttrs(builder.finish()); BindingsBuilder builder2 = evaluator.buildBindings(10); - builder2.insert(evaluator.symbols.create("one"), &vOne); - builder2.insert(evaluator.symbols.create("two"), &vTwo); - builder2.insert(evaluator.symbols.create("nested"), &vAttrs); + builder2.insert(evaluator.symbols.create("one"), vOne); + builder2.insert(evaluator.symbols.create("two"), vTwo); + builder2.insert(evaluator.symbols.create("nested"), vAttrs); Value vNested; vNested.mkAttrs(builder2.finish()); auto list = evaluator.mem.newList(5); - list->elems[0] = &vOne; - list->elems[1] = &vTwo; - list->elems[2] = &vNested; + list->elems[0] = vOne; + list->elems[1] = vTwo; + list->elems[2] = vNested; list->size = 3; Value vList{NewValueAs::list, list}; @@ -310,8 +310,8 @@ TEST_F(ValuePrintingTests, attrsTypeFirst) vApple.mkString("apple"); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("type"), &vType); - builder.insert(evaluator.symbols.create("apple"), &vApple); + builder.insert(evaluator.symbols.create("type"), vType); + builder.insert(evaluator.symbols.create("apple"), vApple); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -421,8 +421,8 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs) vTwo.mkInt(2); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("one"), &vOne); - builder.insert(evaluator.symbols.create("two"), &vTwo); + builder.insert(evaluator.symbols.create("one"), vOne); + builder.insert(evaluator.symbols.create("two"), vTwo); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -440,7 +440,7 @@ TEST_F(ValuePrintingTests, ansiColorsDerivation) vDerivation.mkString("derivation"); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.s.type, &vDerivation); + builder.insert(evaluator.s.type, vDerivation); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -468,7 +468,7 @@ TEST_F(ValuePrintingTests, ansiColorsError) state.eval(e, vError); test( - *vError.attrs()->begin()->value, + vError.attrs()->begin()->value, ANSI_RED "«error: uh oh!»" ANSI_NORMAL, PrintOptions{ .ansiColors = true, @@ -519,7 +519,7 @@ TEST_F(ValuePrintingTests, ansiColorsAssert) ASSERT_EQ(v.type(), nAttrs); test( - *v.attrs()->begin()->value, + v.attrs()->begin()->value, ANSI_RED "«error: assertion failed»" ANSI_NORMAL, PrintOptions{.ansiColors = true, .force = true} ); @@ -534,14 +534,14 @@ TEST_F(ValuePrintingTests, ansiColorsList) vTwo.mkInt(2); auto vList = evaluator.mem.newList(5); - vList->elems[0] = &vOne; - vList->elems[1] = &vTwo; + vList->elems[0] = vOne; + vList->elems[1] = vTwo; vList->size = 3; test( Value(NewValueAs::list, vList), "[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA - "«nullptr»" ANSI_NORMAL " ]", + "«invalid»" ANSI_NORMAL " ]", PrintOptions{.ansiColors = true} ); } @@ -640,14 +640,14 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated) vZero.mkInt(0); BindingsBuilder innerBuilder = evaluator.buildBindings(1); - innerBuilder.insert(evaluator.symbols.create("x"), &vZero); + innerBuilder.insert(evaluator.symbols.create("x"), vZero); Value vInner; vInner.mkAttrs(innerBuilder.finish()); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("a"), &vInner); - builder.insert(evaluator.symbols.create("b"), &vInner); + builder.insert(evaluator.symbols.create("a"), vInner); + builder.insert(evaluator.symbols.create("b"), vInner); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -665,14 +665,14 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated) vZero.mkInt(0); BindingsBuilder innerBuilder = evaluator.buildBindings(1); - innerBuilder.insert(evaluator.symbols.create("x"), &vZero); + innerBuilder.insert(evaluator.symbols.create("x"), vZero); Value vInner; vInner.mkAttrs(innerBuilder.finish()); auto vList = evaluator.mem.newList(3); - vList->elems[0] = &vInner; - vList->elems[1] = &vInner; + vList->elems[0] = vInner; + vList->elems[1] = vInner; vList->size = 2; test( @@ -688,14 +688,14 @@ TEST_F(ValuePrintingTests, listRepeated) vZero.mkInt(0); BindingsBuilder innerBuilder = evaluator.buildBindings(1); - innerBuilder.insert(evaluator.symbols.create("x"), &vZero); + innerBuilder.insert(evaluator.symbols.create("x"), vZero); Value vInner; vInner.mkAttrs(innerBuilder.finish()); auto list = evaluator.mem.newList(3); - list->elems[0] = &vInner; - list->elems[1] = &vInner; + list->elems[0] = vInner; + list->elems[1] = vInner; list->size = 2; Value vList(NewValueAs::list, list); @@ -716,8 +716,8 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided) vTwo.mkInt(2); BindingsBuilder builder = evaluator.buildBindings(10); - builder.insert(evaluator.symbols.create("one"), &vOne); - builder.insert(evaluator.symbols.create("two"), &vTwo); + builder.insert(evaluator.symbols.create("one"), vOne); + builder.insert(evaluator.symbols.create("two"), vTwo); Value vAttrs; vAttrs.mkAttrs(builder.finish()); @@ -732,7 +732,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided) Value vThree; vThree.mkInt(3); - builder.insert(evaluator.symbols.create("three"), &vThree); + builder.insert(evaluator.symbols.create("three"), vThree); vAttrs.mkAttrs(builder.finish()); test(vAttrs, @@ -753,8 +753,8 @@ TEST_F(ValuePrintingTests, ansiColorsListElided) auto list = evaluator.mem.newList(4); Value vList{NewValueAs::list, list}; - list->elems[0] = &vOne; - list->elems[1] = &vTwo; + list->elems[0] = vOne; + list->elems[1] = vTwo; list->size = 2; test(vList, @@ -767,7 +767,7 @@ TEST_F(ValuePrintingTests, ansiColorsListElided) Value vThree; vThree.mkInt(3); - list->elems[2] = &vThree; + list->elems[2] = vThree; list->size = 3; test(vList, @@ -787,7 +787,7 @@ TEST_F(ValuePrintingTests, osc8InAttrSets) auto vZero = Value{NewValueAs::integer, NixInt{0}}; - builder.insert(evaluator.symbols.create("x"), &vZero, pos); + builder.insert(evaluator.symbols.create("x"), vZero, pos); auto vAttrs = Value{NewValueAs::attrs, builder.finish()}; auto hyperlink = makeHyperlink("x", makeHyperlinkLocalPath("/dev/null", 1));