mildly cleanup ExprSelect::eval

Better variable names, some comments, and a slight logic rearrange.

Change-Id: I9685ae252f83217aa85f06432234159c9ad19d1c
This commit is contained in:
Qyriad 2024-06-22 18:51:10 -06:00
parent e09cc60df9
commit fb8553f63c

View file

@ -4,6 +4,7 @@
#include "primops.hh" #include "primops.hh"
#include "print-options.hh" #include "print-options.hh"
#include "shared.hh" #include "shared.hh"
#include "suggestions.hh"
#include "types.hh" #include "types.hh"
#include "store-api.hh" #include "store-api.hh"
#include "derivations.hh" #include "derivations.hh"
@ -1426,11 +1427,13 @@ static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & a
void ExprSelect::eval(EvalState & state, Env & env, Value & v) void ExprSelect::eval(EvalState & state, Env & env, Value & v)
{ {
Value vTmp; Value vFirst;
PosIdx pos2;
Value * vAttrs = &vTmp;
e->eval(state, env, vTmp); // Pointer to the current attrset Value in this select chain.
Value * vCurrent = &vFirst;
// Position for the current attrset Value in this select chain.
PosIdx posCurrent;
e->eval(state, env, vFirst);
try { try {
auto dts = state.debugRepl auto dts = state.debugRepl
@ -1443,48 +1446,75 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
showAttrPath(state, env, attrPath)) showAttrPath(state, env, attrPath))
: nullptr; : nullptr;
for (auto & i : attrPath) { for (auto const & currentAttrName : attrPath) {
state.nrLookups++; state.nrLookups++;
Bindings::iterator j;
auto name = getName(i, state, env); Symbol const name = getName(currentAttrName, state, env);
if (def) {
state.forceValue(*vAttrs, pos); state.forceValue(*vCurrent, pos);
if (vAttrs->type() != nAttrs ||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) if (vCurrent->type() != nAttrs) {
{
def->eval(state, env, v); // If we have an `or` provided default,
// then this is allowed to not be an attrset.
if (def != nullptr) {
this->def->eval(state, env, v);
return; return;
} }
} else {
state.forceAttrs(*vAttrs, pos, "while selecting an attribute"); // Otherwise, we must type error.
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { state.error<TypeError>(
std::set<std::string> allAttrNames; "expected a set but found %s: %s",
for (auto & attr : *vAttrs->attrs) showType(*vCurrent),
allAttrNames.insert(state.symbols[attr.name]); ValuePrinter(state, *vCurrent, errorPrintOptions)
auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]); ).withTrace(pos, "while selecting an attribute").debugThrow();
state.error<EvalError>("attribute '%1%' missing", state.symbols[name])
.atPos(pos).withSuggestions(suggestions).withFrame(env, *this).debugThrow();
}
} }
vAttrs = j->value;
pos2 = j->pos; // Now that we know this is actually an attrset, try to find an attr
if (state.countCalls) state.attrSelects[pos2]++; // with the selected name.
Bindings::iterator attrIt = vCurrent->attrs->find(name);
if (attrIt == vCurrent->attrs->end()) {
// If we have an `or` provided default, then we'll use that.
if (def != nullptr) {
this->def->eval(state, env, v);
return;
}
// Otherwise, missing attr error.
std::set<std::string> allAttrNames;
for (auto const & attr : *vCurrent->attrs) {
allAttrNames.insert(state.symbols[attr.name]);
}
auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]);
state.error<EvalError>("attribute '%s' missing", state.symbols[name])
.atPos(pos)
.withSuggestions(suggestions)
.withFrame(env, *this)
.debugThrow();
}
// If we're here, then we successfully found the attribute.
// Set our currently operated-on attrset to this one, and keep going.
vCurrent = attrIt->value;
posCurrent = attrIt->pos;
if (state.countCalls) state.attrSelects[posCurrent]++;
} }
state.forceValue(*vAttrs, (pos2 ? pos2 : this->pos ) ); state.forceValue(*vCurrent, (posCurrent ? posCurrent : this->pos));
} catch (Error & e) { } catch (Error & e) {
if (pos2) { if (posCurrent) {
auto pos2r = state.positions[pos2]; auto pos2r = state.positions[posCurrent];
auto origin = std::get_if<SourcePath>(&pos2r.origin); auto origin = std::get_if<SourcePath>(&pos2r.origin);
if (!(origin && *origin == state.derivationInternal)) if (!(origin && *origin == state.derivationInternal))
state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'", state.addErrorTrace(e, posCurrent, "while evaluating the attribute '%1%'",
showAttrPath(state, env, attrPath)); showAttrPath(state, env, attrPath));
} }
throw; throw;
} }
v = *vAttrs; v = *vCurrent;
} }