-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
lib/types.nix: implement getSubOptions for either #422272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
8895863
135273f
1f90ec3
1a61a83
4edc3d7
67da488
b18d7a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1439,6 +1439,9 @@ let | |||||||||||||||||
| # Either value of type `t1` or `t2`. | ||||||||||||||||||
| either = | ||||||||||||||||||
| t1: t2: | ||||||||||||||||||
| let | ||||||||||||||||||
| isEitherOrSubmodule = t: t.name == "either" || t.name == "submodule"; | ||||||||||||||||||
| in | ||||||||||||||||||
| mkOptionType rec { | ||||||||||||||||||
| name = "either"; | ||||||||||||||||||
| description = | ||||||||||||||||||
|
|
@@ -1520,6 +1523,32 @@ let | |||||||||||||||||
| t2 | ||||||||||||||||||
| ]; | ||||||||||||||||||
| }; | ||||||||||||||||||
| # We have to be really careful of recursively-defined types here. either is the type used | ||||||||||||||||||
| # to allow finitely-sized values for recursively-defined types, so we have to put limits | ||||||||||||||||||
| # on how we recurse when looking for submodules. To that end, we'll look for submodule | ||||||||||||||||||
| # children, and only recurse into either itself. This means `either str submodule` will | ||||||||||||||||||
| # work, and `either str (attrsOf submodule)` won't, but that's better than nothing. | ||||||||||||||||||
|
Comment on lines
+1526
to
+1530
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I disagree with this comment. I do think But I don't think there should be fundamental limits put in place for which sub types should be recursed into. And I don't think
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't treat
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the logical difference I was missing between current recursive structures and a recursive However I still feel like having arbitrary restrictions on which types we support recursing into is a flawed approach. I much prefer @hsjobeki and @infinisil 's suggestions of counting the recursion depth and/or checking for repeated/duplicate nodes, as that feels like a more general solution. Or perhaps there's another approach?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you propose to count recursion depth, without completely replacing I do agree that having restrictions on what types we support isn't great. But it's not arbitrary, it's better than what we have today, and I don't actually see any practical alternative right now.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As i have written down in my other comment A possible solution: deprecate/change Giving types more control over docs generation is probably generally a good idea. And can be done in a non-breaking way. For example we could introduce a new |
||||||||||||||||||
| getSubOptions = | ||||||||||||||||||
| prefix: | ||||||||||||||||||
| lib.recursiveUpdateUntil | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The returned subopts attrset doesn't have to match the "real" attrnames, because attrnames are discarded when collecting options for docs. Elsewhere, we avoid name conflicts and the need to do updates by doing things like: getSubOptions = loc: {
left = t1.getSubOptions loc;
right = t2.getSubOptions loc;
}
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where do we do this? I would expect that writing code like that would trip up
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E.g. for freeformType's sub-options, we nest them in Lines 1276 to 1282 in 35e52de
The relevant docs code in Line 607 in a033f62
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That code isn't what you described before. What you described before was a type that inserted keys for its nested types. We can't do that because it breaks
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point I'm trying to make is that the option's The For example, with the freeformType sub-options above, the loc will be something like Even if we look at a simpler example, like One scenario where this may be relevant for an |
||||||||||||||||||
| ( | ||||||||||||||||||
| _: a: b: | ||||||||||||||||||
| lib.isOption a || lib.isOption b | ||||||||||||||||||
| ) | ||||||||||||||||||
| (optionalAttrs (isEitherOrSubmodule t2) (t2.getSubOptions prefix)) | ||||||||||||||||||
| (optionalAttrs (isEitherOrSubmodule t1) (t1.getSubOptions prefix)); | ||||||||||||||||||
| getSubModules = | ||||||||||||||||||
| let | ||||||||||||||||||
| t1sm = if isEitherOrSubmodule t1 then t1.getSubModules else null; | ||||||||||||||||||
| t2sm = if isEitherOrSubmodule t2 then t2.getSubModules else null; | ||||||||||||||||||
| in | ||||||||||||||||||
| if t1sm == null then t2sm else t1sm; | ||||||||||||||||||
| substSubModules = | ||||||||||||||||||
| m: | ||||||||||||||||||
| let | ||||||||||||||||||
| t1sm = if isEitherOrSubmodule t1 then t1.getSubModules else null; | ||||||||||||||||||
| in | ||||||||||||||||||
| if t1sm == null then either t1 (t2.substSubModules m) else either (t1.substSubModules m) t2; | ||||||||||||||||||
| nestedTypes.left = t1; | ||||||||||||||||||
| nestedTypes.right = t2; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A cleaner way to write this would be:
However, as per my comment on the comment below, I don't think these special cases should exist at all.