lib.types: init mergeTypes (#364620)

This commit is contained in:
Johannes Kirschbauer 2025-02-10 22:10:30 +07:00 committed by GitHub
commit 9d3e649939
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 88 additions and 0 deletions

View File

@ -2612,4 +2612,45 @@ runTests {
};
expected = "c";
};
testMergeTypesSimple =
let
mergedType = types.mergeTypes types.str types.str;
in
{
expr = mergedType.name;
expected = "str";
};
testMergeTypesFail =
let
mergedType = types.mergeTypes types.str types.int;
in
{
expr = types.isType "merge-error" mergedType;
expected = true;
};
testMergeTypesEnum =
let
enumAB = lib.types.enum ["A" "B"];
enumXY = lib.types.enum ["X" "Y"];
merged = lib.types.mergeTypes enumAB enumXY; # -> enum [ "A" "B" "X" "Y" ]
in
{
expr = {
checkA = merged.check "A";
checkB = merged.check "B";
checkX = merged.check "X";
checkY = merged.check "Y";
checkC = merged.check "C";
};
expected = {
checkA = true;
checkB = true;
checkX = true;
checkY = true;
checkC = false;
};
};
}

View File

@ -1125,6 +1125,53 @@ rec {
addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };
};
/**
Merges two option types together.
:::{.note}
Uses the type merge function of the first type, to merge it with the second type.
Usually types can only be merged if they are of the same type
:::
# Inputs
: `a` (option type): The first option type.
: `b` (option type): The second option type.
# Returns
- The merged option type.
- `{ _type = "merge-error"; error = "Cannot merge types"; }` if the types can't be merged.
# Examples
:::{.example}
## `lib.types.mergeTypes` usage example
```nix
let
enumAB = lib.types.enum ["A" "B"];
enumXY = lib.types.enum ["X" "Y"];
# This operation could be notated as: [ A ] | [ B ] -> [ A B ]
merged = lib.types.mergeTypes enumAB enumXY; # -> enum [ "A" "B" "X" "Y" ]
in
assert merged.check "A"; # true
assert merged.check "B"; # true
assert merged.check "X"; # true
assert merged.check "Y"; # true
merged.check "C" # false
```
:::
*/
mergeTypes = a: b:
assert isOptionType a && isOptionType b;
let
merged = a.typeMerge b.functor;
in
if merged == null then
setType "merge-error" { error = "Cannot merge types"; }
else
merged;
};
in outer_types // outer_types.types