Deficiency: uninstantiable union
fields still require a tag value (proposal: exclude them)
#19860
Labels
proposal
This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone
Tagged
union
-s are allowed to have states/fields of uninstantiable (noreturn
-like) types - see #3257, #15909, and other issues for explanation.However, in status-quo it is required that the
union
states/fields match the tagenum
's states/fields exactly,including states/fields of uninstantiable types.
This introduces an unnecessary inefficiency to tagged
union
-s that can only be worked around bymanual reification via
@Type
, which worsens ergonomics, making code both harder to read and write.Some example code to reference:
The main issue with status-quo is that the tag type is forced to grow to more bits than necessary.
There are two main cases to consider:
For user-provided
union(T)
tag types, I propose it should simply be allowed to provide a more optimalenum
type than in status-quo,which is not required (but can still be allowed) to reserve states/values for uninstantiable union states/fields.
This boils down to selectively loosening the current state/field equivalence check between the union and the tag type.
For compiler-provided
union(enum)
tag types, it might make senseafter Proposal: namespace type equivalence based on AST node + captures #18816 / compiler: namespace type equivalence based on AST node + captures #19190
to expect the tag type to be deduplicated for types created from the same AST node.
However, this currently isn't the case, and I personally don't see a lot of value in doing this.
If that particular behavior is desired, an explicit
enum
type can be created and used instead.Therefore, I propose that the compiler-provided tag type also shouldn't include states/fields for union states/fields with uninstantiable types.
Technically optional: Salvaging (exhaustive)
switch
The one additional demand I want to pose here is that the ergonomics of
switch
should not degrade due to this optimization.I find it highly valuable to be able to write a single switch, include all fields, and re-use that code regardless of which fields are instantiable and which aren't.
I believe that today this only works because the tag enum contains all of these fields, which is used as result type of the enum literals in the
switch
prongs.In order to not degrade this use case, tagged
union
types basically need a list of all uninstantiable field names,and those particular names have to be whitelisted to appear in
switch
prongs.(Further allowing them in
==
/!=
comparisons, etc., would also be nice though .)The cleanest implementation I can think of for this would be to include a second
full_tag_type
inbuiltin.Type.Union
.This full tag type were to be used as "first result location" for type checking,
while the actual field enum type is used afterwards - at this point uninstantiable field names are dropped due to being unreachable.
I realize this last part is a semi-big language feature to propose, but I really think the ergonomic boon would warrant it.
That said, there'd be ways for me to work around it in userland, so it's not as critical of a requirement as the first half
(which would require reifying all applicable tagged union types with
@Type
).The text was updated successfully, but these errors were encountered: