This commit is contained in:
Eelco Dolstra 2022-02-04 00:33:13 +01:00
commit 4c755c3b3f
15 changed files with 41 additions and 56 deletions

View file

@ -198,8 +198,9 @@ void SourceExprCommand::completeInstallable(std::string_view prefix)
prefix_ = ""; prefix_ = "";
} }
Value &v1(*findAlongAttrPath(*state, prefix_, *autoArgs, root).first); auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root);
state->forceValue(v1); Value &v1(*v);
state->forceValue(v1, pos);
Value v2; Value v2;
state->autoCallFunction(*autoArgs, v1, v2); state->autoCallFunction(*autoArgs, v1, v2);
@ -446,7 +447,7 @@ struct InstallableAttrPath : InstallableValue
std::pair<Value *, Pos> toValue(EvalState & state) override std::pair<Value *, Pos> toValue(EvalState & state) override
{ {
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v); auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
state.forceValue(*vRes); state.forceValue(*vRes, pos);
return {vRes, pos}; return {vRes, pos};
} }
@ -496,7 +497,7 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
assert(aOutputs); assert(aOutputs);
state.forceValue(*aOutputs->value); state.forceValue(*aOutputs->value, aOutputs->value->determinePos(noPos));
return aOutputs->value; return aOutputs->value;
} }
@ -521,7 +522,7 @@ ref<eval_cache::EvalCache> openEvalCache(
auto vFlake = state.allocValue(); auto vFlake = state.allocValue();
flake::callFlake(state, *lockedFlake, *vFlake); flake::callFlake(state, *lockedFlake, *vFlake);
state.forceAttrs(*vFlake); state.forceAttrs(*vFlake, noPos);
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
assert(aOutputs); assert(aOutputs);
@ -608,7 +609,7 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
for (auto & attrPath : getActualAttrPaths()) { for (auto & attrPath : getActualAttrPaths()) {
try { try {
auto [v, pos] = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs); auto [v, pos] = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
state.forceValue(*v); state.forceValue(*v, pos);
return {v, pos}; return {v, pos};
} catch (AttrPathNotFound & e) { } catch (AttrPathNotFound & e) {
} }

View file

@ -58,7 +58,7 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
Value * vNew = state.allocValue(); Value * vNew = state.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew); state.autoCallFunction(autoArgs, *v, *vNew);
v = vNew; v = vNew;
state.forceValue(*v); state.forceValue(*v, noPos);
/* It should evaluate to either a set or an expression, /* It should evaluate to either a set or an expression,
according to what is specified in the attrPath. */ according to what is specified in the attrPath. */

View file

@ -336,7 +336,7 @@ Value & AttrCursor::getValue()
if (!_value) { if (!_value) {
if (parent) { if (parent) {
auto & vParent = parent->first->getValue(); auto & vParent = parent->first->getValue();
root->state.forceAttrs(vParent); root->state.forceAttrs(vParent, noPos);
auto attr = vParent.attrs->get(parent->second); auto attr = vParent.attrs->get(parent->second);
if (!attr) if (!attr)
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr()); throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
@ -381,7 +381,7 @@ Value & AttrCursor::forceValue()
auto & v = getValue(); auto & v = getValue();
try { try {
root->state.forceValue(v); root->state.forceValue(v, noPos);
} catch (EvalError &) { } catch (EvalError &) {
debug("setting '%s' to failed", getAttrPathStr()); debug("setting '%s' to failed", getAttrPathStr());
if (root->db) if (root->db)

View file

@ -51,14 +51,6 @@ void EvalState::forceValue(Value & v, const Pos & pos)
} }
inline void EvalState::forceAttrs(Value & v)
{
forceValue(v);
if (v.type() != nAttrs)
throwTypeError("value is %1% while a set was expected", v);
}
inline void EvalState::forceAttrs(Value & v, const Pos & pos) inline void EvalState::forceAttrs(Value & v, const Pos & pos)
{ {
forceValue(v, pos); forceValue(v, pos);
@ -67,14 +59,6 @@ inline void EvalState::forceAttrs(Value & v, const Pos & pos)
} }
inline void EvalState::forceList(Value & v)
{
forceValue(v);
if (!v.isList())
throwTypeError("value is %1% while a list was expected", v);
}
inline void EvalState::forceList(Value & v, const Pos & pos) inline void EvalState::forceList(Value & v, const Pos & pos)
{ {
forceValue(v, pos); forceValue(v, pos);

View file

@ -1138,7 +1138,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
Hence we need __overrides.) */ Hence we need __overrides.) */
if (hasOverrides) { if (hasOverrides) {
Value * vOverrides = (*v.attrs)[overrides->second.displ].value; Value * vOverrides = (*v.attrs)[overrides->second.displ].value;
state.forceAttrs(*vOverrides); state.forceAttrs(*vOverrides, vOverrides->determinePos(noPos));
Bindings * newBnds = state.allocBindings(v.attrs->capacity() + vOverrides->attrs->size()); Bindings * newBnds = state.allocBindings(v.attrs->capacity() + vOverrides->attrs->size());
for (auto & i : *v.attrs) for (auto & i : *v.attrs)
newBnds->push_back(i); newBnds->push_back(i);
@ -1286,7 +1286,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
e->eval(state, env, vTmp); e->eval(state, env, vTmp);
for (auto & i : attrPath) { for (auto & i : attrPath) {
state.forceValue(*vAttrs); state.forceValue(*vAttrs, noPos);
Bindings::iterator j; Bindings::iterator j;
Symbol name = getName(i, state, env); Symbol name = getName(i, state, env);
if (vAttrs->type() != nAttrs || if (vAttrs->type() != nAttrs ||
@ -1500,14 +1500,15 @@ void EvalState::incrFunctionCall(ExprLambda * fun)
void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
{ {
forceValue(fun); Pos pos = fun.determinePos(noPos);
forceValue(fun, pos);
if (fun.type() == nAttrs) { if (fun.type() == nAttrs) {
auto found = fun.attrs->find(sFunctor); auto found = fun.attrs->find(sFunctor);
if (found != fun.attrs->end()) { if (found != fun.attrs->end()) {
Value * v = allocValue(); Value * v = allocValue();
callFunction(*found->value, fun, *v, noPos); callFunction(*found->value, fun, *v, pos);
forceValue(*v); forceValue(*v, pos);
return autoCallFunction(args, *v, res); return autoCallFunction(args, *v, res);
} }
} }
@ -1796,7 +1797,7 @@ void EvalState::forceValueDeep(Value & v)
recurse = [&](Value & v) { recurse = [&](Value & v) {
if (!seen.insert(&v).second) return; if (!seen.insert(&v).second) return;
forceValue(v); forceValue(v, v.determinePos(noPos));
if (v.type() == nAttrs) { if (v.type() == nAttrs) {
for (auto & i : *v.attrs) for (auto & i : *v.attrs)
@ -1933,7 +1934,7 @@ bool EvalState::isDerivation(Value & v)
if (v.type() != nAttrs) return false; if (v.type() != nAttrs) return false;
Bindings::iterator i = v.attrs->find(sType); Bindings::iterator i = v.attrs->find(sType);
if (i == v.attrs->end()) return false; if (i == v.attrs->end()) return false;
forceValue(*i->value); forceValue(*i->value, *i->pos);
if (i->value->type() != nString) return false; if (i->value->type() != nString) return false;
return strcmp(i->value->string.s, "derivation") == 0; return strcmp(i->value->string.s, "derivation") == 0;
} }
@ -2045,8 +2046,8 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
bool EvalState::eqValues(Value & v1, Value & v2) bool EvalState::eqValues(Value & v1, Value & v2)
{ {
forceValue(v1); forceValue(v1, noPos);
forceValue(v2); forceValue(v2, noPos);
/* !!! Hack to support some old broken code that relies on pointer /* !!! Hack to support some old broken code that relies on pointer
equality tests between sets. (Specifically, builderDefs calls equality tests between sets. (Specifically, builderDefs calls

View file

@ -222,7 +222,7 @@ public:
of the evaluation of the thunk. If `v' is a delayed function of the evaluation of the thunk. If `v' is a delayed function
application, call the function and overwrite `v' with the application, call the function and overwrite `v' with the
result. Otherwise, this is a no-op. */ result. Otherwise, this is a no-op. */
inline void forceValue(Value & v, const Pos & pos = noPos); inline void forceValue(Value & v, const Pos & pos);
/* Force a value, then recursively force list elements and /* Force a value, then recursively force list elements and
attributes. */ attributes. */
@ -232,9 +232,7 @@ public:
NixInt forceInt(Value & v, const Pos & pos); NixInt forceInt(Value & v, const Pos & pos);
NixFloat forceFloat(Value & v, const Pos & pos); NixFloat forceFloat(Value & v, const Pos & pos);
bool forceBool(Value & v, const Pos & pos); bool forceBool(Value & v, const Pos & pos);
inline void forceAttrs(Value & v);
inline void forceAttrs(Value & v, const Pos & pos); inline void forceAttrs(Value & v, const Pos & pos);
inline void forceList(Value & v);
inline void forceList(Value & v, const Pos & pos); inline void forceList(Value & v, const Pos & pos);
void forceFunction(Value & v, const Pos & pos); // either lambda or primop void forceFunction(Value & v, const Pos & pos); // either lambda or primop
std::string_view forceString(Value & v, const Pos & pos = noPos); std::string_view forceString(Value & v, const Pos & pos = noPos);

View file

@ -107,7 +107,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
string name(state->forceStringNoCtx(*elem, *i->pos)); string name(state->forceStringNoCtx(*elem, *i->pos));
Bindings::iterator out = attrs->find(state->symbols.create(name)); Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error? if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value); state->forceAttrs(*out->value, *i->pos);
/* And evaluate its outPath attribute. */ /* And evaluate its outPath attribute. */
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
@ -172,7 +172,7 @@ StringSet DrvInfo::queryMetaNames()
bool DrvInfo::checkMeta(Value & v) bool DrvInfo::checkMeta(Value & v)
{ {
state->forceValue(v); state->forceValue(v, v.determinePos(noPos));
if (v.type() == nList) { if (v.type() == nList) {
for (auto elem : v.listItems()) for (auto elem : v.listItems())
if (!checkMeta(*elem)) return false; if (!checkMeta(*elem)) return false;
@ -278,7 +278,7 @@ static bool getDerivation(EvalState & state, Value & v,
bool ignoreAssertionFailures) bool ignoreAssertionFailures)
{ {
try { try {
state.forceValue(v); state.forceValue(v, v.determinePos(noPos));
if (!state.isDerivation(v)) return true; if (!state.isDerivation(v)) return true;
/* Remove spurious duplicates (e.g., a set like `rec { x = /* Remove spurious duplicates (e.g., a set like `rec { x =

View file

@ -210,7 +210,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
if (!vScope) if (!vScope)
state.evalFile(path, v); state.evalFile(path, v);
else { else {
state.forceAttrs(*vScope); state.forceAttrs(*vScope, pos);
Env * env = &state.allocEnv(vScope->attrs->size()); Env * env = &state.allocEnv(vScope->attrs->size());
env->up = &state.baseEnv; env->up = &state.baseEnv;
@ -2502,7 +2502,7 @@ static void prim_zipAttrsWith(EvalState & state, const Pos & pos, Value * * args
for (unsigned int n = 0; n < listSize; ++n) { for (unsigned int n = 0; n < listSize; ++n) {
Value * vElem = listElems[n]; Value * vElem = listElems[n];
try { try {
state.forceAttrs(*vElem); state.forceAttrs(*vElem, noPos);
for (auto & attr : *vElem->attrs) for (auto & attr : *vElem->attrs)
attrsSeen[attr.name].first++; attrsSeen[attr.name].first++;
} catch (TypeError & e) { } catch (TypeError & e) {

View file

@ -318,7 +318,7 @@ static void main_nix_build(int argc, char * * argv)
for (auto & i : attrPaths) { for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(*state, i, *autoArgs, vRoot).first); Value & v(*findAlongAttrPath(*state, i, *autoArgs, vRoot).first);
state->forceValue(v); state->forceValue(v, v.determinePos(noPos));
getDerivations(*state, v, "", *autoArgs, drvs, false); getDerivations(*state, v, "", *autoArgs, drvs, false);
} }
} }

View file

@ -129,7 +129,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* Evaluate it. */ /* Evaluate it. */
debug("evaluating user environment builder"); debug("evaluating user environment builder");
state.forceValue(topLevel); state.forceValue(topLevel, topLevel.determinePos(noPos));
PathSet context; PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath)); Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context)); auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context));

View file

@ -40,7 +40,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
for (auto & i : attrPaths) { for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first); Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
state.forceValue(v); state.forceValue(v, v.determinePos(noPos));
PathSet context; PathSet context;
if (evalOnly) { if (evalOnly) {

View file

@ -81,7 +81,7 @@ struct CmdEval : MixJSON, InstallableCommand
recurse = [&](Value & v, const Pos & pos, const Path & path) recurse = [&](Value & v, const Pos & pos, const Path & path)
{ {
state->forceValue(v); state->forceValue(v, pos);
if (v.type() == nString) if (v.type() == nString)
// FIXME: disallow strings with contexts? // FIXME: disallow strings with contexts?
writeFile(path, v.string.s); writeFile(path, v.string.s);

View file

@ -124,12 +124,13 @@ struct CmdFlakeLock : FlakeCommand
static void enumerateOutputs(EvalState & state, Value & vFlake, static void enumerateOutputs(EvalState & state, Value & vFlake,
std::function<void(const std::string & name, Value & vProvide, const Pos & pos)> callback) std::function<void(const std::string & name, Value & vProvide, const Pos & pos)> callback)
{ {
state.forceAttrs(vFlake); auto pos = vFlake.determinePos(noPos);
state.forceAttrs(vFlake, pos);
auto aOutputs = vFlake.attrs->get(state.symbols.create("outputs")); auto aOutputs = vFlake.attrs->get(state.symbols.create("outputs"));
assert(aOutputs); assert(aOutputs);
state.forceAttrs(*aOutputs->value); state.forceAttrs(*aOutputs->value, pos);
auto sHydraJobs = state.symbols.create("hydraJobs"); auto sHydraJobs = state.symbols.create("hydraJobs");

View file

@ -28,12 +28,12 @@ string resolveMirrorUrl(EvalState & state, string url)
Value vMirrors; Value vMirrors;
// FIXME: use nixpkgs flake // FIXME: use nixpkgs flake
state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors); state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors);
state.forceAttrs(vMirrors); state.forceAttrs(vMirrors, noPos);
auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName)); auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
if (mirrorList == vMirrors.attrs->end()) if (mirrorList == vMirrors.attrs->end())
throw Error("unknown mirror name '%s'", mirrorName); throw Error("unknown mirror name '%s'", mirrorName);
state.forceList(*mirrorList->value); state.forceList(*mirrorList->value, noPos);
if (mirrorList->value->listSize() < 1) if (mirrorList->value->listSize() < 1)
throw Error("mirror URL '%s' did not expand to anything", url); throw Error("mirror URL '%s' did not expand to anything", url);
@ -196,11 +196,11 @@ static int main_nix_prefetch_url(int argc, char * * argv)
Value vRoot; Value vRoot;
state->evalFile(path, vRoot); state->evalFile(path, vRoot);
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first); Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
state->forceAttrs(v); state->forceAttrs(v, noPos);
/* Extract the URL. */ /* Extract the URL. */
auto & attr = v.attrs->need(state->symbols.create("urls")); auto & attr = v.attrs->need(state->symbols.create("urls"));
state->forceList(*attr.value); state->forceList(*attr.value, noPos);
if (attr.value->listSize() < 1) if (attr.value->listSize() < 1)
throw Error("'urls' list is empty"); throw Error("'urls' list is empty");
url = state->forceString(*attr.value->listElems()[0]); url = state->forceString(*attr.value->listElems()[0]);

View file

@ -342,7 +342,7 @@ StringSet NixRepl::completePrefix(string prefix)
Expr * e = parseString(expr); Expr * e = parseString(expr);
Value v; Value v;
e->eval(*state, *env, v); e->eval(*state, *env, v);
state->forceAttrs(v); state->forceAttrs(v, noPos);
for (auto & i : *v.attrs) { for (auto & i : *v.attrs) {
string name = i.name; string name = i.name;
@ -673,7 +673,7 @@ void NixRepl::reloadFiles()
void NixRepl::addAttrsToScope(Value & attrs) void NixRepl::addAttrsToScope(Value & attrs)
{ {
state->forceAttrs(attrs); state->forceAttrs(attrs, attrs.determinePos(noPos));
if (displ + attrs.attrs->size() >= envSize) if (displ + attrs.attrs->size() >= envSize)
throw Error("environment full; cannot add more variables"); throw Error("environment full; cannot add more variables");
@ -712,7 +712,7 @@ void NixRepl::evalString(string s, Value & v)
{ {
Expr * e = parseString(s); Expr * e = parseString(s);
e->eval(*state, *env, v); e->eval(*state, *env, v);
state->forceValue(v); state->forceValue(v, v.determinePos(noPos));
} }
@ -742,7 +742,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
str.flush(); str.flush();
checkInterrupt(); checkInterrupt();
state->forceValue(v); state->forceValue(v, v.determinePos(noPos));
switch (v.type()) { switch (v.type()) {