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; }