mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-12-27 05:43:50 +03:00
lib/generators: withRecursion: don't break attr-sets with special attrs
Closes #168327 The issue reported there can be demonstrated with the following expression: → nix-instantiate --eval -E "with import ./. {}; pkgs.lib.options.showDefs [ { file = \"foo\"; value = pkgs.rust.packages.stable.buildRustPackages; } ]" error: attempt to call something which is not a function but a string at /home/ma27/Projects/nixpkgs/lib/trivial.nix:442:35: 441| isFunction = f: builtins.isFunction f || 442| (f ? __functor && isFunction (f.__functor f)); | ^ 443| Basically, if a `__functor` is in an attribute-set at depth-limit, `__functor` will be set to `"<unevaluated>"`. This however breaks `lib.isFunction` which checks for a `__functor` by invoking `__functor` with `f` itself. The same issue - "magic" attributes being shadowed by `withRecursion` - also applies to others such as `__pretty`/`__functionArgs`/`__toString`. Since these attributes have a low-risk of causing a stack overflow (because these are flat attr-sets or even functions), ignoring them in `withRecursion` seems like a valid solution.
This commit is contained in:
parent
dbe672e4a7
commit
7203788068
@ -251,6 +251,16 @@ rec {
|
|||||||
}:
|
}:
|
||||||
assert builtins.isInt depthLimit;
|
assert builtins.isInt depthLimit;
|
||||||
let
|
let
|
||||||
|
specialAttrs = [
|
||||||
|
"__functor"
|
||||||
|
"__functionArgs"
|
||||||
|
"__toString"
|
||||||
|
"__pretty"
|
||||||
|
];
|
||||||
|
stepIntoAttr = evalNext: name:
|
||||||
|
if builtins.elem name specialAttrs
|
||||||
|
then id
|
||||||
|
else evalNext;
|
||||||
transform = depth:
|
transform = depth:
|
||||||
if depthLimit != null && depth > depthLimit then
|
if depthLimit != null && depth > depthLimit then
|
||||||
if throwOnDepthLimit
|
if throwOnDepthLimit
|
||||||
@ -261,7 +271,7 @@ rec {
|
|||||||
let
|
let
|
||||||
evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
|
evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
|
||||||
in
|
in
|
||||||
if isAttrs v then mapAttrs (const evalNext) v
|
if isAttrs v then mapAttrs (stepIntoAttr evalNext) v
|
||||||
else if isList v then map evalNext v
|
else if isList v then map evalNext v
|
||||||
else transform (depth + 1) v;
|
else transform (depth + 1) v;
|
||||||
in
|
in
|
||||||
|
@ -613,6 +613,21 @@ runTests {
|
|||||||
expected = false;
|
expected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
testWithRecursionDealsWithFunctors =
|
||||||
|
let
|
||||||
|
functor = {
|
||||||
|
__functor = self: { a, b, }: null;
|
||||||
|
};
|
||||||
|
a = {
|
||||||
|
value = "1234";
|
||||||
|
b = functor;
|
||||||
|
c.d = functor;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
|
||||||
|
expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
|
||||||
|
};
|
||||||
|
|
||||||
testToPrettyMultiline = {
|
testToPrettyMultiline = {
|
||||||
expr = mapAttrs (const (generators.toPretty { })) rec {
|
expr = mapAttrs (const (generators.toPretty { })) rec {
|
||||||
list = [ 3 4 [ false ] ];
|
list = [ 3 4 [ false ] ];
|
||||||
|
Loading…
Reference in New Issue
Block a user