Hi Chris,
To me the conclusion is exactly the opposite: since we have is_struct/2, there is no need to add a bunch of guards to Kernel. Furthermore, adding such guards to Kernel will only feel natural for Elixir built-types. For everyone else, the usage is more bureaucratic (i.e. import/require a module and then use it). So is_struct/2 is more consistent.
The argument that the Regex struct is an implementation detail does not hold because, given that Elixir has limited built-in types, it has to be a struct by definition. For example, if anyone has ever implemented a protocol for Regex, you are relying on the fact it is a struct - as there is literally no other option.
The MapSet is really an issue with Dialyzer not having a mechanism for us to express the constructs we have in Elixir. As mentioned in the linked issue, it manifests in other occasions too, and I would rather fix Dialyzer. Furthermore, a "is_mapset" guard would have the same warnings as is_struct/2", if any, so it wouldn't really address this problem.
In any case, Regex.regex? does send mixed signals now that we have is_struct/2, so I will schedule it for deprecation in the long run. Thanks!