lib/modules: Add context to the "option does not exist" error

Add trace items that provide context for a failed definition that
can not be caught within the Nix language.

This also adds a test for the `tryEval` behavior of `showDefs`.

+12 -1
lib/modules.nix
···
if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
let
firstDef = head merged.unmatchedDefns;
-
baseMsg = "The option `${showOption (prefix ++ firstDef.prefix)}' does not exist. Definition values:${showDefs [ firstDef ]}";
+
baseMsg =
+
let
+
optText = showOption (prefix ++ firstDef.prefix);
+
defText =
+
builtins.addErrorContext
+
"while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
+
(builtins.addErrorContext
+
"while evaluating a definition from `${firstDef.file}'"
+
( showDefs [ firstDef ])
+
);
+
in
+
"The option `${optText}' does not exist. Definition values:${defText}";
in
if attrNames options == [ "_module" ]
then
+3
lib/tests/modules.sh
···
# Check boolean option.
checkConfigOutput '^false$' config.enable ./declare-enable.nix
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
+
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*' config.enable ./define-enable-throw.nix
+
checkConfigError 'while evaluating a definition from `.*/define-enable-abort.nix' config.enable ./define-enable-abort.nix
+
checkConfigError 'while evaluating the error message for definitions for .enable., which is an option that does not exist' config.enable ./define-enable-abort.nix
checkConfigOutput '^1$' config.bare-submodule.nested ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix
checkConfigOutput '^2$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix
+3
lib/tests/modules/define-enable-abort.nix
···
+
{
+
config.enable = abort "oops";
+
}
+3
lib/tests/modules/define-enable-throw.nix
···
+
{
+
config.enable = throw "oops";
+
}