Browse Source

fmt improvement; Minor refactoring

Ginger Bill 9 years ago
parent
commit
59b0cf61ef
10 changed files with 225 additions and 216 deletions
  1. 50 60
      code/demo.odin
  2. 1 1
      code/old_demos/demo002.odin
  3. 55 17
      core/fmt.odin
  4. 12 0
      core/runtime.odin
  5. 6 14
      src/checker/checker.cpp
  6. 35 24
      src/checker/expr.cpp
  7. 39 58
      src/checker/type.cpp
  8. 1 8
      src/codegen/print_llvm.cpp
  9. 19 34
      src/codegen/ssa.cpp
  10. 7 0
      src/tokenizer.cpp

+ 50 - 60
code/demo.odin

@@ -1,22 +1,8 @@
-#import "fmt.odin" as fmt
+// #import "fmt.odin" as fmt
+// #import "os.odin" as os
 
 
 main :: proc() {
 main :: proc() {
-	Fruit :: enum {
-		APPLE = -2,
-		BANANA,
-		GRAPE,
-		MELON = 123,
-		TOMATO,
-	}
-
-	s1 := enum_to_string(Fruit.BANANA)
-	e := Fruit.MELON
-	s2 := enum_to_string(e)
-
-	fmt.println(Fruit.APPLE)
-	fmt.println(Fruit.count)
-	fmt.println(Fruit.min_value)
-	fmt.println(Fruit.max_value)
+
 }
 }
 
 
 
 
