mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-27 15:31:33 +00:00
Merge pull request #7087 from korvahkh/const-union-fixes
Implement fixes for constant unions
This commit is contained in:
@@ -689,7 +689,7 @@ gb_internal bool check_proc_params_assignable(CheckerContext *c, Type *x, Type *
|
||||
|
||||
#define MAXIMUM_TYPE_DISTANCE 10
|
||||
|
||||
gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type, bool allow_array_programming) {
|
||||
gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type, bool allow_array_programming, bool allow_unions=true) {
|
||||
if (c == nullptr) {
|
||||
GB_ASSERT(operand->mode == Addressing_Value);
|
||||
GB_ASSERT(is_type_typed(operand->type));
|
||||
@@ -895,7 +895,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_union(dst)) {
|
||||
if (is_type_union(dst) && allow_unions) {
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
if (are_types_identical(vt, s)) {
|
||||
return 1;
|
||||
@@ -917,7 +917,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
i64 prev_lowest_score = -1;
|
||||
i64 lowest_score = -1;
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
i64 score = check_distance_between_types(c, operand, vt, allow_array_programming);
|
||||
i64 score = check_distance_between_types(c, operand, vt, allow_array_programming, /*allow_unions*/false);
|
||||
if (score >= 0) {
|
||||
if (lowest_score < 0) {
|
||||
lowest_score = score;
|
||||
@@ -1035,7 +1035,7 @@ gb_internal i64 assign_score_function(i64 distance, bool is_variadic=false) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false, bool allow_array_programming=true) {
|
||||
gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false, bool allow_array_programming=true, bool allow_unions=true) {
|
||||
if (c == nullptr) {
|
||||
GB_ASSERT(operand->mode == Addressing_Value);
|
||||
GB_ASSERT(is_type_typed(operand->type));
|
||||
@@ -1045,7 +1045,7 @@ gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *o
|
||||
return false;
|
||||
}
|
||||
|
||||
i64 score = check_distance_between_types(c, operand, type, allow_array_programming);
|
||||
i64 score = check_distance_between_types(c, operand, type, allow_array_programming, allow_unions);
|
||||
if (score >= 0) {
|
||||
if (score_) *score_ = assign_score_function(score, is_variadic);
|
||||
return true;
|
||||
@@ -1159,7 +1159,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
|
||||
if (is_type_untyped(operand->type)) {
|
||||
Type *target_type = type;
|
||||
if (type == nullptr || is_type_any(type)) {
|
||||
Type *elem_type = core_broadcastable_elem_type(type);
|
||||
if (is_type_union(elem_type)) {
|
||||
target_type = elem_type;
|
||||
}
|
||||
if (type == nullptr || is_type_any(elem_type)) {
|
||||
if (type == nullptr && is_type_untyped_uninit(operand->type)) {
|
||||
String article = error_article(context_name); // Grab definite or indefinite article matching `context_name`, or "" if not found.
|
||||
|
||||
@@ -1252,6 +1256,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
}
|
||||
|
||||
if (check_is_assignable_to(c, operand, type)) {
|
||||
if (operand->mode == Addressing_Constant && type_conversion_is_variant(type, operand->type)) {
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, operand->expr, type);
|
||||
operand->value = exact_value_variant(operand->expr);
|
||||
}
|
||||
if (operand->mode == Addressing_Type && is_type_typeid(type)) {
|
||||
add_type_info_type(c, operand->type);
|
||||
add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
|
||||
@@ -3925,6 +3934,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
|
||||
x->mode = Addressing_Value;
|
||||
} else if (is_type_union(type)) {
|
||||
if (is_type_union_constantable(type)) {
|
||||
x->value = exact_value_variant(x->expr);
|
||||
return true;
|
||||
}
|
||||
x->mode = Addressing_Value;
|
||||
@@ -3991,8 +4001,9 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb
|
||||
if (is_type_untyped(x->type)) {
|
||||
Type *final_type = type;
|
||||
if (is_const_expr && !is_type_constant_type(type)) {
|
||||
if (is_type_union(type)) {
|
||||
convert_to_typed(c, x, type);
|
||||
Type *elem_type = core_broadcastable_elem_type(type);
|
||||
if (is_type_union(elem_type)) {
|
||||
convert_to_typed(c, x, elem_type);
|
||||
}
|
||||
final_type = default_type(x->type);
|
||||
}
|
||||
@@ -5185,11 +5196,12 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
case Type_Array: {
|
||||
Type *elem = base_array_type(t);
|
||||
if (check_is_assignable_to(c, operand, elem)) {
|
||||
while (is_type_array(elem)) {
|
||||
elem = base_array_type(elem);
|
||||
}
|
||||
elem = core_broadcastable_elem_type(elem);
|
||||
operand->mode = Addressing_Value;
|
||||
convert_to_typed(c, operand, elem, /*no_final_update*/true);
|
||||
if (is_type_union(elem)) {
|
||||
target_type = operand->type;
|
||||
}
|
||||
} else {
|
||||
if (operand->value.kind == ExactValue_String) {
|
||||
String s = operand->value.value_string;
|
||||
@@ -5294,7 +5306,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *vt = t->Union.variants[i];
|
||||
i64 score = 0;
|
||||
if (check_is_assignable_to_with_score(c, operand, vt, &score)) {
|
||||
if (check_is_assignable_to_with_score(c, operand, vt, &score, /*is_variadic*/false, /*allow_array_programming*/true, /*allow_unions*/t->Union.variants.count == 1)) {
|
||||
valids[valid_count].index = i;
|
||||
valids[valid_count].score = score;
|
||||
valid_count += 1;
|
||||
@@ -5328,7 +5340,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
convert_to_typed(c, operand, new_type, /*no_final_update*/true);
|
||||
target_type = new_type;
|
||||
target_type = operand->type;
|
||||
break;
|
||||
} else if (valid_count > 1) {
|
||||
ERROR_BLOCK();
|
||||
@@ -12851,8 +12863,21 @@ gb_internal ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, T
|
||||
}
|
||||
gb_string_free(xs);
|
||||
}
|
||||
if (o->type != nullptr && is_type_untyped(o->type)) {
|
||||
add_untyped(c, node, o->mode, o->type, o->value);
|
||||
if (o->type != nullptr) {
|
||||
if (type_hint != nullptr) {
|
||||
Type *elem_type = core_broadcastable_elem_type(type_hint);
|
||||
if (is_type_untyped(o->type)) {
|
||||
if (is_type_union(elem_type)) {
|
||||
convert_to_typed(c, o, elem_type);
|
||||
}
|
||||
}
|
||||
if (type_conversion_is_variant(elem_type, o->type)) {
|
||||
o->value.variant_type = o->type;
|
||||
}
|
||||
}
|
||||
if (is_type_untyped(o->type)) {
|
||||
add_untyped(c, node, o->mode, o->type, o->value);
|
||||
}
|
||||
}
|
||||
check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed");
|
||||
|
||||
@@ -12986,6 +13011,14 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) {
|
||||
return v.value_procedure == nullptr;
|
||||
case ExactValue_Typeid:
|
||||
return v.value_typeid == nullptr;
|
||||
case ExactValue_Variant:
|
||||
if (v.value_variant == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (v.value_variant->tav.mode != Addressing_Constant) {
|
||||
return false;
|
||||
}
|
||||
return is_exact_value_zero(v.value_variant->tav.value);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -13013,8 +13046,26 @@ gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, E
|
||||
return test;
|
||||
}
|
||||
|
||||
gb_internal bool compare_exact_values_variant(TokenKind op, ExactValue x, ExactValue y) {
|
||||
Ast *lhs = x.value_variant;
|
||||
Ast *rhs = y.value_variant;
|
||||
|
||||
return compare_exact_values(op, lhs->tav.value, rhs->tav.value);
|
||||
}
|
||||
|
||||
gb_internal void match_exact_values_variant(ExactValue *x, ExactValue *y) {
|
||||
GB_ASSERT(x->kind == ExactValue_Variant);
|
||||
while (x->value_variant != nullptr &&
|
||||
x->value_variant->tav.mode == Addressing_Constant) {
|
||||
*x = x->value_variant->tav.value;
|
||||
}
|
||||
while (y->kind == ExactValue_Variant &&
|
||||
y->value_variant != nullptr &&
|
||||
y->value_variant->tav.mode == Addressing_Constant) {
|
||||
*y = y->value_variant->tav.value;
|
||||
}
|
||||
match_exact_values(x, y);
|
||||
}
|
||||
|
||||
gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -3439,7 +3439,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
cc.link_section = e->Variable.link_section;
|
||||
|
||||
ExactValue v = tav.value;
|
||||
lbValue init = lb_const_value(m, e->type, v, lb_build_expr_original_const_type(decl->init_expr), cc);
|
||||
lbValue init = lb_const_value(m, e->type, v, cc);
|
||||
|
||||
|
||||
LLVMDeleteGlobal(g.value);
|
||||
|
||||
@@ -418,7 +418,7 @@ static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, {
|
||||
|
||||
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Type *value_type=nullptr, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT);
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT);
|
||||
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
|
||||
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeR
|
||||
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
|
||||
|
||||
if (force_non_named) {
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, true);
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, LLVMIsPackedStruct(t));
|
||||
}
|
||||
|
||||
bool failure = false;
|
||||
@@ -216,7 +216,7 @@ gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeR
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, true);
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, LLVMIsPackedStruct(t));
|
||||
}
|
||||
return LLVMConstNamedStruct(t, values, value_count);
|
||||
}
|
||||
@@ -582,13 +582,13 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel,
|
||||
return lb_is_elem_const(elem, ft);
|
||||
}
|
||||
|
||||
gb_internal void lb_const_array_spread(lbModule *m, lbConstContext cc, Type *array, ExactValue value, lbValue *res, Type *value_type) {
|
||||
gb_internal void lb_const_array_spread(lbModule *m, lbConstContext cc, Type *array, ExactValue value, lbValue *res) {
|
||||
GB_ASSERT(array->kind == Type_Array);
|
||||
|
||||
i64 count = array->Array.count;
|
||||
Type *elem = array->Array.elem;
|
||||
|
||||
lbValue single_elem = lb_const_value(m, elem, value, value_type, cc);
|
||||
lbValue single_elem = lb_const_value(m, elem, value, cc);
|
||||
|
||||
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count);
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
@@ -661,7 +661,7 @@ gb_internal lbValue lb_const_value_bit_field(lbModule *m, Type *type, Ast *value
|
||||
if (fv->value->tav.mode != Addressing_Constant) {
|
||||
continue;
|
||||
}
|
||||
lbValue field_expr = lb_const_value(m, field_type, fv->value->tav.value, field_type);
|
||||
lbValue field_expr = lb_const_value(m, field_type, fv->value->tav.value);
|
||||
array_add(&values, field_expr);
|
||||
array_add(&fields, FieldData{field_type, cast(u64)bit_offset, cast(u64)bit_size});
|
||||
}
|
||||
@@ -791,7 +791,7 @@ gb_internal lbValue lb_const_value_bit_field(lbModule *m, Type *type, Ast *value
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Type *value_type, lbConstContext cc) {
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) {
|
||||
if (cc.allow_local) {
|
||||
cc.is_rodata = false;
|
||||
}
|
||||
@@ -803,6 +803,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
lbValue res = {};
|
||||
res.type = original_type;
|
||||
while (value.kind == ExactValue_Variant &&
|
||||
(value.variant_type == nullptr ||
|
||||
are_types_identical(value.variant_type, original_type))) {
|
||||
value = value.value_variant->tav.value;
|
||||
}
|
||||
if (!is_type_bit_field(original_type)) {
|
||||
type = core_type(type);
|
||||
value = convert_exact_value_for_type(value, type);
|
||||
@@ -816,25 +821,36 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
GB_ASSERT(bt->kind == Type_Union);
|
||||
if (bt->Union.variants.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
} else if (bt->Union.variants.count == 1) {
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
if (cl->type == nullptr) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
if (are_types_identical(type_of_expr(cl->type), original_type)) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value_type == t_untyped_nil) {
|
||||
Type *value_type = value.variant_type;
|
||||
switch (value.kind) {
|
||||
case ExactValue_Invalid:
|
||||
return lb_const_nil(m, original_type);
|
||||
|
||||
case ExactValue_Compound: {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (value_type == nullptr || are_types_identical(value_type, original_type)) {
|
||||
GB_ASSERT(cl->elems.count == 0);
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExactValue_Variant:
|
||||
value = value.value_variant->tav.value;
|
||||
break;
|
||||
}
|
||||
GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value));
|
||||
GB_ASSERT(!are_types_identical(value_type, original_type));
|
||||
|
||||
if (value_type == t_untyped_nil) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
if (bt->Union.variants.count == 1) {
|
||||
Type *t = bt->Union.variants[0];
|
||||
lbValue cv = lb_const_value(m, t, value, value_type, cc);
|
||||
|
||||
lbValue cv = lb_const_value(m, t, value, cc);
|
||||
GB_ASSERT(LLVMIsConstant(cv.value));
|
||||
|
||||
LLVMTypeRef llvm_type = lb_type(m, original_type);
|
||||
@@ -870,51 +886,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
if (value_type == nullptr) {
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
value_type = type_of_expr(value.value_compound);
|
||||
} else if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
} else if (value_type == t_untyped_nil) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value));
|
||||
|
||||
// NOTE(korvahkh): forces calculation of variant_block_size
|
||||
type_size_of(bt);
|
||||
i64 block_size = bt->Union.variant_block_size;
|
||||
|
||||
while (are_types_identical(value_type, original_type)) {
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
value_type = type_of_expr(value.value_compound);
|
||||
if (!are_types_identical(value_type, original_type)) {
|
||||
break;
|
||||
}
|
||||
|
||||
GB_PANIC("%s --> %s vs %s",
|
||||
expr_to_string(value.value_compound),
|
||||
temp_canonical_string(value_type), temp_canonical_string(original_type));
|
||||
|
||||
} else if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
GB_PANIC("(value.kind=%s) %s vs %s",
|
||||
exact_value_kind_string[value.kind],
|
||||
temp_canonical_string(value_type), temp_canonical_string(original_type));
|
||||
}
|
||||
// union_multiple_allow_compound:;
|
||||
|
||||
lbValue cv = lb_const_value(m, value_type, value, value_type, cc);
|
||||
lbValue cv = lb_const_value(m, value_type, value, cc);
|
||||
Type *variant_type = cv.type;
|
||||
|
||||
LLVMValueRef values[4] = {};
|
||||
@@ -1015,7 +991,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
count = gb_max(cast(isize)cl->max_count, count);
|
||||
Type *elem = base_type(type)->Slice.elem;
|
||||
Type *t = alloc_type_array(elem, count);
|
||||
lbValue backing_array = lb_const_value(m, t, value, nullptr, cc);
|
||||
lbValue backing_array = lb_const_value(m, t, value, cc);
|
||||
|
||||
LLVMValueRef array_data = nullptr;
|
||||
|
||||
@@ -1154,7 +1130,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
value.kind != ExactValue_Invalid &&
|
||||
value.kind != ExactValue_Compound) {
|
||||
|
||||
lb_const_array_spread(m, cc, type, value, &res, value_type);
|
||||
lb_const_array_spread(m, cc, type, value, &res);
|
||||
return res;
|
||||
} else if (is_type_matrix(type) &&
|
||||
value.kind != ExactValue_Invalid &&
|
||||
@@ -1165,7 +1141,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
Type *elem = type->Matrix.elem;
|
||||
|
||||
lbValue single_elem = lb_const_value(m, elem, value, value_type, cc);
|
||||
lbValue single_elem = lb_const_value(m, elem, value, cc);
|
||||
single_elem.value = llvm_const_cast(m, single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
|
||||
|
||||
i64 total_elem_count = matrix_type_total_internal_elems(type);
|
||||
@@ -1187,7 +1163,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 count = type->SimdVector.count;
|
||||
Type *elem = type->SimdVector.elem;
|
||||
|
||||
lbValue single_elem = lb_const_value(m, elem, value, value_type, cc);
|
||||
lbValue single_elem = lb_const_value(m, elem, value, cc);
|
||||
single_elem.value = llvm_const_cast(m, single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
|
||||
|
||||
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count);
|
||||
@@ -1374,7 +1350,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
if (is_type_bit_field(original_type)) {
|
||||
return lb_const_value_bit_field(m, original_type, value.value_compound);
|
||||
} else if (is_type_slice(type)) {
|
||||
return lb_const_value(m, type, value, value_type, cc);
|
||||
return lb_const_value(m, type, value, cc);
|
||||
} else if (is_type_soa_struct(type)) {
|
||||
GB_ASSERT(type->kind == Type_Struct);
|
||||
GB_ASSERT(type->Struct.soa_kind == StructSoa_Fixed);
|
||||
@@ -1415,7 +1391,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
aos_values[value_index++] = val;
|
||||
}
|
||||
@@ -1430,7 +1406,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
aos_values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1485,7 +1461,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
aos_values[i] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
for (isize i = elem_count; i < type->Struct.soa_count; i++) {
|
||||
aos_values[i] = nullptr;
|
||||
@@ -1533,7 +1509,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
|
||||
|
||||
for (isize i = 0; i < type->Array.count; i++) {
|
||||
values[i] = lb_const_value(m, elem_type, value, elem_type, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, value, cc).value;
|
||||
}
|
||||
|
||||
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
|
||||
@@ -1564,7 +1540,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1579,7 +1555,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1607,7 +1583,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
if (is_type_tuple(tav.type)) {
|
||||
elem_index += tav.type->Tuple.variables.count;
|
||||
} else {
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < type->Array.count; i++) {
|
||||
@@ -1656,7 +1632,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1671,7 +1647,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1699,7 +1675,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
if (is_type_tuple(tav.type)) {
|
||||
elem_index += tav.type->Tuple.variables.count;
|
||||
} else {
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < type->EnumeratedArray.count; i++) {
|
||||
@@ -1748,7 +1724,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1766,7 +1742,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1790,7 +1766,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)capacity);
|
||||
|
||||
for (isize i = 0; i < capacity; i++) {
|
||||
values[i] = lb_const_value(m, elem_type, value, elem_type, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, value, cc).value;
|
||||
}
|
||||
|
||||
res.value = lb_fill_fixed_capacity_dynamic_array(m, capacity, original_type, values, cc);
|
||||
@@ -1808,7 +1784,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
if (is_type_tuple(tav.type)) {
|
||||
elem_index += tav.type->Tuple.variables.count;
|
||||
} else {
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
values[elem_index++] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < capacity; i++) {
|
||||
@@ -1856,7 +1832,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1871,7 +1847,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1890,7 +1866,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
LLVMTypeRef et = lb_type(m, elem_type);
|
||||
|
||||
@@ -1920,7 +1896,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
if (tav.value.kind != ExactValue_Invalid) {
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, f->type, cc);
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc);
|
||||
|
||||
LLVMValueRef values[2];
|
||||
unsigned value_count = 0;
|
||||
@@ -1975,7 +1951,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i32 index = field_remapping[f->Variable.field_index];
|
||||
if (elem_type_can_be_constant(f->type)) {
|
||||
if (sel.index.count == 1) {
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, lb_build_expr_original_const_type(fv->value), cc);
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc);
|
||||
LLVMTypeRef value_type = LLVMTypeOf(value.value);
|
||||
GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type));
|
||||
values[index] = value.value;
|
||||
@@ -1984,7 +1960,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
if (!visited[index]) {
|
||||
auto new_cc = cc;
|
||||
new_cc.allow_local = false;
|
||||
values[index] = lb_const_value(m, f->type, {}, nullptr, new_cc).value;
|
||||
values[index] = lb_const_value(m, f->type, {}, new_cc).value;
|
||||
visited[index] = true;
|
||||
}
|
||||
|
||||
@@ -2023,7 +1999,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
}
|
||||
}
|
||||
if (is_constant) {
|
||||
LLVMValueRef elem_value = lb_const_value(m, cv_type, tav.value, tav.type, cc).value;
|
||||
LLVMValueRef elem_value = lb_const_value(m, cv_type, tav.value, cc).value;
|
||||
if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) {
|
||||
if (is_type_union(cv_type) || is_type_raw_union(cv_type)) {
|
||||
force_non_named = true;
|
||||
@@ -2085,7 +2061,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
|
||||
if (elem_type_can_be_constant(f->type)) {
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc);
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc);
|
||||
LLVMTypeRef value_type = LLVMTypeOf(value.value);
|
||||
isize lb_sizeof_value_type = lb_sizeof(value_type);
|
||||
isize type_size_of_f_type = type_size_of(f->type);
|
||||
@@ -2226,7 +2202,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
|
||||
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
i64 offset = matrix_row_major_index_to_offset(type, k);
|
||||
GB_ASSERT(values[offset] == nullptr);
|
||||
@@ -2238,7 +2214,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
GB_ASSERT(index < max_count);
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(fv->value), cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
i64 offset = matrix_row_major_index_to_offset(type, index);
|
||||
GB_ASSERT(values[offset] == nullptr);
|
||||
values[offset] = val;
|
||||
@@ -2262,7 +2238,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
i64 offset = 0;
|
||||
offset = matrix_row_major_index_to_offset(type, i);
|
||||
values[offset] = lb_const_value(m, elem_type, tav.value, lb_build_expr_original_const_type(cl->elems[i]), cc).value;
|
||||
values[offset] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
for (isize i = 0; i < total_count; i++) {
|
||||
if (values[i] == nullptr) {
|
||||
|
||||
@@ -3207,7 +3207,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
Type *elem = base_array_type(dst);
|
||||
lbValue e = lb_emit_conv(p, value, elem);
|
||||
lbAddr v = lb_add_local_generated(p, t, false);
|
||||
lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), elem, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
|
||||
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
|
||||
lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j);
|
||||
@@ -3244,7 +3244,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
lb_emit_store(p, d, s);
|
||||
} else if (i == j) {
|
||||
lbValue d = lb_emit_matrix_epi(p, v.addr, i, j);
|
||||
lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), dst->Matrix.elem, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
lb_emit_store(p, d, s);
|
||||
}
|
||||
}
|
||||
@@ -3439,11 +3439,12 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
|
||||
|
||||
if (are_types_identical(a, b)) {
|
||||
// NOTE(bill): No need for a conversion
|
||||
} else if ((lb_is_const(left) && !is_type_array(left.type)) || lb_is_const_nil(left)) {
|
||||
} else if ((lb_is_const(left) && !is_type_array(left.type) && !is_type_union(left.type)) || lb_is_const_nil(left)) {
|
||||
// NOTE(karl): !is_type_array(left.type) is there to avoid lb_emit_conv
|
||||
// trying to convert a constant array into a non-array. In that case we
|
||||
// want the `else` branch to happen, so it can try to convert the
|
||||
// non-array into an array instead.
|
||||
// NOTE(korvahkh): We also need !is_type_union(left.type).
|
||||
|
||||
if (lb_is_const_nil(left)) {
|
||||
if (internal_check_is_assignable_to(right.type, left.type)) {
|
||||
@@ -3454,7 +3455,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
|
||||
}
|
||||
}
|
||||
left = lb_emit_conv(p, left, right.type);
|
||||
} else if ((lb_is_const(right) && !is_type_array(right.type)) || lb_is_const_nil(right)) {
|
||||
} else if ((lb_is_const(right) && !is_type_array(right.type) && !is_type_union(right.type)) || lb_is_const_nil(right)) {
|
||||
|
||||
if (lb_is_const_nil(right)) {
|
||||
if (internal_check_is_assignable_to(left.type, right.type)) {
|
||||
@@ -4462,28 +4463,6 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
gb_internal Type *lb_build_expr_original_const_type(Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
Type *type = type_of_expr(expr);
|
||||
if (is_type_union(type)) {
|
||||
if (expr->kind == Ast_CallExpr) {
|
||||
if (expr->CallExpr.proc->tav.mode == Addressing_Type) {
|
||||
Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]);
|
||||
return res;
|
||||
}
|
||||
} else if (expr->kind == Ast_Ident || expr->kind == Ast_SelectorExpr) {
|
||||
// a named constant carries the union as its type, so follow it to the declaration the
|
||||
// checker resolved: `C :: U(3)` is the variant `int`, not `U`
|
||||
Entity *e = entity_of_node(expr);
|
||||
if (e != nullptr && e->kind == Entity_Constant &&
|
||||
e->decl_info != nullptr && e->decl_info->init_expr != nullptr) {
|
||||
return lb_build_expr_original_const_type(e->decl_info->init_expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return type_of_expr(expr);
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
@@ -4496,9 +4475,8 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
|
||||
if (tv.value.kind != ExactValue_Invalid) {
|
||||
Type *original_type = lb_build_expr_original_const_type(expr);
|
||||
// NOTE(bill): Short on constant values
|
||||
return lb_const_value(p->module, type, tv.value, original_type, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
} else if (tv.mode == Addressing_Type) {
|
||||
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
|
||||
return lb_typeid(m, tv.type);
|
||||
@@ -4579,7 +4557,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
GB_ASSERT(tav.mode == Addressing_Constant);
|
||||
|
||||
return lb_const_value(p->module, type, tv.value, tv.type, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SelectorCallExpr, expr);
|
||||
@@ -4862,7 +4840,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->kind == Entity_Constant) {
|
||||
Type *t = default_type(type_of_expr(expr));
|
||||
lbValue v = lb_const_value(p->module, t, e->Constant.value, lb_build_expr_original_const_type(expr), LB_CONST_CONTEXT_DEFAULT_NO_LOCAL);
|
||||
lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL);
|
||||
if (LLVMIsConstant(v.value)) {
|
||||
lbAddr g = lb_add_global_generated_from_procedure(p, t, v);
|
||||
return g;
|
||||
|
||||
@@ -2434,7 +2434,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
if (e->Variable.is_rodata) {
|
||||
cc.is_rodata = true;
|
||||
}
|
||||
value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, nullptr, cc);
|
||||
value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, cc);
|
||||
}
|
||||
|
||||
String mangled_name = {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -52,3 +52,195 @@ union_constant_as_a_global_initializer :: proc(t: ^testing.T) {
|
||||
if v, ok := G.(int); testing.expect(t, ok, "global lost its variant") { testing.expect_value(t, v, 3) }
|
||||
if v, ok := GS.(string); testing.expect(t, ok, "string global lost its variant") { testing.expect_value(t, v, "hello") }
|
||||
}
|
||||
|
||||
A :: union {B, bool}
|
||||
B :: union {C, int }
|
||||
C :: struct{}
|
||||
|
||||
@(test)
|
||||
union_const_access :: proc(t: ^testing.T) {
|
||||
X :: struct{x: A}{B(C{})}
|
||||
testing.expect_value(t, X.x, A(B(C{})))
|
||||
|
||||
E :: enum {y}
|
||||
Y : [E]A : {.y = true}
|
||||
testing.expect_value(t, Y[.y], A(true))
|
||||
}
|
||||
|
||||
@(test)
|
||||
nested_union_implicit_cast :: proc(t: ^testing.T) {
|
||||
Av: A: Bv
|
||||
Bv: B: Cv
|
||||
Cv: C: {}
|
||||
testing.expect_value(t, Av, A(B(C{})))
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_ternary :: proc(t: ^testing.T) {
|
||||
E0 : A = B(C{}) if true else B(C{})
|
||||
E1 : A = true if true else true
|
||||
E2 := A(B(C{}) if true else B(C{}))
|
||||
E3 := A(true if true else true)
|
||||
|
||||
testing.expect_value(t, E0, A(B(C{})))
|
||||
testing.expect_value(t, E1, A(true))
|
||||
testing.expect_value(t, E2, A(B(C{})))
|
||||
testing.expect_value(t, E3, A(true))
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_array :: proc(t: ^testing.T) {
|
||||
C0: [2][2]A: B(C{})
|
||||
C1: struct {x: [2][2]A} : {B(C{})}
|
||||
testing.expect_value(t, C0, [2][2]A{0..<2 = B(C{})})
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_multi_level_cast :: proc(t: ^testing.T) {
|
||||
UI :: union {int, bool}
|
||||
foo: Maybe(UI): 1
|
||||
bar: union{UI}: 2
|
||||
baz: UI: 3
|
||||
qux: struct{ui: UI}: {4}
|
||||
testing.expect_value(t, foo, 1)
|
||||
testing.expect_value(t, bar, 2)
|
||||
testing.expect_value(t, baz, 3)
|
||||
testing.expect_value(t, qux.ui, 4)
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_args :: proc(t: ^testing.T) {
|
||||
implicit_bool :: proc(a: A = true ) -> A { return a.(bool) }
|
||||
explicit_bool :: proc(a: A = A(true)) -> A { return a.(bool) }
|
||||
nil_union :: proc(a: A = B{} ) -> A { return a.(B ) }
|
||||
struct_union :: proc(a: A = B(C{}) ) -> A { return a.(B ) }
|
||||
|
||||
testing.expect_value(t, implicit_bool(), true)
|
||||
testing.expect_value(t, explicit_bool(), true)
|
||||
testing.expect_value(t, nil_union (), B{})
|
||||
testing.expect_value(t, struct_union (), B(C{}))
|
||||
|
||||
testing.expect_value(t, implicit_bool(true ), true)
|
||||
testing.expect_value(t, explicit_bool(A(true)), true)
|
||||
testing.expect_value(t, nil_union (B{} ), B{})
|
||||
testing.expect_value(t, struct_union (B(C{}) ), B(C{}))
|
||||
|
||||
testing.expect_value(t, implicit_bool(a=true ), true)
|
||||
testing.expect_value(t, explicit_bool(a=A(true)), true)
|
||||
testing.expect_value(t, nil_union (a=B{} ), B{})
|
||||
testing.expect_value(t, struct_union (a=B(C{}) ), B(C{}))
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_in_aggregates :: proc(t: ^testing.T) {
|
||||
S :: struct {
|
||||
x : union { int, string },
|
||||
y : u128,
|
||||
}
|
||||
U :: struct #packed {v: [2]S, n: i64}
|
||||
V :: struct {x: [dynamic; 2]S}
|
||||
|
||||
s := [dynamic; 2]S { {x=1} }
|
||||
u := U { {{x=1}, {x=2}}, 2 }
|
||||
v := V{x = { {x=1} }}
|
||||
|
||||
testing.expect_value(t, s [0], S{x=1})
|
||||
testing.expect_value(t, u.v[1], S{x=2})
|
||||
testing.expect_value(t, v.x[0], S{x=1})
|
||||
}
|
||||
|
||||
@(test)
|
||||
union_named_constants :: proc(t: ^testing.T) {
|
||||
Inner_Left :: enum {
|
||||
a,
|
||||
b,
|
||||
}
|
||||
|
||||
Inner_Right :: enum {
|
||||
c,
|
||||
d,
|
||||
}
|
||||
|
||||
Inner :: union {
|
||||
Inner_Left,
|
||||
Inner_Right,
|
||||
}
|
||||
|
||||
Outer :: union {
|
||||
Inner,
|
||||
int,
|
||||
}
|
||||
|
||||
Atom :: struct {
|
||||
token: Outer,
|
||||
}
|
||||
|
||||
Promoted_Value :: union {
|
||||
int,
|
||||
f32,
|
||||
string,
|
||||
}
|
||||
|
||||
Promoted_Inner :: struct {
|
||||
value: Promoted_Value,
|
||||
padding0: int,
|
||||
padding1: int,
|
||||
}
|
||||
|
||||
Promoted_Outer :: struct {
|
||||
using inner: Promoted_Inner,
|
||||
}
|
||||
|
||||
NAMED_INNER :: Inner(Inner_Left.a)
|
||||
|
||||
DIRECT_ATOMS :: [?]Atom{{token = Inner(Inner_Left.a)}}
|
||||
|
||||
NAMED_ATOMS :: [?]Atom{{token = NAMED_INNER}}
|
||||
|
||||
INDEXED_OUTERS :: [1]Outer {
|
||||
0 = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
RANGED_OUTERS :: [1]Outer {
|
||||
0..=0 = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
Outer_Index :: enum {first}
|
||||
|
||||
ENUMERATED_OUTERS :: [Outer_Index]Outer {
|
||||
.first = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
RANGED_ENUMERATED_OUTERS :: [Outer_Index]Outer {
|
||||
.first..=.first = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{
|
||||
0 = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
RANGED_FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{
|
||||
0..=0 = Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
POSITIONAL_FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{
|
||||
Inner(Inner_Left.a),
|
||||
}
|
||||
|
||||
testing.expect_value(t, DIRECT_ATOMS[0], Atom{token = Inner(.a)})
|
||||
testing.expect_value(t, NAMED_ATOMS[0], Atom{token = NAMED_INNER})
|
||||
testing.expect_value(t, INDEXED_OUTERS[0], Inner(.a))
|
||||
testing.expect_value(t, RANGED_OUTERS[0], Inner(.a))
|
||||
testing.expect_value(t, ENUMERATED_OUTERS[.first], Inner(.a))
|
||||
testing.expect_value(t, RANGED_ENUMERATED_OUTERS[.first], Inner(.a))
|
||||
fco := FIXED_CAPACITY_OUTERS
|
||||
rfco := RANGED_FIXED_CAPACITY_OUTERS
|
||||
testing.expect_value(t, fco[0], Inner(.a))
|
||||
testing.expect_value(t, rfco[0], Inner(.a))
|
||||
testing.expect_value(t, POSITIONAL_FIXED_CAPACITY_OUTERS[0], Inner(.a))
|
||||
testing.expect_value(t, Promoted_Outer {
|
||||
value = Promoted_Value(int(1)),
|
||||
}, Promoted_Outer {
|
||||
inner = {Promoted_Value(int(1)), 0, 0},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user