Browse Source

Merge branch 'master' into llvm-integration

gingerBill 5 years ago
parent
commit
e197af766d

+ 2 - 7
core/log/file_console_logger.odin

@@ -30,17 +30,15 @@ Default_File_Logger_Opts :: Options{
 
 
 
 
 File_Console_Logger_Data :: struct {
 File_Console_Logger_Data :: struct {
-    lowest_level: Level,
     file_handle:  os.Handle,
     file_handle:  os.Handle,
     ident : string,
     ident : string,
 }
 }
 
 
 create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
 create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
     data := new(File_Console_Logger_Data);
     data := new(File_Console_Logger_Data);
-    data.lowest_level = lowest;
     data.file_handle = h;
     data.file_handle = h;
     data.ident = ident;
     data.ident = ident;
-    return Logger{file_console_logger_proc, data, opt};
+    return Logger{file_console_logger_proc, data, lowest, opt};
 }
 }
 
 
 destroy_file_logger ::proc(log : ^Logger) {
 destroy_file_logger ::proc(log : ^Logger) {
@@ -52,10 +50,9 @@ destroy_file_logger ::proc(log : ^Logger) {
 
 
 create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger {
 create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger {
     data := new(File_Console_Logger_Data);
     data := new(File_Console_Logger_Data);
-    data.lowest_level = lowest;
     data.file_handle = os.INVALID_HANDLE;
     data.file_handle = os.INVALID_HANDLE;
     data.ident = ident;
     data.ident = ident;
-    return Logger{file_console_logger_proc, data, opt};
+    return Logger{file_console_logger_proc, data, lowest, opt};
 }
 }
 
 
 destroy_console_logger ::proc(log : ^Logger) {
 destroy_console_logger ::proc(log : ^Logger) {
@@ -65,8 +62,6 @@ destroy_console_logger ::proc(log : ^Logger) {
 
 
 file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
 file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
     data := cast(^File_Console_Logger_Data)logger_data;
     data := cast(^File_Console_Logger_Data)logger_data;
-    if level < data.lowest_level do return;
-
     h : os.Handle;
     h : os.Handle;
     if(data.file_handle != os.INVALID_HANDLE) do h = data.file_handle;
     if(data.file_handle != os.INVALID_HANDLE) do h = data.file_handle;
     else                                      do h = level <= Level.Error ? context.stdout : context.stderr;
     else                                      do h = level <= Level.Error ? context.stdout : context.stderr;

+ 25 - 10
core/log/log.odin

@@ -60,9 +60,10 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
 Logger :: runtime.Logger;
 Logger :: runtime.Logger;
 /*
 /*
 Logger :: struct {
 Logger :: struct {
-	procedure: Logger_Proc,
-	data:      rawptr,
-	options:   Options,
+	procedure:    Logger_Proc,
+	data:      	  rawptr,
+	lowest_level: Level,
+	options:   	  Logger_Options,
 }
 }
 */
 */
 
 
@@ -74,7 +75,7 @@ create_multi_logger :: proc(logs: ..Logger) -> Logger {
 	data := new(Multi_Logger_Data);
 	data := new(Multi_Logger_Data);
 	data.loggers = make([]Logger, len(logs));
 	data.loggers = make([]Logger, len(logs));
 	copy(data.loggers, logs);
 	copy(data.loggers, logs);
-	return Logger{multi_logger_proc, data, nil};
+	return Logger{multi_logger_proc, data, Level.Debug, nil};
 }
 }
 
 
 destroy_multi_logger :: proc(log : ^Logger) {
 destroy_multi_logger :: proc(log : ^Logger) {
@@ -98,18 +99,32 @@ nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Optio
 }
 }
 
 
 nil_logger :: proc() -> Logger {
 nil_logger :: proc() -> Logger {
-	return Logger{nil_logger_proc, nil, nil};
+	return Logger{nil_logger_proc, nil, Level.Debug, nil};
 }
 }
 
 
 // TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
 // TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
-debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug,   fmt_str=fmt_str, args=args, location=location);
-info  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info,    fmt_str=fmt_str, args=args, location=location);
-warn  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
-error :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error,   fmt_str=fmt_str, args=args, location=location);
-fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal,   fmt_str=fmt_str, args=args, location=location);
+debugf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug,   fmt_str=fmt_str, args=args, location=location);
+infof  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info,    fmt_str=fmt_str, args=args, location=location);
+warnf  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
+errorf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error,   fmt_str=fmt_str, args=args, location=location);
+fatalf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal,   fmt_str=fmt_str, args=args, location=location);
+
+debug :: proc(args : ..any, location := #caller_location) do log(level=Level.Debug,   args=args, location=location);
+info  :: proc(args : ..any, location := #caller_location) do log(level=Level.Info,    args=args, location=location);
+warn  :: proc(args : ..any, location := #caller_location) do log(level=Level.Warning, args=args, location=location);
+error :: proc(args : ..any, location := #caller_location) do log(level=Level.Error,   args=args, location=location);
+fatal :: proc(args : ..any, location := #caller_location) do log(level=Level.Fatal,   args=args, location=location);
+
+log :: proc(level : Level, args : ..any, location := #caller_location) {
+	logger := context.logger;
+	if level < logger.lowest_level do return;
+	str := fmt.tprint(..args); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
+	logger.procedure(logger.data, level, str, logger.options, location);
+}
 
 
 logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
 logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
 	logger := context.logger;
 	logger := context.logger;
+	if level < logger.lowest_level do return;
 	str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
 	str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
 	logger.procedure(logger.data, level, str, logger.options, location);
 	logger.procedure(logger.data, level, str, logger.options, location);
 }
 }

+ 1 - 1
core/math/linalg/general.odin

@@ -357,7 +357,7 @@ matrix_mul_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
 		  IS_NUMERIC(E) {
 		  IS_NUMERIC(E) {
 	for i in 0..<I {
 	for i in 0..<I {
 		for j in 0..<J {
 		for j in 0..<J {
-			c[i] += a[i][j] * b[i];
+			c[j] += a[i][j] * b[i];
 		}
 		}
 	}
 	}
 	return;
 	return;

+ 11 - 9
core/math/math.odin

@@ -742,26 +742,28 @@ atan2_f64 :: proc(y, x: f64) -> f64 {
 atan2 :: proc{atan2_f32, atan2_f64};
 atan2 :: proc{atan2_f32, atan2_f64};
 
 
 atan_f32 :: proc(x: f32) -> f32 {
 atan_f32 :: proc(x: f32) -> f32 {
-	return atan2_f32(1.0, x);
+	return atan2_f32(1, x);
 }
 }
-atan :: proc{atan_f32};
-
+atan_f64 :: proc(x: f64) -> f64 {
+	return atan2_f64(1, x);
+}
+atan :: proc{atan_f32, atan_f64};
 
 
 asin_f32 :: proc(x: f32) -> f32 {
 asin_f32 :: proc(x: f32) -> f32 {
-	return atan2_f32(x, sqrt_f32(1 - x*x));
+	return atan2_f32(x, 1 + sqrt_f32(1 - x*x));
 }
 }
 asin_f64 :: proc(x: f64) -> f64 {
 asin_f64 :: proc(x: f64) -> f64 {
-	return atan2_f64(x, sqrt_f64(1 - x*x));
+	return atan2_f64(x, 1 + sqrt_f64(1 - x*x));
 }
 }
-asin :: proc{asin_f32};
+asin :: proc{asin_f32, asin_f64};
 
 
 acos_f32 :: proc(x: f32) -> f32 {
 acos_f32 :: proc(x: f32) -> f32 {
-	return atan2_f32(sqrt_f32(1 - x), sqrt_f32(1 + x));
+	return 2 * atan2_f32(sqrt_f32(1 - x), sqrt_f32(1 + x));
 }
 }
 acos_f64 :: proc(x: f64) -> f64 {
 acos_f64 :: proc(x: f64) -> f64 {
-	return atan2_f64(sqrt_f64(1 - x), sqrt_f64(1 + x));
+	return 2 * atan2_f64(sqrt_f64(1 - x), sqrt_f64(1 + x));
 }
 }
-acos :: proc{acos_f32};
+acos :: proc{acos_f32, acos_f64};
 
 
 
 
 sinh_f32 :: proc(x: f32) -> f32 {
 sinh_f32 :: proc(x: f32) -> f32 {

+ 11 - 1
core/mem/mem.odin

@@ -45,8 +45,18 @@ copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawpt
 	return runtime.mem_copy_non_overlapping(dst, src, len);
 	return runtime.mem_copy_non_overlapping(dst, src, len);
 }
 }
 compare :: inline proc "contextless" (a, b: []byte) -> int {
 compare :: inline proc "contextless" (a, b: []byte) -> int {
-	return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
+	// NOTE(tetra): no-abc is okay here because if the slices are empty, `&a[0]` is just nil+0 == nil, which
+	// compare_byte_ptrs handles fine when the passed length is also zero.
+	res := #no_bounds_check compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
+	if res == 0 && len(a) != len(b) {
+		return len(a) <= len(b) ? -1 : +1;
+	} else if len(a) == 0 && len(b) == 0 {
+		return 0;
+	} else {
+		return res;
+	}
 }
 }
+
 compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
 compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
 	x := slice_ptr(a, n);
 	x := slice_ptr(a, n);
 	y := slice_ptr(b, n);
 	y := slice_ptr(b, n);

+ 33 - 0
core/os/os_darwin.odin

@@ -5,6 +5,7 @@ foreign import libc "system:c"
 
 
 import "core:runtime"
 import "core:runtime"
 import "core:strings"
 import "core:strings"
+import "core:c"
 
 
 OS :: "darwin";
 OS :: "darwin";
 
 
@@ -263,6 +264,8 @@ X_OK :: 1; // Test for execute permission
 F_OK :: 0; // Test for file existance
 F_OK :: 0; // Test for file existance
 
 
 foreign libc {
 foreign libc {
+	@(link_name="__error") __error :: proc() -> ^int ---;
+
 	@(link_name="open")    _unix_open    :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---;
 	@(link_name="open")    _unix_open    :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---;
 	@(link_name="close")   _unix_close   :: proc(handle: Handle) ---;
 	@(link_name="close")   _unix_close   :: proc(handle: Handle) ---;
 	@(link_name="read")    _unix_read    :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
 	@(link_name="read")    _unix_read    :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@@ -278,6 +281,8 @@ foreign libc {
 	@(link_name="free")    _unix_free    :: proc(ptr: rawptr) ---;
 	@(link_name="free")    _unix_free    :: proc(ptr: rawptr) ---;
 	@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
 	@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
 	@(link_name="getenv")  _unix_getenv  :: proc(cstring) -> cstring ---;
 	@(link_name="getenv")  _unix_getenv  :: proc(cstring) -> cstring ---;
+	@(link_name="getcwd")  _unix_getcwd  :: proc(buf: cstring, len: c.size_t) -> cstring ---;
+	@(link_name="chdir")   _unix_chdir   :: proc(buf: cstring) -> c.int ---;
 
 
 	@(link_name="exit")    _unix_exit    :: proc(status: int) ---;
 	@(link_name="exit")    _unix_exit    :: proc(status: int) ---;
 }
 }
@@ -289,6 +294,10 @@ foreign dl {
 	@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
 	@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
 }
 }
 
 
+get_last_error :: proc() -> int {
+	return __error()^;
+}
+
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
 	cstr := strings.clone_to_cstring(path);
 	cstr := strings.clone_to_cstring(path);
 	handle := _unix_open(cstr, flags, mode);
 	handle := _unix_open(cstr, flags, mode);
@@ -394,6 +403,30 @@ getenv :: proc(name: string) -> (string, bool) {
 	return string(cstr), true;
 	return string(cstr), true;
 }
 }
 
 
+get_current_directory :: proc() -> string {
+	page_size := get_page_size(); // NOTE(tetra): See note in os_linux.odin/get_current_directory.
+	buf := make([dynamic]u8, page_size);
+	for {
+		cwd := _unix_getcwd(cstring(#no_bounds_check &buf[0]), c.size_t(len(buf)));
+		if cwd != nil {
+			return string(cwd);
+		}
+		if Errno(get_last_error()) != ERANGE {
+			return "";
+		}
+		resize(&buf, len(buf)+page_size);
+	}
+	unreachable();
+	return "";
+}
+
+set_current_directory :: proc(path: string) -> (err: Errno) {
+	cstr := strings.clone_to_cstring(path, context.temp_allocator);
+	res := _unix_chdir(cstr);
+	if res == -1 do return Errno(get_last_error());
+	return ERROR_NONE;
+}
+
 exit :: inline proc(code: int) -> ! {
 exit :: inline proc(code: int) -> ! {
 	_unix_exit(code);
 	_unix_exit(code);
 }
 }

+ 145 - 114
core/os/os_linux.odin

@@ -5,6 +5,7 @@ foreign import libc "system:c"
 
 
 import "core:runtime"
 import "core:runtime"
 import "core:strings"
 import "core:strings"
+import "core:c"
 
 
 OS :: "linux";
 OS :: "linux";
 
 
@@ -15,94 +16,95 @@ Syscall   :: distinct int;
 
 
 INVALID_HANDLE :: ~Handle(0);
 INVALID_HANDLE :: ~Handle(0);
 
 
-ERROR_NONE:    	Errno : 0;
-EPERM:         	Errno : 1;
-ENOENT:        	Errno : 2;
-ESRCH:         	Errno : 3;
-EINTR:         	Errno : 4;
-EIO:           	Errno : 5;
-ENXIO:         	Errno : 6;
-EBADF:         	Errno : 9;
-EAGAIN:        	Errno : 11;
-ENOMEM:        	Errno : 12;
-EACCES:        	Errno : 13;
-EFAULT:        	Errno : 14;
-EEXIST:        	Errno : 17;
-ENODEV:        	Errno : 19;
-ENOTDIR:       	Errno : 20;
-EISDIR:        	Errno : 21;
-EINVAL:        	Errno : 22;
-ENFILE:        	Errno : 23;
-EMFILE:        	Errno : 24;
-ETXTBSY:       	Errno : 26;
-EFBIG:         	Errno : 27;
-ENOSPC:        	Errno : 28;
-ESPIPE:        	Errno : 29;
-EROFS:         	Errno : 30;
-EPIPE:         	Errno : 32;
-
-EDEADLK: 		Errno :	35;	/* Resource deadlock would occur */
-ENAMETOOLONG: 	Errno : 36;	/* File name too long */
-ENOLCK: 		Errno : 37;	/* No record locks available */
-
-ENOSYS: Errno : 38;	/* Invalid system call number */
-
-ENOTEMPTY: 	Errno : 39;	/* Directory not empty */
-ELOOP: 		Errno : 40;	/* Too many symbolic links encountered */
-EWOULDBLOCK: Errno : EAGAIN;	/* Operation would block */
-ENOMSG: 	Errno : 42;	/* No message of desired type */
-EIDRM: 		Errno : 43;	/* Identifier removed */
-ECHRNG: 	Errno : 44;	/* Channel number out of range */
-EL2NSYNC: 	Errno : 45;	/* Level 2 not synchronized */
-EL3HLT: 	Errno : 46;	/* Level 3 halted */
-EL3RST: 	Errno : 47;	/* Level 3 reset */
-ELNRNG: 	Errno : 48;	/* Link number out of range */
-EUNATCH: 	Errno : 49;	/* Protocol driver not attached */
-ENOCSI: 	Errno : 50;	/* No CSI structure available */
-EL2HLT: 	Errno : 51;	/* Level 2 halted */
-EBADE: 		Errno : 52;	/* Invalid exchange */
-EBADR: 		Errno : 53;	/* Invalid request descriptor */
-EXFULL: 	Errno : 54;	/* Exchange full */
-ENOANO: 	Errno : 55;	/* No anode */
-EBADRQC: 	Errno : 56;	/* Invalid request code */
-EBADSLT: 	Errno : 57;	/* Invalid slot */
-EDEADLOCK:  Errno : EDEADLK;
-EBFONT: 	Errno : 59;	/* Bad font file format */
-ENOSTR: 	Errno : 60;	/* Device not a stream */
-ENODATA: 	Errno : 61;	/* No data available */
-ETIME: 		Errno : 62;	/* Timer expired */
-ENOSR: 		Errno : 63;	/* Out of streams resources */
-ENONET: 	Errno : 64;	/* Machine is not on the network */
-ENOPKG: 	Errno : 65;	/* Package not installed */
-EREMOTE: 	Errno : 66;	/* Object is remote */
-ENOLINK: 	Errno : 67;	/* Link has been severed */
-EADV: 		Errno : 68;	/* Advertise error */
-ESRMNT: 	Errno : 69;	/* Srmount error */
-ECOMM: 		Errno : 70;	/* Communication error on send */
-EPROTO: 	Errno : 71;	/* Protocol error */
-EMULTIHOP: 	Errno : 72;	/* Multihop attempted */
-EDOTDOT: 	Errno : 73;	/* RFS specific error */
-EBADMSG: 	Errno : 74;	/* Not a data message */
-EOVERFLOW: 	Errno : 75;	/* Value too large for defined data type */
-ENOTUNIQ: 	Errno : 76;	/* Name not unique on network */
-EBADFD: 	Errno : 77;	/* File descriptor in bad state */
-EREMCHG: 	Errno : 78;	/* Remote address changed */
-ELIBACC: 	Errno : 79;	/* Can not access a needed shared library */
-ELIBBAD: 	Errno : 80;	/* Accessing a corrupted shared library */
-ELIBSCN: 	Errno : 81;	/* .lib section in a.out corrupted */
-ELIBMAX: 	Errno : 82;	/* Attempting to link in too many shared libraries */
-ELIBEXEC: 	Errno : 83;	/* Cannot exec a shared library directly */
-EILSEQ: 	Errno : 84;	/* Illegal byte sequence */
-ERESTART: 	Errno : 85;	/* Interrupted system call should be restarted */
-ESTRPIPE: 	Errno : 86;	/* Streams pipe error */
-EUSERS: 	Errno : 87;	/* Too many users */
-ENOTSOCK: 	Errno : 88;	/* Socket operation on non-socket */
-EDESTADDRREQ: Errno : 89;	/* Destination address required */
-EMSGSIZE: 	Errno : 90;	/* Message too long */
-EPROTOTYPE: Errno : 91;	/* Protocol wrong type for socket */
-ENOPROTOOPT: 	Errno : 92;	/* Protocol not available */
-EPROTONOSUPPORT: Errno : 93;	/* Protocol not supported */
-ESOCKTNOSUPPORT: Errno : 94;	/* Socket type not supported */
+ERROR_NONE:     Errno : 0;
+EPERM:          Errno : 1;
+ENOENT:         Errno : 2;
+ESRCH:          Errno : 3;
+EINTR:          Errno : 4;
+EIO:            Errno : 5;
+ENXIO:          Errno : 6;
+EBADF:          Errno : 9;
+EAGAIN:         Errno : 11;
+ENOMEM:         Errno : 12;
+EACCES:         Errno : 13;
+EFAULT:         Errno : 14;
+EEXIST:         Errno : 17;
+ENODEV:         Errno : 19;
+ENOTDIR:        Errno : 20;
+EISDIR:         Errno : 21;
+EINVAL:         Errno : 22;
+ENFILE:         Errno : 23;
+EMFILE:         Errno : 24;
+ETXTBSY:        Errno : 26;
+EFBIG:          Errno : 27;
+ENOSPC:         Errno : 28;
+ESPIPE:         Errno : 29;
+EROFS:          Errno : 30;
+EPIPE:          Errno : 32;
+
+ERANGE:         Errno : 34; /* Result too large */
+EDEADLK:        Errno : 35; /* Resource deadlock would occur */
+ENAMETOOLONG:   Errno : 36; /* File name too long */
+ENOLCK:         Errno : 37; /* No record locks available */
+
+ENOSYS:         Errno : 38;	/* Invalid system call number */
+
+ENOTEMPTY:      Errno : 39;	/* Directory not empty */
+ELOOP:          Errno : 40;	/* Too many symbolic links encountered */
+EWOULDBLOCK:    Errno : EAGAIN; /* Operation would block */
+ENOMSG:         Errno : 42;	/* No message of desired type */
+EIDRM:          Errno : 43;	/* Identifier removed */
+ECHRNG:         Errno : 44;	/* Channel number out of range */
+EL2NSYNC:       Errno : 45;	/* Level 2 not synchronized */
+EL3HLT:         Errno : 46;	/* Level 3 halted */
+EL3RST:         Errno : 47;	/* Level 3 reset */
+ELNRNG:         Errno : 48;	/* Link number out of range */
+EUNATCH:        Errno : 49;	/* Protocol driver not attached */
+ENOCSI:         Errno : 50;	/* No CSI structure available */
+EL2HLT:         Errno : 51;	/* Level 2 halted */
+EBADE:          Errno : 52;	/* Invalid exchange */
+EBADR:          Errno : 53;	/* Invalid request descriptor */
+EXFULL:         Errno : 54;	/* Exchange full */
+ENOANO:         Errno : 55;	/* No anode */
+EBADRQC:        Errno : 56;	/* Invalid request code */
+EBADSLT:        Errno : 57;	/* Invalid slot */
+EDEADLOCK:      Errno : EDEADLK;
+EBFONT:         Errno : 59;	/* Bad font file format */
+ENOSTR:         Errno : 60;	/* Device not a stream */
+ENODATA:        Errno : 61;	/* No data available */
+ETIME:          Errno : 62;	/* Timer expired */
+ENOSR:          Errno : 63;	/* Out of streams resources */
+ENONET:         Errno : 64;	/* Machine is not on the network */
+ENOPKG:         Errno : 65;	/* Package not installed */
+EREMOTE:        Errno : 66;	/* Object is remote */
+ENOLINK:        Errno : 67;	/* Link has been severed */
+EADV:           Errno : 68;	/* Advertise error */
+ESRMNT:         Errno : 69;	/* Srmount error */
+ECOMM:          Errno : 70;	/* Communication error on send */
+EPROTO:         Errno : 71;	/* Protocol error */
+EMULTIHOP:      Errno : 72;	/* Multihop attempted */
+EDOTDOT:        Errno : 73;	/* RFS specific error */
+EBADMSG:        Errno : 74;	/* Not a data message */
+EOVERFLOW:      Errno : 75;	/* Value too large for defined data type */
+ENOTUNIQ:       Errno : 76;	/* Name not unique on network */
+EBADFD:         Errno : 77;	/* File descriptor in bad state */
+EREMCHG:        Errno : 78;	/* Remote address changed */
+ELIBACC:        Errno : 79;	/* Can not access a needed shared library */
+ELIBBAD:        Errno : 80;	/* Accessing a corrupted shared library */
+ELIBSCN:        Errno : 81;	/* .lib section in a.out corrupted */
+ELIBMAX:        Errno : 82;	/* Attempting to link in too many shared libraries */
+ELIBEXEC:       Errno : 83;	/* Cannot exec a shared library directly */
+EILSEQ:         Errno : 84;	/* Illegal byte sequence */
+ERESTART:       Errno : 85;	/* Interrupted system call should be restarted */
+ESTRPIPE:       Errno : 86;	/* Streams pipe error */
+EUSERS:         Errno : 87;	/* Too many users */
+ENOTSOCK:       Errno : 88;	/* Socket operation on non-socket */
+EDESTADDRREQ:   Errno : 89;	/* Destination address required */
+EMSGSIZE:       Errno : 90;	/* Message too long */
+EPROTOTYPE:     Errno : 91;	/* Protocol wrong type for socket */
+ENOPROTOOPT:    Errno : 92;	/* Protocol not available */
+EPROTONOSUPPORT:Errno : 93;	/* Protocol not supported */
+ESOCKTNOSUPPORT:Errno : 94;	/* Socket type not supported */
 EOPNOTSUPP: 	Errno : 95;	/* Operation not supported on transport endpoint */
 EOPNOTSUPP: 	Errno : 95;	/* Operation not supported on transport endpoint */
 EPFNOSUPPORT: 	Errno : 96;	/* Protocol family not supported */
 EPFNOSUPPORT: 	Errno : 96;	/* Protocol family not supported */
 EAFNOSUPPORT: 	Errno : 97;	/* Address family not supported by protocol */
 EAFNOSUPPORT: 	Errno : 97;	/* Address family not supported by protocol */
@@ -259,29 +261,31 @@ foreign libc {
 	@(link_name="__errno_location") __errno_location    :: proc() -> ^int ---;
 	@(link_name="__errno_location") __errno_location    :: proc() -> ^int ---;
 	@(link_name="syscall")          syscall             :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
 	@(link_name="syscall")          syscall             :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
 
 
-	@(link_name="open")             _unix_open          :: proc(path: cstring, flags: int, mode: int) -> Handle ---;
-	@(link_name="close")            _unix_close         :: proc(fd: Handle) -> int ---;
-	@(link_name="read")             _unix_read          :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
-	@(link_name="write")            _unix_write         :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
-	@(link_name="lseek64")          _unix_seek          :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
+	@(link_name="open")             _unix_open          :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---;
+	@(link_name="close")            _unix_close         :: proc(fd: Handle) -> c.int ---;
+	@(link_name="read")             _unix_read          :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
+	@(link_name="write")            _unix_write         :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
+	@(link_name="lseek64")          _unix_seek          :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---;
 	@(link_name="gettid")           _unix_gettid        :: proc() -> u64 ---;
 	@(link_name="gettid")           _unix_gettid        :: proc() -> u64 ---;
-	@(link_name="getpagesize")      _unix_getpagesize   :: proc() -> i32 ---;
-	@(link_name="stat")             _unix_stat          :: proc(path: cstring, stat: ^Stat) -> int ---;
-	@(link_name="fstat")            _unix_fstat         :: proc(fd: Handle, stat: ^Stat) -> int ---;
-	@(link_name="access")           _unix_access        :: proc(path: cstring, mask: int) -> int ---;
+	@(link_name="getpagesize")      _unix_getpagesize   :: proc() -> c.int ---;
+	@(link_name="stat")             _unix_stat          :: proc(path: cstring, stat: ^Stat) -> c.int ---;
+	@(link_name="fstat")            _unix_fstat         :: proc(fd: Handle, stat: ^Stat) -> c.int ---;
+	@(link_name="access")           _unix_access        :: proc(path: cstring, mask: c.int) -> c.int ---;
 
 
-	@(link_name="malloc")           _unix_malloc        :: proc(size: int) -> rawptr ---;
-	@(link_name="calloc")           _unix_calloc        :: proc(num, size: int) -> rawptr ---;
+	@(link_name="malloc")           _unix_malloc        :: proc(size: c.size_t) -> rawptr ---;
+	@(link_name="calloc")           _unix_calloc        :: proc(num, size: c.size_t) -> rawptr ---;
 	@(link_name="free")             _unix_free          :: proc(ptr: rawptr) ---;
 	@(link_name="free")             _unix_free          :: proc(ptr: rawptr) ---;
-	@(link_name="realloc")          _unix_realloc       :: proc(ptr: rawptr, size: int) -> rawptr ---;
+	@(link_name="realloc")          _unix_realloc       :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---;
 	@(link_name="getenv")           _unix_getenv        :: proc(cstring) -> cstring ---;
 	@(link_name="getenv")           _unix_getenv        :: proc(cstring) -> cstring ---;
+	@(link_name="getcwd")           _unix_getcwd        :: proc(buf: cstring, len: c.size_t) -> cstring ---;
+	@(link_name="chdir")            _unix_chdir         :: proc(buf: cstring) -> c.int ---;
 
 
-	@(link_name="exit")             _unix_exit          :: proc(status: int) -> ! ---;
+	@(link_name="exit")             _unix_exit          :: proc(status: c.int) -> ! ---;
 }
 }
 foreign dl {
 foreign dl {
-	@(link_name="dlopen")           _unix_dlopen        :: proc(filename: cstring, flags: int) -> rawptr ---;
+	@(link_name="dlopen")           _unix_dlopen        :: proc(filename: cstring, flags: c.int) -> rawptr ---;
 	@(link_name="dlsym")            _unix_dlsym         :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
 	@(link_name="dlsym")            _unix_dlsym         :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
-	@(link_name="dlclose")          _unix_dlclose       :: proc(handle: rawptr) -> int ---;
+	@(link_name="dlclose")          _unix_dlclose       :: proc(handle: rawptr) -> c.int ---;
 	@(link_name="dlerror")          _unix_dlerror       :: proc() -> cstring ---;
 	@(link_name="dlerror")          _unix_dlerror       :: proc() -> cstring ---;
 }
 }
 
 
@@ -295,7 +299,7 @@ get_last_error :: proc() -> int {
 
 
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
 	cstr := strings.clone_to_cstring(path);
 	cstr := strings.clone_to_cstring(path);
-	handle := _unix_open(cstr, flags, mode);
+	handle := _unix_open(cstr, c.int(flags), c.int(mode));
 	delete(cstr);
 	delete(cstr);
 	if handle == -1 {
 	if handle == -1 {
 		return INVALID_HANDLE, Errno(get_last_error());
 		return INVALID_HANDLE, Errno(get_last_error());
@@ -312,26 +316,26 @@ close :: proc(fd: Handle) -> Errno {
 }
 }
 
 
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
-	bytes_read := _unix_read(fd, &data[0], len(data));
+	bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)));
 	if bytes_read == -1 {
 	if bytes_read == -1 {
 		return -1, Errno(get_last_error());
 		return -1, Errno(get_last_error());
 	}
 	}
-	return bytes_read, ERROR_NONE;
+	return int(bytes_read), ERROR_NONE;
 }
 }
 
 
 write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE;
 		return 0, ERROR_NONE;
 	}
 	}
-	bytes_written := _unix_write(fd, &data[0], len(data));
+	bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)));
 	if bytes_written == -1 {
 	if bytes_written == -1 {
 		return -1, Errno(get_last_error());
 		return -1, Errno(get_last_error());
 	}
 	}
-	return bytes_written, ERROR_NONE;
+	return int(bytes_written), ERROR_NONE;
 }
 }
 
 
 seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
 seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
-	res := _unix_seek(fd, offset, i32(whence));
+	res := _unix_seek(fd, offset, c.int(whence));
 	if res == -1 {
 	if res == -1 {
 		return -1, Errno(get_last_error());
 		return -1, Errno(get_last_error());
 	}
 	}
@@ -397,7 +401,7 @@ fstat :: inline proc(fd: Handle) -> (Stat, Errno) {
 access :: inline proc(path: string, mask: int) -> (bool, Errno) {
 access :: inline proc(path: string, mask: int) -> (bool, Errno) {
 	cstr := strings.clone_to_cstring(path);
 	cstr := strings.clone_to_cstring(path);
 	defer delete(cstr);
 	defer delete(cstr);
-	result := _unix_access(cstr, mask);
+	result := _unix_access(cstr, c.int(mask));
 	if result == -1 {
 	if result == -1 {
 		return false, Errno(get_last_error());
 		return false, Errno(get_last_error());
 	}
 	}
@@ -406,11 +410,11 @@ access :: inline proc(path: string, mask: int) -> (bool, Errno) {
 
 
 heap_alloc :: proc(size: int) -> rawptr {
 heap_alloc :: proc(size: int) -> rawptr {
 	assert(size >= 0);
 	assert(size >= 0);
-	return _unix_calloc(1, size);
+	return _unix_calloc(1, c.size_t(size));
 }
 }
 
 
 heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
 heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
-	return _unix_realloc(ptr, new_size);
+	return _unix_realloc(ptr, c.size_t(new_size));
 }
 }
 
 
 heap_free :: proc(ptr: rawptr) {
 heap_free :: proc(ptr: rawptr) {
@@ -427,8 +431,35 @@ getenv :: proc(name: string) -> (string, bool) {
 	return string(cstr), true;
 	return string(cstr), true;
 }
 }
 
 
+get_current_directory :: proc() -> string {
+	// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
+	// an authoritative value for it across all systems.
+	// The largest value I could find was 4096, so might as well use the page size.
+	page_size := get_page_size();
+	buf := make([dynamic]u8, page_size);
+	for {
+		cwd := _unix_getcwd(cstring(#no_bounds_check &buf[0]), c.size_t(len(buf)));
+		if cwd != nil {
+			return string(cwd);
+		}
+		if Errno(get_last_error()) != ERANGE {
+			return "";
+		}
+		resize(&buf, len(buf)+page_size);
+	}
+	unreachable();
+	return "";
+}
+
+set_current_directory :: proc(path: string) -> (err: Errno) {
+	cstr := strings.clone_to_cstring(path, context.temp_allocator);
+	res := _unix_chdir(cstr);
+	if res == -1 do return Errno(get_last_error());
+	return ERROR_NONE;
+}
+
 exit :: proc(code: int) -> ! {
 exit :: proc(code: int) -> ! {
-	_unix_exit(code);
+	_unix_exit(c.int(code));
 }
 }
 
 
 current_thread_id :: proc "contextless" () -> int {
 current_thread_id :: proc "contextless" () -> int {
@@ -438,7 +469,7 @@ current_thread_id :: proc "contextless" () -> int {
 dlopen :: inline proc(filename: string, flags: int) -> rawptr {
 dlopen :: inline proc(filename: string, flags: int) -> rawptr {
 	cstr := strings.clone_to_cstring(filename);
 	cstr := strings.clone_to_cstring(filename);
 	defer delete(cstr);
 	defer delete(cstr);
-	handle := _unix_dlopen(cstr, flags);
+	handle := _unix_dlopen(cstr, c.int(flags));
 	return handle;
 	return handle;
 }
 }
 dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
 dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {

+ 35 - 0
core/os/os_windows.odin

@@ -2,6 +2,7 @@
 package os
 package os
 
 
 import "core:sys/win32"
 import "core:sys/win32"
+import "core:intrinsics"
 
 
 OS :: "windows";
 OS :: "windows";
 
 
@@ -265,6 +266,40 @@ get_page_size :: proc() -> int {
 }
 }
 
 
 
 
+
+// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName;
+// The current directory is stored as a global variable in the process.
+@private cwd_gate := false;
+
+get_current_directory :: proc() -> string {
+	for intrinsics.atomic_xchg(&cwd_gate, true) {}
+
+	sz_utf16 := win32.get_current_directory_w(0, nil);
+	dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator); // the first time, it _includes_ the NUL.
+
+	sz_utf16 = win32.get_current_directory_w(u32(len(dir_buf_wstr)), cast(win32.Wstring) &dir_buf_wstr[0]);
+	assert(int(sz_utf16)+1 == len(dir_buf_wstr)); // the second time, it _excludes_ the NUL.
+
+	intrinsics.atomic_store(&cwd_gate, false);
+
+	dir_utf8 := win32.utf16_to_utf8(dir_buf_wstr);
+	return dir_utf8[:len(dir_utf8)-1]; // NOTE(tetra): Remove the NUL.
+}
+
+set_current_directory :: proc(path: string) -> (err: Errno) {
+	wstr := win32.utf8_to_wstring(path);
+
+	for intrinsics.atomic_xchg(&cwd_gate, true) {}
+	defer intrinsics.atomic_store(&cwd_gate, false);
+
+	res := win32.set_current_directory_w(wstr);
+	if res == 0 do return Errno(win32.get_last_error());
+
+	return;
+}
+
+
+
 exit :: proc(code: int) -> ! {
 exit :: proc(code: int) -> ! {
 	win32.exit_process(u32(code));
 	win32.exit_process(u32(code));
 }
 }

+ 5 - 4
core/runtime/core.odin

@@ -276,9 +276,10 @@ Logger_Options :: bit_set[Logger_Option];
 Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location);
 Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location);
 
 
 Logger :: struct {
 Logger :: struct {
-	procedure: Logger_Proc,
-	data:      rawptr,
-	options:   Logger_Options,
+	procedure:    Logger_Proc,
+	data:      	  rawptr,
+	lowest_level: Logger_Level,
+	options:   	  Logger_Options,
 }
 }
 
 
 Context :: struct {
 Context :: struct {
@@ -434,7 +435,7 @@ default_logger_proc :: proc(data: rawptr, level: Logger_Level, text: string, opt
 }
 }
 
 
 default_logger :: proc() -> Logger {
 default_logger :: proc() -> Logger {
-	return Logger{default_logger_proc, nil, nil};
+	return Logger{default_logger_proc, nil, Logger_Level.Debug, nil};
 }
 }
 
 
 
 

+ 1 - 1
core/sort/sort.odin

@@ -103,7 +103,7 @@ _log2 :: proc(x: int) -> int {
 	return res;
 	return res;
 }
 }
 
 
-merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) where intrinsics.type_is_ordered(T) {
+merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 	merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) {
 	merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) {
 		s, m := start, mid;
 		s, m := start, mid;
 
 

+ 2 - 0
core/strings/strings.odin

@@ -52,6 +52,8 @@ unsafe_string_to_cstring :: proc(str: string) -> cstring {
 	return cstring(d.data);
 	return cstring(d.data);
 }
 }
 
 
+// Compares two strings, returning a value representing which one comes first lexiographically.
+// -1 for `a`; 1 for `b`, or 0 if they are equal.
 compare :: proc(lhs, rhs: string) -> int {
 compare :: proc(lhs, rhs: string) -> int {
 	return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs);
 	return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs);
 }
 }

+ 5 - 0
core/sys/win32/kernel32.odin

@@ -35,6 +35,11 @@ foreign kernel32 {
 	@(link_name="GetVersionExA")             get_version                  :: proc(osvi: ^OS_Version_Info_Ex_A) ---;
 	@(link_name="GetVersionExA")             get_version                  :: proc(osvi: ^OS_Version_Info_Ex_A) ---;
 	@(link_name="GetCurrentThreadId")        get_current_thread_id        :: proc() -> u32 ---;
 	@(link_name="GetCurrentThreadId")        get_current_thread_id        :: proc() -> u32 ---;
 
 
+	// NOTE(tetra): Not thread safe with SetCurrentDirectory and GetFullPathName;
+	// The current directory is stored as a global variable in the process.
+	@(link_name="GetCurrentDirectoryW")       get_current_directory_w     :: proc(len: u32, buf: Wstring) -> u32 ---;
+	@(link_name="SetCurrentDirectoryW")       set_current_directory_w     :: proc(buf: Wstring) -> u32 ---;
+
 	@(link_name="GetSystemTimeAsFileTime")   get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) ---;
 	@(link_name="GetSystemTimeAsFileTime")   get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) ---;
 	@(link_name="FileTimeToLocalFileTime")   file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool ---;
 	@(link_name="FileTimeToLocalFileTime")   file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool ---;
 	@(link_name="FileTimeToSystemTime")      file_time_to_system_time     :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool ---;
 	@(link_name="FileTimeToSystemTime")      file_time_to_system_time     :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool ---;

+ 1 - 1
src/check_decl.cpp

@@ -1207,7 +1207,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
 	}
 	}
 
 
 
 
-	bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
+	bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
 	if (!where_clause_ok) {
 	if (!where_clause_ok) {
 		// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
 		// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
 		return;
 		return;

+ 10 - 3
src/check_expr.cpp

@@ -2260,6 +2260,8 @@ bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
 			x->mode = Addressing_Value;
 			x->mode = Addressing_Value;
 		} else if (is_type_slice(type) && is_type_string(x->type)) {
 		} else if (is_type_slice(type) && is_type_string(x->type)) {
 			x->mode = Addressing_Value;
 			x->mode = Addressing_Value;
+		} else if (is_type_union(type)) {
+			x->mode = Addressing_Value;
 		}
 		}
 		return true;
 		return true;
 	}
 	}
@@ -5942,7 +5944,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
 				Entity *e = sig_params[operand_index];
 				Entity *e = sig_params[operand_index];
 				Type *t = e->type;
 				Type *t = e->type;
 				Operand o = operands[operand_index];
 				Operand o = operands[operand_index];
-				call->viral_state_flags |= o.expr->viral_state_flags;
+				if (o.expr != nullptr) {
+					call->viral_state_flags |= o.expr->viral_state_flags;
+				}
 
 
 				if (e->kind == Entity_TypeName) {
 				if (e->kind == Entity_TypeName) {
 					// GB_ASSERT(!variadic);
 					// GB_ASSERT(!variadic);
@@ -6296,7 +6300,7 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize
 }
 }
 
 
 
 
-bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *clauses, bool print_err) {
+bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Array<Ast *> *clauses, bool print_err) {
 	if (clauses != nullptr) {
 	if (clauses != nullptr) {
 		for_array(i, *clauses) {
 		for_array(i, *clauses) {
 			Ast *clause = (*clauses)[i];
 			Ast *clause = (*clauses)[i];
@@ -6304,9 +6308,11 @@ bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *cla
 			check_expr(ctx, &o, clause);
 			check_expr(ctx, &o, clause);
 			if (o.mode != Addressing_Constant) {
 			if (o.mode != Addressing_Constant) {
 				if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
 				if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
+				if (print_err && call_expr) error(call_expr, "at caller location");
 				return false;
 				return false;
 			} else if (o.value.kind != ExactValue_Bool) {
 			} else if (o.value.kind != ExactValue_Bool) {
 				if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
 				if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
+				if (print_err && call_expr) error(call_expr, "at caller location");
 				return false;
 				return false;
 			} else if (!o.value.value_bool) {
 			} else if (!o.value.value_bool) {
 				if (print_err) {
 				if (print_err) {
@@ -6348,6 +6354,7 @@ bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *cla
 						}
 						}
 					}
 					}
 
 
+					if (call_expr) error(call_expr, "at caller location");
 				}
 				}
 				return false;
 				return false;
 			}
 			}
@@ -6613,7 +6620,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 					ctx.curr_proc_sig  = e->type;
 					ctx.curr_proc_sig  = e->type;
 
 
 					GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
 					GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
-					if (!evaluate_where_clauses(&ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
+					if (!evaluate_where_clauses(&ctx, operand->expr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
 						continue;
 						continue;
 					}
 					}
 				}
 				}

+ 7 - 1
src/check_stmt.cpp

@@ -314,7 +314,11 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
 
 
 		gbString str = expr_to_string(lhs->expr);
 		gbString str = expr_to_string(lhs->expr);
 		if (e != nullptr && e->flags & EntityFlag_Param) {
 		if (e != nullptr && e->flags & EntityFlag_Param) {
-			error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
+			if (e->flags & EntityFlag_Using) {
+				error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
+			} else {
+				error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
+			}
 		} else {
 		} else {
 			error(lhs->expr, "Cannot assign to '%s'", str);
 			error(lhs->expr, "Cannot assign to '%s'", str);
 		}
 		}
@@ -497,6 +501,8 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
 				Entity *f = found->elements.entries[i].value;
 				Entity *f = found->elements.entries[i].value;
 				if (f->kind == Entity_Variable) {
 				if (f->kind == Entity_Variable) {
 					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
 					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
+					if (e->flags & EntityFlag_Value) uvar->flags |= EntityFlag_Value;
+					if (e->flags & EntityFlag_Param) uvar->flags |= EntityFlag_Param;
 					Entity *prev = scope_insert(ctx->scope, uvar);
 					Entity *prev = scope_insert(ctx->scope, uvar);
 					if (prev != nullptr) {
 					if (prev != nullptr) {
 						gbString expr_str = expr_to_string(expr);
 						gbString expr_str = expr_to_string(expr);

+ 2 - 2
src/check_type.cpp

@@ -527,7 +527,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 		if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
 		if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
 			error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
 			error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
 		} else {
 		} else {
-			bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
+			bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &st->where_clauses, true);
 		}
 		}
 		check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
 		check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
 	}
 	}
@@ -714,7 +714,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
 	if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
 	if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
 		error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
 		error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
 	} else {
 	} else {
-		bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
+		bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
 	}
 	}
 
 
 
 

+ 4 - 3
src/ir.cpp

@@ -5714,7 +5714,7 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
 	}
 	}
 
 
 	// TODO(bill): Actually figure out what the conversion needs to be correctly 'cause LLVM
 	// TODO(bill): Actually figure out what the conversion needs to be correctly 'cause LLVM
-	return ir_emit_bitcast(proc, value, dst);
+	return ir_emit_bitcast(proc, value, t);
 }
 }
 
 
 
 
@@ -7348,10 +7348,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
 					GB_ASSERT(are_types_identical(ir_type(left), key_type));
 					GB_ASSERT(are_types_identical(ir_type(left), key_type));
 
 
 					Type *it = bit_set_to_int(rt);
 					Type *it = bit_set_to_int(rt);
+					left = ir_emit_conv(proc, left, it);
 
 
 					irValue *lower = ir_value_constant(it, exact_value_i64(rt->BitSet.lower));
 					irValue *lower = ir_value_constant(it, exact_value_i64(rt->BitSet.lower));
-					irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, ir_type(left));
-					irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, ir_type(left));
+					irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, it);
+					irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, it);
 					bit = ir_emit_conv(proc, bit, it);
 					bit = ir_emit_conv(proc, bit, it);
 
 
 					irValue *old_value = ir_emit_bitcast(proc, right, it);
 					irValue *old_value = ir_emit_bitcast(proc, right, it);

+ 2 - 2
src/main.cpp

@@ -1529,11 +1529,11 @@ int main(int arg_count, char const **arg_ptr) {
 			// Shared libraries are .dylib on MacOS and .so on Linux.
 			// Shared libraries are .dylib on MacOS and .so on Linux.
 			#if defined(GB_SYSTEM_OSX)
 			#if defined(GB_SYSTEM_OSX)
 				output_ext = STR_LIT(".dylib");
 				output_ext = STR_LIT(".dylib");
+				link_settings = "-dylib -dynamic";
 			#else
 			#else
 				output_ext = STR_LIT(".so");
 				output_ext = STR_LIT(".so");
+				link_settings = "-shared";
 			#endif
 			#endif
-
-			link_settings = "-shared";
 		} else {
 		} else {
 			// TODO: Do I need anything here?
 			// TODO: Do I need anything here?
 			link_settings = "";
 			link_settings = "";