ppx_deriving
ppx_deriving copied to clipboard
type nonrec is ignored, causing an infinite loop
Hi,
I'm trying to use is with type nonrec
but it seems that this annotation is ignored.
Example:
type t = int
[@@deriving ord]
module M = struct
type nonrec t = t
[@@deriving ord]
end
let () = Printf.printf "%d\n" (M.compare 1 2)
This triggers an infinite loop instead of calling the top-level compare
function.
Thanks for this great project!
Please note that I do not have much time to maintain this library, and will not fix this bug. I can offer you assistance in writing a PR though.
Sure, I'd be interested. Any pointers would be appreciated.
@emillon Sure. First, try compiling your code using ocamlc -dsource
. This will output the preprocessed source as currently used. I think you will quickly spot why implementing type nonrec
is problematic; this messes rather badly with the hygiene mechanism. (Also try using [@@deriving]
with a let..and phrase to see the source of additional complexity.)
I think rewriting the output of ppx_deriving such that it works with type nonrec will already go a long way towards fixing this.
This issue is mentioned in Facebook's Infer Contributors Guide.
Recent versions of ppx_deriving (4.1.5 (released in November 2017) and later) show an error when nonrec
is used, so at least there is no silent production of looping code anymore.
I had a look last week and my impression is that it is not an easy problem to solve. At first it looks like just not adding the rec
keyword would make the resulting code sensible for a nonrec
type (the name of the generated function would refer to the generated function of the previous type of the same name, which is what we want), but in fact the structure of the returned code is decided by the plugins, not by the API module (which mostly provide helpers to make plugin life easier), so (1) fixing this issue would require a change in each of the plugins and (2) we have to do some API design/changes if we want to push more logic into the API module. Then I ran out of time for the day, and I stopped looking at it.
Remark: some plugins have evolved in a way that uses the recursivity of the generator for convenience; for example show
generates a show
and pp
function, the definition of show
depends on pp
, but there is no explicit sequencing of declarations as they are in a big mutually-recursive block. To stop being recursive by default, we have to break those mutual blocks in the plugins.