• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Kakadu / zanuda / 42

19 Oct 2025 08:44PM UTC coverage: 86.206% (-0.3%) from 86.475%
42

push

github

Kakadu
[lint] Better List.map detection

Now we should detect List.map specialized for concrete ~f

Signed-off-by: Kakadu <Kakadu@pm.me>

16 of 21 new or added lines in 1 file covered. (76.19%)

82 existing lines in 1 file now uncovered.

2231 of 2588 relevant lines covered (86.21%)

531.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.49
/src/pattern/Tast_pattern.ml
1
[@@@ocaml.text "/*"]
2

3
(** Copyright 2021-2025, Kakadu. *)
4

5
(** SPDX-License-Identifier: LGPL-3.0-or-later *)
6

7
[@@@ocaml.text "/*"]
8

9
module Ast_pattern0 = struct
10
  exception Expected of Location.t * string
11

12
  let fail loc expected = raise (Expected (loc, expected))
71,628✔
13

14
  type context =
15
    { (* [matched] counts how many constructors have been matched. This is used to find what
16
         pattern matches the most some piece of ast in [Ast_pattern.alt]. In the case where
17
         all branches fail to match, we report the error from the one that matches the
18
         most.
19
         This is only incremented by combinators that can fail. *)
20
      mutable matched : int
21
    }
22

23
  type ('matched_value, 'k, 'k_result) t =
24
    | T of (context -> Location.t -> 'matched_value -> 'k -> 'k_result)
25

26
  (* end of copy-paste from https://github.com/ocaml-ppx/ppxlib/blob/0.22.2/src/ast_pattern0.ml *)
27
  (* TODO: deal with licencing issues *)
28
end
29

30
open Location
31
open Format
32
open Ast_pattern0
33

34
let debug_enabled = false
35

36
let log fmt =
37
  let open Format in
1,244✔
38
  if debug_enabled then kasprintf (printf "%s\n%!") fmt else ifprintf std_formatter fmt
×
39
;;
40

41
type ('a, 'b, 'c) t = ('a, 'b, 'c) Ast_pattern0.t
42

43
let save_context ctx = ctx.matched
126,072✔
44
let restore_context ctx backup = ctx.matched <- backup
82,900✔
45
let incr_matched c = c.matched <- c.matched + 1
4,201✔
46

47
let parse (T f) loc ?on_error x k =
48
  try f { matched = 0 } loc x k with
1,619✔
49
  | Expected (loc, expected) ->
29,629✔
50
    (match on_error with
51
     | None -> Location.raise_errorf ~loc "%s expected" expected
×
52
     | Some f -> f expected)
29,629✔
53
;;
54

55
module Packed = struct
56
  type ('a, 'b) t = T : ('a, 'b, 'c) Ast_pattern0.t * 'b -> ('a, 'c) t
57

58
  let create t f = T (t, f)
×
59
  let parse (T (t, f)) loc x = parse t loc x f
×
60
end
61

62
let __ : 'a 'b. ('a, 'a -> 'b, 'b) t =
63
  T
64
    (fun ctx _loc x k ->
65
      incr_matched ctx;
2,891✔
66
      k x)
2,891✔
67
;;
68

69
let as__ : 'a 'b 'c. ('a, 'b, 'c) t -> ('a, 'a -> 'b, 'c) t =
70
  fun (T f1) ->
71
  T
3,706✔
72
    (fun ctx loc x k ->
73
      let k = f1 ctx loc x (k x) in
264✔
74
      k)
122✔
75
;;
76

77
let pair (T f1) (T f2) =
78
  T
9,614✔
79
    (fun ctx loc (x1, x2) k ->
80
      let k = f1 ctx loc x1 k in
412✔
81
      let k = f2 ctx loc x2 k in
393✔
82
      k)
264✔
83
;;
84

85
let ( ** ) = pair
86

87
let __' =
88
  T
89
    (fun ctx loc x k ->
90
      incr_matched ctx;
21✔
91
      k { loc; txt = x })
21✔
92
;;
93

94
let drop : 'a 'b. ('a, 'b, 'b) t =
95
  T
96
    (fun ctx _loc _ k ->
97
      incr_matched ctx;
1,230✔
98
      k)
1,230✔
99
;;
100

101
let ( +?? ) (T fargs) msg =
UNCOV
102
  T
×
103
    (fun ctx loc e k ->
UNCOV
104
      try fargs ctx loc e k with
×
UNCOV
105
      | Ast_pattern0.Expected (loc, _) -> fail loc msg)
×
106
;;
107

108
let cst ~to_string ?(equal = Stdlib.( = )) v =
5,525✔
109
  T
5,525✔
110
    (fun ctx loc x k ->
111
      if equal x v
146✔
112
      then (
59✔
113
        incr_matched ctx;
114
        (* printf "cst succeeded for %s\n%!" (to_string v); *)
115
        k)
59✔
116
      else fail loc (to_string v))
87✔
117
;;
118

119
let int v = cst ~to_string:Int.to_string v
490✔
UNCOV
120
let char v = cst ~to_string:(Printf.sprintf "%C") v
×
121
let string v = cst ~to_string:(Printf.sprintf "%S") v
5,035✔
UNCOV
122
let float v = cst ~to_string:Float.to_string v
×
UNCOV
123
let int32 v = cst ~to_string:Int32.to_string v
×
124
let int64 v = cst ~to_string:Int64.to_string v
×
125
let nativeint v = cst ~to_string:Nativeint.to_string v
×
UNCOV
126
let bool v = cst ~to_string:Bool.to_string v
×
127

128
let false_ =
129
  T
130
    (fun ctx loc x k ->
UNCOV
131
      match x with
×
UNCOV
132
      | false ->
×
133
        ctx.matched <- ctx.matched + 1;
134
        k
135
      | _ -> fail loc "false")
×
136
;;
137

138
let true_ =
139
  T
140
    (fun ctx loc x k ->
UNCOV
141
      match x with
×
UNCOV
142
      | true ->
×
143
        ctx.matched <- ctx.matched + 1;
144
        k
UNCOV
145
      | _ -> fail loc "true")
×
146
;;
147

148
let nil =
149
  T
150
    (fun ctx loc x k ->
151
      log "trying [] \n%!";
441✔
152
      match x with
441✔
153
      | [] ->
339✔
154
        ctx.matched <- ctx.matched + 1;
155
        k
156
      | _ -> fail loc "[]")
102✔
157
;;
158

159
let ( ^:: ) (T f0) (T f1) =
160
  T
23,050✔
161
    (fun ctx loc x k ->
162
      match x with
694✔
163
      | x0 :: x1 ->
640✔
164
        ctx.matched <- ctx.matched + 1;
165
        (* Format.printf "trying elem of cons cell\n%!"; *)
166
        let k = f0 ctx loc x0 k in
167
        (* Format.printf "trying tail of cons cell\n%!"; *)
168
        let k = f1 ctx loc x1 k in
532✔
169
        (* Format.printf "trying  cons cell succeeded\n%!"; *)
170
        k
383✔
171
      | _ ->
54✔
172
        (* Format.printf "failing elem of cons cell\n%!"; *)
173
        fail loc "::")
174
;;
175

176
let list (T fel) =
177
  let rec helper acc ctx loc xs k =
2✔
178
    match xs with
6✔
179
    | [] -> k (List.rev acc)
2✔
180
    | h :: tl ->
4✔
181
      (match fel ctx loc h Fun.id with
182
       | x -> helper (x :: acc) ctx loc tl k)
4✔
183
  in
184
  T (fun ctx loc xs k -> helper [] ctx loc xs k)
2✔
185
;;
186

187
let none =
188
  T
189
    (fun ctx loc x k ->
190
      match x with
76✔
191
      | None ->
76✔
192
        ctx.matched <- ctx.matched + 1;
193
        k
UNCOV
194
      | _ -> fail loc "None")
×
195
;;
196

197
let some (T f0) =
198
  T
8,406✔
199
    (fun ctx loc x k ->
200
      match x with
156✔
201
      | Some x0 ->
156✔
202
        ctx.matched <- ctx.matched + 1;
203
        let k = f0 ctx loc x0 k in
204
        k
73✔
205
      | _ -> fail loc "Some")
×
206
;;
207

208
let triple (T f1) (T f2) (T f3) =
UNCOV
209
  T
×
210
    (fun ctx loc (x1, x2, x3) k ->
UNCOV
211
      let k = f1 ctx loc x1 k in
×
UNCOV
212
      let k = f2 ctx loc x2 k in
×
UNCOV
213
      let k = f3 ctx loc x3 k in
×
UNCOV
214
      k)
×
215
;;
216

217
let alt (T f1) (T f2) =
218
  T
12,753✔
219
    (fun ctx loc x k ->
220
      let backup = save_context ctx in
42,833✔
221
      try f1 ctx loc x k with
834✔
222
      | e1 ->
41,999✔
223
        let m1 = save_context ctx in
224
        restore_context ctx backup;
41,999✔
225
        (try f2 ctx loc x k with
759✔
226
         | e2 ->
41,240✔
227
           let m2 = save_context ctx in
228
           if m1 >= m2
41,240✔
229
           then (
40,901✔
230
             restore_context ctx m1;
231
             raise e1)
40,901✔
232
           else raise e2))
339✔
233
;;
234

235
let ( ||| ) = alt
236

237
let conde = function
UNCOV
238
  | [] -> fail Location.none "Bad argument"
×
239
  | h :: tl -> List.fold_left ( ||| ) h tl
27✔
240
;;
241

UNCOV
242
let map (T func) ~f = T (fun ctx loc x k -> func ctx loc x (f k))
×
UNCOV
243
let map' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (f loc k))
×
UNCOV
244
let map_result (T func) ~f = T (fun ctx loc x k -> f (func ctx loc x k))
×
UNCOV
245
let ( >>| ) t f = map t ~f
×
246
let map0 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (k f))
348✔
247
let map1 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a -> k (f a)))
607✔
248
let map2 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b -> k (f a b)))
373✔
249
let map3 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b c -> k (f a b c)))
58✔
250

