diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh
index 309c5311361c1..526a2fac9117d 100755
--- a/lib/tests/modules.sh
+++ b/lib/tests/modules.sh
@@ -179,6 +179,13 @@ checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.
## Paths should be allowed as values and work as expected
checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix
+## evalModules should be settable
+checkConfigOutput 10 config.submodule.value ./submoduleWithLib.nix
+
+# Check the file location information is propagated into submodules
+checkConfigOutput the-file.nix config.submodule.internalFiles.0 ./submoduleFiles.nix
+
+
# Check that disabledModules works recursively and correctly
checkConfigOutput "true" config.enable ./disable-recursive/main.nix
checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-foo.nix}
diff --git a/lib/tests/modules/submoduleFiles.nix b/lib/tests/modules/submoduleFiles.nix
new file mode 100644
index 0000000000000..c0d9b2cef3e8d
--- /dev/null
+++ b/lib/tests/modules/submoduleFiles.nix
@@ -0,0 +1,21 @@
+{ lib, ... }: {
+ options.submodule = lib.mkOption {
+ default = {};
+ type = lib.types.submoduleWith {
+ modules = [ ({ options, ... }: {
+ options.value = lib.mkOption {};
+
+ options.internalFiles = lib.mkOption {
+ default = options.value.files;
+ };
+ })];
+ };
+ };
+
+ imports = [
+ {
+ _file = "the-file.nix";
+ submodule.value = 10;
+ }
+ ];
+}
diff --git a/lib/tests/modules/submoduleWithLib.nix b/lib/tests/modules/submoduleWithLib.nix
new file mode 100644
index 0000000000000..a011b366ff34e
--- /dev/null
+++ b/lib/tests/modules/submoduleWithLib.nix
@@ -0,0 +1,13 @@
+{ lib, ... }: {
+ options.submodule = lib.mkOption {
+ default = {};
+ type = lib.types.submoduleWith {
+ evalModules = ((import ../..).extend (self: super: { value = 10; })).evalModules;
+ modules = [ ({ lib, ... }: {
+ options.value = lib.mkOption {
+ default = lib.value;
+ };
+ })];
+ };
+ };
+}
diff --git a/lib/types.nix b/lib/types.nix
index 77105740bc235..6a88c1ad51a7a 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -408,27 +408,23 @@ rec {
submoduleWith =
{ modules
+ , evalModules ? lib.modules.evalModules
, specialArgs ? {}
, shorthandOnlyDefinesConfig ? false
}@attrs:
let
- inherit (lib.modules) evalModules;
-
- coerce = unify: value: if isFunction value
- then setFunctionArgs (args: unify (value args)) (functionArgs value)
- else unify (if shorthandOnlyDefinesConfig then { config = value; } else value);
allModules = defs: modules ++ imap1 (n: { value, file }:
- if isAttrs value || isFunction value then
- # Annotate the value with the location of its definition for better error messages
- coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value
- else value
+ if isAttrs value && shorthandOnlyDefinesConfig
+ then { _file = file; config = value; }
+ else { _file = file; imports = [ value ]; }
) defs;
freeformType = (evalModules {
inherit modules specialArgs;
args.name = "‹name›";
- })._module.freeformType;
+ })._module.freeformType or null;
+ # `or null` in case the given evalModules doesn't have that attribute yet
in
mkOptionType rec {
@@ -477,6 +473,10 @@ rec {
modules = modules;
specialArgs = specialArgs;
shorthandOnlyDefinesConfig = shorthandOnlyDefinesConfig;
+ } // optionalAttrs (attrs ? evalModules) {
+ # We need to be able to detect whether evalModules was set or not in
+ # the binOp function, to throw an error if it was set multiple times
+ inherit (attrs) evalModules;
};
binOp = lhs: rhs: {
modules = lhs.modules ++ rhs.modules;
@@ -489,6 +489,10 @@ rec {
if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
then lhs.shorthandOnlyDefinesConfig
else throw "A submoduleWith option is declared multiple times with conflicting shorthandOnlyDefinesConfig values";
+ } // optionalAttrs (lhs ? evalModules || rhs ? evalModules) {
+ evalModules = if lhs ? evalModules && rhs ? evalModules
+ then throw "A submoduleWith option is declared multiple times with conflicting evalModules values"
+ else lhs.evalModules or rhs.evalModules;
};
};
};
diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml
index 3d2191e2f3f31..25013918bd31a 100644
--- a/nixos/doc/manual/development/option-types.xml
+++ b/nixos/doc/manual/development/option-types.xml
@@ -319,6 +319,7 @@
types.submoduleWith {
modules,
+ evalModules ? lib.evalModules,
specialArgs ? {},
shorthandOnlyDefinesConfig ? false }
@@ -335,6 +336,14 @@
Only options defined with this argument are included in rendered documentation.
+
+ evalModules
+ The function used to evaluate the given modules. This can be set to a
+ lib.evalModules from another nixpkgs version if
+ the modules require that version for evaluation. This also causes
+ the lib module argument for the submodules to
+ point to the lib from evalModules.
+
specialArgs
An attribute set of extra arguments to be passed to the module functions.