瀏覽代碼

Merge https://github.com/gingerBill/Odin

Zac Pierson 8 年之前
父節點
當前提交
8d5896ab7e
共有 15 個文件被更改,包括 875 次插入433 次删除
  1. 10 5
      code/demo.odin
  2. 44 1
      core/_preload.odin
  3. 9 12
      core/fmt.odin
  4. 2 1
      core/opengl.odin
  5. 72 0
      core/sys/wgl.odin
  6. 6 17
      core/sys/windows.odin
  7. 265 74
      src/check_expr.c
  8. 9 0
      src/checker.c
  9. 1 0
      src/entity.c
  10. 1 1
      src/gb/gb.h
  11. 249 155
      src/ir.c
  12. 45 9
      src/ir_print.c
  13. 5 4
      src/main.c
  14. 135 140
      src/parser.c
  15. 22 14
      src/types.c

+ 10 - 5
code/demo.odin

@@ -5,18 +5,22 @@
 #import "mem.odin";
 #import "opengl.odin";
 #import "os.odin";
-#import "utf8.odin";
-
+// #import "halloc.odin";
 
 main :: proc() {
-	x: f32 = false ? 123 : 55;
-	fmt.println("Ternary:", x);
+	m: map[int]int;
+	m[123] = 312;
+	fmt.println(m[123]);
+	delete(m, 123);
+	fmt.println(m[123]);
+
+
 /*
 /*
 	Version 0.1.1
 
 	Added:
-	 * Dynamic Arrays [dynamic]Type`
+	 * Dynamic Arrays `[dynamic]Type`
 	 * Dynamic Maps   `map[Key]Value`
 	 * Dynamic array and map literals
 	 * Custom struct alignemnt `struct #align 8 { bar: i8 }`
@@ -29,6 +33,7 @@ main :: proc() {
 	 * immutable variables are "completely immutable" - rules need a full explanation
 	 * `slice_to_bytes` - convert any slice to a slice of bytes
 	 * `union_cast` allows for optional ok check
+	 * ?: ternary operator
 
 	Removed:
 	 * Maybe/option types

+ 44 - 1
core/_preload.odin

@@ -37,6 +37,7 @@ Calling_Convention :: enum {
 	FAST = 3,
 }
 
+/*
 Type_Info :: union {
 	Named: struct #ordered {
 		name: string,
@@ -96,6 +97,48 @@ Type_Info :: union {
 		count:            int, // == 0 if dynamic
 	},
 }
+*/
+Type_Info :: union {
+	Named{name: string, base: ^Type_Info},
+	Integer{size: int, signed: bool},
+	Float{size: int},
+	String{},
+	Boolean{},
+	Any{},
+	Pointer{
+		elem: ^Type_Info, // nil -> rawptr
+	},
+	Procedure{
+		params:     ^Type_Info, // Type_Info.Tuple
+		results:    ^Type_Info, // Type_Info.Tuple
+		variadic:   bool,
+		convention: Calling_Convention,
+	},
+	Array{
+		elem:      ^Type_Info,
+		elem_size: int,
+		count:     int,
+	},
+	Dynamic_Array{elem: ^Type_Info, elem_size: int},
+	Slice        {elem: ^Type_Info, elem_size: int},
+	Vector       {elem: ^Type_Info, elem_size, count, align: int},
+	Tuple        {using record: Type_Info_Record}, // Only really used for procedures
+	Struct       {using record: Type_Info_Record},
+	Union        {using record: Type_Info_Record},
+	Raw_Union    {using record: Type_Info_Record},
+	Enum{
+		base:   ^Type_Info,
+		names:  []string,
+		values: []Type_Info_Enum_Value,
+	},
+	Map{
+		key:              ^Type_Info,
+		value:            ^Type_Info,
+		generated_struct: ^Type_Info,
+		count:            int, // == 0 if dynamic
+	},
+}
+
 
 // // NOTE(bill): only the ones that are needed (not all types)
 // // This will be set by the compiler
@@ -633,7 +676,7 @@ __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
 }
 
 
-__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) {
+__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
 	fr := __dynamic_map_find(h, key);
 	if fr.entry_index >= 0 {
 		__dynamic_map_erase(h, fr);

+ 9 - 12
core/fmt.odin

@@ -116,11 +116,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		case ti == type_info(int):  buffer_write_string(buf, "int");
 		case ti == type_info(uint): buffer_write_string(buf, "uint");
 		default:
-			if info.signed {
-				buffer_write_string(buf, "i");
-			} else {
-				buffer_write_string(buf, "u");
-			}
+			buffer_write_string(buf, info.signed ? "i" : "u");
 			fi := Fmt_Info{buf = buf};
 			fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
 		}
@@ -297,7 +293,7 @@ sprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
 
 
 
-parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
+parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
 	is_digit :: proc(r: rune) -> bool #inline {
 		return '0' <= r && r <= '9';
 	}
@@ -320,7 +316,12 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
 	return result, offset+i, i != 0;
 }
 
-_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) {
+_arg_number :: proc(fi: ^Fmt_Info,
+                    arg_index: int,
+                    format: string,
+                    offset: int,
+                    arg_count: int,
+                    ) -> (index: int, offset: int, ok: bool) {
 	parse_arg_number :: proc(format: string) -> (int, int, bool) {
 		if format.count < 3 {
 			return 0, 1, false;
@@ -396,11 +397,7 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
 fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
 	match verb {
 	case 't', 'v':
-		if b {
-			buffer_write_string(buf, "true");
-		} else {
-			buffer_write_string(buf, "false");
-		}
+		buffer_write_string(buf, b ? "true" : "false");
 	default:
 		fmt_bad_verb(fi, verb);
 	}

+ 2 - 1
core/opengl.odin

@@ -1,5 +1,6 @@
 #foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
 #import win32 "sys/windows.odin" when ODIN_OS == "windows";
+#import "sys/wgl.odin" when ODIN_OS == "windows";
 #load "opengl_constants.odin";
 
 Clear         :: proc(mask: u32)                                #foreign lib "glClear";
@@ -35,7 +36,7 @@ _libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
 
 GetProcAddress :: proc(name: string) -> proc() #cc_c {
 	assert(name[name.count-1] == 0);
-	res := win32.wglGetProcAddress(name.data);
+	res := wgl.GetProcAddress(name.data);
 	if res == nil {
 		res = win32.GetProcAddress(_libgl, name.data);
 	}

+ 72 - 0
core/sys/wgl.odin

@@ -0,0 +1,72 @@
+#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
+#import . "windows.odin";
+
+CONTEXT_MAJOR_VERSION_ARB          :: 0x2091;
+CONTEXT_MINOR_VERSION_ARB          :: 0x2092;
+CONTEXT_FLAGS_ARB                  :: 0x2094;
+CONTEXT_PROFILE_MASK_ARB           :: 0x9126;
+CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
+CONTEXT_CORE_PROFILE_BIT_ARB       :: 0x00000001;
+
+HGLRC :: HANDLE;
+COLORREF :: u32;
+
+LAYERPLANEDESCRIPTOR :: struct #ordered {
+	size:             u16,
+	version:          u16,
+	flags:            u32,
+	pixel_type:       byte,
+	color_bits:       byte,
+	red_bits:         byte,
+	red_shift:        byte,
+	green_bits:       byte,
+	green_shift:      byte,
+	blue_bits:        byte,
+	blue_shift:       byte,
+	alpha_bits:       byte,
+	alpha_shift:      byte,
+	accum_bits:       byte,
+	accum_red_bits:   byte,
+	accum_green_bits: byte,
+	accum_blue_bits:  byte,
+	accum_alpha_bits: byte,
+	depth_bits:       byte,
+	stencil_bits:     byte,
+	aux_buffers:      byte,
+	layer_type:       byte,
+	reserved:         byte,
+	transparent:      COLORREF,
+}
+
+POINTFLOAT :: struct #ordered {
+	x, y: f32,
+}
+
+GLYPHMETRICSFLOAT :: struct #ordered {
+	black_box_x:  f32,
+	black_box_y:  f32,
+	glyph_origin: POINTFLOAT,
+	cell_inc_x:   f32,
+	cell_inc_y:   f32,
+}
+
+CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
+ChoosePixelFormatARBType    :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
+
+
+CreateContext           :: proc(hdc: HDC) -> HGLRC                                                                                               #foreign opengl32 "wglCreateContext";
+MakeCurrent             :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL                                                                                  #foreign opengl32 "wglMakeCurrent";
+GetProcAddress          :: proc(c_str: ^u8) -> PROC                                                                                              #foreign opengl32 "wglGetProcAddress";
+DeleteContext           :: proc(hglrc: HGLRC) -> BOOL                                                                                            #foreign opengl32 "wglDeleteContext";
+CopyContext             :: proc(src, dst: HGLRC, mask: u32) -> BOOL                                                                              #foreign opengl32 "wglCopyContext";
+CreateLayerContext      :: proc(hdc: HDC, layer_plane: i32) -> HGLRC                                                                             #foreign opengl32 "wglCreateLayerContext";
+DescribeLayerPlane      :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL                         #foreign opengl32 "wglDescribeLayerPlane";
+GetCurrentContext       :: proc() -> HGLRC                                                                                                       #foreign opengl32 "wglGetCurrentContext";
+GetCurrentDC            :: proc() -> HDC                                                                                                         #foreign opengl32 "wglGetCurrentDC";
+GetLayerPaletteEntries  :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32                                                #foreign opengl32 "wglGetLayerPaletteEntries";
+RealizeLayerPalette     :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL                                                               #foreign opengl32 "wglRealizeLayerPalette";
+SetLayerPaletteEntries  :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32                                                #foreign opengl32 "wglSetLayerPaletteEntries";
+ShareLists              :: proc(hglrc1, hglrc2: HGLRC) -> BOOL                                                                                   #foreign opengl32 "wglShareLists";
+SwapLayerBuffers        :: proc(hdc: HDC, planes: u32) -> BOOL                                                                                   #foreign opengl32 "wglSwapLayerBuffers";
+UseFontBitmaps          :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL                                                                  #foreign opengl32 "wglUseFontBitmaps";
+UseFontOutlines         :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";

+ 6 - 17
core/sys/windows.odin

@@ -2,7 +2,6 @@
 #foreign_system_library "user32.lib"   when ODIN_OS == "windows";
 #foreign_system_library "gdi32.lib"    when ODIN_OS == "windows";
 #foreign_system_library "winmm.lib"    when ODIN_OS == "windows";
-#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
 
 HANDLE    :: rawptr;
 HWND      :: HANDLE;
@@ -168,6 +167,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) ->
 AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
 GetActiveWindow  :: proc() -> HWND #foreign user32;
 
