feat: remove some requirements for merging types

The type merging code is too restrictive - a bug - since as some types
that specify defaults can't be merged at all even if they should be able
to.

I've made the merging system to allow merging if any of the following
apply:
- Unmergeable properties are unspecified on one side
- Unmergeable properties have different priorities, in which case we
  will take the more important priority - this allows overrides
- Unmergeable properties are the same on both sides, for example this
  lets us specify everything at default priorities and have them merged

Merging each of the problem properties manually also lets us pinpoint
what the issue is and merge them in a nicer way

Change-Id: I605b034fdfc537e84785ce5149e443f54e5d4e3a
This commit is contained in:
Skyler Grey 2025-06-03 13:11:02 +00:00
parent 7b154aae01
commit 1405f5515f

View file

@ -116,15 +116,23 @@ lib: {
++ result.options
else
result.options;
getPriority =
value:
if lib.types.is "override" value then
value.priority
else
lib.modules.DEFAULT_PRIORITY;
higherPriority = value1: value2: (getPriority value1) < (getPriority value2);
mergeProperty = name:
if (higherPriority result.${name} option.options.${name}) then result.${name}
else if (higherPriority option.options.${name} result.${name}) then option.options.${name}
else if result.${name} == option.options.${name} then result.${name} # This is mostly so any defaults/etc. get merged cleanly
else builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles}, but their ${name} values could not be merged. Please set one as a higher priority (e.g. using `${name} = lib.modules.overrides.force <value>`) or remove a definition";
in
if
shared "default"
|| shared "example"
|| shared "description"
|| shared "apply"
|| (shared "type" && !isTypeMergeable)
shared "type" && !isTypeMergeable
then
builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles}"
builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles} but its type is not mergeable. Please remove a definition"
else
option.options
// result
@ -132,6 +140,10 @@ lib: {
declarations = result.declarations ++ [ option.__file__ ];
options = submodules;
}
// (if shared "default" then { default = mergeProperty "default"; } else {})
// (if shared "example" then { example = mergeProperty "example"; } else {})
// (if shared "description" then { description = mergeProperty "description"; } else {})
// (if shared "apply" then { apply = mergeProperty "apply"; } else {})
// typeSet;
in
builtins.foldl' merge {