ppx_deriving_qcheck cannot derive a generator from a recursive type declaration with containers
Minimal reproducible example:
type t = Box of t list [@@deriving qcheck]
ppx_deriving_qcheck produces the following generator with unbound gen:
let gen = QCheck.Gen.map (fun gen0 -> Box gen0) (QCheck.Gen.list gen)
This trick (given -rectypes is enabled) make it derive the following generator:
type 'a open_t = Box of 'a list
and t = t open_t
[@@deriving qcheck]
let rec gen_open_t gen_a =
QCheck.Gen.map (fun gen0 -> Box gen0) (QCheck.Gen.list gen_a)
and gen_sized n = gen_open_t (gen_sized (n / 2))
let gen = QCheck.Gen.sized gen_sized
However, this generatior is non-terminating.
Thanks for the report!
Ping @vch9 - I think we are not handling type constructors correctly in is_rec_typ
Thanks for the report again.
Definitely a problem in is_rec_type, t should not be considered recursive (in the latter). I will try to have a look
I think the deriver fails on a very much simpler example: type t = t list. I did not consider the rectypes flag as I just discovered it :sweat_smile:.
It creates:
let gen = QCheck.Gen.list gen
let arb = QCheck.make @@ gen
Should we be smarter than:
let rec gen = QCheck.Gen.list gen
let arb = QCheck.make @@ gen
?
IMO using rectypes is a cornercase that we don't necessarily have to support (I read the report as trying to use it as a workaround).
I suggest prioritising the reported case type t = Box of t list of "vanilla OCaml usage" where it seems we don't identify an occurrence of t as recursive when it is a type parameter to a type constructor such as list (or option or result ...) :thinking:
In trying out a potential workaround I just experienced the following error variant:
utop # #require "ppx_deriving";;
utop # #require "ppx_deriving_qcheck";;
utop # type t = Box of foo
and foo = t list [@@deriving qcheck];;
Error: Unbound value n