+DestroyWindow       :: proc(wnd: HWND) -> BOOL #foreign user32;
+DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
+
 
 GetQueryPerformanceFrequency :: proc() -> i64 {
 	r: i64;
@@ -360,10 +362,6 @@ PFD_DEPTH_DONTCARE        :: 0x20000000;
 PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
 PFD_STEREO_DONTCARE       :: 0x80000000;
 
-HGLRC :: HANDLE;
-PROC  :: #type proc() #cc_c;
-wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
-
 
 PIXELFORMATDESCRIPTOR :: struct #ordered {
 	size,
@@ -396,23 +394,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
 	damage_mask: u32,
 }
 
-GetDC             :: proc(h: HANDLE) -> HDC #foreign user32;
-SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign gdi32;
+GetDC             :: proc(h: HWND) -> HDC #foreign user32;
+SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
 ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
 SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign gdi32;
 ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
 
-WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091;
-WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092;
-WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126;
-WGL_CONTEXT_CORE_PROFILE_BIT_ARB          :: 0x0001;
-WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
-
-wglCreateContext  :: proc(hdc: HDC) -> HGLRC              #foreign opengl32;
-wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
-wglGetProcAddress :: proc(c_str: ^u8) -> PROC             #foreign opengl32;
-wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL           #foreign opengl32;
 
+PROC  :: #type proc() #cc_c;
 
 
 GetKeyState      :: proc(v_key: i32) -> i16 #foreign user32;

+ 265 - 74
src/check_expr.c

@@ -183,10 +183,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 
 	// TODO(bill): Should I allow this implicit conversion at all?!
 	// rawptr <- ^T
-	if (is_type_rawptr(dst) && is_type_pointer(src)) {
-		if (dst != type) {
-			return -1;
-		}
+	if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) {
 	    return 5;
 	}
 #endif
@@ -358,7 +355,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 
 				Token name_token = name->Ident;
 
-				if (str_eq(name_token.string, str_lit(""))) {
+				if (str_eq(name_token.string, str_lit("names"))) {
 					error(name_token, "`names` is a reserved identifier for unions");
 					continue;
 				}
@@ -599,22 +596,76 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
 	GB_ASSERT(is_type_union(union_type));
 	ast_node(ut, UnionType, node);
 
-	isize field_count = 1;
-	for_array(field_index, ut->fields) {
-		AstNode *field = ut->fields.e[field_index];
-		switch (field->kind) {
-		case_ast_node(f, Field, field);
-			field_count += f->names.count;
-		case_end;
-		}
-	}
+	isize field_count = ut->fields.count+1;
+
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+
+	MapEntity entity_map = {0};
+	map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count);
 
 	Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
 
-	check_fields(c, node, ut->fields, fields, field_count, str_lit("union"));
+	isize field_index = 0;
+	fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
+
+	for_array(i, ut->fields) {
+		AstNode *field = ut->fields.e[i];
+		if (field->kind != AstNode_UnionField) {
+			continue;
+		}
+		ast_node(f, UnionField, ut->fields.e[i]);
+		Token name_token = f->name->Ident;
+
+		if (str_eq(name_token.string, str_lit("names"))) {
+			error(name_token, "`names` is a reserved identifier for unions");
+			continue;
+		}
+
+		Type *base_type = make_type_struct(c->allocator);
+		{
+			ast_node(fl, FieldList, f->list);
+			isize field_count = 0;
+			for_array(j, fl->list) {
+				ast_node(f, Field, fl->list.e[j]);
+				field_count += f->names.count;
+			}
+
+			Token token = name_token;
+			token.kind = Token_struct;
+			AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count,
+			                                        false, true, NULL);
+
+			check_open_scope(c, dummy_struct);
+			check_struct_type(c, base_type, dummy_struct);
+			check_close_scope(c);
+			base_type->Record.node = dummy_struct;
+		}
+
+		Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
+		Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
+		type->Named.type_name = e;
+		add_entity(c, c->context.scope, f->name, e);
+
+		if (str_eq(name_token.string, str_lit("_"))) {
+			error(name_token, "`_` cannot be used a union subtype");
+			continue;
+		}
+
+		HashKey key = hash_string(name_token.string);
+		if (map_entity_get(&entity_map, key) != NULL) {
+			// TODO(bill): Scope checking already checks the declaration
+			error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
+		} else {
+			map_entity_set(&entity_map, key, e);
+			fields[field_index++] = e;
+		}
+		add_entity_use(c, f->name, e);
+	}
+
+	gb_temp_arena_memory_end(tmp);
 
-	union_type->Record.fields            = fields;
-	union_type->Record.field_count       = field_count;
+	union_type->Record.fields      = fields;
+	union_type->Record.field_count = field_index;
 	union_type->Record.names = make_names_field_for_record(c, c->context.scope);
 }
 
@@ -798,7 +849,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 }
 
 
-Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
+Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) {
+	if (_params == NULL) {
+		return NULL;
+	}
+	ast_node(field_list, FieldList, _params);
+	AstNodeArray params = field_list->list;
+
 	if (params.count == 0) {
 		return NULL;
 	}
@@ -808,7 +865,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 		AstNode *field = params.e[i];
 		if (ast_node_expect(field, AstNode_Field)) {
 			ast_node(f, Field, field);
-			variable_count += f->names.count;
+			variable_count += max(f->names.count, 1);
 		}
 	}
 
@@ -877,26 +934,73 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 	return tuple;
 }
 
-Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) {
+Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
+	if (_results == NULL) {
+		return NULL;
+	}
+	ast_node(field_list, FieldList, _results);
+	AstNodeArray results = field_list->list;
+
 	if (results.count == 0) {
 		return NULL;
 	}
 	Type *tuple = make_type_tuple(c->allocator);
 
-	Entity **variables = gb_alloc_array(c->allocator, Entity *, results.count);
+	isize variable_count = 0;
+	for_array(i, results) {
+		AstNode *field = results.e[i];
+		if (ast_node_expect(field, AstNode_Field)) {
+			ast_node(f, Field, field);
+			variable_count += max(f->names.count, 1);
+		}
+	}
+
+	Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
 	isize variable_index = 0;
 	for_array(i, results) {
-		AstNode *item = results.e[i];
-		Type *type = check_type(c, item);
-		Token token = ast_node_token(item);
-		token.string = str_lit(""); // NOTE(bill): results are not named
-		// TODO(bill): Should I have named results?
-		Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
-		// NOTE(bill): No need to record
-		variables[variable_index++] = param;
+		ast_node(field, Field, results.e[i]);
+		Type *type = check_type(c, field->type);
+		if (field->names.count == 0) {
+			Token token = ast_node_token(field->type);
+			token.string = str_lit("");
+			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+			variables[variable_index++] = param;
+		} else {
+			for_array(j, field->names) {
+				Token token = ast_node_token(field->type);
+				token.string = str_lit("");
+
+				AstNode *name = field->names.e[j];
+				if (name->kind != AstNode_Ident) {
+					error_node(name, "Expected an identifer for as the field name");
+				} else {
+					token = name->Ident;
+				}
+
+				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+				variables[variable_index++] = param;
+			}
+		}
+	}
+
+	for (isize i = 0; i < variable_index; i++) {
+		String x = variables[i]->token.string;
+		if (x.len == 0 || str_eq(x, str_lit("_"))) {
+			continue;
+		}
+		for (isize j = i+1; j < variable_index; j++) {
+			String y = variables[j]->token.string;
+			if (y.len == 0 || str_eq(y, str_lit("_"))) {
+				continue;
+			}
+			if (str_eq(x, y)) {
+				error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y));
+			}
+		}
 	}
+
 	tuple->Tuple.variables = variables;
-	tuple->Tuple.variable_count = results.count;
+	tuple->Tuple.variable_count = variable_index;
 
 	return tuple;
 }
