diff --git a/lib/modules.nix b/lib/modules.nix index 4966619f..9371ba4b 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -630,7 +630,13 @@ let loc = prefix ++ [name]; defns = pushedDownDefinitionsByName.${name} or []; defns' = rawDefinitionsByName.${name} or []; - optionDecls = filter (m: isOption m.options) decls; + optionDecls = filter + (m: m.options?_type + && (m.options._type == "option" + || throwDeclarationTypeError loc m.options._type + ) + ) + decls; in if length optionDecls == length decls then let opt = fixupOptionType loc (mergeOptionDecls loc decls); @@ -692,6 +698,32 @@ let ) unmatchedDefnsByName); }; + throwDeclarationTypeError = loc: actualTag: + let + name = lib.strings.escapeNixIdentifier (lib.lists.last loc); + path = showOption loc; + depth = length loc; + + paragraphs = [ + "Expected an option declaration at option path `${path}` but got an attribute set with type ${actualTag}" + ] ++ optional (actualTag == "option-type") '' + When declaring an option, you must wrap the type in a `mkOption` call. It should look somewhat like: + ${comment} + ${name} = lib.mkOption { + description = ...; + type = ; + ... + }; + ''; + + # Ideally we'd know the exact syntax they used, but short of that, + # we can only reliably repeat the last. However, we repeat the + # full path in a non-misleading way here, in case they overlook + # the start of the message. Examples attract attention. + comment = optionalString (depth > 1) "\n # ${showOption loc}"; + in + throw (concatStringsSep "\n\n" paragraphs); + /* Merge multiple option declarations into a single declaration. In general, there should be only one declaration of each option. The exception is the ‘options’ attribute, which specifies diff --git a/lib/tests/modules/options-type-error-configuration.nix b/lib/tests/modules/options-type-error-configuration.nix new file mode 100644 index 00000000..bcd6db89 --- /dev/null +++ b/lib/tests/modules/options-type-error-configuration.nix @@ -0,0 +1,6 @@ +{ lib, ... }: { + options = { + # unlikely mistake, but we can catch any attrset with _type + result = lib.evalModules { modules = []; }; + }; +} diff --git a/lib/tests/modules/options-type-error-typical-nested.nix b/lib/tests/modules/options-type-error-typical-nested.nix new file mode 100644 index 00000000..2c07e19f --- /dev/null +++ b/lib/tests/modules/options-type-error-typical-nested.nix @@ -0,0 +1,5 @@ +{ lib, ... }: { + options = { + result.here = lib.types.str; + }; +} diff --git a/lib/tests/modules/options-type-error-typical.nix b/lib/tests/modules/options-type-error-typical.nix new file mode 100644 index 00000000..416f436e --- /dev/null +++ b/lib/tests/modules/options-type-error-typical.nix @@ -0,0 +1,5 @@ +{ lib, ... }: { + options = { + result = lib.types.str; + }; +}