浏览代码

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

Zac Pierson 8 年之前
父节点
当前提交
72d4bfb32a
共有 11 个文件被更改,包括 514 次插入176 次删除
  1. 37 8
      code/demo.odin
  2. 61 33
      core/_preload.odin
  3. 54 6
      core/fmt.odin
  4. 1 1
      src/check_decl.c
  5. 61 22
      src/check_expr.c
  6. 7 2
      src/check_stmt.c
  7. 11 3
      src/checker.c
  8. 31 26
      src/gb/gb.h
  9. 203 70
      src/ir.c
  10. 1 0
      src/parser.c
  11. 47 5
      src/types.c

+ 37 - 8
code/demo.odin

@@ -9,16 +9,45 @@
 #import "utf8.odin";
 #import "utf8.odin";
 #import ht "http_test.odin";
 #import ht "http_test.odin";
 
 
-
 main :: proc() {
 main :: proc() {
-	Value :: type f32;
-	m: map[int]Value;
-	reserve(^m, 16);
-	defer free(m);
-	// m[123] = 345.0;
-	if x, ok := m[123]; ok {
-		fmt.println(x);
+	{
+		m: map[f32]int;
+		reserve(^m, 16);
+		defer free(m);
+
+		m[1.0] = 1278;
+		m[2.0] = 7643;
+		m[3.0] = 564;
+		c := m[3.0];
+		_, ok := m[3.0];
+		// assert(ok && c == 564);
+
+		fmt.print("map[");
+		i := 0;
+		for val, key in m {
+			if i > 0 {
+				fmt.print(", ");
+			}
+			fmt.printf("%f=%v", key, val);
+			i += 1;
+		}
+		fmt.println("]");
 	}
 	}
+	{
+		m := map[string]u32{
+			"a" = 56,
+			"b" = 13453,
+			"c" = 7654,
+		};
+		defer free(m);
+
+		c := m["c"];
+		_, ok := m["c"];
+		assert(ok && c == 7654);
+
+		fmt.println(m);
+	}
+
 
 
 
 
 	// fm: map[128, int]f32;
 	// fm: map[128, int]f32;

+ 61 - 33
core/_preload.odin

@@ -20,11 +20,12 @@ Type_Info_Member :: struct #ordered {
 	offset:    int,        // offsets are not used in tuples
 	offset:    int,        // offsets are not used in tuples
 }
 }
 Type_Info_Record :: struct #ordered {
 Type_Info_Record :: struct #ordered {
-	fields:  []Type_Info_Member,
-	size:    int, // in bytes
-	align:   int, // in bytes
-	packed:  bool,
-	ordered: bool,
+	fields:       []Type_Info_Member,
+	size:         int, // in bytes
+	align:        int, // in bytes
+	packed:       bool,
+	ordered:      bool,
+	custom_align: bool,
 }
 }
 Type_Info_Enum_Value :: raw_union {
 Type_Info_Enum_Value :: raw_union {
 	f: f64,
 	f: f64,
@@ -90,10 +91,16 @@ Type_Info :: union {
 	Union:     Type_Info_Record,
 	Union:     Type_Info_Record,
 	Raw_Union: Type_Info_Record,
 	Raw_Union: Type_Info_Record,
 	Enum: struct #ordered {
 	Enum: struct #ordered {
-		base:  ^Type_Info,
-		names: []string,
+		base:   ^Type_Info,
+		names:  []string,
 		values: []Type_Info_Enum_Value,
 		values: []Type_Info_Enum_Value,
 	},
 	},
+	Map: struct #ordered {
+		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)
 // // NOTE(bill): only the ones that are needed (not all types)
@@ -113,6 +120,21 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 }
 }
 
 
 
 
+type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
+	if info == nil {
+		return nil;
+	}
+	base := info;
+	match type i in base {
+	case Type_Info.Named:
+		base = i.base;
+	case Type_Info.Enum:
+		base = i.base;
+	}
+	return base;
+}
+
+
 
 
 assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
 assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
 
 
@@ -438,29 +460,32 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
 
 
 
 
 __default_hash :: proc(data: []byte) -> u64 {
 __default_hash :: proc(data: []byte) -> u64 {
-	return hash.murmur64(data);
+	return hash.fnv64a(data);
+}
+__default_hash_string :: proc(s: string) -> u64 {
+	return __default_hash(cast([]byte)s);
 }
 }
 
 
-Map_Key :: struct #ordered {
+__Map_Key :: struct #ordered {
 	hash: u64,
 	hash: u64,
 	str:  string,
 	str:  string,
 }
 }
 
 
-Map_Find_Result :: struct #ordered {
+__Map_Find_Result :: struct #ordered {
 	hash_index:  int,
 	hash_index:  int,
 	entry_prev:  int,
 	entry_prev:  int,
 	entry_index: int,
 	entry_index: int,
 }
 }
 
 
-Map_Entry_Header :: struct #ordered {
-	key:  Map_Key,
+__Map_Entry_Header :: struct #ordered {
+	key:  __Map_Key,
 	next: int,
 	next: int,
 /*
 /*
 	value: Value_Type,
 	value: Value_Type,
 */
 */
 }
 }
 
 
-Map_Header :: struct #ordered {
+__Map_Header :: struct #ordered {
 	m:             ^Raw_Dynamic_Map,
 	m:             ^Raw_Dynamic_Map,
 	is_key_string: bool,
 	is_key_string: bool,
 	entry_size:    int,
 	entry_size:    int,
@@ -468,13 +493,13 @@ Map_Header :: struct #ordered {
 	value_offset:  int,
 	value_offset:  int,
 }
 }
 
 
-__dynamic_map_reserve :: proc(using header: Map_Header, capacity: int) -> bool {
+__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool {
 	h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity);
 	h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity);
 	e := __dynamic_array_reserve(^m.entries, entry_size, entry_align,    capacity);
 	e := __dynamic_array_reserve(^m.entries, entry_size, entry_align,    capacity);
 	return h && e;
 	return h && e;
 }
 }
 
 
-__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) {
+__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
 	new_header := header;
 	new_header := header;
 	nm: Raw_Dynamic_Map;
 	nm: Raw_Dynamic_Map;
 	new_header.m = ^nm;
 	new_header.m = ^nm;
@@ -511,25 +536,27 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) {
 			__dynamic_map_grow(new_header);
 			__dynamic_map_grow(new_header);
 		}
 		}
 	}
 	}
-	free(header.m);
+	free_ptr_with_allocator(header.m.hashes.allocator,  header.m.hashes.data);
+	free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
 	header.m^ = nm;
 	header.m^ = nm;
-
 }
 }
 
 
-__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr {
+__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
 	index := __dynamic_map_find(h, key).entry_index;
 	index := __dynamic_map_find(h, key).entry_index;
 	if index >= 0 {
 	if index >= 0 {
 		data := cast(^byte)__dynamic_map_get_entry(h, index);
 		data := cast(^byte)__dynamic_map_get_entry(h, index);
-		return data + h.value_offset;
+		val := data + h.value_offset;
+		return val;
 	}
 	}
 	return nil;
 	return nil;
 }
 }
 
 