@@ -24,6 +10,51 @@ main :: proc() {
 
 
 // #foreign_system_library "Ws2_32"
 // #foreign_system_library "Ws2_32"
 
 
+
+// SOCKET :: type uint
+// INVALID_SOCKET :: ~(0 as SOCKET)
+
+// AF :: enum i32 {
+// 	UNSPEC    = 0,       // unspecified
+// 	UNIX      = 1,       // local to host (pipes, portals)
+// 	INET      = 2,       // internetwork: UDP, TCP, etc.
+// 	IMPLINK   = 3,       // arpanet imp addresses
+// 	PUP       = 4,       // pup protocols: e.g. BSP
+// 	CHAOS     = 5,       // mit CHAOS protocols
+// 	NS        = 6,       // XEROX NS protocols
+// 	ISO       = 7,       // ISO protocols
+// 	OSI       = ISO,     // OSI is ISO
+// 	ECMA      = 8,       // european computer manufacturers
+// 	DATAKIT   = 9,       // datakit protocols
+// 	CCITT     = 10,      // CCITT protocols, X.25 etc
+// 	SNA       = 11,      // IBM SNA
+// 	DECnet    = 12,      // DECnet
+// 	DLI       = 13,      // Direct data link interface
+// 	LAT       = 14,      // LAT
+// 	HYLINK    = 15,      // NSC Hyperchannel
+// 	APPLETALK = 16,      // AppleTalk
+// 	ROUTE     = 17,      // Internal Routing Protocol
+// 	LINK      = 18,      // Link layer interface
+// 	XTP       = 19,      // eXpress Transfer Protocol (no AF)
+// 	COIP      = 20,      // connection-oriented IP, aka ST II
+// 	CNT       = 21,      // Computer Network Technology
+// 	RTIP      = 22,      // Help Identify RTIP packets
+// 	IPX       = 23,      // Novell Internet Protocol
+// 	SIP       = 24,      // Simple Internet Protocol
+// 	PIP       = 25,      // Help Identify PIP packets
+// 	MAX       = 26,
+// }
+
+// SOCK_STREAM  :: 1
+// SOCKET_ERROR :: -1
+// IPPROTO_TCP  :: 6
+// AI_PASSIVE   :: 0x0020
+// SOMAXCONN    :: 128
+
+// SD_RECEIVE :: 0
+// SD_SEND    :: 1
+// SD_BOTH    :: 2
+
 // WSADESCRIPTION_LEN :: 256
 // WSADESCRIPTION_LEN :: 256
 // WSASYS_STATUS_LEN  :: 128
 // WSASYS_STATUS_LEN  :: 128
 // WSADATA :: struct #ordered {
 // WSADATA :: struct #ordered {
@@ -31,6 +62,7 @@ main :: proc() {
 // 	high_version:  i16
 // 	high_version:  i16
 
 
 
 
+// // NOTE(bill): This is x64 ordering
 // 	max_sockets:   u16
 // 	max_sockets:   u16
 // 	max_udp_dg:    u16
 // 	max_udp_dg:    u16
 // 	vendor_info:   ^byte
 // 	vendor_info:   ^byte
@@ -55,48 +87,6 @@ main :: proc() {
 // }
 // }
 
 
 
 
-// SOCKET :: type uint
-// INVALID_SOCKET :: ~(0 as SOCKET)
-
-// AF_UNSPEC      :: 0       // unspecified
-// AF_UNIX        :: 1       // local to host (pipes, portals)
-// AF_INET        :: 2       // internetwork: UDP, TCP, etc.
-// AF_IMPLINK     :: 3       // arpanet imp addresses
-// AF_PUP         :: 4       // pup protocols: e.g. BSP
-// AF_CHAOS       :: 5       // mit CHAOS protocols
-// AF_NS          :: 6       // XEROX NS protocols
-// AF_ISO         :: 7       // ISO protocols
-// AF_OSI         :: AF_ISO  // OSI is ISO
-// AF_ECMA        :: 8       // european computer manufacturers
-// AF_DATAKIT     :: 9       // datakit protocols
-// AF_CCITT       :: 10      // CCITT protocols, X.25 etc
-// AF_SNA         :: 11      // IBM SNA
-// AF_DECnet      :: 12      // DECnet
-// AF_DLI         :: 13      // Direct data link interface
-// AF_LAT         :: 14      // LAT
-// AF_HYLINK      :: 15      // NSC Hyperchannel
-// AF_APPLETALK   :: 16      // AppleTalk
-// AF_ROUTE       :: 17      // Internal Routing Protocol
-// AF_LINK        :: 18      // Link layer interface
-// pseudo_AF_XTP  :: 19      // eXpress Transfer Protocol (no AF)
-// AF_COIP        :: 20      // connection-oriented IP, aka ST II
-// AF_CNT         :: 21      // Computer Network Technology
-// pseudo_AF_RTIP :: 22      // Help Identify RTIP packets
-// AF_IPX         :: 23      // Novell Internet Protocol
-// AF_SIP         :: 24      // Simple Internet Protocol
-// pseudo_AF_PIP  :: 25      // Help Identify PIP packets
-// AF_MAX         :: 26
-
-// SOCK_STREAM  :: 1
-// SOCKET_ERROR :: -1
-// IPPROTO_TCP  :: 6
-// AI_PASSIVE   :: 0x0020
-// SOMAXCONN    :: 128
-
-// SD_RECEIVE :: 0
-// SD_SEND    :: 1
-// SD_BOTH    :: 2
-
 // WSAStartup      :: proc(version_requested: i16, data: ^WSADATA) -> i32                             #foreign #dll_import
 // WSAStartup      :: proc(version_requested: i16, data: ^WSADATA) -> i32                             #foreign #dll_import
 // WSACleanup      :: proc() -> i32                                                                   #foreign #dll_import
 // WSACleanup      :: proc() -> i32                                                                   #foreign #dll_import
 // getaddrinfo     :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
 // getaddrinfo     :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
@@ -131,7 +121,7 @@ main :: proc() {
 // 	}
 // 	}
 // 	defer WSACleanup()
 // 	defer WSACleanup()
 
 
-// 	hints.family   = AF_INET
+// 	hints.family   = AF.INET as i32
 // 	hints.socktype = SOCK_STREAM
 // 	hints.socktype = SOCK_STREAM
 // 	hints.protocol = IPPROTO_TCP
 // 	hints.protocol = IPPROTO_TCP
 // 	hints.flags    = AI_PASSIVE
 // 	hints.flags    = AI_PASSIVE

+ 1 - 1
code/old_demos/demo002.odin

@@ -120,7 +120,7 @@ variadic_procedures :: proc() {
 
 
 	print_prefix_f32s("a"); nl()
 	print_prefix_f32s("a"); nl()
 	print_prefix_f32s("b", 1); nl()
 	print_prefix_f32s("b", 1); nl()
-	print_prefix_f32s("c", 1, 2, 3); nl()
+7	print_prefix_f32s("c", 1, 2, 3); nl()
 
 
 	// Internally, the variadic procedures get allocated to an array on the stack,
 	// Internally, the variadic procedures get allocated to an array on the stack,
 	// and this array is passed a slice
 	// and this array is passed a slice

+ 55 - 17
core/fmt.odin

@@ -2,42 +2,47 @@
 
 
 PRINT_BUF_SIZE :: 1<<12
 PRINT_BUF_SIZE :: 1<<12
 
 
-fprint :: proc(f: ^os.File, args: ..any) {
-	data: [PRINT_BUF_SIZE]byte
-	buf := data[:0]
+bprint :: proc(buf: ^[]byte, args: ..any) {
 	prev_string := false
 	prev_string := false
 
 
 	for i := 0; i < args.count; i++ {
 	for i := 0; i < args.count; i++ {
 		arg := args[i]
 		arg := args[i]
 		is_string := arg.data != null && type_info_is_string(arg.type_info)
 		is_string := arg.data != null && type_info_is_string(arg.type_info)
-		if i > 0 && is_string && !prev_string {
-			print_space_to_buffer(^buf)
+		if i > 0 && !is_string && !prev_string {
+			print_space_to_buffer(buf)
 		}
 		}
-		print_any_to_buffer(^buf, arg)
+		print_any_to_buffer(buf, arg)
 		prev_string = is_string;
 		prev_string = is_string;
 	}
 	}
-
-	os.write(f, buf)
 }
 }
 
 
-fprintln :: proc(f: ^os.File, args: ..any) {
-	data: [PRINT_BUF_SIZE]byte
-	buf := data[:0]
-
+bprintln :: proc(buf: ^[]byte, args: ..any) {
 	for i := 0; i < args.count; i++ {
 	for i := 0; i < args.count; i++ {
 		if i > 0 {
 		if i > 0 {
-			append(^buf, #rune " ")
+			append(buf, #rune " ")
 		}
 		}
-		print_any_to_buffer(^buf, args[i])
+		print_any_to_buffer(buf, args[i])
 	}
 	}
+	print_nl_to_buffer(buf)
+}
 
 
-	print_nl_to_buffer(^buf)
+fprint :: proc(f: ^os.File, args: ..any) {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	bprint(^buf, ..args)
+	os.write(f, buf)
+}
+
+fprintln :: proc(f: ^os.File, args: ..any) {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	bprintln(^buf, ..args)
 	os.write(f, buf)
 	os.write(f, buf)
 }
 }
 fprintf :: proc(f: ^os.File, fmt: string, args: ..any) {
 fprintf :: proc(f: ^os.File, fmt: string, args: ..any) {
 	data: [PRINT_BUF_SIZE]byte
 	data: [PRINT_BUF_SIZE]byte
 	buf := data[:0]
 	buf := data[:0]
-	printf_to_buffer(^buf, fmt, ..args)
+	bprintf(^buf, fmt, ..args)
 	os.write(f, buf)
 	os.write(f, buf)
 }
 }
 
 
@@ -52,6 +57,39 @@ printf :: proc(fmt: string, args: ..any) {
 	fprintf(os.stdout, fmt, ..args)
 	fprintf(os.stdout, fmt, ..args)
 }
 }
 
 
+sprint :: proc(args: ..any) -> string {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	bprint(^buf, ..args)
+	s := new_slice(byte, buf.count)
+	copy(s, buf)
+	return s as string
+}
+sprintln :: proc(args: ..any) -> string {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	bprintln(^buf, ..args)
+	s := new_slice(byte, buf.count)
+	copy(s, buf)
+	return s as string
+}
+sprintf :: proc(fmt: string, args: ..any) -> string {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	bprintf(^buf, fmt, ..args)
+	s := new_slice(byte, buf.count)
+	copy(s, buf)
+	return s as string
+}
+
+
+
+fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	print_type_to_buffer(^buf, info)
+	os.write(f, buf)
+}
 
 
 
 
 
 
@@ -561,7 +599,7 @@ type_info_is_string :: proc(info: ^Type_Info) -> bool {
 }
 }
 
 
 
 
-printf_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
+bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) {
 	is_digit :: proc(r: rune) -> bool #inline {
 	is_digit :: proc(r: rune) -> bool #inline {
 		return r >= #rune "0" && r <= #rune "9"
 		return r >= #rune "0" && r <= #rune "9"
 	}
 	}

+ 12 - 0
core/runtime.odin

@@ -63,6 +63,18 @@ Type_Info :: union {
 	}
 	}
 }
 }
 
 