@@ -2514,6 +2618,39 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
 	return true;
 }
 
+isize entity_overload_count(Scope *s, String name) {
+	Entity *e = scope_lookup_entity(s, name);
+	if (e == NULL) {
+		return 0;
+	}
+	if (e->kind == Entity_Procedure) {
+		// NOTE(bill): Overloads are only allowed with the same scope
+		return map_entity_multi_count(&s->elements, hash_string(e->token.string));
+	}
+	return 1;
+}
+
+bool check_is_field_exported(Checker *c, Entity *field) {
+	if (field == NULL) {
+		// NOTE(bill): Just incase
+		return true;
+	}
+	if (field->kind != Entity_Variable) {
+		return true;
+	}
+	Scope *file_scope = field->scope;
+	if (file_scope == NULL) {
+		return true;
+	}
+	while (!file_scope->is_file) {
+		file_scope = file_scope->parent;
+	}
+	if (!is_entity_exported(field) && file_scope != c->context.file_scope) {
+		return false;
+	}
+	return true;
+}
+
 Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
 	ast_node(se, SelectorExpr, node);
 
@@ -2535,8 +2672,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	}
 
 	if (op_expr->kind == AstNode_Ident) {
-		String name = op_expr->Ident.string;
-		Entity *e = scope_lookup_entity(c->context.scope, name);
+		String op_name = op_expr->Ident.string;
+		Entity *e = scope_lookup_entity(c->context.scope, op_name);
 
 		add_entity_use(c, op_expr, e);
 		expr_entity = e;
@@ -2545,38 +2682,31 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 			// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
 			// It pretty much needs to be in this order and this way
 			// If you can clean this up, please do but be really careful
-
-			String sel_name = selector->Ident.string;
+			String import_name = op_name;
+			Scope *import_scope = e->ImportName.scope;
+			String entity_name = selector->Ident.string;
 
 			check_op_expr = false;
-			entity = scope_lookup_entity(e->ImportName.scope, sel_name);
+			entity = scope_lookup_entity(import_scope, entity_name);
 			bool is_declared = entity != NULL;
 			if (is_declared) {
 				if (entity->kind == Entity_Builtin) {
+					// NOTE(bill): Builtin's are in the universe scope which is part of every scopes hierarchy
+					// This means that we should just ignore the found result through it
 					is_declared = false;
-				} else if (entity->scope->is_global && !e->ImportName.scope->is_global) {
+				} else if (entity->scope->is_global && !import_scope->is_global) {
 					is_declared = false;
 				}
 			}
 			if (!is_declared) {
-				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
+				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(entity_name), LIT(import_name));
 				goto error;
 			}
 			check_entity_decl(c, entity, NULL, NULL);
 			GB_ASSERT(entity->type != NULL);
 
-			bool is_overloaded = false;
-			isize overload_count = 0;
-			HashKey key = {0};
-			if (entity->kind == Entity_Procedure) {
-				key = hash_string(entity->token.string);
-				// NOTE(bill): Overloads are only allowed with the same scope
-				Scope *s = entity->scope;
-				overload_count = map_entity_multi_count(&s->elements, key);
-				if (overload_count > 1) {
-					is_overloaded = true;
-				}
-			}
+			isize overload_count = entity_overload_count(import_scope, entity_name);
+			bool is_overloaded = overload_count > 1;
 
 			bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL;
 			bool is_not_exported = !is_entity_exported(entity);
@@ -2588,28 +2718,28 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 			if (is_not_exported) {
 				gbString sel_str = expr_to_string(selector);
-				error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
+				error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(import_name));
 				gb_string_free(sel_str);
