aboutsummaryrefslogtreecommitdiff
path: root/src/types.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2020-02-01 11:10:28 +0000
committergingerBill <bill@gingerbill.org>2020-02-01 11:10:28 +0000
commit0f399a72941c7cebcb5ad0580a9d94d1a7a37ac0 (patch)
tree249d37e76b25472674b4a8e7cb8aabec1ba6ab02 /src/types.cpp
parent4bcb667e97fc84d3eb5d7d4df34d566baddfaa1c (diff)
Add `union #maybe`
Diffstat (limited to 'src/types.cpp')
-rw-r--r--src/types.cpp51
1 files changed, 44 insertions, 7 deletions
diff --git a/src/types.cpp b/src/types.cpp
index e120c77c0..d2a040b0b 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -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;
+
+ 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;
- return align_formula(size + tag_size, align);
+ size += tag_size;
+ }
+ return align_formula(size, align);
} break;