Infinite recursion when submodule config depends on other submodule

I’m trying to make an impermanence setup clearer but I keep getting an infinite recursion error.

options.systemd.services = lib.mkOption {
    type = lib.types.attrsOf (lib.types.submodule ( { name, config, ... }: {
        options.persist = {
            enable = lib.mkEnableOption "persist service state";
        };

        config.serviceConfig.BindPaths = lib.mkIf config.persist.enable "/var/lib/${config.serviceConfig.StateDirectory}:/persist/var/lib/${config.serviceConfig.StateDirectory}";
    }));
};

The idea is to add a submodule for each for Systemd services with an option for whether their state should be persisted. If enabled, then within that submodule, I change the service’s state directory to the persistent directory using the BindPaths option directory. But this just recurses infinitely.

If I set serviceConfig.BindPaths to an arbitrary string then it works fine, but doesn’t work when the BindPaths option refers to serviceConfig.StateDirectory.

I suppose one (ugly) work around is to create a bunch of overrides files and stick them in the Systemd directory but I’d prefer something a bit cleaner. Any hints?

I fixed this myself. For some reason which I don’t fully understand, the whole serviceConfig attribute set must be specified, i.e., this works

config = lib.mkIf (config.persist.enable) {
  serviceConfig = {
    BindPaths = [ "/persist/var/lib/${config.serviceConfig.StateDirectory}:/var/lib/${config.serviceConfig.StateDirectory}" ];
  };
};

but

config = lib.mkIf (config.persist.enable) {
  serviceConfig.BindPaths = "/persist/var/lib/${config.serviceConfig.StateDirectory}:/var/lib/${config.serviceConfig.StateDirectory}" ;
};

does not.

… really? Those should be parsed identically by nix, nevermind evaluation.

Oops. Yes you are correct: the culprit was the lack of the list for BindPaths.

Ok, that’s surprising but not nonsensical. Still, I wonder why that turns out to be relevant?