-				// NOTE(bill): Not really an error so don't goto error
 				goto error;
 			}
 
 			if (is_overloaded) {
-				Scope *s = entity->scope;
+				HashKey key = hash_string(entity_name);
 				bool skip = false;
 
 				Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
-				map_entity_multi_get_all(&s->elements, key, procs);
-				for (isize i = 0; i < overload_count; /**/) {
+				map_entity_multi_get_all(&import_scope->elements, key, procs);
+				for (isize i = 0; i < overload_count; i++) {
 					Type *t = base_type(procs[i]->type);
 					if (t == t_invalid) {
 						continue;
 					}
 
 					// NOTE(bill): Check to see if it's imported
-					if (map_bool_get(&e->ImportName.scope->implicit, hash_pointer(procs[i]))) {
+					if (map_bool_get(&import_scope->implicit, hash_pointer(procs[i]))) {
 						gb_swap(Entity *, procs[i], procs[overload_count-1]);
 						overload_count--;
+						i--; // NOTE(bill): Counteract the post event
 						continue;
 					}
 
@@ -2623,8 +2753,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 							break;
 						}
 					}
-
-					i++;
 				}
 
 				if (overload_count > 0 && !skip) {
@@ -2648,7 +2776,13 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 
 
 	if (entity == NULL && selector->kind == AstNode_Ident) {
-		sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
+		String field_name = selector->Ident.string;
+		sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type);
+
+		if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) {
+			error_node(op_expr, "`%.*s` is an unexported field", LIT(field_name));
+			goto error;
+		}
 		entity = sel.entity;
 
 		// NOTE(bill): Add type info needed for fields like `names`
@@ -2913,7 +3047,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 	} break;
 
 	case BuiltinProc_append: {
-		// append :: proc([dynamic]Type, item: ...Type) {
+		// append :: proc([dynamic]Type, item: ...Type)
 		Type *type = operand->type;
 		type = base_type(type);
 		if (!is_type_dynamic_array(type)) {
@@ -2943,6 +3077,37 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		operand->type = t_int;
 	} break;
 
+	case BuiltinProc_delete: {
+		// delete :: proc(map[Key]Value, key: Key)
+		Type *type = operand->type;
+		if (!is_type_map(type)) {
+			gbString str = type_to_string(type);
+			error_node(operand->expr, "Expected a map, got `%s`", str);
+			gb_string_free(str);
+			return false;
+		}
+
+		Type *key = base_type(type)->Map.key;
+		Operand x = {Addressing_Invalid};
+		AstNode *key_node = ce->args.e[1];
+		Operand op = {0};
+		check_expr(c, &op, key_node);
+		if (op.mode == Addressing_Invalid) {
+			return false;
+		}
+
+		if (!check_is_assignable_to(c, &op, key)) {
+			gbString kt = type_to_string(key);
+			gbString ot = type_to_string(op.type);
+			error_node(operand->expr, "Expected a key of type `%s`, got `%s`", key, ot);
+			gb_string_free(ot);
+			gb_string_free(kt);
+			return false;
+		}
+
+		operand->mode = Addressing_NoValue;
+	} break;
+
 
 	case BuiltinProc_size_of: {
 		// size_of :: proc(Type) -> untyped int
@@ -4381,10 +4546,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 						String name = fv->field->Ident.string;
 
 						Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
-						if (sel.entity == NULL) {
+						bool is_unknown = sel.entity == NULL;
+						if (is_unknown) {
 							error_node(elem, "Unknown field `%.*s` in structure literal", LIT(name));
 							continue;
 						}
+						if (!is_unknown && !check_is_field_exported(c, sel.entity)) {
+							error_node(elem, "Cannot assign to an unexported field `%.*s` in structure literal", LIT(name));
+							continue;
+						}
+
 
 						if (sel.index.count > 1) {
 							error_node(elem, "Cannot assign to an anonymous field `%.*s` in a structure literal (at the moment)", LIT(name));
@@ -4427,6 +4598,14 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 							break;
 						}
 
+						if (!check_is_field_exported(c, field)) {
+							gbString t = type_to_string(type);
+							error_node(o->expr, "Implicit assignment to an unexported field `%.*s` in `%s` literal",
+							           LIT(field->token.string), t);
+							gb_string_free(t);
+							continue;
+						}
+
 						if (base_type(field->type) == t_any) {
 							is_constant = false;
 						}
@@ -5126,16 +5305,6 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
 
 gbString write_expr_to_string(gbString str, AstNode *node);
 
-gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
-	for_array(i, params) {
-		if (i > 0) {
-			str = gb_string_appendc(str, sep);
-		}
-		str = write_expr_to_string(str, params.e[i]);
-	}
-	return str;
-}
-
 gbString write_record_fields_to_string(gbString str, AstNodeArray params) {
 	for_array(i, params) {
 		if (i > 0) {
@@ -5301,6 +5470,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		if (f->flags&FieldFlag_using) {
 			str = gb_string_appendc(str, "using ");
 		}
+		if (f->flags&FieldFlag_immutable) {
+			str = gb_string_appendc(str, "immutable ");
+		}
+		if (f->flags&FieldFlag_no_alias) {
+			str = gb_string_appendc(str, "no_alias ");
+		}
+
 		for_array(i, f->names) {
 			AstNode *name = f->names.e[i];
 			if (i > 0) {
@@ -5308,14 +5484,24 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 			}
 			str = write_expr_to_string(str, name);
 		}
-
-		str = gb_string_appendc(str, ": ");
+		if (f->names.count > 0) {
+			str = gb_string_appendc(str, ": ");
+		}
 		if (f->flags&FieldFlag_ellipsis) {
 			str = gb_string_appendc(str, "...");
 		}
 		str = write_expr_to_string(str, f->type);
 	case_end;
 
+	case_ast_node(f, FieldList, node);
+		for_array(i, f->list) {
+			if (i > 0) {
+				str = gb_string_appendc(str, ", ");
+			}
+			str = write_expr_to_string(str, f->list.e[i]);
+		}
+	case_end;
+
 	case_ast_node(ce, CallExpr, node);
 		str = write_expr_to_string(str, ce->proc);
 		str = gb_string_appendc(str, "(");
@@ -5332,7 +5518,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 
 	case_ast_node(pt, ProcType, node);
 		str = gb_string_appendc(str, "proc(");
-		str = write_params_to_string(str, pt->params, ", ");
+		str = write_expr_to_string(str, pt->params);
 		str = gb_string_appendc(str, ")");
 	case_end;
 
@@ -5366,7 +5552,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 			str = gb_string_appendc(str, " ");
 		}
 		str = gb_string_appendc(str, "{");
-		str = write_params_to_string(str, et->fields, ", ");
+		for_array(i, et->fields) {
+			if (i > 0) {
+				str = gb_string_appendc(str, ", ");
+			}
+			str = write_expr_to_string(str, et->fields.e[i]);
+		}
 		str = gb_string_appendc(str, "}");
 	case_end;
 

+ 9 - 0
src/checker.c

@@ -30,6 +30,7 @@ typedef enum BuiltinProcId {
 	BuiltinProc_reserve,
 	BuiltinProc_clear,
 	BuiltinProc_append,
+	BuiltinProc_delete,
 
 	BuiltinProc_size_of,
 	BuiltinProc_size_of_val,
@@ -73,6 +74,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{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("size_of_val"),      1, false, Expr_Expr},
@@ -259,6 +261,7 @@ typedef struct DelayedDecl {
 } DelayedDecl;
 
 typedef struct CheckerContext {
+	Scope *    file_scope;
 	Scope *    scope;
 	DeclInfo * decl;
 	u32        stmt_state_flags;
@@ -1016,6 +1019,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
 		c->curr_ast_file = file;
 		c->context.decl  = file->decl_info;
 		c->context.scope = file->scope;
+		c->context.file_scope = file->scope;
 	}
 }
 
@@ -1242,6 +1246,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
 			ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
 			switch (kind) {
 			case ProcOverload_Identical:
+				error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
+				is_invalid = true;
+				break;
 			case ProcOverload_CallingConvention:
 				error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
 				is_invalid = true;
@@ -1746,6 +1753,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 				Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
 				                                    id->fullpath, id->import_name.string,
 				                                    scope);
+
+
 				add_entity(c, parent_scope, NULL, e);
 			}
 		}

+ 1 - 0
src/entity.c

@@ -113,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) {
 }
 
 bool is_entity_exported(Entity *e) {
+	// TODO(bill): Determine the actual exportation rules for imports of entities
 	GB_ASSERT(e != NULL);
 	if (!is_entity_kind_exported(e->kind)) {
 		return false;

+ 1 - 1
src/gb/gb.h

@@ -705,7 +705,7 @@ extern "C++" {
 #endif
 
 #ifndef gb_is_between
-#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
+#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
 #endif
 
 #ifndef gb_abs

+ 249 - 155
src/ir.c

@@ -15,13 +15,14 @@ typedef Array(irValue *) irValueArray;
 #define MAP_NAME MapIrDebugInfo
 #include "map.c"
 
+
 typedef struct irModule {
 	CheckerInfo * info;
 	gbArena       arena;
 	gbArena       tmp_arena;
 	gbAllocator   allocator;
 	gbAllocator   tmp_allocator;
-	bool generate_debug_info;
+	// bool generate_debug_info;
 
 	u32 stmt_state_flags;
 
@@ -29,20 +30,20 @@ typedef struct irModule {
 	String layout;
 	// String triple;
 
-	MapEntity       min_dep_map; // Key: Entity *
-	MapIrValue      values;      // Key: Entity *
-	MapIrValue      members;     // Key: String
-	MapString       type_names;  // Key: Type *
-	MapIrDebugInfo  debug_info;  // Key: Unique pointer
-	i32             global_string_index;
-	i32             global_array_index; // For ConstantSlice
+	MapEntity             min_dep_map; // Key: Entity *
+	MapIrValue            values;      // Key: Entity *
+	MapIrValue            members;     // Key: String
+	MapString             type_names;  // Key: Type *
+	MapIrDebugInfo        debug_info;  // Key: Unique pointer
+	i32                   global_string_index;
+	i32                   global_array_index; // For ConstantSlice
 
-	Entity *        entry_point_entity;
+	Entity *              entry_point_entity;
 
-	Array(irProcedure *) procs;             // NOTE(bill): All procedures with bodies
-	irValueArray         procs_to_generate; // NOTE(bill): Procedures to generate
+	Array(irProcedure *)  procs;             // NOTE(bill): All procedures with bodies
+	irValueArray          procs_to_generate; // NOTE(bill): Procedures to generate
 
-	Array(String) foreign_library_paths; // Only the ones that were used
+	Array(String)         foreign_library_paths; // Only the ones that were used
 } irModule;
 
 // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory)
@@ -121,6 +122,7 @@ struct irProcedure {
 	irTargetList *       target_list;
 	irValueArray         referrers;
 
+
 	i32                  local_count;
 	i32                  instr_count;
 	i32                  block_count;
@@ -134,90 +136,99 @@ struct irProcedure {
 
 
 #define IR_INSTR_KINDS \
-	IR_INSTR_KIND(Comment, struct { String text; }) \
-	IR_INSTR_KIND(Local,   struct { \
-		Entity *      entity; \
-		Type *        type; \
-		bool          zero_initialized; \
-		irValueArray referrers; \
-	}) \
-	IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \
-	IR_INSTR_KIND(Store,    struct { irValue *address, *value; }) \
+	IR_INSTR_KIND(Comment, struct { String text; })                   \
+	IR_INSTR_KIND(Local,   struct {                                   \
+		Entity *      entity;                                         \
+		Type *        type;                                           \
+		bool          zero_initialized;                               \
+		irValueArray referrers;                                       \
+	})                                                                \
+	IR_INSTR_KIND(ZeroInit, struct { irValue *address; })             \
+	IR_INSTR_KIND(Store,    struct { irValue *address, *value; })     \
 	IR_INSTR_KIND(Load,     struct { Type *type; irValue *address; }) \
-	IR_INSTR_KIND(PtrOffset, struct { \
-		irValue *address; \
-		irValue *offset; \
-	}) \
-	IR_INSTR_KIND(ArrayElementPtr, struct { \
-		irValue *address; \
-		Type *   result_type; \
-		irValue *elem_index; \
-	}) \
-	IR_INSTR_KIND(StructElementPtr, struct {  \
-		irValue *address; \
-		Type *    result_type; \
-		i32       elem_index; \
-	}) \
-	IR_INSTR_KIND(StructExtractValue, struct { \
-		irValue *address; \
-		Type *    result_type; \
-		i32       index; \
-	}) \
-	IR_INSTR_KIND(UnionTagPtr, struct { \
-		irValue *address; \
-		Type     *type; /* ^int */  \
-	}) \
-	IR_INSTR_KIND(UnionTagValue, struct { \
-		irValue *address; \
-		Type     *type; /* int */ \
-	}) \
-	IR_INSTR_KIND(Conv, struct { \
-		irConvKind kind; \
-		irValue *value; \
-		Type *from, *to; \
-	}) \
-	IR_INSTR_KIND(Jump, struct { irBlock *block; }) \
-	IR_INSTR_KIND(If, struct { \
-		irValue *cond; \
-		irBlock *true_block; \
-		irBlock *false_block; \
-	}) \
-	IR_INSTR_KIND(Return, struct { irValue *value; }) \
-	IR_INSTR_KIND(Select, struct { \
-		irValue *cond; \
-		irValue *true_value; \
-		irValue *false_value; \
-	}) \
-	IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \
-	IR_INSTR_KIND(Unreachable, i32) \
-	IR_INSTR_KIND(UnaryOp, struct { \
-		Type *    type; \
-		TokenKind op; \
-		irValue *expr; \
-	}) \
-	IR_INSTR_KIND(BinaryOp, struct { \
-		Type *    type; \
-		TokenKind op; \
-		irValue *left, *right; \
+	IR_INSTR_KIND(PtrOffset, struct {                                 \
+		irValue *address;                                             \
+		irValue *offset;                                              \
+	})                                                                \
+	IR_INSTR_KIND(ArrayElementPtr, struct {                           \
+		irValue *address;                                             \
+		Type *   result_type;                                         \
+		irValue *elem_index;                                          \
+	})                                                                \
+	IR_INSTR_KIND(StructElementPtr, struct {                          \
+		irValue *address;                                             \
+		Type *    result_type;                                        \
+		i32       elem_index;                                         \
+	})                                                                \
+	IR_INSTR_KIND(StructExtractValue, struct {                        \
+		irValue *address;                                             \
+		Type *    result_type;                                        \
+		i32       index;                                              \
+	})                                                                \
+	IR_INSTR_KIND(UnionTagPtr, struct {                               \
+		irValue *address;                                             \
+		Type     *type; /* ^int */                                    \
+	})                                                                \
+	IR_INSTR_KIND(UnionTagValue, struct {                             \
+		irValue *address;                                             \
+		Type     *type; /* int */                                     \
+	})                                                                \
+	IR_INSTR_KIND(Conv, struct {                                      \
+		irConvKind kind;                                              \
+		irValue *value;                                               \
+		Type *from, *to;                                              \
+	})                                                                \
+	IR_INSTR_KIND(Jump, struct { irBlock *block; })                   \
+	IR_INSTR_KIND(If, struct {                                        \
+		irValue *cond;                                                \
+		irBlock *true_block;                                          \
+		irBlock *false_block;                                         \
+	})                                                                \
+	IR_INSTR_KIND(Return, struct { irValue *value; })                 \
+	IR_INSTR_KIND(Select, struct {                                    \
+		irValue *cond;                                                \
+		irValue *true_value;                                          \
+		irValue *false_value;                                         \
+	})                                                                \
+	IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; })    \
+	IR_INSTR_KIND(Unreachable, i32)                                   \
+	IR_INSTR_KIND(UnaryOp, struct {                                   \
+		Type *    type;                                               \
+		TokenKind op;                                                 \
+		irValue * expr;                                               \
+	})                                                                \
+	IR_INSTR_KIND(BinaryOp, struct {                                  \
+		Type *    type;                                               \
+		TokenKind op;                                                 \
+		irValue * left, *right;                                       \
+	})                                                                \
+	IR_INSTR_KIND(Call, struct {                                      \
+		Type *    type; /* return type */                             \
+		irValue * value;                                              \
+		irValue **args;                                               \
+		isize     arg_count;                                          \
+	})                                                                \
+	IR_INSTR_KIND(StartupRuntime, i32)                                \
+	IR_INSTR_KIND(BoundsCheck, struct {                               \
+		TokenPos pos;                                                 \
+		irValue *index;                                               \
+		irValue *len;                                                 \
+	})                                                                \
+	IR_INSTR_KIND(SliceBoundsCheck, struct {                          \
+		TokenPos pos;                                                 \
+		irValue *low;                                                 \
+		irValue *high;                                                \
+		bool     is_substring;                                        \
+	})                                                                \
+	IR_INSTR_KIND(DebugDeclare, struct { \
+		irDebugInfo *debug_info; \
+		AstNode *    expr; \
+		Entity *     entity; \
+		bool         is_addr; \
+		irValue *    value; \
 	}) \
-	IR_INSTR_KIND(Call, struct { \
-		Type *    type; /* return type */  \
-		irValue *value; \
-		irValue **args; \
-		isize      arg_count; \
-	}) \
-	IR_INSTR_KIND(StartupRuntime, i32) \
-	IR_INSTR_KIND(BoundsCheck, struct { \
-		TokenPos  pos; \
-		irValue *index; \
-		irValue *len; \
-	}) \
-	IR_INSTR_KIND(SliceBoundsCheck, struct { \
-		TokenPos  pos; \
-		irValue *low; \
-		irValue *high; \
-		bool      is_substring; \
-	})
+
+
 
 #define IR_CONV_KINDS \
 	IR_CONV_KIND(trunc) \
@@ -394,7 +405,6 @@ irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *m
 	return v;
 }
 
-
 typedef enum irDebugEncoding {
 	irDebugBasicEncoding_Invalid       = 0,
 
@@ -519,14 +529,19 @@ struct irDebugInfo {
 	};
 };
 
+
+
 typedef struct irGen {
 	irModule module;
-	gbFile    output_file;
-	bool       opt_called;
+	gbFile   output_file;
+	bool     opt_called;
 } irGen;
 
 
 
+
+
+
 Type *ir_type(irValue *value);
 Type *ir_instr_type(irInstr *instr) {
 	switch (instr->kind) {
@@ -948,6 +963,16 @@ irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue
 	v->Instr.SliceBoundsCheck.is_substring = is_substring;
 	return v;
 }
+irValue *ir_make_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
+	irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare);
+	v->Instr.DebugDeclare.debug_info = debug_info;
+	v->Instr.DebugDeclare.expr       = expr;
+	v->Instr.DebugDeclare.entity     = entity;
+	v->Instr.DebugDeclare.is_addr    = is_addr;
+	v->Instr.DebugDeclare.value      = value;
+	return v;
+
+}
 
 
 
@@ -967,6 +992,23 @@ irValue *ir_make_value_constant_slice(gbAllocator a, Type *type, irValue *backin
 	return v;
 }
 
+
+
+irValue *ir_emit(irProcedure *proc, irValue *instr) {
+	GB_ASSERT(instr->kind == irValue_Instr);
+	irBlock *b = proc->curr_block;
+	instr->Instr.parent = b;
+	if (b != NULL) {
+		irInstr *i = ir_get_last_instr(b);
+		if (!ir_is_instr_terminating(i)) {
+			array_add(&b->instrs, instr);
+		}
+	}
+	return instr;
+}
+
+
+
 irValue *ir_make_const_int(gbAllocator a, i64 i) {
 	return ir_make_value_constant(a, t_int, make_exact_value_integer(i));
 }
@@ -1060,13 +1102,6 @@ void ir_add_block_to_proc(irProcedure *proc, irBlock *b) {
 	b->index = proc->block_count++;
 }
 
-
-// irBlock *ir_add_block(irProcedure *proc, AstNode *node, char *label) {
-// 	irBlock *block = ir_new_block(proc, node, label);
-// 	ir_add_block_to_proc(proc, block);
-// 	return block;
-// }
-
 void ir_start_block(irProcedure *proc, irBlock *block) {
 	proc->curr_block = block;
 	if (block != NULL) {
@@ -1166,7 +1201,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
 
 
 
-irValue *ir_add_local(irProcedure *proc, Entity *e) {
+irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) {
 	irBlock *b = proc->decl_block; // all variables must be in the first block
 	irValue *instr = ir_make_instr_local(proc, e, true);
 	instr->Instr.parent = b;
@@ -1178,6 +1213,11 @@ irValue *ir_add_local(irProcedure *proc, Entity *e) {
 		ir_emit_zero_init(proc, instr);
 	// }
 
+	if (expr != NULL) {
+		irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
+		ir_emit(proc, ir_make_instr_debug_declare(proc, di, expr, e, true, instr));
+	}
+
 	return instr;
 }
 
@@ -1186,7 +1226,7 @@ irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero
 	if (found) {
 		Entity *e = *found;
 		ir_emit_comment(proc, e->token.string);
-		return ir_add_local(proc, e);
+		return ir_add_local(proc, e, name);
 	}
 	return NULL;
 }
@@ -1202,14 +1242,14 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) {
 	                                 scope,
 	                                 empty_token,
 	                                 type, false);
-	return ir_add_local(proc, e);
+	return ir_add_local(proc, e, NULL);
 }
 
 
-irValue *ir_add_param(irProcedure *proc, Entity *e) {
+irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) {
 	irValue *v = ir_make_value_param(proc->module->allocator, proc, e);
 #if 1
-	irValue *l = ir_add_local(proc, e);
+	irValue *l = ir_add_local(proc, e, expr);
 	ir_emit_store(proc, l, v);
 
 #else
@@ -1227,9 +1267,9 @@ irValue *ir_add_param(irProcedure *proc, Entity *e) {
 ////////////////////////////////////////////////////////////////
 
 irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
-	if (!proc->module->generate_debug_info) {
-		return NULL;
-	}
+	// if (!proc->module->generate_debug_info) {
+	// 	return NULL;
+	// }
 
 	GB_ASSERT(file != NULL);
 	irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_File);
@@ -1259,9 +1299,9 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
 
 
 irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) {
-	if (!proc->module->generate_debug_info) {
-		return NULL;
-	}
+	// if (!proc->module->generate_debug_info) {
+	// 	return NULL;
+	// }
 
 	GB_ASSERT(entity != NULL);
 	irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_Proc);
@@ -1281,18 +1321,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na
 ////////////////////////////////////////////////////////////////
 
 
-irValue *ir_emit(irProcedure *proc, irValue *instr) {
-	GB_ASSERT(instr->kind == irValue_Instr);
-	irBlock *b = proc->curr_block;
-	instr->Instr.parent = b;
-	if (b != NULL) {
-		irInstr *i = ir_get_last_instr(b);
-		if (!ir_is_instr_terminating(i)) {
-			array_add(&b->instrs, instr);
-		}
-	}
-	return instr;
-}
+
 irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
 #if 1
 	// NOTE(bill): Sanity check
@@ -3215,7 +3244,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 						args[3] = capacity;
 						return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
 					} else if (is_type_dynamic_map(type)) {
-						irValue **args = gb_alloc_array(a, irValue *, 4);
+						irValue **args = gb_alloc_array(a, irValue *, 2);
 						args[0] = ir_gen_map_header(proc, ptr, type);
 						args[1] = capacity;
 						return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
@@ -3331,6 +3360,23 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
 				} break;
 
+				case BuiltinProc_delete: {
+					ir_emit_comment(proc, str_lit("delete"));
+					irValue *map = ir_build_expr(proc, ce->args.e[0]);
+					irValue *key = ir_build_expr(proc, ce->args.e[1]);
+					Type *map_type = ir_type(map);
+					GB_ASSERT(is_type_dynamic_map(map_type));
+					Type *key_type = base_type(map_type)->Map.key;
+
+					irValue *addr = ir_address_from_load_or_generate_local(proc, map);
+
+					gbAllocator a = proc->module->allocator;
+					irValue **args = gb_alloc_array(a, irValue *, 2);
+					args[0] = ir_gen_map_header(proc, addr, map_type);
+					args[1] = ir_gen_map_key(proc, key, key_type);
+					return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2);
+				} break;
+
 
 				case BuiltinProc_assert: {
 					ir_emit_comment(proc, str_lit("assert"));
@@ -5357,7 +5403,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 				irValue *tag_var = NULL;
 				if (tag_var_entity != NULL) {
-					tag_var = ir_add_local(proc, tag_var_entity);
+					tag_var = ir_add_local(proc, tag_var_entity, NULL);
 				} else {
 					tag_var = ir_add_local_generated(proc, tag_var_type);
 				}
@@ -5385,7 +5431,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 				irValue *tag_var = NULL;
 				if (tag_var_entity != NULL) {
-					tag_var = ir_add_local(proc, tag_var_entity);
+					tag_var = ir_add_local(proc, tag_var_entity, NULL);
 				} else {
 					tag_var = ir_add_local_generated(proc, tag_var_type);
 				}
@@ -5558,12 +5604,26 @@ void ir_begin_procedure_body(irProcedure *proc) {
 	ir_start_block(proc, proc->entry_block);
 
 	if (proc->type->Proc.params != NULL) {
+		ast_node(pt, ProcType, proc->type_expr);
+		isize param_index = 0;
+		isize q_index = 0;
+
 		TypeTuple *params = &proc->type->Proc.params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
+			ast_node(fl, FieldList, pt->params);
+			GB_ASSERT(fl->list.count > 0);
+			GB_ASSERT(fl->list.e[0]->kind == AstNode_Field);
+			if (q_index == fl->list.e[param_index]->Field.names.count) {
+				q_index = 0;
+				param_index++;
+			}
+			ast_node(field, Field, fl->list.e[param_index]);
+			AstNode *name = field->names.e[q_index++];
+
 			Entity *e = params->variables[i];
 			if (!str_eq(e->token.string, str_lit("")) &&
 			    !str_eq(e->token.string, str_lit("_"))) {
-				irValue *param = ir_add_param(proc, e);
+				irValue *param = ir_add_param(proc, e, name);
 				array_add(&proc->params, param);
 			}
 		}
@@ -5790,7 +5850,7 @@ bool ir_gen_init(irGen *s, Checker *c) {
 	}
 
 	ir_init_module(&s->module, c);
-	s->module.generate_debug_info = false;
+	// s->module.generate_debug_info = false;
 
 	// TODO(bill): generate appropriate output name
 	int pos = cast(int)string_extension_position(c->parser->init_fullpath);
@@ -6025,7 +6085,9 @@ void ir_gen_tree(irGen *s) {
 				name = pd->link_name;
 			}
 
-			irValue *p = ir_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
+			AstNode *type_expr = decl->proc_lit->ProcLit.type;
+
+			irValue *p = ir_make_value_procedure(a, m, e, e->type, type_expr, body, name);
 			p->Proc.tags = pd->tags;
 
 			ir_module_add_value(m, e, p);
@@ -6067,7 +6129,6 @@ void ir_gen_tree(irGen *s) {
 	for_array(i, m->debug_info.entries) {
 		MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i];
 		irDebugInfo *di = entry->value;
-		di->id = i;
 		if (di->kind == irDebugInfo_Proc) {
 			array_add(&all_procs->AllProcs.procs, di);
 		}
@@ -6406,10 +6467,11 @@ void ir_gen_tree(irGen *s) {
 				case Type_Tuple: {
 					ir_emit_comment(proc, str_lit("Type_Info_Tuple"));
 					tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr);
+					irValue *record = ir_emit_struct_ep(proc, tag, 0);
 
 					{
 						irValue *align = ir_make_const_int(a, type_align_of(a, t));
-						ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
 					}
 
 					irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6429,14 +6491,15 @@ void ir_gen_tree(irGen *s) {
 						}
 					}
 
-					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-					ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+					ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
 				} break;
 				case Type_Record: {
 					switch (t->Record.kind) {
 					case TypeRecord_Struct: {
 						ir_emit_comment(proc, str_lit("Type_Info_Struct"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
 
 						{
 							irValue *size         = ir_make_const_int(a,  type_size_of(a, t));
@@ -6444,11 +6507,11 @@ void ir_gen_tree(irGen *s) {
 							irValue *packed       = ir_make_const_bool(a, t->Record.struct_is_packed);
 							irValue *ordered      = ir_make_const_bool(a, t->Record.struct_is_ordered);
 							irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), packed);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), ordered);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), custom_align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), packed);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), ordered);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align);
 						}
 
 						irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6475,28 +6538,52 @@ void ir_gen_tree(irGen *s) {
 							ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
 						}
 
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
 					} break;
