Skip to content

Commit 5036058

Browse files
committed
Fix recursive polymorphic variants derivation
Fixes #187
1 parent 42081bc commit 5036058

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

src/ppx_deriving_qcheck/README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,22 @@ type tree = [ `Leaf of int | `Node of tree * tree ]
261261
262262
(* ==> *)
263263
264-
/!\ FIXME: https://github.com/vch9/ppx_deriving_qcheck/issues/7 /!\
264+
let gen_tree =
265+
(QCheck.Gen.sized @@ QCheck.Gen.fix (fun self -> function
266+
| 0 ->
267+
QCheck.Gen.frequency [
268+
( 1, QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int);
269+
]
270+
| n ->
271+
QCheck.Gen.frequency [
272+
( 1, QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int);
273+
( 1,
274+
QCheck.Gen.map (fun gen0 -> `Node gen0)
275+
(QCheck.Gen.map
276+
(fun (gen0, gen1) -> (gen0, gen1))
277+
(QCheck.Gen.pair (self (n / 2)) (self (n / 2)))))
278+
])
279+
: tree QCheck.Gen.t)
265280
```
266281

267282
## Mutual recursive types

src/ppx_deriving_qcheck/ppx_deriving_qcheck.ml

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ let rec longident_to_str = function
4444
| Lapply (lg1, lg2) ->
4545
Printf.sprintf "%s %s" (longident_to_str lg1) (longident_to_str lg2)
4646

47+
let rec is_rec_typ typ_name = function
48+
| { ptyp_desc = Ptyp_constr ({ txt = x; _ }, _); _ } ->
49+
longident_to_str x = typ_name
50+
| { ptyp_desc = Ptyp_tuple xs; _ } -> List.exists (is_rec_typ typ_name) xs
51+
| _ -> false
52+
4753
let name s =
4854
let prefix = "gen" in
4955
match s with "t" -> prefix | s -> prefix ^ "_" ^ s
@@ -309,13 +315,7 @@ and gen_from_variant ~loc typ_name rws =
309315
let is_rec (row : row_field) : bool =
310316
match row.prf_desc with
311317
| Rinherit _ -> false
312-
| Rtag (_, _, typs) ->
313-
List.exists
314-
(function
315-
| { ptyp_desc = Ptyp_constr ({ txt = x; _ }, _); _ } ->
316-
longident_to_str x = typ_name
317-
| _ -> false)
318-
typs
318+
| Rtag (_, _, typs) -> List.exists (is_rec_typ typ_name) typs
319319
in
320320
let to_gen ?env (row : row_field) : expression =
321321
let w =
@@ -386,12 +386,6 @@ and gen_from_arrow ~loc ~env left right =
386386
QCheck.fun_nary QCheck.Tuple.([%e observable left] @-> [%e obs]) [%e arb]
387387
|> QCheck.gen]
388388
389-
let rec is_rec_typ typ_name = function
390-
| { ptyp_desc = Ptyp_constr ({ txt = x; _ }, _); _ } ->
391-
longident_to_str x = typ_name
392-
| { ptyp_desc = Ptyp_tuple xs; _ } -> List.exists (is_rec_typ typ_name) xs
393-
| _ -> false
394-
395389
let gen_from_kind_variant ~loc ~env typ_name xs =
396390
let (module A) = Ast_builder.make loc in
397391
let is_rec (constr : constructor_declaration) : bool =

test/ppx_deriving_qcheck/deriver/test.ml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,43 @@ let test_weight_konstrs () =
792792
in
793793
check_eq ~expected ~actual "deriving weight konstrs"
794794

795+
(* Regression test: https://github.com/c-cube/qcheck/issues/187 *)
796+
let test_recursive_poly_variant () =
797+
let expected =
798+
[
799+
[%stri
800+
let gen_tree =
801+
(QCheck.Gen.sized
802+
@@ QCheck.Gen.fix (fun self -> function
803+
| 0 ->
804+
QCheck.Gen.frequency
805+
[
806+
( 1,
807+
QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int
808+
);
809+
]
810+
| n ->
811+
QCheck.Gen.frequency
812+
[
813+
( 1,
814+
QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int
815+
);
816+
( 1,
817+
QCheck.Gen.map
818+
(fun gen0 -> `Node gen0)
819+
(QCheck.Gen.map
820+
(fun (gen0, gen1) -> (gen0, gen1))
821+
(QCheck.Gen.pair (self (n / 2)) (self (n / 2))))
822+
);
823+
])
824+
: tree QCheck.Gen.t)];
825+
]
826+
in
827+
let actual =
828+
f @@ extract [%stri type tree = [ `Leaf of int | `Node of tree * tree ]]
829+
in
830+
check_eq ~expected ~actual "deriving recursive polymorphic variants"
831+
795832
let () =
796833
Alcotest.(
797834
run
@@ -830,5 +867,9 @@ let () =
830867
test_case "deriving fun list" `Quick test_fun_list;
831868
test_case "deriving fun n" `Quick test_fun_n;
832869
test_case "deriving fun tuple" `Quick test_fun_tuple;
870+
test_case
871+
"deriving rec poly variants"
872+
`Quick
873+
test_recursive_poly_variant;
833874
] );
834875
])

0 commit comments

Comments
 (0)