lib.types.submoduleWith: Avoid _key collisions after extendModules

This commit is contained in:
Robert Hensing 2022-04-24 00:07:59 +02:00
parent 3ca4a1714a
commit 224426ba6d
4 changed files with 61 additions and 4 deletions

View file

@ -113,6 +113,10 @@ rec {
args ? {}
, # This would be remove in the future, Prefer _module.check option instead.
check ? true
# Internal variable to avoid `_key` collisions regardless
# of `extendModules`. Used in `submoduleWith`.
# Test case: lib/tests/modules, "168767"
, extensionOffset ? 0
}:
let
withWarnings = x:
@ -338,15 +342,17 @@ rec {
modules ? [],
specialArgs ? {},
prefix ? [],
extensionOffset ? length modules,
}:
evalModules (evalModulesArgs // {
modules = regularModules ++ modules;
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
prefix = extendArgs.prefix or evalModulesArgs.prefix;
inherit extensionOffset;
});
type = lib.types.submoduleWith {
inherit modules specialArgs;
inherit modules specialArgs extensionOffset;
};
result = withWarnings {

View file

@ -293,7 +293,7 @@ checkConfigOutput '^"a c"$' config.result ./functionTo/merging-attrs.nix
# moduleType
checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a b y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix
## emptyValue's
@ -327,6 +327,10 @@ checkConfigError 'The option .theOption.nested. in .other.nix. is already declar
# 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
# Anonymous submodules don't get nixed by import resolution/deduplication
# because of an `extendModules` bug, issue 168767.
checkConfigOutput '^1$' config.sub.specialisation.value ./extendModules-168767-imports.nix
cat <<EOF
====== module tests ======
$pass Pass

View file

@ -0,0 +1,41 @@
{ lib
, extendModules
, ...
}:
with lib;
{
imports = [
{
options.sub = mkOption {
default = { };
type = types.submodule (
{ config
, extendModules
, ...
}:
{
options.value = mkOption {
type = types.int;
};
options.specialisation = mkOption {
default = { };
inherit
(extendModules {
modules = [{
specialisation = mkOverride 0 { };
}];
})
type;
};
}
);
};
}
{ config.sub.value = 1; }
];
}

View file

@ -568,6 +568,11 @@ rec {
{ modules
, specialArgs ? {}
, shorthandOnlyDefinesConfig ? false
# Internal variable to avoid `_key` collisions regardless
# of `extendModules`. Wired through by `evalModules`.
# Test case: lib/tests/modules, "168767"
, extensionOffset ? 0
}@attrs:
let
inherit (lib.modules) evalModules;
@ -579,11 +584,11 @@ rec {
allModules = defs: imap1 (n: { value, file }:
if isFunction value
then setFunctionArgs
(args: lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (value args))
(args: lib.modules.unifyModuleSyntax file "${toString file}-${toString (n + extensionOffset)}" (value args))
(functionArgs value)
else if isAttrs value
then
lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (shorthandToModule value)
lib.modules.unifyModuleSyntax file "${toString file}-${toString (n + extensionOffset)}" (shorthandToModule value)
else value
) defs;
@ -620,6 +625,7 @@ rec {
(base.extendModules {
modules = [ { _module.args.name = last loc; } ] ++ allModules defs;
prefix = loc;
extensionOffset = extensionOffset + length defs;
}).config;
emptyValue = { value = {}; };
getSubOptions = prefix: (base.extendModules