about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lib/tests/modules/types-attrTag.nix10
-rw-r--r--lib/types.nix23
2 files changed, 32 insertions, 1 deletions
diff --git a/lib/tests/modules/types-attrTag.nix b/lib/tests/modules/types-attrTag.nix
index b105d01512dc5..b8b1dff21e19f 100644
--- a/lib/tests/modules/types-attrTag.nix
+++ b/lib/tests/modules/types-attrTag.nix
@@ -39,6 +39,9 @@ in
           yay = mkOption {
             type = types.int;
           };
+          extensible = mkOption {
+            type = types.enum [ "foo" ];
+          };
         }
       );
     };
@@ -71,6 +74,9 @@ in
             nay = mkOption {
               type = types.bool;
             };
+            extensible = mkOption {
+              type = types.enum [ "bar" ];
+            };
           }
         );
       };
@@ -89,11 +95,15 @@ in
     nested.right.left = "not a number";
     merged.negative.nay = false;
     merged.positive.yay = 100;
+    merged.extensi-foo.extensible = "foo";
+    merged.extensi-bar.extensible = "bar";
     okChecks =
       assert config.intStrings.hello.right == "hello world";
       assert config.intStrings.numberOne.left == 1;
       assert config.merged.negative.nay == false;
       assert config.merged.positive.yay == 100;
+      assert config.merged.extensi-foo.extensible == "foo";
+      assert config.merged.extensi-bar.extensible == "bar";
       # assert lib.foldl' (a: b: builtins.trace b a) true (lib.attrNames config.docs);
       assert config.docs."submodules.<name>.foo.bar".type == "signed integer";
       assert config.docs."submodules.<name>.qux".type == "string";
diff --git a/lib/types.nix b/lib/types.nix
index 2c6845178852c..2f0b10fe96583 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -667,7 +667,28 @@ rec {
               }
             else throw "The option `${showOption loc}` is defined as ${lib.strings.escapeNixIdentifier choice}, but ${lib.strings.escapeNixIdentifier choice} is not among the valid choices (${choicesStr}). Value ${choice} was defined in ${showFiles (getFiles defs)}.";
         nestedTypes = tags;
-        functor = (defaultFunctor "attrTagWith") // { payload = { inherit tags; }; binOp = a: b: { tags = a.tags // b.tags; }; };
+        functor = (defaultFunctor "attrTagWith") // {
+          payload = { inherit tags; };
+          binOp =
+            let
+              # Add metadata in the format that submodules work with
+              wrapOptionDecl =
+                option: { options = option; _file = "<attrTag {...}>"; pos = null; };
+            in
+            a: b: {
+              tags = a.tags // b.tags //
+                mapAttrs
+                  (tagName: bOpt:
+                    lib.mergeOptionDecls
+                      # FIXME: loc is not accurate; should include prefix
+                      #        Fortunately, it's only used for error messages, where a "relative" location is kinda ok.
+                      #        It is also returned though, but use of the attribute seems rare?
+                      [tagName]
+                      [ (wrapOptionDecl a.tags.${tagName}) (wrapOptionDecl bOpt) ]
+                  )
+                  (builtins.intersectAttrs a.tags b.tags);
+          };
+        };
       };
 
     uniq = unique { message = ""; };