@@ -438,4 +438,76 @@ rec {
438438 ${ extenderName } = f : makeExtensibleWithCustomName extenderName ( extends f rattrs ) ;
439439 }
440440 ) ;
441+
442+ /**
443+ Convert to an extending function (overlay).
444+
445+ `toExtension` is the `toFunction` for extending functions (a.k.a. extensions or overlays).
446+ It converts a non-function or a single-argument function to an extending function,
447+ while returning a two-argument function as-is.
448+
449+ That is, it takes a value of the shape `x`, `prev: x`, or `final: prev: x`,
450+ and returns `final: prev: x`, assuming `x` is not a function.
451+
452+ This function takes care of the input to `stdenv.mkDerivation`'s
453+ `overrideAttrs` function.
454+ It bridges the gap between `<pkg>.overrideAttrs`
455+ before and after the overlay-style support.
456+
457+ # Inputs
458+
459+ `f`
460+ : The function or value to convert to an extending function.
461+
462+ # Type
463+
464+ ```
465+ toExtension ::
466+ b' -> Any -> Any -> b'
467+ or
468+ toExtension ::
469+ (a -> b') -> Any -> a -> b'
470+ or
471+ toExtension ::
472+ (a -> a -> b) -> a -> a -> b
473+ where b' = ! Callable
474+
475+ Set a = b = b' = AttrSet & ! Callable to make toExtension return an extending function.
476+ ```
477+
478+ # Examples
479+ :::{.example}
480+ ## `lib.fixedPoints.toExtension` usage example
481+
482+ ```nix
483+ fix (final: { a = 0; c = final.a; })
484+ => { a = 0; c = 0; };
485+
486+ fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; }))
487+ => { a = 1; b = 2; c = 1; };
488+
489+ fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; }))
490+ => { a = 1; b = 0; c = 1; };
491+
492+ fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1 })) (final: { a = 0; c = final.a; }))
493+ => { a = 1; b = 0; c = 2; };
494+ ```
495+ :::
496+ */
497+ toExtension =
498+ f :
499+ if lib . isFunction f then
500+ final : prev :
501+ let
502+ fPrev = f prev ;
503+ in
504+ if lib . isFunction fPrev then
505+ # f is (final: prev: { ... })
506+ f final prev
507+ else
508+ # f is (prev: { ... })
509+ fPrev
510+ else
511+ # f is not a function; probably { ... }
512+ final : prev : f ;
441513}
0 commit comments