+type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
+	for {
+		match type i : info {
+		case Type_Info.Named:
+			info = i.base
+			continue
+		}
+
+		return info
+	}
+}
+
 
 
 
 
 assume :: proc(cond: bool) #foreign "llvm.assume"
 assume :: proc(cond: bool) #foreign "llvm.assume"

+ 6 - 14
src/checker/checker.cpp

@@ -416,7 +416,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 
 
 void check_scope_usage(Checker *c, Scope *scope) {
 void check_scope_usage(Checker *c, Scope *scope) {
 	// TODO(bill): Use this?
 	// TODO(bill): Use this?
-#if 1
+#if 0
 	gb_for_array(i, scope->elements.entries) {
 	gb_for_array(i, scope->elements.entries) {
 		auto *entry = scope->elements.entries + i;
 		auto *entry = scope->elements.entries + i;
 		Entity *e = entry->value;
 		Entity *e = entry->value;
@@ -457,9 +457,7 @@ void add_global_entity(Entity *entity) {
 }
 }
 
 
 void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
 void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
-	Token token = {Token_Identifier};
-	token.string = name;
-	Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type);
+	Entity *entity = alloc_entity(a, Entity_Constant, NULL, make_token_ident(name), type);
 	entity->Constant.value = value;
 	entity->Constant.value = value;
 	add_global_entity(entity);
 	add_global_entity(entity);
 }
 }
@@ -475,14 +473,10 @@ void init_universal_scope(void) {
 
 
 // Types
 // Types
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
-		Token token = {Token_Identifier};
-		token.string = basic_types[i].Basic.name;
-		add_global_entity(make_entity_type_name(a, NULL, token, &basic_types[i]));
+		add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_types[i].Basic.name), &basic_types[i]));
 	}
 	}
 	for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) {
 	for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) {
-		Token token = {Token_Identifier};
-		token.string = basic_type_aliases[i].Basic.name;
-		add_global_entity(make_entity_type_name(a, NULL, token, &basic_type_aliases[i]));
+		add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_type_aliases[i].Basic.name), &basic_type_aliases[i]));
 	}
 	}
 
 
 // Constants
 // Constants
@@ -493,9 +487,7 @@ void init_universal_scope(void) {
 // Builtin Procedures
 // Builtin Procedures
 	for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
 	for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
 		BuiltinProcId id = cast(BuiltinProcId)i;
 		BuiltinProcId id = cast(BuiltinProcId)i;
-		Token token = {Token_Identifier};
-		token.string = builtin_procs[i].name;
-		Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, t_invalid);
+		Entity *entity = alloc_entity(a, Entity_Builtin, NULL, make_token_ident(builtin_procs[i].name), t_invalid);
 		entity->Builtin.id = id;
 		entity->Builtin.id = id;
 		add_global_entity(entity);
 		add_global_entity(entity);
 	}
 	}
@@ -968,7 +960,7 @@ void check_parsed_files(Checker *c) {
 					di->entities = entities;
 					di->entities = entities;
 					di->entity_count = entity_count;
 					di->entity_count = entity_count;
 					di->type_expr = vd->type;
 					di->type_expr = vd->type;
-					di->init_expr = vd->values[0]; // TODO(bill): Is this correct?
+					di->init_expr = vd->values[0];
 				}
 				}
 
 
 				gb_for_array(i, vd->names) {
 				gb_for_array(i, vd->names) {

+ 35 - 24
src/checker/expr.cpp

@@ -133,8 +133,7 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
 }
 }
 
 
 
 
-// NOTE(bill): `content_name` is for debugging
-// TODO(bill): Maybe allow assignment to tuples?
+// NOTE(bill): `content_name` is for debugging and error messages
 void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) {
 void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) {
 	check_not_tuple(c, operand);
 	check_not_tuple(c, operand);
 	if (operand->mode == Addressing_Invalid)
 	if (operand->mode == Addressing_Invalid)
@@ -153,8 +152,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 		}
 		}
 	}
 	}
 
 