-					case TypeRecord_Union:
+					case TypeRecord_Union: {
 						ir_emit_comment(proc, str_lit("Type_Info_Union"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
 						{
 							irValue *size    = ir_make_const_int(a, type_size_of(a, t));
 							irValue *align   = ir_make_const_int(a, type_align_of(a, t));
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3),  size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4),  align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3),  size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4),  align);
 						}
-						break;
+
+						irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
+						irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index);
+
+						for (isize source_index = 1; source_index < t->Record.field_count; source_index++) {
+							// TODO(bill): Order fields in source order not layout order
+							Entity *f = t->Record.fields[source_index];
+							irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type);
+							irValue *index     = ir_make_const_int(a, source_index);
+							irValue *type_info = ir_emit_ptr_offset(proc, memory_types,   index);
+
+							ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
+							if (f->token.string.len > 0) {
+								irValue *name = ir_emit_ptr_offset(proc, memory_names,   index);
+								ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+							}
+						}
+
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
+
+					} break;
 					case TypeRecord_RawUnion: {
 						ir_emit_comment(proc, str_lit("Type_Info_RawUnion"));
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr);
+						irValue *record = ir_emit_struct_ep(proc, tag, 0);
+
 						{
 							irValue *size    = ir_make_const_int(a, type_size_of(a, t));
 							irValue *align   = ir_make_const_int(a, type_align_of(a, t));
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3),  size);
-							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4),  align);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3),  size);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4),  align);
 						}
 
 						irValue *memory_types   = ir_type_info_member_offset(proc, type_info_member_types,   t->Record.field_count, &type_info_member_types_index);