-__dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) {
+__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
+	index: int;
+
 	if m.hashes.count == 0 {
 	if m.hashes.count == 0 {
 		__dynamic_map_grow(h);
 		__dynamic_map_grow(h);
 	}
 	}
-	index: int;
 	fr := __dynamic_map_find(h, key);
 	fr := __dynamic_map_find(h, key);
 	if fr.entry_index >= 0 {
 	if fr.entry_index >= 0 {
 		index = fr.entry_index;
 		index = fr.entry_index;
@@ -544,7 +571,8 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) {
 	}
 	}
 	{
 	{
 		data := cast(^byte)__dynamic_map_get_entry(h, index);
 		data := cast(^byte)__dynamic_map_get_entry(h, index);
-		mem.copy(data+value_offset, value, entry_size-value_offset);
+		val := data+value_offset;
+		mem.copy(val, value, entry_size-value_offset);
 	}
 	}
 
 
 	if __dynamic_map_full(h) {
 	if __dynamic_map_full(h) {
@@ -553,17 +581,17 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) {
 }
 }
 
 
 
 
-__dynamic_map_grow :: proc(using h: Map_Header) {
+__dynamic_map_grow :: proc(using h: __Map_Header) {
 	new_count := 2*m.entries.count + 8;
 	new_count := 2*m.entries.count + 8;
 	__dynamic_map_rehash(h, new_count);
 	__dynamic_map_rehash(h, new_count);
 }
 }
 
 
-__dynamic_map_full :: proc(using h: Map_Header) -> bool {
+__dynamic_map_full :: proc(using h: __Map_Header) -> bool {
 	return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
 	return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
 }
 }
 
 
 
 
-__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool {
+__dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
 	if a.hash == b.hash {
 	if a.hash == b.hash {
 		if h.is_key_string {
 		if h.is_key_string {
 			return a.str == b.str;
 			return a.str == b.str;
@@ -573,8 +601,8 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool {
 	return false;
 	return false;
 }
 }
 
 
-__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result {
-	fr := Map_Find_Result{-1, -1, -1};
+__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
+	fr := __Map_Find_Result{-1, -1, -1};
 	if m.hashes.count > 0 {
 	if m.hashes.count > 0 {
 		fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
 		fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
 		fr.entry_index = m.hashes[fr.hash_index];
 		fr.entry_index = m.hashes[fr.hash_index];
@@ -590,7 +618,7 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result
 	return fr;
 	return fr;
 }
 }
 
 
-__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int {
+__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
 	prev := m.entries.count;
 	prev := m.entries.count;
 	c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
 	c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
 	if c != prev {
 	if c != prev {
@@ -598,23 +626,23 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int {
 		end.key = key;
 		end.key = key;
 		end.next = -1;
 		end.next = -1;
 	}
 	}
-	return c;
+	return prev;
 }
 }
 
 
 
 
-__dynamic_map_remove :: proc(using h: Map_Header, key: Map_Key) {
+__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) {
 	fr := __dynamic_map_find(h, key);
 	fr := __dynamic_map_find(h, key);
 	if fr.entry_index >= 0 {
 	if fr.entry_index >= 0 {
 		__dynamic_map_erase(h, fr);
 		__dynamic_map_erase(h, fr);
 	}
 	}
 }
 }
 
 
-__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
+__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
 	data := cast(^byte)m.entries.data + index*entry_size;
 	data := cast(^byte)m.entries.data + index*entry_size;
-	return cast(^Map_Entry_Header)data;
+	return cast(^__Map_Entry_Header)data;
 }
 }
 
 
-__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) {
+__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
 	if fr.entry_prev < 0 {
 	if fr.entry_prev < 0 {
 		m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
 		m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
 	} else {
 	} else {

+ 54 - 6
core/fmt.odin

@@ -142,10 +142,13 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		if info.params == nil {
 		if info.params == nil {
 			buffer_write_string(buf, "()");
 			buffer_write_string(buf, "()");
 		} else {
 		} else {
-			count := (cast(^Tuple)info.params).fields.count;
-			if count == 1 { buffer_write_string(buf, "("); }
-			buffer_write_type(buf, info.params);
-			if count == 1 { buffer_write_string(buf, ")"); }
+			fields := (cast(^Tuple)info.params).fields;
+			buffer_write_string(buf, "(");
+			for f, i in fields {
+				if i > 0 { buffer_write_string(buf, ", "); }
+				buffer_write_type(buf, f.type_info);
+			}
+			buffer_write_string(buf, ")");
 		}
 		}
 		if info.results != nil {
 		if info.results != nil {
 			buffer_write_string(buf, " -> ");
 			buffer_write_string(buf, " -> ");
@@ -188,18 +191,30 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		buffer_write_string(buf, "]");
 		buffer_write_string(buf, "]");
 		buffer_write_type(buf, info.elem);
 		buffer_write_type(buf, info.elem);
 
 
+	case Map:
+		buffer_write_string(buf, "map[");
+		buffer_write_type(buf, info.key);
+		buffer_write_byte(buf, ']');
+		buffer_write_type(buf, info.value);
+
 	case Struct:
 	case Struct:
 		buffer_write_string(buf, "struct ");
 		buffer_write_string(buf, "struct ");
 		if info.packed  { buffer_write_string(buf, "#packed "); }
 		if info.packed  { buffer_write_string(buf, "#packed "); }
 		if info.ordered { buffer_write_string(buf, "#ordered "); }
 		if info.ordered { buffer_write_string(buf, "#ordered "); }
-		buffer_write_string(buf, "{");
+		if info.custom_align {
+			buffer_write_string(buf, "#align ");
+			fi := Fmt_Info{buf = buf};
+			fmt_int(^fi, cast(u64)info.align, false, 'd');
+			buffer_write_byte(buf, ' ');
+		}
+		buffer_write_byte(buf, '{');
 		for field, i in info.fields {
 		for field, i in info.fields {
 			buffer_write_string(buf, field.name);
 			buffer_write_string(buf, field.name);
 			buffer_write_string(buf, ": ");
 			buffer_write_string(buf, ": ");
 			buffer_write_type(buf, field.type_info);
 			buffer_write_type(buf, field.type_info);
 			buffer_write_byte(buf, ',');
 			buffer_write_byte(buf, ',');
 		}
 		}
-		buffer_write_string(buf, "}");
+		buffer_write_byte(buf, '}');
 
 
 	case Union:
 	case Union:
 		buffer_write_string(buf, "union {");
 		buffer_write_string(buf, "union {");
@@ -775,6 +790,39 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v');
 			fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v');
 		}
 		}
 
 
+	case Map:
+		if verb != 'v' {
+			fmt_bad_verb(fi, verb);
+			return;
+		}
+
+		buffer_write_string(fi.buf, "map[");
+		defer buffer_write_byte(fi.buf, ']');
+		entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
+		gs, _ := union_cast(^Struct)info.generated_struct;
+		ed, _ := union_cast(^Dynamic_Array)gs.fields[1].type_info;
+		entry_type, _ := union_cast(^Struct)ed.elem;
+		entry_size := ed.elem_size;
+		for i in 0..<entries.count {
+			if i > 0 {
+				buffer_write_string(fi.buf, ", ");
+			}
+			data := cast(^byte)entries.data + i*entry_size;
+
+			header := cast(^__Map_Entry_Header)data;
+			if types.is_string(info.key) {
+				buffer_write_string(fi.buf, header.key.str);
+			} else {
+				fi := Fmt_Info{buf = fi.buf};
+				fmt_arg(^fi, any{info.key, cast(rawptr)^header.key.hash}, 'v');
+			}
+
+			buffer_write_string(fi.buf, "=");
+
+			value := data + entry_type.fields[2].offset;
+			fmt_arg(fi, any{info.value, cast(rawptr)value}, 'v');
+		}
+
 	case Slice:
 	case Slice:
 		if verb != 'v' {
 		if verb != 'v' {
 			fmt_bad_verb(fi, verb);
 			fmt_bad_verb(fi, verb);

+ 1 - 1
src/check_decl.c

@@ -63,7 +63,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
 	// an extra allocation
 	// an extra allocation
 	ArrayOperand operands = {0};
 	ArrayOperand operands = {0};
 	array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
 	array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
-	check_unpack_arguments(c, &operands, inits);
+	check_unpack_arguments(c, lhs_count, &operands, inits, true);
 
 
 	isize rhs_count = operands.count;
 	isize rhs_count = operands.count;
 	for_array(i, operands) {
 	for_array(i, operands) {

+ 61 - 22
src/check_expr.c

@@ -1097,8 +1097,8 @@ Type *make_map_tuple_type(gbAllocator a, Type *value) {
 	Type *t = make_type_tuple(a);
 	Type *t = make_type_tuple(a);
 	t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
 	t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
 	t->Tuple.variable_count = 2;
 	t->Tuple.variable_count = 2;
-	t->Tuple.variables[0] = make_entity_param(a, NULL, blank_token, value,  false, false);
-	t->Tuple.variables[1] = make_entity_param(a, NULL, blank_token, t_bool, false, false);
+	t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value,  false, 0);
+	t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1);
 	return t;
 	return t;
 }
 }
 
 
@@ -1132,11 +1132,17 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 	gbAllocator a = c->allocator;
 	gbAllocator a = c->allocator;
 
 
 	{
 	{
+		// NOTE(bill): The preload types may have not been set yet
+		if (t_map_key == NULL) {
+			init_preload(c);
+		}
+		GB_ASSERT(t_map_key != NULL);
+
 		Type *entry_type = make_type_struct(a);
 		Type *entry_type = make_type_struct(a);
 
 
 		/*
 		/*
 		struct {
 		struct {
-			hash:  u64,
+			hash:  Map_Key,
 			next:  int,
 			next:  int,
 			key:   Key_Type,
 			key:   Key_Type,
 			value: Value_Type,
 			value: Value_Type,
@@ -1148,9 +1154,9 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 
 
 		isize field_count = 3;
 		isize field_count = 3;
 		Entity **fields = gb_alloc_array(a, Entity *, field_count);
 		Entity **fields = gb_alloc_array(a, Entity *, field_count);
-		fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")),   t_u64, false, false);
-		fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")),  t_int, false, false);
-		fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, false);
+		fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")),   t_map_key, false, 0);
+		fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")),  t_int,     false, 1);
+		fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value,     false, 2);
 
 
 		check_close_scope(c);
 		check_close_scope(c);
 
 
@@ -1159,7 +1165,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 		entry_type->Record.field_count         = field_count;
 		entry_type->Record.field_count         = field_count;
 
 
 		type_set_offsets(c->sizes, a, entry_type);
 		type_set_offsets(c->sizes, a, entry_type);
-
 		type->Map.entry_type = entry_type;
 		type->Map.entry_type = entry_type;
 	}
 	}
 
 
@@ -1181,8 +1186,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 
 
 		isize field_count = 2;
 		isize field_count = 2;
 		Entity **fields = gb_alloc_array(a, Entity *, field_count);
 		Entity **fields = gb_alloc_array(a, Entity *, field_count);
-		fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")),  hashes_type,  false, false);
-		fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, false);
+		fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0);
+		fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, 1);
 
 
 		check_close_scope(c);
 		check_close_scope(c);
 
 
@@ -1191,7 +1196,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 		generated_struct_type->Record.field_count         = field_count;
 		generated_struct_type->Record.field_count         = field_count;
 
 
 		type_set_offsets(c->sizes, a, generated_struct_type);
 		type_set_offsets(c->sizes, a, generated_struct_type);
-
 		type->Map.generated_struct_type = generated_struct_type;
 		type->Map.generated_struct_type = generated_struct_type;
 	}
 	}
 
 
@@ -2676,7 +2680,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		gbString op_str   = expr_to_string(op_expr);
 		gbString op_str   = expr_to_string(op_expr);
 		gbString type_str = type_to_string(operand->type);
 		gbString type_str = type_to_string(operand->type);
 		gbString sel_str  = expr_to_string(selector);
 		gbString sel_str  = expr_to_string(selector);
-		error_node(op_expr, "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
+		error_node(op_expr, "`%s` of type `%s` has no field `%s`", op_str, type_str, sel_str);
 		gb_string_free(sel_str);
 		gb_string_free(sel_str);
 		gb_string_free(type_str);
 		gb_string_free(type_str);
 		gb_string_free(op_str);
 		gb_string_free(op_str);
@@ -2885,14 +2889,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		Type *type = operand->type;
 		Type *type = operand->type;
 		if (!is_type_pointer(type)) {
 		if (!is_type_pointer(type)) {
 			gbString str = type_to_string(type);
 			gbString str = type_to_string(type);
-			error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
+			error_node(operand->expr, "Expected a pointer, got `%s`", str);
 			gb_string_free(str);
 			gb_string_free(str);
 			return false;
 			return false;
 		}
 		}
 		type = type_deref(type);
 		type = type_deref(type);
-		if (!is_type_dynamic_array(type)) {
+		if (!is_type_dynamic_array(type) && !is_type_map(type)) {
 			gbString str = type_to_string(type);
 			gbString str = type_to_string(type);
-			error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
+			error_node(operand->expr, "Expected a pointer to a map or dynamic array, got `%s`", str);
 			gb_string_free(str);
 			gb_string_free(str);
 			return false;
 			return false;
 		}
 		}
@@ -3824,18 +3828,28 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
 
 
 typedef Array(Operand) ArrayOperand;
 typedef Array(Operand) ArrayOperand;
 
 
-void check_unpack_arguments(Checker *c, ArrayOperand *operands, AstNodeArray args) {
+void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) {
 	for_array(i, args) {
 	for_array(i, args) {
 		Operand o = {0};
 		Operand o = {0};
 		check_multi_expr(c, &o, args.e[i]);
 		check_multi_expr(c, &o, args.e[i]);
 
 
-		if (o.mode == Addressing_MapIndex) {
-			Type *tuple_type = make_map_tuple_type(c->allocator, o.type);
-			add_type_and_value(&c->info, o.expr, o.mode, tuple_type, (ExactValue){0});
-			o.type = tuple_type;
-		}
-
 		if (o.type == NULL || o.type->kind != Type_Tuple) {
 		if (o.type == NULL || o.type->kind != Type_Tuple) {
+			if (o.mode == Addressing_MapIndex &&
+			    allow_map_ok &&
+			    lhs_count == 2 &&
+			    args.count == 1) {
+				Type *tuple = make_map_tuple_type(c->allocator, o.type);
+				add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
+
+				Operand val = o;
+				Operand ok = o;
+				val.mode = Addressing_Value;
+				ok.mode  = Addressing_Value;
+				ok.type  = t_bool;
+				array_add(operands, val);
+				array_add(operands, ok);
+				continue;
+			}
 			array_add(operands, o);
 			array_add(operands, o);
 		} else {
 		} else {
 			TypeTuple *tuple = &o.type->Tuple;
 			TypeTuple *tuple = &o.type->Tuple;
@@ -3854,7 +3868,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 
 
 	ArrayOperand operands;
 	ArrayOperand operands;
 	array_init_reserve(&operands, heap_allocator(), 2*ce->args.count);
 	array_init_reserve(&operands, heap_allocator(), 2*ce->args.count);
-	check_unpack_arguments(c, &operands, ce->args);
+	check_unpack_arguments(c, -1, &operands, ce->args, false);
 
 
 	if (operand->mode == Addressing_Overload) {
 	if (operand->mode == Addressing_Overload) {
 		GB_ASSERT(operand->overload_entities != NULL &&
 		GB_ASSERT(operand->overload_entities != NULL &&
@@ -4740,6 +4754,31 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			}
 			}
 		} break;
 		} break;
 
 
+		case Type_Map: {
+			if (cl->elems.count == 0) {
+				break;
+			}
+			is_constant = false;
+			{ // Checker values
+				for_array(i, cl->elems) {
+					AstNode *elem = cl->elems.e[i];
+					if (elem->kind != AstNode_FieldValue) {
+						error_node(elem, "Only `field = value` elements are allowed in a map literal");
+						continue;
+					}
+					ast_node(fv, FieldValue, elem);
+					check_expr_with_type_hint(c, o, fv->field, t->Map.key);
+					check_assignment(c, o, t->Map.key, str_lit("map literal"));
+					if (o->mode == Addressing_Invalid) {
+						continue;
+					}
+
+					check_expr_with_type_hint(c, o, fv->value, t->Map.value);
+					check_assignment(c, o, t->Map.value, str_lit("map literal"));
+				}
+			}
+		} break;
+
 		default: {
 		default: {
 			gbString str = type_to_string(type);
 			gbString str = type_to_string(type);
 			error_node(node, "Invalid compound literal type `%s`", str);
 			error_node(node, "Invalid compound literal type `%s`", str);

+ 7 - 2
src/check_stmt.c

@@ -256,11 +256,11 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 		e->flags |= EntityFlag_Used;
 		e->flags |= EntityFlag_Used;
 	}
 	}
 
 
+	Type *assignment_type = op_b.type;
 	switch (op_b.mode) {
 	switch (op_b.mode) {
 	case Addressing_Invalid:
 	case Addressing_Invalid:
 		return NULL;
 		return NULL;
 	case Addressing_Variable:
 	case Addressing_Variable:
-		break;
 	case Addressing_MapIndex:
 	case Addressing_MapIndex:
 		break;
 		break;
 	default: {
 	default: {
@@ -287,7 +287,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	} break;
 	} break;
 	}
 	}
 
 
-	check_assignment(c, op_a, op_b.type, str_lit("assignment"));
+	check_assignment(c, op_a, assignment_type, str_lit("assignment"));
 	if (op_a->mode == Addressing_Invalid) {
 	if (op_a->mode == Addressing_Invalid) {
 		return NULL;
 		return NULL;
 	}
 	}
@@ -719,6 +719,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					val = t->Vector.elem;
 					val = t->Vector.elem;
 					idx = t_int;
 					idx = t_int;
 					break;
 					break;
+
+				case Type_Map:
+					val = t->Map.value;
+					idx = t->Map.key;
+					break;
 				}
 				}
 			}
 			}
 
 

+ 11 - 3
src/checker.c

@@ -958,6 +958,12 @@ void add_type_info_type(Checker *c, Type *t) {
 		}
 		}
 	} break;
 	} break;
 
 
+	case Type_Map: {
+		add_type_info_type(c, bt->Map.key);
+		add_type_info_type(c, bt->Map.value);
+		add_type_info_type(c, bt->Map.generated_struct_type);
+	} break;
+
 	case Type_Tuple:
 	case Type_Tuple:
 		for (isize i = 0; i < bt->Tuple.variable_count; i++) {
 		for (isize i = 0; i < bt->Tuple.variable_count; i++) {
 			Entity *var = bt->Tuple.variables[i];
 			Entity *var = bt->Tuple.variables[i];
@@ -1093,7 +1099,7 @@ void init_preload(Checker *c) {
 
 
 
 
 
 
-		if (record->field_count != 19) {
+		if (record->field_count != 20) {
 			compiler_error("Invalid `Type_Info` layout");
 			compiler_error("Invalid `Type_Info` layout");
 		}
 		}
 		t_type_info_named         = record->fields[ 1]->type;
 		t_type_info_named         = record->fields[ 1]->type;
@@ -1114,6 +1120,7 @@ void init_preload(Checker *c) {
 		t_type_info_union         = record->fields[16]->type;
 		t_type_info_union         = record->fields[16]->type;
 		t_type_info_raw_union     = record->fields[17]->type;
 		t_type_info_raw_union     = record->fields[17]->type;
 		t_type_info_enum          = record->fields[18]->type;
 		t_type_info_enum          = record->fields[18]->type;
+		t_type_info_map           = record->fields[19]->type;
 
 
 		t_type_info_named_ptr         = make_type_pointer(heap_allocator(), t_type_info_named);
 		t_type_info_named_ptr         = make_type_pointer(heap_allocator(), t_type_info_named);
 		t_type_info_integer_ptr       = make_type_pointer(heap_allocator(), t_type_info_integer);
 		t_type_info_integer_ptr       = make_type_pointer(heap_allocator(), t_type_info_integer);
@@ -1133,6 +1140,7 @@ void init_preload(Checker *c) {
 		t_type_info_union_ptr         = make_type_pointer(heap_allocator(), t_type_info_union);
 		t_type_info_union_ptr         = make_type_pointer(heap_allocator(), t_type_info_union);
 		t_type_info_raw_union_ptr     = make_type_pointer(heap_allocator(), t_type_info_raw_union);
 		t_type_info_raw_union_ptr     = make_type_pointer(heap_allocator(), t_type_info_raw_union);
 		t_type_info_enum_ptr          = make_type_pointer(heap_allocator(), t_type_info_enum);
 		t_type_info_enum_ptr          = make_type_pointer(heap_allocator(), t_type_info_enum);
+		t_type_info_map_ptr           = make_type_pointer(heap_allocator(), t_type_info_map);
 	}
 	}
 
 
 	if (t_allocator == NULL) {
 	if (t_allocator == NULL) {
@@ -1155,12 +1163,12 @@ void init_preload(Checker *c) {
 	}
 	}
 
 
 	if (t_map_key == NULL) {
 	if (t_map_key == NULL) {
-		Entity *e = find_core_entity(c, str_lit("Map_Key"));
+		Entity *e = find_core_entity(c, str_lit("__Map_Key"));
 		t_map_key = e->type;
 		t_map_key = e->type;
 	}
 	}
 
 
 	if (t_map_header == NULL) {
 	if (t_map_header == NULL) {
-		Entity *e = find_core_entity(c, str_lit("Map_Header"));
+		Entity *e = find_core_entity(c, str_lit("__Map_Header"));
 		t_map_header = e->type;
 		t_map_header = e->type;
 	}
 	}
 
 

+ 31 - 26
src/gb/gb.h

@@ -58,6 +58,7 @@ TODOS
 	- More date & time functions
 	- More date & time functions
 
 
 VERSION HISTORY
 VERSION HISTORY
+	0.27  - OSX fixes and Linux gbAffinity
 	0.26d - Minor changes to how gbFile works
 	0.26d - Minor changes to how gbFile works
 	0.26c - gb_str_to_f* fix
 	0.26c - gb_str_to_f* fix
 	0.26b - Minor fixes
 	0.26b - Minor fixes
@@ -4990,16 +4991,13 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
 }
 }
 
 
 #elif defined(GB_SYSTEM_LINUX)
 #elif defined(GB_SYSTEM_LINUX)
-#warning gbAffinity is mostly mostly untested on Linux. All I know is that it compiles and runs.
-#warning TODO(bill): gb_affinity_set on Linux is a stub
-
-// I have to read /proc/cpuinfo to get the number of threads per core.
+// IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot!
+// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core.
 #include <stdio.h>
 #include <stdio.h>
 
 
 void gb_affinity_init(gbAffinity *a) {
 void gb_affinity_init(gbAffinity *a) {
-	usize count, count_size = gb_size_of(count);
-
-	b32 accurate = true;
+	b32   accurate = true;
+	isize threads = 0;
 
 
 	a->thread_count     = 1;
 	a->thread_count     = 1;
 	a->core_count       = sysconf(_SC_NPROCESSORS_ONLN);
 	a->core_count       = sysconf(_SC_NPROCESSORS_ONLN);
@@ -5012,37 +5010,43 @@ void gb_affinity_init(gbAffinity *a) {
 	}
 	}
 
 
 	// Parsing /proc/cpuinfo to get the number of threads per core.
 	// Parsing /proc/cpuinfo to get the number of threads per core.
-	// NOTE: This calls the CPU's threads "cores", although the wording
-	//   is kind of weird. This should be right, though.
-	FILE* cpu_info = fopen("/proc/cpuinfo", "r");
-
-	int threads = 0;
-
-	if(cpu_info) {
-		while(1) {
+	// NOTE(zangent): This calls the CPU's threads "cores", although the wording
+	// is kind of weird. This should be right, though.
+	if (fopen("/proc/cpuinfo", "r") != NULL) {
+		for (;;) {
 			// The 'temporary char'. Everything goes into this char,
 			// The 'temporary char'. Everything goes into this char,
 			// so that we can check against EOF at the end of this loop.
 			// so that we can check against EOF at the end of this loop.
 			char c;
 			char c;
 
 
-			#define check(letter) ((c = getc(cpu_info)) == letter)
-			if(check('c') && check('p') && check('u') && check(' ') &&
-				check('c') && check('o') && check('r') && check('e') && check('s')) {
+#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter)
+			if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') &&
+			    AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) {
 				// We're on a CPU info line.
 				// We're on a CPU info line.
-				while(!check(EOF)) {
-					if(c == '\n') break;
-					else if(c < '0' || c > '9') continue;
+				while (!AF__CHECK(EOF)) {
+					if (c == '\n') {
+						break;
+					} else if (c < '0' || '9' > c) {
+						continue;
+					}
 					threads = threads * 10 + (c - '0');
 					threads = threads * 10 + (c - '0');
 				}
 				}
 				break;
 				break;
 			} else {
 			} else {
-				while(!check('\n')) {if(c==EOF) break;}
+				while (!AF__CHECK('\n')) {
+					if (c==EOF) {
+						break;
+					}
+				}
 			}
 			}
-			if(c == EOF) break;
+			if (c == EOF) {
+				break;
+			}
+#undef AF__CHECK
 		}
 		}
 	}
 	}
 
 
-	if(threads == 0) {
-		threads = 1;
+	if (threads == 0) {
+		threads  = 1;
 		accurate = false;
 		accurate = false;
 	}
 	}
 
 
@@ -5062,7 +5066,8 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
 }
 }
 
 
 isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
 isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
-	GB_ASSERT(core >= 0 && core < a->core_count);
+
+	GB_ASSERT(0 <= core && core < a->core_count);
 	return a->threads_per_core;
 	return a->threads_per_core;
 }
 }
 #else
 #else

+ 203 - 70
src/ir.c

@@ -372,6 +372,7 @@ typedef struct irAddr {
 		struct {
 		struct {
 			irValue *map_key;
 			irValue *map_key;
 			Type *   map_type;
 			Type *   map_type;
+			Type *   map_result;
 		};
 		};
 	};
 	};
 	// union {
 	// union {
@@ -384,10 +385,11 @@ irAddr ir_make_addr(irValue *addr) {
 	return v;
 	return v;
 }
 }
 
 
-irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type) {
+irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) {
 	irAddr v = {irAddr_Map, addr};
 	irAddr v = {irAddr_Map, addr};
-	v.map_key  = map_key;
-	v.map_type = map_type;
+	v.map_key    = map_key;
+	v.map_type   = map_type;
+	v.map_result = map_result;
 	return v;
 	return v;
 }
 }
 
 
@@ -589,23 +591,6 @@ Type *ir_type(irValue *value) {
 	return NULL;
 	return NULL;
 }
 }
 
 
-Type *ir_addr_type(irAddr addr) {
-	if (addr.addr == NULL) {
-		return NULL;
-	}
-
-	if (addr.kind == irAddr_Map) {
-		Type *t = base_type(addr.map_type);
-		GB_ASSERT(is_type_map(t));
-		return t->Map.value;
-	}
-
-	Type *t = ir_type(addr.addr);
-	GB_ASSERT(is_type_pointer(t));
-	return type_deref(t);
-}
-
-
 
 
 bool ir_is_blank_ident(AstNode *node) {
 bool ir_is_blank_ident(AstNode *node) {
 	if (node->kind == AstNode_Ident) {
 	if (node->kind == AstNode_Ident) {
@@ -990,6 +975,9 @@ irValue *ir_make_const_i32(gbAllocator a, i64 i) {
 irValue *ir_make_const_i64(gbAllocator a, i64 i) {
 irValue *ir_make_const_i64(gbAllocator a, i64 i) {
 	return ir_make_value_constant(a, t_i64, make_exact_value_integer(i));
 	return ir_make_value_constant(a, t_i64, make_exact_value_integer(i));
 }
 }
+irValue *ir_make_const_u64(gbAllocator a, u64 i) {
+	return ir_make_value_constant(a, t_u64, make_exact_value_integer(i));
+}
 irValue *ir_make_const_f32(gbAllocator a, f32 f) {
 irValue *ir_make_const_f32(gbAllocator a, f32 f) {
 	return ir_make_value_constant(a, t_f32, make_exact_value_float(f));
 	return ir_make_value_constant(a, t_f32, make_exact_value_float(f));
 }
 }
@@ -1398,12 +1386,16 @@ void ir_emit_startup_runtime(irProcedure *proc) {
 	ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
 	ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
 }
 }
 
 
+irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
+	return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
+}
+
 
 
 irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
 irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
 irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right);
 irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right);
 
 
 irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) {
 irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) {
-	GB_ASSERT(is_type_pointer(ir_type(map_val)));
+	GB_ASSERT_MSG(is_type_pointer(ir_type(map_val)), "%s", type_to_string(ir_type(map_val)));
 	gbAllocator a = proc->module->allocator;
 	gbAllocator a = proc->module->allocator;
 	irValue *h = ir_add_local_generated(proc, t_map_header);
 	irValue *h = ir_add_local_generated(proc, t_map_header);
 
 
@@ -1431,17 +1423,43 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type)
 	return ir_emit_load(proc, h);
 	return ir_emit_load(proc, h);
 }
 }
 
 
-irValue *ir_gen_map_key(irProcedure *proc, irValue *key) {
+irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
 	irValue *v = ir_add_local_generated(proc, t_map_key);
 	irValue *v = ir_add_local_generated(proc, t_map_key);
-	irValue *hash = ir_emit_struct_ep(proc, v, 0);
 	Type *t = base_type(ir_type(key));
 	Type *t = base_type(ir_type(key));
+	key = ir_emit_conv(proc, key, key_type);
 	if (is_type_integer(t)) {
 	if (is_type_integer(t)) {
-		ir_emit_store(proc, hash, ir_emit_conv(proc, key, t_u64));
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, t_u64));
 	} else if (is_type_pointer(t)) {
 	} else if (is_type_pointer(t)) {
 		irValue *p = ir_emit_conv(proc, key, t_uint);
 		irValue *p = ir_emit_conv(proc, key, t_uint);
-		ir_emit_store(proc, hash, ir_emit_conv(proc, p, t_u64));
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64));
+	} else if (is_type_float(t)) {
+		irValue *bits = NULL;
+		i64 size = type_size_of(proc->module->sizes, proc->module->allocator, t);
+		switch (8*size) {
+		case 32: bits = ir_emit_bitcast(proc, key, t_u32); break;
+		case 64: bits = ir_emit_bitcast(proc, key, t_u64); break;
+		default: GB_PANIC("Unhandled float size: %lld bits", size); break;
+		}
+
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, t_u64));
+	} else if (is_type_string(t)) {
+		irValue *str = ir_emit_conv(proc, key, t_string);
+		irValue *hashed_str = NULL;
+
+		if (str->kind == irValue_Constant) {
+			ExactValue ev = str->Constant.value;
+			GB_ASSERT(ev.kind == ExactValue_String);
+			u64 hs = gb_fnv64a(ev.value_string.text, ev.value_string.len);
+			hashed_str = ir_make_const_u64(proc->module->allocator, hs);
+		} else {
+			irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1);
+			args[0] = str;
+			hashed_str = ir_emit_global_call(proc, "__default_hash_string", args, 1);
+		}
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str);
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str);
 	} else {
 	} else {
-		GB_PANIC("TODO(bill): Map Key type");
+		GB_PANIC("Unhandled map key type");
 	}
 	}
 
 
 	return ir_emit_load(proc, v);
 	return ir_emit_load(proc, v);
@@ -1461,35 +1479,51 @@ irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val)
 }
 }
 
 
 
 
-irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
+Type *ir_addr_type(irAddr addr) {
 	if (addr.addr == NULL) {
 	if (addr.addr == NULL) {
 		return NULL;
 		return NULL;
 	}
 	}
+
 	if (addr.kind == irAddr_Map) {
 	if (addr.kind == irAddr_Map) {
-		Type *map_type = base_type(addr.map_type);
-		irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
-		irValue *key = ir_gen_map_key(proc, addr.map_key);
-		irValue *ptr =ir_address_from_load_or_generate_local(proc, value);
-		ptr = ir_emit_conv(proc, ptr, t_rawptr);
+		Type *t = base_type(addr.map_type);
+		GB_ASSERT(is_type_map(t));
+		return t->Map.value;
+	}
 
 
-		irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
-		args[0] = h;
-		args[1] = key;
-		args[2] = ptr;
+	Type *t = ir_type(addr.addr);
+	GB_ASSERT(is_type_pointer(t));
+	return type_deref(t);
+}
+
+irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
+                                     irValue *map_key, irValue *map_value) {
+	map_type = base_type(map_type);
+
+	irValue *h = ir_gen_map_header(proc, addr, map_type);
+	irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key);
+	irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value);
+	irValue *ptr = ir_address_from_load_or_generate_local(proc, v);
+	ptr = ir_emit_conv(proc, ptr, t_rawptr);
+
+	irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
+	args[0] = h;
+	args[1] = key;
+	args[2] = ptr;
+
+	return ir_emit_global_call(proc, "__dynamic_map_set", args, 3);
+}
 
 
-		return ir_emit_global_call(proc, "__dynamic_map_set", args, 3);
+
+irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
+	if (addr.addr == NULL) {
+		return NULL;
+	}
+	if (addr.kind == irAddr_Map) {
+		return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value);
 	}
 	}
 
 
-	// if (addr.kind == irAddr_Vector) {
-		// irValue *v = ir_emit_load(proc, addr.addr);
-		// Type *elem_type = base_type(ir_type(v))->Vector.elem;
-		// irValue *elem = ir_emit_conv(proc, value, elem_type);
-		// irValue *out = ir_emit(proc, ir_make_instr_insert_element(proc, v, elem, addr.Vector.index));
-		// return ir_emit_store(proc, addr.addr, out);
-	// } else {
-		irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr));
-		return ir_emit_store(proc, addr.addr, v);
-	// }
+	irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr));
+	return ir_emit_store(proc, addr.addr, v);
 }
 }
 
 
 irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
 irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
@@ -1503,7 +1537,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
 		Type *map_type = base_type(addr.map_type);
 		Type *map_type = base_type(addr.map_type);
 		irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type);
 		irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type);
 		irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
 		irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
-		irValue *key = ir_gen_map_key(proc, addr.map_key);
+		irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key);
 
 
 		irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2);
 		irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2);
 		args[0] = h;
 		args[0] = h;
@@ -1527,7 +1561,12 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
 		ir_start_block(proc, done);
 		ir_start_block(proc, done);
 
 
 
 
-		return ir_emit_load(proc, v);
+		if (is_type_tuple(addr.map_result)) {
+			return ir_emit_load(proc, v);
+		} else {
+			irValue *single = ir_emit_struct_ep(proc, v, 0);
+			return ir_emit_load(proc, single);
+		}
 	}
 	}
 
 
 	// if (addr.kind == irAddr_Vector) {
 	// if (addr.kind == irAddr_Vector) {
@@ -1886,6 +1925,13 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec
 			e = ir_emit_array_epi(proc, e, index);
 			e = ir_emit_array_epi(proc, e, index);
 		} else if (type->kind == Type_Array) {
 		} else if (type->kind == Type_Array) {
 			e = ir_emit_array_epi(proc, e, index);
 			e = ir_emit_array_epi(proc, e, index);
+		} else if (type->kind == Type_Map) {
+			e = ir_emit_struct_ep(proc, e, 1);
+			switch (index) {
+			case 0: e = ir_emit_struct_ep(proc, e, 1); break; // count
+			case 1: e = ir_emit_struct_ep(proc, e, 2); break; // capacity
+			case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator
+			}
 		} else {
 		} else {
 			GB_PANIC("un-gep-able type");
 			GB_PANIC("un-gep-able type");
 		}
 		}
@@ -1912,6 +1958,13 @@ irValue *ir_emit_deep_field_ev(irProcedure *proc, Type *type, irValue *e, Select
 			GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
 			GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
 			type = type->Record.fields[index]->type;
 			type = type->Record.fields[index]->type;
 			e = ir_emit_conv(proc, e, type);
 			e = ir_emit_conv(proc, e, type);
+		} else if (type->kind == Type_Map) {
+			e = ir_emit_struct_ev(proc, e, 1);
+			switch (index) {
+			case 0: e = ir_emit_struct_ev(proc, e, 1); break; // count
+			case 1: e = ir_emit_struct_ev(proc, e, 2); break; // capacity
+			case 2: e = ir_emit_struct_ev(proc, e, 3); break; // allocator
+			}
 		} else {
 		} else {
 			e = ir_emit_struct_ev(proc, e, index);
 			e = ir_emit_struct_ev(proc, e, index);
 		}
 		}
@@ -2068,9 +2121,6 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
 	return str_lit("");
 	return str_lit("");
 }
 }
 
 
-irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
-	return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
-}
 
 
 
 
 irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
@@ -2977,7 +3027,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 
 
 
 	case_ast_node(cl, CompoundLit, expr);
 	case_ast_node(cl, CompoundLit, expr);
-		return ir_emit_load(proc, ir_build_addr(proc, expr).addr);
+		return ir_addr_load(proc, ir_build_addr(proc, expr));
 	case_end;
 	case_end;
 
 
 
 
@@ -3159,9 +3209,19 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 
 				case BuiltinProc_clear: {
 				case BuiltinProc_clear: {
 					ir_emit_comment(proc, str_lit("reserve"));
 					ir_emit_comment(proc, str_lit("reserve"));
-					irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
-					irValue *count_ptr = ir_emit_struct_ep(proc, array_ptr, 1);
-					ir_emit_store(proc, count_ptr, v_zero);
+					irValue *ptr = ir_build_expr(proc, ce->args.e[0]);
+					Type *t = base_type(type_deref(ir_type(ptr)));
+					if (is_type_dynamic_array(t)) {
+						irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
+						ir_emit_store(proc, count_ptr, v_zero);
+					} else if (is_type_dynamic_map(t)) {
+						irValue *ha = ir_emit_struct_ep(proc, ptr, 0);
+						irValue *ea = ir_emit_struct_ep(proc, ptr, 1);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero);
+						ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero);
+					} else {
+						GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t));
+					}
 					return NULL;
 					return NULL;
 				} break;
 				} break;
 
 
@@ -3537,11 +3597,11 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 	case_end;
 	case_end;
 
 
 	case_ast_node(de, DemaybeExpr, expr);
 	case_ast_node(de, DemaybeExpr, expr);
-		return ir_emit_load(proc, ir_build_addr(proc, expr).addr);
+		return ir_addr_load(proc, ir_build_addr(proc, expr));
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, SliceExpr, expr);
 	case_ast_node(se, SliceExpr, expr);
-		return ir_emit_load(proc, ir_build_addr(proc, expr).addr);
+		return ir_addr_load(proc, ir_build_addr(proc, expr));
 	case_end;
 	case_end;
 
 
 	case_ast_node(ie, IndexExpr, expr);
 	case_ast_node(ie, IndexExpr, expr);
@@ -3764,21 +3824,17 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		Type *t = base_type(type_of_expr(proc->module->info, ie->expr));
 		Type *t = base_type(type_of_expr(proc->module->info, ie->expr));
 		gbAllocator a = proc->module->allocator;
 		gbAllocator a = proc->module->allocator;
 
 
-
 		bool deref = is_type_pointer(t);
 		bool deref = is_type_pointer(t);
 		t = base_type(type_deref(t));
 		t = base_type(type_deref(t));
 
 
 		if (is_type_map(t)) {
 		if (is_type_map(t)) {
 			irAddr map_addr = ir_build_addr(proc, ie->expr);
 			irAddr map_addr = ir_build_addr(proc, ie->expr);
 			irValue *map_val = map_addr.addr;
 			irValue *map_val = map_addr.addr;
-			if (deref) {
-				map_val = ir_addr_load(proc, map_addr);
-			}
-
 			irValue *key = ir_build_expr(proc, ie->index);
 			irValue *key = ir_build_expr(proc, ie->index);
 			key = ir_emit_conv(proc, key, t->Map.key);
 			key = ir_emit_conv(proc, key, t->Map.key);
 
 
-			return ir_make_addr_map(map_val, key, t);
+			Type *result_type = type_of_expr(proc->module->info, expr);
+			return ir_make_addr_map(map_val, key, t, result_type);
 		}
 		}
 
 
 		irValue *using_addr = NULL;
 		irValue *using_addr = NULL;
@@ -4127,6 +4183,28 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 				}
 				}
 			}
 			}
 		} break;
 		} break;
+
+		case Type_Map: {
+			if (cl->elems.count == 0) {
+				break;
+			}
+			gbAllocator a = proc->module->allocator;
+			{
+				irValue **args = gb_alloc_array(a, irValue *, 4);
+				args[0] = ir_gen_map_header(proc, v, type);
+				args[1] = ir_make_const_int(a, 2*cl->elems.count);
+				ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
+			}
+			for_array(field_index, cl->elems) {
+				AstNode *elem = cl->elems.e[field_index];
+				ast_node(fv, FieldValue, elem);
+
+				irValue *key   = ir_build_expr(proc, fv->field);
+				irValue *value = ir_build_expr(proc, fv->value);
+				ir_insert_dynamic_map_key_and_value(proc, v, type, key, value);
+			}
+		} break;
+
 		case Type_Array: {
 		case Type_Array: {
 			if (cl->elems.count > 0) {
 			if (cl->elems.count > 0) {
 				ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
 				ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
@@ -4346,6 +4424,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr) {
 
 
 }
 }
 
 
+
 void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr,
 void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr,
                             irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) {
                             irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) {
 	irValue *count = NULL;
 	irValue *count = NULL;
@@ -4365,6 +4444,11 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
 	irBlock *done = NULL;
 	irBlock *done = NULL;
 	irBlock *body = NULL;
 	irBlock *body = NULL;
 
 
+	irValue *key = NULL;
+	if (expr_type->kind == Type_Map) {
+		key = ir_add_local_generated(proc, expr_type->Map.key);
+	}
+
 	irValue *index = ir_add_local_generated(proc, t_int);
 	irValue *index = ir_add_local_generated(proc, t_int);
 	ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, -1));
 	ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, -1));
 
 
@@ -4401,6 +4485,26 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
 			irValue *elem = ir_emit_struct_ep(proc, expr, 0);
 			irValue *elem = ir_emit_struct_ep(proc, expr, 0);
 			elem = ir_emit_load(proc, elem);
 			elem = ir_emit_load(proc, elem);
 			val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
 			val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
+		} break;
+		case Type_Map: {
+			irValue *entries = ir_emit_struct_ep(proc, expr, 1);
+			irValue *elem = ir_emit_struct_ep(proc, entries, 0);
+			elem = ir_emit_load(proc, elem);
+
+			irValue *entry = ir_emit_ptr_offset(proc, elem, idx);
+			val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2));
+
+			irValue *hash = ir_emit_struct_ep(proc, entry, 0);
+			if (is_type_string(expr_type->Map.key)) {
+				irValue *str = ir_emit_struct_ep(proc, hash, 1);
+				ir_emit_store(proc, key, ir_emit_load(proc, str));
+			} else {
+				irValue *hash_ptr = ir_emit_struct_ep(proc, hash, 0);
+				hash_ptr = ir_emit_conv(proc, hash_ptr, ir_type(key));
+				ir_emit_store(proc, key, ir_emit_load(proc, hash_ptr));
+			}
+
+
 		} break;
 		} break;
 		default:
 		default:
 			GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type));
 			GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type));
@@ -4408,6 +4512,10 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
 		}
 		}
 	}
 	}
 
 
+	if (key != NULL) {
+		idx = ir_emit_load(proc, key);
+	}
+
 	if (val_)  *val_  = val;
 	if (val_)  *val_  = val;
 	if (idx_)  *idx_  = idx;
 	if (idx_)  *idx_  = idx;
 	if (loop_) *loop_ = loop;
 	if (loop_) *loop_ = loop;
@@ -4598,8 +4706,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 					if (lvals.e[i].addr == NULL) {
 					if (lvals.e[i].addr == NULL) {
 						continue;
 						continue;
 					}
 					}
-					irValue *v = ir_emit_conv(proc, inits.e[i], ir_addr_type(lvals.e[i]));
-					ir_addr_store(proc, lvals.e[i], v);
+					ir_addr_store(proc, lvals.e[i], inits.e[i]);
 				}
 				}
 			}
 			}
 
 
@@ -4957,6 +5064,16 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			Type *expr_type = type_of_expr(proc->module->info, rs->expr);
 			Type *expr_type = type_of_expr(proc->module->info, rs->expr);
 			Type *et = base_type(type_deref(expr_type));
 			Type *et = base_type(type_deref(expr_type));
 			switch (et->kind) {
 			switch (et->kind) {
+			case Type_Map: {
+				irAddr addr = ir_build_addr(proc, rs->expr);
+				irValue *map = addr.addr;
+				if (is_type_pointer(type_deref(ir_addr_type(addr)))) {
+					map = ir_addr_load(proc, addr);
+				}
+				irValue *entries_ptr = ir_emit_struct_ep(proc, map, 1);
+				irValue *count_ptr = ir_emit_struct_ep(proc, entries_ptr, 1);
+				ir_build_range_indexed(proc, map, val_type, count_ptr, &val, &index, &loop, &done);
+			} break;
 			case Type_Array: {
 			case Type_Array: {
 				irValue *count_ptr = NULL;
 				irValue *count_ptr = NULL;
 				irValue *array = ir_build_addr(proc, rs->expr).addr;
 				irValue *array = ir_build_addr(proc, rs->expr).addr;
@@ -6164,14 +6281,16 @@ void ir_gen_tree(irGen *s) {
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
 
 
 						{
 						{
-							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 *size    = ir_make_const_int(a, type_size_of(m->sizes, a, t));
-							irValue *align   = ir_make_const_int(a, type_align_of(m->sizes, a, t));
+							irValue *size         = ir_make_const_int(a,  type_size_of(m->sizes, a, t));
+							irValue *align        = ir_make_const_int(a,  type_align_of(m->sizes, a, t));
+							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, 1), size);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), size);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), align);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), align);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), packed);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), packed);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ordered);
 							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ordered);
+							ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), custom_align);
 						}
 						}
 
 
 						irValue *memory = ir_type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
 						irValue *memory = ir_type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
@@ -6394,6 +6513,20 @@ void ir_gen_tree(irGen *s) {
 
 
 					// TODO(bill): Type_Info for procedures
 					// TODO(bill): Type_Info for procedures
 				} break;
 				} break;
+
+				case Type_Map: {
+					tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr);
+
+					irValue *key              = ir_emit_struct_ep(proc, tag, 0);
+					irValue *value            = ir_emit_struct_ep(proc, tag, 1);
+					irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2);
+					irValue *count            = ir_emit_struct_ep(proc, tag, 3);
+
+					ir_emit_store(proc, key,              ir_get_type_info_ptr(proc, type_info_data, t->Map.key));
+					ir_emit_store(proc, value,            ir_get_type_info_ptr(proc, type_info_data, t->Map.value));
+					ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, type_info_data, t->Map.generated_struct_type));
+					ir_emit_store(proc, count,            ir_make_const_int(a, t->Map.count));
+				} break;
 				}
 				}
 
 
 				if (tag != NULL) {
 				if (tag != NULL) {

+ 1 - 0
src/parser.c

@@ -1854,6 +1854,7 @@ bool is_literal_type(AstNode *node) {
 	case AstNode_ArrayType:
 	case AstNode_ArrayType:
 	case AstNode_VectorType:
 	case AstNode_VectorType:
 	case AstNode_StructType:
 	case AstNode_StructType:
+	case AstNode_MapType:
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;

+ 47 - 5
src/types.c

@@ -300,6 +300,7 @@ gb_global Type *t_type_info_struct        = NULL;
 gb_global Type *t_type_info_union         = NULL;
 gb_global Type *t_type_info_union         = NULL;
 gb_global Type *t_type_info_raw_union     = NULL;
 gb_global Type *t_type_info_raw_union     = NULL;
 gb_global Type *t_type_info_enum          = NULL;
 gb_global Type *t_type_info_enum          = NULL;
+gb_global Type *t_type_info_map           = NULL;
 
 
 
 
 gb_global Type *t_type_info_named_ptr         = NULL;
 gb_global Type *t_type_info_named_ptr         = NULL;
@@ -320,6 +321,7 @@ gb_global Type *t_type_info_struct_ptr        = NULL;
 gb_global Type *t_type_info_union_ptr         = NULL;
 gb_global Type *t_type_info_union_ptr         = NULL;
 gb_global Type *t_type_info_raw_union_ptr     = NULL;
 gb_global Type *t_type_info_raw_union_ptr     = NULL;
 gb_global Type *t_type_info_enum_ptr          = NULL;
 gb_global Type *t_type_info_enum_ptr          = NULL;
+gb_global Type *t_type_info_map_ptr           = NULL;
 
 
 
 
 
 
@@ -921,6 +923,14 @@ bool are_types_identical(Type *x, Type *y) {
 			       are_types_identical(x->Proc.results, y->Proc.results);
 			       are_types_identical(x->Proc.results, y->Proc.results);
 		}
 		}
 		break;
 		break;
+
+	case Type_Map:
+		if (y->kind == Type_Map) {
+			return x->Map.count == y->Map.count &&
+			       are_types_identical(x->Map.key,   y->Map.key) &&
+			       are_types_identical(x->Map.value, y->Map.value);
+		}
+		break;
 	}
 	}
 
 
 
 
@@ -1073,6 +1083,10 @@ gb_global Entity *entity__dynamic_array_count     = NULL;
 gb_global Entity *entity__dynamic_array_capacity  = NULL;
 gb_global Entity *entity__dynamic_array_capacity  = NULL;
 gb_global Entity *entity__dynamic_array_allocator = NULL;
 gb_global Entity *entity__dynamic_array_allocator = NULL;
 
 
+gb_global Entity *entity__dynamic_map_count     = NULL;
+gb_global Entity *entity__dynamic_map_capacity  = NULL;
+gb_global Entity *entity__dynamic_map_allocator = NULL;
+
 Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel);
 Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel);
 
 
 Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_type) {
 Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_type) {
@@ -1240,7 +1254,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 			sel.entity = entity__slice_count;
 			sel.entity = entity__slice_count;
 			return sel;
 			return sel;
 		}
 		}
-	}  else if (type->kind == Type_DynamicArray) {
+	} else if (type->kind == Type_DynamicArray) {
 		String data_str      = str_lit("data");
 		String data_str      = str_lit("data");
 		String count_str     = str_lit("count");
 		String count_str     = str_lit("count");
 		String capacity_str  = str_lit("capacity");
 		String capacity_str  = str_lit("capacity");
@@ -1273,6 +1287,36 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 			sel.entity = entity__dynamic_array_allocator;
 			sel.entity = entity__dynamic_array_allocator;
 			return sel;
 			return sel;
 		}
 		}
+	} else if (type->kind == Type_Map) {
+		String count_str     = str_lit("count");
+		String capacity_str  = str_lit("capacity");
+		String allocator_str = str_lit("allocator");
+
+		if (str_eq(field_name, count_str)) {
+			selection_add_index(&sel, 0);
+			if (entity__dynamic_map_count == NULL) {
+				entity__dynamic_map_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 0);
+				entity__dynamic_map_count->Variable.is_immutable = true;
+			}
+			sel.entity = entity__dynamic_map_count;
+			return sel;
+		} else if (str_eq(field_name, capacity_str)) {
+			selection_add_index(&sel, 1);
+			if (entity__dynamic_map_capacity == NULL) {
+				entity__dynamic_map_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 1);
+				entity__dynamic_map_capacity->Variable.is_immutable = true;
+			}
+			sel.entity = entity__dynamic_map_capacity;
+			return sel;
+		} else if (str_eq(field_name, allocator_str)) {
+			selection_add_index(&sel, 2);
+			if (entity__dynamic_map_allocator == NULL) {
+				entity__dynamic_map_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 2);
+				entity__dynamic_map_allocator->Variable.is_immutable = true;
+			}
+			sel.entity = entity__dynamic_map_allocator;
+			return sel;
+		}
 	}
 	}
 
 
 	if (type->kind != Type_Record) {
 	if (type->kind != Type_Record) {
@@ -1527,8 +1571,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
 
 
 	case Type_Map: {
 	case Type_Map: {
 		if (t->Map.count == 0) { // Dynamic
 		if (t->Map.count == 0) { // Dynamic
-			// NOTE(bill): same as a dynamic array
-			return s.word_size;
+			return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path);
 		}
 		}
 		GB_PANIC("TODO(bill): Fixed map alignment");
 		GB_PANIC("TODO(bill): Fixed map alignment");
 	} break;
 	} break;
@@ -1744,8 +1787,7 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
 
 
 	case Type_Map: {
 	case Type_Map: {
 		if (t->Map.count == 0) { // Dynamic
 		if (t->Map.count == 0) { // Dynamic
-			// NOTE(bill): same as a two dynamic arrays
-			return 2 * type_size_of_internal(s, allocator, t_raw_dynamic_array, path);
+			return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path);
 		}
 		}
 		GB_PANIC("TODO(bill): Fixed map size");
 		GB_PANIC("TODO(bill): Fixed map size");
 	}
 	}