-
-
 	if (type != NULL) {
 	if (type != NULL) {
 		if (!check_is_assignable_to(c, operand, type, is_argument)) {
 		if (!check_is_assignable_to(c, operand, type, is_argument)) {
 			gbString type_string = type_to_string(type);
 			gbString type_string = type_to_string(type);
@@ -579,8 +576,6 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 	if (named_type != NULL) {
 	if (named_type != NULL) {
 		constant_type = named_type;
 		constant_type = named_type;
 	}
 	}
-	Token blank_token = {Token_Identifier};
-	blank_token.string = make_string("");
 	Entity *blank_entity = make_entity_constant(c->allocator, c->context.scope, blank_token, constant_type, make_exact_value_integer(0));;
 	Entity *blank_entity = make_entity_constant(c->allocator, c->context.scope, blank_token, constant_type, make_exact_value_integer(0));;
 
 
 	gb_for_array(i, et->fields) {
 	gb_for_array(i, et->fields) {
@@ -590,15 +585,15 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 		Token name_token = f->field->Ident;
 		Token name_token = f->field->Ident;
 
 
 		if (name_token.string == make_string("count")) {
 		if (name_token.string == make_string("count")) {
-			error(name_token, "`count` is a reserved identifier for enums");
+			error(name_token, "`count` is a reserved identifier for enumerations");
 			fields[field_index++] = blank_entity;
 			fields[field_index++] = blank_entity;
 			continue;
 			continue;
 		} else if (name_token.string == make_string("min_value")) {
 		} else if (name_token.string == make_string("min_value")) {
-			error(name_token, "`min_value` is a reserved identifier for enums");
+			error(name_token, "`min_value` is a reserved identifier for enumerations");
 			fields[field_index++] = blank_entity;
 			fields[field_index++] = blank_entity;
 			continue;
 			continue;
 		} else if (name_token.string == make_string("max_value")) {
 		} else if (name_token.string == make_string("max_value")) {
-			error(name_token, "`max_value` is a reserved identifier for enums");
+			error(name_token, "`max_value` is a reserved identifier for enumerations");
 			fields[field_index++] = blank_entity;
 			fields[field_index++] = blank_entity;
 			continue;
 			continue;
 		}
 		}
@@ -611,7 +606,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 				o.mode = Addressing_Invalid;
 				o.mode = Addressing_Invalid;
 			}
 			}
 			if (o.mode != Addressing_Invalid) {
 			if (o.mode != Addressing_Invalid) {
-				check_assignment(c, &o, base_type, make_string("enumeration"));
+				check_assignment(c, &o, constant_type, make_string("enumeration"));
 			}
 			}
 			if (o.mode != Addressing_Invalid) {
 			if (o.mode != Addressing_Invalid) {
 				iota = o.value;
 				iota = o.value;
@@ -639,14 +634,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 			error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string));
 			error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string));
 		} else {
 		} else {
 			map_set(&entity_map, key, e);
 			map_set(&entity_map, key, e);
+			add_entity(c, c->context.scope, NULL, e);
 			fields[field_index++] = e;
 			fields[field_index++] = e;
 		}
 		}
 		add_entity_use(&c->info, f->field, e);
 		add_entity_use(&c->info, f->field, e);
 	}
 	}
-	enum_type->Record.min_value = min_value;
-	enum_type->Record.max_value = max_value;
+
 	enum_type->Record.other_fields = fields;
 	enum_type->Record.other_fields = fields;
 	enum_type->Record.other_field_count = gb_array_count(et->fields);
 	enum_type->Record.other_field_count = gb_array_count(et->fields);
+
+	enum_type->Record.enum_count = make_entity_constant(c->allocator, NULL,
+		make_token_ident(make_string("count")), t_int, make_exact_value_integer(enum_type->Record.other_field_count));
+	enum_type->Record.min_value  = make_entity_constant(c->allocator, NULL,
+		make_token_ident(make_string("min_value")), constant_type, make_exact_value_integer(min_value));
+	enum_type->Record.max_value  = make_entity_constant(c->allocator, NULL,
+		make_token_ident(make_string("max_value")), constant_type, make_exact_value_integer(max_value));
 }
 }
 
 
 Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) {
 Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) {
@@ -1019,7 +1021,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
 	case_ast_node(et, EnumType, e);
 	case_ast_node(et, EnumType, e);
 		type = make_type_enum(c->allocator);
 		type = make_type_enum(c->allocator);
 		set_base_type(named_type, type);
 		set_base_type(named_type, type);
+		check_open_scope(c, e);
 		check_enum_type(c, type, named_type, e);
 		check_enum_type(c, type, named_type, e);
+		check_close_scope(c);
 		type->Record.node = e;
 		type->Record.node = e;
 		goto end;
 		goto end;
 	case_end;
 	case_end;
@@ -2070,7 +2074,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
 	}
 	}
 
 
 	if (entity == NULL) {
 	if (entity == NULL) {
-		entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
+		entity = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
 	}
 	}
 	if (entity == NULL) {
 	if (entity == NULL) {
 		gbString op_str   = expr_to_string(op_expr);
 		gbString op_str   = expr_to_string(op_expr);
@@ -2217,7 +2221,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		Operand op = {};
 		Operand op = {};
 		check_expr_or_type(c, &op, ce->args[0]);
 		check_expr_or_type(c, &op, ce->args[0]);
 		Type *type = op.type;
 		Type *type = op.type;
-		if (!type) {
+		if (type == NULL || op.mode == Addressing_Builtin) {
 			error(ast_node_token(ce->args[0]), "Expected a type for `size_of`");
 			error(ast_node_token(ce->args[0]), "Expected a type for `size_of`");
 			return false;
 			return false;
 		}
 		}
@@ -2231,8 +2235,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	case BuiltinProc_size_of_val:
 	case BuiltinProc_size_of_val:
 		// size_of_val :: proc(val: Type) -> int
 		// size_of_val :: proc(val: Type) -> int
 		check_assignment(c, operand, NULL, make_string("argument of `size_of_val`"));
 		check_assignment(c, operand, NULL, make_string("argument of `size_of_val`"));
-		if (operand->mode == Addressing_Invalid)
+		if (operand->mode == Addressing_Invalid) {
 			return false;
 			return false;
+		}
 
 
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type));
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type));
@@ -2244,7 +2249,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		Operand op = {};
 		Operand op = {};
 		check_expr_or_type(c, &op, ce->args[0]);
 		check_expr_or_type(c, &op, ce->args[0]);
 		Type *type = op.type;
 		Type *type = op.type;
-		if (!type) {
+		if (type == NULL || op.mode == Addressing_Builtin) {
 			error(ast_node_token(ce->args[0]), "Expected a type for `align_of`");
 			error(ast_node_token(ce->args[0]), "Expected a type for `align_of`");
 			return false;
 			return false;
 		}
 		}
@@ -2256,8 +2261,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	case BuiltinProc_align_of_val:
 	case BuiltinProc_align_of_val:
 		// align_of_val :: proc(val: Type) -> int
 		// align_of_val :: proc(val: Type) -> int
 		check_assignment(c, operand, NULL, make_string("argument of `align_of_val`"));
 		check_assignment(c, operand, NULL, make_string("argument of `align_of_val`"));
-		if (operand->mode == Addressing_Invalid)
+		if (operand->mode == Addressing_Invalid) {
 			return false;
 			return false;
+		}
 
 
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type));
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type));
@@ -2270,7 +2276,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		check_expr_or_type(c, &op, ce->args[0]);
 		check_expr_or_type(c, &op, ce->args[0]);
 		Type *type = get_base_type(op.type);
 		Type *type = get_base_type(op.type);
 		AstNode *field_arg = unparen_expr(ce->args[1]);
 		AstNode *field_arg = unparen_expr(ce->args[1]);
-		if (type != NULL) {
+		if (type != NULL  || op.mode == Addressing_Builtin) {
 			error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`");
 			error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`");
 			return false;
 			return false;
 		}
 		}
@@ -2286,7 +2292,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 
 
 
 		ast_node(arg, Ident, field_arg);
 		ast_node(arg, Ident, field_arg);
-		Selection sel = lookup_field(type, arg->string, operand->mode == Addressing_Type);
+		Selection sel = lookup_field(c->allocator, type, arg->string, operand->mode == Addressing_Type);
 		if (sel.entity == NULL) {
 		if (sel.entity == NULL) {
 			gbString type_str = type_to_string(type);
 			gbString type_str = type_to_string(type);
 			error(ast_node_token(ce->args[0]),
 			error(ast_node_token(ce->args[0]),
@@ -2324,7 +2330,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 
 
 
 		ast_node(i, Ident, s->selector);
 		ast_node(i, Ident, s->selector);
-		Selection sel = lookup_field(type, i->string, operand->mode == Addressing_Type);
+		Selection sel = lookup_field(c->allocator, type, i->string, operand->mode == Addressing_Type);
 		if (sel.entity == NULL) {
 		if (sel.entity == NULL) {
 			gbString type_str = type_to_string(type);
 			gbString type_str = type_to_string(type);
 			error(ast_node_token(arg),
 			error(ast_node_token(arg),
@@ -2341,7 +2347,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	case BuiltinProc_type_of_val:
 	case BuiltinProc_type_of_val:
 		// type_of_val :: proc(val: Type) -> type(Type)
 		// type_of_val :: proc(val: Type) -> type(Type)
 		check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
 		check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
-		if (operand->mode == Addressing_Invalid)
+		if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin)
 			return false;
 			return false;
 		operand->mode = Addressing_Type;
 		operand->mode = Addressing_Type;
 		break;
 		break;
@@ -2349,11 +2355,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 
 	case BuiltinProc_type_info: {
 	case BuiltinProc_type_info: {
 		// type_info :: proc(val_or_type) -> ^Type_Info
 		// type_info :: proc(val_or_type) -> ^Type_Info
+		operand->mode = Addressing_Value;
+		operand->type = t_type_info_ptr;
+
 		Operand op = {};
 		Operand op = {};
 		check_expr_or_type(c, &op, ce->args[0]);
 		check_expr_or_type(c, &op, ce->args[0]);
+		if (op.type == NULL || op.type == t_invalid || operand->mode == Addressing_Builtin) {
+			error(ast_node_token(op.expr), "Invalid argument to `type_info`");
+			return false;
+		}
 		add_type_info_type(c, op.type);
 		add_type_info_type(c, op.type);
-		operand->mode = Addressing_Value;
-		operand->type = t_type_info_ptr;
 	} break;
 	} break;
 
 
 	case BuiltinProc_compile_assert:
 	case BuiltinProc_compile_assert:
@@ -3193,7 +3204,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 						}
 						}
 						String name = kv->field->Ident.string;
 						String name = kv->field->Ident.string;
 
 
-						Selection sel = lookup_field(type, name, o->mode == Addressing_Type);
+						Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
 						if (sel.entity == NULL) {
 						if (sel.entity == NULL) {
 							error(ast_node_token(elem),
 							error(ast_node_token(elem),
 							      "Unknown field `%.*s` in structure literal", LIT(name));
 							      "Unknown field `%.*s` in structure literal", LIT(name));

+ 39 - 58
src/checker/type.cpp

@@ -120,8 +120,9 @@ struct Type {
 
 
 			// enum only
 			// enum only
 			Type *   enum_base; // Default is `int`
 			Type *   enum_base; // Default is `int`
-			i64      min_value;
-			i64      max_value;
+			Entity * enum_count;
+			Entity * min_value;
+			Entity * max_value;
 
 
 			// struct only
 			// struct only
 			i64 *    struct_offsets;
 			i64 *    struct_offsets;
@@ -703,25 +704,28 @@ Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) {
 }
 }
 
 
 void selection_add_index(Selection *s, isize index) {
 void selection_add_index(Selection *s, isize index) {
+	// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
+	// of heap allocation
 	if (s->index == NULL) {
 	if (s->index == NULL) {
 		gb_array_init(s->index, gb_heap_allocator());
 		gb_array_init(s->index, gb_heap_allocator());
 	}
 	}
 	gb_array_append(s->index, index);
 	gb_array_append(s->index, index);
 }
 }
 
 
-gb_global Entity *entity__any_type_info = NULL;
-gb_global Entity *entity__any_data      = NULL;
-gb_global Entity *entity__string_data   = NULL;
-gb_global Entity *entity__string_count  = NULL;
+gb_global Entity *entity__any_type_info  = NULL;
+gb_global Entity *entity__any_data       = NULL;
+gb_global Entity *entity__string_data    = NULL;
+gb_global Entity *entity__string_count   = NULL;
+gb_global Entity *entity__slice_count    = NULL;
+gb_global Entity *entity__slice_capacity = NULL;
 
 
-Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
+Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
 	GB_ASSERT(type_ != NULL);
 	GB_ASSERT(type_ != NULL);
 
 
 	if (field_name == make_string("_")) {
 	if (field_name == make_string("_")) {
 		return empty_selection;
 		return empty_selection;
 	}
 	}
 
 
-	gbAllocator a = gb_heap_allocator();
 	Type *type = type_deref(type_);
 	Type *type = type_deref(type_);
 	b32 is_ptr = type != type_;
 	b32 is_ptr = type != type_;
 	type = get_base_type(type);
 	type = get_base_type(type);
@@ -732,14 +736,10 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 			String type_info_str = make_string("type_info");
 			String type_info_str = make_string("type_info");
 			String data_str = make_string("data");
 			String data_str = make_string("data");
 			if (entity__any_type_info == NULL) {
 			if (entity__any_type_info == NULL) {
-				Token token = {Token_Identifier};
-				token.string = type_info_str;
-				entity__any_type_info = make_entity_field(a, NULL, token, t_type_info_ptr, false, 0);
+				entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 0);
 			}
 			}
 			if (entity__any_data == NULL) {
 			if (entity__any_data == NULL) {
-				Token token = {Token_Identifier};
-				token.string = data_str;
-				entity__any_data = make_entity_field(a, NULL, token, t_rawptr, false, 1);
+				entity__any_data = make_entity_field(a, NULL, make_token_ident(data_str), t_rawptr, false, 1);
 			}
 			}
 
 
 			if (field_name == type_info_str) {
 			if (field_name == type_info_str) {
@@ -756,15 +756,11 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 			String data_str = make_string("data");
 			String data_str = make_string("data");
 			String count_str = make_string("count");
 			String count_str = make_string("count");
 			if (entity__string_data == NULL) {
 			if (entity__string_data == NULL) {
-				Token token = {Token_Identifier};
-				token.string = data_str;
-				entity__string_data = make_entity_field(a, NULL, token, make_type_pointer(a, t_u8), false, 0);
+				entity__string_data = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, t_u8), false, 0);
 			}
 			}
 
 
 			if (entity__string_count == NULL) {
 			if (entity__string_count == NULL) {
-				Token token = {Token_Identifier};
-				token.string = count_str;
-				entity__string_count = make_entity_field(a, NULL, token, t_int, false, 1);
+				entity__string_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
 			}
 			}
 
 
 			if (field_name == data_str) {
 			if (field_name == data_str) {
@@ -784,20 +780,16 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 		String count_str = make_string("count");
 		String count_str = make_string("count");
 		// NOTE(bill): Underlying memory address cannot be changed
 		// NOTE(bill): Underlying memory address cannot be changed
 		if (field_name == count_str) {
 		if (field_name == count_str) {
-			Token token = {Token_Identifier};
-			token.string = count_str;
 			// HACK(bill): Memory leak
 			// HACK(bill): Memory leak
-			sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Array.count));
+			sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Array.count));
 			return sel;
 			return sel;
 		}
 		}
 	} else if (type->kind == Type_Vector) {
 	} else if (type->kind == Type_Vector) {
 		String count_str = make_string("count");
 		String count_str = make_string("count");
 		// NOTE(bill): Vectors are not addressable
 		// NOTE(bill): Vectors are not addressable
 		if (field_name == count_str) {
 		if (field_name == count_str) {
-			Token token = {Token_Identifier};
-			token.string = count_str;
 			// HACK(bill): Memory leak
 			// HACK(bill): Memory leak
-			sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Vector.count));
+			sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
 			return sel;
 			return sel;
 		}
 		}
 	} else if (type->kind == Type_Slice) {
 	} else if (type->kind == Type_Slice) {
@@ -807,24 +799,24 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 
 
 		if (field_name == data_str) {
 		if (field_name == data_str) {
 			selection_add_index(&sel, 0);
 			selection_add_index(&sel, 0);
-			Token token = {Token_Identifier};
-			token.string = data_str;
 			// HACK(bill): Memory leak
 			// HACK(bill): Memory leak
-			sel.entity = make_entity_field(a, NULL, token, make_type_pointer(a, type->Slice.elem), false, 0);
+			sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->Slice.elem), false, 0);
 			return sel;
 			return sel;
 		} else if (field_name == count_str) {
 		} else if (field_name == count_str) {
 			selection_add_index(&sel, 1);
 			selection_add_index(&sel, 1);
-			Token token = {Token_Identifier};
-			token.string = count_str;
-			// HACK(bill): Memory leak
-			sel.entity = make_entity_field(a, NULL, token, t_int, false, 1);
+			if (entity__slice_count == NULL) {
+				entity__slice_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
+			}
+
+			sel.entity = entity__slice_count;
 			return sel;
 			return sel;
 		} else if (field_name == capacity_str) {
 		} else if (field_name == capacity_str) {
 			selection_add_index(&sel, 2);
 			selection_add_index(&sel, 2);
-			Token token = {Token_Identifier};
-			token.string = capacity_str;
-			// HACK(bill): Memory leak
-			sel.entity = make_entity_field(a, NULL, token, t_int, false, 2);
+			if (entity__slice_capacity == NULL) {
+				entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
+			}
+
+			sel.entity = entity__slice_capacity;
 			return sel;
 			return sel;
 		}
 		}
 	}
 	}
