Fragile pattern-matching not detected

I began using the compiler flag that triggers the warning

Warning 4 [fragile-match]: this pattern-matching is fragile.
It will remain exhaustive when constructors are added to type t.

because I feel safer with it. But I’m not sure why it fails to detect some fragile pattern-matchings like the following:

let f_fragile = function [] -> 0 | _ -> 1
let f_fragil2 = function _ :: _ -> 1 | _ -> 0
let f_robuste = function [] -> 0 | _ :: _ -> 1

which does not trigger any warning.

My guess is that it’s because it’s in the standard library (the same happens with function None -> 0 | _ -> 1) for instance, but “my” types are correctly detected), but I’m not sure: I can still modify the code in the standard library and add for instance a third constructor to the type 'a list, and the compiler “wouldn’t know”. So:

  1. Is this the reason, and is there a “super warning” I can use to warn also in the case of standard library types?
  2. Is there another reason, and how do I fix it?

Indeed, even for types like list and option, I feel safer using the robust version, which is more explicit and less sensitive to the order of patterns.

Probably specifically for builtins. For instance result isn’t builtin and I do get a warning from function Ok _ -> 1 | _ -> 2.

1 Like

The fragile pattern matching check seems to be making the following exclusions:

I guess the reason is that no new constructors will ever be added to these types in Stdlib. But I can also see the preference for more explicitness for fallback cases.

3 Likes

Note that these four types are not defined in Stdlib at all (and Bool.t, List.t, Option.t and Unit.t are all aliases)… in other words, neither Stdlib (nor any replacement standard library) could ever add any constructors to these types, because they’re part of the language. If you define your own type t_666 = true | false, you’ll get warning 4 on function true -> Bool.(true) | _ -> Bool.(false) :face_with_peeking_eye:

I think it might even be the case that without the exceptions, the warning could be triggered on some code generated while some parts of the surface language are being desugared, but I haven’t properly thought about that!

2 Likes

Thanks Sim. Since that looks very localized, I guess I can simply remove that function (and replace its only call, later in the same file: (if extendable_path path then add_path path r else r) to (add_path path r), and then “compile that compiler” and use that compiler for my development. Maybe I will do that, but I’m not sure the benefit is worth the hassle: maybe I’ll simply try to be extra careful “humanly” on such pattern-matchings.