Browse Source

Named return value act as variables; Code reorganization

gingerBill 7 years ago
parent
commit
419ab6f00c
15 changed files with 1131 additions and 1136 deletions
  1. 12 10
      core/fmt.odin
  2. 1 1
      core/os.odin
  3. 1 2
      core/strconv.odin
  4. 21 1
      examples/demo.odin
  5. 14 0
      src/check_expr.cpp
  6. 51 110
      src/check_stmt.cpp
  7. 12 0
      src/check_type.cpp
  8. 4 376
      src/checker.cpp
  9. 400 0
      src/checker.hpp
  10. 9 8
      src/entity.cpp
  11. 43 78
      src/ir.cpp
  12. 7 4
      src/main.cpp
  13. 10 546
      src/parser.cpp
  14. 545 0
      src/parser.hpp
  15. 1 0
      src/types.cpp

+ 12 - 10
core/fmt.odin

@@ -309,26 +309,26 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
 }
 
 
-_parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
+_parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok: bool) {
 	is_digit :: inline proc(r: rune) -> bool{
 		return '0' <= r && r <= '9';
 	}
 
-	result := 0;
-	i := 0;
-	for i < len(s[offset..]) {
-		c := rune(s[offset+i]);
+	new_offset = offset;
+	n := len(s[new_offset..]);
+	for new_offset < n {
+		c := rune(s[new_offset]);
 		if !is_digit(c) do break;
-		i += 1;
+		new_offset += 1;
 
 		result *= 10;
 		result += int(c)-'0';
 	}
-
-	return result, offset+i, i != 0;
+	ok = new_offset > offset;
+	return;
 }
 
-_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_count: int) -> (index, offset: int, ok: bool) {
+_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_count: int) -> (index, new_offset: int, ok: bool) {
 	parse_arg_number :: proc(format: string) -> (int, int, bool) {
 		if len(format) < 3 do return 0, 1, false;
 
@@ -350,7 +350,9 @@ _arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_c
 		return arg_index, offset, false;
 	}
 	fi.reordered = true;
-	index, width, ok := parse_arg_number(format[offset..]);
+
+	width: int;
+	index, width, ok = parse_arg_number(format[offset..]);
 	if ok && 0 <= index && index < arg_count {
 		return index, offset+width, true;
 	}

+ 1 - 1
core/os.odin

@@ -25,7 +25,7 @@ read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
 		return nil, true;
 	}
 
-	data := make([]byte, int(length));
+	data = make([]byte, int(length));
 	if data == nil {
 		return nil, false;
 	}

+ 1 - 2
core/strconv.odin

@@ -14,7 +14,7 @@ parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
 	case "0", "f", "F", "false", "FALSE", "False":
 		return false, true;
 	}
-	return ok = false;
+	return;
 }
 
 _digit_value :: proc(r: rune) -> int {
@@ -428,7 +428,6 @@ digits := "0123456789abcdefghijklmnopqrstuvwxyz";
 
 
 is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
-	neg := false;
 	if is_signed {
 		switch bit_size {
 		case 8:

+ 21 - 1
examples/demo.odin

@@ -648,15 +648,35 @@ using_in :: proc() {
 	println(f);
 }
 
+named_proc_parameters :: proc() {
+	foo0 :: proc() -> int {
+		return 123;
+	}
+	foo1 :: proc() -> (a: int) {
+		a = 123;
+		return;
+	}
+	foo2 :: proc() -> (a, b: int) {
+		// Named return values act like variables within the scope
+		a = 321;
+		b = 567;
+		return b, a;
+	}
+	fmt.println("foo0 =", foo0());
+	fmt.println("foo1 =", foo1());
+	fmt.println("foo2 =", foo2());
+}
+
 main :: proc() {
-	general_stuff();
 	when false {
+		general_stuff();
 		default_struct_values();
 		union_type();
 		parametric_polymorphism();
 		threading_example();
 		array_programming();
 		using_in();
+		named_proc_parameters();
 	}
 }
 

+ 14 - 0
src/check_expr.cpp

@@ -1108,6 +1108,12 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 			error(op, "Operator '%.*s' is only allowed with numeric or pointer expressions", LIT(op.string));
 			return false;
 		}
+#if defined(NO_POINTER_ARITHMETIC)
+		if (is_type_pointer(type)) {
+			error(o->expr, "Pointer arithmetic is not supported");
+			return false;
+		}
+#else
 		if (is_type_pointer(type)) {
 			o->type = t_int;
 		}
@@ -1118,6 +1124,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 			return false;
 		}
 		break;
+#endif
 
 	case Token_Mul:
 	case Token_Quo:
@@ -1644,6 +1651,12 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
 		return operand;
 	}
 
+#if defined(NO_POINTER_ARITHMETIC)
+	operand.mode = Addressing_Invalid;
+	error(operand.expr, "Pointer arithmetic is not supported");
+	return operand;
+#else
+
 	Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
 	Type *elem = base_ptr->Pointer.elem;
 	i64 elem_size = type_size_of(c->allocator, elem);
@@ -1670,6 +1683,7 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
 	}
 
 	return operand;
+#endif
 }
 
 

+ 51 - 110
src/check_stmt.cpp

@@ -1165,135 +1165,76 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			break;
 		}
 
-		bool first_is_field_value = false;
-		if (rs->results.count > 0) {
-			bool fail = false;
-			first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue);
-			for_array(i, rs->results) {
-				AstNode *arg = rs->results[i];
-				bool mix = false;
-				if (first_is_field_value) {
-					mix = arg->kind != AstNode_FieldValue;
-				} else {
-					mix = arg->kind == AstNode_FieldValue;
-				}
-				if (mix) {
-					error(arg, "Mixture of 'field = value' and value elements in a procedure all is not allowed");
-					fail = true;
-				}
-			}
-
-			if (fail) {
-				return;
-			}
-		}
+		// bool first_is_field_value = false;
+		// if (rs->results.count > 0) {
+		// 	bool fail = false;
+		// 	first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue);
+		// 	for_array(i, rs->results) {
+		// 		AstNode *arg = rs->results[i];
+		// 		bool mix = false;
+		// 		if (first_is_field_value) {
+		// 			mix = arg->kind != AstNode_FieldValue;
+		// 		} else {
+		// 			mix = arg->kind == AstNode_FieldValue;
+		// 		}
+		// 		if (mix) {
+		// 			error(arg, "Mixture of 'field = value' and value elements in a procedure all is not allowed");
+		// 			fail = true;
+		// 		}
+		// 	}
+
+		// 	if (fail) {
+		// 		return;
+		// 	}
+		// }
 
 
 		Type *proc_type = c->proc_stack[c->proc_stack.count-1];
 		TypeProc *pt = &proc_type->Proc;
 		isize result_count = 0;
+		bool has_named_results = pt->has_named_results;
 		if (pt->results) {
 			result_count = proc_type->Proc.results->Tuple.variables.count;
 		}
 
 
-		isize result_count_excluding_defaults = result_count;
-		for (isize i = result_count-1; i >= 0; i--) {
-			Entity *e = pt->results->Tuple.variables[i];
-			if (e->kind == Entity_TypeName) {
-				break;
-			}
+		// isize result_count_excluding_defaults = result_count;
+		// for (isize i = result_count-1; i >= 0; i--) {
+		// 	Entity *e = pt->results->Tuple.variables[i];
+		// 	if (e->kind == Entity_TypeName) {
+		// 		break;
+		// 	}
 
-			GB_ASSERT(e->kind == Entity_Variable);
-			if (e->Variable.default_value.kind != ExactValue_Invalid ||
-			    e->Variable.default_is_nil) {
-				result_count_excluding_defaults--;
-				continue;
-			}
-			break;
-		}
+		// 	GB_ASSERT(e->kind == Entity_Variable);
+		// 	if (e->Variable.default_value.kind != ExactValue_Invalid ||
+		// 	    e->Variable.default_is_nil) {
+		// 		result_count_excluding_defaults--;
+		// 		continue;
+		// 	}
+		// 	break;
+		// }
 
 		Array<Operand> operands = {};
 		defer (array_free(&operands));
 
-		if (first_is_field_value) {
-			array_init_count(&operands, heap_allocator(), rs->results.count);
-			for_array(i, rs->results) {
-				AstNode *arg = rs->results[i];
-				ast_node(fv, FieldValue, arg);
-				check_expr(c, &operands[i], fv->value);
-			}
-		} else {
+		// if (first_is_field_value) {
+		// 	array_init_count(&operands, heap_allocator(), rs->results.count);
+		// 	for_array(i, rs->results) {
+		// 		AstNode *arg = rs->results[i];
+		// 		ast_node(fv, FieldValue, arg);
+		// 		check_expr(c, &operands[i], fv->value);
+		// 	}
+		// } else {
 			array_init(&operands, heap_allocator(), 2*rs->results.count);
 			check_unpack_arguments(c, nullptr, -1, &operands, rs->results, false);
-		}
-
-
-		if (first_is_field_value) {
-			bool *visited = gb_alloc_array(c->allocator, bool, result_count);
-
-			for_array(i, rs->results) {
-				AstNode *arg = rs->results[i];
-				ast_node(fv, FieldValue, arg);
-				if (fv->field->kind != AstNode_Ident) {
-					gbString expr_str = expr_to_string(fv->field);
-					error(arg, "Invalid parameter name '%s' in return statement", expr_str);
-					gb_string_free(expr_str);
-					continue;
-				}
-				String name = fv->field->Ident.token.string;
-				isize index = lookup_procedure_result(pt, name);
-				if (index < 0) {
-					error(arg, "No result named '%.*s' for this procedure type", LIT(name));
-					continue;
-				}
-				if (visited[index]) {
-					error(arg, "Duplicate result '%.*s' in return statement", LIT(name));
-					continue;
-				}
-
-				visited[index] = true;
-				Operand *o = &operands[i];
-				Entity *e = pt->results->Tuple.variables[index];
-				check_assignment(c, &operands[i], e->type, str_lit("return statement"));
-			}
-
-			for (isize i = 0; i < result_count; i++) {
-				if (!visited[i]) {
-					Entity *e = pt->results->Tuple.variables[i];
-					if (is_blank_ident(e->token)) {
-						continue;
-					}
-					GB_ASSERT(e->kind == Entity_Variable);
-					if (e->Variable.default_value.kind != ExactValue_Invalid) {
-						continue;
-					}
+		// }
 
-					if (e->Variable.default_is_nil) {
-						continue;
-					}
-
-					gbString str = type_to_string(e->type);
-					error(node, "Return value '%.*s' of type '%s' is missing in return statement",
-					      LIT(e->token.string), str);
-					gb_string_free(str);
-				}
-			}
-
-		} else if (result_count == 0 && rs->results.count > 0) {
+		if (result_count == 0 && rs->results.count > 0) {
 			error(rs->results[0], "No return values expected");
-		} else if (operands.count > result_count) {
-			if (result_count_excluding_defaults < result_count) {
-				error(node, "Expected a maximum of %td return values, got %td", result_count, operands.count);
-			} else {
-				error(node, "Expected %td return values, got %td", result_count, operands.count);
-			}
-		} else if (operands.count < result_count_excluding_defaults) {
-			if (result_count_excluding_defaults < result_count) {
-				error(node, "Expected a minimum of %td return values, got %td", result_count_excluding_defaults, operands.count);
-			} else {
-				error(node, "Expected %td return values, got %td", result_count_excluding_defaults, operands.count);
-			}
+		} else if (has_named_results && operands.count == 0) {
+			// Okay
+		} else if (operands.count != result_count) {
+			error(node, "Expected %td return values, got %td", result_count, operands.count);
 		} else {
 			isize max_count = rs->results.count;
 			for (isize i = 0; i < max_count; i++) {

+ 12 - 0
src/check_type.cpp

@@ -1423,10 +1423,16 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 					token = name->Ident.token;
 				}
 
+				if (is_blank_ident(token))  {
+					error(name, "Result value cannot be a blank identifer `_`");
+				}
+
 				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+				param->flags |= EntityFlag_Result;
 				param->Variable.default_value = value;
 				param->Variable.default_is_nil = default_is_nil;
 				array_add(&variables, param);
+				add_entity(c, scope, name, param);
 			}
 		}
 	}
