tvix/eval: thunk cycle detection triggers at same level

#245
Opened by tazjin at 2023-02-01T07·57+00

This is only a presentation issue, not an eval issue as such:

tvix-repl> let x = y + 2; y = 42; in [ x  x x x  ] 
=> [ 44 <CYCLE> <CYCLE> <CYCLE> ] :: list

What's going on is that TotalDisplay will find the evaluated thunk in the thunk set, and terminate the printing even though it is happening on the same level.

This is a bug. I'm not sure about the semantics yet, but we have to do something more sensible here.

  1. In the REPL, C++ Nix does something similar, but only for certain types of values (e.g. not integers):

    nix-repl> :p let x = { foo = y + 2; }; y = 42; in [ x x x x ]
    [ { foo = 44; } «repeated» «repeated» «repeated» ]
    

    I don't think that is too useful, so replicating it is probably not worth it, especially since nix-instantiate(1) doesn't exhibit it.

    sterni at 2023-06-04T13·04+00

  2. Interestingly, Nix 2.13 adopts the behavior of Nix 2.3's repl for nix-instantiate(1):

    > nix-instantiate --eval --strict -E 'let test = { a = 3; b = test; c = test; }; in test'
    { a = 3; b = { a = 3; b = <CYCLE>; c = <CYCLE>; }; c = { a = 3; b = <CYCLE>; c = <CYCLE>; }; }
    > nix repl
    Welcome to Nix version 2.3.16. Type :? for help.
    
    nix-repl> let test = { a = 3; b = test; c = test; }; in test
    { a = 3; b = { ... }; c = «repeated»; }
    > nix-shell -p nix --run "nix-instantiate --eval -E 'let test = { a = 3; b = test; c = test; }; in test'"
    { a = 3; b = «repeated»; c = «repeated»; }
    

    sterni at 2023-06-13T13·30+00

  3. No, actually the REPL behavior is a secret third kind of cycle display behavior that 2.3 and 2.13 share:

    Welcome to Nix version 2.3.16. Type :? for help.
    nix-repl> :p let test = { a = 3; b = test; c = test; }; in test
    { a = 3; b = { a = 3; b = «repeated»; c = «repeated»; }; c = «repeated»; }
    
    
    Welcome to Nix 2.13.3. Type :? for help.
    
    nix-repl> :p let test = { a = 3; b = test; c = test; }; in test
    { a = 3; b = { a = 3; b = «repeated»; c = «repeated»; }; c = «repeated»; }
    

    sterni at 2023-06-13T13·31+00

  4. Very bizarre behavior in C++ Nix 2.3 (which no longer appears in later versions I think):

    let test = { a = 42; b = test; c = test; }; in test
    # => { a = 42; b = { a = 42; b = <CYCLE>; c = <CYCLE>; }; c = { a = 42; b = <CYCLE>; c = <CYCLE>; }; }
    let test = { a = 42; b = test; c = test; }; in [test]
    # => [ { a = 42; b = <CYCLE>; c = <CYCLE>; } ]
    

    sterni at 2023-06-13T13·50+00