Skip to content

Commit

Permalink
AttrCursor: Remove forceErrors
Browse files Browse the repository at this point in the history
Instead, force evaluation of the original value only if we need to
show the exception to the user.
  • Loading branch information
edolstra committed May 24, 2024
1 parent 8b86f41 commit 2c88930
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 20 deletions.
40 changes: 28 additions & 12 deletions src/libexpr/eval-cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@

namespace nix::eval_cache {

CachedEvalError::CachedEvalError(ref<AttrCursor> cursor, Symbol attr)
: EvalError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
, cursor(cursor), attr(attr)
{ }

void CachedEvalError::force()
{
auto & v = cursor->forceValue();

if (v.type() == nAttrs) {
auto a = v.attrs()->get(this->attr);

state.forceValue(*a->value, a->pos);
}

// Shouldn't happen.
throw EvalError(state, "evaluation of cached failed attribute '%s' unexpectedly succeeded", cursor->getAttrPathStr(attr));
}

static const char * schema = R"sql(
create table if not exists Attributes (
parent integer not null,
Expand Down Expand Up @@ -470,7 +489,7 @@ Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
return Suggestions::bestMatches(strAttrNames, root->state.symbols[name]);
}

std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
{
if (root->db) {
if (!cachedValue)
Expand All @@ -487,12 +506,9 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
if (attr) {
if (std::get_if<missing_t>(&attr->second))
return nullptr;
else if (std::get_if<failed_t>(&attr->second)) {
if (forceErrors)
debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name));
else
throw CachedEvalError(root->state, "cached failure of attribute '%s'", getAttrPathStr(name));
} else
else if (std::get_if<failed_t>(&attr->second))
throw CachedEvalError(ref(shared_from_this()), name);
else
return std::make_shared<AttrCursor>(root,
std::make_pair(shared_from_this(), name), nullptr, std::move(attr));
}
Expand Down Expand Up @@ -537,9 +553,9 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(std::string_view name)
return maybeGetAttr(root->state.symbols.create(name));
}

ref<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
ref<AttrCursor> AttrCursor::getAttr(Symbol name)
{
auto p = maybeGetAttr(name, forceErrors);
auto p = maybeGetAttr(name);
if (!p)
throw Error("attribute '%s' does not exist", getAttrPathStr(name));
return ref(p);
Expand All @@ -550,11 +566,11 @@ ref<AttrCursor> AttrCursor::getAttr(std::string_view name)
return getAttr(root->state.symbols.create(name));
}

OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force)
OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath)
{
auto res = shared_from_this();
for (auto & attr : attrPath) {
auto child = res->maybeGetAttr(attr, force);
auto child = res->maybeGetAttr(attr);
if (!child) {
auto suggestions = res->getSuggestionsForAttr(attr);
return OrSuggestions<ref<AttrCursor>>::failed(suggestions);
Expand Down Expand Up @@ -751,7 +767,7 @@ bool AttrCursor::isDerivation()

StorePath AttrCursor::forceDerivation()
{
auto aDrvPath = getAttr(root->state.sDrvPath, true);
auto aDrvPath = getAttr(root->state.sDrvPath);
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
/* The eval cache contains 'drvPath', but the actual path has
Expand Down
25 changes: 20 additions & 5 deletions src/libexpr/eval-cache.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,28 @@

namespace nix::eval_cache {

MakeError(CachedEvalError, EvalError);

struct AttrDb;
class AttrCursor;

struct CachedEvalError : EvalError
{
const ref<AttrCursor> cursor;
const Symbol attr;

CachedEvalError(ref<AttrCursor> cursor, Symbol attr);

/**
* Evaluate this attribute, which should result in a regular
* `EvalError` exception being thrown.
*/
[[noreturn]]
void force();
};

class EvalCache : public std::enable_shared_from_this<EvalCache>
{
friend class AttrCursor;
friend class CachedEvalError;

std::shared_ptr<AttrDb> db;
EvalState & state;
Expand Down Expand Up @@ -73,6 +87,7 @@ typedef std::variant<
class AttrCursor : public std::enable_shared_from_this<AttrCursor>
{
friend class EvalCache;
friend class CachedEvalError;

ref<EvalCache> root;
typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, Symbol>> Parent;
Expand Down Expand Up @@ -102,19 +117,19 @@ public:

Suggestions getSuggestionsForAttr(Symbol name);

std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name, bool forceErrors = false);
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name);

std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);

ref<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
ref<AttrCursor> getAttr(Symbol name);

ref<AttrCursor> getAttr(std::string_view name);

/**
* Get an attribute along a chain of attrsets. Note that this does
* not auto-call functors or functions.
*/
OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force = false);
OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const std::vector<Symbol> & attrPath);

std::string getString();

Expand Down
1 change: 0 additions & 1 deletion src/libexpr/eval-error.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ template class EvalErrorBuilder<TypeError>;
template class EvalErrorBuilder<UndefinedVarError>;
template class EvalErrorBuilder<MissingArgumentError>;
template class EvalErrorBuilder<InfiniteRecursionError>;
template class EvalErrorBuilder<CachedEvalError>;
template class EvalErrorBuilder<InvalidPathError>;

}
1 change: 0 additions & 1 deletion src/libexpr/eval-error.hh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ MakeError(Abort, EvalError);
MakeError(TypeError, EvalError);
MakeError(UndefinedVarError, EvalError);
MakeError(MissingArgumentError, EvalError);
MakeError(CachedEvalError, EvalError);
MakeError(InfiniteRecursionError, EvalError);

struct InvalidPathError : public EvalError
Expand Down
11 changes: 10 additions & 1 deletion src/nix/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "terminal.hh"
#include "users.hh"
#include "network-proxy.hh"
#include "eval-cache.hh"

#include <sys/types.h>
#include <regex>
Expand Down Expand Up @@ -515,7 +516,15 @@ void mainWrapped(int argc, char * * argv)
if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) {
evalSettings.pureEval = false;
}
args.command->second->run();

try {
args.command->second->run();
} catch (eval_cache::CachedEvalError & e) {
/* Evaluate the original attribute that resulted in this
cached error so that we can show the original error to the
user. */
e.force();
}
}

}
Expand Down

0 comments on commit 2c88930

Please sign in to comment.