mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-10 03:23:29 +03:00
Revert "lib/types: init {types.attrsWith}"
This commit is contained in:
parent
afd9ca8bf0
commit
907cb3d253
4 changed files with 47 additions and 177 deletions
|
@ -751,47 +751,17 @@ let
|
||||||
t' = opt.options.type;
|
t' = opt.options.type;
|
||||||
mergedType = t.typeMerge t'.functor;
|
mergedType = t.typeMerge t'.functor;
|
||||||
typesMergeable = mergedType != null;
|
typesMergeable = mergedType != null;
|
||||||
|
typeSet = if (bothHave "type") && typesMergeable
|
||||||
# TODO: Remove this when all downstream reliances of internals: 'functor.wrapped' are sufficiently migrated.
|
then { type = mergedType; }
|
||||||
# A function that adds the deprecated wrapped message to a type.
|
else {};
|
||||||
addDeprecatedWrapped = t:
|
|
||||||
t // {
|
|
||||||
functor = t.functor // {
|
|
||||||
wrapped = t.functor.wrappedDeprecationMessage {
|
|
||||||
inherit loc;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
typeSet =
|
|
||||||
if opt.options ? type then
|
|
||||||
if res ? type then
|
|
||||||
if typesMergeable then
|
|
||||||
{
|
|
||||||
type =
|
|
||||||
if mergedType ? functor.wrappedDeprecationMessage then
|
|
||||||
addDeprecatedWrapped mergedType
|
|
||||||
else
|
|
||||||
mergedType;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
# Keep in sync with the same error below!
|
|
||||||
throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
|
|
||||||
else if opt.options.type ? functor.wrappedDeprecationMessage then
|
|
||||||
{ type = addDeprecatedWrapped opt.options.type; }
|
|
||||||
else
|
|
||||||
{}
|
|
||||||
else
|
|
||||||
{};
|
|
||||||
|
|
||||||
bothHave = k: opt.options ? ${k} && res ? ${k};
|
bothHave = k: opt.options ? ${k} && res ? ${k};
|
||||||
in
|
in
|
||||||
if bothHave "default" ||
|
if bothHave "default" ||
|
||||||
bothHave "example" ||
|
bothHave "example" ||
|
||||||
bothHave "description" ||
|
bothHave "description" ||
|
||||||
bothHave "apply"
|
bothHave "apply" ||
|
||||||
|
(bothHave "type" && (! typesMergeable))
|
||||||
then
|
then
|
||||||
# Keep in sync with the same error above!
|
|
||||||
throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
|
throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
|
|
|
@ -386,14 +386,6 @@ checkConfigOutput '^true$' config.conditionalWorks ./declare-attrsOf.nix ./attrs
|
||||||
checkConfigOutput '^false$' config.conditionalWorks ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
|
checkConfigOutput '^false$' config.conditionalWorks ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
|
||||||
checkConfigOutput '^"empty"$' config.value.foo ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
|
checkConfigOutput '^"empty"$' config.value.foo ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
|
||||||
|
|
||||||
# Check attrsWith type merging
|
|
||||||
checkConfigError 'The option `mergedLazyNonLazy'\'' in `.*'\'' is already declared in `.*'\''\.' options.mergedLazyNonLazy ./lazy-attrsWith.nix
|
|
||||||
checkConfigOutput '^11$' config.lazyResult ./lazy-attrsWith.nix
|
|
||||||
checkConfigError 'infinite recursion encountered' config.nonLazyResult ./lazy-attrsWith.nix
|
|
||||||
|
|
||||||
# Test the attrsOf functor.wrapped warning
|
|
||||||
# shellcheck disable=2016
|
|
||||||
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `type.functor.wrapped` attribute of the option `mergedLazyLazy` is accessed, use `nestedTypes.elemType` instead.' options.mergedLazyLazy.type.functor.wrapped ./lazy-attrsWith.nix
|
|
||||||
|
|
||||||
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
|
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
|
||||||
checkConfigError 'A definition for option .* is not of type .*' \
|
checkConfigError 'A definition for option .* is not of type .*' \
|
||||||
|
@ -583,7 +575,6 @@ checkConfigOutput '^38|27$' options.submoduleLine38.declarationPositions.1.line
|
||||||
# nested options work
|
# nested options work
|
||||||
checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix
|
checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix
|
||||||
|
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
====== module tests ======
|
====== module tests ======
|
||||||
$pass Pass
|
$pass Pass
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
# Check that AttrsWith { lazy = true; } is lazy
|
|
||||||
{ lib, ... }:
|
|
||||||
let
|
|
||||||
inherit (lib) types mkOption;
|
|
||||||
|
|
||||||
lazyAttrsOf = mkOption {
|
|
||||||
# Same as lazyAttrsOf
|
|
||||||
type = types.attrsWith {
|
|
||||||
lazy = true;
|
|
||||||
elemType = types.int;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
attrsOf = mkOption {
|
|
||||||
# Same as lazyAttrsOf
|
|
||||||
type = types.attrsWith {
|
|
||||||
elemType = types.int;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
# Module A
|
|
||||||
(
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
options.mergedLazyLazy = lazyAttrsOf;
|
|
||||||
options.mergedLazyNonLazy = lazyAttrsOf;
|
|
||||||
options.mergedNonLazyNonLazy = attrsOf;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Module B
|
|
||||||
(
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
options.mergedLazyLazy = lazyAttrsOf;
|
|
||||||
options.mergedLazyNonLazy = attrsOf;
|
|
||||||
options.mergedNonLazyNonLazy = attrsOf;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Result
|
|
||||||
(
|
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
# Can only evaluate if lazy
|
|
||||||
config.mergedLazyLazy.bar = config.mergedLazyLazy.baz + 1;
|
|
||||||
config.mergedLazyLazy.baz = 10;
|
|
||||||
options.lazyResult = mkOption { default = config.mergedLazyLazy.bar; };
|
|
||||||
|
|
||||||
# Can not only evaluate if not lazy
|
|
||||||
config.mergedNonLazyNonLazy.bar = config.mergedNonLazyNonLazy.baz + 1;
|
|
||||||
config.mergedNonLazyNonLazy.baz = 10;
|
|
||||||
options.nonLazyResult = mkOption { default = config.mergedNonLazyNonLazy.bar; };
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
|
118
lib/types.nix
118
lib/types.nix
|
@ -83,15 +83,11 @@ rec {
|
||||||
# Default type merging function
|
# Default type merging function
|
||||||
# takes two type functors and return the merged type
|
# takes two type functors and return the merged type
|
||||||
defaultTypeMerge = f: f':
|
defaultTypeMerge = f: f':
|
||||||
let
|
let mergedWrapped = f.wrapped.typeMerge f'.wrapped.functor;
|
||||||
mergedWrapped = f.wrapped.typeMerge f'.wrapped.functor;
|
mergedPayload = f.binOp f.payload f'.payload;
|
||||||
mergedPayload = f.binOp f.payload f'.payload;
|
|
||||||
|
|
||||||
hasPayload = assert (f'.payload != null) == (f.payload != null); f.payload != null;
|
hasPayload = assert (f'.payload != null) == (f.payload != null); f.payload != null;
|
||||||
hasWrapped = assert (f'.wrapped != null) == (f.wrapped != null); f.wrapped != null;
|
hasWrapped = assert (f'.wrapped != null) == (f.wrapped != null); f.wrapped != null;
|
||||||
|
|
||||||
typeFromPayload = if mergedPayload == null then null else f.type mergedPayload;
|
|
||||||
typeFromWrapped = if mergedWrapped == null then null else f.type mergedWrapped;
|
|
||||||
in
|
in
|
||||||
# Abort early: cannot merge different types
|
# Abort early: cannot merge different types
|
||||||
if f.name != f'.name
|
if f.name != f'.name
|
||||||
|
@ -99,23 +95,23 @@ rec {
|
||||||
else
|
else
|
||||||
|
|
||||||
if hasPayload then
|
if hasPayload then
|
||||||
# Just return the payload if returning wrapped is deprecated
|
if hasWrapped then
|
||||||
if f ? wrappedDeprecationMessage then
|
|
||||||
typeFromPayload
|
|
||||||
else if hasWrapped then
|
|
||||||
# Has both wrapped and payload
|
# Has both wrapped and payload
|
||||||
throw ''
|
throw ''
|
||||||
Type ${f.name} defines both `functor.payload` and `functor.wrapped` at the same time, which is not supported.
|
Type ${f.name} defines both `functor.payload` and `functor.wrapped` at the same time, which is not supported.
|
||||||
|
|
||||||
Use either `functor.payload` or `functor.wrapped` but not both.
|
Use either `functor.payload` or `functor.wrapped` but not both.
|
||||||
|
|
||||||
If your code worked before remove either `functor.wrapped` or `functor.payload` from the type definition.
|
If your code worked before remove `functor.payload` from the type definition.
|
||||||
''
|
''
|
||||||
else
|
else
|
||||||
typeFromPayload
|
# Has payload
|
||||||
|
if mergedPayload == null then null else f.type mergedPayload
|
||||||
else
|
else
|
||||||
if hasWrapped then
|
if hasWrapped then
|
||||||
typeFromWrapped
|
# Has wrapped
|
||||||
|
# TODO(@hsjobeki): This could also be a warning and removed in the future
|
||||||
|
if mergedWrapped == null then null else f.type mergedWrapped
|
||||||
else
|
else
|
||||||
f.type;
|
f.type;
|
||||||
|
|
||||||
|
@ -586,78 +582,48 @@ rec {
|
||||||
substSubModules = m: nonEmptyListOf (elemType.substSubModules m);
|
substSubModules = m: nonEmptyListOf (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
attrsOf = elemType: attrsWith { inherit elemType; };
|
attrsOf = elemType: mkOptionType rec {
|
||||||
|
name = "attrsOf";
|
||||||
|
description = "attribute set of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
||||||
|
descriptionClass = "composite";
|
||||||
|
check = isAttrs;
|
||||||
|
merge = loc: defs:
|
||||||
|
mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
|
||||||
|
(mergeDefinitions (loc ++ [name]) elemType defs).optionalValue
|
||||||
|
)
|
||||||
|
# Push down position info.
|
||||||
|
(map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs)));
|
||||||
|
emptyValue = { value = {}; };
|
||||||
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: attrsOf (elemType.substSubModules m);
|
||||||
|
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||||
|
nestedTypes.elemType = elemType;
|
||||||
|
};
|
||||||
|
|
||||||
# A version of attrsOf that's lazy in its values at the expense of
|
# A version of attrsOf that's lazy in its values at the expense of
|
||||||
# conditional definitions not working properly. E.g. defining a value with
|
# conditional definitions not working properly. E.g. defining a value with
|
||||||
# `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with
|
# `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with
|
||||||
# attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an
|
# attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an
|
||||||
# error that it's not defined. Use only if conditional definitions don't make sense.
|
# error that it's not defined. Use only if conditional definitions don't make sense.
|
||||||
lazyAttrsOf = elemType: attrsWith { inherit elemType; lazy = true; };
|
lazyAttrsOf = elemType: mkOptionType rec {
|
||||||
|
name = "lazyAttrsOf";
|
||||||
# base type for lazyAttrsOf and attrsOf
|
description = "lazy attribute set of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
||||||
attrsWith =
|
|
||||||
let
|
|
||||||
# Push down position info.
|
|
||||||
pushPositions = map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value);
|
|
||||||
binOp = lhs: rhs:
|
|
||||||
let
|
|
||||||
elemType = lhs.elemType.typeMerge rhs.elemType.functor;
|
|
||||||
lazy =
|
|
||||||
if lhs.lazy == rhs.lazy then
|
|
||||||
lhs.lazy
|
|
||||||
else
|
|
||||||
null;
|
|
||||||
in
|
|
||||||
if elemType == null || lazy == null then
|
|
||||||
null
|
|
||||||
else
|
|
||||||
{
|
|
||||||
inherit elemType lazy;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
elemType,
|
|
||||||
lazy ? false,
|
|
||||||
}:
|
|
||||||
mkOptionType {
|
|
||||||
name = if lazy then "lazyAttrsOf" else "attrsOf";
|
|
||||||
description = (if lazy then "lazy attribute set" else "attribute set") + " of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
|
||||||
descriptionClass = "composite";
|
descriptionClass = "composite";
|
||||||
check = isAttrs;
|
check = isAttrs;
|
||||||
merge = if lazy then (
|
merge = loc: defs:
|
||||||
# Lazy merge Function
|
zipAttrsWith (name: defs:
|
||||||
loc: defs:
|
let merged = mergeDefinitions (loc ++ [name]) elemType defs;
|
||||||
zipAttrsWith (name: defs:
|
# mergedValue will trigger an appropriate error when accessed
|
||||||
let merged = mergeDefinitions (loc ++ [name]) elemType defs;
|
in merged.optionalValue.value or elemType.emptyValue.value or merged.mergedValue
|
||||||
# mergedValue will trigger an appropriate error when accessed
|
)
|
||||||
in merged.optionalValue.value or elemType.emptyValue.value or merged.mergedValue
|
# Push down position info.
|
||||||
)
|
(map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs);
|
||||||
# Push down position info.
|
|
||||||
(pushPositions defs)
|
|
||||||
) else (
|
|
||||||
# Non-lazy merge Function
|
|
||||||
loc: defs:
|
|
||||||
mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
|
|
||||||
(mergeDefinitions (loc ++ [name]) elemType (defs)).optionalValue
|
|
||||||
)
|
|
||||||
# Push down position info.
|
|
||||||
(pushPositions defs)))
|
|
||||||
);
|
|
||||||
emptyValue = { value = {}; };
|
emptyValue = { value = {}; };
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = m: attrsWith { elemType = elemType.substSubModules m; inherit lazy; };
|
substSubModules = m: lazyAttrsOf (elemType.substSubModules m);
|
||||||
functor = defaultFunctor "attrsWith" // {
|
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||||
wrappedDeprecationMessage = { loc }: lib.warn ''
|
|
||||||
The deprecated `type.functor.wrapped` attribute of the option `${showOption loc}` is accessed, use `type.nestedTypes.elemType` instead.
|
|
||||||
'' elemType;
|
|
||||||
payload = {
|
|
||||||
# Important!: Add new function attributes here in case of future changes
|
|
||||||
inherit elemType lazy;
|
|
||||||
};
|
|
||||||
inherit binOp;
|
|
||||||
};
|
|
||||||
nestedTypes.elemType = elemType;
|
nestedTypes.elemType = elemType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue