Browse Source

Allow pointers to `append`; Fix strconv stuff; `new_slice` allows for capacity

Ginger Bill 8 years ago
parent
commit
9e8c9be1ea
12 changed files with 184 additions and 88 deletions
  1. 2 2
      build.bat
  2. 2 2
      code/demo.odin
  3. 4 6
      core/fmt.odin
  4. 10 9
      core/strconv.odin
  5. 2 2
      core/strings.odin
  6. 31 31
      core/sync.odin
  7. 75 8
      core/sys/windows.odin
  8. 35 12
      src/check_expr.c
  9. 1 1
      src/checker.c
  10. 16 5
      src/ir.c
  11. 5 6
      src/ir_print.c
  12. 1 4
      src/types.c

+ 2 - 2
build.bat

@@ -44,8 +44,8 @@ del *.ilk > NUL 2> NUL
 
 
 cl %compiler_settings% "src\main.c" ^
 cl %compiler_settings% "src\main.c" ^
 	/link %linker_settings% -OUT:%exe_name% ^
 	/link %linker_settings% -OUT:%exe_name% ^
-	&& odin run code/demo.odin
-	rem && odin run code/Jaze/src/main.odin
+	&& odin build code/Jaze/src/main.odin
+	rem && odin run code/demo.odin
 	rem && odin build_dll code/example.odin ^
 	rem && odin build_dll code/example.odin ^
 	rem odin run code/demo.odin
 	rem odin run code/demo.odin
 
 

+ 2 - 2
code/demo.odin

@@ -6,6 +6,7 @@
 #import "opengl.odin";
 #import "opengl.odin";
 #import "os.odin";
 #import "os.odin";
 #import "strconv.odin";
 #import "strconv.odin";