@@ -1673,6 +1679,12 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 		}
 	}
 
+	if (result_count > 0) {
+		Entity *first = results->Tuple.variables[0];
+		type->Proc.has_named_results = first->token.string != "";
+	}
+
+
 	ProcCallingConvention cc = pt->calling_convention;
 	if (cc == ProcCC_ForeignBlockDefault) {
 		cc = ProcCC_CDecl;

+ 4 - 376
src/checker.cpp

@@ -1,150 +1,6 @@
 #include "entity.cpp"
-
-enum ExprKind {
-	Expr_Expr,
-	Expr_Stmt,
-};
-
-// Statements and Declarations
-enum StmtFlag {
-	Stmt_BreakAllowed       = 1<<0,
-	Stmt_ContinueAllowed    = 1<<1,
-	Stmt_FallthroughAllowed = 1<<2,
-
-	Stmt_CheckScopeDecls    = 1<<5,
-};
-
-struct BuiltinProc {
-	String   name;
-	isize    arg_count;
-	bool     variadic;
-	ExprKind kind;
-};
-enum BuiltinProcId {
-	BuiltinProc_Invalid,
-
-	BuiltinProc_len,
-	BuiltinProc_cap,
-
-	// BuiltinProc_new,
-	BuiltinProc_make,
-	// BuiltinProc_free,
-
-	// BuiltinProc_reserve,
-	// BuiltinProc_clear,
-	// BuiltinProc_append,
-	// BuiltinProc_delete,
-
-	BuiltinProc_size_of,
-	BuiltinProc_align_of,
-	BuiltinProc_offset_of,
-	BuiltinProc_type_of,
-	BuiltinProc_type_info_of,
-
-	BuiltinProc_compile_assert,
-
-	BuiltinProc_swizzle,
-
-	BuiltinProc_complex,
-	BuiltinProc_real,
-	BuiltinProc_imag,
-	BuiltinProc_conj,
-
-	// BuiltinProc_slice_ptr,
-	// BuiltinProc_slice_to_bytes,
-
-	BuiltinProc_expand_to_tuple,
-
-	BuiltinProc_min,
-	BuiltinProc_max,
-	BuiltinProc_abs,
-	BuiltinProc_clamp,
-
-	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
-
-	BuiltinProc_COUNT,
-};
-gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
-	{STR_LIT(""),                 0, false, Expr_Stmt},
-
-	{STR_LIT("len"),              1, false, Expr_Expr},
-	{STR_LIT("cap"),              1, false, Expr_Expr},
-
-	// {STR_LIT("new"),              1, false, Expr_Expr},
-	{STR_LIT("make"),             1, true,  Expr_Expr},
-	// {STR_LIT("free"),             1, false, Expr_Stmt},
-
-	// {STR_LIT("reserve"),          2, false, Expr_Stmt},
-	// {STR_LIT("clear"),            1, false, Expr_Stmt},
-	// {STR_LIT("append"),           1, true,  Expr_Expr},
-	// {STR_LIT("delete"),           2, false, Expr_Stmt},
-
-	{STR_LIT("size_of"),          1, false, Expr_Expr},
-	{STR_LIT("align_of"),         1, false, Expr_Expr},
-	{STR_LIT("offset_of"),        2, false, Expr_Expr},
-	{STR_LIT("type_of"),          1, false, Expr_Expr},
-	{STR_LIT("type_info_of"),     1, false, Expr_Expr},
-
-	{STR_LIT("compile_assert"),   1, false, Expr_Expr},
-
-	{STR_LIT("swizzle"),          1, true,  Expr_Expr},
-
-	{STR_LIT("complex"),          2, false, Expr_Expr},
-	{STR_LIT("real"),             1, false, Expr_Expr},
-	{STR_LIT("imag"),             1, false, Expr_Expr},
-	{STR_LIT("conj"),             1, false, Expr_Expr},
-
-	// {STR_LIT("slice_ptr"),        2, true,  Expr_Expr},
-	// {STR_LIT("slice_to_bytes"),   1, false, Expr_Expr},
-
-	{STR_LIT("expand_to_tuple"),  1, false, Expr_Expr},
-
-	{STR_LIT("min"),              2, false, Expr_Expr},
-	{STR_LIT("max"),              2, false, Expr_Expr},
-	{STR_LIT("abs"),              1, false, Expr_Expr},
-	{STR_LIT("clamp"),            3, false, Expr_Expr},
-
-	{STR_LIT(""),                 0, true,  Expr_Expr}, // DIRECTIVE
-};
-
-
 #include "types.cpp"
 
