Make most calls to determinePos() lazy

This commit is contained in:
Eelco Dolstra 2022-02-04 00:31:33 +01:00
parent 4c755c3b3f
commit bd383d1b6f
10 changed files with 46 additions and 24 deletions

View file

@ -497,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, aOutputs->value->determinePos(noPos)); state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); });
return aOutputs->value; return aOutputs->value;
} }

View file

@ -15,12 +15,6 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s))
}); });
} }
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
{
throw TypeError(s, showType(v));
}
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v)) LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v))
{ {
throw TypeError({ throw TypeError({
@ -31,6 +25,13 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const
void EvalState::forceValue(Value & v, const Pos & pos) void EvalState::forceValue(Value & v, const Pos & pos)
{
forceValue(v, [&]() { return pos; });
}
template<typename Callable>
void EvalState::forceValue(Value & v, Callable getPos)
{ {
if (v.isThunk()) { if (v.isThunk()) {
Env * env = v.thunk.env; Env * env = v.thunk.env;
@ -47,15 +48,22 @@ void EvalState::forceValue(Value & v, const Pos & pos)
else if (v.isApp()) else if (v.isApp())
callFunction(*v.app.left, *v.app.right, v, noPos); callFunction(*v.app.left, *v.app.right, v, noPos);
else if (v.isBlackhole()) else if (v.isBlackhole())
throwEvalError(pos, "infinite recursion encountered"); throwEvalError(getPos(), "infinite recursion encountered");
} }
inline void EvalState::forceAttrs(Value & v, const Pos & pos) inline void EvalState::forceAttrs(Value & v, const Pos & pos)
{ {
forceValue(v, pos); forceAttrs(v, [&]() { return pos; });
}
template <typename Callable>
inline void EvalState::forceAttrs(Value & v, Callable getPos)
{
forceValue(v, getPos);
if (v.type() != nAttrs) if (v.type() != nAttrs)
throwTypeError(pos, "value is %1% while a set was expected", v); throwTypeError(getPos(), "value is %1% while a set was expected", v);
} }

View file

@ -219,7 +219,7 @@ string showType(const Value & v)
} }
} }
Pos Value::determinePos(const Pos &pos) const Pos Value::determinePos(const Pos & pos) const
{ {
switch (internalType) { switch (internalType) {
case tAttrs: return *attrs->pos; case tAttrs: return *attrs->pos;
@ -754,6 +754,11 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const
}); });
} }
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
{
throw TypeError(s, showType(v));
}
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1))
{ {
throw AssertionError({ throw AssertionError({
@ -1138,7 +1143,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, vOverrides->determinePos(noPos)); state.forceAttrs(*vOverrides, [&]() { return 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);
@ -1500,7 +1505,8 @@ void EvalState::incrFunctionCall(ExprLambda * fun)
void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
{ {
Pos pos = fun.determinePos(noPos); auto pos = fun.determinePos(noPos);
forceValue(fun, pos); forceValue(fun, pos);
if (fun.type() == nAttrs) { if (fun.type() == nAttrs) {
@ -1797,7 +1803,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, v.determinePos(noPos)); forceValue(v, [&]() { return v.determinePos(noPos); });
if (v.type() == nAttrs) { if (v.type() == nAttrs) {
for (auto & i : *v.attrs) for (auto & i : *v.attrs)

View file

@ -224,6 +224,9 @@ public:
result. Otherwise, this is a no-op. */ result. Otherwise, this is a no-op. */
inline void forceValue(Value & v, const Pos & pos); inline void forceValue(Value & v, const Pos & pos);
template <typename Callable>
inline void forceValue(Value & v, Callable getPos);
/* Force a value, then recursively force list elements and /* Force a value, then recursively force list elements and
attributes. */ attributes. */
void forceValueDeep(Value & v); void forceValueDeep(Value & v);
@ -232,7 +235,12 @@ 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, const Pos & pos);
void forceAttrs(Value & v, const Pos & pos);
template <typename Callable>
inline void forceAttrs(Value & v, Callable getPos);
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

@ -172,7 +172,7 @@ StringSet DrvInfo::queryMetaNames()
bool DrvInfo::checkMeta(Value & v) bool DrvInfo::checkMeta(Value & v)
{ {
state->forceValue(v, v.determinePos(noPos)); state->forceValue(v, [&]() { return 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, v.determinePos(noPos)); state.forceValue(v, [&]() { return 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

@ -361,7 +361,7 @@ public:
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size; return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
} }
Pos determinePos(const Pos &pos) const; Pos determinePos(const Pos & pos) const;
/* Check whether forcing this value requires a trivial amount of /* Check whether forcing this value requires a trivial amount of
computation. In particular, function applications are computation. In particular, function applications are

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, v.determinePos(noPos)); state->forceValue(v, [&]() { return 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, topLevel.determinePos(noPos)); state.forceValue(topLevel, [&]() { return 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, v.determinePos(noPos)); state.forceValue(v, [&]() { return v.determinePos(noPos); });
PathSet context; PathSet context;
if (evalOnly) { if (evalOnly) {

View file

@ -673,7 +673,7 @@ void NixRepl::reloadFiles()
void NixRepl::addAttrsToScope(Value & attrs) void NixRepl::addAttrsToScope(Value & attrs)
{ {
state->forceAttrs(attrs, attrs.determinePos(noPos)); state->forceAttrs(attrs, [&]() { return 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, v.determinePos(noPos)); state->forceValue(v, [&]() { return 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, v.determinePos(noPos)); state->forceValue(v, [&]() { return v.determinePos(noPos); });
switch (v.type()) { switch (v.type()) {