+#import "sync.odin";
 
 
 main :: proc() {
 main :: proc() {
 	// buf: [64]byte;
 	// buf: [64]byte;
@@ -15,8 +16,7 @@ main :: proc() {
 	// fmt.println(s);
 	// fmt.println(s);
 	// fmt.printf("%3d\n", 102);
 	// fmt.printf("%3d\n", 102);
 
 
-	a: [10]int;
-	s := a[..0];
+	s := new_slice(int, 0, 10);
 	append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
 	append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
 	fmt.println(s);
 	fmt.println(s);
 
 

+ 4 - 6
core/fmt.odin

@@ -8,10 +8,10 @@
 _BUFFER_SIZE :: 1<<12;
 _BUFFER_SIZE :: 1<<12;
 
 
 write_string :: proc(buf: ^[]byte, s: string) {
 write_string :: proc(buf: ^[]byte, s: string) {
-	append(buf^, ..cast([]byte)s);
+	append(buf, ..cast([]byte)s);
 }
 }
 write_byte :: proc(buf: ^[]byte, b: byte) {
 write_byte :: proc(buf: ^[]byte, b: byte) {
-	append(buf^, b);
+	append(buf, b);
 }
 }
 write_rune :: proc(buf: ^[]byte, r: rune) {
 write_rune :: proc(buf: ^[]byte, r: rune) {
 	if r < utf8.RUNE_SELF {
 	if r < utf8.RUNE_SELF {
@@ -20,7 +20,7 @@ write_rune :: proc(buf: ^[]byte, r: rune) {
 	}
 	}
 
 
 	b, n := utf8.encode_rune(r);
 	b, n := utf8.encode_rune(r);
-	append(buf^, ..b[..n]);
+	append(buf, ..b[..n]);
 }
 }
 
 
 Fmt_Info :: struct {
 Fmt_Info :: struct {
@@ -431,7 +431,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
 
 
 	count := min(width, fi.buf.capacity-fi.buf.count);
 	count := min(width, fi.buf.capacity-fi.buf.count);
 	for _ in 0..count {
 	for _ in 0..count {
-		append(fi.buf^, pad_byte);
+		append(fi.buf, pad_byte);
 	}
 	}
 }
 }
 
 
@@ -533,8 +533,6 @@ _pad :: proc(fi: ^Fmt_Info, s: string) {
 }
 }
 
 
 fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
 fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
-
-
 	match verb {
 	match verb {
 	// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
 	// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
 	// case 'f', 'F', 'v':
 	// case 'f', 'F', 'v':

+ 10 - 9
core/strconv.odin

@@ -109,12 +109,9 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
 		round_shortest(d, mant, exp, flt);
 		round_shortest(d, mant, exp, flt);
 		digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
 		digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
 		match fmt {
 		match fmt {
-		case 'e', 'E':
-			prec = digs.count-1;
-		case 'f', 'F':
-			prec = max(digs.count-digs.decimal_point, 0);
-		case 'g', 'G':
-			prec = digs.count;
+		case 'e', 'E': prec = digs.count-1;
+		case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
+		case 'g', 'G': prec = digs.count;
 		}
 		}
 	} else {
 	} else {
 		match fmt {
 		match fmt {
@@ -139,9 +136,10 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
 	case 'f', 'F':
 	case 'f', 'F':
 		add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
 		add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
 			for b in bytes {
 			for b in bytes {
-				if dst.count <= w^ {
+				if dst.capacity <= w^ {
 					break;
 					break;
 				}
 				}
+				dst.count++;
 				dst[w^] = b;
 				dst[w^] = b;
 				w^++;
 				w^++;
 			}
 			}
@@ -166,6 +164,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
 			add_bytes(^dst, ^w, '0');
 			add_bytes(^dst, ^w, '0');
 		}
 		}
 
 
+
 		// fractional part
 		// fractional part
 		if prec > 0 {
 		if prec > 0 {
 			add_bytes(^dst, ^w, '.');
 			add_bytes(^dst, ^w, '.');
@@ -181,10 +180,12 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
 		return buf[..w];
 		return buf[..w];
 
 
 	case 'e', 'E':
 	case 'e', 'E':
-		return nil; // TODO
+		panic("strconv: e/E float printing is not yet supported");
+		return buf; // TODO
 
 
 	case 'g', 'G':
 	case 'g', 'G':
-		return nil; // TODO
+		panic("strconv: g/G float printing is not yet supported");
+		return buf; // TODO
 	}
 	}
 
 
 	c: [2]byte;
 	c: [2]byte;

+ 2 - 2
core/strings.odin

@@ -1,8 +1,8 @@
 new_c_string :: proc(s: string) -> ^byte {
 new_c_string :: proc(s: string) -> ^byte {
-	c := new_c_string(byte, s.count+1);
+	c := new_slice(byte, s.count+1);
 	copy(c, cast([]byte)s);
 	copy(c, cast([]byte)s);
 	c[s.count] = 0;
 	c[s.count] = 0;
-	return c;
+	return c.data;
 }
 }
 
 
 to_odin_string :: proc(c: ^byte) -> string {
 to_odin_string :: proc(c: ^byte) -> string {

+ 31 - 31
core/sync.odin

@@ -2,14 +2,14 @@
 #import "atomic.odin";
 #import "atomic.odin";
 
 
 Semaphore :: struct {
 Semaphore :: struct {
-	handle: win32.HANDLE,
+	_handle: win32.HANDLE,
 }
 }
 
 
 Mutex :: struct {
 Mutex :: struct {
-	semaphore: Semaphore,
-	counter:   i32,
-	owner:     i32,
-	recursion: i32,
+	_semaphore: Semaphore,
+	_counter:   i32,
+	_owner:     i32,
+	_recursion: i32,
 }
 }
 
 
 current_thread_id :: proc() -> i32 {
 current_thread_id :: proc() -> i32 {
@@ -17,74 +17,74 @@ current_thread_id :: proc() -> i32 {
 }
 }
 
 
 semaphore_init :: proc(s: ^Semaphore) {
 semaphore_init :: proc(s: ^Semaphore) {
-	s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
+	s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
 }
 }
 
 
 semaphore_destroy :: proc(s: ^Semaphore) {
 semaphore_destroy :: proc(s: ^Semaphore) {
-	win32.CloseHandle(s.handle);
+	win32.CloseHandle(s._handle);
 }
 }
 
 
 semaphore_post :: proc(s: ^Semaphore, count: int) {
 semaphore_post :: proc(s: ^Semaphore, count: int) {
-	win32.ReleaseSemaphore(s.handle, cast(i32)count, nil);
+	win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
 }
 }
 
 
 semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
 semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
 
 
 semaphore_wait :: proc(s: ^Semaphore) {
 semaphore_wait :: proc(s: ^Semaphore) {
-	win32.WaitForSingleObject(s.handle, win32.INFINITE);
+	win32.WaitForSingleObject(s._handle, win32.INFINITE);
 }
 }
 
 
 
 
 mutex_init :: proc(m: ^Mutex) {
 mutex_init :: proc(m: ^Mutex) {
-	atomic.store(^m.counter, 0);
-	atomic.store(^m.owner, current_thread_id());
-	semaphore_init(^m.semaphore);
-	m.recursion = 0;
+	atomic.store(^m._counter, 0);
+	atomic.store(^m._owner, current_thread_id());
+	semaphore_init(^m._semaphore);
+	m._recursion = 0;
 }
 }
 mutex_destroy :: proc(m: ^Mutex) {
 mutex_destroy :: proc(m: ^Mutex) {
-	semaphore_destroy(^m.semaphore);
+	semaphore_destroy(^m._semaphore);
 }
 }
 mutex_lock :: proc(m: ^Mutex) {
 mutex_lock :: proc(m: ^Mutex) {
 	thread_id := current_thread_id();
 	thread_id := current_thread_id();
-	if atomic.fetch_add(^m.counter, 1) > 0 {
-		if thread_id != atomic.load(^m.owner) {
-			semaphore_wait(^m.semaphore);
+	if atomic.fetch_add(^m._counter, 1) > 0 {
+		if thread_id != atomic.load(^m._owner) {
+			semaphore_wait(^m._semaphore);
 		}
 		}
 	}
 	}
-	atomic.store(^m.owner, thread_id);
-	m.recursion++;
+	atomic.store(^m._owner, thread_id);
+	m._recursion++;
 }
 }
 mutex_try_lock :: proc(m: ^Mutex) -> bool {
 mutex_try_lock :: proc(m: ^Mutex) -> bool {
 	thread_id := current_thread_id();
 	thread_id := current_thread_id();
-	if atomic.load(^m.owner) == thread_id {
-		atomic.fetch_add(^m.counter, 1);
+	if atomic.load(^m._owner) == thread_id {
+		atomic.fetch_add(^m._counter, 1);
 	} else {
 	} else {
 		expected: i32 = 0;
 		expected: i32 = 0;
-		if atomic.load(^m.counter) != 0 {
+		if atomic.load(^m._counter) != 0 {
 			return false;
 			return false;
 		}
 		}
-		if atomic.compare_exchange(^m.counter, expected, 1) == 0 {
+		if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
 			return false;
 			return false;
 		}
 		}
-		atomic.store(^m.owner, thread_id);
+		atomic.store(^m._owner, thread_id);
 	}
 	}
-	m.recursion++;
+	m._recursion++;
 	return true;
 	return true;
 }
 }
 mutex_unlock :: proc(m: ^Mutex) {
 mutex_unlock :: proc(m: ^Mutex) {
 	recursion: i32;
 	recursion: i32;
 	thread_id := current_thread_id();
 	thread_id := current_thread_id();
-	assert(thread_id == atomic.load(^m.owner));
+	assert(thread_id == atomic.load(^m._owner));
 
 
-	m.recursion--;
-	recursion = m.recursion;
+	m._recursion--;
+	recursion = m._recursion;
 	if recursion == 0 {
 	if recursion == 0 {
-		atomic.store(^m.owner, thread_id);
+		atomic.store(^m._owner, thread_id);
 	}
 	}
 
 
-	if atomic.fetch_add(^m.counter, -1) > 1 {
+	if atomic.fetch_add(^m._counter, -1) > 1 {
 		if recursion == 0 {
 		if recursion == 0 {
-			semaphore_release(^m.semaphore);
+			semaphore_release(^m._semaphore);
 		}
 		}
 	}
 	}
 }
 }

+ 75 - 8
core/sys/windows.odin

@@ -40,14 +40,19 @@ WS_CAPTION          :: 0x00C00000;
 WS_VISIBLE          :: 0x10000000;
 WS_VISIBLE          :: 0x10000000;
 WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
 WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
 
 
-WM_DESTROY     :: 0x0002;
-WM_SIZE	       :: 0x0005;
-WM_CLOSE       :: 0x0010;
-WM_ACTIVATEAPP :: 0x001C;
-WM_QUIT        :: 0x0012;
-WM_KEYDOWN     :: 0x0100;
-WM_KEYUP       :: 0x0101;
-WM_SIZING      :: 0x0214;
+WM_DESTROY           :: 0x0002;
+WM_SIZE	             :: 0x0005;
+WM_CLOSE             :: 0x0010;
+WM_ACTIVATEAPP       :: 0x001C;
+WM_QUIT              :: 0x0012;
+WM_KEYDOWN           :: 0x0100;
+WM_KEYUP             :: 0x0101;
+WM_SIZING            :: 0x0214;
+WM_MOUSEWHEEL        :: 0x020A;
+WM_SYSKEYDOWN        :: 0x0104;
+WM_WINDOWPOSCHANGED  :: 0x0047;
+WM_SETCURSOR         :: 0x0020;
+WM_CHAR              :: 0x0102;
 
 
 PM_REMOVE :: 1;
 PM_REMOVE :: 1;
 
 
@@ -300,6 +305,68 @@ ReadBarrier      :: proc() #foreign kernel32;
 
 
 
 
 
 
+
+
+HMONITOR :: HANDLE;
+
+GWL_STYLE     :: -16;
+
+HWND_TOP :: cast(HWND)cast(uint)0;
+
+MONITOR_DEFAULTTONULL    :: 0x00000000;
+MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
+MONITOR_DEFAULTTONEAREST :: 0x00000002;
+
+SWP_FRAMECHANGED  :: 0x0020;
+SWP_NOOWNERZORDER :: 0x0200;
+SWP_NOZORDER      :: 0x0004;
+SWP_NOSIZE        :: 0x0001;
+SWP_NOMOVE        :: 0x0002;
+
+
+MONITORINFO :: struct #ordered {
+	size:      u32,
+	monitor:   RECT,
+	work:      RECT,
+	flags:     u32,
+}
+
+WINDOWPLACEMENT :: struct #ordered {
+	length:     u32,
+	flags:      u32,
+	show_cmd:   u32,
+	min_pos:    POINT,
+	max_pos:    POINT,
+	normal_pos: RECT,
+}
+
+GetMonitorInfoA    :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
+MonitorFromWindow  :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
+
+SetWindowPos       :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
+
+GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
+SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
+
+GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
+SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
+
+GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
+
+HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
+HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
+LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
+LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
+
+
+
+
+
+
+
+
+
+
 BITMAPINFOHEADER :: struct #ordered {
 BITMAPINFOHEADER :: struct #ordered {
 	size:              u32,
 	size:              u32,
 	width, height:     i32,
 	width, height:     i32,

+ 35 - 12
src/check_expr.c

@@ -2918,9 +2918,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 			err = "Too many";
 			err = "Too many";
 		}
 		}
 
 
-		if (err) {
+		if (err != NULL) {
 			gbString expr = expr_to_string(ce->proc);
 			gbString expr = expr_to_string(ce->proc);
-			error(ce->close, "`%s` arguments for `%s`, expected %td, got %td",
+			error(ce->close, "%s arguments for `%s`, expected %td, got %td",
 			      err, expr,
 			      err, expr,
 			      bp->arg_count, ce->args.count);
 			      bp->arg_count, ce->args.count);
 			gb_string_free(expr);
 			gb_string_free(expr);
@@ -2962,6 +2962,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 	} break;
 	} break;
 	case BuiltinProc_new_slice: {
 	case BuiltinProc_new_slice: {
 		// new_slice :: proc(Type, len: int) -> []Type
 		// new_slice :: proc(Type, len: int) -> []Type
+		// new_slice :: proc(Type, len, cap: int) -> []Type
 		Operand op = {0};
 		Operand op = {0};
 		check_expr_or_type(c, &op, ce->args.e[0]);
 		check_expr_or_type(c, &op, ce->args.e[0]);
 		Type *type = op.type;
 		Type *type = op.type;
@@ -2970,15 +2971,27 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 			return false;
 			return false;
 		}
 		}
 
 
-		check_expr(c, &op, ce->args.e[1]);
-		if (op.mode == Addressing_Invalid) {
-			return false;
-		}
-		if (!is_type_integer(op.type)) {
-			gbString type_str = type_to_string(op.type);
-			error_node(call, "Length for `new_slice` must be an integer, got `%s`", type_str);
-			gb_string_free(type_str);
-			return false;
+		isize arg_count = ce->args.count;
+		if (arg_count < 2 || 3 < arg_count) {
+			error_node(ce->args.e[0], "`new_slice` expects 2 or 3 arguments, found %td", arg_count);
+			// NOTE(bill): Return the correct type to reduce errors
+		} else {
+			// If any are constant
+			i64 sizes[2] = {0};
+			isize size_count = 0;
+			for (isize i = 1; i < arg_count; i++) {
+				i64 val = 0;
+				bool ok = check_index_value(c, ce->args.e[i], -1, &val);
+				if (ok && val >= 0) {
+					GB_ASSERT(size_count < gb_count_of(sizes));
+					sizes[size_count++] = val;
+				}
+			}
+
+			if (size_count == 2 && sizes[0] > sizes[1]) {
+				error_node(ce->args.e[1], "`new_slice` count and capacity are swapped");
+				// No need quit
+			}
 		}
 		}
 
 
 		operand->mode = Addressing_Value;
 		operand->mode = Addressing_Value;
@@ -3060,7 +3073,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		// append :: proc([dynamic]Type, item: ..Type)
 		// append :: proc([dynamic]Type, item: ..Type)
 		// append :: proc([]Type, item: ..Type)
 		// append :: proc([]Type, item: ..Type)
 		Type *type = operand->type;
 		Type *type = operand->type;
-		type = base_type(type);
+		bool is_pointer = is_type_pointer(type);
+		type = base_type(type_deref(type));
 		if (!is_type_dynamic_array(type) && !is_type_slice(type)) {
 		if (!is_type_dynamic_array(type) && !is_type_slice(type)) {
 			gbString str = type_to_string(type);
 			gbString str = type_to_string(type);
 			error_node(operand->expr, "Expected a slice or dynamic array, got `%s`", str);
 			error_node(operand->expr, "Expected a slice or dynamic array, got `%s`", str);
@@ -3068,6 +3082,15 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 			return false;
 			return false;
 		}
 		}
 
 
+		bool is_addressable = operand->mode == Addressing_Variable;
+		if (is_pointer) {
+			is_addressable = true;
+		}
+		if (!is_addressable) {
+			error_node(operand->expr, "`append` can only operate on addressable values");
+			return false;
+		}
+
 		Type *elem = NULL;
 		Type *elem = NULL;
 		Type *slice_elem = NULL;
 		Type *slice_elem = NULL;
 		if (is_type_dynamic_array(type)) {
 		if (is_type_dynamic_array(type)) {

+ 1 - 1
src/checker.c

@@ -68,7 +68,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT(""),                 0, false, Expr_Stmt},
 	{STR_LIT(""),                 0, false, Expr_Stmt},
 
 
 	{STR_LIT("new"),              1, false, Expr_Expr},
 	{STR_LIT("new"),              1, false, Expr_Expr},
-	{STR_LIT("new_slice"),        2, false, Expr_Expr},
+	{STR_LIT("new_slice"),        2, true,  Expr_Expr},
 	{STR_LIT("free"),             1, false, Expr_Stmt},
 	{STR_LIT("free"),             1, false, Expr_Stmt},
 
 
 	{STR_LIT("reserve"),          2, false, Expr_Stmt},
 	{STR_LIT("reserve"),          2, false, Expr_Stmt},

+ 16 - 5
src/ir.c

@@ -3168,7 +3168,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 
 				case BuiltinProc_new_slice: {
 				case BuiltinProc_new_slice: {
 					ir_emit_comment(proc, str_lit("new_slice"));
 					ir_emit_comment(proc, str_lit("new_slice"));
-					// new_slice :: proc(Type, len: int) -> ^Type
+					// new_slice :: proc(Type, len: int) -> []Type
+					// new_slice :: proc(Type, len, cap: int) -> []Type
 					gbAllocator allocator = proc->module->allocator;
 					gbAllocator allocator = proc->module->allocator;
 
 
 					Type *type = type_of_expr(proc->module->info, ce->args.e[0]);
 					Type *type = type_of_expr(proc->module->info, ce->args.e[0]);
@@ -3182,10 +3183,15 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					irValue *elem_align = ir_make_const_int(allocator, a);
 					irValue *elem_align = ir_make_const_int(allocator, a);
 
 
 					irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
 					irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
+					irValue *capacity = count;
 
 
-					ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, count, false);
+					if (ce->args.count == 3)  {
+						capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int);
+					}
+
+					ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false);
 
 
-					irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, count, t_int);
+					irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int);
 
 
 					irValue **args = gb_alloc_array(allocator, irValue *, 2);
 					irValue **args = gb_alloc_array(allocator, irValue *, 2);
 					args[0] = slice_size;
 					args[0] = slice_size;
@@ -3195,7 +3201,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					irValue *ptr = ir_emit_conv(proc, call, ptr_type);
 					irValue *ptr = ir_emit_conv(proc, call, ptr_type);
 					irValue *slice = ir_add_local_generated(proc, slice_type);
 					irValue *slice = ir_add_local_generated(proc, slice_type);
 
 
-					ir_fill_slice(proc, slice, ptr, count, count);
+					ir_fill_slice(proc, slice, ptr, count, capacity);
 					return ir_emit_load(proc, slice);
 					return ir_emit_load(proc, slice);
 				} break;
 				} break;
 
 
