lib.functionArgs: fix correctness for nested functors

Restore the correct behaviour prior to commit bb71feaec1
("lib.functionArgs: save a function call on every lookup")
while preserving its performance gain with best efforts.
This commit is contained in:
Yueh-Shun Li
2026-10-16 06:08:51 +08:00
parent 85effadebf
commit 653dd12f1c
2 changed files with 64 additions and 2 deletions

View File

@@ -57,6 +57,7 @@ let
foldlAttrs
foldr
functionArgs
genAttrs
generators
genList
getExe
@@ -930,6 +931,54 @@ runTests {
expected = "1.2.3";
};
testFunctionArgsNestedFunctors =
let
faOrig = {
x = false;
};
faAlt = {
x = false;
y = true;
};
f0 = { x, ... }: x;
in
{
expr = {
a = functionArgs {
__functor = self: {
__functor = self: f0;
__functionArgs = faAlt;
};
};
b = functionArgs { __functor = self: { __functor = self: f0; }; };
c = functionArgs {
__functor = {
__functor = self: outer: f0;
};
};
d = functionArgs {
__functor = {
__functor = self: outer: {
__functor = self: f0;
__functionArgs = faAlt;
};
};
};
e = functionArgs {
__functor = {
__functor = self: outer: { __functor = self: f0; };
};
};
};
expected = {
a = faAlt;
b = faOrig;
c = faOrig;
d = faAlt;
e = faOrig;
};
};
testIsFunctionStr = {
expr = isFunction "a";
expected = false;

View File

@@ -1104,9 +1104,22 @@ in
*/
functionArgs =
let
functionArgs = builtins.functionArgs;
functionArgsLambda = builtins.functionArgs;
in
f: if f ? __functor then f.__functionArgs or (functionArgs (f.__functor f)) else functionArgs f;
f:
if f ? __functor then
f.__functionArgs or (
let
fInner = f.__functor f;
in
# Peel one recursion to avoid calling functionArgs
if fInner ? __functor then
fInner.__functionArgs or (functionArgs fInner)
else
functionArgsLambda fInner
)
else
functionArgsLambda f;
/**
Check whether something is a function or something