Excessive strictness involving // and fixpoints causing infrec

#363
Opened by raitobezarius at 2023-12-30T01·33+00

MWE:

{ pkgs ? import <nixpkgs> {}, lib ? pkgs.lib }:
let
  packages = self: 
  let 
    builtins_ = lib.mapAttrs self.build { };
in
  {
    build = pname: deps: derivation {
      name = "mwe-${pname}";
      inherit deps;
      builder = "/bin/sh";
      system = "x86_64-linux";
    };
    builtins_ = builtins_;
  } // builtins_;
in pkgs.lib.fix' packages

This will work in Nix, but not in Tvix, causes an infrec.

  1. Root cause: // builtins_ seemingly? Is it related to partial attrset construction observation?

    raitobezarius at 2023-12-30T02·02+00

  2. Nope, this is a bug in builtins.mapAttrs, namely it forcing f too early. This can be seen when replacing lib.mapAttrs (== builtins.mapAttrs) with a hand rolled version:

    { pkgs ? import <nixpkgs> {}, lib ? pkgs.lib }:
    
    let
      mapAttrs = f: attrs:
       let
        names = builtins.attrNames attrs;
        name = builtins.head names;
       in
       if builtins.length names == 0
       then { }
       else { ${name} = f name attrs.${name}; } // mapAttrs f (builtins.removeAttrs attrs [ name ]);
    
      packages = self:
      let
        builtins_ = mapAttrs self.build { };
      in
      {
        build = pname: deps: derivation {
          name = "mwe-${pname}";
          inherit deps;
          builder = "/bin/sh";
          system = "x86_64-linux";
        };
        builtins_ = builtins_;
      } // builtins_;
    in lib.fix' packages
    

    sterni at 2023-12-30T10·22+00

  3. Ah I see, that makes sense, thank you for finding about it!

    raitobezarius at 2023-12-31T01·34+00