summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-support/default.nix2
-rw-r--r--doc/module-system/module-system.chapter.md6
-rw-r--r--lib/modules.nix26
-rw-r--r--lib/tests/modules/class-check.nix6
-rw-r--r--lib/types.nix10
-rw-r--r--nixos/lib/eval-config-minimal.nix5
-rw-r--r--nixos/lib/testing/default.nix2
-rw-r--r--nixos/modules/misc/documentation.nix2
-rw-r--r--pkgs/top-level/default.nix2
9 files changed, 39 insertions, 22 deletions
diff --git a/doc/doc-support/default.nix b/doc/doc-support/default.nix
index 67195a4a58b..cfa7cbdc828 100644
--- a/doc/doc-support/default.nix
+++ b/doc/doc-support/default.nix
@@ -47,7 +47,7 @@ let
   optionsDoc = pkgs.nixosOptionsDoc {
     inherit (pkgs.lib.evalModules {
       modules = [ ../../pkgs/top-level/config.nix ];
-      specialArgs.class = "nixpkgsConfig";
+      class = "nixpkgsConfig";
     }) options;
     documentType = "none";
     transformOptions = opt:
diff --git a/doc/module-system/module-system.chapter.md b/doc/module-system/module-system.chapter.md
index 9a24ab70c6c..51e600d7564 100644
--- a/doc/module-system/module-system.chapter.md
+++ b/doc/module-system/module-system.chapter.md
@@ -28,11 +28,11 @@ An attribute set of module arguments that can be used in `imports`.
 
 This is in contrast to `config._module.args`, which is only available after all `imports` have been resolved.
 
-#### `specialArgs.class` {#module-system-lib-evalModules-param-specialArgs-class}
+#### `class` {#module-system-lib-evalModules-param-class}
 
-If the `class` attribute is set in `specialArgs`, the module system will reject modules with a different `class`.
+If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `class`.
 
-The `class` value should be in lower [camel case](https://en.wikipedia.org/wiki/Camel_case).
+The `class` value should be a string in lower [camel case](https://en.wikipedia.org/wiki/Camel_case).
 
 If applicable, the `class` should match the "prefix" of the attributes used in (experimental) [flakes](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#description). Some examples are:
 
diff --git a/lib/modules.nix b/lib/modules.nix
index e83d5b6d1ca..3550ebddaea 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -78,13 +78,13 @@ let
                   # when resolving module structure (like in imports). For everything else,
                   # there's _module.args. If specialArgs.modulesPath is defined it will be
                   # used as the base path for disabledModules.
-                  #
-                  # `specialArgs.class`:
+                  specialArgs ? {}
+                , # `class`:
                   # A nominal type for modules. When set and non-null, this adds a check to
                   # make sure that only compatible modules are imported.
-                  specialArgs ? {}
-                , # This would be remove in the future, Prefer _module.args option instead.
-                  args ? {}
+                  # This would be remove in the future, Prefer _module.args option instead.
+                  class ? null
+                , args ? {}
                 , # This would be remove in the future, Prefer _module.check option instead.
                   check ? true
                 }:
@@ -220,6 +220,16 @@ let
               within a configuration, but can be used in module imports.
             '';
           };
+
+          _module.class = mkOption {
+            readOnly = true;
+            internal = true;
+            description = lib.mdDoc ''
+              If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `class`.
+
+              This option contains the expected `class` attribute of the current module evaluation.
+            '';
+          };
         };
 
         config = {
@@ -227,13 +237,14 @@ let
             inherit extendModules;
             moduleType = type;
           };
+          _module.class = class;
           _module.specialArgs = specialArgs;
         };
       };
 
       merged =
         let collected = collectModules
