mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-22 14:25:21 +00:00
Allow unions with one variant to be constant
This commit is contained in:
@@ -1565,7 +1565,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
|
||||
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
|
||||
@@ -3500,6 +3500,21 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_union_constantable(Type *type) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_Union);
|
||||
|
||||
|
||||
if (bt->Union.variants.count <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for (Type *v : bt->Union.variants) {
|
||||
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
|
||||
bool is_const_expr = x->mode == Addressing_Constant;
|
||||
|
||||
@@ -3524,6 +3539,9 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
|
||||
} else if (is_type_slice(type) && is_type_string(x->type)) {
|
||||
x->mode = Addressing_Value;
|
||||
} else if (is_type_union(type)) {
|
||||
if (is_type_union_constantable(type)) {
|
||||
return true;
|
||||
}
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
if (x->mode == Addressing_Value) {
|
||||
@@ -3582,7 +3600,11 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb
|
||||
Type *final_type = type;
|
||||
if (is_const_expr && !is_type_constant_type(type)) {
|
||||
if (is_type_union(type)) {
|
||||
convert_to_typed(c, x, type);
|
||||
if (is_type_union_constantable(type)) {
|
||||
|
||||
} else {
|
||||
convert_to_typed(c, x, type);
|
||||
}
|
||||
}
|
||||
final_type = default_type(x->type);
|
||||
}
|
||||
@@ -8151,7 +8173,11 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
} else {
|
||||
// NOTE(bill): Otherwise the compiler can override the polymorphic type
|
||||
// as it assumes it is determining the type
|
||||
AddressingMode old_mode = operand->mode;
|
||||
check_cast(c, operand, t);
|
||||
if (old_mode == Addressing_Constant && old_mode != operand->mode) {
|
||||
gb_printf_err("HERE: %d -> %d %s\n", old_mode, operand->mode, expr_to_string(operand->expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
operand->type = t;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -2226,6 +2226,18 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
if (is_type_union_maybe_pointer(type)) {
|
||||
LLVMTypeRef variant = lb_type(m, type->Union.variants[0]);
|
||||
array_add(&fields, variant);
|
||||
} else if (type->Union.variants.count == 1) {
|
||||
LLVMTypeRef block_type = lb_type(m, type->Union.variants[0]);
|
||||
|
||||
LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
|
||||
array_add(&fields, block_type);
|
||||
array_add(&fields, tag_type);
|
||||
i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type);
|
||||
i64 padding = size - used_size;
|
||||
if (padding > 0) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align);
|
||||
array_add(&fields, padding_type);
|
||||
}
|
||||
} else {
|
||||
LLVMTypeRef block_type = nullptr;
|
||||
|
||||
@@ -3131,7 +3143,6 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
|
||||
lbValue *found = map_get(&target_module->values, e);
|
||||
rw_mutex_shared_unlock(&target_module->values_mutex);
|
||||
if (found == nullptr) {
|
||||
// THIS IS THE RACE CONDITION
|
||||
lbProcedure *missing_proc_in_target_module = lb_create_procedure(target_module, e, false);
|
||||
array_add(&target_module->missing_procedures_to_check, missing_proc_in_target_module);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user