libexpr: de-ptr-ize many Value uses

with thunk state being shareable we no longer need to worry about value
uniqueness, only about value lifetime. this means we can liberally drop
indirections and allocations, passing references instead of pointers or
using stack memory instead of gc-managed memory for some intermediates.

Change-Id: I2d48a6fd57a376d544bd9bd2d05e5420611986d1
This commit is contained in:
eldritch horrors
2025-10-05 16:22:35 +02:00
parent 23df732ddb
commit db35aa753b
35 changed files with 311 additions and 247 deletions
+6 -6
View File
@@ -285,12 +285,12 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
};
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(
*state,
i,
takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs,
vRoot
).first);
Value v(
findAlongAttrPath(
*state, i, takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs, vRoot
)
.first
);
state->forceValue(v, noPos);
getDerivations(
*state,
+3 -3
View File
@@ -200,7 +200,7 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
Value vRoot;
loadSourceExpr(state, nixExprPath, vRoot);
Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, pathPrefix, autoArgs, vRoot).first);
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
@@ -482,7 +482,7 @@ static void queryInstSources(EvalState & state,
Value vRoot;
loadSourceExpr(state, *instSource.nixExprPath, vRoot);
for (auto & i : args) {
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
}
break;
@@ -519,7 +519,7 @@ static void setMetaFlag(EvalState & state, DrvInfo & drv,
{
auto v = state.ctx.mem.allocValue();
v->mkString(value);
drv.setMeta(state, name, v);
drv.setMeta(state, name, *v);
}
static void installDerivations(Globals & globals,
+1 -1
View File
@@ -38,7 +38,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
state.eval(e, vRoot);
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, i, autoArgs, vRoot).first);
state.forceValue(v, noPos);
NixStringContext context;
+11 -9
View File
@@ -12,9 +12,10 @@ namespace nix {
InstallableAttrPath::InstallableAttrPath(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec)
ExtendedOutputsSpec extendedOutputsSpec
)
: InstallableValue(state)
, cmd(cmd)
, v(allocRootValue(v))
@@ -22,10 +23,10 @@ InstallableAttrPath::InstallableAttrPath(
, extendedOutputsSpec(std::move(extendedOutputsSpec))
{ }
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
std::pair<Value, PosIdx> InstallableAttrPath::toValue(EvalState & state)
{
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(*evaluator), **v);
state.forceValue(*vRes, pos);
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(*evaluator), *v);
state.forceValue(vRes, pos);
return {vRes, pos};
}
@@ -34,7 +35,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
auto [v, pos] = toValue(state);
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
state, *v, pos, fmt("while evaluating the attribute '%s'", attrPath)
state, v, pos, fmt("while evaluating the attribute '%s'", attrPath)
))
{
return { *derivedPathWithInfo };
@@ -43,7 +44,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
Bindings & autoArgs = *cmd.getAutoArgs(*evaluator);
DrvInfos drvInfos;
getDerivations(state, *v, "", autoArgs, drvInfos, false);
getDerivations(state, v, "", autoArgs, drvInfos, false);
// Backward compatibility hack: group results by drvPath. This
// helps keep .all output together.
@@ -92,9 +93,10 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
InstallableAttrPath InstallableAttrPath::parse(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec)
ExtendedOutputsSpec extendedOutputsSpec
)
{
return {
state, cmd, v,
+7 -5
View File
@@ -20,13 +20,14 @@ class InstallableAttrPath : public InstallableValue
InstallableAttrPath(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec);
ExtendedOutputsSpec extendedOutputsSpec
);
std::string what() const override { return attrPath; };
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
std::pair<Value, PosIdx> toValue(EvalState & state) override;
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
@@ -35,9 +36,10 @@ public:
static InstallableAttrPath parse(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec);
ExtendedOutputsSpec extendedOutputsSpec
);
};
}
+2 -2
View File
@@ -136,9 +136,9 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths(EvalState & state)
}};
}
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
std::pair<Value, PosIdx> InstallableFlake::toValue(EvalState & state)
{
return {&getCursor(state)->forceValue(state), noPos};
return {getCursor(state)->forceValue(state), noPos};
}
std::vector<ref<eval_cache::AttrCursor>>
+1 -1
View File
@@ -55,7 +55,7 @@ struct InstallableFlake : InstallableValue
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
std::pair<Value, PosIdx> toValue(EvalState & state) override;
/**
* Get a cursor to every attrpath in getActualAttrPaths() that
+3 -2
View File
@@ -9,8 +9,9 @@ std::vector<ref<eval_cache::AttrCursor>>
InstallableValue::getCursors(EvalState & state)
{
auto evalCache =
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt,
[&](EvalState & state) { return toValue(state).first; });
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, [&](EvalState & state) {
return toValue(state).first;
});
return {evalCache->getRoot()};
}
+1 -1
View File
@@ -77,7 +77,7 @@ struct InstallableValue : Installable
virtual ~InstallableValue() { }
virtual std::pair<Value *, PosIdx> toValue(EvalState & state) = 0;
virtual std::pair<Value, PosIdx> toValue(EvalState & state) = 0;
/**
* Get a cursor to each value this Installable could refer to.
+9 -11
View File
@@ -235,8 +235,7 @@ void SourceExprCommand::completeInstallable(EvalState & state, AddCompletions &
prefix_ = "";
}
auto [v, pos] = findAlongAttrPath(state, prefix_, *autoArgs, root);
Value &v1(*v);
auto [v1, pos] = findAlongAttrPath(state, prefix_, *autoArgs, root);
state.forceValue(v1, pos);
Value v2;
state.autoCallFunction(*autoArgs, v1, v2, pos);
@@ -412,15 +411,15 @@ ref<eval_cache::EvalCache> openEvalCache(
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
throw Error("not everything is cached, but evaluation is not allowed");
auto vFlake = state.ctx.mem.allocValue();
flake::callFlake(state, *lockedFlake, *vFlake);
Value vFlake;
flake::callFlake(state, *lockedFlake, vFlake);
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
state.forceAttrs(vFlake, noPos, "while parsing cached flake data");
auto aOutputs = vFlake->attrs()->get(state.ctx.symbols.create("outputs"));
auto aOutputs = vFlake.attrs()->get(state.ctx.symbols.create("outputs"));
assert(aOutputs);
return aOutputs->value;
return *aOutputs->value;
};
if (fingerprint) {
@@ -465,10 +464,9 @@ Installables SourceExprCommand::parseInstallables(
for (auto & s : ss) {
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
result.push_back(
make_ref<InstallableAttrPath>(
InstallableAttrPath::parse(
evaluator, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
result.push_back(make_ref<InstallableAttrPath>(InstallableAttrPath::parse(
evaluator, *this, *vFile, std::move(prefix), std::move(extendedOutputsSpec)
)));
}
} else {
+1 -1
View File
@@ -949,7 +949,7 @@ void NixRepl::loadFiles()
for (auto & [i, what] : getValues()) {
notice("Loading installable '%1%'...", Magenta(what));
addAttrsToScope(*i);
addAttrsToScope(i);
}
loadReplOverlays();
+1 -1
View File
@@ -8,7 +8,7 @@ namespace nix {
struct AbstractNixRepl : NeverAsync
{
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
typedef std::vector<std::pair<Value, std::string>> AnnotatedValues;
static ReplExitStatus
run(const SearchPath & searchPath,
+24 -22
View File
@@ -69,13 +69,12 @@ std::string unparseAttrPath(std::vector<std::string> const & attrPath)
return ret.str();
}
std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
std::pair<Value, PosIdx>
findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & autoArgs, Value & vIn)
{
auto tokens = parseAttrPath(attrPath);
Value * v = &vIn;
Value v = vIn;
PosIdx pos = noPos;
for (auto [attrPathIdx, attr] : enumerate(tokens)) {
@@ -84,10 +83,10 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
auto attrIndex = string2Int<unsigned int>(attr);
/* Evaluate the expression. */
Value * vNew = state.ctx.mem.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew, pos);
Value vNew;
state.autoCallFunction(autoArgs, v, vNew, pos);
v = vNew;
state.forceValue(*v, noPos);
state.forceValue(v, noPos);
/* It should evaluate to either a set or an expression,
according to what is specified in the attrPath. */
@@ -96,7 +95,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
if (attr.empty())
throw Error("empty attribute name in selection path '%1%'", attrPath);
if (v->type() != nAttrs) {
if (v.type() != nAttrs) {
auto pathPart =
std::vector<std::string>(tokens.begin(), tokens.begin() + attrPathIdx);
state.ctx.errors
@@ -105,17 +104,18 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
"set but is %3%: %4%",
attrPath,
unparseAttrPath(pathPart),
showType(*v),
ValuePrinter(state, *v, errorPrintOptions)
showType(v),
ValuePrinter(state, v, errorPrintOptions)
)
.debugThrow();
}
auto a = v->attrs()->get(state.ctx.symbols.create(attr));
auto a = v.attrs()->get(state.ctx.symbols.create(attr));
if (!a) {
std::set<std::string> attrNames;
for (auto & attr : *v->attrs())
for (auto & attr : *v.attrs()) {
attrNames.emplace(state.ctx.symbols[attr.name]);
}
auto suggestions = Suggestions::bestMatches(attrNames, attr);
auto pathPart =
@@ -127,33 +127,33 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
attr,
attrPath,
unparseAttrPath(pathPart),
ValuePrinter(state, *v, errorPrintOptions)
ValuePrinter(state, v, errorPrintOptions)
);
}
v = &*a->value;
v = *a->value;
pos = a->pos;
} else {
if (!v->isList()) {
if (!v.isList()) {
state.ctx.errors
.make<TypeError>(
"the expression selected by the selection path '%1%' should be a list but "
"is %2%: %3%",
attrPath,
showType(*v),
ValuePrinter(state, *v, errorPrintOptions)
showType(v),
ValuePrinter(state, v, errorPrintOptions)
)
.debugThrow();
}
if (*attrIndex >= v->listSize()) {
if (*attrIndex >= v.listSize()) {
throw AttrPathNotFound(
"list index %1% in selection path '%2%' is out of range for list %3%",
*attrIndex,
attrPath,
ValuePrinter(state, *v, errorPrintOptions)
ValuePrinter(state, v, errorPrintOptions)
);
}
v = v->listElems()[*attrIndex];
v = *v.listElems()[*attrIndex];
pos = noPos;
}
@@ -165,7 +165,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
{
Value * v2;
Value v2;
try {
auto dummyArgs = state.ctx.mem.allocBindings(0);
v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
@@ -176,7 +176,9 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
// FIXME: is it possible to extract the Pos object instead of doing this
// toString + parsing?
NixStringContext context;
auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
auto path = state.coerceToPath(
noPos, v2, context, "while evaluating the 'meta.position' attribute of a derivation"
);
auto fn = path.canonical().abs();
+3 -5
View File
@@ -10,11 +10,9 @@ namespace nix {
MakeError(AttrPathNotFound, Error);
MakeError(NoPositionInfo, Error);
std::pair<Value *, PosIdx> findAlongAttrPath(
EvalState & state,
const std::string & attrPath,
Bindings & autoArgs,
Value & vIn);
std::pair<Value, PosIdx> findAlongAttrPath(
EvalState & state, const std::string & attrPath, Bindings & autoArgs, Value & vIn
);
/**
* Heuristic to find the filename and lineno or a nix value.
+6 -5
View File
@@ -341,7 +341,7 @@ EvalCache::EvalCache(
{
}
Value * EvalCache::getRootValue(EvalState & state)
Value & EvalCache::getRootValue(EvalState & state)
{
if (!value) {
debug("getting root value");
@@ -362,8 +362,9 @@ AttrCursor::AttrCursor(
std::optional<std::pair<AttrId, AttrValue>> && cachedValue)
: root(root), parent(parent), cachedValue(std::move(cachedValue))
{
if (value)
_value = allocRootValue(value);
if (value) {
_value = allocRootValue(*value);
}
}
AttrKey AttrCursor::getKey()
@@ -386,11 +387,11 @@ 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));
}
return **_value;
return *_value;
}
std::vector<std::string> AttrCursor::getAttrPath(EvalState & state) const
+2 -2
View File
@@ -12,7 +12,7 @@ namespace nix::eval_cache {
struct AttrDb;
class AttrCursor;
typedef std::function<Value *(EvalState &)> RootLoader;
typedef std::function<Value(EvalState &)> RootLoader;
/**
* EvalState with caching support. Historically this was part of EvalState,
@@ -42,7 +42,7 @@ class EvalCache : public std::enable_shared_from_this<EvalCache>
RootLoader rootLoader;
RootValue value;
Value * getRootValue(EvalState & state);
Value & getRootValue(EvalState & state);
public:
+28 -27
View File
@@ -69,9 +69,9 @@ gdb.execute("handle SIGPWR SIGXCPU ignore")
namespace nix {
RootValue allocRootValue(Value * v)
RootValue allocRootValue(Value v)
{
return std::allocate_shared<Value *>(TraceableAllocator<Value *>(), v);
return std::allocate_shared<Value>(TraceableAllocator<Value>(), v);
}
// Pretty print types for assertion errors
@@ -1157,12 +1157,12 @@ 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;
state.forceAttrs(*vOverrides, noPos, "while evaluating the `__overrides` attribute");
Bindings * newBnds = state.ctx.mem.allocBindings(capacity + vOverrides->attrs()->size());
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())
newBnds->push_back(i);
for (auto & i : *vOverrides->attrs()) {
for (auto & i : *vOverrides.attrs()) {
ExprAttrs::AttrDefs::iterator j = attrs.find(i.name);
if (j != attrs.end()) {
(*newBnds)[j->second.displ] = i;
@@ -1507,15 +1507,19 @@ FormalsMatch matchupLambdaAttrs(EvalState & state, Env & env, Displacement & dis
return result;
}
Env & SimplePattern::match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos)
Env & SimplePattern::match(
ExprLambda & lambda, EvalState & state, Env & up, Value & arg, const PosIdx pos
)
{
Env & env2(state.ctx.mem.allocEnv(1));
env2.up = &up;
env2.values[0] = arg;
env2.values[0] = &arg;
return env2;
}
Env & AttrsPattern::match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos)
Env & AttrsPattern::match(
ExprLambda & lambda, EvalState & state, Env & up, Value & arg, const PosIdx pos
)
{
auto & ctx = state.ctx;
@@ -1524,27 +1528,23 @@ Env & AttrsPattern::match(ExprLambda & lambda, EvalState & state, Env & up, Valu
Displacement displ = 0;
try {
state.forceAttrs(*arg, lambda.pos, "while evaluating the value passed for the lambda argument");
state.forceAttrs(
arg, lambda.pos, "while evaluating the value passed for the lambda argument"
);
} catch (Error & e) {
if (pos) e.addTrace(ctx.positions[pos], "from call site");
throw;
}
if (name)
env2.values[displ++] = arg;
if (name) {
env2.values[displ++] = &arg;
}
///* For each formal argument, get the actual argument. If
// there is no matching actual argument but the formal
// argument has a default, use the default. */
auto const formalsMatch = matchupLambdaAttrs(
state,
env2,
displ,
*this,
*arg->attrs(),
ctx.symbols
);
auto const formalsMatch =
matchupLambdaAttrs(state, env2, displ, *this, *arg.attrs(), ctx.symbols);
if (!formalsMatch.unexpected.empty() || !formalsMatch.missing.empty()) {
Suggestions sug; // empty suggestions -> no suggestions
@@ -1616,7 +1616,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> 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);
@@ -1781,10 +1781,10 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res, PosI
if (fun.type() == nAttrs) {
auto found = fun.attrs()->get(ctx.s.functor);
if (found) {
Value * v = ctx.mem.allocValue();
callFunction(*found->value, fun, *v, pos);
forceValue(*v, pos);
return autoCallFunction(args, *v, res, pos);
Value v;
callFunction(*found->value, fun, v, pos);
forceValue(v, pos);
return autoCallFunction(args, v, res, pos);
}
}
@@ -1829,7 +1829,8 @@ https://docs.lix.systems/manual/lix/stable/language/constructs.html#functions)",
}
}
callFunction(fun, ctx.mem.allocValue()->mkAttrs(attrs), res, pos);
Value vAttrs{NewValueAs::attrs, attrs.finish()};
callFunction(fun, vAttrs, res, pos);
}
+27 -17
View File
@@ -96,7 +96,7 @@ static void expectType(EvalState & state, ValueType type,
static std::pair<std::map<FlakeId, FlakeInput>, std::optional<fetchers::Attrs>> parseFlakeInputs(
EvalState & state,
Value * value,
Value & value,
const PosIdx pos,
const std::optional<Path> & baseDir,
InputPath lockRootPath,
@@ -144,11 +144,17 @@ static void parseFlakeInputAttr(EvalState & state, const Attr & attr, fetchers::
#pragma GCC diagnostic pop
}
static FlakeInput parseFlakeInput(EvalState & state,
const std::string & inputName, Value * value, const PosIdx pos,
const std::optional<Path> & baseDir, InputPath lockRootPath, unsigned depth)
static FlakeInput parseFlakeInput(
EvalState & state,
const std::string & inputName,
Value & value,
const PosIdx pos,
const std::optional<Path> & baseDir,
InputPath lockRootPath,
unsigned depth
)
{
expectType(state, nAttrs, *value, pos);
expectType(state, nAttrs, value, pos);
FlakeInput input;
@@ -160,7 +166,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
fetchers::Attrs attrs;
std::optional<std::string> url;
for (nix::Attr attr : *(value->attrs())) {
for (nix::Attr attr : *(value.attrs())) {
try {
if (attr.name == sUrl) {
expectType(state, nString, *attr.value, attr.pos);
@@ -172,7 +178,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
} 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) {
@@ -218,7 +224,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
static std::pair<std::map<FlakeId, FlakeInput>, std::optional<fetchers::Attrs>> parseFlakeInputs(
EvalState & state,
Value * value,
Value & value,
const PosIdx pos,
const std::optional<Path> & baseDir,
InputPath lockRootPath,
@@ -228,10 +234,10 @@ static std::pair<std::map<FlakeId, FlakeInput>, std::optional<fetchers::Attrs>>
{
std::map<FlakeId, FlakeInput> inputs;
expectType(state, nAttrs, *value, pos);
expectType(state, nAttrs, value, pos);
std::optional<fetchers::Attrs> selfAttrs = std::nullopt;
for (const nix::Attr & inputAttr : *(*value).attrs()) {
for (const nix::Attr & inputAttr : *value.attrs()) {
std::string inputName{state.ctx.symbols[inputAttr.name]};
if (inputName == "self") {
experimentalFeatureSettings.require(Xp::FlakeSelfAttrs);
@@ -251,7 +257,7 @@ static std::pair<std::map<FlakeId, FlakeInput>, std::optional<fetchers::Attrs>>
inputs.emplace(
inputName,
parseFlakeInput(
state, inputName, inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth
state, inputName, *inputAttr.value, inputAttr.pos, baseDir, lockRootPath, depth
)
);
}
@@ -337,7 +343,7 @@ static Flake getFlake(
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);
}
@@ -926,13 +932,17 @@ void callFlake(EvalState & state,
vRootSubdir->mkString(lockedFlake.flake.lockedRef.subdir);
if (!state.ctx.caches.vCallFlake) {
state.ctx.caches.vCallFlake = allocRootValue(state.ctx.mem.allocValue());
state.eval(state.ctx.parseExprFromString(
#include "call-flake.nix.gen.hh"
, CanonPath::root), **state.ctx.caches.vCallFlake);
state.ctx.caches.vCallFlake = allocRootValue({});
state.eval(
state.ctx.parseExprFromString(
#include "call-flake.nix.gen.hh"
, CanonPath::root
),
*state.ctx.caches.vCallFlake
);
}
state.callFunction(**state.ctx.caches.vCallFlake, *vLocks, *vTmp1, noPos);
state.callFunction(*state.ctx.caches.vCallFlake, *vLocks, *vTmp1, noPos);
state.callFunction(*vTmp1, *vRootSrc, *vTmp2, noPos);
state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos);
}
+2 -3
View File
@@ -384,8 +384,7 @@ bool DrvInfo::queryMetaBool(EvalState & state, const std::string & name, bool de
return def;
}
void DrvInfo::setMeta(EvalState & state, const std::string & name, Value * v)
void DrvInfo::setMeta(EvalState & state, const std::string & name, Value & v)
{
getMeta(state);
auto attrs = state.ctx.buildBindings(1 + (meta ? meta->size() : 0));
@@ -394,7 +393,7 @@ void DrvInfo::setMeta(EvalState & state, const std::string & name, Value * v)
for (auto i : *meta)
if (i.name != sym)
attrs.insert(i);
if (v) attrs.insert(sym, v);
attrs.insert(sym, &v);
meta = attrs.finish();
}
+1 -1
View File
@@ -73,7 +73,7 @@ public:
std::string queryMetaString(EvalState & state, const std::string & name);
NixInt queryMetaInt(EvalState & state, const std::string & name, NixInt def);
bool queryMetaBool(EvalState & state, const std::string & name, bool def);
void setMeta(EvalState & state, const std::string & name, Value * v);
void setMeta(EvalState & state, const std::string & name, Value & v);
/*
MetaInfo queryMetaInfo(EvalState & state) const;
+36 -27
View File
@@ -8,11 +8,6 @@
namespace nix {
/*
* Used for `JSONObjectState`
*/
using ValueMap = GcMap<Symbol, Value *>;
// for more information, refer to
// https://github.com/nlohmann/json/blob/master/include/nlohmann/detail/input/json_sax.hpp
class JSONSax : nlohmann::json_sax<JSON> {
@@ -26,49 +21,57 @@ class JSONSax : nlohmann::json_sax<JSON> {
assert(false && "tried to close toplevel json parser state");
}
explicit JSONState(std::unique_ptr<JSONState> && p) : parent(std::move(p)) {}
explicit JSONState(Value * v) : v(allocRootValue(v)) {}
JSONState() = default;
JSONState(JSONState & p) = delete;
Value & value(EvalState & state)
{
if (!v)
v = allocRootValue(state.ctx.mem.allocValue());
return **v;
if (!v) {
v = allocRootValue({});
}
return *v;
}
virtual ~JSONState() {}
virtual void add() {}
virtual void add(EvalState & state) {}
};
class JSONObjectState : public JSONState {
using JSONState::JSONState;
ValueMap attrs;
GcMap<Symbol, Value> attrs;
Symbol _key;
std::unique_ptr<JSONState> resolve(EvalState & state) override
{
auto attrs2 = state.ctx.buildBindings(attrs.size());
for (auto & i : attrs)
attrs2.insert(i.first, i.second);
for (auto & i : attrs) {
auto v = state.ctx.mem.allocValue();
*v = i.second;
attrs2.insert(i.first, v);
}
parent->value(state).mkAttrs(attrs2.alreadySorted());
return std::move(parent);
}
void add() override { v = nullptr; }
void add(EvalState & state) override {
attrs.insert_or_assign(_key, value(state));
v = nullptr;
}
public:
void key(string_t & name, EvalState & state)
{
attrs.insert_or_assign(state.ctx.symbols.create(name), &value(state));
_key = state.ctx.symbols.create(name);
}
};
class JSONListState : public JSONState {
GcVector<Value *> values;
GcVector<Value> values;
std::unique_ptr<JSONState> resolve(EvalState & state) override
{
auto list = state.ctx.mem.newList(values.size());
parent->value(state) = {NewValueAs::list, list};
for (size_t n = 0; n < values.size(); ++n) {
list->elems[n] = values[n];
*(list->elems[n] = state.ctx.mem.allocValue()) = values[n];
}
return std::move(parent);
}
void add() override {
void add(EvalState & state) override {
values.push_back(*v);
v = nullptr;
}
@@ -83,26 +86,31 @@ class JSONSax : nlohmann::json_sax<JSON> {
std::unique_ptr<JSONState> rs;
public:
JSONSax(EvalState & state, Value & v) : state(state), rs(new JSONState(&v)) {};
JSONSax(EvalState & state) : state(state), rs(new JSONState()) {};
Value result()
{
return rs->value(state);
}
bool null() override
{
rs->value(state).mkNull();
rs->add();
rs->add(state);
return true;
}
bool boolean(bool val) override
{
rs->value(state).mkBool(val);
rs->add();
rs->add(state);
return true;
}
bool number_integer(number_integer_t val) override
{
rs->value(state).mkInt(val);
rs->add();
rs->add(state);
return true;
}
@@ -115,21 +123,21 @@ public:
}
NixInt::Inner val = val_;
rs->value(state).mkInt(val);
rs->add();
rs->add(state);
return true;
}
bool number_float(number_float_t val, const string_t & s) override
{
rs->value(state).mkFloat(val);
rs->add();
rs->add(state);
return true;
}
bool string(string_t & val) override
{
rs->value(state).mkString(val);
rs->add();
rs->add(state);
return true;
}
@@ -156,7 +164,7 @@ public:
bool end_object() override {
rs = rs->resolve(state);
rs->add();
rs->add(state);
return true;
}
@@ -179,10 +187,11 @@ public:
void parseJSON(EvalState & state, const std::string_view & s_, Value & v)
{
JSONSax parser(state, v);
JSONSax parser(state);
bool res = JSON::sax_parse(s_, &parser);
if (!res)
throw JSONParseError("Invalid JSON Value");
v = parser.result();
}
}
+6 -3
View File
@@ -409,7 +409,8 @@ struct Pattern {
virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) = 0;
virtual void accept(ExprVisitor & ev) = 0;
virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) = 0;
virtual Env &
match(ExprLambda & lambda, EvalState & state, Env & up, Value & arg, const PosIdx pos) = 0;
virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const = 0;
};
@@ -424,7 +425,8 @@ struct SimplePattern : Pattern
virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) override;
virtual void accept(ExprVisitor & ev) override;
virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) override;
virtual Env &
match(ExprLambda & lambda, EvalState & state, Env & up, Value & arg, const PosIdx pos) override;
virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const override;
};
@@ -445,7 +447,8 @@ struct AttrsPattern : Pattern
virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) override;
virtual void accept(ExprVisitor & ev) override;
virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) override;
virtual Env &
match(ExprLambda & lambda, EvalState & state, Env & up, Value & arg, const PosIdx pos) override;
virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const override;
+63 -38
View File
@@ -196,18 +196,22 @@ static void import(EvalState & state, Value & vPath, Value * vScope, Value & v)
w->mkAttrs(attrs);
if (!state.ctx.caches.vImportedDrvToDerivation) {
state.ctx.caches.vImportedDrvToDerivation = allocRootValue(state.ctx.mem.allocValue());
state.eval(state.ctx.parseExprFromString(
#include "imported-drv-to-derivation.nix.gen.hh"
, CanonPath::root), **state.ctx.caches.vImportedDrvToDerivation);
state.ctx.caches.vImportedDrvToDerivation = allocRootValue({});
state.eval(
state.ctx.parseExprFromString(
#include "imported-drv-to-derivation.nix.gen.hh"
, CanonPath::root
),
*state.ctx.caches.vImportedDrvToDerivation
);
}
state.forceFunction(
**state.ctx.caches.vImportedDrvToDerivation,
*state.ctx.caches.vImportedDrvToDerivation,
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");
}
@@ -425,49 +429,70 @@ struct CompareValues : NeverAsync
CompareValues(EvalState & state, const std::string_view && errorCtx) : state(state), errorCtx(errorCtx) { };
bool operator () (Value * v1, Value * v2) const
bool operator()(Value * v1, Value * v2) const
{
return (*this)(*v1, *v2, errorCtx);
}
bool operator()(Value & v1, Value & v2) const
{
return (*this)(v1, v2, errorCtx);
}
bool operator () (Value * v1, Value * v2, std::string_view errorCtx) const
bool operator()(Value & v1, Value & v2, std::string_view errorCtx) const
{
try {
if (v1->type() == nFloat && v2->type() == nInt) {
return v1->fpoint() < v2->integer().value;
if (v1.type() == nFloat && v2.type() == nInt) {
return v1.fpoint() < v2.integer().value;
}
if (v1->type() == nInt && v2->type() == nFloat) {
return v1->integer().value < v2->fpoint();
if (v1.type() == nInt && v2.type() == nFloat) {
return v1.integer().value < v2.fpoint();
}
if (v1.type() != v2.type()) {
state.ctx.errors
.make<EvalError>("cannot compare %s with %s", showType(v1), showType(v2))
.debugThrow();
}
if (v1->type() != v2->type())
state.ctx.errors.make<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow();
// Allow selecting a subset of enum values
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (v1->type()) {
case nInt:
return v1->integer() < v2->integer();
case nFloat:
return v1->fpoint() < v2->fpoint();
case nString:
return v1->str() < v2->str();
case nPath:
return strcmp(v1->string().content, v2->string().content) < 0;
case nList:
// Lexicographic comparison
for (size_t i = 0;; i++) {
if (i == v2->listSize()) {
return false;
} else if (i == v1->listSize()) {
return true;
} else if (!state.eqValues(*v1->listElems()[i], *v2->listElems()[i], noPos, errorCtx)) {
return (*this)(v1->listElems()[i], v2->listElems()[i], "while comparing two list elements");
}
switch (v1.type()) {
case nInt:
return v1.integer() < v2.integer();
case nFloat:
return v1.fpoint() < v2.fpoint();
case nString:
return v1.str() < v2.str();
case nPath:
return strcmp(v1.string().content, v2.string().content) < 0;
case nList:
// Lexicographic comparison
for (size_t i = 0;; i++) {
if (i == v2.listSize()) {
return false;
} else if (i == v1.listSize()) {
return true;
} else if (!state.eqValues(
*v1.listElems()[i], *v2.listElems()[i], noPos, errorCtx
))
{
return (*this)(
*v1.listElems()[i],
*v2.listElems()[i],
"while comparing two list elements"
);
}
}
default:
state.ctx.errors.make<EvalError>("cannot compare %s with %s; values of that type are incomparable", showType(*v1), showType(*v2)).debugThrow();
#pragma GCC diagnostic pop
}
state.ctx.errors
.make<EvalError>(
"cannot compare %s with %s; values of that type are incomparable",
showType(v1),
showType(v2)
)
.debugThrow();
#pragma GCC diagnostic pop
}
} catch (Error & e) {
if (!errorCtx.empty())
e.addTrace(nullptr, errorCtx);
@@ -2255,7 +2280,7 @@ static void prim_sort(EvalState & state, Value * * args, Value & v)
if (args[0]->isPrimOp()) {
auto ptr = args[0]->primOp()->fun.target<decltype(&prim_lessThan)>();
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};
@@ -2493,7 +2518,7 @@ static void prim_lessThan(EvalState & state, Value * * args, Value & v)
state.forceValue(*args[0], noPos);
state.forceValue(*args[1], noPos);
CompareValues comp(state, "");
v.mkBool(comp(args[0], args[1]));
v.mkBool(comp(*args[0], *args[1]));
}
+2 -3
View File
@@ -1066,8 +1066,7 @@ using PrimOp = Value::PrimOp;
/**
* A value allocated in traceable memory.
*/
typedef std::shared_ptr<Value *> RootValue;
RootValue allocRootValue(Value * v);
typedef std::shared_ptr<Value> RootValue;
RootValue allocRootValue(Value v);
}
+8 -6
View File
@@ -96,20 +96,22 @@ struct CmdBundle : InstallableCommand
lockFlags
};
auto vRes = evaluator->mem.allocValue();
evalState->callFunction(*bundler.toValue(*evalState).first, *val, *vRes, noPos);
Value vRes;
auto fn = bundler.toValue(*evalState).first;
evalState->callFunction(fn, val, vRes, noPos);
if (!evalState->isDerivation(*vRes))
if (!evalState->isDerivation(vRes)) {
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
}
auto attr1 = vRes->attrs()->get(evaluator->s.drvPath);
auto attr1 = vRes.attrs()->get(evaluator->s.drvPath);
if (!attr1)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
NixStringContext context2;
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
auto attr2 = vRes->attrs()->get(evaluator->s.outPath);
auto attr2 = vRes.attrs()->get(evaluator->s.outPath);
if (!attr2)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
@@ -123,7 +125,7 @@ struct CmdBundle : InstallableCommand
}));
if (!outLink) {
auto * attr = vRes->attrs()->get(evaluator->s.name);
auto * attr = vRes.attrs()->get(evaluator->s.name);
if (!attr)
throw Error("attribute 'name' missing");
outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, "");
+1 -1
View File
@@ -37,7 +37,7 @@ struct CmdEdit : InstallableCommand
auto [v, pos] = installableValue->toValue(*state);
try {
return findPackageFilename(*state, *v, installable->what());
return findPackageFilename(*state, v, installable->what());
} catch (NoPositionInfo &) {
throw Error("cannot find position information for '%s", installableValue->what());
}
+13 -8
View File
@@ -79,21 +79,26 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
NixStringContext context;
if (apply) {
auto vApply = evaluator->mem.allocValue();
state->eval(evaluator->parseExprFromString(*apply, CanonPath::fromCwd()), *vApply);
auto vRes = evaluator->mem.allocValue();
state->callFunction(*vApply, *v, *vRes, noPos);
Value vApply;
state->eval(evaluator->parseExprFromString(*apply, CanonPath::fromCwd()), vApply);
Value vRes;
state->callFunction(vApply, v, vRes, noPos);
v = vRes;
}
if (raw) {
logger->pause();
writeFull(STDOUT_FILENO, *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
writeFull(
STDOUT_FILENO,
*state->coerceToString(
noPos, v, context, "while generating the eval command output"
)
);
}
else if (json)
{
logger->cout("%s", printValueAsJSON(*state, true, *v, pos, context, false));
logger->cout("%s", printValueAsJSON(*state, true, v, pos, context, false));
}
else
@@ -102,8 +107,8 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
"%s",
ValuePrinter(
*state,
*v,
PrintOptions {
v,
PrintOptions{
.force = true,
.derivationPaths = true,
.errors = ErrorPrintBehavior::ThrowTopLevel,
+6 -5
View File
@@ -522,9 +522,10 @@ struct CmdFlakeCheck : FlakeCommand
fmt("checking NixOS configuration '%s'", attrPath));
Bindings & bindings(*evaluator->mem.allocBindings(0));
auto vToplevel = findAlongAttrPath(*state, "config.system.build.toplevel", bindings, v).first;
state->forceValue(*vToplevel, pos);
if (!state->isDerivation(*vToplevel))
state->forceValue(vToplevel, pos);
if (!state->isDerivation(vToplevel)) {
throw Error("attribute 'config.system.build.toplevel' is not a derivation");
}
} catch (Error & e) {
e.addTrace(resolve(pos), HintFmt("while checking the NixOS configuration '%s'", attrPath));
reportError(e);
@@ -584,12 +585,12 @@ struct CmdFlakeCheck : FlakeCommand
{
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
auto vFlake = evaluator->mem.allocValue();
flake::callFlake(*state, flake, *vFlake);
Value vFlake;
flake::callFlake(*state, flake, vFlake);
enumerateOutputs(
*state,
*vFlake,
vFlake,
[&](const std::string_view name, Value & vOutput, const PosIdx pos) {
Activity act(*logger, lvlInfo, actUnknown,
fmt("checking flake output '%s'", name));
+14 -10
View File
@@ -357,19 +357,23 @@ static void showHelp(AsyncIoRoot & aio, std::vector<std::string> subcommand, Nix
Evaluator evaluator(aio, {}, aio.blockOn(openStore("dummy://")));
auto state = evaluator.begin(aio);
auto vGenerateManpage = evaluator.mem.allocValue();
state->eval(evaluator.parseExprFromString(
#include "generate-manpage.nix.gen.hh"
, CanonPath::root), *vGenerateManpage);
Value vGenerateManpage;
state->eval(
evaluator.parseExprFromString(
#include "generate-manpage.nix.gen.hh"
, CanonPath::root
),
vGenerateManpage
);
auto vDump = evaluator.mem.allocValue();
vDump->mkString(toplevel.dumpCli());
Value vDump;
vDump.mkString(toplevel.dumpCli());
auto vRes = evaluator.mem.allocValue();
state->callFunction(*vGenerateManpage, evaluator.builtins.get("false"), *vRes, noPos);
state->callFunction(*vRes, *vDump, *vRes, noPos);
Value vRes;
state->callFunction(vGenerateManpage, evaluator.builtins.get("false"), vRes, noPos);
state->callFunction(vRes, vDump, vRes, noPos);
auto attr = vRes->attrs()->get(evaluator.symbols.create(mdName + ".md"));
auto attr = vRes.attrs()->get(evaluator.symbols.create(mdName + ".md"));
if (!attr)
throw UsageError("`nix` has no subcommand '%s'", concatStringsSep("", subcommand));
+1 -1
View File
@@ -207,7 +207,7 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str
evaluator->paths.resolveExprPath(
aio.blockOn(lookupFileArg(*evaluator, args.empty() ? "." : args[0])).unwrap()),
vRoot);
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
Value v(findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
state->forceAttrs(v, noPos, "while evaluating the source attribute to prefetch");
/* Extract the URL. */
+4 -4
View File
@@ -66,15 +66,15 @@ struct CmdRepl : RawInstallablesCommand
if (file){
auto [val, pos] = installable.toValue(*state);
auto what = installable.what();
state->forceValue(*val, pos);
state->forceValue(val, pos);
auto autoArgs = getAutoArgs(*evaluator);
auto valPost = evaluator->mem.allocValue();
state->autoCallFunction(*autoArgs, *val, *valPost, pos);
state->autoCallFunction(*autoArgs, val, *valPost, pos);
state->forceValue(*valPost, pos);
values.push_back( {valPost, what });
values.push_back({*valPost, what});
} else {
auto [val, pos] = installable.toValue(*state);
values.push_back( {val, what} );
values.push_back({val, what});
}
}
return values;
+6 -4
View File
@@ -292,12 +292,14 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
auto evaluator = std::make_unique<Evaluator>(aio(), SearchPath{}, store);
auto state = evaluator->begin(aio());
auto v = evaluator->mem.allocValue();
state->eval(evaluator->parseExprFromString(data, CanonPath("/no-such-path")), *v);
Value v;
state->eval(evaluator->parseExprFromString(data, CanonPath("/no-such-path")), v);
Bindings & bindings(*evaluator->mem.allocBindings(0));
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first;
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, v).first;
return store->parseStorePath(state->forceString(*v2, noPos, "while evaluating the path tho latest nix version"));
return store->parseStorePath(
state->forceString(v2, noPos, "while evaluating the path tho latest nix version")
);
}
};
+4 -4
View File
@@ -126,7 +126,7 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
nix::Bindings &autoArgs, nix::AutoCloseFD &to,
nix::AutoCloseFD &from, MyArgs &args, nix::AsyncIoRoot &aio) {
nix::Value *vRoot = [&]() {
nix::Value vRoot = [&]() {
auto state = evaluator->begin(aio);
if (args.flake) {
auto [flakeRef, fragment, outputSpec] =
@@ -138,7 +138,7 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
return flake.toValue(*state).first;
} else {
return releaseExprTopLevelValue(*state, autoArgs, args);
return *releaseExprTopLevelValue(*state, autoArgs, args);
}
}();
@@ -168,11 +168,11 @@ void worker(nix::ref<nix::eval_cache::CachingEvaluator> evaluator,
nix::JSON{{"attr", attrPathS}, {"attrPath", path}};
try {
auto vTmp =
nix::findAlongAttrPath(*state, attrPathS, autoArgs, *vRoot)
nix::findAlongAttrPath(*state, attrPathS, autoArgs, vRoot)
.first;
auto v = evaluator->mem.allocValue();
state->autoCallFunction(autoArgs, *vTmp, *v, {});
state->autoCallFunction(autoArgs, vTmp, *v, {});
if (v->type() == nix::nAttrs) {
if (auto drvInfo = nix::getDerivation(*state, *v, false)) {
+2 -2
View File
@@ -15,7 +15,7 @@ namespace nix {
class AttrPathEval : public LibExprTest
{
public:
std::pair<Value *, PosIdx> testFindAlongAttrPath(std::string expr, std::string path);
std::pair<Value, PosIdx> testFindAlongAttrPath(std::string expr, std::string path);
};
RC_GTEST_PROP(AttrPath, prop_round_trip, ())
@@ -29,7 +29,7 @@ RC_GTEST_PROP(AttrPath, prop_round_trip, ())
RC_ASSERT(strings == unparsedReparsed);
}
std::pair<Value *, PosIdx> AttrPathEval::testFindAlongAttrPath(std::string expr, std::string path)
std::pair<Value, PosIdx> AttrPathEval::testFindAlongAttrPath(std::string expr, std::string path)
{
auto v = eval(expr);
auto bindings = evalState().ctx.buildBindings(0).finish();
+6 -6
View File
@@ -27,9 +27,9 @@ RC_GTEST_FIXTURE_PROP(
prop_opaque_path_round_trip,
(const SingleDerivedPath::Opaque & o))
{
auto * v = evaluator.mem.allocValue();
evaluator.paths.mkStorePathString(o.path, *v);
auto d = state.coerceToSingleDerivedPath(noPos, *v, "");
Value v;
evaluator.paths.mkStorePathString(o.path, v);
auto d = state.coerceToSingleDerivedPath(noPos, v, "");
RC_ASSERT(SingleDerivedPath { o } == d);
}
@@ -41,9 +41,9 @@ RC_GTEST_FIXTURE_PROP(
prop_derived_path_built_out_path_round_trip,
(const SingleDerivedPath::Built & b, const StorePath & outPath))
{
auto * v = evaluator.mem.allocValue();
state.mkOutputString(*v, b, outPath);
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, "");
Value v;
state.mkOutputString(v, b, outPath);
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, v, "");
RC_ASSERT(SingleDerivedPath { b } == d);
}