251
let map4 (T func) ~f =
252
  T (fun ctx loc x k -> func ctx loc x (fun a b c d -> k (f a b c d)))
11✔
253
;;
254

255
let map5 (T func) ~f =
256
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e -> k (f a b c d e)))
22✔
257
;;
258

259
let map6 (T func) ~f:fmap =
260
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e f -> k (fmap a b c d e f)))
1✔
261
;;
262

263
let map7 (T func) ~f:fmap =
264
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e f g -> k (fmap a b c d e f g)))
3✔
265
;;
266

267
let map0' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (k (f loc)))
×
UNCOV
268
let map1' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a -> k (f loc a)))
×
UNCOV
269
let map2' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b -> k (f loc a b)))
×
UNCOV
270
let map_result (T func) ~f = T (fun ctx loc x k -> f (func ctx loc x k))
×
UNCOV
271
let alt_option some none = alt (map1 some ~f:(fun x -> Some x)) (map0 none ~f:None)
×
272

273
let many (T f) =
UNCOV
274
  T (fun ctx loc l k -> k (ListLabels.map l ~f:(fun x -> f ctx loc x (fun x -> x))))
×
275
;;
276

UNCOV
277
let loc (T f) = T (fun ctx _loc (x : _ Ppxlib.Loc.t) k -> f ctx x.loc x.txt k)
×
UNCOV
278
let pack0 t = map t ~f:(fun f -> f ())
×
UNCOV
279
let pack2 t = map t ~f:(fun f x y -> f (x, y))
×
UNCOV
280
let pack3 t = map t ~f:(fun f x y z -> f (x, y, z))
×
281

282
(* end of copy-paste from https://github.com/ocaml-ppx/ppxlib/blob/0.22.2/src/ast_pattern.ml *)
283
(* TODO: deal with licencing issues *)
284

285
let lident (T fident) =
286
  T
603✔
287
    (fun ctx loc x k ->
288
      match x with
145✔
289
      | Longident.Lident id ->
135✔
290
        ctx.matched <- ctx.matched + 1;
291
        k |> fident ctx loc id
292
      | _ -> fail loc "lident")
10✔
293
;;
294

295
let elongident (lident : Longident.t) =
296
  T
59✔
297
    (fun ctx loc x k ->
298
      if Stdlib.compare x lident = 0
183✔
299
      then (
15✔
300
        ctx.matched <- ctx.matched + 1;
301
        k)
302
      else fail loc "elongident")
168✔
303
;;
304

305
let path_pident (T fident) =
306
  T
2✔
307
    (fun ctx loc x k ->
308
      match x with
2✔
309
      | Path.Pident id ->
1✔
310
        ctx.matched <- ctx.matched + 1;
311
        k |> fident ctx loc id
312
      | _ -> fail loc "path_pident")
1✔
313
;;
314

315
let path xs =
316
  let rec helper ps ctx loc x k =
5,919✔
317
    let cmp_names l r =
13,894✔
318
      let ans = String.equal l r in
7,365✔
319
      (* printf "\t\tCompare names %s and %s:  %b\n%!" l r ans; *)
320
      ans
7,365✔
321
    in
322
    match x, ps with
323
    | Path.Pident id, [ id0 ] ->
118✔
324
      if cmp_names (Ident.name id) id0
118✔
325
      then (
111✔
326
        let () = ctx.matched <- ctx.matched + 1 in
327
        k)
328
      else fail loc "path"
7✔
329
    | Path.Pdot (next, id), id0 :: ids when cmp_names id id0 -> helper ids ctx loc next k
156✔
UNCOV
330
    | Path.Papply _, _ -> fail loc "path got Papply"
×
331
    | _ -> fail loc (sprintf "path %s" (String.concat "." xs))
13,620✔
332
  in
333
  T (helper (List.rev xs))
5,919✔
334
;;
335

336
let path_of_list = function
337
  | [] -> failwith "Bad argument: path_of_list"
1✔
338
  | s :: tl ->
2✔
339
    ListLabels.fold_left
340
      tl
341
      ~init:(Path.Pident (Ident.create_local s))
2✔
342
      ~f:(fun acc x -> Path.Pdot (acc, x))
4✔
343
;;
344

345
let%test_module " " =
346
  (module struct
347
    [@@@coverage off]
348

349
    let names = [ "Stdlib!"; "List"; "length" ]
350

351
    [%%if ocaml_version < (5, 0, 0)]
352

353
    let pp_path = Path.print
354

355
    [%%else]
356

357
    let pp_path = Format_doc.compat Path.print
358

359
    [%%endif]
360

361
    let%test_unit _ =
362
      let old = !Clflags.unique_ids in
363
      Clflags.unique_ids := false;
364
      [%test_eq: Base.string]
365
        "Stdlib!.List.length"
366
        (asprintf "%a" pp_path (path_of_list names));
367
      Clflags.unique_ids := old
368
    ;;
369

370
    let%test _ =
371
      let noloc =
372
        Warnings.
373
          { loc_start = Lexing.dummy_pos; loc_end = Lexing.dummy_pos; loc_ghost = true }
374
      in
375
      parse (path names) noloc ~on_error:(fun _ -> false) (path_of_list names) true
376
    ;;
377
  end)
378
;;
379

380
open Typedtree
381

382
let econst (T f0) =
383
  T
2✔
384
    (fun ctx loc x k ->
385
      match x.exp_desc with
2✔
386
      | Texp_constant n ->
2✔
387
        ctx.matched <- ctx.matched + 1;
388
        f0 ctx loc n k
UNCOV
389
      | _ -> fail loc (sprintf "econst"))
×
390
;;
391

392
let eint (T f0) =
393
  T
490✔
394
    (fun ctx loc x k ->
395
      match x.exp_desc with
17✔
396
      | Texp_constant (Asttypes.Const_int n) ->
8✔
397
        ctx.matched <- ctx.matched + 1;
398
        f0 ctx loc n k
399
      | _ -> fail loc "eint")
9✔
400
;;
401

402
let estring =
403
  T
404
    (fun ctx loc x k ->
405
      match x.exp_desc with
15✔
406
      | Texp_constant (Asttypes.Const_string (s, _, None)) ->
15✔
407
        ctx.matched <- ctx.matched + 1;
408
        k s
UNCOV
409
      | _ -> fail loc "estring")
×
410
;;
411

412
let ebool =
413
  T
414
    (fun ctx loc x k ->
415
      match x.exp_desc with
95✔
416
      | Texp_construct ({ txt = Lident "true" }, _, []) ->
11✔
417
        ctx.matched <- ctx.matched + 1;
418
        k true
419
      | Texp_construct ({ txt = Lident "false" }, _, []) ->
8✔
420
        ctx.matched <- ctx.matched + 1;
421
        k false
422
      | _ -> fail loc (sprintf "ebool"))
76✔
423
;;
424

425
[%%if ocaml_version < (5, 0, 0)]
426

427
let tpat_var (T fname) =
428
  T
1,549✔
429
    (fun ctx loc x k ->
430
      match x.pat_desc with
53✔
431
      | Tpat_var (_, { txt }) ->
53✔
432
        ctx.matched <- ctx.matched + 1;
433
        k |> fname ctx loc txt
UNCOV
434
      | _ -> fail loc "tpat_var")
×
435
;;
436

437
let tpat_id (T fname) =
438
  T
1,984✔
439
    (fun ctx loc x k ->
440
      match x.pat_desc with
348✔
441
      | Tpat_var (id, { loc }) ->
286✔
442
        ctx.matched <- ctx.matched + 1;
443
        k |> fname ctx loc id
444
      | _ -> fail loc "tpat_var_id")
62✔
445
;;
446

447
[%%else]
448

449
let tpat_var (T fname) =
450
  T
451
    (fun (type kind) ctx loc (x : kind pattern_desc pattern_data) k ->
452
      match x.pat_desc with
453
      | Tpat_var (_, { txt }, _uid) ->
454
        ctx.matched <- ctx.matched + 1;
455
        k |> fname ctx loc txt
456
      | Tpat_value v ->
457
        (match (v :> pattern).pat_desc with
458
         | Tpat_var (_, { txt }, _uid) ->
459
           ctx.matched <- ctx.matched + 1;
460
           k |> fname ctx loc txt
461
         | _ -> fail loc "tpat_var")
462
      | _ -> fail loc "tpat_var")
463
;;
464

465
let tpat_id (T fname) =
466
  T
467
    (fun (type kind) ctx loc (x : kind pattern_desc pattern_data) k ->
468
      match x.pat_desc with
469
      | Typedtree.Tpat_value v ->
470
        (match (v :> pattern).pat_desc with
471
         | Tpat_var (id, { loc }, _uid) ->
472
           ctx.matched <- ctx.matched + 1;
473
           k |> fname ctx loc id
474
         | _ -> fail loc "tpat_id")
475
      | Tpat_var (id, { loc }, _uid) ->
476
        ctx.matched <- ctx.matched + 1;
477
        k |> fname ctx loc id
478
      | _ -> fail loc "tpat_id 2")
479
;;
480

481
[%%endif]
482

483
let tpat_constructor (T fname) (T fargs) =
484
  T
5,920✔
485
    (fun ctx loc x k ->
486
      match x.pat_desc with
93✔
487
      | Tpat_construct ({ txt }, _, args, _) ->
80✔
488
        ctx.matched <- ctx.matched + 1;
489
        k |> fname ctx loc txt |> fargs ctx loc args
70✔
490
      | _ -> fail loc "tpat_constructor")
13✔
491
;;
492

493
let tpat_tuple (T fargs) =
494
  T
×
495
    (fun ctx loc x k ->
UNCOV
496
      match x.pat_desc with
×
UNCOV
497
      | Tpat_tuple pats ->
×
498
        ctx.matched <- ctx.matched + 1;
499
        k |> fargs ctx loc pats
UNCOV
500
      | _ -> fail loc "tpat_tuple")
×
501
;;
502

503
let tpat_value (T fpat) =
504
  T
×
505
    (fun ctx loc x k ->
UNCOV
506
      match x.pat_desc with
×
UNCOV
507
      | Tpat_value arg ->
×
508
        let inner = (arg :> value pattern_desc pattern_data) in
509
        ctx.matched <- ctx.matched + 1;
510
        k |> fpat ctx loc inner
UNCOV
511
      | _ -> fail loc "tpat_value")
×
512
;;
513

514
let tpat_exception (T fpat) =
UNCOV
515
  T
×
516
    (fun ctx loc x k ->
UNCOV
517
      match x.pat_desc with
×
UNCOV
518
      | Tpat_exception exc ->
×
519
        ctx.matched <- ctx.matched + 1;
520
        k |> fpat ctx loc exc
UNCOV
521
      | _ -> fail loc "tpat_exception")
×
522
;;
523

524
let tpat_any =
525
  T
526
    (fun ctx loc x k ->
527
      match x.pat_desc with
3✔
528
      | Tpat_any ->
2✔
529
        ctx.matched <- ctx.matched + 1;
530
        k
531
      | _ -> fail loc "tpat_any")
1✔
532
;;
533

534
let texp_ident (T fpath) =
535
  T
15,115✔
536
    (fun ctx loc x k ->
UNCOV
537
      let __ _ = log "texp_ident %a\n%!" My_printtyped.expr x in
×
538
      match x.exp_desc with
539
      | Texp_ident (path, _, _) ->
12,119✔
540
        ctx.matched <- ctx.matched + 1;
541
        let ans = fpath ctx loc path k in
542
        log "texp_ident + %a\n%!" My_printtyped.expr x;
803✔
543
        ans
803✔
544
      | _ -> fail loc "texp_ident")
3,159✔
545
;;
546

547
let texp_ident_loc (T fpath) =
548
  T
1,275✔
549
    (fun ctx loc x k ->
550
      match x.exp_desc with
15✔
551
      | Texp_ident (path, _, _) ->
10✔
552
        ctx.matched <- ctx.matched + 1;
553
        k x.exp_loc |> fpath ctx loc path
10✔
554
      | _ -> fail loc "texp_ident")
5✔
555
;;
556

557
(* TODO(Kakadu): accept and Ident, and not a string *)
558
let pident (T fstr) =
559
  T
7,583✔
560
    (fun ctx loc x k ->
561
      match x with
218✔
562
      | Path.Pident id -> fstr ctx loc (Ident.name id) k
95✔
563
      | _ -> fail loc "pident")
123✔
564
;;
565

566
let texp_ident_typ (T fpath) (T ftyp) =
567
  T
294✔
568
    (fun ctx loc x k ->
569
      (* let __ _ = Format.printf "texp_ident_typ %a\n%!" MyPrinttyped.expr x in *)
570
      match x.exp_desc with
1,639✔
571
      | Texp_ident (path, _, typ) ->
855✔
572
        ctx.matched <- ctx.matched + 1;
573
        k |> fpath ctx loc path |> ftyp ctx loc typ.Types.val_type
449✔
574
      | _ -> fail loc "texp_ident_typ")
784✔
575
;;
576

577
[%%if ocaml_version < (5, 0, 0)]
578

579
let texp_assert (T fexp) =
580
  T
59✔
581
    (fun ctx loc x k ->
582
      match x.exp_desc with
1,485✔
583
      | Texp_assert e ->
1✔
584
        ctx.matched <- ctx.matched + 1;
585
        fexp ctx loc e k
586
      | _ -> fail loc "texp_assert")
1,484✔
587
;;
588

589
[%%else]
590

591
let texp_assert (T fexp) =
592
  T
593
    (fun ctx loc x k ->
594
       match x.exp_desc with
595
       | Texp_assert (e, _) ->
596
         ctx.matched <- ctx.matched + 1;
597
         fexp ctx loc e k
598
       | _ -> fail loc "texp_assert"
599
     : context -> Warnings.loc -> expression -> 'a -> 'b)
600
;;
601

602
[%%endif]
603

604
let texp_apply (T f0) (T args0) =
605
  T
6,120✔
606
    (fun ctx loc x k ->
607
      (* let __ _ = log "texp_apply %a\n%!" MyPrinttyped.expr x in *)
608
      match x.exp_desc with
26,188✔
609
      | Texp_apply (f, args) ->
3,710✔
610
        ctx.matched <- ctx.matched + 1;
611
        let ans = k |> f0 ctx loc f |> args0 ctx loc args in
73✔
612
        (* let _ = log "texp_apply + %a\n%!" MyPrinttyped.expr x in *)
613
        ans
43✔
614
      | _ -> fail loc "texp_apply")
22,478✔
615
;;
616

617
let texp_apply_nolabelled (T f0) (T args0) =
618
  let exception EarlyExit in
1,578✔
619
  T
620
    (fun ctx loc x k ->
621
      match x.exp_desc with
3,144✔
622
      | Texp_apply (f, args) ->
500✔
623
        ctx.matched <- ctx.matched + 1;
624
        let k = f0 ctx loc f k in
625
        (try
100✔
626
           let args =
627
             ListLabels.map args ~f:(function
UNCOV
628
               | Asttypes.Labelled _, _ | Asttypes.Optional _, _ | _, None ->
×
629
                 raise EarlyExit
630
               | _, Some x -> x)
213✔
631
           in
632
           args0 ctx loc args k
25✔
633
         with
634
         | EarlyExit -> fail loc "texp_apply: None among the arguments ")
2✔
635
      | _ -> fail loc "texp_apply")
2,644✔
636
;;
637

638
let texp_construct (T fpath) (T fcd) (T fargs) =
639
  T
226✔
640
    (fun ctx loc x k ->
641
      match x.exp_desc with
1,513✔
642
      | Texp_construct (path, cd, args) ->
196✔
643
        ctx.matched <- ctx.matched + 1;
644
        let k = fpath ctx loc path.txt k in
645
        k |> fcd ctx loc cd |> fargs ctx loc args
28✔
646
      | _ -> fail loc (sprintf "texp_construct"))
1,317✔
647
;;
648

649
let texp_assert_false () = texp_assert (texp_construct (lident (string "false")) drop nil)
59✔
650

651
let texp_let (T fvbs) (T fexpr) =
652
  T
1,498✔
653
    (fun ctx loc x k ->
654
      match x.exp_desc with
1,291✔
655
      | Texp_let (_flg, vbs, expr) ->
18✔
656
        ctx.matched <- ctx.matched + 1;
657
        k |> fvbs ctx loc vbs |> fexpr ctx loc expr
15✔
658
      | _ -> fail loc (sprintf "texp_let"))
1,273✔
659
;;
660

661
let nolabel =
662
  T
663
    (fun ctx loc x k ->
664
      match x with
257✔
665
      | Asttypes.Nolabel ->
238✔
666
        ctx.matched <- ctx.matched + 1;
667
        k
668
      | _ -> fail loc "nolabel")
19✔
669
;;
670

671
let labelled (T fstr) =
672
  T
60✔
673
    (fun ctx loc x k ->
674
      match x with
3✔
675
      | Asttypes.Labelled s ->
2✔
676
        ctx.matched <- ctx.matched + 1;
677
        k |> fstr ctx loc s
678
      | _ -> fail loc "labelled")
1✔
679
;;
680

681
let texp_apply1 f x = texp_apply f ((nolabel ** some x) ^:: nil)
3,480✔
682
let texp_apply2 f x y = texp_apply f ((nolabel ** some x) ^:: (nolabel ** some y) ^:: nil)
2,227✔
683

684
[%%if ocaml_version < (4, 11, 2)]
685

686
(* 4.10 *)
687
type case_val = Typedtree.case
688
type case_comp = Typedtree.case
689
type value_pat = pattern
690
type comp_pat = pattern
691

692
[%%else]
693

694
type case_val = value case
695
type case_comp = computation case
696
type value_pat = value pattern_desc pattern_data
697
type comp_pat = computation pattern_desc pattern_data
698

699
[%%endif]
700
[%%if ocaml_version < (5, 0, 0)]
701

702
let texp_function (T fcases) =
UNCOV
703
  T
×
704
    (fun ctx loc e k ->
UNCOV
705
      match e.exp_desc with
×
UNCOV
706
      | Texp_function { cases } ->
×
707
        ctx.matched <- ctx.matched + 1;
708
        k |> fcases ctx loc cases
UNCOV
709
      | _ -> fail loc "texp_function")
×
710
;;
711

712
let texp_function_body (T fargs) (T frhs) =
713
  let rec helper acc ctx loc e k =
6,936✔
714
    match e.exp_desc with
6,429✔
715
    | Texp_function
989✔
716
        { cases =
717
            [ { c_lhs = { pat_desc = Tpat_var (pid, _); pat_loc; _ }
718
              ; c_rhs
719
              ; c_guard = None
720
              }
721
            ]
722
        ; arg_label
723
        ; partial = Total
724
        } -> helper ((arg_label, (pid, pat_loc)) :: acc) ctx loc c_rhs k
725
    | _ when [] = acc -> fail loc "texp_function_body"
4,721✔
726
    | _ -> k |> fargs ctx loc (List.rev acc) |> frhs ctx loc e
623✔
727
  in
728
  T (helper [])
6,936✔
729
;;
730

731
let texp_function_cases
732
  :  ((Asttypes.arg_label * (Ident.t * Location.t)) list, 'a, 'b) t
733
  -> (value case list, 'b, 'c) t
734
  -> (expression, 'a, 'c) t
735
  =
736
  fun (T fargs) (T frhs) ->
737
  let rec helper acc ctx loc e k =
5,960✔
738
    match e.exp_desc with
4,875✔
739
    | Typedtree.Texp_function
598✔
740
        { cases =
741
            [ { c_lhs = { pat_desc = Tpat_var (pid, tag); _ }; c_rhs; c_guard = _ } ]
742
        ; arg_label
743
        ; partial = Total
744
        } -> helper ((arg_label, (pid, tag.loc)) :: acc) ctx loc c_rhs k
745
    | Texp_function { cases = _ :: _ :: _ as cases; _ } ->
106✔
746
      k |> fargs ctx loc (List.rev acc) |> frhs ctx loc cases
68✔
747
    | _ -> fail loc "texp_function_cases"
4,171✔
748
  in
749
  T (helper [])
5,960✔
750
;;
751

752
[%%else]
753

754
let texp_function_cases (T fparam) (T fcases) =
755
  T
756
    (fun ctx loc e k ->
757
      match e.exp_desc with
758
      | Texp_function (params, Tfunction_cases cases) ->
759
        ctx.matched <- ctx.matched + 1;
760
        k
761
        |> fparam
762
             ctx
763
             loc
764
             (List.map (fun p -> p.Typedtree.fp_arg_label, (p.fp_param, p.fp_loc)) params)
765
        |> fcases ctx loc cases.cases
766
      | _ -> fail loc "texp_function")
767
;;
768

769
let texp_function_body (T fparam) (T fcases) =
770
  T
771
    (fun ctx loc e k ->
772
      match e.exp_desc with
773
      | Typedtree.Texp_function (params, Tfunction_body e) ->
774
        ctx.matched <- ctx.matched + 1;
775
        k
776
        |> fparam
777
             ctx
778
             loc
779
             (List.map (fun p -> p.fp_arg_label, (p.fp_param, p.fp_loc)) params)
780
        |> fcases ctx loc e
781
      | _ -> fail loc "texp_function")
782
;;
783

784
[%%endif]
785

786
let case (T pat) (T guard) (T rhs) =
787
  T
7,474✔
788
    (fun ctx loc { c_lhs; c_rhs; c_guard } k ->
789
      k |> pat ctx loc c_lhs |> guard ctx loc c_guard |> rhs ctx loc c_rhs)
57✔
790
;;
791

792
let ccase (T pat) (T guard) (T rhs) =
UNCOV
793
  T
×
794
    (fun ctx loc { c_lhs; c_rhs; c_guard } k ->
UNCOV
795
      k |> pat ctx loc c_lhs |> guard ctx loc c_guard |> rhs ctx loc c_rhs)
×
796
;;
797

798
[%%if ocaml_version < (5, 0, 0)]
799

800
let texp_match (T fexpr) (T fcomp_cases) (T fval_cases) =
801
  let rec split (type _a) (comps, vals) (cases : _ case list) =
2,814✔
802
    let _ : case_comp list = comps in
215✔
803
    let _ : case_val list = vals in
804
    let wrap (type a) comps vals : a case -> case_comp list * case_val list =
805
      let _ : case_comp list = comps in
147✔
806
      let _ : case_val list = vals in
807
      fun case ->
808
        match case with
147✔
809
        | { c_lhs = { pat_desc = Tpat_value p }; _ } ->
142✔
810
          ( comps
811
          , { c_lhs = (p :> pattern); c_rhs = case.c_rhs; c_guard = case.c_guard } :: vals
812
          )
UNCOV
813
        | { c_lhs = { pat_desc = Tpat_any }; _ } -> comps, (case :> case_val) :: vals
×
UNCOV
814
        | { c_lhs = { pat_desc = Tpat_var _ }; _ } -> comps, (case :> case_val) :: vals
×
UNCOV
815
        | { c_lhs = { pat_desc = Tpat_alias _ }; _ } -> comps, (case :> case_val) :: vals
×
UNCOV
816
        | { c_lhs = { pat_desc = Tpat_constant _ }; _ } ->
×
817
          comps, (case :> case_val) :: vals
UNCOV
818
        | { c_lhs = { pat_desc = Tpat_construct _ }; _ } ->
×
819
          comps, (case :> case_val) :: vals
UNCOV
820
        | { c_lhs = { pat_desc = Tpat_variant _ }; _ } ->
×
821
          comps, (case :> case_val) :: vals
UNCOV
822
        | { c_lhs = { pat_desc = Tpat_record _ }; _ } -> comps, (case :> case_val) :: vals
×
UNCOV
823
        | { c_lhs = { pat_desc = Tpat_array _ }; _ } -> comps, (case :> case_val) :: vals
×
UNCOV
824
        | { c_lhs = { pat_desc = Tpat_lazy _ }; _ } -> comps, (case :> case_val) :: vals
×
825
        (* | { c_lhs = { pat_desc = Tpat_value _ }; _ } -> (case :> case_comp) :: comps, vals *)
826
        | { c_lhs = { pat_desc = Tpat_exception _ }; _ } ->
3✔
827
          (case :> case_comp) :: comps, vals
828
        | { c_lhs = { pat_desc = Tpat_or _ }; _ } ->
2✔
829
          (* TODO(Kakadu): What to do here? We need to look deeply into or-pattern to understand where to place it?
830
            See issue #76
831
          *)
832
          (* failwith "Or-patterns are not yet implemented" *)
833
          comps, vals
UNCOV
834
        | { c_lhs; _ } ->
×
835
          (* Format.eprintf "%a\n%!" My_printtyped.pattern c_lhs; *)
836
          Format.eprintf
837
            "Unsupported pattern: tag = %d, is_block = %b\n"
UNCOV
838
            Obj.(tag @@ repr c_lhs)
×
UNCOV
839
            Obj.(is_block @@ repr c_lhs);
×
UNCOV
840
          assert false
×
841
    in
842
    match cases with
843
    | h :: tl -> split (wrap comps vals h) tl
147✔
844
    | [] -> List.rev comps, List.rev vals
68✔
845
  in
846
  T
847
    (fun ctx loc e k ->
848
      match e.exp_desc with
3,012✔
849
      | Texp_match (e, cases, _) ->
68✔
850
        ctx.matched <- ctx.matched + 1;
851
        let comp_cases, val_cases = split ([], []) cases in
852
        (* log
853
           "There are %d comp cases and %d val cases"
854
           (List.length comp_cases)
855
           (List.length val_cases); *)
856
        k
68✔
857
        |> fexpr ctx loc e
858
        |> fcomp_cases ctx loc comp_cases
62✔
859
        |> fval_cases ctx loc val_cases
62✔
860
      | _ -> fail loc "texp_match")
2,944✔
861
;;
862

863
[%%else]
864

865
let texp_match (T fexpr) (T fcomp_cases) (T fval_cases) =
866
  T
867
    (fun ctx loc e k ->
868
      match e.Typedtree.exp_desc with
869
      | Texp_match (e, ccases, vcases, _) ->
870
        let ccases, vcases =
871
          List.fold_left
872
            (fun (cacc, vacc) c ->
873
              match c.c_lhs.pat_desc with
874
              | Tpat_value v ->
875
                cacc, { c with c_lhs = (v :> value general_pattern) } :: vacc
876
              | _ -> cacc, vacc)
877
            ([], vcases)
878
            ccases
879
        in
880
        ctx.matched <- ctx.matched + 1;
881
        k |> fexpr ctx loc e |> fcomp_cases ctx loc ccases |> fval_cases ctx loc vcases
882
      | _ -> fail loc "texp_match")
883
;;
884

885
[%%endif]
886

887
let texp_ite (T pred) (T fthen) (T felse) =
888
  T
708✔
889
    (fun ctx loc e k ->
890
      match e.exp_desc with
8,066✔
891
      | Texp_ifthenelse (p, thenb, elseb) ->
185✔
892
        ctx.matched <- ctx.matched + 1;
893
        k |> pred ctx loc p |> fthen ctx loc thenb |> felse ctx loc elseb
77✔
894
      | _ -> fail loc "texp_ite")
7,881✔
895
;;
896

897
[%%if ocaml_version < (5, 0, 0)]
898

899
let texp_try (T fexpr) (T fcases) =
900
  T
59✔
901
    (fun ctx loc e k ->
902
      match e.exp_desc with
1,487✔
903
      | Texp_try (e, cases) ->
3✔
904
        ctx.matched <- ctx.matched + 1;
905
        k |> fexpr ctx loc e |> fcases ctx loc cases
3✔
906
      | _ -> fail loc "texp_try")
1,484✔
907
;;
908

909
[%%else]
910

911
let texp_try (T fexpr) (T fcases) =
912
  T
913
    (fun ctx loc e k ->
914
      match e.exp_desc with
915
      | Typedtree.Texp_try (e, cases, _) ->
916
        (* TODO: support effects *)
917
        ctx.matched <- ctx.matched + 1;
918
        k |> fexpr ctx loc e |> fcases ctx loc cases
919
      | _ -> fail loc "texp_try")
920
;;
921

922
[%%endif]
923

924
let texp_record (T fext) (T ffields) =
925
  T
1,495✔
926
    (fun ctx loc e k ->
927
      match e.exp_desc with
1,495✔
928
      | Texp_record { fields; extended_expression; _ } ->
19✔
929
        ctx.matched <- ctx.matched + 1;
930
        k |> fext ctx loc extended_expression |> ffields ctx loc fields
19✔
931
      | _ -> fail loc "texp_record")
1,476✔
932
;;
933

934
let texp_field (T fexpr) (T fdesc) =
935
  T
56✔
936
    (fun ctx loc e k ->
937
      match e.exp_desc with
51✔
938
      | Texp_field (e, _, desc) ->
17✔
939
        ctx.matched <- ctx.matched + 1;
940
        k |> fexpr ctx loc e |> fdesc ctx loc desc
17✔
941
      | _ -> fail loc "texp_field")
34✔
942
;;
943

944
let label_desc (T fname) =
945
  T
112✔
946
    (fun ctx loc e k ->
947
      match e with
95✔
948
      | { Types.lbl_name; _ } ->
95✔
949
        ctx.matched <- ctx.matched + 1;
950
        k |> fname ctx loc lbl_name)
951
;;
952

953
let rld_kept =
954
  T
955
    (fun ctx loc e k ->
956
      match e with
56✔
957
      | Kept _ ->
×
958
        ctx.matched <- ctx.matched + 1;
959
        k
960
      | _ -> fail loc "rld_kept")
56✔
961
;;
962

963
let rld_overriden (T flident) (T fexpr) =
964
  T
112✔
965
    (fun ctx loc e k ->
966
      match e with
95✔
967
      | Overridden ({ txt = lident }, e) ->
95✔
968
        ctx.matched <- ctx.matched + 1;
969
        k |> flident ctx loc lident |> fexpr ctx loc e
85✔
UNCOV
970
      | _ -> fail loc "rld_overriden")
×
971
;;
972

973
let value_binding (T fpat) (T fexpr) =
974
  T
1,660✔
975
    (fun ctx loc { vb_pat; vb_expr } k ->
976
      ctx.matched <- ctx.matched + 1;
171✔
977
      k |> fpat ctx loc vb_pat |> fexpr ctx loc vb_expr)
169✔
978
;;
979

980
(*   let hack0 (T path0) =
981
     T
982
     (fun ctx loc x k ->
983
     match x.Types.val_type.Types.desc with
984
     | Tconstr (path, [], _) ->
985
     ctx.matched <- ctx.matched + 1;
986
     path0 ctx loc path k
987
     | _ -> fail loc "hack0")
988
     ;;
989

990
     let hack1 ?(on_vd = drop) (T path0) =
991
     T
992
     (fun ctx loc x k ->
993
     match x.exp_desc with
994
     | Texp_ident (path, _, vd) ->
995
     ctx.matched <- ctx.matched + 1;
996
     let (T fvd) = on_vd in
997
     k |> path0 ctx loc path |> fvd ctx loc vd
998
     | _ -> fail loc "texp_ident")
999
     ;;
1000

1001
     let __ path = hack1 __ path *)
1002
let rec core_typ (T ftexpr) = T (fun ctx loc x k -> ftexpr ctx loc x.ctyp_type k)
175✔
1003

1004
let rec typ_constr (T fpath) (T fargs) =
1005
  let rec helper ctx loc x k =
697✔
1006
    (* Format.printf "typ = %a\n%!" Printtyp.type_expr x; *)
1007
    match Types.get_desc x with
2,422✔
1008
    | Tconstr (path, args, _) ->
1,293✔
1009
      ctx.matched <- ctx.matched + 1;
1010
      k |> fpath ctx loc path |> fargs ctx loc args
205✔
1011
    | Tlink arg -> helper ctx loc arg k
×
1012
    | _ -> fail loc "typ_constr"
1,129✔
1013
  in
1014
  T helper
1015
;;
1016

1017
let rec typ_arrow (T l) (T r) =
1018
  let rec helper ctx loc x k =
356✔
1019
    (* Format.printf "typ = %a\n%!" Printtyp.type_expr x; *)
1020
    match Types.get_desc x with
22✔
1021
    | Tarrow (_, tl, tr, _) ->
22✔
1022
      ctx.matched <- ctx.matched + 1;
1023
      k |> l ctx loc tl |> r ctx loc tr
22✔
UNCOV
1024
    | _ -> fail loc "typ_arrow"
×
1025
  in
1026
  T helper
1027
;;
1028

1029
let typ_kind_abstract =
1030
  T
1031
    (fun ctx loc x k ->
1032
      match x with
67✔
1033
      | Typedtree.Ttype_abstract ->
8✔
1034
        ctx.matched <- ctx.matched + 1;
1035
        k
1036
      | _ -> fail loc "typ_kind_abstract")
59✔
1037
;;
1038

1039
let typ_kind_open =
1040
  T
1041
    (fun ctx loc x k ->
1042
      match x with
67✔
UNCOV
1043
      | Typedtree.Ttype_open ->
×
1044
        ctx.matched <- ctx.matched + 1;
1045
        k
1046
      | _ -> fail loc "typ_kind_open")
67✔
1047
;;
1048

1049
let typ_kind_variant =
1050
  T
1051
    (fun ctx loc x k ->
1052
      match x with
59✔
1053
      | Typedtree.Ttype_variant _ ->
49✔
1054
        ctx.matched <- ctx.matched + 1;
1055
        k
1056
      | _ -> fail loc "typ_kind_variant")
10✔
1057
;;
1058

1059
let typ_kind_record (T flabels) =
1060
  T
57✔
1061
    (fun ctx loc x k ->
1062
      match x with
10✔
1063
      | Typedtree.Ttype_record labels ->
10✔
1064
        ctx.matched <- ctx.matched + 1;
1065
        k |> flabels ctx loc labels
UNCOV
1066
      | _ -> fail loc "typ_kind_record")
×
1067
;;
1068

1069
(* Structure *)
1070

1071
let tstr_attribute (T fattr) =
1072
  T
40✔
1073
    (fun ctx loc str k ->
1074
      match str.str_desc with
40✔
1075
      | Tstr_attribute attr ->
15✔
1076
        ctx.matched <- ctx.matched + 1;
1077
        k |> fattr ctx loc attr
1078
      | _ -> fail loc "tstr_attribute")
25✔
1079
;;
1080

1081
let tsig_attribute (T fattr) =
1082
  T
3✔
1083
    (fun ctx loc str k ->
1084
      match str.sig_desc with
3✔
1085
      | Tsig_attribute attr ->
2✔
1086
        ctx.matched <- ctx.matched + 1;
1087
        k |> fattr ctx loc attr
1088
      | _ -> fail loc "tsig_attribute")
1✔
1089
;;
1090

1091
let tsig_val_name (T fname) =
UNCOV
1092
  T
×
1093
    (fun ctx loc str k ->
UNCOV
1094
      match str.sig_desc with
×
UNCOV
1095
      | Tsig_value { val_id = txt } ->
×
1096
        ctx.matched <- ctx.matched + 1;
1097
        k |> fname ctx loc txt
UNCOV
1098
      | _ -> fail loc "tsig_val_name")
×
1099
;;
1100

1101
let attribute (T fname) (T fpayload) =
1102
  T
43✔
1103
    (fun ctx loc attr k ->
1104
      let open Parsetree in
17✔
1105
      k |> fname ctx loc attr.attr_name.txt |> fpayload ctx loc attr.attr_payload)
17✔
1106
;;
1107

1108
let payload_stru (T fstru) =
1109
  T
43✔
1110
    (fun ctx loc x k ->
1111
      match x with
17✔
1112
      | Parsetree.PStr stru -> k |> fstru ctx loc stru
17✔
UNCOV
1113
      | _ -> fail loc "payload_stru")
×
1114
;;
1115

1116
let pstr_eval (T f) =
1117
  T
43✔
1118
    (fun ctx loc x k ->
1119
      match x.Parsetree.pstr_desc with
17✔
1120
      | Parsetree.Pstr_eval (e, _) -> k |> f ctx loc e
17✔
UNCOV
1121
      | _ -> fail loc "pstr_eval")
×
1122
;;
1123

1124
let pexp_constant (T f) =
1125
  T
43✔
1126
    (fun ctx loc e k ->
1127
      match e.Parsetree.pexp_desc with
17✔
1128
      | Parsetree.Pexp_constant e -> k |> f ctx loc e
13✔
1129
      | _ -> fail loc "pexp_constant")
4✔
1130
;;
1131

1132
[%%if ocaml_version < (5, 0, 0)]
1133

1134
let pexp_function_cases (T fargs) (T fcases) =
1135
  let open Parsetree in
3✔
1136
  let rec helper acc ctx loc x k =
1137
    match x.pexp_desc with
9✔
1138
    | Pexp_fun (Asttypes.Nolabel, None, pat, rhs) -> helper (pat :: acc) ctx loc rhs k
6✔
1139
    | Pexp_function cases -> k |> fargs ctx loc (List.rev acc) |> fcases ctx loc cases
3✔
UNCOV
1140
    | _ -> fail loc "pexp_function_cases"
×
1141
  in
1142
  T (helper [])
3✔
1143
;;
1144

1145
let pexp_function_body (T fargs) (T fcases) =
1146
  let open Parsetree in
1✔
1147
  let rec helper acc ctx loc x k =
1148
    match x.pexp_desc with
3✔
1149
    | Pexp_fun (Asttypes.Nolabel, None, pat, rhs) -> helper (pat :: acc) ctx loc rhs k
2✔
1150
    | _ -> k |> fargs ctx loc (List.rev acc) |> fcases ctx loc x
1✔
1151
  in
1152
  T (helper [])
1✔
1153
;;
1154

1155
let pconst_string (T fstring) =
1156
  T
43✔
1157
    (fun ctx loc x k ->
1158
      match x with
13✔
1159
      | Parsetree.Pconst_string (s, _, _) -> k |> fstring ctx loc s
13✔
UNCOV
1160
      | _ -> fail loc "pconst_string")
×
1161
;;
1162

1163
[%%else]
1164

1165
let pexp_function_body (T fargs) (T fbody) =
1166
  let open Parsetree in
1167
  T
1168
    (fun ctx loc x k ->
1169
      match x.pexp_desc with
1170
      | Pexp_function (params, _, Pfunction_body e) ->
1171
        let args =
1172
          List.map
1173
            (fun p ->
1174
              match p.pparam_desc with
1175
              | Pparam_val (Nolabel, _, pat) -> pat
1176
              | Pparam_newtype _ | _ -> fail loc "pexp_function_body: params")
1177
            params
1178
        in
1179
        k |> fargs ctx loc args |> fbody ctx loc e
1180
      | _ -> fail loc "pexp_function_body")
1181
;;
1182

1183
let pexp_function_cases (T fargs) (T fcases) =
1184
  let open Parsetree in
1185
  T
1186
    (fun ctx loc x k ->
1187
      match x.pexp_desc with
1188
      | Pexp_function (params, _, Pfunction_cases (cases, _, _)) ->
1189
        let args =
1190
          List.map
1191
            (fun p ->
1192
              match p.pparam_desc with
1193
              | Pparam_val (Nolabel, _, pat) -> pat
1194
              | Pparam_newtype _ | _ -> fail loc "pexp_function_cases: params")
1195
            params
1196
        in
1197
        k |> fargs ctx loc args |> fcases ctx loc cases
1198
      | _ -> fail loc "pexp_function_cases")
1199
;;
1200

1201
let pconst_string (T fstring) =
1202
  T
1203
    (fun ctx loc x k ->
1204
      match x.Parsetree.pconst_desc with
1205
      | Parsetree.Pconst_string (s, _, _) -> k |> fstring ctx loc s
1206
      | _ -> fail loc "pconst_string")
1207
;;
1208

1209
[%%endif]
1210

1211
let pexp_apply (T f) (T fargs) =
1212
  let open Parsetree in
1✔
1213
  let helper ctx loc x k =
1214
    match x.pexp_desc with
1✔
1215
    | Pexp_apply (efun, eargs) -> k |> f ctx loc efun |> fargs ctx loc eargs
1✔
UNCOV
1216
    | _ -> fail loc "pexp_apply"
×
1217
  in
1218
  T helper
1219
;;
1220

1221
let tstr_docattr on_str =
1222
  tstr_attribute
40✔
1223
    (attribute
40✔
1224
       drop
1225
       (payload_stru (pstr_eval (pexp_constant (pconst_string on_str)) ^:: nil)))
40✔
1226
;;
1227

1228
let tsig_docattr on_str =
1229
  tsig_attribute
3✔
1230
    (attribute
3✔
1231
       drop
1232
       (payload_stru (pstr_eval (pexp_constant (pconst_string on_str)) ^:: nil)))
3✔
1233
;;
1234

1235
type context = Ast_pattern0.context
1236

UNCOV
1237
let of_func f = T f
×
UNCOV
1238
let to_func (T f) = f
×
1239
let fail = fail
1240

1241
let%test_module "Fake tests, only to increase coverage" =
1242
  (module struct
1243
    [@@@coverage off]
1244

1245
    let noloc =
1246
      Warnings.
1247
        { loc_start = Lexing.dummy_pos; loc_end = Lexing.dummy_pos; loc_ghost = true }
1248
    ;;
1249

1250
    let%test _ =
1251
      match path_of_list [] with
1252
      | exception Failure _ -> true
1253
      | _ -> false
1254
    ;;
1255

1256
    let%test_unit _ =
1257
      let mk p ?(inv = false) what =
1258
        let on_error, rez =
1259
          if inv then Fun.const true, false else Fun.const false, true
1260
        in
1261
        parse p noloc ~on_error what rez
1262
      in
1263
      [%test_eq: Base.bool]
1264
        true
1265
        (mk
1266
           ~inv:true
1267
           (path_pident drop)
1268
           Path.(Pdot (Pident (Ident.create_local "List"), "map")));
1269
      [%test_eq: Base.bool]
1270
        true
1271
        (mk (path_pident drop) Path.(Pident (Ident.create_local "compare")));
1272
      [%test_eq: Base.bool] true (mk ~inv:true (labelled drop) Asttypes.Nolabel);
1273
      [%test_eq: Base.bool]
1274
        true
1275
        (mk
1276
           (econst drop)
1277
           { Typedtree.exp_desc = Texp_constant (Asttypes.Const_string ("", noloc, None))
1278
           ; exp_extra = []
1279
           ; exp_type = Predef.type_string
1280
           ; exp_loc = noloc
1281
           ; exp_env = Env.empty
1282
           ; exp_attributes = []
1283
           });
1284
      let _42 =
1285
        { Typedtree.exp_desc = Texp_constant (Asttypes.Const_int 42)
1286
        ; exp_extra = []
1287
        ; exp_type = Predef.type_int
1288
        ; exp_loc = noloc
1289
        ; exp_env = Env.empty
1290
        ; exp_attributes = []
1291
        }
1292
      in
1293
      [%test_eq: Base.bool] true (mk (econst drop) _42)
1294
    ;;
1295
  end)
1296
;;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc