-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
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
lib/types.nix: listOf.check needs to check the elements #173568
Conversation
Prior to this commit, the `check` method in the `listOf` type in `lib/types.nix` would accept *any* list, even if the list was not in fact a "list of" the specified type. This meant that for checking purposes, `listOf bool` and `listOf int` were the same thing. This commit fixes that problem.
This check indeed isn't done like this, because it's too strict. Here's an example of where it breaks: ((import ./lib).evalModules {
modules = [
({ lib, ... }: {
options.foo = lib.mkOption {
type = lib.types.listOf lib.types.str;
};
config.foo = [
(lib.mkIf true "test")
];
})
];
}).config Before this PR running
But with this PR it fails:
I'm a bit surprised that no test in |
Btw there's another PR that wanted to do the same, but with a different motivation and an alternate solution: #168295 |
That doesn't seem that hard to work around: check = v: isList v && all (e: elemType.check e || e ? _type ) v; Of course it's not perfect but it's better, though ideally it'd be done after we
+1 |
I need to point out that in the module system, the recursive check is already done using
This then also comes with good error messages. |
Sure, but if we typecheck after |
@ckiee Do you have an example? I think the merging mechanism used by the module system is very solid |
@infinisil Looking more closely it seems that won't be a problem so I like your approach more than mine now, though it looks like it'd be headache-inducing to implement and verify the API hasn't changed other than the original |
Thanks for linking to that; that PR is closed and wouldn't pass CI if reopened. It also makes |
Is there a more minimal example? Perhaps that doesn't use NixOS modules? I run an entirely nixpkgs-built userspace but do not use NixOS, so I've never dug into NixOS modules. It seems weird that nixpkgs isn't allowed to check its The error message produced by
Thanks, I have included this in the latest push. |
Or is it? As above, the result before this PR is a ((import ./lib).evalModules {
modules = [
({ lib, ... }: {
options.foo = lib.mkOption {
type = lib.types.listOf lib.types.str;
};
config.foo = [
(lib.mkIf true "test")
"this is okay"
"but the next one won't be:"
(lib.mkIf true { oopsie = "doopsie"; }) # <-- added this
];
})
];
}).config #ckie@cookiemonster ~/git/nixpkgs -> nix-instantiate --eval --strict types.nix
error: A definition for option `foo.[definition 1-entry 4]' is not of type `string'. Definition values:
- In `<unknown-file>':
{
oopsie = "doopsie";
}
#(use '--show-trace' to show detailed location information) I expected it to evaluate fine and show it in the list but it didn't. I am very confused at why it is now actually evaluating the |
Yes, according to the nix language specification it is an attrset, not a string. |
But it isn't by the end of the evaluation. Then it's either gone or mapped into the inner value. |
I really have no idea what you're getting at here. Could you please provide a simpler example that doesn't involve the entire NixOS module system? Or explain why the problem isn't in the NixOS module system? As I mentioned in the comment at the top of this PR, if somebody can explain to me why types aren't types I'll change this PR to add just a comment explaining the situation. But at the moment I am totally failing to understand why nix types aren't nix types. So I would not know how to even begin writing that comment. Can you point me to some section of the nix language specification that I should re-read? |
I tried that test case on |
Please see the latest push, with which this test passes. I have tried all the test cases mentioned so far in this PR and get the same results with or without this PR (making sure to include the most recent commit). |
I think this diff is reasonable now. Can you squash and fix the merge conflict? |
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.
Strong 👎, this PR is not acceptable like this. As already explained in #173568 (comment), the module system does check listOf
's fully, and that's the way in which listOf
is intended to be used. So if you want meta to be fully checked you should make it use mergeDefinitions
.
Oh, for some reason I was convinced this doesn't error currently, but it does (on recent nixos-unstable and the commit this PR is based on) ((import ./lib).evalModules {
modules = [
({ lib, ... }: {
options.foo = lib.mkOption {
type = lib.types.listOf lib.types.str;
};
config.foo = [
(lib.mkIf true 123)
# or: 123
];
})
];
}).config
So unless I am missing something very obvious I don't see why this PR got this far at all? |
This is all very unfortunate. The non-obvious requirement here is that the module system needs to be close to as lazy as possible; otherwise some configuration logic becomes inexpressible. The I also would like to see a more useful I can't dismiss the possibility of improving the module-and-type system, but the requirements are be tight:
An avenue that's worth exploring is to make Perhaps another possibility is adding a new attribute to the types, specifically for strict and deep checking. This will have no use in the module system, but could be a little bit faster than using the merge functions. We'll want to make Even if improving |
# NixOS apparently has a different notion of "type" than nix(lang) | ||
# does; see discussion in GH #173568 |
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.
Is this the type of comment you would like to have in your code base?
It is accusatory and it lacks real meaning. Can't even paste a URL. A few extra words could have fixed that. (and a lazy Ctrl+L Ctrl+C to copy the whole url)
(I'll shut up now, but I figured this is useful feedback for your future PRs)
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.
I would be happy to include complete URLs, and will do so in the future. It wasn't laziness. Some people get cranky about big long URLs messing up the line-wrapping in multi-line comments. Other people insist on prefixing issue numbers to identify the bugtracker (BZ for Bugzilla, etc) in case the project migrates from one to another in the future. Personally, I don't have strong feelings about any of these things, and just go along with the prevailing trend. Now that I know, my future PRs which reference github issues from a comment will use a complete URL.
Regarding the part of the comment before the question mark:
Is this the type of comment you would like to have in your code base?
It is highly non-obvious that types.nix
uses a different definition of "list of <type>
" than the Nix language definition does. I do think that non-obvious departures should be documented with comments. Is it documented somewhere else?
Thank you, @roberth, for taking the time to explain your objection. I appreciate that. |
The main motivation for this PR was checking the In any case, my takeaway from this whole discussion is approximately: "nixpkgs can't typecheck its Additional context, if helpful: I use "NixpkgsOS" rather than NixOS. Perhaps I lack perspective because of that. |
This isn't true. You could use
I get the scare quotes, but the module system is actually an independent component, independent of NixOS. It's used in many places. The layering works out fine:
where examples of configuration managers are NixOS, nix-darwin, home-manager.
Unless you like a challenge!
I don't expect NixOS users (or even contributors I guess) to fully understand the importance of laziness in the module system either. |
The costs are often paid in personal friction and generally pissing off of people. I don't rise to those sorts of challenges.
Thanks for pointing out that home-manager can be used standalone, without NixOS. This gives me a reason to learn about it, and therefore to learn about modules (I don't have any Darwin-capable hardware, so nix-darwin isn't particularly motivating for me). Somebody should probably update the wiki, which strongly implies that modules are something specific to NixOS:
Maybe when I understand them better I will make that update. The fact that |
Description of changes
Prior to this commit, the
check
method in thelistOf
type inlib/types.nix
would accept any list, even if the list was not in fact a "list of" the specified type. This meant that for checking purposes,listOf bool
andlistOf int
were the same thing.This commit fixes that problem.
If the behavior above was in fact deliberate (which I would find surprising), please explain the reasoning to me and I will amend this commit to instead insert a comment explaining why this is the case.
This PR also makes a minor adjustment to the type declaration for
meta.license
. Previously this field could be a list oflicense
s or a list ofstr
, but not a heterogeneous list with somelicense
s and somestr
s. Since many packages are in fact using heterogeneous mixed lists oflicense
-and-str
, and the oldtypes.nix
wasn't checking the old type declaration, I have updated the declaration to agree with the current usage.Things done