Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ let
fromHexString toHexString toBaseDigits inPureEvalMode isBool isInt pathExists
genericClosure readFile;
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
composeManyExtensions makeExtensible makeExtensibleWithCustomName
toExtension;
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
getAttrFromPath attrVals attrNames attrValues getAttrs catAttrs filterAttrs
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
Expand Down
72 changes: 72 additions & 0 deletions lib/fixed-points.nix
Original file line number Diff line number Diff line change
Expand Up @@ -438,4 +438,76 @@ rec {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
}
);

/**
Convert to an extending function (overlay).

`toExtension` is the `toFunction` for extending functions (a.k.a. extensions or overlays).
It converts a non-function or a single-argument function to an extending function,
while returning a two-argument function as-is.

That is, it takes a value of the shape `x`, `prev: x`, or `final: prev: x`,
and returns `final: prev: x`, assuming `x` is not a function.

This function takes care of the input to `stdenv.mkDerivation`'s
`overrideAttrs` function.
It bridges the gap between `<pkg>.overrideAttrs`
before and after the overlay-style support.

# Inputs

`f`
: The function or value to convert to an extending function.

# Type

```
toExtension ::
b' -> Any -> Any -> b'
or
toExtension ::
(a -> b') -> Any -> a -> b'
or
toExtension ::
(a -> a -> b) -> a -> a -> b
where b' = ! Callable

Set a = b = b' = AttrSet & ! Callable to make toExtension return an extending function.
```

# Examples
:::{.example}
## `lib.fixedPoints.toExtension` usage example

```nix
fix (final: { a = 0; c = final.a; })
=> { a = 0; c = 0; };

fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 2; c = 1; };

fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 0; c = 1; };

fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1 })) (final: { a = 0; c = final.a; }))
=> { a = 1; b = 0; c = 2; };
```
:::
*/
toExtension =
f:
if lib.isFunction f then
final: prev:
let
fPrev = f prev;
in
if lib.isFunction fPrev then
# f is (final: prev: { ... })
f final prev
else
# f is (prev: { ... })
fPrev
else
# f is not a function; probably { ... }
final: prev: f;
}
29 changes: 24 additions & 5 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ let
const
escapeXML
evalModules
extends
filter
fix
fold
Expand Down Expand Up @@ -102,6 +103,7 @@ let
take
testAllTrue
toBaseDigits
toExtension
toHexString
fromHexString
toInt
Expand Down Expand Up @@ -233,11 +235,6 @@ runTests {
];
};

testFix = {
expr = fix (x: {a = if x ? a then "a" else "b";});
expected = {a = "a";};
};

testComposeExtensions = {
expr = let obj = makeExtensible (self: { foo = self.bar; });
f = self: super: { bar = false; baz = true; };
Expand Down Expand Up @@ -1237,6 +1234,28 @@ runTests {
attrsToList { someFunc= a: a + 1;}
);

# FIXED-POINTS

testFix = {
expr = fix (x: {a = if x ? a then "a" else "b";});
expected = {a = "a";};
};

testToExtension = {
expr = [
(fix (final: { a = 0; c = final.a; }))
(fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })))
(fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })))
(fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; })))
];
expected = [
{ a = 0; c = 0; }
{ a = 1; b = 2; c = 1; }
{ a = 1; b = 0; c = 1; }
{ a = 1; b = 0; c = 2; }
];
};

# GENERATORS
# these tests assume attributes are converted to lists
# in alphabetical order
Expand Down
16 changes: 1 addition & 15 deletions pkgs/build-support/go/module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,6 @@ let
GO111MODULE = "on";
GOTOOLCHAIN = "local";

toExtension =
overlay0:
if lib.isFunction overlay0 then
final: prev:
if lib.isFunction (overlay0 prev) then
# `overlay0` is `final: prev: { ... }`
overlay0 final prev
else
# `overlay0` is `prev: { ... }`
overlay0 prev
else
# `overlay0` is `{ ... }`
final: prev: overlay0;

in
(stdenv.mkDerivation (finalAttrs:
args
Expand Down Expand Up @@ -333,7 +319,7 @@ in
# Canonicallize `overrideModAttrs` as an attribute overlay.
# `passthru.overrideModAttrs` will be overridden
# when users want to override `goModules`.
overrideModAttrs = toExtension overrideModAttrs;
overrideModAttrs = lib.toExtension overrideModAttrs;
} // passthru;

meta = {
Expand Down
22 changes: 2 additions & 20 deletions pkgs/stdenv/generic/make-derivation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,8 @@ let
# ^^^^

overrideAttrs = f0:
let
f = self: super:
# Convert f0 to an overlay. Legacy is:
# overrideAttrs (super: {})
# We want to introduce self. We follow the convention of overlays:
# overrideAttrs (self: super: {})
# Which means the first parameter can be either self or super.
# This is surprising, but far better than the confusion that would
# arise from flipping an overlay's parameters in some cases.
let x = f0 super;
in
if builtins.isFunction x
then
# Can't reuse `x`, because `self` comes first.
# Looks inefficient, but `f0 super` was a cheap thunk.
f0 self super
else x;
in
makeDerivationExtensible
(self: let super = rattrs self; in super // (if builtins.isFunction f0 || f0?__functor then f self super else f0));
makeDerivationExtensible
(lib.extends (lib.toExtension f0) rattrs);

finalPackage =
mkDerivationSimple overrideAttrs args;
Expand Down