There is basically no extra complexity, just refactoring. The only difference is that, for example, setting the initializer for a GlobalVariable.c statically requires a Constant.c, not just any llvalue as allowed by the existing bindings. I don't see this as additional complexity, because you have to know the real types anyway to work with the current bindings. I'm simply making them explicit in the interface. There is unfortunately the annoyance of frequent upcasts: to past your Constant.c x to a function that expects a Value.c, you must write (x :> Value.c). But that limitation of the OCaml language can be removed, and it already has been in the implicit_subtyping branch. I would love to see those changes integrated into mainline OCaml, or at least updated to work with the latest release! :)
You guys are right that I was too sweeping with my statement about type safety... the other features you mentioned are great reasons to prefer OCaml, and they're important to me too. What I should have said was, I don't want to have to sacrifice type safety of the bindings so I can work in OCaml, especially when I see no fundamental reason why that sacrifice is necessary. Frankly I was very surprised when I first discovered that the bindings are so inadequate in this respect, and that no one had done anything about it. Maybe that's because no one cares, but I doubt it. It may not be the most important thing, but I see it as free help from OCaml's type and module systems, and I'll take that help, especially when working with such a large and complex project like LLVM.