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:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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>>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()};
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user