summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorRobert Hensing <robert@roberthensing.nl>2022-02-28 22:39:56 +0100
committerRobert Hensing <robert@roberthensing.nl>2022-03-03 00:29:11 +0100
commit11537c9c0239dc4ae52477faa78a4a0a7bdf206c (patch)
tree4c7d2b9f657108be2a4ddb0641643417df53952c /lib
parent81f342d1f3a6bab4a57e195ce99a153b82b1ef86 (diff)
downloadnixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar.gz
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar.bz2
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar.lz
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar.xz
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.tar.zst
nixpkgs-11537c9c0239dc4ae52477faa78a4a0a7bdf206c.zip
lib.modules: Improve option-is-prefix error message
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix24
-rwxr-xr-xlib/tests/modules.sh6
-rw-r--r--lib/tests/modules/declare-set.nix12
3 files changed, 39 insertions, 3 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 62e9615d25b..7d9c55f9a15 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -9,6 +9,7 @@ let
     catAttrs
     concatLists
     concatMap
+    concatStringsSep
     elem
     filter
     findFirst
@@ -46,6 +47,20 @@ let
     showOption
     unknownModule
     ;
+
+  showDeclPrefix = loc: decl: prefix:
+    " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
+  showRawDecls = loc: decls:
+    concatStringsSep "\n"
+      (sort (a: b: a < b)
+        (concatMap
+          (decl: map
+            (showDeclPrefix loc decl)
+            (attrNames decl.options)
+          )
+          decls
+      ));
+
 in
 
 rec {
@@ -500,7 +515,7 @@ rec {
               unmatchedDefns = [];
             }
           else if optionDecls != [] then
-              if (lib.head optionDecls).options.type.name == "submodule"
+              if all (x: x.options.type.name == "submodule") optionDecls
               # Raw options can only be merged into submodules. Merging into
               # attrsets might be nice, but ambiguous. Suppose we have
               # attrset as a `attrsOf submodule`. User declares option
@@ -509,7 +524,7 @@ rec {
               #  b. option `foo.bar` is available in all `attrset.*`
               #  c. reject and require "<name>" as a reminder that it behaves like (b).
               #  d. magically combine (a) and (c).
-              # All options are merely syntax sugar though.
+              # All of the above are merely syntax sugar though.
               then
                 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
                 in {
@@ -519,8 +534,11 @@ rec {
               else
                 let
                   firstNonOption = findFirst (m: !isOption m.options) "" decls;
+                  nonOptions = filter (m: !isOption m.options) decls;
                 in
-                throw "The option `${showOption loc}' in `${(lib.head optionDecls)._file}' is a prefix of options in `${firstNonOption._file}'."
+                throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
+                  showRawDecls loc nonOptions
+                }"
           else
             mergeModules' loc decls defns) declsByName;
 
diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh
index 3591b8f1e6f..e903714a720 100755
--- a/lib/tests/modules.sh
+++ b/lib/tests/modules.sh
@@ -309,6 +309,12 @@ checkConfigOutput "10" config.processedToplevel ./raw.nix
 checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
 checkConfigOutput "bar" config.priorities ./raw.nix
 
+## Option collision
+checkConfigError \
+  'The option .set. in module .*/declare-set.nix. would be a parent of the following options, but its type .attribute set of signed integers. does not support nested options.\n\s*- option[(]s[)] with prefix .set.enable. in module .*/declare-enable-nested.nix.' \
+  config.set \
+  ./declare-set.nix ./declare-enable-nested.nix
+
 # Test that types.optionType merges types correctly
 checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
 checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
diff --git a/lib/tests/modules/declare-set.nix b/lib/tests/modules/declare-set.nix
new file mode 100644
index 00000000000..853418531a8
--- /dev/null
+++ b/lib/tests/modules/declare-set.nix
@@ -0,0 +1,12 @@
+{ lib, ... }:
+
+{
+  options.set = lib.mkOption {
+    default = { };
+    example = { a = 1; };
+    type = lib.types.attrsOf lib.types.int;
+    description = ''
+      Some descriptive text
+    '';
+  };
+}