Przeglądaj źródła

Begin minimize `Type` size by replacing `Array` with `Slice` etc

gingerBill 4 lat temu
rodzic
commit
fb8fa5217d

+ 13 - 0
src/array.cpp

@@ -150,6 +150,19 @@ void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count
 
 
 
+template <typename T>
+gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
+	GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
+	Slice<T> out = {};
+	isize len = hi-lo;
+	if (len > 0) {
+		out.data = array.data+lo;
+		out.count = len;
+	}
+	return out;
+}
+
+
 template <typename T>
 void slice_ordered_remove(Slice<T> *array, isize index) {
 	GB_ASSERT(0 <= index && index < array->count);

+ 16 - 16
src/check_builtin.cpp

@@ -64,13 +64,13 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
 	Type *right_type = nullptr;
 	if (x->type->kind == Type_Tuple) {
 		auto const &vars = x->type->Tuple.variables;
-		auto lhs = array_slice(vars, 0, vars.count-1);
+		auto lhs = slice(vars, 0, vars.count-1);
 		auto rhs = vars[vars.count-1];
 		if (lhs.count == 1) {
 			left_type = lhs[0]->type;
 		} else if (lhs.count != 0) {
 			left_type = alloc_type_tuple();
-			left_type->Tuple.variables = array_make_from_ptr(lhs.data, lhs.count, lhs.count);
+			left_type->Tuple.variables = lhs;
 		}
 
 		right_type = rhs->type;
@@ -120,13 +120,13 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na
 	Type *right_type = nullptr;
 	if (x->type->kind == Type_Tuple) {
 		auto const &vars = x->type->Tuple.variables;
-		auto lhs = array_slice(vars, 0, vars.count-1);
+		auto lhs = slice(vars, 0, vars.count-1);
 		auto rhs = vars[vars.count-1];
 		if (lhs.count == 1) {
 			left_type = lhs[0]->type;
 		} else if (lhs.count != 0) {
 			left_type = alloc_type_tuple();
-			left_type->Tuple.variables = array_make_from_ptr(lhs.data, lhs.count, lhs.count);
+			left_type->Tuple.variables = lhs;
 		}
 
 		right_type = rhs->type;
@@ -1156,12 +1156,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 
 		if (is_type_struct(type)) {
 			isize variable_count = type->Struct.fields.count;
-			array_init(&tuple->Tuple.variables, a, variable_count);
+			slice_init(&tuple->Tuple.variables, a, variable_count);
 			// TODO(bill): Should I copy each of the entities or is this good enough?
 			gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count);
 		} else if (is_type_array(type)) {
 			isize variable_count = cast(isize)type->Array.count;
-			array_init(&tuple->Tuple.variables, a, variable_count);
+			slice_init(&tuple->Tuple.variables, a, variable_count);
 			for (isize i = 0; i < variable_count; i++) {
 				tuple->Tuple.variables[i] = alloc_entity_array_elem(nullptr, blank_token, type->Array.elem, cast(i32)i);
 			}
@@ -1240,14 +1240,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			} else if (is_type_enum(type)) {
 				operand->mode  = Addressing_Constant;
 				operand->type  = original_type;
-				operand->value = type->Enum.min_value;
+				operand->value = *type->Enum.min_value;
 				return true;
 			} else if (is_type_enumerated_array(type)) {
 				Type *bt = base_type(type);
 				GB_ASSERT(bt->kind == Type_EnumeratedArray);
 				operand->mode  = Addressing_Constant;
 				operand->type  = bt->EnumeratedArray.index;
-				operand->value = bt->EnumeratedArray.min_value;
+				operand->value = *bt->EnumeratedArray.min_value;
 				return true;
 			}
 			gbString type_str = type_to_string(original_type);
@@ -1414,14 +1414,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			} else if (is_type_enum(type)) {
 				operand->mode  = Addressing_Constant;
 				operand->type  = original_type;
-				operand->value = type->Enum.max_value;
+				operand->value = *type->Enum.max_value;
 				return true;
 			} else if (is_type_enumerated_array(type)) {
 				Type *bt = base_type(type);
 				GB_ASSERT(bt->kind == Type_EnumeratedArray);
 				operand->mode  = Addressing_Constant;
 				operand->type  = bt->EnumeratedArray.index;
-				operand->value = bt->EnumeratedArray.max_value;
+				operand->value = *bt->EnumeratedArray.max_value;
 				return true;
 			}
 			gbString type_str = type_to_string(original_type);
@@ -1788,8 +1788,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		if (elem == nullptr) {
 			elem = alloc_type_struct();
 			elem->Struct.scope = s;
-			elem->Struct.fields = fields;
-			elem->Struct.tags = array_make<String>(permanent_allocator(), fields.count);
+			elem->Struct.fields = slice_from_array(fields);
+			elem->Struct.tags = slice_make<String>(permanent_allocator(), fields.count);
 			elem->Struct.node = dummy_node_struct;
 			type_set_offsets(elem);
 		}
@@ -1938,8 +1938,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		if (is_type_array(elem)) {
 			Type *old_array = base_type(elem);
 			soa_struct = alloc_type_struct();
-			soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), cast(isize)old_array->Array.count);
-			soa_struct->Struct.tags = array_make<String>(heap_allocator(), cast(isize)old_array->Array.count);
+			soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), cast(isize)old_array->Array.count);
+			soa_struct->Struct.tags = slice_make<String>(heap_allocator(), cast(isize)old_array->Array.count);
 			soa_struct->Struct.node = operand->expr;
 			soa_struct->Struct.soa_kind = StructSoa_Fixed;
 			soa_struct->Struct.soa_elem = elem;
@@ -1971,8 +1971,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 
 			Type *old_struct = base_type(elem);
 			soa_struct = alloc_type_struct();
-			soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
-			soa_struct->Struct.tags = array_make<String>(heap_allocator(), old_struct->Struct.tags.count);
+			soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
+			soa_struct->Struct.tags = slice_make<String>(heap_allocator(), old_struct->Struct.tags.count);
 			soa_struct->Struct.node = operand->expr;
 			soa_struct->Struct.soa_kind = StructSoa_Fixed;
 			soa_struct->Struct.soa_elem = elem;

+ 24 - 12
src/check_expr.cpp

@@ -1023,10 +1023,10 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
 				if (poly->EnumeratedArray.count != source->EnumeratedArray.count) {
 					return false;
 				}
-				if (compare_exact_values(Token_NotEq, poly->EnumeratedArray.min_value, source->EnumeratedArray.min_value)) {
+				if (compare_exact_values(Token_NotEq, *poly->EnumeratedArray.min_value, *source->EnumeratedArray.min_value)) {
 					return false;
 				}
-				if (compare_exact_values(Token_NotEq, poly->EnumeratedArray.max_value, source->EnumeratedArray.max_value)) {
+				if (compare_exact_values(Token_NotEq, *poly->EnumeratedArray.max_value, *source->EnumeratedArray.max_value)) {
 					return false;
 				}
 				return is_polymorphic_type_assignable(c, poly->EnumeratedArray.index, source->EnumeratedArray.index, true, modify_type);
@@ -3425,8 +3425,8 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
 			if (is_type_enum(index_type)) {
 				Type *bt = base_type(index_type);
 				GB_ASSERT(bt->kind == Type_Enum);
-				ExactValue lo = bt->Enum.min_value;
-				ExactValue hi = bt->Enum.max_value;
+				ExactValue const &lo = *bt->Enum.min_value;
+				ExactValue const &hi = *bt->Enum.max_value;
 				String lo_str = {};
 				String hi_str = {};
 				if (bt->Enum.fields.count > 0) {
@@ -3556,7 +3556,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
 						if (is_type_enumerated_array(node->tav.type)) {
 							Type *bt = base_type(node->tav.type);
 							GB_ASSERT(bt->kind == Type_EnumeratedArray);
-							corrected_index = index + exact_value_to_i64(bt->EnumeratedArray.min_value);
+							corrected_index = index + exact_value_to_i64(*bt->EnumeratedArray.min_value);
 						}
 						if (op != Token_RangeHalf) {
 							if (lo <= corrected_index && corrected_index <= hi) {
@@ -3580,7 +3580,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
 						if (is_type_enumerated_array(node->tav.type)) {
 							Type *bt = base_type(node->tav.type);
 							GB_ASSERT(bt->kind == Type_EnumeratedArray);
-							index_value = exact_value_sub(index_value, bt->EnumeratedArray.min_value);
+							index_value = exact_value_sub(index_value, *bt->EnumeratedArray.min_value);
 						}
 
 						i64 field_index = exact_value_to_i64(index_value);
@@ -3738,6 +3738,18 @@ void check_did_you_mean_type(String const &name, Array<Entity *> const &fields)
 	check_did_you_mean_print(&d);
 }
 
+void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields) {
+	ERROR_BLOCK();
+	
+	DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
+	defer (did_you_mean_destroy(&d));
+
+	for_array(i, fields) {
+		did_you_mean_append(&d, fields[i]->token.string);
+	}
+	check_did_you_mean_print(&d);
+}
+
 void check_did_you_mean_scope(String const &name, Scope *scope) {
 	ERROR_BLOCK();
 	
@@ -7305,8 +7317,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 			gbString index_type_str = type_to_string(index_type);
 			defer (gb_string_free(index_type_str));
 
-			i64 total_lo = exact_value_to_i64(t->EnumeratedArray.min_value);
-			i64 total_hi = exact_value_to_i64(t->EnumeratedArray.max_value);
+			i64 total_lo = exact_value_to_i64(*t->EnumeratedArray.min_value);
+			i64 total_hi = exact_value_to_i64(*t->EnumeratedArray.max_value);
 
 			String total_lo_string = {};
 			String total_hi_string = {};
@@ -7319,10 +7331,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 					if (f->kind != Entity_Constant) {
 						continue;
 					}
-					if (total_lo_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, t->EnumeratedArray.min_value)) {
+					if (total_lo_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.min_value)) {
 						total_lo_string = f->token.string;
 					}
-					if (total_hi_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, t->EnumeratedArray.max_value)) {
+					if (total_hi_string.len == 0 && compare_exact_values(Token_CmpEq, f->Constant.value, *t->EnumeratedArray.max_value)) {
 						total_hi_string = f->token.string;
 					}
 					if (total_lo_string.len != 0 && total_hi_string.len != 0) {
@@ -8472,13 +8484,13 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		Type *params = alloc_type_tuple();
 		Type *results = alloc_type_tuple();
 		if (param_types.count != 0) {
-			array_init(&params->Tuple.variables, heap_allocator(), param_types.count);
+			slice_init(&params->Tuple.variables, heap_allocator(), param_types.count);
 			for_array(i, param_types) {
 				params->Tuple.variables[i] = alloc_entity_param(scope, blank_token, param_types[i], false, true);
 			}
 		}
 		if (return_type != nullptr) {
-			array_init(&results->Tuple.variables, heap_allocator(), 1);
+			slice_init(&results->Tuple.variables, heap_allocator(), 1);
 			results->Tuple.variables[0] = alloc_entity_param(scope, blank_token, return_type, false, true);
 		}
 

+ 29 - 26
src/check_type.cpp

@@ -92,10 +92,10 @@ bool does_field_type_allow_using(Type *t) {
 	return false;
 }
 
-void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Slice<Ast *> const &params,
+void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, Slice<String> *tags, Slice<Ast *> const &params,
                          isize init_field_capacity, Type *struct_type, String context) {
-	*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
-	*tags   = array_make<String>(heap_allocator(), 0, init_field_capacity);
+	auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
+	auto tags_array = array_make<String>(heap_allocator(), 0, init_field_capacity);
 
 	GB_ASSERT(node->kind == Ast_StructType);
 	GB_ASSERT(struct_type->kind == Type_Struct);
@@ -153,20 +153,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
 
 			Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
 			add_entity(ctx, ctx->scope, name, field);
-			array_add(fields, field);
+			array_add(&fields_array, field);
 			String tag = p->tag.string;
 			if (tag.len != 0 && !unquote_string(permanent_allocator(), &tag, 0, tag.text[0] == '`')) {
 				error(p->tag, "Invalid string literal");
 				tag = {};
 			}
-			array_add(tags, tag);
+			array_add(&tags_array, tag);
 
 			field_src_index += 1;
 		}
 
 
 		if (is_using && p->names.count > 0) {
-			Type *first_type = (*fields)[fields->count-1]->type;
+			Type *first_type = fields_array[fields_array.count-1]->type;
 			Type *t = base_type(type_deref(first_type));
 
 			if (!does_field_type_allow_using(t) &&
@@ -182,6 +182,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
 			populate_using_entity_scope(ctx, node, p, type);
 		}
 	}
+	
+	*fields = slice_from_array(fields_array);
+	*tags = slice_from_array(tags_array);
 }
 
 
@@ -498,7 +501,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
 
 		if (entities.count > 0) {
 			Type *tuple = alloc_type_tuple();
-			tuple->Tuple.variables = entities;
+			tuple->Tuple.variables = slice_from_array(entities);
 			polymorphic_params_type = tuple;
 		}
 	}
@@ -816,8 +819,8 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
 
 	enum_type->Enum.fields = fields;
 	enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope);
-	enum_type->Enum.min_value = min_value;
-	enum_type->Enum.max_value = max_value;
+	*enum_type->Enum.min_value = min_value;
+	*enum_type->Enum.max_value = max_value;
 
 	enum_type->Enum.min_value_index = min_value_index;
 	enum_type->Enum.max_value_index = max_value_index;
@@ -1705,7 +1708,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
 	}
 
 	Type *tuple = alloc_type_tuple();
-	tuple->Tuple.variables = variables;
+	tuple->Tuple.variables = slice_from_array(variables);
 
 	if (success_) *success_ = success;
 	if (specialization_count_) *specialization_count_ = specialization_count;
@@ -1815,7 +1818,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
 		}
 	}
 
-	tuple->Tuple.variables = variables;
+	tuple->Tuple.variables = slice_from_array(variables);
 
 	return tuple;
 }
@@ -2059,7 +2062,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
 Type *make_optional_ok_type(Type *value, bool typed) {
 	gbAllocator a = permanent_allocator();
 	Type *t = alloc_type_tuple();
-	array_init(&t->Tuple.variables, a, 2);
+	slice_init(&t->Tuple.variables, a, 2);
 	t->Tuple.variables[0] = alloc_entity_field(nullptr, blank_token, value,  false, 0);
 	t->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1);
 	return t;
@@ -2083,11 +2086,11 @@ void init_map_entry_type(Type *type) {
 	*/
 	Scope *s = create_scope(nullptr, builtin_pkg->scope);
 
-	auto fields = array_make<Entity *>(permanent_allocator(), 0, 4);
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hash")),  t_uintptr,       false, cast(i32)fields.count, EntityState_Resolved));
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")),  t_int,           false, cast(i32)fields.count, EntityState_Resolved));
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")),   type->Map.key,   false, cast(i32)fields.count, EntityState_Resolved));
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved));
+	auto fields = slice_make<Entity *>(permanent_allocator(), 4);
+	fields[0] = alloc_entity_field(s, make_token_ident(str_lit("hash")),  t_uintptr,       false, cast(i32)fields.count, EntityState_Resolved);
+	fields[1] = alloc_entity_field(s, make_token_ident(str_lit("next")),  t_int,           false, cast(i32)fields.count, EntityState_Resolved);
+	fields[2] = alloc_entity_field(s, make_token_ident(str_lit("key")),   type->Map.key,   false, cast(i32)fields.count, EntityState_Resolved);
+	fields[3] = alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved);
 
 
 	entry_type->Struct.fields = fields;
@@ -2120,9 +2123,9 @@ void init_map_internal_types(Type *type) {
 	Type *entries_type = alloc_type_dynamic_array(type->Map.entry_type);
 
 
-	auto fields = array_make<Entity *>(permanent_allocator(), 0, 2);
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0, EntityState_Resolved));
-	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
+	auto fields = slice_make<Entity *>(permanent_allocator(), 2);
+	fields[0] = alloc_entity_field(s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0, EntityState_Resolved);
+	fields[1] = alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved);
 
 	generated_struct_type->Struct.fields = fields;
 
@@ -2239,8 +2242,8 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
 		field_count = 0;
 
 		soa_struct = alloc_type_struct();
-		soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), field_count+extra_field_count);
-		soa_struct->Struct.tags = array_make<String>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.tags = slice_make<String>(heap_allocator(), field_count+extra_field_count);
 		soa_struct->Struct.node = array_typ_expr;
 		soa_struct->Struct.soa_kind = soa_kind;
 		soa_struct->Struct.soa_elem = elem;
@@ -2254,8 +2257,8 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
 		field_count = cast(isize)old_array->Array.count;
 
 		soa_struct = alloc_type_struct();
-		soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), field_count+extra_field_count);
-		soa_struct->Struct.tags = array_make<String>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.tags = slice_make<String>(heap_allocator(), field_count+extra_field_count);
 		soa_struct->Struct.node = array_typ_expr;
 		soa_struct->Struct.soa_kind = soa_kind;
 		soa_struct->Struct.soa_elem = elem;
@@ -2296,8 +2299,8 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
 		GB_ASSERT(old_struct->Struct.tags.count == field_count);
 
 		soa_struct = alloc_type_struct();
-		soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), field_count+extra_field_count);
-		soa_struct->Struct.tags = array_make<String>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), field_count+extra_field_count);
+		soa_struct->Struct.tags = slice_make<String>(heap_allocator(), field_count+extra_field_count);
 		soa_struct->Struct.node = array_typ_expr;
 		soa_struct->Struct.soa_kind = soa_kind;
 		soa_struct->Struct.soa_elem = elem;

+ 22 - 17
src/checker.cpp

@@ -4865,22 +4865,25 @@ void check_deferred_procedures(Checker *c) {
 		Entity *dst = src->Procedure.deferred_procedure.entity;
 		GB_ASSERT(dst != nullptr);
 		GB_ASSERT(dst->kind == Entity_Procedure);
+		
+		char const *attribute = "deferred_none";
+		switch (dst_kind) {
+		case DeferredProcedure_none:
+			attribute = "deferred_none";
+			break;
+		case DeferredProcedure_in:
+			attribute = "deferred_in";
+			break;
+		case DeferredProcedure_out:
+			attribute = "deferred_out";
+			break;
+		case DeferredProcedure_in_out:
+			attribute = "deferred_in_out";
+			break;
+		}
 
 		if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) {
-			switch (dst_kind) {
-			case DeferredProcedure_none:
-				error(src->token, "'deferred_none' cannot be used with a polymorphic procedure");
-				break;
-			case DeferredProcedure_in:
-				error(src->token, "'deferred_in' cannot be used with a polymorphic procedure");
-				break;
-			case DeferredProcedure_out:
-				error(src->token, "'deferred_out' cannot be used with a polymorphic procedure");
-				break;
-			case DeferredProcedure_in_out:
-				error(src->token, "'deferred_in_out' cannot be used with a polymorphic procedure");
-				break;
-			}
+			error(src->token, "'%s' cannot be used with a polymorphic procedure", attribute);
 			continue;
 		}
 
@@ -4974,17 +4977,19 @@ void check_deferred_procedures(Checker *c) {
 				GB_ASSERT(src_results->kind == Type_Tuple);
 				len += src_results->Tuple.variables.count;
 			}
-			array_init(&sv, heap_allocator(), 0, len);
+			slice_init(&sv, heap_allocator(), len);
+			isize offset = 0;
 			if (src_params != nullptr) {
 				for_array(i, src_params->Tuple.variables) {
-					array_add(&sv, src_params->Tuple.variables[i]);
+					sv[offset++] = src_params->Tuple.variables[i];
 				}
 			}
 			if (src_results != nullptr) {
 				for_array(i, src_results->Tuple.variables) {
-					array_add(&sv, src_results->Tuple.variables[i]);
+					sv[offset++] = src_results->Tuple.variables[i];
 				}
 			}
+			GB_ASSERT(offset == len);
 
 
 			if (are_types_identical(tsrc, dst_params)) {

+ 3 - 3
src/llvm_backend.cpp

@@ -761,7 +761,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 	if (build_context.metrics.os == TargetOs_windows && build_context.build_mode == BuildMode_DynamicLibrary) {
 		is_dll_main = true;
 		name = str_lit("DllMain");
-		array_init(&params->Tuple.variables, permanent_allocator(), 3);
+		slice_init(&params->Tuple.variables, permanent_allocator(), 3);
 		params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("hinstDLL"),   t_rawptr, false, true);
 		params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"),  t_u32,    false, true);
 		params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true);
@@ -769,12 +769,12 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 		name = str_lit("mainCRTStartup");
 	} else {
 		has_args = true;
-		array_init(&params->Tuple.variables, permanent_allocator(), 2);
+		slice_init(&params->Tuple.variables, permanent_allocator(), 2);
 		params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
 		params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
 	}
 
-	array_init(&results->Tuple.variables, permanent_allocator(), 1);
+	slice_init(&results->Tuple.variables, permanent_allocator(), 1);
 	results->Tuple.variables[0] = alloc_entity_param(nullptr, blank_token, t_i32, false, true);
 
 	Type *proc_type = alloc_type_proc(nullptr,

+ 2 - 2
src/llvm_backend_const.cpp

@@ -690,8 +690,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 
 				isize value_index = 0;
 
-				i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value);
-				i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value);
+				i64 total_lo = exact_value_to_i64(*type->EnumeratedArray.min_value);
+				i64 total_hi = exact_value_to_i64(*type->EnumeratedArray.max_value);
 
 				for (i64 i = total_lo; i <= total_hi; i++) {
 					bool found = false;

+ 4 - 4
src/llvm_backend_expr.cpp

@@ -2872,13 +2872,13 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			auto index_tv = type_and_value_of_expr(ie->index);
 
 			lbValue index = {};
-			if (compare_exact_values(Token_NotEq, t->EnumeratedArray.min_value, exact_value_i64(0))) {
+			if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) {
 				if (index_tv.mode == Addressing_Constant) {
-					ExactValue idx = exact_value_sub(index_tv.value, t->EnumeratedArray.min_value);
+					ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
 					index = lb_const_value(p->module, index_type, idx);
 				} else {
 					index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
-					index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, t->EnumeratedArray.min_value), index_type);
+					index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
 				}
 			} else {
 				index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
@@ -3472,7 +3472,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 				}
 
 
-				i32 index_offset = cast(i32)exact_value_to_i64(bt->EnumeratedArray.min_value);
+				i32 index_offset = cast(i32)exact_value_to_i64(*bt->EnumeratedArray.min_value);
 
 				for_array(i, temp_data) {
 					i32 index = temp_data[i].elem_index - index_offset;

+ 1 - 1
src/llvm_backend_general.cpp

@@ -1670,7 +1670,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
 				i64 alignment = type_align_of(type);
 				unsigned size_of_union = cast(unsigned)type_size_of(type);
-				fields[0] = lb_alignment_prefix_type_hack(m, alignment);
+				fields[0] = lb_alignment_prefix_type_hack(m, gb_min(alignment, 16));
 				fields[1] = LLVMArrayType(lb_type(m, t_u8), size_of_union);
 				return LLVMStructTypeInContext(ctx, fields, field_count, false);
 			}

