From 0c6e46e34965ba0db4e0b755ee473868a4fef21f Mon Sep 17 00:00:00 2001 From: regnat Date: Tue, 8 Mar 2022 06:16:51 +0100 Subject: Add some suggestions to the evaluator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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? ``` --- src/libexpr/eval.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') 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 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; -- cgit v1.2.3