summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Hensing <robert@roberthensing.nl>2022-03-10 20:25:49 +0100
committerRobert Hensing <robert@roberthensing.nl>2022-03-10 20:25:49 +0100
commit55ee7ab4a6b5281cf1c352bc714b07c59c4546ee (patch)
tree88e1047bc4f89890be69997da44acdb5e5bb715c
parent87fce11f62f21409321ce0f2441f03901c9c8a9f (diff)
downloadnixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar.gz
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar.bz2
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar.lz
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar.xz
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.tar.zst
nixpkgs-55ee7ab4a6b5281cf1c352bc714b07c59c4546ee.zip
lib.types.optionType: Only merge when necessary
-rwxr-xr-xlib/tests/modules.sh3
-rw-r--r--lib/tests/modules/adhoc-freeformType-survives-type-merge.nix14
-rw-r--r--lib/types.nix4
3 files changed, 20 insertions, 1 deletions
diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh
index e4bb7ad2190..350fe85e748 100755
--- a/lib/tests/modules.sh
+++ b/lib/tests/modules.sh
@@ -311,6 +311,9 @@ checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
 # Test that types.optionType correctly annotates option locations
 checkConfigError 'The option .theOption.nested. in .other.nix. is already declared in .optionTypeFile.nix.' config.theOption.nested ./optionTypeFile.nix
 
+# Test that types.optionType leaves types untouched as long as they don't need to be merged
+checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survives-type-merge.nix
+
 cat <<EOF
 ====== module tests ======
 $pass Pass
diff --git a/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix b/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix
new file mode 100644
index 00000000000..3cefb543c25
--- /dev/null
+++ b/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix
@@ -0,0 +1,14 @@
+{ lib, ... }: {
+  options.dummy = lib.mkOption { type = lib.types.anything; default = {}; };
+  freeformType =
+    let
+      a = lib.types.attrsOf (lib.types.submodule { options.bar = lib.mkOption { }; });
+    in
+    # modifying types like this breaks type merging.
+    # This test makes sure that type merging is not performed when only a single declaration exists.
+    # Don't modify types in practice!
+    a // {
+      merge = loc: defs: { freeformItems = a.merge loc defs; };
+    };
+  config.foo.bar = "ok";
+}
diff --git a/lib/types.nix b/lib/types.nix
index 3fcac9c31b3..2e7261f7553 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -535,7 +535,9 @@ rec {
       description = "optionType";
       check = value: value._type or null == "option-type";
       merge = loc: defs:
-        let
+        if length defs == 1
+        then (head defs).value
+        else let
           # Prepares the type definitions for mergeOptionDecls, which
           # annotates submodules types with file locations
           optionModules = map ({ value, file }: