Allow unions with one variant to be constant

This commit is contained in:
gingerBill
2025-09-19 11:56:44 +01:00
parent 1a4da5cb0f
commit 6338e0a8a3
4 changed files with 82 additions and 4 deletions
+42 -1
View File
@@ -168,7 +168,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
return llvm_const_named_struct_internal(struct_type, values, value_count_);
}
Type *bt = base_type(t);
GB_ASSERT(bt->kind == Type_Struct);
GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union);
GB_ASSERT(value_count_ == bt->Struct.fields.count);
@@ -585,6 +585,47 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
bool is_local = cc.allow_local && m->curr_procedure != nullptr;
if (is_type_union(type) && is_type_union_constantable(type)) {
Type *bt = base_type(type);
GB_ASSERT(bt->kind == Type_Union);
GB_ASSERT(bt->Union.variants.count <= 1);
if (bt->Union.variants.count == 0) {
return lb_const_nil(m, original_type);
} else if (bt->Union.variants.count == 1) {
Type *t = bt->Union.variants[0];
lbValue cv = lb_const_value(m, t, value, cc);
GB_ASSERT(LLVMIsConstant(cv.value));
LLVMTypeRef llvm_type = lb_type(m, original_type);
if (is_type_union_maybe_pointer(type)) {
LLVMValueRef values[1] = {cv.value};
res.value = llvm_const_named_struct_internal(llvm_type, values, 1);
res.type = original_type;
return res;
} else {
unsigned tag_value = 1;
if (bt->Union.kind == UnionType_no_nil) {
tag_value = 0;
}
LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false);
LLVMValueRef padding = nullptr;
LLVMValueRef values[3] = {cv.value, tag, padding};
isize value_count = 2;
if (LLVMCountStructElementTypes(llvm_type) > 2) {
value_count = 3;
padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2));
}
res.value = llvm_const_named_struct_internal(llvm_type, values, value_count);
res.type = original_type;
return res;
}
}
}
// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
if (is_type_slice(type)) {