about summary refs log tree commit diff
path: root/lib/modules.nix
diff options
context:
space:
mode:
authorRobert Hensing <robert@roberthensing.nl>2022-01-24 15:58:17 +0100
committerRobert Hensing <robert@roberthensing.nl>2022-03-03 00:28:35 +0100
commitd030e2109fd491e32cb48df54d100aa608551298 (patch)
tree6da4c8737d4d14e9cb049c5872f6671bbfe4494e /lib/modules.nix
parent33e8df0921c410320185c9a1859656a4ec771f62 (diff)
lib.modules: Let module declare options directly in bare submodule
... where a bare submodule is an option that has a type like
`submoduleWith x`, as opposed to `attrsOf (submoduleWith x)`.

This makes migration unnecessary when introducing a freeform type
in an existing option tree.

Closes #146882
Diffstat (limited to 'lib/modules.nix')
-rw-r--r--lib/modules.nix22
1 files changed, 21 insertions, 1 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 79d54e4a53876..bde89123cd980 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -474,6 +474,18 @@ rec {
           [{ inherit (module) file; inherit value; }]
         ) configs;
 
+      # Convert an option tree decl to a submodule option decl
+      optionTreeToOption = decl:
+        if isOption decl.options
+        then decl
+        else decl // {
+            options = mkOption {
+              type = types.submoduleWith {
+                modules = [ { options = decl.options; } ];
+              };
+            };
+          };
+
       resultsByName = mapAttrs (name: decls:
         # We're descending into attribute ‘name’.
         let
@@ -493,7 +505,15 @@ rec {
               firstOption = findFirst (m: isOption m.options) "" decls;
               firstNonOption = findFirst (m: !isOption m.options) "" decls;
             in
-              throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
+              if firstOption.options.type?isSubmodule && firstOption.options.type.isSubmodule
+              then
+                let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
+                in {
+                  matchedOptions = evalOptionValue loc opt defns';
+                  unmatchedDefns = [];
+                }
+              else
+                throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
           else
             mergeModules' loc decls defns) declsByName;