Unions don't have a discriminant. Anonymous Sum types have a discriminant, you just can't name it. Unions in Rust are unsafe because you can't tell what the underlying value will be.
Well, that depends. If the union consists of two types that share the same underlying structure, then obviously at runtime we can never know what the value is.
But otherwise we can. And this is something that we will know at compile-time, so we can prevent runtime-checks that would not work.
But essentially, when it comes to union types, they behave like sets. The compiler merges them. (A | B) | (A | B) is the same as A | B. But for sum types (even anonymous ones such as tuples) the compiler can't merge them because that would lose information (if the result is from the first A | B or the second one). Instead, you end up with a nested structure.
Which one is desired depends on the use-case, but it's definitely different.
> It's impossible for the compiler to do anything with x without adding some kind of runtime type tag.
Yes, in this particular case that's true. If the developer tries to do anything except maybe printing it for debug then the compiler will tell the developer so and the developer will have to switch to sumtypes / wrap it just like it is done in OCaml by default.
But otherwise we can. And this is something that we will know at compile-time, so we can prevent runtime-checks that would not work.