mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 10:13:35 +00:00
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:
@@ -29,6 +29,7 @@ enum ExactValueKind {
|
||||
ExactValue_Typeid = 10,
|
||||
ExactValue_String16 = 11,
|
||||
ExactValue_AsmTemplate = 12,
|
||||
ExactValue_Variant = 13,
|
||||
|
||||
ExactValue_Count,
|
||||
};
|
||||
@@ -47,6 +48,8 @@ gb_global char const *exact_value_kind_string[ExactValue_Count] = {
|
||||
"Procedure",
|
||||
"Typeid",
|
||||
"String16",
|
||||
"AsmTemplate",
|
||||
"Variant",
|
||||
};
|
||||
|
||||
struct ExactValue {
|
||||
@@ -64,7 +67,9 @@ struct ExactValue {
|
||||
Type * value_typeid;
|
||||
String16 value_string16;
|
||||
Ast * value_asm_template;
|
||||
Ast * value_variant;
|
||||
};
|
||||
Type *variant_type;
|
||||
};
|
||||
|
||||
gb_global ExactValue const empty_exact_value = {};
|
||||
@@ -115,6 +120,9 @@ gb_internal uintptr hash_exact_value(ExactValue v) {
|
||||
case ExactValue_Typeid:
|
||||
res = ptr_map_hash_key(v.value_typeid);
|
||||
break;
|
||||
case ExactValue_Variant:
|
||||
res = ptr_map_hash_key(v.value_variant);
|
||||
break;
|
||||
default:
|
||||
res = gb_fnv32a(&v, gb_size_of(ExactValue));
|
||||
}
|
||||
@@ -202,6 +210,11 @@ gb_internal ExactValue exact_value_typeid(Type *type) {
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_internal ExactValue exact_value_variant(Ast *node) {
|
||||
ExactValue result = {ExactValue_Variant};
|
||||
result.value_variant = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_internal ExactValue exact_value_integer_from_string(String const &string) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
@@ -688,6 +701,7 @@ gb_internal i32 exact_value_order(ExactValue const &v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
case ExactValue_Compound:
|
||||
case ExactValue_Variant:
|
||||
return 0;
|
||||
case ExactValue_Bool:
|
||||
case ExactValue_String:
|
||||
@@ -712,6 +726,8 @@ gb_internal i32 exact_value_order(ExactValue const &v) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void match_exact_values_variant(ExactValue *x, ExactValue *y);
|
||||
|
||||
gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
if (exact_value_order(*y) < exact_value_order(*x)) {
|
||||
match_exact_values(y, x);
|
||||
@@ -772,6 +788,10 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExactValue_Variant:
|
||||
match_exact_values_variant(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
|
||||
@@ -973,6 +993,7 @@ gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) {
|
||||
}
|
||||
|
||||
gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y);
|
||||
gb_internal bool compare_exact_values_variant(TokenKind op, ExactValue x, ExactValue y);
|
||||
|
||||
gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
match_exact_values(&x, &y);
|
||||
@@ -1119,6 +1140,16 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y)
|
||||
return false;
|
||||
}
|
||||
return compare_exact_values_compound_lit(op, x, y);
|
||||
|
||||
case ExactValue_Variant:
|
||||
if (op != Token_CmpEq && op != Token_NotEq) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.kind != y.kind) {
|
||||
return op == Token_NotEq;
|
||||
}
|
||||
return compare_exact_values_variant(op, x, y);
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid comparison: %d", x.kind);
|
||||
@@ -1184,6 +1215,8 @@ gb_internal gbString write_exact_value_to_string(gbString str, ExactValue const
|
||||
return write_expr_to_string(str, v.value_compound, false);
|
||||
case ExactValue_Procedure:
|
||||
return write_expr_to_string(str, v.value_procedure, false);
|
||||
case ExactValue_Variant:
|
||||
return write_expr_to_string(str, v.value_variant, false);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user