diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 1a7b90593b1d7..a197e4ca879f8 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -771,6 +771,33 @@ rec { ) [pattern attrs])); + /* Pattern intersection. Specifically, the following is true + if it does not `throw`: + + forall patternList, + forall arg, + matchAttrs (intersectPatterns patternList) arg + == all (matchAttrs patternList) arg + + Type: + intersectPatterns :: [ AttrSet ] -> AttrSet + */ + intersectPatterns = let + inherit (lib) any unique isFunction elem; + inherit (lib.strings) concatStringsSep; + mergeLeaves = path: list: + let list' = unique list; in + # avoid introducing any new dependencies on function equality + assert any isFunction list -> throw "function found in pattern list at path '${concatStringsSep "." path}'"; + assert length list == 0 -> throw "this should not happen; path '${concatStringsSep "." path}'"; + assert length list' != 1 -> throw "disjoint patterns intersected at path '${concatStringsSep "." path}', values=${builtins.toString list'}"; + elemAt list' 0; + intersectPatterns' = path: list: + if !(any isAttrs list) then mergeLeaves path list + else if all isAttrs list then mapAttrs (k: v: intersectPatterns' (path++[k]) v) (zipAttrs list) + else throw "mix of attrsets and non-attrsets at path '${concatStringsSep "." path}', values = ${concatStringsSep "\n" (map builtins.toJSON list)}"; + in list: (intersectPatterns' [] list); + /* Override only the attributes that are already present in the old set useful for deep-overriding. diff --git a/lib/lists.nix b/lib/lists.nix index 8b2c2d12801bb..1317bf011087c 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -631,9 +631,15 @@ rec { => [ "13" "14" "23" "24" ] */ crossLists = builtins.trace - "lib.crossLists is deprecated, use lib.cartesianProductOfSets instead" + "lib.crossLists is deprecated, use lib.cartesianProductOfLists instead" (f: foldl (fs: args: concatMap (f: map f args) fs) [f]); + cartesianProductOfLists = lists: + let + inherit (lib) cartesianProductOfSets toString nameValuePair genAttrs attrValues; + attrs = builtins.listToAttrs (imap0 (i: nameValuePair (builtins.toString i)) lists); + cross = cartesianProductOfSets attrs; + in map attrValues cross; /* Remove duplicate elements from the list. O(n^2) complexity.