diff --git a/lib/tests/modules/types-attrTag.nix b/lib/tests/modules/types-attrTag.nix index b105d01512dc..b8b1dff21e19 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..foo.bar".type == "signed integer"; assert config.docs."submodules..qux".type == "string"; diff --git a/lib/types.nix b/lib/types.nix index 2c6845178852..2f0b10fe9658 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 = ""; 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 = ""; };