mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-14 22:33:43 +00:00
Fix #5129
This commit is contained in:
@@ -836,7 +836,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
|
||||
Type *tag_type = union_tag_type(bt);
|
||||
LLVMTypeRef llvm_tag_type = lb_type(m, tag_type);
|
||||
i64 tag_index = union_variant_index(bt, variant_type);
|
||||
i64 tag_index = union_variant_index_checked(bt, variant_type);
|
||||
GB_ASSERT(tag_index >= 0);
|
||||
values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false);
|
||||
i64 used_size = block_size + type_size_of(tag_type);
|
||||
|
||||
@@ -5388,11 +5388,20 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
Type *fet = field_expr.type;
|
||||
GB_ASSERT(fet->kind != Type_Tuple);
|
||||
|
||||
// HACK TODO(bill): THIS IS A MASSIVE HACK!!!!
|
||||
if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) {
|
||||
GB_ASSERT_MSG(union_variant_index(ft, fet) >= 0, "%s", type_to_string(fet));
|
||||
if (union_is_variant_of(ft, fet)) {
|
||||
// NOTE(bill, 2026-03-15): If it's a direct assignment for a variant to the
|
||||
// direct union we can just assign it directly to minimize wasted code generation
|
||||
//
|
||||
// TODO(bill): Allow this for deeply nested unions too e.g. union{union{T}}
|
||||
GB_ASSERT_MSG(union_variant_index_checked(ft, fet) >= 0, "%s", type_to_string(fet));
|
||||
GB_ASSERT(are_types_identical(type_deref(gep.type), ft));
|
||||
|
||||
lb_emit_store_union_variant(p, gep, field_expr, fet);
|
||||
lb_emit_store_union_variant(p, gep, field_expr, fet);
|
||||
} else {
|
||||
lbValue fv = lb_emit_conv(p, field_expr, ft);
|
||||
lb_emit_store(p, gep, fv);
|
||||
}
|
||||
} else {
|
||||
lbValue fv = lb_emit_conv(p, field_expr, ft);
|
||||
lb_emit_store(p, gep, fv);
|
||||
|
||||
@@ -1497,7 +1497,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_const_union_tag(lbModule *m, Type *u, Type *v) {
|
||||
return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index(u, v)));
|
||||
return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index_checked(u, v)));
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
|
||||
@@ -1540,13 +1540,17 @@ gb_internal void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent,
|
||||
// No tag needed!
|
||||
} else {
|
||||
lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent);
|
||||
lb_emit_store(p, tag_ptr, lb_const_union_tag(p->module, t, variant_type));
|
||||
lbValue tag = lb_const_union_tag(p->module, t, variant_type);
|
||||
lb_emit_store(p, tag_ptr, tag);
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) {
|
||||
Type *pt = base_type(type_deref(parent.type));
|
||||
GB_ASSERT(pt->kind == Type_Union);
|
||||
|
||||
GB_ASSERT_MSG(union_is_variant_of(pt, variant_type), "%s %s", type_to_string(pt), type_to_string(variant_type));
|
||||
|
||||
if (pt->Union.kind == UnionType_shared_nil) {
|
||||
GB_ASSERT(type_size_of(variant_type));
|
||||
|
||||
|
||||
@@ -1064,7 +1064,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
|
||||
i64 tag_index = 0;
|
||||
if (tag_type != nullptr) {
|
||||
tag_index = union_variant_index(ut, tag_type);
|
||||
tag_index = union_variant_index_checked(ut, tag_type);
|
||||
}
|
||||
GB_ASSERT(tag_index <= Typeid__COUNT);
|
||||
|
||||
|
||||
@@ -3375,7 +3375,7 @@ gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal i64 union_variant_index(Type *u, Type *v) {
|
||||
gb_internal i64 union_variant_index_checked(Type *u, Type *v) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
|
||||
@@ -3389,9 +3389,24 @@ gb_internal i64 union_variant_index(Type *u, Type *v) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
GB_PANIC("unfound variant -> %s %s", type_to_string(u), type_to_string(v));
|
||||
return -1;
|
||||
}
|
||||
|
||||
gb_internal bool union_is_variant_of(Type *u, Type *v) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *vt = u->Union.variants[i];
|
||||
if (union_variant_index_types_equal(v, vt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gb_internal i64 union_tag_size(Type *u) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
|
||||
Reference in New Issue
Block a user