-          (specialArgs.class or null)
+          class
           (specialArgs.modulesPath or "")
           (regularModules ++ [ internalModule ])
           ({ inherit lib options config specialArgs; } // specialArgs);
@@ -310,13 +321,14 @@ let
         prefix ? [],
         }:
           evalModules (evalModulesArgs // {
+            inherit class;
             modules = regularModules ++ modules;
             specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
             prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
           });
 
       type = lib.types.submoduleWith {
-        inherit modules specialArgs;
+        inherit modules specialArgs class;
       };
 
       result = withWarnings {
diff --git a/lib/tests/modules/class-check.nix b/lib/tests/modules/class-check.nix
index f492c844abf..02d1431cc88 100644
--- a/lib/tests/modules/class-check.nix
+++ b/lib/tests/modules/class-check.nix
@@ -3,7 +3,7 @@
     _module.freeformType = lib.types.anything;
     ok =
       lib.evalModules {
-        specialArgs.class = "nixos";
+        class = "nixos";
         modules = [
           ./module-class-is-nixos.nix
         ];
@@ -11,7 +11,7 @@
 
     fail =
       lib.evalModules {
-        specialArgs.class = "nixos";
+        class = "nixos";
         modules = [
           ./module-class-is-nixos.nix
           ./module-class-is-darwin.nix
@@ -20,7 +20,7 @@
 
     fail-anon =
       lib.evalModules {
-        specialArgs.class = "nixos";
+        class = "nixos";
         modules = [
           ./module-class-is-nixos.nix
           { _file = "foo.nix#darwinModules.default";
diff --git a/lib/types.nix b/lib/types.nix
index 666e6502d16..e0da18a2feb 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -696,6 +696,7 @@ rec {
       , specialArgs ? {}
       , shorthandOnlyDefinesConfig ? false
       , description ? null
+      , class ? null
       }@attrs:
       let
         inherit (lib.modules) evalModules;
@@ -707,7 +708,7 @@ rec {
         ) defs;
 
         base = evalModules {
-          inherit specialArgs;
+          inherit class specialArgs;
           modules = [{
             # This is a work-around for the fact that some sub-modules,
             # such as the one included in an attribute set, expects an "args"
@@ -762,9 +763,14 @@ rec {
         functor = defaultFunctor name // {
           type = types.submoduleWith;
           payload = {
-            inherit modules specialArgs shorthandOnlyDefinesConfig description;
+            inherit modules class specialArgs shorthandOnlyDefinesConfig description;
           };
           binOp = lhs: rhs: {
+            class =
+              if lhs.class == null then rhs.class
+              else if rhs.class == null then lhs.class
+              else if lhs.class == rhs.class then lhs.class
+              else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\".";
             modules = lhs.modules ++ rhs.modules;
             specialArgs =
               let intersecting = builtins.intersectAttrs lhs.specialArgs rhs.specialArgs;
diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix
index 7e28f430512..03638912197 100644
--- a/nixos/lib/eval-config-minimal.nix
+++ b/nixos/lib/eval-config-minimal.nix
@@ -38,11 +38,10 @@ let
   #       is experimental.
   lib.evalModules {
     inherit prefix modules;
+    class = "nixos";
     specialArgs = {
       modulesPath = builtins.toString ../modules;
-    } // specialArgs // {
-      class = "nixos";
-    };
+    } // specialArgs;
   };
 
 in
diff --git a/nixos/lib/testing/default.nix b/nixos/lib/testing/default.nix
index 1bd6278ce68..a89f734b1e6 100644
--- a/nixos/lib/testing/default.nix
+++ b/nixos/lib/testing/default.nix
@@ -3,7 +3,7 @@ let
 
   evalTest = module: lib.evalModules {
     modules = testModules ++ [ module ];
-    specialArgs.class = "nixosTest";
+    class = "nixosTest";
   };
   runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result;
 
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 1821dd866cb..31486a2216a 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -38,8 +38,8 @@ let
           modules = [ {
             _module.check = false;
           } ] ++ docModules.eager;
+          class = "nixos";
           specialArgs = specialArgs // {
-            class = "nixos";
             pkgs = scrubDerivations "pkgs" pkgs;
             # allow access to arbitrary options for eager modules, eg for getting
             # option types from lazy modules
diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix
index f54ce84aeda..ba00e78ce2e 100644
--- a/pkgs/top-level/default.nix
+++ b/pkgs/top-level/default.nix
@@ -82,7 +82,7 @@ in let
         config = config1;
       })
     ];
-    specialArgs.class = "nixpkgsConfig";
+    class = "nixpkgsConfig";
   };
 
   # take all the rest as-is