+ 2 - 2
src/llvm_backend_proc.cpp

@@ -1393,7 +1393,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 				Type *res_type = nullptr;
 				gbAllocator a = permanent_allocator();
 				res_type = alloc_type_tuple();
-				array_init(&res_type->Tuple.variables, a, 2);
+				slice_init(&res_type->Tuple.variables, a, 2);
 				res_type->Tuple.variables[0] = alloc_entity_field(nullptr, blank_token, type,        false, 0);
 				res_type->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1);
 
@@ -1738,7 +1738,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 
 		if (tv.type->kind == Type_Tuple) {
 			Type *fix_typed = alloc_type_tuple();
-			array_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
+			slice_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
 			fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0];
 			fix_typed->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1);
 

+ 3 - 3
src/llvm_backend_stmt.cpp

@@ -332,8 +332,8 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
 			val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx));
 			// NOTE(bill): Override the idx value for the enumeration
 			Type *index_type = expr_type->EnumeratedArray.index;
-			if (compare_exact_values(Token_NotEq, expr_type->EnumeratedArray.min_value, exact_value_u64(0))) {
-				idx = lb_emit_arith(p, Token_Add, idx, lb_const_value(m, index_type, expr_type->EnumeratedArray.min_value), index_type);
+			if (compare_exact_values(Token_NotEq, *expr_type->EnumeratedArray.min_value, exact_value_u64(0))) {
+				idx = lb_emit_arith(p, Token_Add, idx, lb_const_value(m, index_type, *expr_type->EnumeratedArray.min_value), index_type);
 			}
 		}
 		break;
@@ -984,7 +984,7 @@ void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *s
 						lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
 					}
 					if (val1_type) {
-						ExactValue idx = exact_value_add(exact_value_i64(i), t->EnumeratedArray.min_value);
+						ExactValue idx = exact_value_add(exact_value_i64(i), *t->EnumeratedArray.min_value);
 						lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx));
 					}
 

+ 2 - 2
src/llvm_backend_type.cpp

@@ -450,8 +450,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 			lbValue min_value = lb_emit_struct_ep(p, tag, 4);
 			lbValue max_value = lb_emit_struct_ep(p, tag, 5);
 
-			lbValue min_v = lb_const_value(m, t_i64, t->EnumeratedArray.min_value);
-			lbValue max_v = lb_const_value(m, t_i64, t->EnumeratedArray.max_value);
+			lbValue min_v = lb_const_value(m, t_i64, *t->EnumeratedArray.min_value);
+			lbValue max_v = lb_const_value(m, t_i64, *t->EnumeratedArray.max_value);
 
 			lb_emit_store(p, min_value, min_v);
 			lb_emit_store(p, max_value, max_v);

+ 26 - 22
src/types.cpp

