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
Prevent mkIf
's from being //
'd, and co.
#72949
Conversation
Is there a way the errors could be nicer? |
@grahamc I considered different things, but none really work out:
|
a2047ac
to
7192b4e
Compare
applyIfFunction = key: f: args@{ config, options, lib, ... }: | ||
# We only want to apply module arguments if we're actually dealing with a | ||
# module function, an opaque wrapper isn't one | ||
if isFunction f && ! isOpaqueWrapper f then |
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.
This right here is a bit hacky. It's needed because the module system assumes that if you have a function as a module, it must be a NixOS module function. This worked fine with imports = [ (mkMerge [ ... ]) ];
previously, because mkMerge
didn't return a function but an attrset. But with this change it does. So we need to prevent it trying to call the opaque wrapper function (which is really just an implementation detail) with NixOS arguments.
I'll argue that the module system allowing both attribute sets and functions as modules on a guessing basis is hacky already, so this is just a counter-hack!
What's the impact on evaluation time / memory? |
@edolstra See https://github.com/NixOS/nixpkgs/pull/72949/checks?check_run_id=291926489 I'm not entirely sure what this eval run includes, it might be |
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.
Thanks for noticing this issue and fixing it.
7192b4e
to
7a71057
Compare
ToDo: Make sure this isn't bad for performance (it might be that ofborg's eval only measures nixpkgs time) |
Doing a measurement on my system with 4 samples:
So that's about a 6% increase in evaluation time. Not sure if worth. It sure can prevent bugs, but the error message is really not that great, and 6% is kind of a lot. Wouldn't have to worry about that if #57477 was resolved |
Thank you for your contributions.
|
Motivation for this change
mkIf
can be very deceiving, since the following doesn't do what you might expect:Because in fact, this results in exactly the same behavior as
The assigment to
foo
gets completely ignored! This is because of the implementation ofmkIf
:nixpkgs/lib/modules.nix
Lines 500 to 503 in 9221668
which makes the resulting value in the above example be of the form
mkIf
creates an attribute set with some special keys the module system uses to figure out whether it's amkIf
and allow lazy evaluation of the condition and contents. So using//
on these attribute sets makes no sense because the keys don't represent the actual values, but some meta attributes!This has led to at least one annoying bug in NixOS, see #72916. In addition I've seen this a couple times when reviewing NixOS module PRs too.
With this change, doing such mistakes gives the error
which admittedly is pretty bad, but any error is better than incorrect behavior that potentially never gets noticed, and this is the only way I could come up with an error being produced at all that doesn't require changing everything.
Now when the user sees this error they have to fix their conditionals by using
mkMerge
which correctly handles this:This problem can also occur with other such functions like
mkMerge
,mkOverride
andmkOrder
combined with//
or attribute access. This PR will make all of those throw an error when used incorrectly.See the commits for an explanation of the implementation.
Ping @jtojnar @JohnAZoidberg @worldofpeace @rycee
Things done
mkIf
+//
(and similar) in nixpkgs