From 474edc15c07c6804730e57197ecf0d3c2faae83b Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sat, 23 Oct 2021 23:10:22 -0500 Subject: [PATCH] Improve error reporting --- flake.nix | 59 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/flake.nix b/flake.nix index 44d016b..160e60a 100644 --- a/flake.nix +++ b/flake.nix @@ -21,8 +21,8 @@ mergeAt = here: lhs: rhs: let - inherit (builtins) isAttrs head tail typeOf concatStringsSep; - inherit (nixlib.lib) zipAttrsWith isList isFunction; + inherit (builtins) isAttrs head tail typeOf concatStringsSep tryEval; + inherit (nixlib.lib) zipAttrsWith isList isFunction getAttrFromPath; f = attrPath: zipAttrsWith (n: values: @@ -31,16 +31,45 @@ rhs' = head values; lhs' = head (tail values); isSingleton = tail values == [ ]; + lhsFilePos = let + lhsPos = builtins.unsafeGetAttrPos n (getAttrFromPath attrPath lhs); + in "${lhsPos.file}:${toString lhsPos.line}:${toString lhsPos.column}"; + rhsFilePos = let + rhsPos = builtins.unsafeGetAttrPos n (getAttrFromPath attrPath rhs); + in "${rhsPos.file}:${toString rhsPos.line}:${toString rhsPos.column}"; in if isSingleton then head values else if !(isAttrs lhs' && isAttrs rhs') then if (typeOf lhs') != (typeOf rhs') && !(isList lhs' && isFunction rhs') - then abort "rigt-hand-side must be of the same type as left-hand-side at '${concatStringsSep ''.'' here'}'" + then abort '' + + rigt-hand-side must be of the same type as left-hand-side + at '${concatStringsSep "." here'}': + - lhs: ${typeOf lhs'} @ ${lhsFilePos} + - rhs: ${typeOf rhs'} @ ${rhsFilePos} + '' else if isList lhs' && isList rhs' - then abort "rigt-hand-side list is not allowed to override left-hand-side list, this would break incrementality of the data spine. Use one of the array merge functions instead at '${concatStringsSep ''.'' here'}'" + then abort '' + + rigt-hand-side list is not allowed to override left-hand-side list, + this would break incrementality of the data spine. Use one of the array + merge functions instead at '${concatStringsSep "." here'}': + - lhs: ${typeOf lhs'} @ ${lhsFilePos} + - rhs: ${typeOf rhs'} @ ${rhsFilePos} + + Available array merge functions: + - data-merge.update [ idx ... ] [ v ... ] + - data-merge.append [ v ] + '' # array function merge - else if isList lhs' && isFunction rhs' then rhs' lhs' here' + else if isList lhs' && isFunction rhs' then let + ex = tryEval (rhs' lhs' here'); + in if ex.success then ex.value else abort '' + + Array merge function error (see trace above the error line for details) on the right-hand-side: + - rhs: ${typeOf rhs'} @ ${rhsFilePos} + '' else rhs' else f here' values ); @@ -50,22 +79,26 @@ merge = mergeAt [ ]; - append = new: orig: here: let + append = new: orig: _: let inherit (builtins) isList typeOf concatStringsSep; inherit (nixlib.lib) assertMsg; in - assert assertMsg (isList new) "appending array merge: right-hand-side must be a list, got: ${typeOf new} at '${concatStringsSep ''.'' here}'"; + assert assertMsg (isList new) '' + APPENDING ARRAY MERGE: argument must be a list, got: ${typeOf new}''; orig ++ new; update = indices: updates: orig: here: let inherit (builtins) isList all isInt length typeOf listToAttrs elemAt hasAttr concatStringsSep; - inherit (nixlib.lib) zipListsWith imap0 assertMsg; + inherit (nixlib.lib) zipListsWith imap0 assertMsg traceSeqN; in - assert assertMsg (isList indices && all (i: isInt i) indices) - "updating array merge: first argument must be a list of indices of items to update in the left-hand-side list, got: ${indices} at '${concatStringsSep ''.'' here}'"; - assert assertMsg (isList updates) "updating array merge: right-hand-side must be a list, got: ${typeOf updates} at '${concatStringsSep ''.'' here}'"; - assert assertMsg (length indices == length updates) - "updating array merge: for each index there must be one corresponding update value, got: ${length indices} indices & ${length updates} updates at '${concatStringsSep ''.'' here}'"; + assert assertMsg (isList indices) '' + UPDATING ARRAY MERGE: first argument must be a list, got: ${typeOf indices}''; + assert assertMsg (isList updates) '' + UPDATING ARRAY MERGE: second argument must be a list, got: ${typeOf updates}''; + assert assertMsg (all (i: isInt i) indices) '' + UPDATING ARRAY MERGE: first argument must be a list of indices (integers) of items to update in the left-hand-side list, got: ${traceSeqN 1 indices "(see trace above)"}''; + assert assertMsg (length indices == length updates) '' + UPDATING ARRAY MERGE: for each index there must be one corresponding update value, got: ${traceSeqN 1 indices "(see first trace above)"} indices & ${traceSeqN 1 updates "(see second trace above)"} updates''; let updated = listToAttrs ( zipListsWith (idx: upd: