bisect_ppx icon indicating copy to clipboard operation
bisect_ppx copied to clipboard

Request feature to disable coverage check of the pattern part of or-patterns

Open mbarbin opened this issue 9 months ago • 0 comments

I have noticed somewhat of a tension between a specific style of spelling out every cases in a pattern matching (let's call it loosely "defensive programming" for a minute) on one hand and reaching exhaustive coverage on the other.

Imagine you have a type

type t = A | B | C

And a particular function that distinguishes the A case:

let is_A : t -> bool = function
| A -> true
| _ -> false

Under the "defensive programming" style, you'd almost never make use of the patany constructor and write this instead:

let is_A = function
| A -> true
| (B | C) -> false

with the aim to be called upon to reconsider at that call site if t ever changes.

Now, currently with bisect_ppx this forces you to exercise all the cases B and C in your test suite if you want to fully cover this function. Sometimes, this is exactly what you want. But sometimes, not. In particular I have cases where I am happy to test for the A case, and 1 of the remaining one being enough.

Note however that I do not want to disable the coverage test for the right-hand side!

let is_A = function
| A -> true
| (B|C) -> false [@coverage off]

Nope!

In the test suite unary.t you can see an example of instrumentation for or-patterns:

   let _ =
     match Some `A with
     | Some (`A | `B) -> print_endline "foo"
     | None -> ()

Instrumented as:

  let _ =
    match Some `A with
    | Some (`A | `B) as ___bisect_matched_value___ ->
        (match[@ocaml.warning "-4-8-9-11-26-27-28-33"]
           ___bisect_matched_value___
         with
        | Some `A ->
            ___bisect_visit___ 1;
            ()
        | Some `B ->
            ___bisect_visit___ 2;
            ()
        | _ -> ());
        ___bisect_post_visit___ 0 (print_endline "foo")
    | None ->
        ___bisect_visit___ 3;
        ()

I would like to request something like a special directive that would cause it to be that instead:

  let _ =
    match Some `A with
    | Some (`A | `B) ->
        ___bisect_post_visit___ 0 (print_endline "foo")
    | None ->
        ___bisect_visit___ 3;
        ()

(Essentially, not generate the extra piece of code that makes sure individual patterns are visited).

I am opening this issue to get a feel for whether that desire is shared by others, and if there are ideas on what the directive or ways to support this should look like.

Thanks!

mbarbin avatar Mar 21 '25 08:03 mbarbin