@@ -129,9 +129,9 @@ enum StructSoaKind {
 };
 
 struct TypeStruct {
-	Array<Entity *> fields;
-	Array<String>   tags;
-	Array<i64>      offsets;
+	Slice<Entity *> fields;
+	Slice<String>   tags;
+	Slice<i64>      offsets;
 	Ast *           node;
 	Scope *         scope;
 
@@ -145,12 +145,12 @@ struct TypeStruct {
 	i64           soa_count;
 	StructSoaKind soa_kind;
 
-	bool are_offsets_set;
-	bool are_offsets_being_processed;
-	bool is_packed;
-	bool is_raw_union;
 	bool is_polymorphic;
-	bool is_poly_specialized;
+	bool are_offsets_set             : 1;
+	bool are_offsets_being_processed : 1;
+	bool is_packed                   : 1;
+	bool is_raw_union                : 1;
+	bool is_poly_specialized         : 1;
 };
 
 struct TypeUnion {
@@ -216,8 +216,8 @@ struct TypeProc {
 	TYPE_KIND(EnumeratedArray, struct {                       \
 		Type *elem;                                       \
 		Type *index;                                      \
-		ExactValue min_value;                             \
-		ExactValue max_value;                             \
+		ExactValue *min_value;                            \
+		ExactValue *max_value;                            \
 		i64 count;                                        \
 		TokenKind op;                                     \
 	})                                                        \
@@ -239,14 +239,14 @@ struct TypeProc {
 		Scope *  scope;                                   \
 		Entity * names;                                   \
 		Type *   base_type;                               \
-		ExactValue min_value;                             \
-		ExactValue max_value;                             \
+		ExactValue *min_value;                            \
+		ExactValue *max_value;                            \
 		isize min_value_index;                            \
 		isize max_value_index;                            \
 	})                                                        \
 	TYPE_KIND(Tuple, struct {                                 \
-		Array<Entity *> variables; /* Entity_Variable */  \
-		Array<i64>      offsets;                          \
+		Slice<Entity *> variables; /* Entity_Variable */  \
+		Slice<i64>      offsets;                          \
 		bool            are_offsets_being_processed;      \
 		bool            are_offsets_set;                  \
 		bool            is_packed;                        \
@@ -803,15 +803,17 @@ Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) {
 	return t;
 }
 
-Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValue min_value, ExactValue max_value, TokenKind op) {
+Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValue const *min_value, ExactValue const *max_value, TokenKind op) {
 	Type *t = alloc_type(Type_EnumeratedArray);
 	t->EnumeratedArray.elem = elem;
 	t->EnumeratedArray.index = index;
-	t->EnumeratedArray.min_value = min_value;
-	t->EnumeratedArray.max_value = max_value;
+	t->EnumeratedArray.min_value = gb_alloc_item(permanent_allocator(), ExactValue);
+	t->EnumeratedArray.max_value = gb_alloc_item(permanent_allocator(), ExactValue);
+	gb_memmove(t->EnumeratedArray.min_value, min_value, gb_size_of(ExactValue));
+	gb_memmove(t->EnumeratedArray.max_value, max_value, gb_size_of(ExactValue));
 	t->EnumeratedArray.op = op;
 
-	t->EnumeratedArray.count = 1 + exact_value_to_i64(exact_value_sub(max_value, min_value));
+	t->EnumeratedArray.count = 1 + exact_value_to_i64(exact_value_sub(*max_value, *min_value));
 	return t;
 }
 
@@ -841,6 +843,8 @@ Type *alloc_type_union() {
 
 Type *alloc_type_enum() {
 	Type *t = alloc_type(Type_Enum);
+	t->Enum.min_value = gb_alloc_item(permanent_allocator(), ExactValue);
+	t->Enum.max_value = gb_alloc_item(permanent_allocator(), ExactValue);
 	return t;
 }
 
@@ -3080,9 +3084,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
 	return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.word_size);
 }
 
-Array<i64> type_set_offsets_of(Array<Entity *> const &fields, bool is_packed, bool is_raw_union) {
+Slice<i64> type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union) {
 	gbAllocator a = permanent_allocator();
-	auto offsets = array_make<i64>(a, fields.count);
+	auto offsets = slice_make<i64>(a, fields.count);
 	i64 curr_offset = 0;
 	if (is_raw_union) {
 		for_array(i, fields) {
@@ -3463,7 +3467,7 @@ Type *reduce_tuple_to_single_type(Type *original_type) {
 
 Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) {
 	Type *t = alloc_type_struct();
-	t->Struct.fields = array_make<Entity *>(heap_allocator(), field_count);
+	t->Struct.fields = slice_make<Entity *>(heap_allocator(), field_count);
 
 	Scope *scope = nullptr;
 	for_array(i, t->Struct.fields) {
@@ -3483,7 +3487,7 @@ Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, b
 	}
 
 	Type *t = alloc_type_tuple();
-	t->Tuple.variables = array_make<Entity *>(heap_allocator(), field_count);
+	t->Tuple.variables = slice_make<Entity *>(heap_allocator(), field_count);
 
 	Scope *scope = nullptr;
 	for_array(i, t->Tuple.variables) {