RFC: Split `Union` to memoize hasuniquerep
This attempts to revisit the issue that gave rise to #44400 more
comprehensively. The core issue is that having `Union` typed fields
forced inference to deal with these as `Type{}`, which can be
substantially slower than dealing with unions as concrete objects.
The patch in #44400 attempted to improve this by returning the correct
`Const` object when the object being queried was `Const` or
`hasuniquerep`. However, we can actually do substantially better
by recognizing that most `Union`s that we encounter in practice themselves
are actually `hasuniquerep`, because we normalize them on construction.
This allows us to use `Const` for these unions significantly more often.
The only issue is that computing whether the normalization succeeded is
non-trivial and would in general require an O(n log n) (in the number of
Union components) sort. This is ok on construction, but not great in the
tfuncs, where this is supposed to be a fast check and having to do the
query would defeat the performance advantage.
Thus, we main meat of this PR is to attemtp to memoize the
`hasuniquerep` bit for `Union` without being breaking to existing
code that deals with `Union`s. This is accomplished as follows:
1. The Union DataType is split into (semantically) `Union{true}`
and `Union{false}`. Since these types are not constructable with
apply_type, there are canonical UniqueUnion and NonuniqueUnion
aliases.
2. `Union` is now the UnionAll of these two.
3. The code from #44400 is still incorporated in addition to handle
NonuniqueUnion cases, but the basic test set from that issue is
already addressed by just the `hasuniquerep` memoization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>