Implement fixes for constant unions

Note that with this commit, casting through
multiply-nested unions is forbidden, e.g.
```
U :: union {int, V}
V :: union {bool}
x: U = true
```
does not compile.
(Previously the compiler would simply crash)

This is to avoid situations where adding variants
can lead to unexpected changes in the value.

For example if `U` is changed to have a `bool`
variant of its own:
```
U :: union {int, bool, V}
```
Then `x: U = true` would equal
`U(true)` instead of `U(V(true))`.

Single-variant unions are exempt, primarily to
improve the ergonomics of `Maybe` in cases like:
```
x: Maybe(union{int, bool}) = 1
```

Fix #6100
Fix #6699
Fix #6895
Fix #6896
Fix #6897
Fix #7036
Fix #7083
Fix #7091
This commit is contained in:
korvahkh
2026-07-22 09:58:49 -05:00
parent 7f80c7093a
commit 02246ac6fd
8 changed files with 199 additions and 139 deletions

View File

@@ -1951,6 +1951,13 @@ gb_internal Type *core_array_type(Type *t) {
}
}
gb_internal Type *core_broadcastable_elem_type(Type *t) {
while (is_type_array(t)) {
t = base_array_type(t);
}
return t;
}
gb_internal i32 type_math_rank(Type *t) {
i32 rank = 0;
for (;;) {
@@ -3609,6 +3616,23 @@ gb_internal Type *union_tag_type(Type *u) {
return t_uint;
}
gb_internal bool type_conversion_is_variant(Type *dst, Type *src) {
dst = base_type(core_broadcastable_elem_type(dst));
if (dst == nullptr) { return false; }
switch (dst->kind) {
case Type_Union:
if (union_is_variant_of(dst, src)) {
return true;
}
if (dst->Union.variants.count == 1) {
return type_conversion_is_variant(dst->Union.variants[0], src);
}
return false;
}
return false;
}
gb_internal int matched_target_features(TypeProc *t) {
if (t->require_target_feature.len == 0) {
return 0;