@@ -3330,7 +3336,12 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 					ir_emit_comment(proc, str_lit("append"));
 					ir_emit_comment(proc, str_lit("append"));
 					gbAllocator a = proc->module->allocator;
 					gbAllocator a = proc->module->allocator;
 
 
-					irValue *array_ptr = ir_build_addr(proc, ce->args.e[0]).addr;
+					Type *value_type = type_of_expr(proc->module->info, ce->args.e[0]);
+					irAddr array_addr = ir_build_addr(proc, ce->args.e[0]);
+					irValue *array_ptr = array_addr.addr;
+					if (is_type_pointer(value_type)) {
+						array_ptr = ir_addr_load(proc, array_addr);
+					}
 					Type *type = ir_type(array_ptr);
 					Type *type = ir_type(array_ptr);
 					GB_ASSERT(is_type_pointer(type));
 					GB_ASSERT(is_type_pointer(type));
 					type = base_type(type_deref(type));
 					type = base_type(type_deref(type));

+ 5 - 6
src/ir_print.c

@@ -664,6 +664,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 	ir_fprintf(f, "\t");
 	ir_fprintf(f, "\t");
 
 
 	switch (instr->kind) {
 	switch (instr->kind) {
+	default: {
+		GB_PANIC("<unknown instr> %d\n", instr->kind);
+		ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
+	} break;
+
 	case irInstr_StartupRuntime: {
 	case irInstr_StartupRuntime: {
 		ir_fprintf(f, "call void ");
 		ir_fprintf(f, "call void ");
 		ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
 		ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
@@ -1281,12 +1286,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 
 
 		ir_fprintf(f, "\n"); */
 		ir_fprintf(f, "\n"); */
 	} break;
 	} break;
-
-
-	default: {
-		GB_PANIC("<unknown instr> %d\n", instr->kind);
-		ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
-	} break;
 	}
 	}
 }
 }
 
 

+ 1 - 4
src/types.c

@@ -1342,9 +1342,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 		}
 		}
 	}
 	}
 
 
-	if (type->kind != Type_Record) {
-		return sel;
-	}
 	if (is_type) {
 	if (is_type) {
 		if (type->kind == Type_Record) {
 		if (type->kind == Type_Record) {
 			if (type->Record.names != NULL &&
 			if (type->Record.names != NULL &&
@@ -1395,7 +1392,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 				}
 				}
 			}
 			}
 		}
 		}
-	} else {
+	} else if (type->kind == Type_Record) {
 		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];
 			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
 			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {