mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-13 06:41:26 -07:00
Add union #maybe
This commit is contained in:
+12
-1
@@ -1525,10 +1525,21 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if info.maybe && len(info.variants) == 1 && reflect.is_pointer(info.variants[0]) {
|
||||
if v.data == nil {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
} else {
|
||||
id := info.variants[0].id;
|
||||
fmt_arg(fi, any{v.data, id}, verb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tag: i64 = -1;
|
||||
tag_ptr := uintptr(v.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||
|
||||
tag: i64 = -1;
|
||||
switch i in tag_any {
|
||||
case u8: tag = i64(i);
|
||||
case i8: tag = i64(i);
|
||||
|
||||
@@ -111,6 +111,7 @@ Type_Info_Union :: struct {
|
||||
tag_type: ^Type_Info,
|
||||
custom_align: bool,
|
||||
no_nil: bool,
|
||||
maybe: bool,
|
||||
};
|
||||
Type_Info_Enum :: struct {
|
||||
base: ^Type_Info,
|
||||
@@ -1131,7 +1132,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
|
||||
array.allocator = context.allocator;
|
||||
}
|
||||
assert(array.allocator.procedure != nil);
|
||||
|
||||
|
||||
if cap <= array.cap do return true;
|
||||
|
||||
old_size := array.cap * elem_size;
|
||||
|
||||
@@ -1907,6 +1907,28 @@ constant_literal_expressions :: proc() {
|
||||
fmt.println(STRING_CONST[3:][:4]);
|
||||
}
|
||||
|
||||
union_maybe :: proc() {
|
||||
fmt.println("\n#union #maybe");
|
||||
|
||||
Maybe :: union(T: typeid) #maybe {T};
|
||||
|
||||
i: Maybe(u8);
|
||||
p: Maybe(^u8); // No tag is stored for pointers, nil is the sentinel value
|
||||
|
||||
#assert(size_of(i) == size_of(u8) + size_of(u8));
|
||||
#assert(size_of(p) == size_of(^u8));
|
||||
|
||||
i = 123;
|
||||
x := i.?;
|
||||
y, y_ok := p.?;
|
||||
p = &x;
|
||||
z, z_ok := p.?;
|
||||
|
||||
fmt.println(i, p);
|
||||
fmt.println(x, &x);
|
||||
fmt.println(y, y_ok);
|
||||
fmt.println(z, z_ok);
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
@@ -1937,5 +1959,6 @@ main :: proc() {
|
||||
threading_example();
|
||||
soa_struct_layout();
|
||||
constant_literal_expressions();
|
||||
union_maybe();
|
||||
}
|
||||
}
|
||||
|
||||
+61
-37
@@ -8572,8 +8572,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
Type *t = check_type(c, ta->type);
|
||||
|
||||
if (o->mode == Addressing_Constant) {
|
||||
gbString expr_str = expr_to_string(o->expr);
|
||||
error(o->expr, "A type assertion cannot be applied to a constant expression: '%s'", expr_str);
|
||||
@@ -8594,54 +8592,80 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
|
||||
bool src_is_ptr = is_type_pointer(o->type);
|
||||
Type *src = type_deref(o->type);
|
||||
Type *dst = t;
|
||||
Type *bsrc = base_type(src);
|
||||
Type *bdst = base_type(dst);
|
||||
|
||||
|
||||
if (is_type_union(src)) {
|
||||
bool ok = false;
|
||||
for_array(i, bsrc->Union.variants) {
|
||||
Type *vt = bsrc->Union.variants[i];
|
||||
if (are_types_identical(vt, dst)) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
if (ta->type != nullptr && ta->type->kind == Ast_UnaryExpr && ta->type->UnaryExpr.op.kind == Token_Question) {
|
||||
if (!is_type_union(src)) {
|
||||
gbString str = type_to_string(o->type);
|
||||
error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %s", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
gbString expr_str = expr_to_string(o->expr);
|
||||
gbString dst_type_str = type_to_string(t);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(dst_type_str));
|
||||
if (bsrc->Union.variants.count == 0) {
|
||||
error(o->expr, "Cannot type assert '%s' to '%s' as this is an empty union", expr_str, dst_type_str);
|
||||
} else {
|
||||
error(o->expr, "Cannot type assert '%s' to '%s' as it is not a variant of that union", expr_str, dst_type_str);
|
||||
}
|
||||
if (bsrc->Union.variants.count != 1) {
|
||||
error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %lld", cast(long long)bsrc->Union.variants.count);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
|
||||
add_type_info_type(c, o->type);
|
||||
add_type_info_type(c, t);
|
||||
add_type_info_type(c, bsrc->Union.variants[0]);
|
||||
|
||||
o->type = t;
|
||||
o->type = bsrc->Union.variants[0];
|
||||
o->mode = Addressing_OptionalOk;
|
||||
} else if (is_type_any(src)) {
|
||||
o->type = t;
|
||||
o->mode = Addressing_OptionalOk;
|
||||
|
||||
add_type_info_type(c, o->type);
|
||||
add_type_info_type(c, t);
|
||||
} else {
|
||||
gbString str = type_to_string(o->type);
|
||||
error(o->expr, "Type assertions can only operate on unions and 'any', got %s", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
Type *t = check_type(c, ta->type);
|
||||
Type *dst = t;
|
||||
Type *bdst = base_type(dst);
|
||||
|
||||
|
||||
if (is_type_union(src)) {
|
||||
bool ok = false;
|
||||
for_array(i, bsrc->Union.variants) {
|
||||
Type *vt = bsrc->Union.variants[i];
|
||||
if (are_types_identical(vt, dst)) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
gbString expr_str = expr_to_string(o->expr);
|
||||
gbString dst_type_str = type_to_string(t);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(dst_type_str));
|
||||
if (bsrc->Union.variants.count == 0) {
|
||||
error(o->expr, "Cannot type assert '%s' to '%s' as this is an empty union", expr_str, dst_type_str);
|
||||
} else {
|
||||
error(o->expr, "Cannot type assert '%s' to '%s' as it is not a variant of that union", expr_str, dst_type_str);
|
||||
}
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
|
||||
add_type_info_type(c, o->type);
|
||||
add_type_info_type(c, t);
|
||||
|
||||
o->type = t;
|
||||
o->mode = Addressing_OptionalOk;
|
||||
} else if (is_type_any(src)) {
|
||||
o->type = t;
|
||||
o->mode = Addressing_OptionalOk;
|
||||
|
||||
add_type_info_type(c, o->type);
|
||||
add_type_info_type(c, t);
|
||||
} else {
|
||||
gbString str = type_to_string(o->type);
|
||||
error(o->expr, "Type assertions can only operate on unions and 'any', got %s", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
add_package_dependency(c, "runtime", "type_assertion_check");
|
||||
|
||||
@@ -748,11 +748,17 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
|
||||
union_type->Union.variants = variants;
|
||||
union_type->Union.no_nil = ut->no_nil;
|
||||
union_type->Union.maybe = ut->maybe;
|
||||
if (union_type->Union.no_nil) {
|
||||
if (variants.count < 2) {
|
||||
error(ut->align, "A union with #no_nil must have at least 2 variants");
|
||||
}
|
||||
}
|
||||
if (union_type->Union.maybe) {
|
||||
if (variants.count != 1) {
|
||||
error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count);
|
||||
}
|
||||
}
|
||||
|
||||
if (ut->align != nullptr) {
|
||||
i64 custom_align = 1;
|
||||
|
||||
+47
-13
@@ -1222,7 +1222,11 @@ irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) {
|
||||
|
||||
// i->UnionTagPtr.type = alloc_type_pointer(t_type_info_ptr);
|
||||
Type *u = type_deref(ir_type(address));
|
||||
if (is_type_union_maybe_pointer(u)) {
|
||||
GB_PANIC("union #maybe UnionTagPtr");
|
||||
}
|
||||
i->UnionTagPtr.type = alloc_type_pointer(union_tag_type(u));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -1234,6 +1238,9 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) {
|
||||
if (address) address->uses += 1;
|
||||
|
||||
Type *u = type_deref(ir_type(address));
|
||||
if (is_type_union_maybe_pointer(u)) {
|
||||
GB_PANIC("union #maybe UnionTagValue");
|
||||
}
|
||||
i->UnionTagPtr.type = union_tag_type(u);
|
||||
return v;
|
||||
}
|
||||
@@ -4351,7 +4358,9 @@ irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) {
|
||||
|
||||
irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) {
|
||||
Type *t = ir_type(x);
|
||||
if (is_type_cstring(t)) {
|
||||
if (is_type_pointer(t)) {
|
||||
return ir_emit_comp(proc, op_kind, x, v_raw_nil);
|
||||
} else if (is_type_cstring(t)) {
|
||||
irValue *ptr = ir_emit_conv(proc, x, t_u8_ptr);
|
||||
return ir_emit_comp(proc, op_kind, ptr, v_raw_nil);
|
||||
} else if (is_type_any(t)) {
|
||||
@@ -5232,8 +5241,12 @@ void ir_emit_store_union_variant(irProcedure *proc, irValue *parent, irValue *va
|
||||
|
||||
Type *t = type_deref(ir_type(parent));
|
||||
|
||||
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
|
||||
ir_emit_store(proc, tag_ptr, ir_const_union_tag(t, variant_type));
|
||||
if (is_type_union_maybe_pointer(t)) {
|
||||
// No tag needed!
|
||||
} else {
|
||||
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
|
||||
ir_emit_store(proc, tag_ptr, ir_const_union_tag(t, variant_type));
|
||||
}
|
||||
}
|
||||
|
||||
irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
||||
@@ -5728,22 +5741,41 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
|
||||
GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type));
|
||||
Type *dst = tuple->Tuple.variables[0]->type;
|
||||
|
||||
|
||||
irValue *value_ = ir_address_from_load_or_generate_local(proc, value);
|
||||
irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_));
|
||||
irValue *dst_tag = ir_const_union_tag(src, dst);
|
||||
|
||||
|
||||
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
|
||||
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
|
||||
irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
||||
ir_emit_if(proc, cond, ok_block, end_block);
|
||||
ir_start_block(proc, ok_block);
|
||||
irValue *tag = nullptr;
|
||||
irValue *dst_tag = nullptr;
|
||||
irValue *cond = nullptr;
|
||||
irValue *data = nullptr;
|
||||
|
||||
irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
|
||||
irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
|
||||
|
||||
irValue *data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0)));
|
||||
if (is_type_union_maybe_pointer(src)) {
|
||||
data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0)));
|
||||
} else {
|
||||
tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_));
|
||||
dst_tag = ir_const_union_tag(src, dst);
|
||||
}
|
||||
|
||||
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
|
||||
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
|
||||
|
||||
if (data != nullptr) {
|
||||
GB_ASSERT(is_type_union_maybe_pointer(src));
|
||||
cond = ir_emit_comp_against_nil(proc, Token_NotEq, data);
|
||||
} else {
|
||||
cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
||||
}
|
||||
|
||||
ir_emit_if(proc, cond, ok_block, end_block);
|
||||
ir_start_block(proc, ok_block);
|
||||
|
||||
|
||||
|
||||
if (data == nullptr) {
|
||||
data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0)));
|
||||
}
|
||||
ir_emit_store(proc, gep0, data);
|
||||
ir_emit_store(proc, gep1, v_true);
|
||||
|
||||
@@ -11465,6 +11497,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
irValue *tag_type_ptr = ir_emit_struct_ep(proc, tag, 2);
|
||||
irValue *custom_align_ptr = ir_emit_struct_ep(proc, tag, 3);
|
||||
irValue *no_nil_ptr = ir_emit_struct_ep(proc, tag, 4);
|
||||
irValue *maybe_ptr = ir_emit_struct_ep(proc, tag, 5);
|
||||
|
||||
isize variant_count = gb_max(0, t->Union.variants.count);
|
||||
irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
|
||||
@@ -11494,6 +11527,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
ir_emit_store(proc, custom_align_ptr, is_custom_align);
|
||||
|
||||
ir_emit_store(proc, no_nil_ptr, ir_const_bool(t->Union.no_nil));
|
||||
ir_emit_store(proc, maybe_ptr, ir_const_bool(t->Union.maybe));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
+28
-4
@@ -508,13 +508,25 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 align = type_align_of(t);
|
||||
|
||||
if (is_type_union_maybe_pointer_original_alignment(t)) {
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_type(f, m, t->Union.variants[0]);
|
||||
ir_write_byte(f, '}');
|
||||
return;
|
||||
}
|
||||
|
||||
i64 block_size = t->Union.variant_block_size;
|
||||
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_alignment_prefix_hack(f, align);
|
||||
ir_fprintf(f, ", [%lld x i8], ", block_size);
|
||||
// ir_print_type(f, m, t_type_info_ptr);
|
||||
ir_print_type(f, m, union_tag_type(t));
|
||||
if (is_type_union_maybe_pointer(t)) {
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t->Union.variants[0]);
|
||||
} else {
|
||||
ir_fprintf(f, ", [%lld x i8], ", block_size);
|
||||
ir_print_type(f, m, union_tag_type(t));
|
||||
}
|
||||
ir_write_byte(f, '}');
|
||||
}
|
||||
return;
|
||||
@@ -1850,6 +1862,12 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
|
||||
case irInstr_UnionTagPtr: {
|
||||
Type *et = ir_type(instr->UnionTagPtr.address);
|
||||
|
||||
Type *ut = type_deref(et);
|
||||
if (is_type_union_maybe_pointer(ut)) {
|
||||
GB_PANIC("union #maybe UnionTagPtr");
|
||||
}
|
||||
|
||||
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
|
||||
Type *t = base_type(type_deref(et));
|
||||
GB_ASSERT(is_type_union(t));
|
||||
@@ -1869,10 +1887,16 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
|
||||
case irInstr_UnionTagValue: {
|
||||
Type *et = ir_type(instr->UnionTagValue.address);
|
||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||
Type *t = base_type(et);
|
||||
|
||||
if (is_type_union_maybe_pointer(t)) {
|
||||
GB_PANIC("union #maybe UnionTagValue");
|
||||
}
|
||||
|
||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||
GB_ASSERT(is_type_union(t));
|
||||
|
||||
|
||||
ir_print_type(f, m, et);
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_value(f, m, instr->UnionTagValue.address, et);
|
||||
|
||||
+20
-3
@@ -929,7 +929,7 @@ Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_c
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil,
|
||||
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_UnionType);
|
||||
result->UnionType.token = token;
|
||||
@@ -937,6 +937,7 @@ Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymor
|
||||
result->UnionType.polymorphic_params = polymorphic_params;
|
||||
result->UnionType.align = align;
|
||||
result->UnionType.no_nil = no_nil;
|
||||
result->UnionType.maybe = maybe;
|
||||
result->UnionType.where_token = where_token;
|
||||
result->UnionType.where_clauses = where_clauses;
|
||||
return result;
|
||||
@@ -2091,6 +2092,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Ast *polymorphic_params = nullptr;
|
||||
Ast *align = nullptr;
|
||||
bool no_nil = false;
|
||||
bool maybe = false;
|
||||
|
||||
CommentGroup *docs = f->lead_comment;
|
||||
Token start_token = f->curr_token;
|
||||
@@ -2118,10 +2120,19 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(tag, "Duplicate union tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
no_nil = true;
|
||||
} else {
|
||||
} else if (tag.string == "maybe") {
|
||||
if (maybe) {
|
||||
syntax_error(tag, "Duplicate union tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
maybe = true;
|
||||
}else {
|
||||
syntax_error(tag, "Invalid union tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
}
|
||||
if (no_nil && maybe) {
|
||||
syntax_error(f->curr_token, "#maybe and #no_nil cannot be applied together");
|
||||
}
|
||||
|
||||
|
||||
Token where_token = {};
|
||||
Array<Ast *> where_clauses = {};
|
||||
@@ -2150,7 +2161,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, where_token, where_clauses);
|
||||
return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, maybe, where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
case Token_enum: {
|
||||
@@ -2350,6 +2361,12 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
|
||||
operand = ast_type_assertion(f, operand, token, type);
|
||||
} break;
|
||||
|
||||
case Token_Question: {
|
||||
Token question = expect_token(f, Token_Question);
|
||||
Ast *type = ast_unary_expr(f, question, nullptr);
|
||||
operand = ast_type_assertion(f, operand, token, type);
|
||||
} break;
|
||||
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected a selector");
|
||||
advance_token(f);
|
||||
|
||||
@@ -515,6 +515,7 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
Array<Ast *> variants; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast * align; \
|
||||
bool maybe; \
|
||||
bool no_nil; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
|
||||
+44
-7
@@ -152,6 +152,7 @@ struct TypeUnion {
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
bool no_nil;
|
||||
bool maybe;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
};
|
||||
@@ -1219,6 +1220,32 @@ bool is_type_map(Type *t) {
|
||||
return t->kind == Type_Map;
|
||||
}
|
||||
|
||||
bool is_type_union_maybe_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Union && t->Union.maybe) {
|
||||
if (t->Union.variants.count == 1) {
|
||||
return is_type_pointer(t->Union.variants[0]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_union_maybe_pointer_original_alignment(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Union && t->Union.maybe) {
|
||||
if (t->Union.variants.count == 1) {
|
||||
Type *v = t->Union.variants[0];
|
||||
if (is_type_pointer(v)) {
|
||||
return type_align_of(v) == type_align_of(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool is_type_integer_endian_big(Type *t) {
|
||||
t = core_type(t);
|
||||
@@ -2024,6 +2051,7 @@ i64 union_tag_size(Type *u) {
|
||||
Type *union_tag_type(Type *u) {
|
||||
i64 s = union_tag_size(u);
|
||||
switch (s) {
|
||||
case 0: return t_u8;
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
@@ -2934,14 +2962,23 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): Align to tag
|
||||
i64 tag_size = union_tag_size(t);
|
||||
i64 size = align_formula(max, tag_size);
|
||||
// NOTE(bill): Calculate the padding between the common fields and the tag
|
||||
t->Union.tag_size = tag_size;
|
||||
t->Union.variant_block_size = size - field_size;
|
||||
i64 size = 0;
|
||||
|
||||
return align_formula(size + tag_size, align);
|
||||
if (is_type_union_maybe_pointer(t)) {
|
||||
size = max;
|
||||
t->Union.tag_size = 0;
|
||||
t->Union.variant_block_size = size;
|
||||
} else {
|
||||
// NOTE(bill): Align to tag
|
||||
i64 tag_size = union_tag_size(t);
|
||||
size = align_formula(max, tag_size);
|
||||
// NOTE(bill): Calculate the padding between the common fields and the tag
|
||||
t->Union.tag_size = tag_size;
|
||||
t->Union.variant_block_size = size - field_size;
|
||||
|
||||
size += tag_size;
|
||||
}
|
||||
return align_formula(size, align);
|
||||
} break;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user