There’s an advantage to polymorphic variants that you have not mentioned: you can pass their values from two different types without the cost of a conversion (if the types are compatible).
I don’t know the exact properties of the hash function, but I believe there is a compile-time check that no two variants with the same hashes are used in the same compilation unit (it checks on all variant constructors appearing in types, so even if you have a collision, you will never be able to build a program manipulating both values together). It’s possible that you could observe a collision with the polymorphic comparison on values whose type has been existentially quantified, but that’s not specific to polymorphic variants (you can check that 0
has the same representation as false
the same way).