aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorregnat <rg@regnat.ovh>2022-03-08 06:16:51 +0100
committerregnat <rg@regnat.ovh>2022-03-08 06:21:45 +0100
commit0c6e46e34965ba0db4e0b755ee473868a4fef21f (patch)
tree33e8a2ee4beb267a84819af46c1966427e351093 /src
parent92b8d4d8861b908a7ec500526a84155c597d6d2b (diff)
Add some suggestions to the evaluator
Make the evaluator show some suggestions when trying to access an invalid field from an attrset. ```console $ nix eval --expr '{ foo = 1; }.foa' error: attribute 'foa' missing at «string»:1:1: 1| { foo = 1; }.foa | ^ Did you mean foo? ```
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 5bf161cc0..1d88e8709 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -727,6 +727,15 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2
throw EvalError(s, s2);
}
+LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s, const std::string & s2))
+{
+ throw EvalError({
+ .msg = hintfmt(s, s2),
+ .errPos = pos,
+ .suggestions = suggestions,
+ });
+}
+
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
{
throw EvalError({
@@ -1281,8 +1290,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
} else {
state.forceAttrs(*vAttrs, pos);
- if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
- throwEvalError(pos, "attribute '%1%' missing", name);
+ if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) {
+ std::set<std::string> allAttrNames;
+ for (auto & attr : *vAttrs->attrs)
+ allAttrNames.insert(attr.name);
+ throwEvalError(
+ pos,
+ Suggestions::bestMatches(allAttrNames, name),
+ "attribute '%1%' missing", name);
+ }
}
vAttrs = j->value;
pos2 = j->pos;