Browse Source

Compiler Internal Changes: TypeRecord_Union -> Type_Union

Ginger Bill 8 years ago
parent
commit
ba5050ac7c
8 changed files with 209 additions and 293 deletions
  1. 0 5
      src/check_decl.cpp
  2. 17 21
      src/check_expr.cpp
  3. 2 2
      src/check_stmt.cpp
  4. 11 14
      src/checker.cpp
  5. 42 76
      src/ir.cpp
  6. 20 23
      src/ir_print.cpp
  7. 4 3
      src/ssa.cpp
  8. 113 149
      src/types.cpp

+ 0 - 5
src/check_decl.cpp

@@ -53,11 +53,6 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
 		if (is_type_bit_field_value(t)) {
 			t = default_bit_field_value_type(t);
 		}
-		if (is_type_variant(t)) {
-			Type *st = base_type(t);
-			GB_ASSERT(st->Record.variant_parent != nullptr);
-			t = st->Record.variant_parent;
-		}
 		GB_ASSERT(is_type_typed(t));
 		e->type = t;
 	}

+ 17 - 21
src/check_expr.cpp

@@ -499,8 +499,8 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 #endif
 
 	if (is_type_union(dst)) {
-		for (isize i = 0; i < dst->Record.variant_count; i++) {
-			Type *vt = dst->Record.variants[i];
+		for (isize i = 0; i < dst->Union.variant_count; i++) {
+			Type *vt = dst->Union.variants[i];
 			if (are_types_identical(vt, s)) {
 				return 1;
 			}
@@ -990,12 +990,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 	array_init(&variants, c->allocator, variant_count);
 	array_add(&variants, t_invalid);
 
-	union_type->Record.scope               = c->context.scope;
-	union_type->Record.are_offsets_set     = false;
-	union_type->Record.is_ordered          = true;
+	union_type->Union.scope               = c->context.scope;
 	{
 		Entity *__tag = make_entity_field(c->allocator, nullptr, make_token_ident(str_lit("__tag")), t_int, false, -1);
-		union_type->Record.union__tag = __tag;
+		union_type->Union.union__tag = __tag;
 	}
 
 	for_array(i, ut->variants) {
@@ -1016,11 +1014,8 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 		}
 	}
 
-	type_set_offsets(c->allocator, union_type);
-
-
-	union_type->Record.variants      = variants.data;
-	union_type->Record.variant_count = variants.count;
+	union_type->Union.variants      = variants.data;
+	union_type->Union.variant_count = variants.count;
 }
 
 void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
@@ -2549,7 +2544,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 		check_open_scope(c, e);
 		check_union_type(c, named_type, *type, e);
 		check_close_scope(c);
-		(*type)->Record.node = e;
+		(*type)->Union.node = e;
 		return true;
 	case_end;
 
@@ -6436,7 +6431,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 		Type *t = base_type(type);
 		switch (t->kind) {
 		case Type_Record: {
-			if (!is_type_struct(t) && !is_type_union(t)) {
+			if (is_type_union(t)) {
+				is_constant = false;
+			}
+			if (cl->elems.count == 0) {
+				break; // NOTE(bill): No need to init
+			}
+			if (!is_type_struct(t)) {
 				if (cl->elems.count != 0) {
 					gbString type_str = type_to_string(type);
 					error(node, "Illegal compound literal type `%s`", type_str);
@@ -6444,12 +6445,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 				}
 				break;
 			}
-			if (is_type_union(t)) {
-				is_constant = false;
-			}
-			if (cl->elems.count == 0) {
-				break; // NOTE(bill): No need to init
-			}
+
 			{ // Checker values
 				isize field_count = t->Record.field_count;
 				if (cl->elems[0]->kind == AstNode_FieldValue) {
@@ -6817,8 +6813,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 
 		if (is_type_union(src)) {
 			bool ok = false;
-			for (isize i = 1; i < bsrc->Record.variant_count; i++) {
-				Type *vt = bsrc->Record.variants[i];
+			for (isize i = 1; i < bsrc->Union.variant_count; i++) {
+				Type *vt = bsrc->Union.variants[i];
 				if (are_types_identical(vt, dst)) {
 					ok = true;
 					break;

+ 2 - 2
src/check_stmt.cpp

@@ -1473,8 +1473,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					if (match_type_kind == MatchType_Union) {
 						GB_ASSERT(is_type_union(bt));
 						bool tag_type_found = false;
-						for (isize i = 0; i < bt->Record.variant_count; i++) {
-							Type *vt = bt->Record.variants[i];
+						for (isize i = 0; i < bt->Union.variant_count; i++) {
+							Type *vt = bt->Union.variants[i];
 							if (are_types_identical(vt, y.type)) {
 								tag_type_found = true;
 								break;

+ 11 - 14
src/checker.cpp

@@ -1152,20 +1152,17 @@ void add_type_info_type(Checker *c, Type *t) {
 		add_type_info_type(c, bt->Enum.base_type);
 		break;
 
+	case Type_Union:
+		add_type_info_type(c, t_int);
+		for (isize i = 0; i < bt->Union.variant_count; i++) {
+			add_type_info_type(c, bt->Union.variants[i]);
+		}
+		break;
+
 	case Type_Record: {
-		switch (bt->Record.kind) {
-		case TypeRecord_Union:
-			add_type_info_type(c, t_int);
-			for (isize i = 0; i < bt->Record.variant_count; i++) {
-				add_type_info_type(c, bt->Record.variants[i]);
-			}
-			/* fallthrough */
-		default:
-			for (isize i = 0; i < bt->Record.field_count; i++) {
-				Entity *f = bt->Record.fields[i];
-				add_type_info_type(c, f->type);
-			}
-			break;
+		for (isize i = 0; i < bt->Record.field_count; i++) {
+			Entity *f = bt->Record.fields[i];
+			add_type_info_type(c, f->type);
 		}
 	} break;
 
@@ -1343,7 +1340,7 @@ void init_preload(Checker *c) {
 		Entity *type_info_variant = record->fields_in_src_order[2];
 		Type *tiv_type = type_info_variant->type;
 		GB_ASSERT(is_type_union(tiv_type));
-		TypeRecord *tiv = &tiv_type->Record;
+		TypeUnion *tiv = &tiv_type->Union;
 
 		if (tiv->variant_count != 23) {
 			compiler_error("Invalid `TypeInfo` layout");

+ 42 - 76
src/ir.cpp

@@ -2949,8 +2949,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 	}
 
 	if (is_type_union(dst)) {
-		for (isize i = 1; i < dst->Record.variant_count; i++) {
-			Type *vt = dst->Record.variants[i];
+		for (isize i = 1; i < dst->Union.variant_count; i++) {
+			Type *vt = dst->Union.variants[i];
 			if (are_types_identical(vt, src_type)) {
 				ir_emit_comment(proc, str_lit("union - child to parent"));
 				gbAllocator a = proc->module->allocator;
@@ -3290,8 +3290,8 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
 
 	irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_));
 	irValue *dst_tag = nullptr;
-	for (isize i = 1; i < src->Record.variant_count; i++) {
-		Type *vt = src->Record.variants[i];
+	for (isize i = 1; i < src->Union.variant_count; i++) {
+		Type *vt = src->Union.variants[i];
 		if (are_types_identical(vt, dst)) {
 			dst_tag = ir_const_int(a, i);
 			break;
@@ -6825,9 +6825,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 					Type *bt = type_deref(case_type);
 					irValue *index = nullptr;
 					Type *ut = base_type(type_deref(parent_type));
-					GB_ASSERT(ut->Record.kind == TypeRecord_Union);
-					for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
-						Type *vt = ut->Record.variants[variant_index];
+					GB_ASSERT(ut->kind == Type_Union);
+					for (isize variant_index = 1; variant_index < ut->Union.variant_count; variant_index++) {
+						Type *vt = ut->Union.variants[variant_index];
 						if (are_types_identical(vt, bt)) {
 							index = ir_const_int(allocator, variant_index);
 							break;
@@ -7232,16 +7232,15 @@ void ir_init_module(irModule *m, Checker *c) {
 				Type *t = cast(Type *)entry->key.ptr;
 
 				switch (t->kind) {
+				case Type_Union:
+					count += t->Union.variant_count;
+					break;
 				case Type_Record:
 					switch (t->Record.kind) {
 					case TypeRecord_Struct:
 					case TypeRecord_RawUnion:
 						count += t->Record.field_count;
 						break;
-					case TypeRecord_Union:
-						count += t->Record.field_count;
-						count += t->Record.variant_count;
-						break;
 					}
 					break;
 				case Type_Tuple:
@@ -8044,6 +8043,36 @@ void ir_gen_tree(irGen *s) {
 						}
 					}
 					break;
+
+				case Type_Union: {
+					ir_emit_comment(proc, str_lit("TypeInfoUnion"));
+					tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr);
+
+					{
+						irValue *variant_names = ir_emit_struct_ep(proc, tag, 1);
+						irValue *variant_types = ir_emit_struct_ep(proc, tag, 2);
+
+						isize variant_count = gb_max(0, t->Union.variant_count-1);
+						irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count);
+						irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
+
+						// NOTE(bill): Zeroth is nil so ignore it
+						for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
+							Type *vt = t->Union.variants[variant_index+1]; // Skip zeroth
+							irValue *tip = ir_get_type_info_ptr(proc, vt);
+
+							irValue *index     = ir_const_int(a, variant_index);
+							irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
+							ir_emit_store(proc, type_info, ir_type_info(proc, vt));
+						}
+
+						irValue *count = ir_const_int(a, variant_count);
+						ir_fill_slice(proc, variant_names, memory_names, count, count);
+						ir_fill_slice(proc, variant_types, memory_types, count, count);
+					}
+
+				} break;
+
 				case Type_Record: {
 					switch (t->Record.kind) {
 					case TypeRecord_Struct: {
@@ -8092,69 +8121,6 @@ void ir_gen_tree(irGen *s) {
 						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
 						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings,  count, count);
 					} break;
-					case TypeRecord_Union: {
-						ir_emit_comment(proc, str_lit("TypeInfoUnion"));
-						tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr);
-
-						{
-							irValue *common_fields = ir_emit_struct_ep(proc, tag, 0);
-
-							isize field_count = t->Record.field_count;
-							irValue *memory_types   = ir_type_info_member_types_offset(proc, field_count);
-							irValue *memory_names   = ir_type_info_member_names_offset(proc, field_count);
-							irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, field_count);
-
-							type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet
-							for (isize field_index = 0; field_index < field_count; field_index++) {
-								// TODO(bill): Order fields in source order not layout order
-								Entity *f = t->Record.fields[field_index];
-								irValue *tip = ir_get_type_info_ptr(proc, f->type);
-								i64 foffset = t->Record.offsets[f->Variable.field_index];
-								GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
-
-								irValue *index     = ir_const_int(a, field_index);
-								irValue *type_info = ir_emit_ptr_offset(proc, memory_types,   index);
-								irValue *offset    = ir_emit_ptr_offset(proc, memory_offsets, index);
-
-								ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
-								if (f->token.string.len > 0) {
-									irValue *name = ir_emit_ptr_offset(proc, memory_names,   index);
-									ir_emit_store(proc, name, ir_const_string(a, f->token.string));
-								}
-								ir_emit_store(proc, offset, ir_const_int(a, foffset));
-							}
-
-
-							irValue *count = ir_const_int(a, field_count);
-							ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types,   count, count);
-							ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names,   count, count);
-							ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, count, count);
-						}
-
-						{
-							irValue *variant_names = ir_emit_struct_ep(proc, tag, 1);
-							irValue *variant_types = ir_emit_struct_ep(proc, tag, 2);
-
-							isize variant_count = gb_max(0, t->Record.variant_count-1);
-							irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count);
-							irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
-
-							// NOTE(bill): Zeroth is nil so ignore it
-							for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
-								Type *vt = t->Record.variants[variant_index+1]; // Skip zeroth
-								irValue *tip = ir_get_type_info_ptr(proc, vt);
-
-								irValue *index     = ir_const_int(a, variant_index);
-								irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
-								ir_emit_store(proc, type_info, ir_type_info(proc, vt));
-							}
-
-							irValue *count = ir_const_int(a, variant_count);
-							ir_fill_slice(proc, variant_names, memory_names, count, count);
-							ir_fill_slice(proc, variant_types, memory_types, count, count);
-						}
-
-					} break;
 					case TypeRecord_RawUnion: {
 						ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
 						tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
@@ -8250,8 +8216,8 @@ void ir_gen_tree(irGen *s) {
 					Type *tiv = base_type(ti->Record.fields_in_src_order[2]->type);
 					GB_ASSERT(is_type_union(tiv));
 					bool found = false;
-					for (isize i = 1; i < tiv->Record.variant_count; i++) {
-						Type *vt = tiv->Record.variants[i];
+					for (isize i = 1; i < tiv->Union.variant_count; i++) {
+						Type *vt = tiv->Union.variants[i];
 						if (are_types_identical(vt, tag_type)) {
 							found = true;
 							irValue *tag_val = ir_const_int(a, i);

+ 20 - 23
src/ir_print.cpp

@@ -285,6 +285,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		ir_print_type(f, m, base_enum_type(t));
 		return;
 
+	case Type_Union: {
+		// 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(heap_allocator(), t);
+		i64 total_size = type_size_of(heap_allocator(), t);
+	#if 1
+		i64 block_size =  t->Union.variant_block_size;
+
+		ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
+		ir_fprintf(f, "[%lld x i8], ", block_size);
+		ir_fprintf(f, "i%lld}", word_bits);
+	#else
+		i64 block_size = total_size - build_context.word_size;
+		ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits);
+	#endif
+	} return;
+
 	case Type_Record: {
 		switch (t->Record.kind) {
 		case TypeRecord_Struct:
@@ -309,26 +326,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 				ir_fprintf(f, ">");
 			}
 			return;
-		case TypeRecord_Union: {
-			// 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(heap_allocator(), t);
-			i64 total_size = type_size_of(heap_allocator(), t);
-		#if 1
-			i64 block_size =  t->Record.variant_block_size;
-
-			ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
-			for (isize i = 0; i < t->Record.field_count; i++) {
-				ir_print_type(f, m, t->Record.fields[i]->type);
-				ir_fprintf(f, ", ");
-			}
-			ir_fprintf(f, "[%lld x i8], ", block_size);
-			ir_fprintf(f, "i%lld}", word_bits);
-		#else
-			i64 block_size = total_size - build_context.word_size;
-			ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits);
-		#endif
-		} return;
 		case TypeRecord_RawUnion: {
 			// 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)
@@ -974,7 +971,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		ir_fprintf(f, " 0, ");
 		ir_print_type(f, m, t_i32);
 	#if 1
-		ir_fprintf(f, " %d", 2 + t->Record.field_count);
+		ir_fprintf(f, " %d", 2);
 	#else
 		ir_fprintf(f, " %d", 2);
 	#endif
@@ -993,11 +990,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		ir_print_value(f, m, instr->UnionTagValue.address, et);
 		ir_fprintf(f, ",");
 	#if 1
-		ir_fprintf(f, " %d", 2 + t->Record.field_count);
+		ir_fprintf(f, " %d", 2);
 	#else
 		ir_fprintf(f, " %d", 2);
 	#endif
-		ir_fprintf(f, ", %d", 2 + t->Record.field_count);
+		ir_fprintf(f, ", %d", 2);
 		ir_fprintf(f, " ; UnionTagValue");
 		ir_fprintf(f, "\n");
 	} break;

+ 4 - 3
src/ssa.cpp

@@ -648,10 +648,11 @@ bool can_ssa_type(Type *t) {
 			}
 		}
 		return true;
+	case Type_Union:
+		return false;
+
 	case Type_Record:
-		if (t->Record.kind == TypeRecord_Union) {
-			return false;
-		} else if (t->Record.kind == TypeRecord_Struct) {
+		if (t->Record.kind == TypeRecord_Struct) {
 			if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
 				return false;
 			}

+ 113 - 149
src/types.cpp

@@ -73,7 +73,7 @@ enum TypeRecordKind {
 
 	TypeRecord_Struct,
 	TypeRecord_RawUnion,
-	TypeRecord_Union, // Tagged
+	// TypeRecord_Union, // Tagged
 	// TypeRecord_Enum,
 
 	TypeRecord_Count,
@@ -93,13 +93,13 @@ struct TypeRecord {
 	Scope *  scope;
 
 	// Entity_TypeName - union
-	Type **  variants;
-	i32      variant_count;
-	Entity * union__tag;
-	i64      variant_block_size; // NOTE(bill): Internal use only
+	// Type **  variants;
+	// i32      variant_count;
+	// Entity * union__tag;
+	// i64      variant_block_size; // NOTE(bill): Internal use only
 
-	Type *   variant_parent;
-	i32      variant_index;
+	// Type *   variant_parent;
+	// i32      variant_index;
 
 	i64 *    offsets;
 	bool     are_offsets_set;
@@ -137,6 +137,17 @@ struct TypeRecord {
 		Entity * min_value;                               \
 		Entity * max_value;                               \
 	})                                                    \
+	TYPE_KIND(Union, struct {                             \
+		Type **  variants;                                \
+		i32      variant_count;                           \
+		AstNode *node;                                    \
+		Scope *  scope;                                   \
+		Entity * union__tag;                              \
+		i64      variant_block_size;                      \
+		Type *   variant_parent;                          \
+		i32      variant_index;                           \
+		i64      custom_align;                            \
+	})                                                    \
 	TYPE_KIND(Named, struct {                             \
 		String  name;                                     \
 		Type *  base;                                     \
@@ -539,8 +550,7 @@ Type *make_type_struct(gbAllocator a) {
 }
 
 Type *make_type_union(gbAllocator a) {
-	Type *t = alloc_type(a, Type_Record);
-	t->Record.kind = TypeRecord_Union;
+	Type *t = alloc_type(a, Type_Union);
 	return t;
 }
 
@@ -867,14 +877,7 @@ bool is_type_struct(Type *t) {
 }
 bool is_type_union(Type *t) {
 	t = base_type(t);
-	return (t->kind == Type_Record && t->Record.kind == TypeRecord_Union);
-}
-bool is_type_variant(Type *t) {
-	t = base_type(t);
-	if (t->kind == Type_Record) {
-		return t->Record.kind == TypeRecord_Struct && t->Record.variant_parent != nullptr;
-	}
-	return false;
+	return t->kind == Type_Union;
 }
 
 bool is_type_raw_union(Type *t) {
@@ -1002,14 +1005,17 @@ bool is_type_polymorphic(Type *t) {
 			}
 			return false;
 		}
-	case Type_Record:
-		for (isize i = 0; i < t->Record.field_count; i++) {
-		    if (is_type_polymorphic(t->Record.fields[i]->type)) {
+		break;
+	case Type_Union:
+		for (isize i = 1; i < t->Union.variant_count; i++) {
+		    if (is_type_polymorphic(t->Union.variants[i])) {
 		    	return true;
 		    }
 		}
-		for (isize i = 1; i < t->Record.variant_count; i++) {
-		    if (is_type_polymorphic(t->Record.variants[i])) {
+		break;
+	case Type_Record:
+		for (isize i = 0; i < t->Record.field_count; i++) {
+		    if (is_type_polymorphic(t->Record.fields[i]->type)) {
 		    	return true;
 		    }
 		}
@@ -1052,11 +1058,9 @@ bool type_has_nil(Type *t) {
 	case Type_DynamicArray:
 	case Type_Map:
 		return true;
+	case Type_Union:
+		return true;
 	case Type_Record:
-		switch (t->Record.kind) {
-		case TypeRecord_Union:
-			return true;
-		}
 		return false;
 	}
 	return false;
@@ -1140,15 +1144,28 @@ bool are_types_identical(Type *x, Type *y) {
 	case Type_Enum:
 		return x == y; // NOTE(bill): All enums are unique
 
+	case Type_Union:
+		if (y->kind == Type_Union) {
+			if (x->Union.variant_count == y->Union.variant_count &&
+			    x->Union.custom_align == y->Union.custom_align) {
+				// NOTE(bill): zeroth variant is nullptr
+				for (isize i = 1; i < x->Union.variant_count; i++) {
+					if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
+						return false;
+					}
+				}
+				return true;
+			}
+		}
+		break;
+
 	case Type_Record:
 		if (y->kind == Type_Record) {
 			if (x->Record.kind == y->Record.kind) {
 				switch (x->Record.kind) {
 				case TypeRecord_Struct:
 				case TypeRecord_RawUnion:
-				case TypeRecord_Union:
 					if (x->Record.field_count == y->Record.field_count &&
-					    x->Record.variant_count == y->Record.variant_count &&
 					    x->Record.is_packed == y->Record.is_packed &&
 					    x->Record.is_ordered == y->Record.is_ordered &&
 					    x->Record.custom_align == y->Record.custom_align) {
@@ -1168,12 +1185,6 @@ bool are_types_identical(Type *x, Type *y) {
 								return false;
 							}
 						}
-						// NOTE(bill): zeroth variant is nullptr
-						for (isize i = 1; i < x->Record.variant_count; i++) {
-							if (!are_types_identical(x->Record.variants[i], y->Record.variants[i])) {
-								return false;
-							}
-						}
 						return true;
 					}
 					break;
@@ -1597,6 +1608,14 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 			}
 		}
 
+	} else if (type->Record.kind == Type_Union) {
+		if (field_name == "__tag") {
+			Entity *e = type->Union.union__tag;
+			GB_ASSERT(e != nullptr);
+			selection_add_index(&sel, -1); // HACK(bill): Leaky memory
+			sel.entity = e;
+			return sel;
+		}
 	} else if (type->kind == Type_Record) {
 		for (isize i = 0; i < type->Record.field_count; i++) {
 			Entity *f = type->Record.fields[i];
@@ -1625,15 +1644,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 				sel.index.count = prev_count;
 			}
 		}
-		if (type->Record.kind == TypeRecord_Union) {
-			if (field_name == "__tag") {
-				Entity *e = type->Record.union__tag;
-				GB_ASSERT(e != nullptr);
-				selection_add_index(&sel, -1); // HACK(bill): Leaky memory
-				sel.entity = e;
-				return sel;
-			}
-		}
 	} else if (type->kind == Type_BitField) {
 		for (isize i = 0; i < type->BitField.field_count; i++) {
 			Entity *f = type->BitField.fields[i];
@@ -1828,6 +1838,24 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 	case Type_Enum:
 		return type_align_of_internal(allocator, t->Enum.base_type, path);
 
+	case Type_Union: {
+		i64 max = build_context.word_size;
+		// NOTE(bill): field zero is null
+		for (isize i = 1; i < t->Union.variant_count; i++) {
+			Type *variant = t->Union.variants[i];
+			type_path_push(path, variant);
+			if (path->failure) {
+				return FAILURE_ALIGNMENT;
+			}
+			i64 align = type_align_of_internal(allocator, variant, path);
+			type_path_pop(path);
+			if (max < align) {
+				max = align;
+			}
+		}
+		return max;
+	} break;
+
 	case Type_Record: {
 		switch (t->Record.kind) {
 		case TypeRecord_Struct:
@@ -1854,35 +1882,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 				return max;
 			}
 			break;
-		case TypeRecord_Union: {
-			i64 max = 1;
-			if (t->Record.field_count > 0) {
-				Type *field_type = t->Record.fields[0]->type;
-				type_path_push(path, field_type);
-				i64 align = type_align_of_internal(allocator, field_type, path);
-				if (path->failure) {
-					return FAILURE_ALIGNMENT;
-				}
-				type_path_pop(path);
-				if (max < align) {
-					max = align;
-				}
-			}
-			// NOTE(bill): field zero is null
-			for (isize i = 1; i < t->Record.variant_count; i++) {
-				Type *variant = t->Record.variants[i];
-				type_path_push(path, variant);
-				if (path->failure) {
-					return FAILURE_ALIGNMENT;
-				}
-				i64 align = type_align_of_internal(allocator, variant, path);
-				type_path_pop(path);
-				if (max < align) {
-					max = align;
-				}
-			}
-			return max;
-		} break;
 		case TypeRecord_RawUnion: {
 			i64 max = 1;
 			for (isize i = 0; i < t->Record.field_count; i++) {
@@ -1947,14 +1946,7 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
 			t->Record.are_offsets_set = true;
 			return true;
 		}
-	} else if (is_type_union(t)) {
-		if (!t->Record.are_offsets_set) {
-			t->Record.are_offsets_being_processed = true;
-			t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false);
-			t->Record.are_offsets_set = true;
-			return true;
-		}
-	}  else if (is_type_tuple(t)) {
+	} else if (is_type_tuple(t)) {
 		if (!t->Tuple.are_offsets_set) {
 			t->Record.are_offsets_being_processed = true;
 			t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
@@ -2080,6 +2072,36 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 	case Type_Enum:
 		return type_size_of_internal(allocator, t->Enum.base_type, path);
 
+	case Type_Union: {
+		i64 align = type_align_of_internal(allocator, t, path);
+		if (path->failure) {
+			return FAILURE_SIZE;
+		}
+
+		i64 max = 0;
+		isize variant_count = t->Union.variant_count;
+
+		i64 field_size = max;
+
+		for (isize i = 1; i < variant_count; i++) {
+			Type *variant_type = t->Union.variants[i];
+			i64 size = type_size_of_internal(allocator, variant_type, path);
+			if (max < size) {
+				max = size;
+			}
+		}
+
+		// NOTE(bill): Align to int
+		i64 size = align_formula(max, build_context.word_size);
+		// NOTE(bill): Calculate the padding between the common fields and the tag
+		t->Union.variant_block_size = size - field_size;
+
+		size += type_size_of(allocator, t_int);
+		size = align_formula(size, align);
+		return size;
+	} break;
+
+
 	case Type_Record: {
 		switch (t->Record.kind) {
 
@@ -2101,52 +2123,6 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 			return align_formula(size, align);
 		} break;
 
-		case TypeRecord_Union: {
-			i64 align = type_align_of_internal(allocator, t, path);
-			if (path->failure) {
-				return FAILURE_SIZE;
-			}
-
-			i64 max = 0;
-			isize field_count = t->Record.field_count;
-			isize variant_count = t->Record.variant_count;
-
-			// Check for recursive types
-			for (isize i = 0; i < field_count; i++) {
-				i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
-				if (path->failure) {
-					return FAILURE_SIZE;
-				}
-			}
-			// NOTE(bill): Zeroth field is invalid
-			type_set_offsets(allocator, t);
-
-			if (field_count > 0) {
-				Type *end_type = t->Record.fields[field_count-1]->type;
-				i64 end_offset = t->Record.offsets[field_count-1];
-				i64 end_size = type_size_of_internal(allocator, end_type, path);
-				max = end_offset + end_size ;
-			}
-			i64 field_size = max;
-
-			for (isize i = 1; i < variant_count; i++) {
-				Type *variant_type = t->Record.variants[i];
-				i64 size = type_size_of_internal(allocator, variant_type, path);
-				if (max < size) {
-					max = size;
-				}
-			}
-
-			// NOTE(bill): Align to int
-			i64 size = align_formula(max, build_context.word_size);
-			// NOTE(bill): Calculate the padding between the common fields and the tag
-			t->Record.variant_block_size = size - field_size;
-
-			size += type_size_of(allocator, t_int);
-			size = align_formula(size, align);
-			return size;
-		} break;
-
 		case TypeRecord_RawUnion: {
 			i64 count = t->Record.field_count;
 			i64 align = type_align_of_internal(allocator, t, path);
@@ -2185,7 +2161,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
 	t = base_type(t);
-	if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct || t->Record.kind == TypeRecord_Union)) {
+	if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct)) {
 		type_set_offsets(allocator, t);
 		if (gb_is_between(index, 0, t->Record.field_count-1)) {
 			return t->Record.offsets[index];
@@ -2342,6 +2318,16 @@ gbString write_type_to_string(gbString str, Type *type) {
 		str = gb_string_appendc(str, "}");
 		break;
 
+	case Type_Union:
+		str = gb_string_appendc(str, "union{");
+		for (isize i = 1; i < type->Union.variant_count; i++) {
+			Type *t = type->Union.variants[i];
+			if (i > 1) str = gb_string_appendc(str, ", ");
+			str = write_type_to_string(str, t);
+		}
+		str = gb_string_appendc(str, "}");
+		break;
+
 	case Type_Record: {
 		switch (type->Record.kind) {
 		case TypeRecord_Struct:
@@ -2366,28 +2352,6 @@ gbString write_type_to_string(gbString str, Type *type) {
 			str = gb_string_appendc(str, "}");
 			break;
 
-		case TypeRecord_Union:
-			str = gb_string_appendc(str, "union{");
-			for (isize i = 0; i < type->Record.field_count; i++) {
-				Entity *f = type->Record.fields[i];
-				GB_ASSERT(f->kind == Entity_Variable);
-				if (i > 0) {
-					str = gb_string_appendc(str, ", ");
-				}
-				str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
-				str = gb_string_appendc(str, ": ");
-				str = write_type_to_string(str, f->type);
-			}
-			for (isize i = 1; i < type->Record.variant_count; i++) {
-				Type *t = type->Record.variants[i];
-				if (i > 1 || type->Record.field_count > 1) {
-					str = gb_string_appendc(str, ", ");
-				}
-				str = write_type_to_string(str, t);
-			}
-			str = gb_string_appendc(str, "}");
-			break;
-
 		case TypeRecord_RawUnion:
 			str = gb_string_appendc(str, "raw_union{");
 			for (isize i = 0; i < type->Record.field_count; i++) {