lib.makeOverridable: preserve constructor override and metadata attributes (#461032)

This commit is contained in:
Robert Hensing 2025-12-22 13:20:41 +00:00 committed by GitHub
commit 34b2f6702f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 97 additions and 1 deletions

View file

@ -156,8 +156,25 @@ rec {
let
# Creates a functor with the same arguments as f
mirrorArgs = mirrorFunctionArgs f;
# Recover overrider and additional attributes for f
# When f is a callable attribute set,
# it may contain its own `f.override` and additional attributes.
# This helper function recovers those attributes and decorate the overrider.
recoverMetadata =
if isAttrs f then
fDecorated:
# Preserve additional attributes for f
f
// fDecorated
# Decorate f.override if presented
// lib.optionalAttrs (f ? override) {
override = fdrv: makeOverridable (f.override fdrv);
}
else
id;
decorate = f': recoverMetadata (mirrorArgs f');
in
mirrorArgs (
decorate (
origArgs:
let
result = f origArgs;

View file

@ -203,6 +203,85 @@ runTests {
};
};
testOverridePreserveFunctionMetadata =
let
toCallableAttrs = f: setFunctionArgs f (functionArgs f);
constructDefinition =
{
a ? 3,
}:
toCallableAttrs (
{
b ? 5,
}:
{
inherit a b;
}
)
// {
inherit a;
c = 7;
};
construct0 = makeOverridable constructDefinition { };
construct1 = makeOverridable construct0;
construct0p = construct0.override { a = 11; };
construct1p = construct1.override { a = 11; };
in
{
expr = {
construct-metadata = {
inherit (construct1) a c;
};
construct-overridden-metadata = {
v = construct0p.a;
inherit (construct1p) a c;
};
construct-overridden-result-overrider = {
result-overriders-exist = mapAttrs (_: f: (f { }) ? override) {
inherit construct1 construct1p;
};
result-overrider-functionality = {
overridden = {
inherit ((construct1p { }).override { b = 13; }) a b;
};
direct = {
inherit (construct1p { b = 13; }) a b;
};
v = {
inherit (construct0p { b = 13; }) a b;
};
};
};
};
expected = {
construct-metadata = {
inherit (construct0) a c;
};
construct-overridden-metadata = {
v = 11;
inherit (construct0p) a c;
};
construct-overridden-result-overrider = {
result-overriders-exist = {
construct1 = true;
construct1p = true;
};
result-overrider-functionality = {
overridden = {
inherit (construct0p { b = 13; }) a b;
};
direct = {
inherit (construct0p { b = 13; }) a b;
};
v = {
a = 11;
b = 13;
};
};
};
};
};
testCallPackageWithOverridePreservesArguments =
let
f =