@@ -834,6 +826,8 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 	}
 	}
 	if (is_type) {
 	if (is_type) {
 		if (is_type_union(type)) {
 		if (is_type_union(type)) {
+			// NOTE(bill): The subtype for a union are stored in the fields
+			// as they are "kind of" like variables but not
 			for (isize i = 0; i < type->Record.field_count; i++) {
 			for (isize i = 0; i < type->Record.field_count; i++) {
 				Entity *f = type->Record.fields[i];
 				Entity *f = type->Record.fields[i];
 				GB_ASSERT(f->kind == Entity_TypeName);
 				GB_ASSERT(f->kind == Entity_TypeName);
@@ -856,27 +850,14 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 		}
 		}
 
 
 		if (is_type_enum(type)) {
 		if (is_type_enum(type)) {
-			String count_str = make_string("count");
-			String min_value_str = make_string("min_value");
-			String max_value_str = make_string("max_value");
-
-			if (field_name == count_str) {
-				Token token = {Token_Identifier};
-				token.string = count_str;
-				// HACK(bill): Memory leak
-				sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Record.other_field_count));
+			if (field_name == make_string("count")) {
+				sel.entity = type->Record.enum_count;
 				return sel;
 				return sel;
-			} else if (field_name == min_value_str) {
-				Token token = {Token_Identifier};
-				token.string = min_value_str;
-				// HACK(bill): Memory leak
-				sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.min_value));
+			} else if (field_name == make_string("min_value")) {
+				sel.entity = type->Record.min_value;
 				return sel;
 				return sel;
-			} else if (field_name == max_value_str) {
-				Token token = {Token_Identifier};
-				token.string = max_value_str;
-				// HACK(bill): Memory leak
-				sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.max_value));
+			} else if (field_name == make_string("max_value")) {
+				sel.entity = type->Record.max_value;
 				return sel;
 				return sel;
 			}
 			}
 		}
 		}
@@ -887,7 +868,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 			GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
 			GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
 			String str = f->token.string;
 			String str = f->token.string;
 			if (field_name == str) {
 			if (field_name == str) {
-				selection_add_index(&sel, i);
+				selection_add_index(&sel, i);  // HACK(bill): Leaky memory
 				sel.entity = f;
 				sel.entity = f;
 				return sel;
 				return sel;
 			}
 			}
@@ -899,7 +880,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
 				}
 				}
 				selection_add_index(&sel, i); // HACK(bill): Leaky memory
 				selection_add_index(&sel, i); // HACK(bill): Leaky memory
 
 
-				sel = lookup_field(f->type, field_name, is_type, sel);
+				sel = lookup_field(a, f->type, field_name, is_type, sel);
 
 
 				if (sel.entity != NULL) {
 				if (sel.entity != NULL) {
 					if (is_type_pointer(f->type))
 					if (is_type_pointer(f->type))

+ 1 - 8
src/codegen/print_llvm.cpp

@@ -396,18 +396,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
 		ssa_print_type(f, m, type);
 		ssa_print_type(f, m, type);
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
-		// if (instr->Local.zero_initialized) {
-		// 	ssa_fprintf(f, "\tstore ");
-		// 	ssa_print_type(f, m, type);
-		// 	ssa_fprintf(f, " zeroinitializer, ");
-		// 	ssa_print_type(f, m, type);
-		// 	ssa_fprintf(f, "* %%%d\n", value->id);
-		// }
 	} break;
 	} break;
 
 
 	case ssaInstr_ZeroInit: {
 	case ssaInstr_ZeroInit: {
 		Type *type = type_deref(ssa_type(instr->ZeroInit.address));
 		Type *type = type_deref(ssa_type(instr->ZeroInit.address));
-		ssa_fprintf(f, "\tstore ");
+		ssa_fprintf(f, "store ");
 		ssa_print_type(f, m, type);
 		ssa_print_type(f, m, type);
 		ssa_fprintf(f, " zeroinitializer, ");
 		ssa_fprintf(f, " zeroinitializer, ");
 		ssa_print_type(f, m, type);
 		ssa_print_type(f, m, type);

+ 19 - 34
src/codegen/ssa.cpp

@@ -385,12 +385,8 @@ void ssa_init_module(ssaModule *m, Checker *c) {
 		// Add type info data
 		// Add type info data
 		{
 		{
 			String name = make_string(SSA_TYPE_INFO_DATA_NAME);
 			String name = make_string(SSA_TYPE_INFO_DATA_NAME);
-			Token token = {Token_Identifier};
-			token.string = name;
-
-
 			isize count = gb_array_count(c->info.type_info_map.entries);
 			isize count = gb_array_count(c->info.type_info_map.entries);
-			Entity *e = make_entity_variable(m->allocator, NULL, token, make_type_array(m->allocator, t_type_info, count));
+			Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, count));
 			ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
 			ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
 			g->Global.is_private  = true;
 			g->Global.is_private  = true;
 			ssa_module_add_value(m, e, g);
 			ssa_module_add_value(m, e, g);
@@ -421,10 +417,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
 			}
 			}
 
 
 			String name = make_string(SSA_TYPE_INFO_DATA_MEMBER_NAME);
 			String name = make_string(SSA_TYPE_INFO_DATA_MEMBER_NAME);
-			Token token = {Token_Identifier};
-			token.string = name;
-
-			Entity *e = make_entity_variable(m->allocator, NULL, token,
+			Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name),
 			                                 make_type_array(m->allocator, t_type_info_member, count));
 			                                 make_type_array(m->allocator, t_type_info_member, count));
 			ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
 			ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
 			ssa_module_add_value(m, e, g);
 			ssa_module_add_value(m, e, g);
@@ -1095,6 +1088,10 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
 		ssa_emit_ret(proc, NULL);
 		ssa_emit_ret(proc, NULL);
 	}
 	}
 
 
+	if (gb_array_count(proc->curr_block->instrs) == 0) {
+		ssa_emit_unreachable(proc);
+	}
+
 	proc->curr_block = proc->decl_block;
 	proc->curr_block = proc->decl_block;
 	ssa_emit_jump(proc, proc->entry_block);
 	ssa_emit_jump(proc, proc->entry_block);
 
 
@@ -1560,14 +1557,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 
 
 	Type *src = get_enum_base_type(get_base_type(src_type));
 	Type *src = get_enum_base_type(get_base_type(src_type));
 	Type *dst = get_enum_base_type(get_base_type(t));
 	Type *dst = get_enum_base_type(get_base_type(t));
-	if (are_types_identical(src, dst)) {
-		return value;
-	}
 
 
 	if (value->kind == ssaValue_Constant) {
 	if (value->kind == ssaValue_Constant) {
 		if (is_type_any(dst)) {
 		if (is_type_any(dst)) {
-			Type *dt = default_type(get_base_type(src_type));
-			ssaValue *default_value = ssa_add_local_generated(proc, dt);
+			ssaValue *default_value = ssa_add_local_generated(proc, default_type(src_type));
 			ssa_emit_store(proc, default_value, value);
 			ssa_emit_store(proc, default_value, value);
 			return ssa_emit_conv(proc, ssa_emit_load(proc, default_value), t_any, is_argument);
 			return ssa_emit_conv(proc, ssa_emit_load(proc, default_value), t_any, is_argument);
 		} else if (dst->kind == Type_Basic) {
 		} else if (dst->kind == Type_Basic) {
@@ -1587,6 +1580,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 		}
 		}
 	}
 	}
 
 
