If you have two types that defines the same label or constructor, distinguishing between the two types requires type-directed disambiguation. Since type-directed disambiguation is not sufficient in all context, this implies that the type of some functions becomes ambiguous
let str x = x.str (* what is the type of `x`? `b` or `c`)
and those functions require some explicit type annotation to remove the ambiguity:
let str (x:c) = x.str
However, in many cases it is not that painful to deal with the ambiguity, that is why the
the duplicate-definitions warning is disabled by default in recent versions of OCaml.
With mutually recursive types, the order of the type definitions is unclear, and there is no point where there is only one definition in scope. Contrarily, with a separated type definitions, you could have something like:
type t = A
let x = A
type u = A
(* ... some code that never use `A:t` *)
where it is fine to shadow A:t if it is never used again.
Thus the duplicate-definitions case is clearly always problematic without type-directed disambiguation, but the situation is slightly less clear cut with separate definitions.
Warning 30 was important before we supported type-based disambiguation, because those situations were always a mistake from the user. It became mostly irrelevant when disambiguation was added. But we took some time noticing, and only disabled it by default in OCaml 4.10 (see #9046). I believe that you can safely forget about it.