4

The future 4.03 release of OCaml has added a new warning, 57, to prevent ambiguous guarded pattern. Namely, the issue is that on an or-pattern with a when clause, if the first part of the or-pat matches, but the when evaluates to false, the complete pattern will be discarded, although another variant of the or-pat could have succeed. For instance, on the following code, ko will be bound to 1, which can be surprising:

type t = A of string | B of string

let bad x y =
  match x,y with
  | A s, _ | _, A s when s = "foo" -> 0
  | _, _ -> 1

let ok = bad (A "foo") (A "bar")
let ko = bad (A "bar") (A "foo")

In 4.03, OCaml will complain with Warning 57: Ambiguous guarded pattern, variable s may match different or-pattern arguments, suggesting you to check whether you really intended this behavior or not.

However, the warning is also active on the second line of the pattern matching in the following definition:

let f x y =
  match  x,y with
  | A _, A _ -> 0
  | A s, _  | _, A s when s = "foo" -> 1
  | _ -> 2

Here, I'd argue that the ambiguity cannot arise, since A _, A _ is matched by the first line, hence at most one of the components of the or-pattern can match if the program gets to this point. Is this reasoning correct?

If the answer is yes, I would like to know in addition whether it is possible to silence this warning on this specific branch. Indeed, I can do match [@warning "-57"] x,y with, but this will silence the warning if someone introduces another ambiguous pattern there sometime later. I've tried to put the attribute at the pattern level (| A s, _ | _, A s [@warning "-57"] when s = "foo"), but this has no effect.

NB: I know that in this specific case I could just replace the catch-all with | A s, B _ | B _, A s when s = "foo" to make the ambiguity disappear, but consider that this is only a reduced example.

Virgile
  • 9,724
  • 18
  • 42

1 Answers1

2

The warning is for people unaware that when guards are not part of the pattern and imagine that A s, _ | _, A s when s = "" is the same as A s, _ | (_, A s when s = "") which is syntactically invalid.

It seems like a good idea to keep the warning, although it would be nice if explicit parentheses prevented it, e.g. (A s, _ | _, A s) when s = "".

You're suggesting that the compiler should be smarter than the average reader and suppress warnings based on non-obvious rules. In other words your reasoning is correct but it's too much overhead for the programmer who is used to rely on warnings.

Martin Jambon
  • 4,629
  • 2
  • 22
  • 28
  • I'm not suggesting that the compiler should be smarter, I'd just like to have a way to tell it: "trust me for _this particular pattern_ I know what I'm doing", without having to discard the warning for the entire pattern-matching expression. – Virgile Feb 22 '16 at 07:43
  • I guess a directive to turn on or off warnings locally would be useful. – Martin Jambon Feb 22 '16 at 16:13