-enum AddressingMode {
-	Addressing_Invalid,       // invalid addressing mode
-	Addressing_NoValue,       // no value (void in C)
-	Addressing_Value,         // computed value (rvalue)
-	Addressing_Immutable,     // immutable computed value (const rvalue)
-	Addressing_Variable,      // addressable variable (lvalue)
-	Addressing_Constant,      // constant
-	Addressing_Type,          // type
-	Addressing_Builtin,       // built-in procedure
-	Addressing_ProcGroup,     // procedure group (overloaded procedure)
-	Addressing_MapIndex,      // map index expression -
-	                          // 	lhs: acts like a Variable
-	                          // 	rhs: acts like OptionalOk
-	Addressing_OptionalOk,    // rhs: acts like a value with an optional boolean part (for existence check)
-};
-
-// Operand is used as an intermediate value whilst checking
-// Operands store an addressing mode, the expression being evaluated,
-// its type and node, and other specific information for certain
-// addressing modes
-// Its zero-value is a valid "invalid operand"
-struct Operand {
-	AddressingMode mode;
-	Type *         type;
-	ExactValue     value;
-	AstNode *      expr;
-	BuiltinProcId  builtin_id;
-	Entity *       proc_group;
-};
-
-struct TypeAndValue {
-	AddressingMode mode;
-	Type *         type;
-	ExactValue     value;
-};
 
 bool is_operand_value(Operand o) {
 	switch (o.mode) {
@@ -166,79 +22,6 @@ bool is_operand_undef(Operand o) {
 
 
 
-struct BlockLabel {
-	String   name;
-	AstNode *label; //  AstNode_Label;
-};
-
-// DeclInfo is used to store information of certain declarations to allow for "any order" usage
-struct DeclInfo {
-	DeclInfo *        parent; // NOTE(bill): only used for procedure literals at the moment
-	Scope *           scope;
-
-	Entity **         entities;
-	isize             entity_count;
-
-	AstNode *         type_expr;
-	AstNode *         init_expr;
-	Array<AstNode *>  init_expr_list;
-	Array<AstNode *>  attributes;
-	AstNode *         proc_lit;      // AstNode_ProcLit
-	Type *            gen_proc_type; // Precalculated
-
-	PtrSet<Entity *>  deps;
-	Array<BlockLabel> labels;
-};
-
-// ProcedureInfo stores the information needed for checking a procedure
-
-
-struct ProcedureInfo {
-	AstFile *             file;
-	Token                 token;
-	DeclInfo *            decl;
-	Type *                type; // Type_Procedure
-	AstNode *             body; // AstNode_BlockStmt
-	u64                   tags;
-	bool                  generated_from_polymorphic;
-};
-
-// ExprInfo stores information used for "untyped" expressions
-struct ExprInfo {
-	bool           is_lhs; // Debug info
-	AddressingMode mode;
-	Type *         type; // Type_Basic
-	ExactValue     value;
-};
-
-ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue value) {
-	ExprInfo ei = {is_lhs, mode, type, value};
-	return ei;
-}
-
-
-
-struct Scope {
-	AstNode *        node;
-	Scope *          parent;
-	Scope *          prev, *next;
-	Scope *          first_child;
-	Scope *          last_child;
-	Map<Entity *>    elements; // Key: String
-	PtrSet<Entity *> implicit;
-
-	Array<Scope *>   shared;
-	Array<AstNode *> delayed_file_decls;
-	PtrSet<Scope *>  imported;
-	PtrSet<Scope *>  exported; // NOTE(bhall): Contains 'using import' too
-	bool             is_proc;
-	bool             is_global;
-	bool             is_file;
-	bool             is_init;
-	bool             is_struct;
-	bool             has_been_imported; // This is only applicable to file scopes
-	AstFile *        file;
-};
 gb_global Scope *universal_scope = nullptr;
 
 void scope_reset(Scope *scope) {
@@ -257,7 +40,7 @@ i32 is_scope_an_ancestor(Scope *parent, Scope *child) {
 	isize i = 0;
 	while (child != nullptr) {
 		if (parent == child) {
-			return true;
+			return i;
 		}
 		child = child->parent;
 		i++;
@@ -265,18 +48,6 @@ i32 is_scope_an_ancestor(Scope *parent, Scope *child) {
 	return -1;
 }
 
-
-struct EntityGraphNode;
-typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
-
-struct EntityGraphNode {
-	Entity *     entity; // Procedure, Variable, Constant
-	EntityGraphNodeSet pred;
-	EntityGraphNodeSet succ;
-	isize        index; // Index in array/queue
-	isize        dep_count;
-};
-
 void entity_graph_node_set_destroy(EntityGraphNodeSet *s) {
 	if (s->hashes.data != nullptr) {
 		ptr_set_destroy(s);
@@ -326,9 +97,6 @@ void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
 
 
 
-struct ImportGraphNode;
-typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
-
 void import_graph_node_set_destroy(ImportGraphNodeSet *s) {
 	if (s->hashes.data != nullptr) {
 		ptr_set_destroy(s);
@@ -350,16 +118,6 @@ void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) {
 	ptr_set_remove(s, n);
 }
 
-struct ImportGraphNode {
-	Scope *            scope;
-	String             path;
-	isize              file_id;
-	ImportGraphNodeSet pred;
-	ImportGraphNodeSet succ;
-	isize              index; // Index in array/queue
-	isize              dep_count;
-};
-
 ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
 	ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode);
 	n->scope   = scope;
@@ -368,7 +126,6 @@ ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
 	return n;
 }
 
-
 void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) {
 	import_graph_node_set_destroy(&n->pred);
 	import_graph_node_set_destroy(&n->succ);
@@ -409,118 +166,10 @@ GB_COMPARE_PROC(ast_node_cmp) {
 	return token_pos_cmp(i.pos, j.pos);
 }
 
-struct ForeignContext {
-	AstNode *             curr_library;
-	ProcCallingConvention default_cc;
-	String                link_prefix;
-	bool                  in_export;
-};
-
-struct CheckerContext {
-	Scope *    file_scope;
-	Scope *    scope;
-	DeclInfo * decl;
-	u32        stmt_state_flags;
-	bool       in_defer; // TODO(bill): Actually handle correctly
-	String     proc_name;
-	Type *     type_hint;
-	DeclInfo * curr_proc_decl;
-	ForeignContext foreign_context;
-
-	bool       collect_delayed_decls;
-	bool       allow_polymorphic_types;
-	bool       no_polymorphic_errors;
-	Scope *    polymorphic_scope;
-};
-
-
-// CheckerInfo stores all the symbol information for a type-checked program
-struct CheckerInfo {
-	Map<TypeAndValue>     types;           // Key: AstNode * | Expression -> Type (and value)
-	Map<ExprInfo>         untyped;         // Key: AstNode * | Expression -> ExprInfo
-	Map<AstFile *>        files;           // Key: String (full path)
-	Map<Entity *>         foreigns;        // Key: String
-	Array<Entity *>       definitions;
-	Array<Entity *>       entities;
-	Array<DeclInfo *>     variable_init_order;
-
-	Map<Array<Entity *> > gen_procs;       // Key: AstNode * | Identifier -> Entity
-	Map<Array<Entity *> > gen_types;       // Key: Type *
-
-	Map<isize>            type_info_map;   // Key: Type *
-	isize                 type_info_count;
-
-	Scope *               init_scope;
-	Entity *              entry_point;
-	PtrSet<Entity *>      minimum_dependency_set;
-};
-
-struct Checker {
-	Parser *    parser;
-	CheckerInfo info;
-	gbMutex     mutex;
-
-	AstFile *                  curr_ast_file;
-	Scope *                    global_scope;
-	// NOTE(bill): Procedures to check
-	Array<ProcedureInfo>       procs;
-	Map<Scope *>               file_scopes; // Key: String (fullpath)
-	Array<ImportGraphNode *>   file_order;
-
-	gbAllocator                allocator;
-	gbArena                    arena;
-	gbArena                    tmp_arena;
-	gbAllocator                tmp_allocator;
-
-	CheckerContext             context;
-
-	Array<Type *>              proc_stack;
-	bool                       done_preload;
-
-	PtrSet<AstFile *>          checked_files;
-
-};
-
-
-
-HashKey hash_node     (AstNode *node)  { return hash_pointer(node); }
-HashKey hash_ast_file (AstFile *file)  { return hash_pointer(file); }
-HashKey hash_entity   (Entity *e)      { return hash_pointer(e); }
-HashKey hash_type     (Type *t)        { return hash_pointer(t); }
-HashKey hash_decl_info(DeclInfo *decl) { return hash_pointer(decl); }
-
-// CheckerInfo API
-TypeAndValue type_and_value_of_expr (CheckerInfo *i, AstNode *expr);
-Type *       type_of_expr           (CheckerInfo *i, AstNode *expr);
-Entity *     entity_of_ident        (CheckerInfo *i, AstNode *identifier);
-Entity *     implicit_entity_of_node(CheckerInfo *i, AstNode *clause);
-Scope *      scope_of_node          (CheckerInfo *i, AstNode *node);
-DeclInfo *   decl_info_of_ident     (CheckerInfo *i, AstNode *ident);
-DeclInfo *   decl_info_of_entity    (CheckerInfo *i, Entity * e);
-AstFile *    ast_file_of_filename   (CheckerInfo *i, String   filename);
-// IMPORTANT: Only to use once checking is done
-isize        type_info_index        (CheckerInfo *i, Type *   type, bool error_on_failure = true);
 
 
-Entity *current_scope_lookup_entity(Scope *s, String name);
-Entity *scope_lookup_entity        (Scope *s, String name);
-void    scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entity **entity_);
-Entity *scope_insert_entity        (Scope *s, Entity *entity);
 
 
-ExprInfo *check_get_expr_info     (CheckerInfo *i, AstNode *expr);
-void      check_set_expr_info     (CheckerInfo *i, AstNode *expr, ExprInfo info);
-void      check_remove_expr_info  (CheckerInfo *i, AstNode *expr);
-void      add_untyped             (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
-void      add_type_and_value      (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value);
-void      add_entity_use          (Checker *c, AstNode *identifier, Entity *entity);
-void      add_implicit_entity     (Checker *c, AstNode *node, Entity *e);
-void      add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d);
-
-void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
-void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
-void check_add_foreign_import_decl(Checker *c, AstNode *decl);
-
 
 void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
 	d->parent = parent;
@@ -771,6 +420,9 @@ Entity *scope_lookup_entity(Scope *s, String name) {
 
 Entity *scope_insert_entity(Scope *s, Entity *entity) {
 	String name = entity->token.string;
+	if (name == "") {
+		return nullptr;
+	}
 	HashKey key = hash_string(name);
 	Entity **found = map_get(&s->elements, key);
 
@@ -1742,30 +1394,6 @@ void init_preload(Checker *c) {
 
 
 
-bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false);
-void check_collect_entities(Checker *c, Array<AstNode *> nodes);
-void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
-void check_delayed_file_import_entity(Checker *c, AstNode *decl);
-
-struct AttributeContext {
-	String  link_name;
-	String  link_prefix;
-	isize   init_expr_list_count;
-	String  thread_local_model;
-};
-
-AttributeContext make_attribute_context(String link_prefix) {
-	AttributeContext ac = {};
-	ac.link_prefix = link_prefix;
-	return ac;
-}
-
-#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
-typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
-
-
-void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
-
 DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
 	if (name == "default_calling_convention") {
 		if (value.kind == ExactValue_String) {

+ 400 - 0
src/checker.hpp

@@ -0,0 +1,400 @@
+// checker.hpp
+
+struct Type;
+struct Entity;
+struct Scope;
+struct DeclInfo;
+struct AstFile;
+
+enum AddressingMode {
+	Addressing_Invalid,       // invalid addressing mode
+	Addressing_NoValue,       // no value (void in C)
+	Addressing_Value,         // computed value (rvalue)
+	Addressing_Immutable,     // immutable computed value (const rvalue)
+	Addressing_Variable,      // addressable variable (lvalue)
+	Addressing_Constant,      // constant
+	Addressing_Type,          // type
+	Addressing_Builtin,       // built-in procedure
+	Addressing_ProcGroup,     // procedure group (overloaded procedure)
+	Addressing_MapIndex,      // map index expression -
+	                          // 	lhs: acts like a Variable
+	                          // 	rhs: acts like OptionalOk
+	Addressing_OptionalOk,    // rhs: acts like a value with an optional boolean part (for existence check)
+};
+
+struct TypeAndValue {
+	AddressingMode mode;
+	Type *         type;
+	ExactValue     value;
+};
+
+
+// ExprInfo stores information used for "untyped" expressions
+struct ExprInfo {
+	bool           is_lhs; // Debug info
+	AddressingMode mode;
+	Type *         type; // Type_Basic
+	ExactValue     value;
+};
+
+gb_inline ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue value) {
+	ExprInfo ei = {is_lhs, mode, type, value};
+	return ei;
+}
+
+
+
+
+enum ExprKind {
+	Expr_Expr,
+	Expr_Stmt,
+};
+
+// Statements and Declarations
+enum StmtFlag {
+	Stmt_BreakAllowed       = 1<<0,
+	Stmt_ContinueAllowed    = 1<<1,
+	Stmt_FallthroughAllowed = 1<<2,
+
+	Stmt_CheckScopeDecls    = 1<<5,
+};
+
+struct BuiltinProc {
+	String   name;
+	isize    arg_count;
+	bool     variadic;
+	ExprKind kind;
+};
+enum BuiltinProcId {
+	BuiltinProc_Invalid,
+
+	BuiltinProc_len,
+	BuiltinProc_cap,
+
+	// BuiltinProc_new,
+	BuiltinProc_make,
+	// BuiltinProc_free,
+
+	// BuiltinProc_reserve,
+	// BuiltinProc_clear,
+	// BuiltinProc_append,
+	// BuiltinProc_delete,
+
+	BuiltinProc_size_of,
+	BuiltinProc_align_of,
+	BuiltinProc_offset_of,
+	BuiltinProc_type_of,
+	BuiltinProc_type_info_of,
+
+	BuiltinProc_compile_assert,
+
+	BuiltinProc_swizzle,
+
+	BuiltinProc_complex,
+	BuiltinProc_real,
+	BuiltinProc_imag,
+	BuiltinProc_conj,
+
+	// BuiltinProc_slice_ptr,
+	// BuiltinProc_slice_to_bytes,
+
+	BuiltinProc_expand_to_tuple,
+
+	BuiltinProc_min,
+	BuiltinProc_max,
+	BuiltinProc_abs,
+	BuiltinProc_clamp,
+
+	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
+
+	BuiltinProc_COUNT,
+};
+gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
+	{STR_LIT(""),                 0, false, Expr_Stmt},
+
+	{STR_LIT("len"),              1, false, Expr_Expr},
+	{STR_LIT("cap"),              1, false, Expr_Expr},
+
+	// {STR_LIT("new"),              1, false, Expr_Expr},
+	{STR_LIT("make"),             1, true,  Expr_Expr},
+	// {STR_LIT("free"),             1, false, Expr_Stmt},
+
+	// {STR_LIT("reserve"),          2, false, Expr_Stmt},
+	// {STR_LIT("clear"),            1, false, Expr_Stmt},
+	// {STR_LIT("append"),           1, true,  Expr_Expr},
+	// {STR_LIT("delete"),           2, false, Expr_Stmt},
+
+	{STR_LIT("size_of"),          1, false, Expr_Expr},
+	{STR_LIT("align_of"),         1, false, Expr_Expr},
+	{STR_LIT("offset_of"),        2, false, Expr_Expr},
+	{STR_LIT("type_of"),          1, false, Expr_Expr},
+	{STR_LIT("type_info_of"),     1, false, Expr_Expr},
+
+	{STR_LIT("compile_assert"),   1, false, Expr_Expr},
+
+	{STR_LIT("swizzle"),          1, true,  Expr_Expr},
+
+	{STR_LIT("complex"),          2, false, Expr_Expr},
+	{STR_LIT("real"),             1, false, Expr_Expr},
+	{STR_LIT("imag"),             1, false, Expr_Expr},
+	{STR_LIT("conj"),             1, false, Expr_Expr},
+
+	// {STR_LIT("slice_ptr"),        2, true,  Expr_Expr},
+	// {STR_LIT("slice_to_bytes"),   1, false, Expr_Expr},
+
+	{STR_LIT("expand_to_tuple"),  1, false, Expr_Expr},
+
+	{STR_LIT("min"),              2, false, Expr_Expr},
+	{STR_LIT("max"),              2, false, Expr_Expr},
+	{STR_LIT("abs"),              1, false, Expr_Expr},
+	{STR_LIT("clamp"),            3, false, Expr_Expr},
+
+	{STR_LIT(""),                 0, true,  Expr_Expr}, // DIRECTIVE
+};
+
+
+// Operand is used as an intermediate value whilst checking
+// Operands store an addressing mode, the expression being evaluated,
+// its type and node, and other specific information for certain
+// addressing modes
+// Its zero-value is a valid "invalid operand"
+struct Operand {
+	AddressingMode mode;
+	Type *         type;
+	ExactValue     value;
+	AstNode *      expr;
+	BuiltinProcId  builtin_id;
+	Entity *       proc_group;
+};
+
+
+struct BlockLabel {
+	String   name;
+	AstNode *label; //  AstNode_Label;
+};
+
+// DeclInfo is used to store information of certain declarations to allow for "any order" usage
+struct DeclInfo {
+	DeclInfo *        parent; // NOTE(bill): only used for procedure literals at the moment
+	Scope *           scope;
+
+	Entity **         entities;
+	isize             entity_count;
+
+	AstNode *         type_expr;
+	AstNode *         init_expr;
+	Array<AstNode *>  init_expr_list;
+	Array<AstNode *>  attributes;
+	AstNode *         proc_lit;      // AstNode_ProcLit
+	Type *            gen_proc_type; // Precalculated
+
+	PtrSet<Entity *>  deps;
+	Array<BlockLabel> labels;
+};
+
+// ProcedureInfo stores the information needed for checking a procedure
+
+
+struct ProcedureInfo {
+	AstFile *             file;
+	Token                 token;
+	DeclInfo *            decl;
+	Type *                type; // Type_Procedure
+	AstNode *             body; // AstNode_BlockStmt
+	u64                   tags;
+	bool                  generated_from_polymorphic;
+};
+
+
+struct Scope {
+	AstNode *        node;
+	Scope *          parent;
+	Scope *          prev, *next;
+	Scope *          first_child;
+	Scope *          last_child;
+	Map<Entity *>    elements; // Key: String
+	PtrSet<Entity *> implicit;
+
+	Array<Scope *>   shared;
+	Array<AstNode *> delayed_file_decls;
+	PtrSet<Scope *>  imported;
+	PtrSet<Scope *>  exported; // NOTE(bhall): Contains 'using import' too
+	bool             is_proc;
+	bool             is_global;
+	bool             is_file;
+	bool             is_init;
+	bool             is_struct;
+	bool             has_been_imported; // This is only applicable to file scopes
+	AstFile *        file;
+};
+
+
+
+
+struct EntityGraphNode;
+typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
+
+struct EntityGraphNode {
+	Entity *     entity; // Procedure, Variable, Constant
+	EntityGraphNodeSet pred;
+	EntityGraphNodeSet succ;
+	isize        index; // Index in array/queue
+	isize        dep_count;
+};
+
+
+
+struct ImportGraphNode;
+typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
+
+
+struct ImportGraphNode {
+	Scope *            scope;
+	String             path;
+	isize              file_id;
+	ImportGraphNodeSet pred;
+	ImportGraphNodeSet succ;
+	isize              index; // Index in array/queue
+	isize              dep_count;
+};
+
+
+struct ForeignContext {
+	AstNode *             curr_library;
+	ProcCallingConvention default_cc;
+	String                link_prefix;
+	bool                  in_export;
+};
+
+struct CheckerContext {
+	Scope *    file_scope;
+	Scope *    scope;
+	DeclInfo * decl;
+	u32        stmt_state_flags;
+	bool       in_defer; // TODO(bill): Actually handle correctly
+	String     proc_name;
+	Type *     type_hint;
+	DeclInfo * curr_proc_decl;
+	ForeignContext foreign_context;
+
+	bool       collect_delayed_decls;
+	bool       allow_polymorphic_types;
+	bool       no_polymorphic_errors;
+	Scope *    polymorphic_scope;
+};
+
+
+// CheckerInfo stores all the symbol information for a type-checked program
+struct CheckerInfo {
+	Map<TypeAndValue>     types;           // Key: AstNode * | Expression -> Type (and value)
+	Map<ExprInfo>         untyped;         // Key: AstNode * | Expression -> ExprInfo
+	Map<AstFile *>        files;           // Key: String (full path)
+	Map<Entity *>         foreigns;        // Key: String
+	Array<Entity *>       definitions;
+	Array<Entity *>       entities;
+	Array<DeclInfo *>     variable_init_order;
+
+	Map<Array<Entity *> > gen_procs;       // Key: AstNode * | Identifier -> Entity
+	Map<Array<Entity *> > gen_types;       // Key: Type *
+
+	Map<isize>            type_info_map;   // Key: Type *
+	isize                 type_info_count;
+
+	Scope *               init_scope;
+	Entity *              entry_point;
+	PtrSet<Entity *>      minimum_dependency_set;
+};
+
+struct Checker {
+	Parser *    parser;
+	CheckerInfo info;
+	gbMutex     mutex;
+
+	AstFile *                  curr_ast_file;
+	Scope *                    global_scope;
+	// NOTE(bill): Procedures to check
+	Array<ProcedureInfo>       procs;
+	Map<Scope *>               file_scopes; // Key: String (fullpath)
+	Array<ImportGraphNode *>   file_order;
+
+	gbAllocator                allocator;
+	gbArena                    arena;
+	gbArena                    tmp_arena;
+	gbAllocator                tmp_allocator;
+
+	CheckerContext             context;
+
+	Array<Type *>              proc_stack;
+	bool                       done_preload;
+
+	PtrSet<AstFile *>          checked_files;
+
+};
+
+
+
+HashKey hash_node     (AstNode *node)  { return hash_pointer(node); }
+HashKey hash_ast_file (AstFile *file)  { return hash_pointer(file); }
+HashKey hash_entity   (Entity *e)      { return hash_pointer(e); }
+HashKey hash_type     (Type *t)        { return hash_pointer(t); }
+HashKey hash_decl_info(DeclInfo *decl) { return hash_pointer(decl); }
+
+
+
+// CheckerInfo API
+TypeAndValue type_and_value_of_expr (CheckerInfo *i, AstNode *expr);
+Type *       type_of_expr           (CheckerInfo *i, AstNode *expr);
+Entity *     entity_of_ident        (CheckerInfo *i, AstNode *identifier);
+Entity *     implicit_entity_of_node(CheckerInfo *i, AstNode *clause);
+Scope *      scope_of_node          (CheckerInfo *i, AstNode *node);
+DeclInfo *   decl_info_of_ident     (CheckerInfo *i, AstNode *ident);
+DeclInfo *   decl_info_of_entity    (CheckerInfo *i, Entity * e);
+AstFile *    ast_file_of_filename   (CheckerInfo *i, String   filename);
+// IMPORTANT: Only to use once checking is done
+isize        type_info_index        (CheckerInfo *i, Type *   type, bool error_on_failure = true);
+
+
+Entity *current_scope_lookup_entity(Scope *s, String name);
+Entity *scope_lookup_entity        (Scope *s, String name);
+void    scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entity **entity_);
+Entity *scope_insert_entity        (Scope *s, Entity *entity);
+
+
+ExprInfo *check_get_expr_info     (CheckerInfo *i, AstNode *expr);
+void      check_set_expr_info     (CheckerInfo *i, AstNode *expr, ExprInfo info);
+void      check_remove_expr_info  (CheckerInfo *i, AstNode *expr);
+void      add_untyped             (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
+void      add_type_and_value      (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value);
+void      add_entity_use          (Checker *c, AstNode *identifier, Entity *entity);
+void      add_implicit_entity     (Checker *c, AstNode *node, Entity *e);
+void      add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d);
+
+void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
+void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
+void check_add_foreign_import_decl(Checker *c, AstNode *decl);
+
+
+
+bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false);
+void check_collect_entities(Checker *c, Array<AstNode *> nodes);
+void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
+void check_delayed_file_import_entity(Checker *c, AstNode *decl);
+
+
+struct AttributeContext {
+	String  link_name;
+	String  link_prefix;
+	isize   init_expr_list_count;
+	String  thread_local_model;
+};
+
+AttributeContext make_attribute_context(String link_prefix) {
+	AttributeContext ac = {};
+	ac.link_prefix = link_prefix;
+	return ac;
+}
+
+#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
+typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
+
+void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);

+ 9 - 8
src/entity.cpp

@@ -37,14 +37,15 @@ enum EntityFlag {
 	EntityFlag_Using         = 1<<2,
 	EntityFlag_Field         = 1<<3,
 	EntityFlag_Param         = 1<<4,
-	EntityFlag_ArrayElem     = 1<<5,
-	EntityFlag_Ellipsis      = 1<<6,
-	EntityFlag_NoAlias       = 1<<7,
-	EntityFlag_TypeField     = 1<<8,
-	EntityFlag_Value         = 1<<9,
-	EntityFlag_Sret          = 1<<10,
-	EntityFlag_BitFieldValue = 1<<11,
-	EntityFlag_PolyConst     = 1<<12,
+	EntityFlag_Result        = 1<<5,
+	EntityFlag_ArrayElem     = 1<<6,
+	EntityFlag_Ellipsis      = 1<<7,
+	EntityFlag_NoAlias       = 1<<8,
+	EntityFlag_TypeField     = 1<<9,
+	EntityFlag_Value         = 1<<10,
+	EntityFlag_Sret          = 1<<11,
+	EntityFlag_BitFieldValue = 1<<12,
+	EntityFlag_PolyConst     = 1<<13,
 
 	EntityFlag_CVarArg       = 1<<20,
 };

+ 43 - 78
src/ir.cpp

@@ -6657,63 +6657,14 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 		isize return_count = proc->type->Proc.result_count;
 		isize res_count = rs->results.count;
 
-		if (res_count > 0 &&
-		    rs->results[0]->kind == AstNode_FieldValue) {
-			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
-			defer (gb_temp_arena_memory_end(tmp));
-
-			Array<irValue *> results;
-			array_init_count(&results, proc->module->tmp_allocator, return_count);
-
-			for_array(arg_index, rs->results) {
-				AstNode *arg = rs->results[arg_index];
-				ast_node(fv, FieldValue, arg);
-				GB_ASSERT(fv->field->kind == AstNode_Ident);
-				String name = fv->field->Ident.token.string;
-				isize index = lookup_procedure_result(&proc->type->Proc, name);
-				GB_ASSERT(index >= 0);
-				irValue *expr = ir_build_expr(proc, fv->value);
-				results[index] = expr;
-			}
-			for (isize i = 0; i < return_count; i++) {
-				Entity *e = tuple->variables[i];
-				GB_ASSERT(e->kind == Entity_Variable);
-				if (results[i] == nullptr) {
-					if (e->Variable.default_value.kind != ExactValue_Invalid) {
-						results[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
-					} else {
-						results[i] = ir_value_nil(proc->module->allocator, e->type);
-					}
-				} else {
-					results[i] = ir_emit_conv(proc, results[i], e->type);
-				}
-			}
-
-			if (results.count == 1) {
-				v = results[0];
-			} else {
-				GB_ASSERT(results.count == return_count);
-
-				Type *ret_type = proc->type->Proc.results;
-				v = ir_add_local_generated(proc, ret_type);
-				for_array(i, results) {
-					irValue *field = ir_emit_struct_ep(proc, v, cast(i32)i);
-					irValue *res = results[i];
-					ir_emit_store(proc, field, res);
-				}
-
-				v = ir_emit_load(proc, v);
-			}
-		} else if (return_count == 0) {
+		if (return_count == 0) {
 			// No return values
 		} else if (return_count == 1) {
 			Entity *e = tuple->variables[0];
 			if (res_count == 0) {
-				if (e->Variable.default_value.kind != ExactValue_Invalid) {
-					v = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
-				} else {
-					v = ir_value_nil(proc->module->allocator, e->type);
-				}
+				irValue **found = map_get(&proc->module->values, hash_entity(e));
+				GB_ASSERT(found);
+				v = ir_emit_load(proc, *found);
 			} else {
 				v = ir_build_expr(proc, rs->results[0]);
 				v = ir_emit_conv(proc, v, e->type);
@@ -6725,33 +6676,28 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			Array<irValue *> results;
 			array_init(&results, proc->module->tmp_allocator, return_count);
 
-			isize total_index = 0;
-			isize res_index = 0;
-			for (; res_index < res_count; res_index++) {
-				irValue *res = ir_build_expr(proc, rs->results[res_index]);
-				Type *t = ir_type(res);
-				if (t->kind == Type_Tuple) {
-					for_array(i, t->Tuple.variables) {
-						Entity *e = t->Tuple.variables[i];
-						irValue *v = ir_emit_struct_ev(proc, res, cast(i32)i);
-						array_add(&results, v);
-						total_index++;
+			if (res_count != 0) {
+				for (isize res_index = 0; res_index < res_count; res_index++) {
+					irValue *res = ir_build_expr(proc, rs->results[res_index]);
+					Type *t = ir_type(res);
+					if (t->kind == Type_Tuple) {
+						for_array(i, t->Tuple.variables) {
+							Entity *e = t->Tuple.variables[i];
+							irValue *v = ir_emit_struct_ev(proc, res, cast(i32)i);
+							array_add(&results, v);
+						}
+					} else {
+						array_add(&results, res);
 					}
-				} else {
-					array_add(&results, res);
-					total_index++;
 				}
-			}
-			while (total_index < return_count) {
-				Entity *e = tuple->variables[total_index];
-				irValue *res = nullptr;
-				if (e->Variable.default_value.kind != ExactValue_Invalid) {
-					res = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
-				} else {
-					res = ir_value_nil(proc->module->allocator, e->type);
+			} else {
+				for (isize res_index = 0; res_index < return_count; res_index++) {
+					Entity *e = tuple->variables[res_index];
+					irValue **found = map_get(&proc->module->values, hash_entity(e));
+					GB_ASSERT(found);
+					irValue *res = ir_emit_load(proc, *found);
+					array_add(&results, res);
 				}
-				array_add(&results, res);
-				total_index++;
 			}
 
 			GB_ASSERT(results.count == return_count);
@@ -6766,7 +6712,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			}
 
 			v = ir_emit_load(proc, v);
-
 		}
 
 		ir_emit_return(proc, v);
@@ -7441,6 +7386,26 @@ void ir_begin_procedure_body(irProcedure *proc) {
 		}
 	}
 
+	if (proc->type->Proc.has_named_results) {
+		GB_ASSERT(proc->type->Proc.result_count > 0);
+		TypeTuple *results = &proc->type->Proc.results->Tuple;
+		for_array(i, results->variables) {
+			Entity *e = results->variables[i];
+			if (e->kind != Entity_Variable) {
+				continue;
+			}
+
+			if (e->token.string != "") {
+				GB_ASSERT(!is_blank_ident(e->token));
+				irValue *res = ir_add_local(proc, e, e->identifier, true);
+				if (e->Variable.default_value.kind != ExactValue_Invalid) {
+					irValue *c = ir_value_constant(a, e->type, e->Variable.default_value);
+					ir_emit_store(proc, res, c);
+				}
+			}
+		}
+	}
+
 
 	if (proc->type->Proc.calling_convention == ProcCC_Odin) {
 		Entity *e = make_entity_param(a, nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);

+ 7 - 4
src/main.cpp

@@ -1,10 +1,15 @@
 // #define NO_ARRAY_BOUNDS_CHECK
+// #define NO_POINTER_ARITHMETIC
 
 #include "common.cpp"
 #include "timings.cpp"
 #include "build_settings.cpp"
 #include "tokenizer.cpp"
 #include "exact_value.cpp"
+
+#include "parser.hpp"
+#include "checker.hpp"
+
 #include "parser.cpp"
 #include "docs.cpp"
 #include "checker.cpp"
@@ -37,6 +42,7 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	// gb_printf_err("%.*s\n", cast(int)cmd_len, cmd_line);
 
 	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	defer (gb_temp_arena_memory_end(tmp));
 
 	cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
 
@@ -54,7 +60,6 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 		exit_code = -1;
 	}
 
-	gb_temp_arena_memory_end(tmp);
 	return exit_code;
 }
 #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
@@ -386,12 +391,10 @@ bool parse_build_flags(Array<String> args) {
 						case BuildFlag_CrossCompile: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							cross_compile_target = value.value_string;
-#ifdef GB_SYSTEM_UNIX
-#ifdef GB_ARCH_64_BIT
+#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
 							if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
 
 							} else
-#endif
 #endif
 							{
 								gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));

+ 10 - 546
src/parser.cpp

@@ -1,543 +1,3 @@
-struct AstNode;
-struct Scope;
-struct Entity;
-struct DeclInfo;
-
-enum ParseFileError {
-	ParseFile_None,
-
-	ParseFile_WrongExtension,
-	ParseFile_InvalidFile,
-	ParseFile_EmptyFile,
-	ParseFile_Permission,
-	ParseFile_NotFound,
-	ParseFile_InvalidToken,
-
-	ParseFile_Count,
-};
-
-struct CommentGroup {
-	Array<Token> list; // Token_Comment
-};
-
-
-enum ImportedFileKind {
-	ImportedFile_Normal,
-	ImportedFile_Shared,
-	ImportedFile_Init,
-};
-
-struct ImportedFile {
-	ImportedFileKind kind;
-	String           path;
-	String           rel_path;
-	TokenPos         pos; // import
-	isize            index;
-};
-
-
-struct AstFile {
-	isize               id;
-	String              fullpath;
-	gbArena             arena;
-	Tokenizer           tokenizer;
-	Array<Token>        tokens;
-	isize               curr_token_index;
-	Token               curr_token;
-	Token               prev_token; // previous non-comment
-
-	// >= 0: In Expression
-	// <  0: In Control Clause
-	// NOTE(bill): Used to prevent type literals in control clauses
-	isize               expr_level;
-	bool                allow_range; // NOTE(bill): Ranges are only allowed in certain cases
-	bool                in_foreign_block;
-	bool                allow_type;
-	isize               when_level;
-
-	Array<AstNode *>    decls;
-	ImportedFileKind    file_kind;
-	bool                is_global_scope;
-	Array<AstNode *>    imports_and_exports; // 'import' 'using import' 'export'
-
-
-	AstNode *           curr_proc;
-	isize               scope_level;
-	Scope *             scope;       // NOTE(bill): Created in checker
-	DeclInfo *          decl_info;   // NOTE(bill): Created in checker
-
-
-	CommentGroup        lead_comment; // Comment (block) before the decl
-	CommentGroup        line_comment; // Comment after the semicolon
-	CommentGroup        docs;         // current docs
-	Array<CommentGroup> comments;     // All the comments!
-
-
-#define PARSER_MAX_FIX_COUNT 6
-	isize    fix_count;
-	TokenPos fix_prev_pos;
-};
-
-
-struct Parser {
-	String              init_fullpath;
-	Array<AstFile *>    files;
-	Array<ImportedFile> imports;
-	isize               total_token_count;
-	isize               total_line_count;
-	gbMutex             file_add_mutex;
-	gbMutex             file_decl_mutex;
-};
-
-enum ProcInlining {
-	ProcInlining_none = 0,
-	ProcInlining_inline = 1,
-	ProcInlining_no_inline = 2,
-};
-
-enum ProcTag {
-	ProcTag_bounds_check    = 1<<0,
-	ProcTag_no_bounds_check = 1<<1,
-	ProcTag_require_results = 1<<4,
-};
-
-enum ProcCallingConvention {
-	ProcCC_Invalid = 0,
-	ProcCC_Odin,
-	ProcCC_Contextless,
-	ProcCC_CDecl,
-	ProcCC_StdCall,
-	ProcCC_FastCall,
-
-	// TODO(bill): Add extra calling conventions
-	// ProcCC_VectorCall,
-	// ProcCC_ClrCall,
-
-	ProcCC_ForeignBlockDefault = -1,
-};
-
-enum StmtStateFlag {
-	StmtStateFlag_bounds_check    = 1<<0,
-	StmtStateFlag_no_bounds_check = 1<<1,
-};
-
-enum FieldFlag {
-	FieldFlag_NONE      = 0,
-	FieldFlag_ellipsis  = 1<<0,
-	FieldFlag_using     = 1<<1,
-	FieldFlag_no_alias  = 1<<2,
-	FieldFlag_c_vararg  = 1<<3,
-	FieldFlag_in        = 1<<4,
-
-	// FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_in,
-	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg,
-	FieldFlag_Struct    = FieldFlag_using,
-};
-
-enum StmtAllowFlag {
-	StmtAllowFlag_None  = 0,
-	StmtAllowFlag_In    = 1<<0,
-	StmtAllowFlag_Label = 1<<1,
-};
-
-
-
-Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
-	Array<AstNode *> a;
-	array_init(&a, heap_allocator(), init_capacity);
-	return a;
-}
-
-
-// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
-// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
-// all the nodes and even memcpy in a different kind of node
-#define AST_NODE_KINDS \
-	AST_NODE_KIND(Ident,          "identifier",      struct { \
-		Token   token;  \
-		Entity *entity; \
-	}) \
-	AST_NODE_KIND(Implicit,       "implicit",        Token) \
-	AST_NODE_KIND(Undef,          "undef",           Token) \
-	AST_NODE_KIND(BasicLit,       "basic literal",   struct { \
-		Token token; \
-	}) \
-	AST_NODE_KIND(BasicDirective, "basic directive", struct { \
-		Token token; \
-		String name; \
-	}) \
-	AST_NODE_KIND(Ellipsis,       "ellipsis", struct { \
-		Token token; \
-		AstNode *expr; \
-	}) \
-	AST_NODE_KIND(ProcGroup, "procedure group", struct { \
-		Token token; \
-		Token open;  \
-		Token close; \
-		Array<AstNode *> args; \
-	}) \
-	AST_NODE_KIND(ProcLit, "procedure literal", struct { \
-		AstNode *type; \
-		AstNode *body; \
-		u64      tags; \
-		ProcInlining inlining; \
-	}) \
-	AST_NODE_KIND(CompoundLit, "compound literal", struct { \
-		AstNode *type; \
-		Array<AstNode *> elems; \
-		Token open, close; \
-	}) \
-AST_NODE_KIND(_ExprBegin,  "",  i32) \
-	AST_NODE_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \
-	AST_NODE_KIND(TagExpr,      "tag expression",         struct { Token token, name; AstNode *expr; }) \
-	AST_NODE_KIND(RunExpr,      "run expression",         struct { Token token, name; AstNode *expr; }) \
-	AST_NODE_KIND(UnaryExpr,    "unary expression",       struct { Token op; AstNode *expr; }) \
-	AST_NODE_KIND(BinaryExpr,   "binary expression",      struct { Token op; AstNode *left, *right; } ) \
-	AST_NODE_KIND(ParenExpr,    "parentheses expression", struct { AstNode *expr; Token open, close; }) \
-	AST_NODE_KIND(SelectorExpr, "selector expression",    struct { Token token; AstNode *expr, *selector; }) \
-	AST_NODE_KIND(IndexExpr,    "index expression",       struct { AstNode *expr, *index; Token open, close; }) \
-	AST_NODE_KIND(DerefExpr,    "dereference expression", struct { Token op; AstNode *expr; }) \
-	AST_NODE_KIND(SliceExpr,    "slice expression", struct { \
-		AstNode *expr; \
-		Token open, close; \
-		Token interval; \
-		AstNode *low, *high; \
-	}) \
-	AST_NODE_KIND(CallExpr,     "call expression", struct { \
-		AstNode *    proc; \
-		Array<AstNode *> args; \
-		Token        open; \
-		Token        close; \
-		Token        ellipsis; \
-	}) \
-	AST_NODE_KIND(FieldValue,    "field value",         struct { Token eq; AstNode *field, *value; }) \
-	AST_NODE_KIND(TernaryExpr,   "ternary expression",  struct { AstNode *cond, *x, *y; }) \
-	AST_NODE_KIND(TypeAssertion, "type assertion",      struct { AstNode *expr; Token dot; AstNode *type; }) \
-	AST_NODE_KIND(TypeCast,      "type cast",           struct { Token token; AstNode *type, *expr; }) \
-AST_NODE_KIND(_ExprEnd,       "", i32) \
-AST_NODE_KIND(_StmtBegin,     "", i32) \
-	AST_NODE_KIND(BadStmt,    "bad statement",                 struct { Token begin, end; }) \
-	AST_NODE_KIND(EmptyStmt,  "empty statement",               struct { Token token; }) \
-	AST_NODE_KIND(ExprStmt,   "expression statement",          struct { AstNode *expr; } ) \
-	AST_NODE_KIND(TagStmt,    "tag statement", struct { \
-		Token token; \
-		Token name; \
-		AstNode *stmt; \
-	}) \
-	AST_NODE_KIND(AssignStmt, "assign statement", struct { \
-		Token op; \
-		Array<AstNode *> lhs, rhs; \
-	}) \
-	AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \
-		Token op; \
-		AstNode *expr; \
-	}) \
-AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
-	AST_NODE_KIND(BlockStmt, "block statement", struct { \
-		Array<AstNode *> stmts; \
-		Token open, close; \
-	}) \
-	AST_NODE_KIND(IfStmt, "if statement", struct { \
-		Token token; \
-		AstNode *init; \
-		AstNode *cond; \
-		AstNode *body; \
-		AstNode *else_stmt; \
-	}) \
-	AST_NODE_KIND(WhenStmt, "when statement", struct { \
-		Token token; \
-		AstNode *cond; \
-		AstNode *body; \
-		AstNode *else_stmt; \
-		bool is_cond_determined; \
-		bool determined_cond; \
-	}) \
-	AST_NODE_KIND(ReturnStmt, "return statement", struct { \
-		Token token; \
-		Array<AstNode *> results; \
-	}) \
-	AST_NODE_KIND(ForStmt, "for statement", struct { \
-		Token    token; \
-		AstNode *label; \
-		AstNode *init; \
-		AstNode *cond; \
-		AstNode *post; \
-		AstNode *body; \
-	}) \
-	AST_NODE_KIND(RangeStmt, "range statement", struct { \
-		Token    token; \
-		AstNode *label; \
-		AstNode *val0; \
-		AstNode *val1; \
-		Token    in_token; \
-		AstNode *expr; \
-		AstNode *body; \
-	}) \
-	AST_NODE_KIND(CaseClause, "case clause", struct { \
-		Token token;             \
-		Array<AstNode *> list;   \
-		Array<AstNode *> stmts;  \
-		Entity *implicit_entity; \
-	}) \
-	AST_NODE_KIND(SwitchStmt, "switch statement", struct { \
-		Token token;   \
-		AstNode *label; \
-		AstNode *init; \
-		AstNode *tag;  \
-		AstNode *body; \
-	}) \
-	AST_NODE_KIND(TypeSwitchStmt, "type switch statement", struct { \
-		Token    token; \
-		AstNode *label; \
-		AstNode *tag;   \
-		AstNode *body;  \
-	}) \
-	AST_NODE_KIND(DeferStmt,  "defer statement",  struct { Token token; AstNode *stmt; }) \
-	AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
-	AST_NODE_KIND(UsingStmt,  "using statement",  struct { \
-		Token token;   \
-		Array<AstNode *> list; \
-	}) \
-	AST_NODE_KIND(UsingInStmt, "using in statement",  struct { \
-		Token using_token;     \
-		Array<AstNode *> list; \
-		Token in_token;        \
-		AstNode *expr;         \
-	}) \
-	AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
-		Token string;     \
-		AstNode *operand; \
-	}) \
-	AST_NODE_KIND(AsmStmt,    "assembly statement", struct { \
-		Token token;           \
-		bool is_volatile;      \
-		Token open, close;     \
-		Token code_string;     \
-		AstNode *output_list;  \
-		AstNode *input_list;   \
-		AstNode *clobber_list; \
-		isize output_count, input_count, clobber_count; \
-	}) \
-	AST_NODE_KIND(PushContext, "context <- statement", struct { \
-		Token token;   \
-		AstNode *expr; \
-		AstNode *body; \
-	}) \
-AST_NODE_KIND(_ComplexStmtEnd, "", i32) \
-AST_NODE_KIND(_StmtEnd,        "", i32) \
-AST_NODE_KIND(_DeclBegin,      "", i32) \
-	AST_NODE_KIND(BadDecl,     "bad declaration",     struct { Token begin, end; }) \
-	AST_NODE_KIND(ForeignBlockDecl, "foreign block declaration", struct { \
-		Token            token;           \
-		AstNode *        foreign_library; \
-		Token            open, close;     \
-		Array<AstNode *> decls;           \
-		Array<AstNode *> attributes;      \
-		bool             been_handled;    \
-		CommentGroup     docs;            \
-	}) \
-	AST_NODE_KIND(Label, "label", struct { 	\
-		Token token; \
-		AstNode *name; \
-	}) \
-	AST_NODE_KIND(ValueDecl, "value declaration", struct { \
-		Array<AstNode *> names;        \
-		AstNode *        type;         \
-		Array<AstNode *> values;       \
-		bool             is_using;     \
-		bool             is_mutable;   \
-		bool             been_handled; \
-		Array<AstNode *> attributes;   \
-		CommentGroup     docs;         \
-		CommentGroup     comment;      \
-	}) \
-	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
-		AstFile *file;          \
-		Token    token;         \
-		Token    relpath;       \
-		String   fullpath;      \
-		Token    import_name;   \
-		bool     is_using;      \
-		bool     been_handled;  \
-		Array<AstNode *> using_in_list; \
-		CommentGroup docs;      \
-		CommentGroup comment;   \
-	}) \
-	AST_NODE_KIND(ExportDecl, "export declaration", struct { \
-		AstFile *file;          \
-		Token    token;         \
-		Token    relpath;       \
-		String   fullpath;      \
-		bool     been_handled;  \
-		Array<AstNode *> using_in_list; \
-		CommentGroup docs;      \
-		CommentGroup comment;   \
-	}) \
-	AST_NODE_KIND(ForeignImportDecl, "foreign import declaration", struct { \
-		Token    token;           \
-		Token    filepath;        \
-		Token    library_name;    \
-		String   base_dir;        \
-		String   collection_name; \
-		String   fullpath;        \
-		bool     been_handled;    \
-		CommentGroup docs;        \
-		CommentGroup comment;     \
-	}) \
-AST_NODE_KIND(_DeclEnd,   "", i32) \
-	AST_NODE_KIND(Attribute, "attribute", struct { \
-		Token    token;         \
-		AstNode *type;          \
-		Array<AstNode *> elems; \
-		Token open, close;      \
-	}) \
-	AST_NODE_KIND(Field, "field", struct { \
-		Array<AstNode *> names;            \
-		AstNode *        type;             \
-		AstNode *        default_value;    \
-		u32              flags;            \
-		CommentGroup     docs;             \
-		CommentGroup     comment;          \
-	}) \
-	AST_NODE_KIND(FieldList, "field list", struct { \
-		Token token; \
-		Array<AstNode *> list; \
-	}) \
-	AST_NODE_KIND(UnionField, "union field", struct { \
-		AstNode *name; \
-		AstNode *list; \
-	}) \
-AST_NODE_KIND(_TypeBegin, "", i32) \
-	AST_NODE_KIND(TypeType, "type", struct { \
-		Token token; \
-		AstNode *specialization; \
-	}) \
-	AST_NODE_KIND(HelperType, "helper type", struct { \
-		Token token; \
-		AstNode *type; \
-	}) \
-	AST_NODE_KIND(AliasType, "alias type", struct { \
-		Token token; \
-		AstNode *type; \
-	}) \
-	AST_NODE_KIND(PolyType, "polymorphic type", struct { \
-		Token    token; \
-		AstNode *type;  \
-		AstNode *specialization;  \
-	}) \
-	AST_NODE_KIND(ProcType, "procedure type", struct { \
-		Token    token;   \
-		AstNode *params;  \
-		AstNode *results; \
-		u64      tags;    \
-		ProcCallingConvention calling_convention; \
-		bool     generic; \
-	}) \
-	AST_NODE_KIND(PointerType, "pointer type", struct { \
-		Token token; \
-		AstNode *type; \
-	}) \
-	AST_NODE_KIND(ArrayType, "array type", struct { \
-		Token token; \
-		AstNode *count; \
-		AstNode *elem; \
-	}) \
-	AST_NODE_KIND(DynamicArrayType, "dynamic array type", struct { \
-		Token token; \
-		AstNode *elem; \
-	}) \
-	AST_NODE_KIND(StructType, "struct type", struct { \
-		Token            token;               \
-		Array<AstNode *> fields;              \
-		isize            field_count;         \
-		AstNode *        polymorphic_params;  \
-		bool             is_packed;           \
-		bool             is_raw_union;        \
-		AstNode *        align;               \
-	}) \
-	AST_NODE_KIND(UnionType, "union type", struct { \
-		Token            token;    \
-		Array<AstNode *> variants; \
-		AstNode *        align;    \
-	}) \
-	AST_NODE_KIND(EnumType, "enum type", struct { \
-		Token            token; \
-		AstNode *        base_type; \
-		Array<AstNode *> fields; /* FieldValue */ \
-	}) \
-	AST_NODE_KIND(BitFieldType, "bit field type", struct { \
-		Token            token; \
-		Array<AstNode *> fields; /* FieldValue with : */ \
-		AstNode *        align; \
-	}) \
-	AST_NODE_KIND(MapType, "map type", struct { \
-		Token    token; \
-		AstNode *count; \
-		AstNode *key; \
-		AstNode *value; \
-	}) \
-AST_NODE_KIND(_TypeEnd,  "", i32)
-
-enum AstNodeKind {
-	AstNode_Invalid,
-#define AST_NODE_KIND(_kind_name_, ...) GB_JOIN2(AstNode_, _kind_name_),
-	AST_NODE_KINDS
-#undef AST_NODE_KIND
-	AstNode_Count,
-};
-
-String const ast_node_strings[] = {
-	{cast(u8 *)"invalid node", gb_size_of("invalid node")},
-#define AST_NODE_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
-	AST_NODE_KINDS
-#undef AST_NODE_KIND
-};
-
-#define AST_NODE_KIND(_kind_name_, name, ...) typedef __VA_ARGS__ GB_JOIN2(AstNode, _kind_name_);
-	AST_NODE_KINDS
-#undef AST_NODE_KIND
-
-struct AstNode {
-	AstNodeKind kind;
-	u32         stmt_state_flags;
-	AstFile *   file;
-	Scope *     scope;
-
-	union {
-#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
-	AST_NODE_KINDS
-#undef AST_NODE_KIND
-	};
-};
-
-
-#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
-#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
-#ifndef case_end
-#define case_end } break;
-#endif
-
-
-gb_inline bool is_ast_node_expr(AstNode *node) {
-	return gb_is_between(node->kind, AstNode__ExprBegin+1, AstNode__ExprEnd-1);
-}
-gb_inline bool is_ast_node_stmt(AstNode *node) {
-	return gb_is_between(node->kind, AstNode__StmtBegin+1, AstNode__StmtEnd-1);
-}
-gb_inline bool is_ast_node_complex_stmt(AstNode *node) {
-	return gb_is_between(node->kind, AstNode__ComplexStmtBegin+1, AstNode__ComplexStmtEnd-1);
-}
-gb_inline bool is_ast_node_decl(AstNode *node) {
-	return gb_is_between(node->kind, AstNode__DeclBegin+1, AstNode__DeclEnd-1);
-}
-gb_inline bool is_ast_node_type(AstNode *node) {
-	return gb_is_between(node->kind, AstNode__TypeBegin+1, AstNode__TypeEnd-1);
-}
-gb_inline bool is_ast_node_when_stmt(AstNode *node) {
-	return node->kind == AstNode_WhenStmt;
-}
-
-
 Token ast_node_token(AstNode *node) {
 	switch (node->kind) {
 	case AstNode_Ident:          return node->Ident.token;
@@ -3135,7 +2595,7 @@ AstNode *parse_results(AstFile *f) {
 
 	AstNode *list = nullptr;
 	expect_token(f, Token_OpenParen);
-	list = parse_field_list(f, nullptr, 0, Token_CloseParen, true, false);
+	list = parse_field_list(f, nullptr, FieldFlag_Results, Token_CloseParen, true, false);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	return list;
 }
@@ -3547,6 +3007,10 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 		Array<AstNode *> names = {};
 		AstNode *type = list[i].node;
 		Token token = blank_token;
+		if (allowed_flags&FieldFlag_Results) {
+			// NOTE(bill): Make this nothing and not `_`
+			token.string = str_lit("");
+		}
 
 		array_init_count(&names, heap_allocator(), 1);
 		token.pos = ast_node_token(type).pos;
@@ -3725,11 +3189,11 @@ AstNode *parse_return_stmt(AstFile *f) {
 
 	while (f->curr_token.kind != Token_Semicolon) {
 		AstNode *arg = parse_expr(f, false);
-		if (f->curr_token.kind == Token_Eq) {
-			Token eq = expect_token(f, Token_Eq);
-			AstNode *value = parse_value(f);
-			arg = ast_field_value(f, arg, value, eq);
-		}
+		// if (f->curr_token.kind == Token_Eq) {
+		// 	Token eq = expect_token(f, Token_Eq);
+		// 	AstNode *value = parse_value(f);
+		// 	arg = ast_field_value(f, arg, value, eq);
+		// }
 
 		array_add(&results, arg);
 		if (f->curr_token.kind != Token_Comma ||

+ 545 - 0
src/parser.hpp

@@ -0,0 +1,545 @@
+struct AstNode;
+struct Scope;
+struct Type;
+struct Entity;
+struct DeclInfo;
+
+
+enum ParseFileError {
+	ParseFile_None,
+
+	ParseFile_WrongExtension,
+	ParseFile_InvalidFile,
+	ParseFile_EmptyFile,
+	ParseFile_Permission,
+	ParseFile_NotFound,
+	ParseFile_InvalidToken,
+
+	ParseFile_Count,
+};
+
+struct CommentGroup {
+	Array<Token> list; // Token_Comment
+};
+
+
+enum ImportedFileKind {
+	ImportedFile_Normal,
+	ImportedFile_Shared,
+	ImportedFile_Init,
+};
+
+struct ImportedFile {
+	ImportedFileKind kind;
+	String           path;
+	String           rel_path;
+	TokenPos         pos; // import
+	isize            index;
+};
+
+
+struct AstFile {
+	isize               id;
+	String              fullpath;
+	gbArena             arena;
+	Tokenizer           tokenizer;
+	Array<Token>        tokens;
+	isize               curr_token_index;
+	Token               curr_token;
+	Token               prev_token; // previous non-comment
+
+	// >= 0: In Expression
+	// <  0: In Control Clause
+	// NOTE(bill): Used to prevent type literals in control clauses
+	isize               expr_level;
+	bool                allow_range; // NOTE(bill): Ranges are only allowed in certain cases
+	bool                in_foreign_block;
+	bool                allow_type;
+	isize               when_level;
+
+	Array<AstNode *>    decls;
+	ImportedFileKind    file_kind;
+	bool                is_global_scope;
+	Array<AstNode *>    imports_and_exports; // 'import' 'using import' 'export'
+
+
+	AstNode *           curr_proc;
+	isize               scope_level;
+	Scope *             scope;       // NOTE(bill): Created in checker
+	DeclInfo *          decl_info;   // NOTE(bill): Created in checker
+
+
+	CommentGroup        lead_comment; // Comment (block) before the decl
+	CommentGroup        line_comment; // Comment after the semicolon
+	CommentGroup        docs;         // current docs
+	Array<CommentGroup> comments;     // All the comments!
+
+
+#define PARSER_MAX_FIX_COUNT 6
+	isize    fix_count;
+	TokenPos fix_prev_pos;
+};
+
+
+struct Parser {
+	String              init_fullpath;
+	Array<AstFile *>    files;
+	Array<ImportedFile> imports;
+	isize               total_token_count;
+	isize               total_line_count;
+	gbMutex             file_add_mutex;
+	gbMutex             file_decl_mutex;
+};
+
+enum ProcInlining {
+	ProcInlining_none = 0,
+	ProcInlining_inline = 1,
+	ProcInlining_no_inline = 2,
+};
+
+enum ProcTag {
+	ProcTag_bounds_check    = 1<<0,
+	ProcTag_no_bounds_check = 1<<1,
+	ProcTag_require_results = 1<<4,
+};
+
+enum ProcCallingConvention {
+	ProcCC_Invalid = 0,
+	ProcCC_Odin,
+	ProcCC_Contextless,
+	ProcCC_CDecl,
+	ProcCC_StdCall,
+	ProcCC_FastCall,
+
+	// TODO(bill): Add extra calling conventions
+	// ProcCC_VectorCall,
+	// ProcCC_ClrCall,
+
+	ProcCC_ForeignBlockDefault = -1,
+};
+
+enum StmtStateFlag {
+	StmtStateFlag_bounds_check    = 1<<0,
+	StmtStateFlag_no_bounds_check = 1<<1,
+};
+
+enum FieldFlag {
+	FieldFlag_NONE      = 0,
+	FieldFlag_ellipsis  = 1<<0,
+	FieldFlag_using     = 1<<1,
+	FieldFlag_no_alias  = 1<<2,
+	FieldFlag_c_vararg  = 1<<3,
+
+	FieldFlag_in        = 1<<5,
+
+
+	FieldFlag_Results   = 1<<16,
+
+	// FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_in,
+	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg,
+	FieldFlag_Struct    = FieldFlag_using,
+};
+
+enum StmtAllowFlag {
+	StmtAllowFlag_None  = 0,
+	StmtAllowFlag_In    = 1<<0,
+	StmtAllowFlag_Label = 1<<1,
+};
+
+
+
+Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
+	Array<AstNode *> a;
+	array_init(&a, heap_allocator(), init_capacity);
+	return a;
+}
+
+
+// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
+// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
+// all the nodes and even memcpy in a different kind of node
+#define AST_NODE_KINDS \
+	AST_NODE_KIND(Ident,          "identifier",      struct { \
+		Token   token;  \
+		Entity *entity; \
+	}) \
+	AST_NODE_KIND(Implicit,       "implicit",        Token) \
+	AST_NODE_KIND(Undef,          "undef",           Token) \
+	AST_NODE_KIND(BasicLit,       "basic literal",   struct { \
+		Token token; \
+	}) \
+	AST_NODE_KIND(BasicDirective, "basic directive", struct { \
+		Token token; \
+		String name; \
+	}) \
+	AST_NODE_KIND(Ellipsis,       "ellipsis", struct { \
+		Token token; \
+		AstNode *expr; \
+	}) \
+	AST_NODE_KIND(ProcGroup, "procedure group", struct { \
+		Token token; \
+		Token open;  \
+		Token close; \
+		Array<AstNode *> args; \
+	}) \
+	AST_NODE_KIND(ProcLit, "procedure literal", struct { \
+		AstNode *type; \
+		AstNode *body; \
+		u64      tags; \
+		ProcInlining inlining; \
+	}) \
+	AST_NODE_KIND(CompoundLit, "compound literal", struct { \
+		AstNode *type; \
+		Array<AstNode *> elems; \
+		Token open, close; \
+	}) \
+AST_NODE_KIND(_ExprBegin,  "",  i32) \
+	AST_NODE_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \
+	AST_NODE_KIND(TagExpr,      "tag expression",         struct { Token token, name; AstNode *expr; }) \
+	AST_NODE_KIND(RunExpr,      "run expression",         struct { Token token, name; AstNode *expr; }) \
+	AST_NODE_KIND(UnaryExpr,    "unary expression",       struct { Token op; AstNode *expr; }) \
+	AST_NODE_KIND(BinaryExpr,   "binary expression",      struct { Token op; AstNode *left, *right; } ) \
+	AST_NODE_KIND(ParenExpr,    "parentheses expression", struct { AstNode *expr; Token open, close; }) \
+	AST_NODE_KIND(SelectorExpr, "selector expression",    struct { Token token; AstNode *expr, *selector; }) \
+	AST_NODE_KIND(IndexExpr,    "index expression",       struct { AstNode *expr, *index; Token open, close; }) \
+	AST_NODE_KIND(DerefExpr,    "dereference expression", struct { Token op; AstNode *expr; }) \
+	AST_NODE_KIND(SliceExpr,    "slice expression", struct { \
+		AstNode *expr; \
+		Token open, close; \
+		Token interval; \
+		AstNode *low, *high; \
+	}) \
+	AST_NODE_KIND(CallExpr,     "call expression", struct { \
+		AstNode *    proc; \
+		Array<AstNode *> args; \
+		Token        open; \
+		Token        close; \
+		Token        ellipsis; \
+	}) \
+	AST_NODE_KIND(FieldValue,    "field value",         struct { Token eq; AstNode *field, *value; }) \
+	AST_NODE_KIND(TernaryExpr,   "ternary expression",  struct { AstNode *cond, *x, *y; }) \
+	AST_NODE_KIND(TypeAssertion, "type assertion",      struct { AstNode *expr; Token dot; AstNode *type; }) \
+	AST_NODE_KIND(TypeCast,      "type cast",           struct { Token token; AstNode *type, *expr; }) \
+AST_NODE_KIND(_ExprEnd,       "", i32) \
+AST_NODE_KIND(_StmtBegin,     "", i32) \
+	AST_NODE_KIND(BadStmt,    "bad statement",                 struct { Token begin, end; }) \
+	AST_NODE_KIND(EmptyStmt,  "empty statement",               struct { Token token; }) \
+	AST_NODE_KIND(ExprStmt,   "expression statement",          struct { AstNode *expr; } ) \
+	AST_NODE_KIND(TagStmt,    "tag statement", struct { \
+		Token token; \
+		Token name; \
+		AstNode *stmt; \
+	}) \
+	AST_NODE_KIND(AssignStmt, "assign statement", struct { \
+		Token op; \
+		Array<AstNode *> lhs, rhs; \
+	}) \
+	AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \
+		Token op; \
+		AstNode *expr; \
+	}) \
+AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
+	AST_NODE_KIND(BlockStmt, "block statement", struct { \
+		Array<AstNode *> stmts; \
+		Token open, close; \
+	}) \
+	AST_NODE_KIND(IfStmt, "if statement", struct { \
+		Token token; \
+		AstNode *init; \
+		AstNode *cond; \
+		AstNode *body; \
+		AstNode *else_stmt; \
+	}) \
+	AST_NODE_KIND(WhenStmt, "when statement", struct { \
+		Token token; \
+		AstNode *cond; \
+		AstNode *body; \
+		AstNode *else_stmt; \
+		bool is_cond_determined; \
+		bool determined_cond; \
+	}) \
+	AST_NODE_KIND(ReturnStmt, "return statement", struct { \
+		Token token; \
+		Array<AstNode *> results; \
+	}) \
+	AST_NODE_KIND(ForStmt, "for statement", struct { \
+		Token    token; \
+		AstNode *label; \
+		AstNode *init; \
+		AstNode *cond; \
+		AstNode *post; \
+		AstNode *body; \
+	}) \
+	AST_NODE_KIND(RangeStmt, "range statement", struct { \
+		Token    token; \
+		AstNode *label; \
+		AstNode *val0; \
+		AstNode *val1; \
+		Token    in_token; \
+		AstNode *expr; \
+		AstNode *body; \
+	}) \
+	AST_NODE_KIND(CaseClause, "case clause", struct { \
+		Token token;             \
+		Array<AstNode *> list;   \
+		Array<AstNode *> stmts;  \
+		Entity *implicit_entity; \
+	}) \
+	AST_NODE_KIND(SwitchStmt, "switch statement", struct { \
+		Token token;   \
+		AstNode *label; \
+		AstNode *init; \
+		AstNode *tag;  \
+		AstNode *body; \
+	}) \
+	AST_NODE_KIND(TypeSwitchStmt, "type switch statement", struct { \
+		Token    token; \
+		AstNode *label; \
+		AstNode *tag;   \
+		AstNode *body;  \
+	}) \
+	AST_NODE_KIND(DeferStmt,  "defer statement",  struct { Token token; AstNode *stmt; }) \
+	AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
+	AST_NODE_KIND(UsingStmt,  "using statement",  struct { \
+		Token token;   \
+		Array<AstNode *> list; \
+	}) \
+	AST_NODE_KIND(UsingInStmt, "using in statement",  struct { \
+		Token using_token;     \
+		Array<AstNode *> list; \
+		Token in_token;        \
+		AstNode *expr;         \
+	}) \
+	AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
+		Token string;     \
+		AstNode *operand; \
+	}) \
+	AST_NODE_KIND(AsmStmt,    "assembly statement", struct { \
+		Token token;           \
+		bool is_volatile;      \
+		Token open, close;     \
+		Token code_string;     \
+		AstNode *output_list;  \
+		AstNode *input_list;   \
+		AstNode *clobber_list; \
+		isize output_count, input_count, clobber_count; \
+	}) \
+	AST_NODE_KIND(PushContext, "context <- statement", struct { \
+		Token token;   \
+		AstNode *expr; \
+		AstNode *body; \
+	}) \
+AST_NODE_KIND(_ComplexStmtEnd, "", i32) \
+AST_NODE_KIND(_StmtEnd,        "", i32) \
+AST_NODE_KIND(_DeclBegin,      "", i32) \
+	AST_NODE_KIND(BadDecl,     "bad declaration",     struct { Token begin, end; }) \
+	AST_NODE_KIND(ForeignBlockDecl, "foreign block declaration", struct { \
+		Token            token;           \
+		AstNode *        foreign_library; \
+		Token            open, close;     \
+		Array<AstNode *> decls;           \
+		Array<AstNode *> attributes;      \
+		bool             been_handled;    \
+		CommentGroup     docs;            \
+	}) \
+	AST_NODE_KIND(Label, "label", struct { 	\
+		Token token; \
+		AstNode *name; \
+	}) \
+	AST_NODE_KIND(ValueDecl, "value declaration", struct { \
+		Array<AstNode *> names;        \
+		AstNode *        type;         \
+		Array<AstNode *> values;       \
+		bool             is_using;     \
+		bool             is_mutable;   \
+		bool             been_handled; \
+		Array<AstNode *> attributes;   \
+		CommentGroup     docs;         \
+		CommentGroup     comment;      \
+	}) \
+	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
+		AstFile *file;          \
+		Token    token;         \
+		Token    relpath;       \
+		String   fullpath;      \
+		Token    import_name;   \
+		bool     is_using;      \
+		bool     been_handled;  \
+		Array<AstNode *> using_in_list; \
+		CommentGroup docs;      \
+		CommentGroup comment;   \
+	}) \
+	AST_NODE_KIND(ExportDecl, "export declaration", struct { \
+		AstFile *file;          \
+		Token    token;         \
+		Token    relpath;       \
+		String   fullpath;      \
+		bool     been_handled;  \
+		Array<AstNode *> using_in_list; \
+		CommentGroup docs;      \
+		CommentGroup comment;   \
+	}) \
+	AST_NODE_KIND(ForeignImportDecl, "foreign import declaration", struct { \
+		Token    token;           \
+		Token    filepath;        \
+		Token    library_name;    \
+		String   base_dir;        \
+		String   collection_name; \
+		String   fullpath;        \
+		bool     been_handled;    \
+		CommentGroup docs;        \
+		CommentGroup comment;     \
+	}) \
+AST_NODE_KIND(_DeclEnd,   "", i32) \
+	AST_NODE_KIND(Attribute, "attribute", struct { \
+		Token    token;         \
+		AstNode *type;          \
+		Array<AstNode *> elems; \
+		Token open, close;      \
+	}) \
+	AST_NODE_KIND(Field, "field", struct { \
+		Array<AstNode *> names;            \
+		AstNode *        type;             \
+		AstNode *        default_value;    \
+		u32              flags;            \
+		CommentGroup     docs;             \
+		CommentGroup     comment;          \
+	}) \
+	AST_NODE_KIND(FieldList, "field list", struct { \
+		Token token; \
+		Array<AstNode *> list; \
+	}) \
+	AST_NODE_KIND(UnionField, "union field", struct { \
+		AstNode *name; \
+		AstNode *list; \
+	}) \
+AST_NODE_KIND(_TypeBegin, "", i32) \
+	AST_NODE_KIND(TypeType, "type", struct { \
+		Token token; \
+		AstNode *specialization; \
+	}) \
+	AST_NODE_KIND(HelperType, "helper type", struct { \
+		Token token; \
+		AstNode *type; \
+	}) \
+	AST_NODE_KIND(AliasType, "alias type", struct { \
+		Token token; \
+		AstNode *type; \
+	}) \
+	AST_NODE_KIND(PolyType, "polymorphic type", struct { \
+		Token    token; \
+		AstNode *type;  \
+		AstNode *specialization;  \
+	}) \
+	AST_NODE_KIND(ProcType, "procedure type", struct { \
+		Token    token;   \
+		AstNode *params;  \
+		AstNode *results; \
+		u64      tags;    \
+		ProcCallingConvention calling_convention; \
+		bool     generic; \
+	}) \
+	AST_NODE_KIND(PointerType, "pointer type", struct { \
+		Token token; \
+		AstNode *type; \
+	}) \
+	AST_NODE_KIND(ArrayType, "array type", struct { \
+		Token token; \
+		AstNode *count; \
+		AstNode *elem; \
+	}) \
+	AST_NODE_KIND(DynamicArrayType, "dynamic array type", struct { \
+		Token token; \
+		AstNode *elem; \
+	}) \
+	AST_NODE_KIND(StructType, "struct type", struct { \
+		Token            token;               \
+		Array<AstNode *> fields;              \
+		isize            field_count;         \
+		AstNode *        polymorphic_params;  \
+		bool             is_packed;           \
+		bool             is_raw_union;        \
+		AstNode *        align;               \
+	}) \
+	AST_NODE_KIND(UnionType, "union type", struct { \
+		Token            token;    \
+		Array<AstNode *> variants; \
+		AstNode *        align;    \
+	}) \
+	AST_NODE_KIND(EnumType, "enum type", struct { \
+		Token            token; \
+		AstNode *        base_type; \
+		Array<AstNode *> fields; /* FieldValue */ \
+	}) \
+	AST_NODE_KIND(BitFieldType, "bit field type", struct { \
+		Token            token; \
+		Array<AstNode *> fields; /* FieldValue with : */ \
+		AstNode *        align; \
+	}) \
+	AST_NODE_KIND(MapType, "map type", struct { \
+		Token    token; \
+		AstNode *count; \
+		AstNode *key; \
+		AstNode *value; \
+	}) \
+AST_NODE_KIND(_TypeEnd,  "", i32)
+
+enum AstNodeKind {
+	AstNode_Invalid,
+#define AST_NODE_KIND(_kind_name_, ...) GB_JOIN2(AstNode_, _kind_name_),
+	AST_NODE_KINDS
+#undef AST_NODE_KIND
+	AstNode_Count,
+};
+
+String const ast_node_strings[] = {
+	{cast(u8 *)"invalid node", gb_size_of("invalid node")},
+#define AST_NODE_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
+	AST_NODE_KINDS
+#undef AST_NODE_KIND
+};
+
+#define AST_NODE_KIND(_kind_name_, name, ...) typedef __VA_ARGS__ GB_JOIN2(AstNode, _kind_name_);
+	AST_NODE_KINDS
+#undef AST_NODE_KIND
+
+struct AstNode {
+	AstNodeKind kind;
+	u32         stmt_state_flags;
+	AstFile *   file;
+	Scope *     scope;
+
+	union {
+#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
+	AST_NODE_KINDS
+#undef AST_NODE_KIND
+	};
+};
+
+
+#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
+#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
+#ifndef case_end
+#define case_end } break;
+#endif
+
+
+gb_inline bool is_ast_node_expr(AstNode *node) {
+	return gb_is_between(node->kind, AstNode__ExprBegin+1, AstNode__ExprEnd-1);
+}
+gb_inline bool is_ast_node_stmt(AstNode *node) {
+	return gb_is_between(node->kind, AstNode__StmtBegin+1, AstNode__StmtEnd-1);
+}
+gb_inline bool is_ast_node_complex_stmt(AstNode *node) {
+	return gb_is_between(node->kind, AstNode__ComplexStmtBegin+1, AstNode__ComplexStmtEnd-1);
+}
+gb_inline bool is_ast_node_decl(AstNode *node) {
+	return gb_is_between(node->kind, AstNode__DeclBegin+1, AstNode__DeclEnd-1);
+}
+gb_inline bool is_ast_node_type(AstNode *node) {
+	return gb_is_between(node->kind, AstNode__TypeBegin+1, AstNode__TypeEnd-1);
+}
+gb_inline bool is_ast_node_when_stmt(AstNode *node) {
+	return node->kind == AstNode_WhenStmt;
+}
+

+ 1 - 0
src/types.cpp

@@ -158,6 +158,7 @@ struct TypeStruct {
 		bool     is_polymorphic;                          \
 		bool     is_poly_specialized;                     \
 		bool     has_proc_default_values;                 \
+		bool     has_named_results;                       \
 		isize    specialization_count;                    \
 		ProcCallingConvention calling_convention;         \
 	})                                                    \