From 11f35afa6f7933d1640e55473a8c7a153bf89b14 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sat, 16 Mar 2024 21:29:52 +0100 Subject: [PATCH] diagnose duplicated attrs at correct path diagnose attr duplication at the path the duplication was detected, not at the path the current attribute wanted to place. doing the latter is only correct if a leaf attribute was duplicated, not if an attrpath was set to a non-attrset in one binding and a (potentially implied) attrset in another binding. fixes #124 Change-Id: Ic4aa9cc12a9874d4e7897c6f64408f10aa36fc82 --- doc/manual/rl-next/dup-attr-errors.md | 22 +++++++++++++++++++ src/libexpr/parser-state.hh | 4 ++-- .../lang/eval-fail-dupAttr-deep.err.exp | 5 +++++ .../lang/eval-fail-dupAttr-deep.nix | 1 + .../lang/eval-fail-dupAttr-inherit.err.exp | 5 +++++ .../lang/eval-fail-dupAttr-inherit.nix | 1 + .../functional/lang/eval-fail-dupAttr.err.exp | 5 +++++ tests/functional/lang/eval-fail-dupAttr.nix | 1 + 8 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 doc/manual/rl-next/dup-attr-errors.md create mode 100644 tests/functional/lang/eval-fail-dupAttr-deep.err.exp create mode 100644 tests/functional/lang/eval-fail-dupAttr-deep.nix create mode 100644 tests/functional/lang/eval-fail-dupAttr-inherit.err.exp create mode 100644 tests/functional/lang/eval-fail-dupAttr-inherit.nix create mode 100644 tests/functional/lang/eval-fail-dupAttr.err.exp create mode 100644 tests/functional/lang/eval-fail-dupAttr.nix diff --git a/doc/manual/rl-next/dup-attr-errors.md b/doc/manual/rl-next/dup-attr-errors.md new file mode 100644 index 000000000..127c8ceb1 --- /dev/null +++ b/doc/manual/rl-next/dup-attr-errors.md @@ -0,0 +1,22 @@ +--- +synopsis: Duplicate attribute reports are more accurate +# prs: cl 557 +--- + +Duplicate attribute errors are now more accurate, showing the path at which an error was detected rather than the full, possibly longer, path that caused the error. +Error reports are now +```ShellSession +$ nix eval --expr '{ a.b = 1; a.b.c.d = 1; }' +error: attribute 'a.b' already defined at «string»:1:3 + at «string»:1:12: + 1| { a.b = 1; a.b.c.d = 1; + | ^ +``` +instead of +```ShellSession +$ nix eval --expr '{ a.b = 1; a.b.c.d = 1; }' +error: attribute 'a.b.c.d' already defined at «string»:1:3 + at «string»:1:12: + 1| { a.b = 1; a.b.c.d = 1; + | ^ +``` diff --git a/src/libexpr/parser-state.hh b/src/libexpr/parser-state.hh index a83d8c8b2..4a8b59f08 100644 --- a/src/libexpr/parser-state.hh +++ b/src/libexpr/parser-state.hh @@ -90,10 +90,10 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * if (j != attrs->attrs.end()) { if (j->second.kind != ExprAttrs::AttrDef::Kind::Inherited) { ExprAttrs * attrs2 = dynamic_cast(j->second.e); - if (!attrs2) dupAttr(attrPath, pos, j->second.pos); + if (!attrs2) dupAttr({attrPath.begin(), i + 1}, pos, j->second.pos); attrs = attrs2; } else - dupAttr(attrPath, pos, j->second.pos); + dupAttr({attrPath.begin(), i + 1}, pos, j->second.pos); } else { ExprAttrs * nested = new ExprAttrs; attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos); diff --git a/tests/functional/lang/eval-fail-dupAttr-deep.err.exp b/tests/functional/lang/eval-fail-dupAttr-deep.err.exp new file mode 100644 index 000000000..bb79605c0 --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr-deep.err.exp @@ -0,0 +1,5 @@ +error: attribute 'a.b.c' already defined at /pwd/lang/eval-fail-dupAttr-deep.nix:1:3 + at /pwd/lang/eval-fail-dupAttr-deep.nix:1:14: + 1| { a.b.c = 1; a.b.c.a.a = 1; } + | ^ + 2| diff --git a/tests/functional/lang/eval-fail-dupAttr-deep.nix b/tests/functional/lang/eval-fail-dupAttr-deep.nix new file mode 100644 index 000000000..186a7f705 --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr-deep.nix @@ -0,0 +1 @@ +{ a.b.c = 1; a.b.c.a.a = 1; } diff --git a/tests/functional/lang/eval-fail-dupAttr-inherit.err.exp b/tests/functional/lang/eval-fail-dupAttr-inherit.err.exp new file mode 100644 index 000000000..7744b838f --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr-inherit.err.exp @@ -0,0 +1,5 @@ +error: attribute 'a' already defined at /pwd/lang/eval-fail-dupAttr-inherit.nix:1:15 + at /pwd/lang/eval-fail-dupAttr-inherit.nix:1:19: + 1| { inherit ({}) a; a.b = 1; } + | ^ + 2| diff --git a/tests/functional/lang/eval-fail-dupAttr-inherit.nix b/tests/functional/lang/eval-fail-dupAttr-inherit.nix new file mode 100644 index 000000000..cb8e4e625 --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr-inherit.nix @@ -0,0 +1 @@ +{ inherit ({}) a; a.b = 1; } diff --git a/tests/functional/lang/eval-fail-dupAttr.err.exp b/tests/functional/lang/eval-fail-dupAttr.err.exp new file mode 100644 index 000000000..567791959 --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr.err.exp @@ -0,0 +1,5 @@ +error: attribute 'a' already defined at /pwd/lang/eval-fail-dupAttr.nix:1:3 + at /pwd/lang/eval-fail-dupAttr.nix:1:10: + 1| { a = 1; a.b = 1; } + | ^ + 2| diff --git a/tests/functional/lang/eval-fail-dupAttr.nix b/tests/functional/lang/eval-fail-dupAttr.nix new file mode 100644 index 000000000..a33535e62 --- /dev/null +++ b/tests/functional/lang/eval-fail-dupAttr.nix @@ -0,0 +1 @@ +{ a = 1; a.b = 1; }