Record element types must have a representable layout

I set up a bunch of recursive modules, some of which have records inside.

I’m getting a weird error, though.

File "src/lib/ir.ml", lines 61-62, characters 6-5:
61 | ......map : Register_map.t
62 |     ;................
Error: Record element types must have a representable layout.
       The layout of Register_map.t is any.
       But the layout of Register_map.t must be representable
         because it is the type of record field map.

Eyeballing the types below, it’s clear to me what the layout of Register_map.t is because Register.t is already defined at that point.

Why does the compiler think otherwise?

and Register : sig
  type t =
    { id : id
    ; size : int
    }
  [@@deriving sexp]
end =
  Register

and Register_map : sig
  type t = Register.t option array [@@deriving sexp]
end =
  Register_map

and Register_index : sig
  type t =
    { id : id
    ; map : Register_map.t
    ; map_index : int
    ; bit_field : Bit_field.t
    }
  [@@deriving sexp]
end =
  Register_index

Note for the curious: this is an OxCaml-specific error (OxCaml allows to define types whose layout is not the uniform layout of regular values, but this comes with restrictions on where these types can be used).

I’m not completely sure of what is going on (the typing of recursive modules is a notoriously complex problem), but I suspect that the signature of Register_index is checked under an approximated environment, where it only knows that Register_map.t exists but not its actual representation. The error then complains that because the representation is not known, the layout isn’t either, so it cannot be used as a record field.

If you don’t actually need the recursion, I would advise against using recursive modules (not only in OxCaml, but in OCaml in general). In this case you can at least switch to individual recursive definitions instead of mutually recursive ones.

I’m using OxCaml to see source code in lldb on macOS. Unfortunately, stock OCaml has no DWARF debug info on the Mac.

The modules do need to be recursive because I’m trying to derive sexps for GADTs by hand and types then start to depend on one another.

This is my compiler’s AST and these things tend to be recursive.

I guess I’ll have to give up source code in lldb for the sake of getting the job done with the stock OCaml compiler.

Testing locally, I was able to reproduce this error, and adding a kind annotation to the type that was complained about fixed it. So in your example, try changing Register_map like this:

and Register_map : sig
  type t : value = Register.t option array [@@deriving sexp]
end

(It’s possible this won’t work, because I don’t have your complete example, but I’d be curious to have a look if not).

Another thing worth noting is that, at least in my small reproduction case, the problem goes away without the [@@deriving sexp]. I haven’t dug in to the generated code yet to see what’s going on in there.

As @vlaviron says, typechecking for recursive types and recursive modules is pretty tricky, and right now OxCaml will require kind annotations in a few cases where it seems like the compiler should be able to work it out.

Thanks for trying out OxCaml!

Ah, after a little more investigation, I’m pretty sure this is the result of a bug that we just found very recently (credit to Ryan Tjoa for tracking it down). He made a PR to fix it on the OxCaml repository, and the fix should make its way into the next release of OxCaml.

This turns out to be a bug that is also present in typechecking of recursive modules in upstream OCaml (it’s just a little harder to hit without OxCaml’s layouts), so we’ll also be making a bug fix upstream soon.

I don’t see hit this bug when compiling with 5.3.

It does work if I change the signature of Register_map as suggested.