+	if (are_types_identical(src, dst)) {
+		return value;
+	}
+
 	// integer -> integer
 	// integer -> integer
 	if (is_type_integer(src) && is_type_integer(dst)) {
 	if (is_type_integer(src) && is_type_integer(dst)) {
 		GB_ASSERT(src->kind == Type_Basic &&
 		GB_ASSERT(src->kind == Type_Basic &&
@@ -1684,7 +1681,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
 			// gb_printf("field_name: %.*s\n", LIT(field_name));
 			// gb_printf("field_name: %.*s\n", LIT(field_name));
 			if (field_name.len > 0) {
 			if (field_name.len > 0) {
 				// NOTE(bill): It can be casted
 				// NOTE(bill): It can be casted
-				Selection sel = lookup_field(sb, field_name, false);
+				Selection sel = lookup_field(proc->module->allocator, sb, field_name, false);
 				if (sel.entity != NULL) {
 				if (sel.entity != NULL) {
 					ssa_emit_comment(proc, make_string("cast - polymorphism"));
 					ssa_emit_comment(proc, make_string("cast - polymorphism"));
 					if (src_is_ptr) {
 					if (src_is_ptr) {
@@ -1821,7 +1818,7 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
 
 
 	String field_name = check_down_cast_name(t, type_deref(ssa_type(value)));
 	String field_name = check_down_cast_name(t, type_deref(ssa_type(value)));
 	GB_ASSERT(field_name.len > 0);
 	GB_ASSERT(field_name.len > 0);
-	Selection sel = lookup_field(t, field_name, false);
+	Selection sel = lookup_field(proc->module->allocator, t, field_name, false);
 	Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
 	Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
 	ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr);
 	ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr);
 
 
@@ -2088,11 +2085,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 
 					if (elem->kind == AstNode_FieldValue) {
 					if (elem->kind == AstNode_FieldValue) {
 						ast_node(kv, FieldValue, elem);
 						ast_node(kv, FieldValue, elem);
-						Selection sel = lookup_field(base_type, kv->field->Ident.string, false);
+						Selection sel = lookup_field(proc->module->allocator, base_type, kv->field->Ident.string, false);
 						index = sel.index[0];
 						index = sel.index[0];
 						field_expr = ssa_build_expr(proc, kv->value);
 						field_expr = ssa_build_expr(proc, kv->value);
 					} else {
 					} else {
-						Selection sel = lookup_field(base_type, st->fields_in_src_order[field_index]->token.string, false);
+						Selection sel = lookup_field(proc->module->allocator, base_type, st->fields_in_src_order[field_index]->token.string, false);
 						index = sel.index[0];
 						index = sel.index[0];
 						field_expr = ssa_build_expr(proc, elem);
 						field_expr = ssa_build_expr(proc, elem);
 					}
 					}
@@ -2158,7 +2155,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 				Entity *e = *found;
 				Entity *e = *found;
 				switch (e->Builtin.id) {
 				switch (e->Builtin.id) {
 				case BuiltinProc_type_info: {
 				case BuiltinProc_type_info: {
-					ssaValue *x = ssa_build_expr(proc, ce->args[0]);
 					Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
 					Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
 					return ssa_type_info(proc, t);
 					return ssa_type_info(proc, t);
 				} break;
 				} break;
@@ -2629,7 +2625,7 @@ ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
 		p = ssa_add_using_variable(proc, parent);
 		p = ssa_add_using_variable(proc, parent);
 	}
 	}
 
 
-	Selection sel = lookup_field(parent->type, name, false);
+	Selection sel = lookup_field(proc->module->allocator, parent->type, name, false);
 	GB_ASSERT(sel.entity != NULL);
 	GB_ASSERT(sel.entity != NULL);
 	ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
 	ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
 	ssaValue *v = NULL;
 	ssaValue *v = NULL;
@@ -2694,25 +2690,14 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
 		Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
 
 
 		if (type == t_invalid) {
 		if (type == t_invalid) {
-			// Imports
+			// NOTE(bill): Imports
 			Entity *imp = entity_of_ident(proc->module->info, se->expr);
 			Entity *imp = entity_of_ident(proc->module->info, se->expr);
 			if (imp != NULL) {
 			if (imp != NULL) {
 				GB_ASSERT(imp->kind == Entity_ImportName);
 				GB_ASSERT(imp->kind == Entity_ImportName);
 			}
 			}
 			return ssa_build_addr(proc, unparen_expr(se->selector));
 			return ssa_build_addr(proc, unparen_expr(se->selector));
-		} /* else if (type == t_string) {
-			Selection sel = lookup_field(type, selector, false);
-			GB_ASSERT(sel.entity != NULL);
-
-			// NOTE(bill): This could a constant and the only non constant
-			// selector is the `.data`, so build the expression instead
-			ssaValue *e = ssa_build_expr(proc, se->expr);
-			ssaValue *a = ssa_build_addr(proc, se->expr).addr;
-
-			a = ssa_emit_deep_field_gep(proc, type, a, sel);
-			return ssa_make_addr(a, expr);
-		}  */else {
-			Selection sel = lookup_field(type, selector, false);
+		} else {
+			Selection sel = lookup_field(proc->module->allocator, type, selector, false);
 			GB_ASSERT(sel.entity != NULL);
 			GB_ASSERT(sel.entity != NULL);
 
 
 			ssaValue *a = ssa_build_addr(proc, se->expr).addr;
 			ssaValue *a = ssa_build_addr(proc, se->expr).addr;

+ 7 - 0
src/tokenizer.cpp

@@ -150,6 +150,13 @@ struct Token {
 };
 };
 
 
 Token empty_token = {Token_Invalid};
 Token empty_token = {Token_Invalid};
+Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}};
+
+Token make_token_ident(String s) {
+	Token t = {Token_Identifier};
+	t.string = s;
+	return t;
+}
 
 
 
 
 struct ErrorCollector {
 struct ErrorCollector {