Problems with types.oneOf and submodules

I just had the same issue and found this post. After a couple hours of digging through the sources of types.nix I think I understand what’s happening. There’s two pertinent points where it goes wrong.

First the merge function of either / oneOf at

merge = loc: defs:
  let
    defList = map (d: d.value) defs;
  in
  if all (x: t1.check x) defList
  then t1.merge loc defs
  else if all (x: t2.check x) defList
  then t2.merge loc defs
  else mergeOneOption loc defs;

It checks whether all defs that are to be merged are either of the left type (t1) or the right type (t2). This makes sense since if we’re merging we only want to have one side of the either, presumably else the merging is probably not well defined.

Now if submodules come into play inside the either we’ll have to look at how those do check at:

check = x: isAttrs x || isFunction x || path.check x;

This is where it breaks all appart if both your type parameters to either are submodules because isAttrs is going to be true thus the merge in either will always think it’s the left type parameter (t1).

I hacked together a solution that seems to work so far but I only just got done so I don’t know yet if it’s just gonna break other things but here it is: A hacky fix for the either submodule problem · GitHub

3 Likes