From 037cf2fad190766319c6c40b931b49c075ce5e78 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Sun, 25 Sep 2022 00:09:13 -0700 Subject: [PATCH] unionOfDisjoint: use builtins.intersectAttrs This brings two benefits: 1. The complete list of collisions is printed in the whenever any colliding attribute is accessed. 2. The sets are intersected using a C++ primitive, which runs in O(n) time (intersecting pre-sorted lists) with small constants rather than interpreted Nix code. Thanks to @toonn for prompting this improvement. --- lib/attrsets.nix | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 31dc27969cc0..de88763854d6 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -627,11 +627,14 @@ rec { `y`, and all values `assert` with an error message. This operator is commutative, unlike (//). */ unionOfDisjoint = x: y: - x // (mapAttrs - (name: val: - if hasAttr name x - then builtins.throw "attribute collision: ${name}" - else val) y); + let + intersection = builtins.intersectAttrs x y; + collisions = lib.concatStringsSep " " (builtins.attrNames intersection); + mask = builtins.mapAttrs (name: value: builtins.throw + "unionOfDisjoint: collision on ${name}; complete list: ${collisions}") + intersection; + in + (x // y) // mask; /*** deprecated stuff ***/