Browse Source

Update internals of a Union and Tuple

Ginger Bill 8 years ago
parent
commit
6d37ed12d2
13 changed files with 238 additions and 302 deletions
  1. 14 13
      core/_preload.odin
  2. 9 16
      core/fmt.odin
  3. 0 4
      core/mem.odin
  4. 7 7
      core/types.odin
  5. 1 1
      src/check_decl.cpp
  6. 53 60
      src/check_expr.cpp
  7. 2 2
      src/check_stmt.cpp
  8. 23 29
      src/checker.cpp
  9. 66 91
      src/ir.cpp
  10. 9 13
      src/ir_print.cpp
  11. 26 23
      src/parser.cpp
  12. 6 12
      src/ssa.cpp
  13. 22 31
      src/types.cpp

+ 14 - 13
core/_preload.odin

@@ -44,15 +44,6 @@ TypeInfo :: struct #ordered {
 		u8, u16, u32, u64, u128, uint,
 		u8, u16, u32, u64, u128, uint,
 		f32, f64,
 		f32, f64,
 	};
 	};
-	Record :: struct #ordered {
-		types:        []^TypeInfo;
-		names:        []string;
-		offsets:      []int;  // offsets may not be used in tuples
-		usings:       []bool; // usings may not be used in tuples
-		packed:       bool;
-		ordered:      bool;
-		custom_align: bool;
-	}
 
 
 // Variant Types
 // Variant Types
 	Named   :: struct #ordered {name: string; base: ^TypeInfo};
 	Named   :: struct #ordered {name: string; base: ^TypeInfo};
@@ -80,9 +71,20 @@ TypeInfo :: struct #ordered {
 	DynamicArray :: struct #ordered {elem: ^TypeInfo; elem_size: int};
 	DynamicArray :: struct #ordered {elem: ^TypeInfo; elem_size: int};
 	Slice        :: struct #ordered {elem: ^TypeInfo; elem_size: int};
 	Slice        :: struct #ordered {elem: ^TypeInfo; elem_size: int};
 	Vector       :: struct #ordered {elem: ^TypeInfo; elem_size, count: int};
 	Vector       :: struct #ordered {elem: ^TypeInfo; elem_size, count: int};
-	Tuple        :: Record; // Only really used for procedures
-	Struct       :: Record;
-	RawUnion     :: Record;
+	Tuple :: struct #ordered { // Only really used for procedures
+		types:        []^TypeInfo;
+		names:        []string;
+	};
+	Struct :: struct #ordered {
+		types:        []^TypeInfo;
+		names:        []string;
+		offsets:      []int;  // offsets may not be used in tuples
+		usings:       []bool; // usings may not be used in tuples
+		is_packed:    bool;
+		is_ordered:   bool;
+		is_raw_union: bool;
+		custom_align: bool;
+	};
 	Union :: struct #ordered {
 	Union :: struct #ordered {
 		variants:   []^TypeInfo;
 		variants:   []^TypeInfo;
 		tag_offset: int;
 		tag_offset: int;
@@ -126,7 +128,6 @@ TypeInfo :: struct #ordered {
 		Vector,
 		Vector,
 		Tuple,
 		Tuple,
 		Struct,
 		Struct,
-		RawUnion,
 		Union,
 		Union,
 		Enum,
 		Enum,
 		Map,
 		Map,

+ 9 - 16
core/fmt.odin

@@ -274,8 +274,9 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 
 
 	case Struct:
 	case Struct:
 		write_string(buf, "struct ");
 		write_string(buf, "struct ");
-		if info.packed  do write_string(buf, "#packed ");
-		if info.ordered do write_string(buf, "#ordered ");
+		if info.is_packed    do write_string(buf, "#packed ");
+		if info.is_ordered   do write_string(buf, "#ordered ");
+		if info.is_raw_union do write_string(buf, "#raw_union ");
 		if info.custom_align {
 		if info.custom_align {
 			write_string(buf, "#align ");
 			write_string(buf, "#align ");
 			write_int(buf, i64(ti.align), 10);
 			write_int(buf, i64(ti.align), 10);
@@ -298,16 +299,6 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 		}
 		write_string(buf, "}");
 		write_string(buf, "}");
 
 
-	case RawUnion:
-		write_string(buf, "raw_union {");
-		for name, i in info.names {
-			if i > 0 do write_string(buf, ", ");
-			write_string(buf, name);
-			write_string(buf, ": ");
-			write_type(buf, info.types[i]);
-		}
-		write_string(buf, "}");
-
 	case Enum:
 	case Enum:
 		write_string(buf, "enum ");
 		write_string(buf, "enum ");
 		write_type(buf, info.base);
 		write_type(buf, info.base);
@@ -317,6 +308,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 			write_string(buf, name);
 			write_string(buf, name);
 		}
 		}
 		write_string(buf, "}");
 		write_string(buf, "}");
+
 	case BitField:
 	case BitField:
 		write_string(buf, "bit_field ");
 		write_string(buf, "bit_field ");
 		if ti.align != 1 {
 		if ti.align != 1 {
@@ -864,6 +856,11 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 
 
 
 
 	case Struct:
 	case Struct:
+		if info.is_raw_union {
+			write_string(fi.buf, "(raw_union)");
+			return;
+		}
+
 		write_byte(fi.buf, '{');
 		write_byte(fi.buf, '{');
 		defer write_byte(fi.buf, '}');
 		defer write_byte(fi.buf, '}');
 
 
@@ -891,10 +888,6 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 			fmt_arg(fi, any{data, ti}, verb);
 			fmt_arg(fi, any{data, ti}, verb);
 		}
 		}
 
 
-
-	case RawUnion:
-		write_string(fi.buf, "(raw_union)");
-
 	case Enum:
 	case Enum:
 		fmt_enum(fi, v, verb);
 		fmt_enum(fi, v, verb);
 
 

+ 0 - 4
core/mem.odin

@@ -245,8 +245,6 @@ align_of_type_info :: proc(type_info: ^TypeInfo) -> int {
 		return type_info.align;
 		return type_info.align;
 	case Union:
 	case Union:
 		return type_info.align;
 		return type_info.align;
-	case RawUnion:
-		return type_info.align;
 	case Enum:
 	case Enum:
 		return align_of_type_info(info.base);
 		return align_of_type_info(info.base);
 	case Map:
 	case Map:
@@ -305,8 +303,6 @@ size_of_type_info :: proc(type_info: ^TypeInfo) -> int {
 		return type_info.size;
 		return type_info.size;
 	case Union:
 	case Union:
 		return type_info.size;
 		return type_info.size;
-	case RawUnion:
-		return type_info.size;
 	case Enum:
 	case Enum:
 		return size_of_type_info(info.base);
 		return size_of_type_info(info.base);
 	case Map:
 	case Map:

+ 7 - 7
core/types.odin

@@ -83,17 +83,17 @@ is_tuple :: proc(info: ^TypeInfo) -> bool {
 }
 }
 is_struct :: proc(info: ^TypeInfo) -> bool {
 is_struct :: proc(info: ^TypeInfo) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := type_info_base(info).variant.(TypeInfo.Struct);
-	return ok;
+	s, ok := type_info_base(info).variant.(TypeInfo.Struct);
+	return ok && !s.is_raw_union;
 }
 }
-is_union :: proc(info: ^TypeInfo) -> bool {
+is_raw_union :: proc(info: ^TypeInfo) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := type_info_base(info).variant.(TypeInfo.Union);
-	return ok;
+	s, ok := type_info_base(info).variant.(TypeInfo.Struct);
+	return ok && s.is_raw_union;
 }
 }
-is_raw_union :: proc(info: ^TypeInfo) -> bool {
+is_union :: proc(info: ^TypeInfo) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := type_info_base(info).variant.(TypeInfo.RawUnion);
+	_, ok := type_info_base(info).variant.(TypeInfo.Union);
 	return ok;
 	return ok;
 }
 }
 is_enum :: proc(info: ^TypeInfo) -> bool {
 is_enum :: proc(info: ^TypeInfo) -> bool {

+ 1 - 1
src/check_decl.cpp

@@ -686,7 +686,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
 	GB_ASSERT(type->kind == Type_Proc);
 	GB_ASSERT(type->kind == Type_Proc);
 	if (type->Proc.param_count > 0) {
 	if (type->Proc.param_count > 0) {
 		TypeTuple *params = &type->Proc.params->Tuple;
 		TypeTuple *params = &type->Proc.params->Tuple;
-		for (isize i = 0; i < params->variable_count; i++) {
+		for_array(i, params->variables) {
 			Entity *e = params->variables[i];
 			Entity *e = params->variables[i];
 			if (e->kind != Entity_Variable) {
 			if (e->kind != Entity_Variable) {
 				continue;
 				continue;

+ 53 - 60
src/check_expr.cpp

@@ -519,7 +519,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 	}
 	}
 
 
 	if (is_type_union(dst)) {
 	if (is_type_union(dst)) {
-		for (isize i = 0; i < dst->Union.variant_count; i++) {
+		for_array(i, dst->Union.variants) {
 			Type *vt = dst->Union.variants[i];
 			Type *vt = dst->Union.variants[i];
 			if (are_types_identical(vt, s)) {
 			if (are_types_identical(vt, s)) {
 				return 1;
 				return 1;
@@ -851,8 +851,7 @@ void check_record_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields,
 			} else {
 			} else {
 				if (o.mode == Addressing_Value && o.type->kind == Type_Tuple) {
 				if (o.mode == Addressing_Value && o.type->kind == Type_Tuple) {
 					// NOTE(bill): Tuples are not first class thus never named
 					// NOTE(bill): Tuples are not first class thus never named
-					isize count = o.type->Tuple.variable_count;
-					for (isize index = 0; index < count; index++) {
+					for_array(index, o.type->Tuple.variables) {
 						Operand single = {Addressing_Value};
 						Operand single = {Addressing_Value};
 						single.type    = o.type->Tuple.variables[index]->type;
 						single.type    = o.type->Tuple.variables[index]->type;
 						single.expr    = v;
 						single.expr    = v;
@@ -1200,9 +1199,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 
 
 			if (entities.count > 0) {
 			if (entities.count > 0) {
 				Type *tuple = make_type_tuple(c->allocator);
 				Type *tuple = make_type_tuple(c->allocator);
-				tuple->Tuple.variables = entities.data;
-				tuple->Tuple.variable_count = entities.count;
-
+				tuple->Tuple.variables = entities;
 				polymorphic_params = tuple;
 				polymorphic_params = tuple;
 			}
 			}
 		}
 		}
@@ -1314,7 +1311,7 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 	GB_ASSERT(is_type_union(union_type));
 	GB_ASSERT(is_type_union(union_type));
 	ast_node(ut, UnionType, node);
 	ast_node(ut, UnionType, node);
 
 
-	isize variant_count = ut->variants.count+1;
+	isize variant_count = ut->variants.count;
 
 
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 	defer (gb_temp_arena_memory_end(tmp));
 	defer (gb_temp_arena_memory_end(tmp));
@@ -1323,9 +1320,8 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 
 
 	Array<Type *> variants = {};
 	Array<Type *> variants = {};
 	array_init(&variants, c->allocator, variant_count);
 	array_init(&variants, c->allocator, variant_count);
-	array_add(&variants, t_invalid);
 
 
-	union_type->Union.scope               = c->context.scope;
+	union_type->Union.scope = c->context.scope;
 
 
 	for_array(i, ut->variants) {
 	for_array(i, ut->variants) {
 		AstNode *node = ut->variants[i];
 		AstNode *node = ut->variants[i];
@@ -1356,8 +1352,7 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 		}
 		}
 	}
 	}
 
 
-	union_type->Union.variants      = variants.data;
-	union_type->Union.variant_count = variants.count;
+	union_type->Union.variants = variants;
 }
 }
 
 
 // void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
 // void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
@@ -1655,8 +1650,8 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
 
 
 			TypeTuple *s_tuple = &s->Record.polymorphic_params->Tuple;
 			TypeTuple *s_tuple = &s->Record.polymorphic_params->Tuple;
 			TypeTuple *t_tuple = &t->Record.polymorphic_params->Tuple;
 			TypeTuple *t_tuple = &t->Record.polymorphic_params->Tuple;
-			GB_ASSERT(t_tuple->variable_count == s_tuple->variable_count);
-			for (isize i = 0; i < s_tuple->variable_count; i++) {
+			GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count);
+			for_array(i, s_tuple->variables) {
 				Entity *s_e = s_tuple->variables[i];
 				Entity *s_e = s_tuple->variables[i];
 				Entity *t_e = t_tuple->variables[i];
 				Entity *t_e = t_tuple->variables[i];
 				Type *st = s_e->type;
 				Type *st = s_e->type;
@@ -1748,10 +1743,10 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
 		if (source->kind == Type_Union) {
 		if (source->kind == Type_Union) {
 			TypeUnion *x = &poly->Union;
 			TypeUnion *x = &poly->Union;
 			TypeUnion *y = &source->Union;
 			TypeUnion *y = &source->Union;
-			if (x->variant_count != y->variant_count) {
+			if (x->variants.count != y->variants.count) {
 				return false;
 				return false;
 			}
 			}
-			for (isize i = 1; i < x->variant_count; i++) {
+			for_array(i, x->variants) {
 				Type *a = x->variants[i];
 				Type *a = x->variants[i];
 				Type *b = y->variants[i];
 				Type *b = y->variants[i];
 				bool ok = is_polymorphic_type_assignable(c, a, b, false, modify_type);
 				bool ok = is_polymorphic_type_assignable(c, a, b, false, modify_type);
@@ -1887,8 +1882,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 
 
 	bool is_variadic = false;
 	bool is_variadic = false;
 	bool is_c_vararg = false;
 	bool is_c_vararg = false;
-	Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
-	isize variable_index = 0;
+	Array<Entity *> variables = {};
+	array_init(&variables, c->allocator, variable_count);
 	for_array(i, params) {
 	for_array(i, params) {
 		AstNode *param = params[i];
 		AstNode *param = params[i];
 		if (param->kind != AstNode_Field) {
 		if (param->kind != AstNode_Field) {
@@ -2033,7 +2028,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 			Entity *param = nullptr;
 			Entity *param = nullptr;
 			if (is_type_param) {
 			if (is_type_param) {
 				if (operands != nullptr) {
 				if (operands != nullptr) {
-					Operand o = (*operands)[variable_index];
+					Operand o = (*operands)[variables.count];
 					if (o.mode == Addressing_Type) {
 					if (o.mode == Addressing_Type) {
 						type = o.type;
 						type = o.type;
 					} else {
 					} else {
@@ -2067,7 +2062,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 				param->TypeName.is_type_alias = true;
 				param->TypeName.is_type_alias = true;
 			} else {
 			} else {
 				if (operands != nullptr && is_type_polymorphic_type) {
 				if (operands != nullptr && is_type_polymorphic_type) {
-					Operand op = (*operands)[variable_index];
+					Operand op = (*operands)[variables.count];
 					type = determine_type_from_polymorphic(c, type, op);
 					type = determine_type_from_polymorphic(c, type, op);
 					if (type == t_invalid) {
 					if (type == t_invalid) {
 						success = false;
 						success = false;
@@ -2093,11 +2088,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 			}
 			}
 
 
 			add_entity(c, scope, name, param);
 			add_entity(c, scope, name, param);
-			variables[variable_index++] = param;
+			array_add(&variables, param);
 		}
 		}
 	}
 	}
 
 
-	variable_count = variable_index;
 
 
 	if (is_variadic) {
 	if (is_variadic) {
 		GB_ASSERT(params.count > 0);
 		GB_ASSERT(params.count > 0);
@@ -2113,7 +2107,6 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 
 
 	Type *tuple = make_type_tuple(c->allocator);
 	Type *tuple = make_type_tuple(c->allocator);
 	tuple->Tuple.variables = variables;
 	tuple->Tuple.variables = variables;
-	tuple->Tuple.variable_count = variable_count;
 
 
 	if (success_) *success_ = success;
 	if (success_) *success_ = success;
 	if (is_variadic_) *is_variadic_ = is_variadic;
 	if (is_variadic_) *is_variadic_ = is_variadic;
@@ -2142,8 +2135,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 		}
 		}
 	}
 	}
 
 
-	Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
-	isize variable_index = 0;
+	Array<Entity *> variables = {};
+	array_init(&variables, c->allocator, variable_count);
 	for_array(i, results) {
 	for_array(i, results) {
 		ast_node(field, Field, results[i]);
 		ast_node(field, Field, results[i]);
 		AstNode *default_value = unparen_expr(field->default_value);
 		AstNode *default_value = unparen_expr(field->default_value);
@@ -2197,7 +2190,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 			param->Variable.default_value = value;
 			param->Variable.default_value = value;
 			param->Variable.default_is_nil = default_is_nil;
 			param->Variable.default_is_nil = default_is_nil;
-			variables[variable_index++] = param;
+			array_add(&variables, param);
 		} else {
 		} else {
 			for_array(j, field->names) {
 			for_array(j, field->names) {
 				Token token = ast_node_token(results[i]);
 				Token token = ast_node_token(results[i]);
@@ -2216,17 +2209,17 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
 				param->Variable.default_value = value;
 				param->Variable.default_value = value;
 				param->Variable.default_is_nil = default_is_nil;
 				param->Variable.default_is_nil = default_is_nil;
-				variables[variable_index++] = param;
+				array_add(&variables, param);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	for (isize i = 0; i < variable_index; i++) {
+	for_array(i, variables) {
 		String x = variables[i]->token.string;
 		String x = variables[i]->token.string;
 		if (x.len == 0 || is_blank_ident(x)) {
 		if (x.len == 0 || is_blank_ident(x)) {
 			continue;
 			continue;
 		}
 		}
-		for (isize j = i+1; j < variable_index; j++) {
+		for (isize j = i+1; j < variables.count; j++) {
 			String y = variables[j]->token.string;
 			String y = variables[j]->token.string;
 			if (y.len == 0 || is_blank_ident(y)) {
 			if (y.len == 0 || is_blank_ident(y)) {
 				continue;
 				continue;
@@ -2238,7 +2231,6 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 	}
 	}
 
 
 	tuple->Tuple.variables = variables;
 	tuple->Tuple.variables = variables;
-	tuple->Tuple.variable_count = variable_index;
 
 
 	return tuple;
 	return tuple;
 }
 }
@@ -2335,7 +2327,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
 Type *reduce_tuple_to_single_type(Type *original_type) {
 Type *reduce_tuple_to_single_type(Type *original_type) {
 	if (original_type != nullptr) {
 	if (original_type != nullptr) {
 		Type *t = core_type(original_type);
 		Type *t = core_type(original_type);
-		if (t->kind == Type_Tuple && t->Tuple.variable_count == 1) {
+		if (t->kind == Type_Tuple && t->Tuple.variables.count == 1) {
 			return t->Tuple.variables[0]->type;
 			return t->Tuple.variables[0]->type;
 		}
 		}
 	}
 	}
@@ -2384,9 +2376,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
 
 
 	if (new_type != original_type) {
 	if (new_type != original_type) {
 		Type *tuple = make_type_tuple(a);
 		Type *tuple = make_type_tuple(a);
-		tuple->Tuple.variable_count = 1;
-		tuple->Tuple.variables = gb_alloc_array(a, Entity *, 1);
-		tuple->Tuple.variables[0] = make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false);
+		Array<Entity *> variables = {};
+		array_init(&variables, a, 1);
+		array_add(&variables, make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false));
+		tuple->Tuple.variables = variables;
 		new_type = tuple;
 		new_type = tuple;
 	}
 	}
 
 
@@ -2437,8 +2430,8 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 
 
 	isize param_count = 0;
 	isize param_count = 0;
 	isize result_count = 0;
 	isize result_count = 0;
-	if (params)  param_count  = params ->Tuple.variable_count;
-	if (results) result_count = results->Tuple.variable_count;
+	if (params)  param_count  = params ->Tuple.variables.count;
+	if (results) result_count = results->Tuple.variables.count;
 
 
 	type->Proc.node               = proc_type_node;
 	type->Proc.node               = proc_type_node;
 	type->Proc.scope              = c->context.scope;
 	type->Proc.scope              = c->context.scope;
@@ -2719,10 +2712,9 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
 Type *make_optional_ok_type(gbAllocator a, Type *value) {
 Type *make_optional_ok_type(gbAllocator a, Type *value) {
 	bool typed = true;
 	bool typed = true;
 	Type *t = make_type_tuple(a);
 	Type *t = make_type_tuple(a);
-	t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
-	t->Tuple.variable_count = 2;
-	t->Tuple.variables[0] = make_entity_field(a, nullptr, blank_token, value,  false, 0);
-	t->Tuple.variables[1] = make_entity_field(a, nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1);
+	array_init(&t->Tuple.variables, a, 2);
+	array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, value,  false, 0));
+	array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1));
 	return t;
 	return t;
 }
 }
 
 
@@ -4304,11 +4296,11 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 	{
 	{
 		gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 		gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 		defer (gb_temp_arena_memory_end(tmp));
 		defer (gb_temp_arena_memory_end(tmp));
-		i32 count = t->Union.variant_count;
+		isize count = t->Union.variants.count;
 		i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
 		i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
 		i32 success_count = 0;
 		i32 success_count = 0;
 		i32 first_success_index = -1;
 		i32 first_success_index = -1;
-		for (i32 i = 1; i < count; i++) {
+		for_array(i, t->Union.variants) {
 			Type *vt = t->Union.variants[i];
 			Type *vt = t->Union.variants[i];
 			i64 score = 0;
 			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)) {
@@ -4358,14 +4350,14 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 		} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
 		} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
 			operand->mode = Addressing_Invalid;
 			operand->mode = Addressing_Invalid;
 			convert_untyped_error(c, operand, target_type);
 			convert_untyped_error(c, operand, target_type);
-			if (count > 1) {
+			if (count > 0) {
 				gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
 				gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
 				gb_printf_err("\t");
 				gb_printf_err("\t");
-				for (i32 i = 1; i < count; i++) {
+				for (i32 i = 0; i < count; i++) {
 					Type *v = t->Union.variants[i];
 					Type *v = t->Union.variants[i];
-					if (i > 1 && count > 3) gb_printf_err(", ");
+					if (i > 0 && count > 2) gb_printf_err(", ");
 					if (i == count-1) {
 					if (i == count-1) {
-						if (count == 3) {
+						if (count == 2) {
 							gb_printf_err(" or ");
 							gb_printf_err(" or ");
 						} else {
 						} else {
 							gb_printf_err("or ");
 							gb_printf_err("or ");
@@ -4692,7 +4684,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 			i64 max_count = 0;
 			i64 max_count = 0;
 			switch (type->kind) {
 			switch (type->kind) {
 			case Type_Record: max_count = type->Record.field_count;   break;
 			case Type_Record: max_count = type->Record.field_count;   break;
-			case Type_Tuple:  max_count = type->Tuple.variable_count; break;
+			case Type_Tuple:  max_count = type->Tuple.variables.count; break;
 			}
 			}
 
 
 			if (index >= max_count) {
 			if (index >= max_count) {
@@ -5591,11 +5583,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 
 
 		Type *tuple = make_type_tuple(a);
 		Type *tuple = make_type_tuple(a);
 		i32 variable_count = type->Record.field_count;
 		i32 variable_count = type->Record.field_count;
-		tuple->Tuple.variables = gb_alloc_array(a, Entity *, variable_count);
-		tuple->Tuple.variable_count = variable_count;
-
+		array_init_count(&tuple->Tuple.variables, a, variable_count);
 		// TODO(bill): Should I copy each of the entities or is this good enough?
 		// TODO(bill): Should I copy each of the entities or is this good enough?
-		gb_memcopy_array(tuple->Tuple.variables, type->Record.fields_in_src_order, variable_count);
+		gb_memcopy_array(tuple->Tuple.variables.data, type->Record.fields_in_src_order, variable_count);
 
 
 		operand->type = tuple;
 		operand->type = tuple;
 		operand->mode = Addressing_Value;
 		operand->mode = Addressing_Value;
@@ -5957,7 +5947,7 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operand
 			}
 			}
 		} else {
 		} else {
 			TypeTuple *tuple = &o.type->Tuple;
 			TypeTuple *tuple = &o.type->Tuple;
-			for (isize j = 0; j < tuple->variable_count; j++) {
+			for_array(j, tuple->variables) {
 				o.type = tuple->variables[j]->type;
 				o.type = tuple->variables[j]->type;
 				array_add(operands, o);
 				array_add(operands, o);
 			}
 			}
@@ -5988,7 +5978,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 	if (pt->params != nullptr) {
 	if (pt->params != nullptr) {
 		param_tuple = &pt->params->Tuple;
 		param_tuple = &pt->params->Tuple;
 
 
-		param_count = param_tuple->variable_count;
+		param_count = param_tuple->variables.count;
 		if (variadic) {
 		if (variadic) {
 			param_count--;
 			param_count--;
 		}
 		}
@@ -6069,7 +6059,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 			TypeProc *pt = &final_proc_type->Proc;
 			TypeProc *pt = &final_proc_type->Proc;
 
 
 			GB_ASSERT(pt->params != nullptr);
 			GB_ASSERT(pt->params != nullptr);
-			Entity **sig_params = pt->params->Tuple.variables;
+			auto sig_params = pt->params->Tuple.variables;
 			isize operand_index = 0;
 			isize operand_index = 0;
 			isize max_operand_count = gb_min(param_count, operands.count);
 			isize max_operand_count = gb_min(param_count, operands.count);
 			for (; operand_index < max_operand_count; operand_index++) {
 			for (; operand_index < max_operand_count; operand_index++) {
@@ -6564,8 +6554,7 @@ isize lookup_polymorphic_struct_parameter(TypeRecord *st, String parameter_name)
 	if (!st->is_polymorphic) return -1;
 	if (!st->is_polymorphic) return -1;
 
 
 	TypeTuple *params = &st->polymorphic_params->Tuple;
 	TypeTuple *params = &st->polymorphic_params->Tuple;
-	isize param_count = params->variable_count;
-	for (isize i = 0; i < param_count; i++) {
+	for_array(i, params->variables) {
 		Entity *e = params->variables[i];
 		Entity *e = params->variables[i];
 		String name = e->token.string;
 		String name = e->token.string;
 		if (is_blank_ident(name)) {
 		if (is_blank_ident(name)) {
@@ -6617,7 +6606,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
 	CallArgumentError err = CallArgumentError_None;
 	CallArgumentError err = CallArgumentError_None;
 
 
 	TypeTuple *tuple = &st->polymorphic_params->Tuple;
 	TypeTuple *tuple = &st->polymorphic_params->Tuple;
-	isize param_count = tuple->variable_count;
+	isize param_count = tuple->variables.count;
 
 
 	Array<Operand> ordered_operands = operands;
 	Array<Operand> ordered_operands = operands;
 	if (named_fields) {
 	if (named_fields) {
@@ -6749,7 +6738,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
 				Type *t = base_type(e->type);
 				Type *t = base_type(e->type);
 				TypeTuple *tuple = &t->Record.polymorphic_params->Tuple;
 				TypeTuple *tuple = &t->Record.polymorphic_params->Tuple;
 				bool ok = true;
 				bool ok = true;
-				GB_ASSERT(param_count == tuple->variable_count);
+				GB_ASSERT(param_count == tuple->variables.count);
 				for (isize j = 0; j < param_count; j++) {
 				for (isize j = 0; j < param_count; j++) {
 					Entity *p = tuple->variables[j];
 					Entity *p = tuple->variables[j];
 					Operand o = ordered_operands[j];
 					Operand o = ordered_operands[j];
@@ -6968,7 +6957,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 		operand->mode = Addressing_NoValue;
 		operand->mode = Addressing_NoValue;
 	} else {
 	} else {
 		GB_ASSERT(is_type_tuple(result_type));
 		GB_ASSERT(is_type_tuple(result_type));
-		switch (result_type->Tuple.variable_count) {
+		switch (result_type->Tuple.variables.count) {
 		case 0:
 		case 0:
 			operand->mode = Addressing_NoValue;
 			operand->mode = Addressing_NoValue;
 			break;
 			break;
@@ -7736,7 +7725,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 
 
 		if (is_type_union(src)) {
 		if (is_type_union(src)) {
 			bool ok = false;
 			bool ok = false;
-			for (isize i = 1; i < bsrc->Union.variant_count; i++) {
+			for_array(i, bsrc->Union.variants) {
 				Type *vt = bsrc->Union.variants[i];
 				Type *vt = bsrc->Union.variants[i];
 				if (are_types_identical(vt, dst)) {
 				if (are_types_identical(vt, dst)) {
 					ok = true;
 					ok = true;
@@ -8120,7 +8109,7 @@ void check_not_tuple(Checker *c, Operand *o) {
 	if (o->mode == Addressing_Value) {
 	if (o->mode == Addressing_Value) {
 		// NOTE(bill): Tuples are not first class thus never named
 		// NOTE(bill): Tuples are not first class thus never named
 		if (o->type->kind == Type_Tuple) {
 		if (o->type->kind == Type_Tuple) {
-			isize count = o->type->Tuple.variable_count;
+			isize count = o->type->Tuple.variables.count;
 			GB_ASSERT(count != 1);
 			GB_ASSERT(count != 1);
 			error(o->expr,
 			error(o->expr,
 			      "%td-valued tuple found where single value expected", count);
 			      "%td-valued tuple found where single value expected", count);
@@ -8192,6 +8181,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_append_length(str, &bd->name[0], bd->name.len);
 		str = gb_string_append_length(str, &bd->name[0], bd->name.len);
 	case_end;
 	case_end;
 
 
+	case_ast_node(ud, Undef, node);
+		str = gb_string_appendc(str, "---");
+	case_end;
+
 	case_ast_node(pl, ProcLit, node);
 	case_ast_node(pl, ProcLit, node);
 		str = write_expr_to_string(str, pl->type);
 		str = write_expr_to_string(str, pl->type);
 	case_end;
 	case_end;

+ 2 - 2
src/check_stmt.cpp

@@ -817,7 +817,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		TypeProc *pt = &proc_type->Proc;
 		TypeProc *pt = &proc_type->Proc;
 		isize result_count = 0;
 		isize result_count = 0;
 		if (pt->results) {
 		if (pt->results) {
-			result_count = proc_type->Proc.results->Tuple.variable_count;
+			result_count = proc_type->Proc.results->Tuple.variables.count;
 		}
 		}
 
 
 
 
@@ -1474,7 +1474,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					if (match_type_kind == MatchType_Union) {
 					if (match_type_kind == MatchType_Union) {
 						GB_ASSERT(is_type_union(bt));
 						GB_ASSERT(is_type_union(bt));
 						bool tag_type_found = false;
 						bool tag_type_found = false;
-						for (isize i = 0; i < bt->Union.variant_count; i++) {
+						for_array(i, bt->Union.variants) {
 							Type *vt = bt->Union.variants[i];
 							Type *vt = bt->Union.variants[i];
 							if (are_types_identical(vt, y.type)) {
 							if (are_types_identical(vt, y.type)) {
 								tag_type_found = true;
 								tag_type_found = true;

+ 23 - 29
src/checker.cpp

@@ -1169,7 +1169,7 @@ void add_type_info_type(Checker *c, Type *t) {
 
 
 	case Type_Union:
 	case Type_Union:
 		add_type_info_type(c, t_int);
 		add_type_info_type(c, t_int);
-		for (isize i = 0; i < bt->Union.variant_count; i++) {
+		for_array(i, bt->Union.variants) {
 			add_type_info_type(c, bt->Union.variants[i]);
 			add_type_info_type(c, bt->Union.variants[i]);
 		}
 		}
 		break;
 		break;
@@ -1188,7 +1188,7 @@ void add_type_info_type(Checker *c, Type *t) {
 	} break;
 	} break;
 
 
 	case Type_Tuple:
 	case Type_Tuple:
-		for (isize i = 0; i < bt->Tuple.variable_count; i++) {
+		for_array(i, bt->Tuple.variables) {
 			Entity *var = bt->Tuple.variables[i];
 			Entity *var = bt->Tuple.variables[i];
 			add_type_info_type(c, var->type);
 			add_type_info_type(c, var->type);
 		}
 		}
@@ -1341,12 +1341,8 @@ void init_preload(Checker *c) {
 		GB_ASSERT(is_type_struct(type_info_entity->type));
 		GB_ASSERT(is_type_struct(type_info_entity->type));
 		TypeRecord *record = &base_type(type_info_entity->type)->Record;
 		TypeRecord *record = &base_type(type_info_entity->type)->Record;
 
 
-		Entity *type_info_record     = find_sub_core_entity(record, str_lit("Record"));
 		Entity *type_info_enum_value = find_sub_core_entity(record, str_lit("EnumValue"));
 		Entity *type_info_enum_value = find_sub_core_entity(record, str_lit("EnumValue"));
 
 
-
-		t_type_info_record = type_info_record->type;
-		t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
 		t_type_info_enum_value = type_info_enum_value->type;
 		t_type_info_enum_value = type_info_enum_value->type;
 		t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
 		t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
 
 
@@ -1357,30 +1353,29 @@ void init_preload(Checker *c) {
 		GB_ASSERT(is_type_union(tiv_type));
 		GB_ASSERT(is_type_union(tiv_type));
 		TypeUnion *tiv = &tiv_type->Union;
 		TypeUnion *tiv = &tiv_type->Union;
 
 
-		if (tiv->variant_count != 22) {
+		if (tiv->variants.count != 20) {
 			compiler_error("Invalid `TypeInfo` layout");
 			compiler_error("Invalid `TypeInfo` layout");
 		}
 		}
-		t_type_info_named         = tiv->variants[ 1];
-		t_type_info_integer       = tiv->variants[ 2];
-		t_type_info_rune          = tiv->variants[ 3];
-		t_type_info_float         = tiv->variants[ 4];
-		t_type_info_complex       = tiv->variants[ 5];
-		t_type_info_string        = tiv->variants[ 6];
-		t_type_info_boolean       = tiv->variants[ 7];
-		t_type_info_any           = tiv->variants[ 8];
-		t_type_info_pointer       = tiv->variants[ 9];
-		t_type_info_procedure     = tiv->variants[10];
-		t_type_info_array         = tiv->variants[11];
-		t_type_info_dynamic_array = tiv->variants[12];
-		t_type_info_slice         = tiv->variants[13];
-		t_type_info_vector        = tiv->variants[14];
-		t_type_info_tuple         = tiv->variants[15];
-		t_type_info_struct        = tiv->variants[16];
-		t_type_info_raw_union     = tiv->variants[17];
-		t_type_info_union         = tiv->variants[18];
-		t_type_info_enum          = tiv->variants[19];
-		t_type_info_map           = tiv->variants[20];
-		t_type_info_bit_field     = tiv->variants[21];
+		t_type_info_named         = tiv->variants[ 0];
+		t_type_info_integer       = tiv->variants[ 1];
+		t_type_info_rune          = tiv->variants[ 2];
+		t_type_info_float         = tiv->variants[ 3];
+		t_type_info_complex       = tiv->variants[ 4];
+		t_type_info_string        = tiv->variants[ 5];
+		t_type_info_boolean       = tiv->variants[ 6];
+		t_type_info_any           = tiv->variants[ 7];
+		t_type_info_pointer       = tiv->variants[ 8];
+		t_type_info_procedure     = tiv->variants[ 9];
+		t_type_info_array         = tiv->variants[10];
+		t_type_info_dynamic_array = tiv->variants[11];
+		t_type_info_slice         = tiv->variants[12];
+		t_type_info_vector        = tiv->variants[13];
+		t_type_info_tuple         = tiv->variants[14];
+		t_type_info_struct        = tiv->variants[15];
+		t_type_info_union         = tiv->variants[16];
+		t_type_info_enum          = tiv->variants[17];
+		t_type_info_map           = tiv->variants[18];
+		t_type_info_bit_field     = tiv->variants[19];
 
 
 		t_type_info_named_ptr         = make_type_pointer(c->allocator, t_type_info_named);
 		t_type_info_named_ptr         = make_type_pointer(c->allocator, t_type_info_named);
 		t_type_info_integer_ptr       = make_type_pointer(c->allocator, t_type_info_integer);
 		t_type_info_integer_ptr       = make_type_pointer(c->allocator, t_type_info_integer);
@@ -1398,7 +1393,6 @@ void init_preload(Checker *c) {
 		t_type_info_vector_ptr        = make_type_pointer(c->allocator, t_type_info_vector);
 		t_type_info_vector_ptr        = make_type_pointer(c->allocator, t_type_info_vector);
 		t_type_info_tuple_ptr         = make_type_pointer(c->allocator, t_type_info_tuple);
 		t_type_info_tuple_ptr         = make_type_pointer(c->allocator, t_type_info_tuple);
 		t_type_info_struct_ptr        = make_type_pointer(c->allocator, t_type_info_struct);
 		t_type_info_struct_ptr        = make_type_pointer(c->allocator, t_type_info_struct);
-		t_type_info_raw_union_ptr     = make_type_pointer(c->allocator, t_type_info_raw_union);
 		t_type_info_union_ptr         = make_type_pointer(c->allocator, t_type_info_union);
 		t_type_info_union_ptr         = make_type_pointer(c->allocator, t_type_info_union);
 		t_type_info_enum_ptr          = make_type_pointer(c->allocator, t_type_info_enum);
 		t_type_info_enum_ptr          = make_type_pointer(c->allocator, t_type_info_enum);
 		t_type_info_map_ptr           = make_type_pointer(c->allocator, t_type_info_map);
 		t_type_info_map_ptr           = make_type_pointer(c->allocator, t_type_info_map);

+ 66 - 91
src/ir.cpp

@@ -617,7 +617,7 @@ Type *ir_instr_type(irInstr *instr) {
 	case irInstr_Call: {
 	case irInstr_Call: {
 		Type *pt = base_type(instr->Call.type);
 		Type *pt = base_type(instr->Call.type);
 		if (pt != nullptr) {
 		if (pt != nullptr) {
-			if (pt->kind == Type_Tuple && pt->Tuple.variable_count == 1) {
+			if (pt->kind == Type_Tuple && pt->Tuple.variables.count == 1) {
 				return pt->Tuple.variables[0]->type;
 				return pt->Tuple.variables[0]->type;
 			}
 			}
 			return pt;
 			return pt;
@@ -2382,8 +2382,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
 		GB_ASSERT(index == -1);
 		GB_ASSERT(index == -1);
 		return ir_emit_union_tag_ptr(proc, s);
 		return ir_emit_union_tag_ptr(proc, s);
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
-		GB_ASSERT(t->Tuple.variable_count > 0);
-		GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+		GB_ASSERT(t->Tuple.variables.count > 0);
 		result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
 		result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
 	} else if (is_type_complex(t)) {
 	} else if (is_type_complex(t)) {
 		Type *ft = base_complex_elem_type(t);
 		Type *ft = base_complex_elem_type(t);
@@ -2445,8 +2444,7 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
 		GB_ASSERT(index == -1);
 		GB_ASSERT(index == -1);
 		return ir_emit_union_tag_value(proc, s);
 		return ir_emit_union_tag_value(proc, s);
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
-		GB_ASSERT(t->Tuple.variable_count > 0);
-		GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+		GB_ASSERT(t->Tuple.variables.count > 0);
 		result_type = t->Tuple.variables[index]->type;
 		result_type = t->Tuple.variables[index]->type;
 	} else if (is_type_complex(t)) {
 	} else if (is_type_complex(t)) {
 		Type *ft = base_complex_elem_type(t);
 		Type *ft = base_complex_elem_type(t);
@@ -2960,7 +2958,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 	}
 	}
 
 
 	if (is_type_union(dst)) {
 	if (is_type_union(dst)) {
-		for (isize i = 1; i < dst->Union.variant_count; i++) {
+		for_array(i, dst->Union.variants) {
 			Type *vt = dst->Union.variants[i];
 			Type *vt = dst->Union.variants[i];
 			if (are_types_identical(vt, src_type)) {
 			if (are_types_identical(vt, src_type)) {
 				ir_emit_comment(proc, str_lit("union - child to parent"));
 				ir_emit_comment(proc, str_lit("union - child to parent"));
@@ -4861,7 +4859,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			AstNode *a = ce->args[i];
 			AstNode *a = ce->args[i];
 			Type *at = base_type(type_of_expr(proc->module->info, a));
 			Type *at = base_type(type_of_expr(proc->module->info, a));
 			if (at->kind == Type_Tuple) {
 			if (at->kind == Type_Tuple) {
-				arg_count += at->Tuple.variable_count;
+				arg_count += at->Tuple.variables.count;
 			} else {
 			} else {
 				arg_count++;
 				arg_count++;
 			}
 			}
@@ -4882,7 +4880,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 				irValue *a = ir_build_expr(proc, arg);
 				irValue *a = ir_build_expr(proc, arg);
 				Type *at = ir_type(a);
 				Type *at = ir_type(a);
 				if (at->kind == Type_Tuple) {
 				if (at->kind == Type_Tuple) {
-					for (isize i = 0; i < at->Tuple.variable_count; i++) {
+					for_array(i, at->Tuple.variables) {
 						Entity *e = at->Tuple.variables[i];
 						Entity *e = at->Tuple.variables[i];
 						irValue *v = ir_emit_struct_ev(proc, a, i);
 						irValue *v = ir_emit_struct_ev(proc, a, i);
 						args[arg_index++] = v;
 						args[arg_index++] = v;
@@ -5129,7 +5127,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 						irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
 						irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
 						names_ptr = ir_emit_struct_ep(proc, enum_info, 3);
 						names_ptr = ir_emit_struct_ep(proc, enum_info, 3);
 					} else if (type->kind == Type_Record) {
 					} else if (type->kind == Type_Record) {
-						irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_record_ptr);
+						irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
 						names_ptr = ir_emit_struct_ep(proc, record_info, 3);
 						names_ptr = ir_emit_struct_ep(proc, record_info, 3);
 					}
 					}
 					return ir_addr(names_ptr);
 					return ir_addr(names_ptr);
@@ -6266,7 +6264,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 					irValue *init = ir_build_expr(proc, vd->values[i]);
 					irValue *init = ir_build_expr(proc, vd->values[i]);
 					Type *t = ir_type(init);
 					Type *t = ir_type(init);
 					if (t->kind == Type_Tuple) {
 					if (t->kind == Type_Tuple) {
-						for (isize i = 0; i < t->Tuple.variable_count; i++) {
+						for_array(i, t->Tuple.variables) {
 							Entity *e = t->Tuple.variables[i];
 							Entity *e = t->Tuple.variables[i];
 							irValue *v = ir_emit_struct_ev(proc, init, i);
 							irValue *v = ir_emit_struct_ev(proc, init, i);
 							array_add(&inits, v);
 							array_add(&inits, v);
@@ -6331,7 +6329,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 					Type *t = ir_type(init);
 					Type *t = ir_type(init);
 					// TODO(bill): refactor for code reuse as this is repeated a bit
 					// TODO(bill): refactor for code reuse as this is repeated a bit
 					if (t->kind == Type_Tuple) {
 					if (t->kind == Type_Tuple) {
-						for (isize i = 0; i < t->Tuple.variable_count; i++) {
+						for_array(i, t->Tuple.variables) {
 							Entity *e = t->Tuple.variables[i];
 							Entity *e = t->Tuple.variables[i];
 							irValue *v = ir_emit_struct_ev(proc, init, i);
 							irValue *v = ir_emit_struct_ev(proc, init, i);
 							array_add(&inits, v);
 							array_add(&inits, v);
@@ -6463,7 +6461,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 				irValue *res = ir_build_expr(proc, rs->results[res_index]);
 				irValue *res = ir_build_expr(proc, rs->results[res_index]);
 				Type *t = ir_type(res);
 				Type *t = ir_type(res);
 				if (t->kind == Type_Tuple) {
 				if (t->kind == Type_Tuple) {
-					for (isize i = 0; i < t->Tuple.variable_count; i++) {
+					for_array(i, t->Tuple.variables) {
 						Entity *e = t->Tuple.variables[i];
 						Entity *e = t->Tuple.variables[i];
 						irValue *v = ir_emit_struct_ev(proc, res, i);
 						irValue *v = ir_emit_struct_ev(proc, res, i);
 						array_add(&results, v);
 						array_add(&results, v);
@@ -6934,7 +6932,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 					irValue *variant_tag = nullptr;
 					irValue *variant_tag = nullptr;
 					Type *ut = base_type(type_deref(parent_type));
 					Type *ut = base_type(type_deref(parent_type));
 					GB_ASSERT(ut->kind == Type_Union);
 					GB_ASSERT(ut->kind == Type_Union);
-					for (isize variant_index = 1; variant_index < ut->Union.variant_count; variant_index++) {
+					for_array(variant_index, ut->Union.variants) {
 						Type *vt = ut->Union.variants[variant_index];
 						Type *vt = ut->Union.variants[variant_index];
 						if (are_types_identical(vt, bt)) {
 						if (are_types_identical(vt, bt)) {
 							variant_tag = ir_type_info(proc, vt);
 							variant_tag = ir_type_info(proc, vt);
@@ -7154,7 +7152,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
 		isize q_index = 0;
 		isize q_index = 0;
 
 
 		TypeTuple *params = &proc->type->Proc.params->Tuple;
 		TypeTuple *params = &proc->type->Proc.params->Tuple;
-		for (isize i = 0; i < params->variable_count; i++) {
+		for_array(i, params->variables) {
 			ast_node(fl, FieldList, pt->params);
 			ast_node(fl, FieldList, pt->params);
 			GB_ASSERT(fl->list.count > 0);
 			GB_ASSERT(fl->list.count > 0);
 			GB_ASSERT(fl->list[0]->kind == AstNode_Field);
 			GB_ASSERT(fl->list[0]->kind == AstNode_Field);
@@ -7340,13 +7338,13 @@ void ir_init_module(irModule *m, Checker *c) {
 
 
 				switch (t->kind) {
 				switch (t->kind) {
 				case Type_Union:
 				case Type_Union:
-					count += t->Union.variant_count;
+					count += t->Union.variants.count;
 					break;
 					break;
 				case Type_Record:
 				case Type_Record:
 					count += t->Record.field_count;
 					count += t->Record.field_count;
 					break;
 					break;
 				case Type_Tuple:
 				case Type_Tuple:
-					count += t->Tuple.variable_count;
+					count += t->Tuple.variables.count;
 					break;
 					break;
 				}
 				}
 			}
 			}
@@ -7718,11 +7716,8 @@ void ir_gen_tree(irGen *s) {
 
 
 		Scope *proc_scope = gb_alloc_item(a, Scope);
 		Scope *proc_scope = gb_alloc_item(a, Scope);
 
 
-		proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 3);
-		proc_params->Tuple.variable_count = 3;
-
-		proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
-		proc_results->Tuple.variable_count = 1;
+		array_init_count(&proc_params->Tuple.variables, a, 3);
+		array_init_count(&proc_results->Tuple.variables, a, 1);
 
 
 		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
 		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
 		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
 		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
@@ -8078,10 +8073,10 @@ void ir_gen_tree(irGen *s) {
 					ir_emit_comment(proc, str_lit("TypeInfoTuple"));
 					ir_emit_comment(proc, str_lit("TypeInfoTuple"));
 					tag = ir_emit_conv(proc, variant_ptr, t_type_info_tuple_ptr);
 					tag = ir_emit_conv(proc, variant_ptr, t_type_info_tuple_ptr);
 
 
-					irValue *memory_types = ir_type_info_member_types_offset(proc, t->Tuple.variable_count);
-					irValue *memory_names = ir_type_info_member_names_offset(proc, t->Tuple.variable_count);
+					irValue *memory_types = ir_type_info_member_types_offset(proc, t->Tuple.variables.count);
+					irValue *memory_names = ir_type_info_member_names_offset(proc, t->Tuple.variables.count);
 
 
-					for (isize i = 0; i < t->Tuple.variable_count; i++) {
+					for_array(i, t->Tuple.variables) {
 						// NOTE(bill): offset is not used for tuples
 						// NOTE(bill): offset is not used for tuples
 						Entity *f = t->Tuple.variables[i];
 						Entity *f = t->Tuple.variables[i];
 
 
@@ -8095,7 +8090,7 @@ void ir_gen_tree(irGen *s) {
 						}
 						}
 					}
 					}
 
 
-					irValue *count = ir_const_int(a, t->Tuple.variable_count);
+					irValue *count = ir_const_int(a, t->Tuple.variables.count);
 					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
 					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
 					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
 					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
 				} break;
 				} break;
@@ -8152,12 +8147,12 @@ void ir_gen_tree(irGen *s) {
 						irValue *variant_types  = ir_emit_struct_ep(proc, tag, 0);
 						irValue *variant_types  = ir_emit_struct_ep(proc, tag, 0);
 						irValue *tag_offset_ptr = ir_emit_struct_ep(proc, tag, 1);
 						irValue *tag_offset_ptr = ir_emit_struct_ep(proc, tag, 1);
 
 
-						isize variant_count = gb_max(0, t->Union.variant_count-1);
+						isize variant_count = gb_max(0, t->Union.variants.count);
 						irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
 						irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
 
 
 						// NOTE(bill): Zeroth is nil so ignore it
 						// NOTE(bill): Zeroth is nil so ignore it
 						for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
 						for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
-							Type *vt = t->Union.variants[variant_index+1]; // Skip zeroth
+							Type *vt = t->Union.variants[variant_index];
 							irValue *tip = ir_get_type_info_ptr(proc, vt);
 							irValue *tip = ir_get_type_info_ptr(proc, vt);
 
 
 							irValue *index     = ir_const_int(a, variant_index);
 							irValue *index     = ir_const_int(a, variant_index);
@@ -8175,77 +8170,57 @@ void ir_gen_tree(irGen *s) {
 				} break;
 				} break;
 
 
 				case Type_Record: {
 				case Type_Record: {
-					if (t->Record.is_raw_union) {
-						ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
-						tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
-
-						irValue *memory_types   = ir_type_info_member_types_offset(proc, t->Record.field_count);
-						irValue *memory_names   = ir_type_info_member_names_offset(proc, t->Record.field_count);
-						irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
+					ir_emit_comment(proc, str_lit("TypeInfoStruct"));
+					tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr);
 
 
-						for (isize i = 0; i < t->Record.field_count; i++) {
-							Entity *f = t->Record.fields[i];
-							irValue *index     = ir_const_int(a, i);
-							irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
-							// NOTE(bill): Offsets are always 0
+					{
+						irValue *is_packed       = ir_const_bool(a, t->Record.is_packed);
+						irValue *is_ordered      = ir_const_bool(a, t->Record.is_ordered);
+						irValue *is_raw_union    = ir_const_bool(a, t->Record.is_raw_union);
+						irValue *is_custom_align = ir_const_bool(a, t->Record.custom_align != 0);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_ordered);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
+					}
 
 
-							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));
-							}
+					i32 count = t->Record.field_count;
+
+					irValue *memory_types   = ir_type_info_member_types_offset  (proc, count);
+					irValue *memory_names   = ir_type_info_member_names_offset  (proc, count);
+					irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count);
+					irValue *memory_usings  = ir_type_info_member_usings_offset (proc, count);
+
+					type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet
+					for (isize source_index = 0; source_index < count; source_index++) {
+						// TODO(bill): Order fields in source order not layout order
+						Entity *f = t->Record.fields_in_src_order[source_index];
+						irValue *tip = ir_get_type_info_ptr(proc, f->type);
+						i64 foffset = 0;
+						if (!t->Record.is_raw_union) {
+							foffset = t->Record.offsets[f->Variable.field_index];
 						}
 						}
+						GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
 
 
-						irValue *count = ir_const_int(a, t->Record.field_count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   count, count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   count, count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
-					} else {
-						ir_emit_comment(proc, str_lit("TypeInfoStruct"));
-						tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr);
-
-						{
-							irValue *packed       = ir_const_bool(a, t->Record.is_packed);
-							irValue *ordered      = ir_const_bool(a, t->Record.is_ordered);
-							irValue *custom_align = ir_const_bool(a, t->Record.custom_align != 0);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), packed);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), ordered);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), custom_align);
-						}
+						irValue *index     = ir_const_int(a, source_index);
+						irValue *type_info = ir_emit_ptr_offset(proc, memory_types,   index);
+						irValue *offset    = ir_emit_ptr_offset(proc, memory_offsets, index);
+						irValue *is_using  = ir_emit_ptr_offset(proc, memory_usings, index);
 
 
-						irValue *memory_types   = ir_type_info_member_types_offset(proc, t->Record.field_count);
-						irValue *memory_names   = ir_type_info_member_names_offset(proc, t->Record.field_count);
-						irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
-						irValue *memory_usings  = ir_type_info_member_usings_offset(proc, t->Record.field_count);
-
-						type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet
-						for (isize source_index = 0; source_index < t->Record.field_count; source_index++) {
-							// TODO(bill): Order fields in source order not layout order
-							Entity *f = t->Record.fields_in_src_order[source_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, source_index);
-							irValue *type_info = ir_emit_ptr_offset(proc, memory_types,   index);
-							irValue *offset    = ir_emit_ptr_offset(proc, memory_offsets, index);
-							irValue *is_using  = ir_emit_ptr_offset(proc, memory_usings, 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));
-							ir_emit_store(proc, is_using, ir_const_bool(a, (f->flags&EntityFlag_Using) != 0));
+						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));
 						}
 						}
-
-						irValue *count = ir_const_int(a, t->Record.field_count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   count, count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   count, count);
-						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);
+						ir_emit_store(proc, offset, ir_const_int(a, foffset));
+						ir_emit_store(proc, is_using, ir_const_bool(a, (f->flags&EntityFlag_Using) != 0));
 					}
 					}
+
+					irValue *cv = ir_const_int(a, count);
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   cv, cv);
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   cv, cv);
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv, cv);
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings,  cv, cv);
 				} break;
 				} break;
 				case Type_Map: {
 				case Type_Map: {
 					ir_emit_comment(proc, str_lit("TypeInfoMap"));
 					ir_emit_comment(proc, str_lit("TypeInfoMap"));

+ 9 - 13
src/ir_print.cpp

@@ -155,12 +155,11 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
 		Type *rt = t->Proc.abi_compat_result_type;
 		Type *rt = t->Proc.abi_compat_result_type;
 		if (!is_type_tuple(rt)) {
 		if (!is_type_tuple(rt)) {
 			ir_print_type(f, m, rt);
 			ir_print_type(f, m, rt);
-		} else if (rt->Tuple.variable_count == 1) {
+		} else if (rt->Tuple.variables.count == 1) {
 			ir_print_type(f, m, rt->Tuple.variables[0]->type);
 			ir_print_type(f, m, rt->Tuple.variables[0]->type);
 		} else {
 		} else {
-			isize count = rt->Tuple.variable_count;
 			ir_fprintf(f, "{");
 			ir_fprintf(f, "{");
-			for (isize i = 0; i < count; i++) {
+			for_array(i, rt->Tuple.variables) {
 				Entity *e = rt->Tuple.variables[i];
 				Entity *e = rt->Tuple.variables[i];
 				if (i > 0) {
 				if (i > 0) {
 					ir_fprintf(f, ", ");
 					ir_fprintf(f, ", ");
@@ -344,15 +343,13 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		}
 		}
 		return;
 		return;
 	case Type_Tuple:
 	case Type_Tuple:
-		if (t->Tuple.variable_count == 1) {
+		if (t->Tuple.variables.count == 1) {
 			ir_print_type(f, m, t->Tuple.variables[0]->type);
 			ir_print_type(f, m, t->Tuple.variables[0]->type);
 		} else {
 		} else {
 			ir_fprintf(f, "{");
 			ir_fprintf(f, "{");
 			isize index = 0;
 			isize index = 0;
-			for (isize i = 0; i < t->Tuple.variable_count; i++) {
-				if (index > 0) {
-					ir_fprintf(f, ", ");
-				}
+			for_array(i, t->Tuple.variables) {
+				if (index > 0) ir_fprintf(f, ", ");
 				Entity *e = t->Tuple.variables[i];
 				Entity *e = t->Tuple.variables[i];
 				if (e->kind == Entity_Variable) {
 				if (e->kind == Entity_Variable) {
 					ir_print_type(f, m, e->type);
 					ir_print_type(f, m, e->type);
@@ -1352,7 +1349,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 			TypeTuple *params = &proc_type->Proc.params->Tuple;
 			TypeTuple *params = &proc_type->Proc.params->Tuple;
 			if (proc_type->Proc.c_vararg) {
 			if (proc_type->Proc.c_vararg) {
 				isize i = 0;
 				isize i = 0;
-				for (; i < params->variable_count-1; i++) {
+				for (; i < params->variables.count-1; i++) {
 					Entity *e = params->variables[i];
 					Entity *e = params->variables[i];
 					GB_ASSERT(e != nullptr);
 					GB_ASSERT(e != nullptr);
 					if (e->kind != Entity_Variable) continue;
 					if (e->kind != Entity_Variable) continue;
@@ -1380,9 +1377,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 					param_index++;
 					param_index++;
 				}
 				}
 			} else {
 			} else {
-				GB_ASSERT(call->arg_count == params->variable_count);
-				isize param_count = params->variable_count;
-				for (isize i = 0; i < param_count; i++) {
+				GB_ASSERT(call->arg_count == params->variables.count);
+				for_array(i, params->variables) {
 					Entity *e = params->variables[i];
 					Entity *e = params->variables[i];
 					GB_ASSERT(e != nullptr);
 					GB_ASSERT(e != nullptr);
 					if (e->kind != Entity_Variable) continue;
 					if (e->kind != Entity_Variable) continue;
@@ -1645,7 +1641,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 			if (e->kind != Entity_Variable) continue;
 			if (e->kind != Entity_Variable) continue;
 			if (param_index > 0) ir_fprintf(f, ", ");
 			if (param_index > 0) ir_fprintf(f, ", ");
 
 
-			if (i+1 == params->variable_count && proc_type->c_vararg) {
+			if (i+1 == params->variables.count && proc_type->c_vararg) {
 				ir_fprintf(f, " ...");
 				ir_fprintf(f, " ...");
 			} else {
 			} else {
 				ir_print_type(f, m, abi_type);
 				ir_print_type(f, m, abi_type);

+ 26 - 23
src/parser.cpp

@@ -2291,34 +2291,37 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		Token token = expect_token(f, Token_proc);
 		Token token = expect_token(f, Token_proc);
 		String link_name = {};
 		String link_name = {};
 		AstNode *type = parse_proc_type(f, token, &link_name);
 		AstNode *type = parse_proc_type(f, token, &link_name);
+
+		if (f->allow_type && f->expr_level < 0) {
+			return type;
+		}
+
 		u64 tags = type->ProcType.tags;
 		u64 tags = type->ProcType.tags;
 
 
 		if (allow_token(f, Token_Undef)) {
 		if (allow_token(f, Token_Undef)) {
 			return ast_proc_lit(f, type, nullptr, tags, link_name);
 			return ast_proc_lit(f, type, nullptr, tags, link_name);
-		} else if (!f->allow_type || f->expr_level >= 0) {
-			if (f->curr_token.kind == Token_OpenBrace) {
-				if ((tags & ProcTag_foreign) != 0) {
-					syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
-				}
-				AstNode *curr_proc = f->curr_proc;
-				AstNode *body = nullptr;
-				f->curr_proc = type;
-				body = parse_body(f);
-				f->curr_proc = curr_proc;
-
-				return ast_proc_lit(f, type, body, tags, link_name);
-			} else if (allow_token(f, Token_do)) {
-				if ((tags & ProcTag_foreign) != 0) {
-					syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
-				}
-				AstNode *curr_proc = f->curr_proc;
-				AstNode *body = nullptr;
-				f->curr_proc = type;
-				body = convert_stmt_to_body(f, parse_stmt(f));
-				f->curr_proc = curr_proc;
-
-				return ast_proc_lit(f, type, body, tags, link_name);
+		} else if (f->curr_token.kind == Token_OpenBrace) {
+			if ((tags & ProcTag_foreign) != 0) {
+				syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
+			}
+			AstNode *curr_proc = f->curr_proc;
+			AstNode *body = nullptr;
+			f->curr_proc = type;
+			body = parse_body(f);
+			f->curr_proc = curr_proc;
+
+			return ast_proc_lit(f, type, body, tags, link_name);
+		} else if (allow_token(f, Token_do)) {
+			if ((tags & ProcTag_foreign) != 0) {
+				syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
 			}
 			}
+			AstNode *curr_proc = f->curr_proc;
+			AstNode *body = nullptr;
+			f->curr_proc = type;
+			body = convert_stmt_to_body(f, parse_stmt(f));
+			f->curr_proc = curr_proc;
+
+			return ast_proc_lit(f, type, body, tags, link_name);
 		}
 		}
 
 
 		if ((tags & ProcTag_foreign) != 0) {
 		if ((tags & ProcTag_foreign) != 0) {

+ 6 - 12
src/ssa.cpp

@@ -639,10 +639,10 @@ bool can_ssa_type(Type *t) {
 	case Type_Map:
 	case Type_Map:
 		return false;
 		return false;
 	case Type_Tuple:
 	case Type_Tuple:
-		if (t->Tuple.variable_count > SSA_MAX_STRUCT_FIELD_COUNT) {
+		if (t->Tuple.variables.count > SSA_MAX_STRUCT_FIELD_COUNT) {
 			return false;
 			return false;
 		}
 		}
-		for (isize i = 0; i < t->Tuple.variable_count; i++) {
+		for_array(i, t->Tuple.variables) {
 			if (!can_ssa_type(t->Tuple.variables[i]->type)) {
 			if (!can_ssa_type(t->Tuple.variables[i]->type)) {
 				return false;
 				return false;
 			}
 			}
@@ -813,14 +813,9 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
 		GB_ASSERT(t->Record.field_count > 0);
 		GB_ASSERT(t->Record.field_count > 0);
 		GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
 		GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
 		result_type = make_type_pointer(a, t->Record.fields[index]->type);
 		result_type = make_type_pointer(a, t->Record.fields[index]->type);
-	} else if (is_type_union(t)) {
-		type_set_offsets(a, t);
-		GB_ASSERT(t->Record.field_count > 0);
-		GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
-		result_type = make_type_pointer(a, t->Record.fields[index]->type);
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
-		GB_ASSERT(t->Tuple.variable_count > 0);
-		GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+		GB_ASSERT(t->Tuple.variables.count > 0);
+		GB_ASSERT(gb_is_between(index, 0, t->Tuple.variables.count-1));
 		result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
 		result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
 	} else if (is_type_slice(t)) {
 	} else if (is_type_slice(t)) {
 		switch (index) {
 		switch (index) {
@@ -882,8 +877,7 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
 		GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
 		GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
 		result_type = t->Record.fields[index]->type;
 		result_type = t->Record.fields[index]->type;
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
-		GB_ASSERT(t->Tuple.variable_count > 0);
-		GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+		GB_ASSERT(t->Tuple.variables.count > 0);
 		result_type = t->Tuple.variables[index]->type;
 		result_type = t->Tuple.variables[index]->type;
 	} else if (is_type_slice(t)) {
 	} else if (is_type_slice(t)) {
 		switch (index) {
 		switch (index) {
@@ -2015,7 +2009,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
 					Type *t = base_type(init->type);
 					Type *t = base_type(init->type);
 					// TODO(bill): refactor for code reuse as this is repeated a bit
 					// TODO(bill): refactor for code reuse as this is repeated a bit
 					if (t->kind == Type_Tuple) {
 					if (t->kind == Type_Tuple) {
-						for (isize i = 0; i < t->Tuple.variable_count; i++) {
+						for_array(i, t->Tuple.variables) {
 							Entity *e = t->Tuple.variables[i];
 							Entity *e = t->Tuple.variables[i];
 							ssaValue *v = ssa_emit_value_index(p, init, i);
 							ssaValue *v = ssa_emit_value_index(p, init, i);
 							array_add(&inits, v);
 							array_add(&inits, v);

+ 22 - 31
src/types.cpp

@@ -119,8 +119,7 @@ struct TypeRecord {
 		Entity * max_value;                               \
 		Entity * max_value;                               \
 	})                                                    \
 	})                                                    \
 	TYPE_KIND(Union, struct {                             \
 	TYPE_KIND(Union, struct {                             \
-		Type **  variants;                                \
-		i32      variant_count;                           \
+		Array<Type *> variants;                           \
 		AstNode *node;                                    \
 		AstNode *node;                                    \
 		Scope *  scope;                                   \
 		Scope *  scope;                                   \
 		Entity * union__type_info;                        \
 		Entity * union__type_info;                        \
@@ -133,8 +132,7 @@ struct TypeRecord {
 		Entity *type_name; /* Entity_TypeName */          \
 		Entity *type_name; /* Entity_TypeName */          \
 	})                                                    \
 	})                                                    \
 	TYPE_KIND(Tuple, struct {                             \
 	TYPE_KIND(Tuple, struct {                             \
-		Entity **variables; /* Entity_Variable */         \
-		i32      variable_count;                          \
+		Array<Entity *> variables; /* Entity_Variable */  \
 		bool     are_offsets_set;                         \
 		bool     are_offsets_set;                         \
 		i64 *    offsets;                                 \
 		i64 *    offsets;                                 \
 	})                                                    \
 	})                                                    \
@@ -330,10 +328,8 @@ gb_global Type *t_string_slice = nullptr;
 
 
 // Type generated for the "preload" file
 // Type generated for the "preload" file
 gb_global Type *t_type_info                   = nullptr;
 gb_global Type *t_type_info                   = nullptr;
-gb_global Type *t_type_info_record            = nullptr;
 gb_global Type *t_type_info_enum_value        = nullptr;
 gb_global Type *t_type_info_enum_value        = nullptr;
 gb_global Type *t_type_info_ptr               = nullptr;
 gb_global Type *t_type_info_ptr               = nullptr;
-gb_global Type *t_type_info_record_ptr        = nullptr;
 gb_global Type *t_type_info_enum_value_ptr    = nullptr;
 gb_global Type *t_type_info_enum_value_ptr    = nullptr;
 
 
 gb_global Type *t_type_info_named             = nullptr;
 gb_global Type *t_type_info_named             = nullptr;
@@ -352,7 +348,6 @@ gb_global Type *t_type_info_slice             = nullptr;
 gb_global Type *t_type_info_vector            = nullptr;
 gb_global Type *t_type_info_vector            = nullptr;
 gb_global Type *t_type_info_tuple             = nullptr;
 gb_global Type *t_type_info_tuple             = nullptr;
 gb_global Type *t_type_info_struct            = nullptr;
 gb_global Type *t_type_info_struct            = nullptr;
-gb_global Type *t_type_info_raw_union         = nullptr;
 gb_global Type *t_type_info_union             = nullptr;
 gb_global Type *t_type_info_union             = nullptr;
 gb_global Type *t_type_info_enum              = nullptr;
 gb_global Type *t_type_info_enum              = nullptr;
 gb_global Type *t_type_info_map               = nullptr;
 gb_global Type *t_type_info_map               = nullptr;
@@ -375,7 +370,6 @@ gb_global Type *t_type_info_slice_ptr         = nullptr;
 gb_global Type *t_type_info_vector_ptr        = nullptr;
 gb_global Type *t_type_info_vector_ptr        = nullptr;
 gb_global Type *t_type_info_tuple_ptr         = nullptr;
 gb_global Type *t_type_info_tuple_ptr         = nullptr;
 gb_global Type *t_type_info_struct_ptr        = nullptr;
 gb_global Type *t_type_info_struct_ptr        = nullptr;
-gb_global Type *t_type_info_raw_union_ptr     = nullptr;
 gb_global Type *t_type_info_union_ptr         = nullptr;
 gb_global Type *t_type_info_union_ptr         = nullptr;
 gb_global Type *t_type_info_enum_ptr          = nullptr;
 gb_global Type *t_type_info_enum_ptr          = nullptr;
 gb_global Type *t_type_info_map_ptr           = nullptr;
 gb_global Type *t_type_info_map_ptr           = nullptr;
@@ -951,7 +945,7 @@ bool is_type_polymorphic(Type *t) {
 		return is_type_polymorphic(t->Slice.elem);
 		return is_type_polymorphic(t->Slice.elem);
 
 
 	case Type_Tuple:
 	case Type_Tuple:
-		for (isize i = 0; i < t->Tuple.variable_count; i++) {
+		for_array(i, t->Tuple.variables) {
 			if (is_type_polymorphic(t->Tuple.variables[i]->type)) {
 			if (is_type_polymorphic(t->Tuple.variables[i]->type)) {
 				return true;
 				return true;
 			}
 			}
@@ -983,7 +977,7 @@ bool is_type_polymorphic(Type *t) {
 		}
 		}
 		break;
 		break;
 	case Type_Union:
 	case Type_Union:
-		for (isize i = 1; i < t->Union.variant_count; i++) {
+		for_array(i, t->Union.variants) {
 		    if (is_type_polymorphic(t->Union.variants[i])) {
 		    if (is_type_polymorphic(t->Union.variants[i])) {
 		    	return true;
 		    	return true;
 		    }
 		    }
@@ -1125,10 +1119,10 @@ bool are_types_identical(Type *x, Type *y) {
 
 
 	case Type_Union:
 	case Type_Union:
 		if (y->kind == Type_Union) {
 		if (y->kind == Type_Union) {
-			if (x->Union.variant_count == y->Union.variant_count &&
+			if (x->Union.variants.count == y->Union.variants.count &&
 			    x->Union.custom_align == y->Union.custom_align) {
 			    x->Union.custom_align == y->Union.custom_align) {
 				// NOTE(bill): zeroth variant is nullptr
 				// NOTE(bill): zeroth variant is nullptr
-				for (isize i = 1; i < x->Union.variant_count; i++) {
+				for_array(i, x->Union.variants) {
 					if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
 					if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
 						return false;
 						return false;
 					}
 					}
@@ -1180,8 +1174,8 @@ bool are_types_identical(Type *x, Type *y) {
 
 
 	case Type_Tuple:
 	case Type_Tuple:
 		if (y->kind == Type_Tuple) {
 		if (y->kind == Type_Tuple) {
-			if (x->Tuple.variable_count == y->Tuple.variable_count) {
-				for (isize i = 0; i < x->Tuple.variable_count; i++) {
+			if (x->Tuple.variables.count == y->Tuple.variables.count) {
+				for_array(i, x->Tuple.variables) {
 					Entity *xe = x->Tuple.variables[i];
 					Entity *xe = x->Tuple.variables[i];
 					Entity *ye = y->Tuple.variables[i];
 					Entity *ye = y->Tuple.variables[i];
 					if (xe->kind != ye->kind || !are_types_identical(xe->type, ye->type)) {
 					if (xe->kind != ye->kind || !are_types_identical(xe->type, ye->type)) {
@@ -1299,7 +1293,7 @@ bool is_type_cte_safe(Type *type) {
 	}
 	}
 
 
 	case Type_Tuple: {
 	case Type_Tuple: {
-		for (isize i = 0; i < type->Tuple.variable_count; i++) {
+		for_array(i, type->Tuple.variables) {
 			Entity *v = type->Tuple.variables[i];
 			Entity *v = type->Tuple.variables[i];
 			if (!is_type_cte_safe(v->type)) {
 			if (!is_type_cte_safe(v->type)) {
 				return false;
 				return false;
@@ -1411,9 +1405,9 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
 
 
 	i64 max_count = 0;
 	i64 max_count = 0;
 	switch (type->kind) {
 	switch (type->kind) {
-	case Type_Record:   max_count = type->Record.field_count;   break;
-	case Type_Tuple:    max_count = type->Tuple.variable_count; break;
-	case Type_BitField: max_count = type->BitField.field_count; break;
+	case Type_Record:   max_count = type->Record.field_count;    break;
+	case Type_Tuple:    max_count = type->Tuple.variables.count; break;
+	case Type_BitField: max_count = type->BitField.field_count;  break;
 	}
 	}
 
 
 	if (index >= max_count) {
 	if (index >= max_count) {
@@ -1813,7 +1807,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 
 	case Type_Tuple: {
 	case Type_Tuple: {
 		i64 max = 1;
 		i64 max = 1;
-		for (isize i = 0; i < t->Tuple.variable_count; i++) {
+		for_array(i, t->Tuple.variables) {
 			i64 align = type_align_of_internal(allocator, t->Tuple.variables[i]->type, path);
 			i64 align = type_align_of_internal(allocator, t->Tuple.variables[i]->type, path);
 			if (max < align) {
 			if (max < align) {
 				max = align;
 				max = align;
@@ -1834,8 +1828,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 
 	case Type_Union: {
 	case Type_Union: {
 		i64 max = build_context.word_size;
 		i64 max = build_context.word_size;
-		// NOTE(bill): field zero is null
-		for (isize i = 1; i < t->Union.variant_count; i++) {
+		for_array(i, t->Union.variants) {
 			Type *variant = t->Union.variants[i];
 			Type *variant = t->Union.variants[i];
 			type_path_push(path, variant);
 			type_path_push(path, variant);
 			if (path->failure) {
 			if (path->failure) {
@@ -1944,7 +1937,7 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
 		if (!t->Tuple.are_offsets_set) {
 		if (!t->Tuple.are_offsets_set) {
 			t->Record.are_offsets_being_processed = true;
 			t->Record.are_offsets_being_processed = true;
-			t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false, false);
+			t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables.data, t->Tuple.variables.count, false, false);
 			t->Tuple.are_offsets_set = true;
 			t->Tuple.are_offsets_set = true;
 			return true;
 			return true;
 		}
 		}
@@ -2054,7 +2047,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 
 	case Type_Tuple: {
 	case Type_Tuple: {
 		i64 count, align, size;
 		i64 count, align, size;
-		count = t->Tuple.variable_count;
+		count = t->Tuple.variables.count;
 		if (count == 0) {
 		if (count == 0) {
 			return 0;
 			return 0;
 		}
 		}
@@ -2075,10 +2068,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 
 		i64 max = 0;
 		i64 max = 0;
 		i64 field_size = 0;
 		i64 field_size = 0;
-		isize variant_count = t->Union.variant_count;
 
 
-
-		for (isize i = 1; i < variant_count; i++) {
+		for_array(i, t->Union.variants) {
 			Type *variant_type = t->Union.variants[i];
 			Type *variant_type = t->Union.variants[i];
 			i64 size = type_size_of_internal(allocator, variant_type, path);
 			i64 size = type_size_of_internal(allocator, variant_type, path);
 			if (max < size) {
 			if (max < size) {
@@ -2158,7 +2149,7 @@ i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
 		}
 		}
 	} else if (t->kind == Type_Tuple) {
 	} else if (t->kind == Type_Tuple) {
 		type_set_offsets(allocator, t);
 		type_set_offsets(allocator, t);
-		if (gb_is_between(index, 0, t->Tuple.variable_count-1)) {
+		if (gb_is_between(index, 0, t->Tuple.variables.count-1)) {
 			return t->Tuple.offsets[index];
 			return t->Tuple.offsets[index];
 		}
 		}
 	}  else if (t->kind == Type_Basic) {
 	}  else if (t->kind == Type_Basic) {
@@ -2309,9 +2300,9 @@ gbString write_type_to_string(gbString str, Type *type) {
 
 
 	case Type_Union:
 	case Type_Union:
 		str = gb_string_appendc(str, "union{");
 		str = gb_string_appendc(str, "union{");
-		for (isize i = 1; i < type->Union.variant_count; i++) {
+		for_array(i, type->Union.variants) {
 			Type *t = type->Union.variants[i];
 			Type *t = type->Union.variants[i];
-			if (i > 1) str = gb_string_appendc(str, ", ");
+			if (i > 0) str = gb_string_appendc(str, ", ");
 			str = write_type_to_string(str, t);
 			str = write_type_to_string(str, t);
 		}
 		}
 		str = gb_string_appendc(str, "}");
 		str = gb_string_appendc(str, "}");
@@ -2374,8 +2365,8 @@ gbString write_type_to_string(gbString str, Type *type) {
 		break;
 		break;
 
 
 	case Type_Tuple:
 	case Type_Tuple:
-		if (type->Tuple.variable_count > 0) {
-			for (isize i = 0; i < type->Tuple.variable_count; i++) {
+		if (type->Tuple.variables.count > 0) {
+			for_array(i, type->Tuple.variables) {
 				Entity *var = type->Tuple.variables[i];
 				Entity *var = type->Tuple.variables[i];
 				if (var != nullptr) {
 				if (var != nullptr) {
 					if (i > 0) {
 					if (i > 0) {