@@ -6516,9 +6603,9 @@ void ir_gen_tree(irGen *s) {
 							}
 						}
 
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names,   ir_make_const_int(a, t->Record.field_count));
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
 					} break;
 					case TypeRecord_Enum:
 						ir_emit_comment(proc, str_lit("Type_Info_Enum"));
@@ -6607,7 +6694,7 @@ void ir_gen_tree(irGen *s) {
 							break;
 						}
 					}
-					GB_ASSERT(found);
+					GB_ASSERT_MSG(found, "%s", type_to_string(tag_type));
 				}
 			}
 		}
@@ -6619,6 +6706,13 @@ void ir_gen_tree(irGen *s) {
 		ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent);
 	}
 
+	// Number debug info
+	for_array(i, m->debug_info.entries) {
+		MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i];
+		irDebugInfo *di = entry->value;
+		di->id = i;
+	}
+
 
 	// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
 }

+ 45 - 9
src/ir_print.c

@@ -1254,6 +1254,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		ir_fprintf(f, ")\n");
 	} break;
 
+	case irInstr_DebugDeclare: {
+		/* irInstrDebugDeclare *dd = &instr->DebugDeclare;
+		Type *vt = ir_type(dd->value);
+		irDebugInfo *di = dd->debug_info;
+		Entity *e = dd->entity;
+		String name = e->token.string;
+		TokenPos pos = e->token.pos;
+		// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
+		ir_fprintf(f, "call void @llvm.dbg.declare(");
+		ir_fprintf(f, "metadata ");
+		ir_print_type(f, m, vt);
+		ir_fprintf(f, " ");
+		ir_print_value(f, m, dd->value, vt);
+		ir_fprintf(f, ", metadata !DILocalVariable(name: \"");
+		ir_print_escape_string(f, name, false);
+		ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line);
+		ir_fprintf(f, ", metadata !DIExpression()");
+		ir_fprintf(f, ")");
+		ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
+
+		ir_fprintf(f, "\n"); */
+	} break;
+
 
 	default: {
 		GB_PANIC("<unknown instr> %d\n", instr->kind);
@@ -1326,11 +1349,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 	}
 
 
-	if (proc->module->generate_debug_info && proc->entity != NULL) {
+	if (proc->entity != NULL) {
 		if (proc->body != NULL) {
-			irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
-			GB_ASSERT(di->kind == irDebugInfo_Proc);
-			ir_fprintf(f, "!dbg !%d ", di->id);
+			irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
+			if (di_ != NULL) {
+				irDebugInfo *di = *di_;
+				GB_ASSERT(di->kind == irDebugInfo_Proc);
+				// ir_fprintf(f, "!dbg !%d ", di->id);
+			}
 		}
 	}
 
@@ -1396,6 +1422,8 @@ void print_llvm_ir(irGen *ir) {
 	ir_print_type(f, m, t_rawptr);
 	ir_fprintf(f, "} ; Basic_any\n");
 
+	ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
+
 
 	for_array(member_index, m->members.entries) {
 		MapIrValueEntry *entry = &m->members.entries.e[member_index];
@@ -1482,9 +1510,18 @@ void print_llvm_ir(irGen *ir) {
 
 
 #if 0
-	if (m->generate_debug_info) {
+	// if (m->generate_debug_info) {
+	{
 		ir_fprintf(f, "\n");
+
+		i32 diec = m->debug_info.entries.count;
+
 		ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
+		ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
+		ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
+		ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
+		ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
+		ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
 
 		for_array(di_index, m->debug_info.entries) {
 			MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
@@ -1493,19 +1530,18 @@ void print_llvm_ir(irGen *ir) {
 
 			switch (di->kind) {
 			case irDebugInfo_CompileUnit: {
-				auto *cu = &di->CompileUnit;
-				irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
+				irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
 				ir_fprintf(f,
 				            "distinct !DICompileUnit("
 				            "language: DW_LANG_Go, " // Is this good enough?
 				            "file: !%d, "
-				            "producer: \"%.*s\", "
+				            "producer: \"clang version 3.9.0 (branches/release_39)\", "
 				            "flags: \"\", "
 				            "runtimeVersion: 0, "
 				            "isOptimized: false, "
 				            "emissionKind: FullDebug"
 				            ")",
-				            file->id, LIT(cu->producer));
+				            file->id);
 
 			} break;
 			case irDebugInfo_File:

+ 5 - 4
src/main.c

@@ -2,6 +2,7 @@
 extern "C" {
 #endif
 
+
 #include "common.c"
 #include "timings.c"
 #include "build_settings.c"
@@ -223,10 +224,10 @@ int main(int argc, char **argv) {
 		return 1;
 	}
 
-	ssa_generate(&checker.info, &build_context);
-#endif
-#if 1
-
+	if (!ssa_generate(&checker.info)) {
+		return 1;
+	}
+#else
 	irGen ir_gen = {0};
 	if (!ir_gen_init(&ir_gen, &checker)) {
 		return 1;

+ 135 - 140
src/parser.c

@@ -302,16 +302,24 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 		AstNode *    type;     \
 		u32          flags;    \
 	}) \
+	AST_NODE_KIND(FieldList, "field list", struct { \
+		Token token; \
+		AstNodeArray list; \
+	}) \
+	AST_NODE_KIND(UnionField, "union field", struct { \
+		AstNode *name; \
+		AstNode *list; \
+	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
 	AST_NODE_KIND(HelperType, "type", struct { \
 		Token token; \
 		AstNode *type; \
 	}) \
 	AST_NODE_KIND(ProcType, "procedure type", struct { \
-		Token token;          \
-		AstNodeArray params;  \
-		AstNodeArray results; \
-		u64          tags;    \
+		Token    token;   \
+		AstNode *params;  \
+		AstNode *results; \
+		u64      tags;    \
 		ProcCallingConvention calling_convention; \
 	}) \
 	AST_NODE_KIND(PointerType, "pointer type", struct { \
@@ -478,11 +486,16 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_ImportDecl:     return node->ImportDecl.token;
 	case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
 
+
 	case AstNode_Field:
 		if (node->Field.names.count > 0) {
 			return ast_node_token(node->Field.names.e[0]);
 		}
 		return ast_node_token(node->Field.type);
+	case AstNode_FieldList:
+		return node->FieldList.token;
+	case AstNode_UnionField:
+		return ast_node_token(node->UnionField.name);
 
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
@@ -952,6 +965,19 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
 	return result;
 }
 
+AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
+	AstNode *result = make_ast_node(f, AstNode_FieldList);
+	result->FieldList.token = token;
+	result->FieldList.list  = list;
+	return result;
+}
+AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
+	AstNode *result = make_ast_node(f, AstNode_UnionField);
+	result->UnionField.name = name;
+	result->UnionField.list = list;
+	return result;
+}
+
 
 AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
 	AstNode *result = make_ast_node(f, AstNode_HelperType);
@@ -961,7 +987,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
 }
 
 
-AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
+AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) {
 	AstNode *result = make_ast_node(f, AstNode_ProcType);
 	result->ProcType.token = token;
 	result->ProcType.params = params;
@@ -1002,7 +1028,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
 }
 
 AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count,
-                          bool is_packed, bool is_ordered, AstNode *align) {
+                         bool is_packed, bool is_ordered, AstNode *align) {
 	AstNode *result = make_ast_node(f, AstNode_StructType);
 	result->StructType.token       = token;
 	result->StructType.fields      = fields;
@@ -1308,7 +1334,6 @@ AstNode *    parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore
 AstNodeArray parse_stmt_list(AstFile *f);
 AstNode *    parse_stmt(AstFile *f);
 AstNode *    parse_body(AstFile *f);
-void         parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
 
 
 
@@ -1949,19 +1974,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			}
 			break;
 
-		case Token_Question:
-			if (!lhs && operand != NULL && f->expr_level >= 0) {
-				AstNode *cond = operand;
-				Token token_q = expect_token(f, Token_Question);
-				AstNode *x = parse_expr(f, false);
-				Token token_c = expect_token(f, Token_Colon);
-				AstNode *y = parse_expr(f, false);
-				operand = ast_ternary_expr(f, cond, x, y);
-			} else {
-				loop = false;
-			}
-			break;
-
 		default:
 			loop = false;
 			break;
@@ -2016,22 +2028,24 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
 // NOTE(bill): result == priority
 i32 token_precedence(TokenKind t) {
 	switch (t) {
-	case Token_CmpOr:
+	case Token_Question:
 		return 1;
-	case Token_CmpAnd:
+	case Token_CmpOr:
 		return 2;
+	case Token_CmpAnd:
+		return 3;
 	case Token_CmpEq:
 	case Token_NotEq:
 	case Token_Lt:
 	case Token_Gt:
 	case Token_LtEq:
 	case Token_GtEq:
-		return 3;
+		return 4;
 	case Token_Add:
 	case Token_Sub:
 	case Token_Or:
 	case Token_Xor:
-		return 4;
+		return 5;
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Mod:
@@ -2039,51 +2053,42 @@ i32 token_precedence(TokenKind t) {
 	case Token_AndNot:
 	case Token_Shl:
 	case Token_Shr:
-		return 5;
-	// case Token_as:
-	// case Token_transmute:
-	// case Token_down_cast:
-	// case Token_union_cast:
-		// return 6;
+		return 6;
 	}
 	return 0;
 }
 
 AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
-	AstNode *expression = parse_unary_expr(f, lhs);
+	AstNode *expr = parse_unary_expr(f, lhs);
 	for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) {
 		for (;;) {
-			AstNode *right;
 			Token op = f->curr_token;
 			i32 op_prec = token_precedence(op.kind);
 			if (op_prec != prec) {
+				// NOTE(bill): This will also catch operators that are not valid "binary" operators
 				break;
 			}
 			expect_operator(f); // NOTE(bill): error checks too
-			if (lhs) {
-				// TODO(bill): error checking
-				lhs = false;
-			}
 
-			switch (op.kind) {
-			/* case Token_as:
-			case Token_transmute:
-			case Token_down_cast:
-			case Token_union_cast:
-				right = parse_type(f);
-				break; */
-
-			default:
-				right = parse_binary_expr(f, false, prec+1);
+			if (op.kind == Token_Question) {
+				AstNode *cond = expr;
+				// Token_Question
+				AstNode *x = parse_expr(f, lhs);
+				Token token_c = expect_token(f, Token_Colon);
+				AstNode *y = parse_expr(f, lhs);
+				expr = ast_ternary_expr(f, cond, x, y);
+			} else {
+				AstNode *right = parse_binary_expr(f, false, prec+1);
 				if (!right) {
-					syntax_error(op, "Expected expression on the right hand side of the binary operator");
+					syntax_error(op, "Expected expression on the right-hand side of the binary operator");
 				}
-				break;
+				expr = ast_binary_expr(f, op, expr, right);
 			}
-			expression = ast_binary_expr(f, op, expression, right);
+
+			lhs = false;
 		}
 	}
-	return expression;
+	return expr;
 }
 
 AstNode *parse_expr(AstFile *f, bool lhs) {
@@ -2278,15 +2283,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
 	return parse_body(f);
 }
 
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
+
+
+AstNode *parse_results(AstFile *f) {
+	if (!allow_token(f, Token_ArrowRight)) {
+		return NULL;
+	}
 
+	if (f->curr_token.kind != Token_OpenParen) {
+		Token begin_token = f->curr_token;
+		AstNodeArray empty_names = {0};
+		AstNodeArray list = make_ast_node_array(f);
+		AstNode *type = parse_type(f);
+		array_add(&list, ast_field(f, empty_names, type, 0));
+		return ast_field_list(f, begin_token, list);
+	}
 
+	AstNode *list = NULL;
+	expect_token(f, Token_OpenParen);
+	list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
+	expect_token_after(f, Token_CloseParen, "parameter list");
+	return list;
+}
 
 AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
-	AstNodeArray params = {0};
-	AstNodeArray results = {0};
+	AstNode *params = {0};
+	AstNode *results = {0};
 
 	Token proc_token = expect_token(f, Token_proc);
-	parse_proc_signature(f, &params, &results);
+	expect_token(f, Token_OpenParen);
+	params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
+	expect_token_after(f, Token_CloseParen, "parameter list");
+	results = parse_results(f);
 
 	u64 tags = 0;
 	String foreign_name = {0};
@@ -2424,8 +2453,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
 	return idents;
 }
 
-AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
-                              TokenKind separator, TokenKind follow) {
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
+	Token start_token = f->curr_token;
+
 	AstNodeArray params = make_ast_node_array(f);
 	AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
 	isize total_name_count = 0;
@@ -2485,7 +2515,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
 		}
 
 		if (name_count_) *name_count_ = total_name_count;
-		return params;
+		return ast_field_list(f, start_token, params);
 	}
 
 	for_array(i, list) {
@@ -2503,11 +2533,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
 	}
 
 	if (name_count_) *name_count_ = total_name_count;
-	return params;
+	return ast_field_list(f, start_token, params);
 }
 
 
-AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
+AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
 	return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
 }
 
@@ -2637,29 +2667,59 @@ AstNode *parse_type_or_ident(AstFile *f) {
 
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
+		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
 		Token close = expect_token(f, Token_CloseBrace);
 
+		AstNodeArray decls = {0};
+		if (fields != NULL) {
+			GB_ASSERT(fields->kind == AstNode_FieldList);
+			decls = fields->FieldList.list;
+		}
+
 		return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
 	} break;
 
 	case Token_union: {
 		Token token = expect_token(f, Token_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
-		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
+		AstNodeArray variants = make_ast_node_array(f);
+
+		while (f->curr_token.kind != Token_CloseBrace &&
+		       f->curr_token.kind != Token_EOF) {
+			AstNode *name  = parse_ident(f);
+			Token    open  = expect_token(f, Token_OpenBrace);
+			isize decl_count = 0;
+			AstNode *list  = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
+			Token    close = expect_token(f, Token_CloseBrace);
+
+			array_add(&variants, ast_union_field(f, name, list));
+
+			if (f->curr_token.kind != Token_Comma) {
+				break;
+			}
+			next_token(f);
+		}
+
+		// AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
-		return ast_union_type(f, token, decls, decl_count);
+
+		return ast_union_type(f, token, variants, variants.count);
 	}
 
 	case Token_raw_union: {
 		Token token = expect_token(f, Token_raw_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
+		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
+		AstNodeArray decls = {0};
+		if (fields != NULL) {
+			GB_ASSERT(fields->kind == AstNode_FieldList);
+			decls = fields->FieldList.list;
+		}
+
 		return ast_raw_union_type(f, token, decls, decl_count);
 	}
 
@@ -2699,39 +2759,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
 }
 
 
-AstNodeArray parse_results(AstFile *f) {
-	AstNodeArray results = make_ast_node_array(f);
-	if (allow_token(f, Token_ArrowRight)) {
-		if (f->curr_token.kind == Token_OpenParen) {
-			expect_token(f, Token_OpenParen);
-			while (f->curr_token.kind != Token_CloseParen &&
-			       f->curr_token.kind != Token_EOF) {
-				array_add(&results, parse_type(f));
-				if (f->curr_token.kind != Token_Comma) {
-					break;
-				}
-				next_token(f);
-			}
-			expect_token(f, Token_CloseParen);
-
-			return results;
-		}
-
-		array_add(&results, parse_type(f));
-		return results;
-	}
-	return results;
-}
-
-void parse_proc_signature(AstFile *f,
-                          AstNodeArray *params,
-                          AstNodeArray *results) {
-	expect_token(f, Token_OpenParen);
-	*params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
-	expect_token_after(f, Token_CloseParen, "parameter list");
-	*results = parse_results(f);
-}
-
 AstNode *parse_body(AstFile *f) {
 	AstNodeArray stmts = {0};
 	Token open, close;
@@ -2747,48 +2774,6 @@ AstNode *parse_body(AstFile *f) {
 	return ast_block_stmt(f, stmts, open, close);
 }
 
-
-/*
-AstNode *parse_proc_decl(AstFile *f) {
-	if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
-		// NOTE(bill): It's an anonymous procedure
-		// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
-		// but is that a problem in practice?
-		return ast_expr_stmt(f, parse_expr(f, true));
-	}
-
-	AstNodeArray params = {0};
-	AstNodeArray results = {0};
-
-	Token proc_token = expect_token(f, Token_proc);
-	AstNode *name = parse_ident(f);
-	parse_proc_signature(f, &params, &results);
-
-	u64 tags = 0;
-	String foreign_name = {0};
-	String link_name = {0};
-	ProcCallingConvention cc = ProcCC_Odin;
-
-	parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
-
-	AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc);
-	AstNode *body = NULL;
-
-	if (f->curr_token.kind == Token_OpenBrace) {
-		if ((tags & ProcTag_foreign) != 0) {
-			syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
-		}
-		AstNode *curr_proc = f->curr_proc;
-		f->curr_proc = proc_type;
-		body = parse_body(f);
-		f->curr_proc = curr_proc;
-	} else if ((tags & ProcTag_foreign) == 0) {
-		syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
-	}
-
-	return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
-} */
-
 AstNode *parse_if_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 		syntax_error(f->curr_token, "You cannot use an if statement in the file scope");
@@ -3458,8 +3443,18 @@ AstNode *parse_stmt(AstFile *f) {
 			return s;
 		}
 
-		expect_semicolon(f, s);
-		return ast_tag_stmt(f, hash_token, name, parse_stmt(f));
+
+		if (str_eq(tag, str_lit("include"))) {
+			syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
+			s = ast_bad_stmt(f, token, f->curr_token);
+		} else {
+			syntax_error(token, "Unknown tag used: `%.*s`", LIT(tag));
+			s = ast_bad_stmt(f, token, f->curr_token);
+		}
+
+		fix_advance_to_next_stmt(f);
+
+		return s;
 	} break;
 
 	case Token_OpenBrace:

+ 22 - 14
src/types.c

@@ -888,7 +888,7 @@ bool are_types_identical(Type *x, Type *y) {
 
 	case Type_Named:
 		if (y->kind == Type_Named) {
-			return x->Named.base == y->Named.base;
+			return x->Named.type_name == y->Named.type_name;
 		}
 		break;
 
@@ -923,7 +923,6 @@ bool are_types_identical(Type *x, Type *y) {
 		break;
 	}
 
-
 	return false;
 }
 
@@ -1023,41 +1022,50 @@ typedef enum ProcTypeOverloadKind {
 ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
  	if (!is_type_proc(x)) return ProcOverload_NotProcedure;
  	if (!is_type_proc(y)) return ProcOverload_NotProcedure;
-	TypeProc *px = &base_type(x)->Proc;
-	TypeProc *py = &base_type(y)->Proc;
+	TypeProc px = base_type(x)->Proc;
+	TypeProc py = base_type(y)->Proc;
 
-	if (px->calling_convention != py->calling_convention) {
+	if (px.calling_convention != py.calling_convention) {
 		return ProcOverload_CallingConvention;
 	}
 
-	if (px->param_count != py->param_count) {
+	if (px.param_count != py.param_count) {
 		return ProcOverload_ParamCount;
 	}
 
-	for (isize i = 0; i < px->param_count; i++) {
-		Entity *ex = px->params->Tuple.variables[i];
-		Entity *ey = py->params->Tuple.variables[i];
+	for (isize i = 0; i < px.param_count; i++) {
+		Entity *ex = px.params->Tuple.variables[i];
+		Entity *ey = py.params->Tuple.variables[i];
 		if (!are_types_identical(ex->type, ey->type)) {
 			return ProcOverload_ParamTypes;
 		}
 	}
 	// IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters
-	if (px->variadic != py->variadic) {
+	if (px.variadic != py.variadic) {
 		return ProcOverload_ParamVariadic;
 	}
 
-	if (px->result_count != py->result_count) {
+	if (px.result_count != py.result_count) {
 		return ProcOverload_ResultCount;
 	}
 
-	for (isize i = 0; i < px->result_count; i++) {
-		Entity *ex = px->results->Tuple.variables[i];
-		Entity *ey = py->results->Tuple.variables[i];
+	for (isize i = 0; i < px.result_count; i++) {
+		Entity *ex = px.results->Tuple.variables[i];
+		Entity *ey = py.results->Tuple.variables[i];
 		if (!are_types_identical(ex->type, ey->type)) {
 			return ProcOverload_ResultTypes;
 		}
 	}
 
+	{
+		Entity *ex = px.params->Tuple.variables[0];
+		Entity *ey = py.params->Tuple.variables[0];
+		bool ok = are_types_identical(ex->type, ey->type);
+		if (ok) {
+			gb_printf_err("Here\n");
+		}
+	}
+
 	return ProcOverload_Identical;
 }