Browse Source

Merge branch 'master' into separate-int-word-sizes

gingerBill 2 years ago
parent
commit
4a75a1e839
100 changed files with 4897 additions and 2541 deletions
  1. 8 1
      build_odin.sh
  2. 4 8
      core/compress/shoco/shoco.odin
  3. 11 11
      core/container/queue/queue.odin
  4. 3 3
      core/encoding/json/marshal.odin
  5. 10 1
      core/encoding/json/parser.odin
  6. 20 17
      core/fmt/fmt.odin
  7. 1 1
      core/fmt/fmt_js.odin
  8. 5 5
      core/image/common.odin
  9. 5 5
      core/image/png/png.odin
  10. 2 2
      core/image/qoi/qoi.odin
  11. 2 2
      core/image/tga/tga.odin
  12. 1 0
      core/intrinsics/intrinsics.odin
  13. 21 8
      core/io/util.odin
  14. 161 84
      core/math/bits/bits.odin
  15. 76 41
      core/math/ease/ease.odin
  16. 11 0
      core/math/fixed/fixed.odin
  17. 124 65
      core/math/linalg/extended.odin
  18. 94 56
      core/math/linalg/general.odin
  19. 351 351
      core/math/linalg/glsl/linalg_glsl.odin
  20. 50 48
      core/math/linalg/glsl/linalg_glsl_math.odin
  21. 350 350
      core/math/linalg/hlsl/linalg_hlsl.odin
  22. 58 56
      core/math/linalg/hlsl/linalg_hlsl_math.odin
  23. 224 112
      core/math/linalg/specific.odin
  24. 200 100
      core/math/linalg/specific_euler_angles_f16.odin
  25. 200 100
      core/math/linalg/specific_euler_angles_f32.odin
  26. 200 100
      core/math/linalg/specific_euler_angles_f64.odin
  27. 64 32
      core/math/linalg/swizzle.odin
  28. 289 225
      core/math/math.odin
  29. 27 23
      core/math/math_basic.odin
  30. 27 26
      core/math/math_basic_js.odin
  31. 14 12
      core/math/math_erf.odin
  32. 10 9
      core/math/math_gamma.odin
  33. 10 8
      core/math/math_lgamma.odin
  34. 9 8
      core/math/math_log1p.odin
  35. 9 0
      core/math/noise/opensimplex2.odin
  36. 26 0
      core/math/rand/distributions.odin
  37. 1 0
      core/math/rand/exp.odin
  38. 1 0
      core/math/rand/normal.odin
  39. 646 23
      core/math/rand/rand.odin
  40. 1 0
      core/math/rand/system_darwin.odin
  41. 1 0
      core/math/rand/system_linux.odin
  42. 1 0
      core/math/rand/system_windows.odin
  43. 33 33
      core/mem/alloc.odin
  44. 19 3
      core/mem/allocators.odin
  45. 2 1
      core/mem/doc.odin
  46. 28 0
      core/mem/mem.odin
  47. 4 0
      core/net/dns.odin
  48. 19 2
      core/net/socket_darwin.odin
  49. 5 1
      core/odin/ast/clone.odin
  50. 22 3
      core/os/os_darwin.odin
  51. 190 83
      core/runtime/core_builtin.odin
  52. 19 19
      core/runtime/core_builtin_matrix.odin
  53. 48 51
      core/runtime/core_builtin_soa.odin
  54. 89 24
      core/runtime/dynamic_map_internal.odin
  55. 36 0
      core/runtime/internal.odin
  56. 1 1
      core/runtime/os_specific_js.odin
  57. 2 2
      core/runtime/procs_wasm32.odin
  58. 67 19
      core/slice/slice.odin
  59. 8 1
      core/slice/sort.odin
  60. 7 3
      core/sync/futex_openbsd.odin
  61. 8 2
      core/sync/primitives_openbsd.odin
  62. 22 22
      core/sys/wasm/wasi/wasi_api.odin
  63. 2 1
      core/sys/windows/kernel32.odin
  64. 3 1
      core/sys/windows/user32.odin
  65. 0 1
      core/thread/thread_windows.odin
  66. 23 18
      core/unicode/utf8/utf8.odin
  67. 2 0
      examples/all/all_vendor.odin
  68. 1 3
      examples/demo/demo.odin
  69. 21 3
      src/build_settings.cpp
  70. 83 0
      src/check_builtin.cpp
  71. 14 10
      src/check_decl.cpp
  72. 48 29
      src/check_expr.cpp
  73. 26 2
      src/check_stmt.cpp
  74. 3 3
      src/check_type.cpp
  75. 30 5
      src/checker.cpp
  76. 2 0
      src/checker_builtin_procs.hpp
  77. 68 12
      src/docs_writer.cpp
  78. 27 10
      src/llvm_abi.cpp
  79. 26 15
      src/llvm_backend.cpp
  80. 1 1
      src/llvm_backend.hpp
  81. 10 5
      src/llvm_backend_const.cpp
  82. 1 1
      src/llvm_backend_debug.cpp
  83. 41 53
      src/llvm_backend_expr.cpp
  84. 2 2
      src/llvm_backend_general.cpp
  85. 11 1
      src/llvm_backend_opt.cpp
  86. 4 4
      src/llvm_backend_proc.cpp
  87. 206 46
      src/llvm_backend_stmt.cpp
  88. 36 11
      src/parser.cpp
  89. 11 1
      src/parser.hpp
  90. 2 2
      src/parser_pos.cpp
  91. 63 0
      src/path.cpp
  92. 3 3
      src/tokenizer.cpp
  93. 19 12
      src/types.cpp
  94. 1 1
      tests/core/crypto/test_core_crypto_modern.odin
  95. 15 1
      tests/core/encoding/json/test_core_json.odin
  96. 32 18
      tests/documentation/documentation_tester.odin
  97. 53 53
      vendor/darwin/Foundation/NSApplication.odin
  98. 7 7
      vendor/darwin/Foundation/NSArray.odin
  99. 6 6
      vendor/darwin/Foundation/NSAutoreleasePool.odin
  100. 37 37
      vendor/darwin/Foundation/NSBundle.odin

+ 8 - 1
build_odin.sh

@@ -135,7 +135,14 @@ build_odin() {
 		EXTRAFLAGS="-O3"
 		;;
 	release-native)
-		EXTRAFLAGS="-O3 -march=native"
+		local ARCH=$(uname -m)
+        	if [ "${ARCH}" == "arm64" ]; then
+            		# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
+            		EXTRAFLAGS="-O3 -mcpu=native"
+        	else
+            		# Use preferred flag for x86 / amd64
+            		EXTRAFLAGS="-O3 -march=native"
+        	fi
 		;;
 	nightly)
 		EXTRAFLAGS="-DNIGHTLY -O3"

+ 4 - 8
core/compress/shoco/shoco.odin

@@ -177,12 +177,10 @@ decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocato
 	max_output_size := decompress_bound(len(input), model)
 
 	buf: [dynamic]u8
-	if !resize(&buf, max_output_size) {
-		return "", .Out_Of_Memory
-	}
+	resize(&buf, max_output_size) or_return
 
 	length, result := decompress_slice_to_output_buffer(input, buf[:])
-	resize(&buf, length)
+	resize(&buf, length) or_return
 	return string(buf[:]), result
 }
 decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
@@ -307,12 +305,10 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
 	max_output_size := compress_bound(len(input))
 
 	buf: [dynamic]u8
-	if !resize(&buf, max_output_size) {
-		return {}, .Out_Of_Memory
-	}
+	resize(&buf, max_output_size) or_return
 
 	length, result := compress_string_to_buffer(input, buf[:])
-	resize(&buf, length)
+	resize(&buf, length) or_return
 	return buf[:length], result
 }
 compress :: proc{compress_string_to_buffer, compress_string}

+ 11 - 11
core/container/queue/queue.odin

@@ -14,7 +14,7 @@ Queue :: struct($T: typeid) {
 DEFAULT_CAPACITY :: 16
 
 // Procedure to initialize a queue
-init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
+init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error {
 	if q.data.allocator.procedure == nil {
 		q.data.allocator = allocator
 	}
@@ -55,11 +55,11 @@ space :: proc(q: $Q/Queue($T)) -> int {
 }
 
 // Reserve enough space for at least the specified capacity
-reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
+reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
 	if uint(capacity) > q.len {
 		return _grow(q, uint(capacity)) 
 	}
-	return true
+	return nil
 }
 
 
@@ -112,25 +112,25 @@ peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
 }
 
 // Push an element to the back of the queue
-push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
+push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
 	if space(q^) == 0 {
 		_grow(q) or_return
 	}
 	idx := (q.offset+uint(q.len))%builtin.len(q.data)
 	q.data[idx] = elem
 	q.len += 1
-	return true
+	return true, nil
 }
 
 // Push an element to the front of the queue
-push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
+push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error)  {
 	if space(q^) == 0 {
 		_grow(q) or_return
 	}	
 	q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
 	q.len += 1
 	q.data[q.offset] = elem
-	return true
+	return true, nil
 }
 
 
@@ -173,7 +173,7 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
 }
 
 // Push multiple elements to the front of the queue
-push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
+push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error)  {
 	n := uint(builtin.len(elems))
 	if space(q^) < int(n) {
 		_grow(q, q.len + n) or_return
@@ -188,7 +188,7 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
 	copy(q.data[insert_from:], elems[:insert_to])
 	copy(q.data[:insert_from], elems[insert_to:])
 	q.len += n
-	return true
+	return true, nil
 }
 
 // Consume `n` elements from the front of the queue
@@ -225,7 +225,7 @@ clear :: proc(q: ^$Q/Queue($T)) {
 
 
 // Internal growinh procedure
-_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
+_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error {
 	new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
 	n := uint(builtin.len(q.data))
 	builtin.resize(&q.data, int(new_capacity)) or_return
@@ -234,5 +234,5 @@ _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
 		copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
 		q.offset += new_capacity - n
 	}
-	return true
+	return nil
 }

+ 3 - 3
core/encoding/json/marshal.odin

@@ -153,7 +153,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
 		case complex128: r, i = f64(real(z)), f64(imag(z))
 		case: return .Unsupported_Type
 		}
-	
+
 		io.write_byte(w, '[')    or_return
 		io.write_f64(w, r)       or_return
 		io.write_string(w, ", ") or_return
@@ -165,8 +165,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
 
 	case runtime.Type_Info_String:
 		switch s in a {
-		case string:  io.write_quoted_string(w, s)         or_return
-		case cstring: io.write_quoted_string(w, string(s)) or_return
+		case string:  io.write_quoted_string(w, s, '"', nil, true)         or_return
+		case cstring: io.write_quoted_string(w, string(s), '"', nil, true) or_return
 		}
 
 	case runtime.Type_Info_Boolean:

+ 10 - 1
core/encoding/json/parser.odin

@@ -2,6 +2,7 @@ package json
 
 import "core:mem"
 import "core:unicode/utf8"
+import "core:unicode/utf16"
 import "core:strconv"
 
 Parser :: struct {
@@ -403,11 +404,19 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
 				}
 				i += 6
 
+				// If this is a surrogate pair, decode as such by taking the next rune too.
+				if r >= utf8.SURROGATE_MIN && r <= utf8.SURROGATE_HIGH_MAX && len(s) > i + 2 && s[i:i+2] == "\\u" {
+					r2 := get_u4_rune(s[i:])
+					if r2 >= utf8.SURROGATE_LOW_MIN && r2 <= utf8.SURROGATE_MAX {
+						i += 6
+						r = utf16.decode_surrogate_pair(r, r2)
+					}
+				}
+
 				buf, buf_width := utf8.encode_rune(r)
 				copy(b[w:], buf[:buf_width])
 				w += buf_width
 
-
 			case '0':
 				if spec != .JSON {
 					b[w] = '\x00'

+ 20 - 17
core/fmt/fmt.odin

@@ -1961,11 +1961,22 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
 	switch a in v {
 	case runtime.Source_Code_Location:
 		io.write_string(fi.writer, a.file_path, &fi.n)
-		io.write_byte(fi.writer, '(', &fi.n)
-		io.write_int(fi.writer, int(a.line), 10, &fi.n)
-		io.write_byte(fi.writer, ':', &fi.n)
-		io.write_int(fi.writer, int(a.column), 10, &fi.n)
-		io.write_byte(fi.writer, ')', &fi.n)
+
+		when ODIN_ERROR_POS_STYLE == .Default {
+			io.write_byte(fi.writer, '(', &fi.n)
+			io.write_int(fi.writer, int(a.line), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.column), 10, &fi.n)
+			io.write_byte(fi.writer, ')', &fi.n)
+		} else when ODIN_ERROR_POS_STYLE == .Unix {
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.line), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.column), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+		} else {
+			#panic("Unhandled ODIN_ERROR_POS_STYLE")
+		}
 		return
 
 	case time.Duration:
@@ -2647,18 +2658,10 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 		}
 	}
 
-
-	custom_types: switch a in arg {
-	case runtime.Source_Code_Location:
-		if fi.hash && verb == 'v' {
-			io.write_string(fi.writer, a.file_path,    &fi.n)
-			io.write_byte(fi.writer, '(',              &fi.n)
-			io.write_i64(fi.writer, i64(a.line), 10,   &fi.n)
-			io.write_byte(fi.writer, ':',              &fi.n)
-			io.write_i64(fi.writer, i64(a.column), 10, &fi.n)
-			io.write_byte(fi.writer, ')',              &fi.n)
-			return
-		}
+	arg_info := type_info_of(arg.id)
+	if info, ok := arg_info.variant.(runtime.Type_Info_Named); ok {
+		fmt_named(fi, arg, verb, info)
+		return
 	}
 
 	base_arg := arg

+ 1 - 1
core/fmt/fmt_js.odin

@@ -7,7 +7,7 @@ foreign import "odin_env"
 
 @(private="file")
 foreign odin_env {
-	write :: proc "c" (fd: u32, p: []byte) ---
+	write :: proc "contextless" (fd: u32, p: []byte) ---
 }
 
 @(private="file")

+ 5 - 5
core/image/common.odin

@@ -634,7 +634,7 @@ alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator :=
 	buf := bytes.Buffer{}
 
 	// Can we allocate the return buffer?
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		return false
 	}
@@ -826,7 +826,7 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al
 	buf := bytes.Buffer{}
 
 	// Can we allocate the return buffer?
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		return false
 	}
@@ -1075,7 +1075,7 @@ apply_palette_rgb :: proc(img: ^Image, palette: [256]RGB_Pixel, allocator := con
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		return false
 	}
@@ -1112,7 +1112,7 @@ apply_palette_rgba :: proc(img: ^Image, palette: [256]RGBA_Pixel, allocator := c
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		return false
 	}
@@ -1147,7 +1147,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		return false
 	}

+ 5 - 5
core/image/png/png.odin

@@ -731,7 +731,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 
@@ -812,7 +812,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16)
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 
@@ -1011,7 +1011,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 
@@ -1522,7 +1522,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 	bytes_per_channel := depth == 16 ? 2 : 1
 
 	num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8)
-	if !resize(&img.pixels.buf, num_bytes) {
+	if resize(&img.pixels.buf, num_bytes) != nil {
 		return .Unable_To_Allocate_Or_Resize
 	}
 
@@ -1564,7 +1564,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 			if x > 0 && y > 0 {
 				temp: bytes.Buffer
 				temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8)
-				if !resize(&temp.buf, temp_len) {
+				if resize(&temp.buf, temp_len) != nil {
 					return .Unable_To_Allocate_Or_Resize
 				}
 

+ 2 - 2
core/image/qoi/qoi.odin

@@ -53,7 +53,7 @@ save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	// Calculate and allocate maximum size. We'll reclaim space to actually written output at the end.
 	max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be)
 
-	if !resize(&output.buf, max_size) {
+	if resize(&output.buf, max_size) != nil {
 		return .Unable_To_Allocate_Or_Resize
 	}
 
@@ -233,7 +233,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 
 	bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8)
 
-	if !resize(&img.pixels.buf, bytes_needed) {
+	if resize(&img.pixels.buf, bytes_needed) != nil {
 	 	return img, .Unable_To_Allocate_Or_Resize
 	}
 

+ 2 - 2
core/image/tga/tga.odin

@@ -57,7 +57,7 @@ save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	// Calculate and allocate necessary space.
 	necessary := pixels * img.channels + size_of(image.TGA_Header)
 
-	if !resize(&output.buf, necessary) {
+	if resize(&output.buf, necessary) != nil {
 		return .Unable_To_Allocate_Or_Resize
 	}
 
@@ -292,7 +292,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		return img, nil
 	}
 
-	if !resize(&img.pixels.buf, dest_channels * img.width * img.height) {
+	if resize(&img.pixels.buf, dest_channels * img.width * img.height) != nil {
 		return img, .Unable_To_Allocate_Or_Resize
 	}
 

+ 1 - 0
core/intrinsics/intrinsics.odin

@@ -192,6 +192,7 @@ type_map_info      :: proc($T: typeid/map[$K]$V) -> ^runtime.Map_Info ---
 type_map_cell_info :: proc($T: typeid)           -> ^runtime.Map_Cell_Info ---
 
 type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
+type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
 
 constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
 

+ 21 - 8
core/io/util.odin

@@ -2,6 +2,7 @@ package io
 
 import "core:strconv"
 import "core:unicode/utf8"
+import "core:unicode/utf16"
 
 read_ptr :: proc(r: Reader, p: rawptr, byte_size: int, n_read: ^int = nil) -> (n: int, err: Error) {
 	return read(r, ([^]byte)(p)[:byte_size], n_read)
@@ -146,7 +147,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
 	return
 }
 
-write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, n_written: ^int = nil) -> (n: int, err: Error) {
+write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
 	is_printable :: proc(r: rune) -> bool {
 		if r <= 0xff {
 			switch r {
@@ -163,7 +164,7 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
 	defer if n_written != nil {
 		n_written^ += n
 	}
-	
+
 	if html_safe {
 		switch r {
 		case '<', '>', '&':
@@ -211,17 +212,29 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
 				write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
 			}
 		case:
-			write_byte(w, '\\', &n) or_return
-			write_byte(w, 'U', &n)  or_return
-			for s := 28; s >= 0; s -= 4 {
-				write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
+			if for_json {
+				buf: [2]u16
+				utf16.encode(buf[:], []rune{c})
+				for bc in buf {
+					write_byte(w, '\\', &n) or_return
+					write_byte(w, 'u', &n)  or_return
+					for s := 12; s >= 0; s -= 4 {
+						write_byte(w, DIGITS_LOWER[bc>>uint(s) & 0xf], &n) or_return
+					}
+				}
+			} else {
+				write_byte(w, '\\', &n) or_return
+				write_byte(w, 'U', &n)  or_return
+				for s := 24; s >= 0; s -= 4 {
+					write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
+				}
 			}
 		}
 	}
 	return
 }
 
-write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written: ^int = nil) -> (n: int, err: Error) {
+write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
 	defer if n_written != nil {
 		n_written^ += n
 	}
@@ -240,7 +253,7 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
 			continue
 		}
 
-		n_wrapper(write_escaped_rune(w, r, quote), &n) or_return
+		n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return
 
 	}
 	write_byte(w, quote, &n) or_return

+ 161 - 84
core/math/bits/bits.odin

@@ -37,68 +37,96 @@ overflowing_sub :: intrinsics.overflow_sub
 overflowing_mul :: intrinsics.overflow_mul
 
 
-log2 :: proc(x: $T) -> T where intrinsics.type_is_integer(T), intrinsics.type_is_unsigned(T) {
+@(require_results)
+log2 :: proc "contextless" (x: $T) -> T where intrinsics.type_is_integer(T), intrinsics.type_is_unsigned(T) {
 	return (8*size_of(T)-1) - count_leading_zeros(x)
 }
 
-rotate_left8 :: proc(x: u8,  k: int) -> u8 {
+@(require_results)
+rotate_left8 :: proc "contextless" (x: u8,  k: int) -> u8 {
 	n :: 8
 	s := uint(k) & (n-1)
 	return x <<s | x>>(n-s)
 }
-rotate_left16 :: proc(x: u16, k: int) -> u16 {
+@(require_results)
+rotate_left16 :: proc "contextless" (x: u16, k: int) -> u16 {
 	n :: 16
 	s := uint(k) & (n-1)
 	return x <<s | x>>(n-s)
 }
-rotate_left32 :: proc(x: u32, k: int) -> u32 {
+@(require_results)
+rotate_left32 :: proc "contextless" (x: u32, k: int) -> u32 {
 	n :: 32
 	s := uint(k) & (n-1)
 	return x <<s | x>>(n-s)
 }
-rotate_left64 :: proc(x: u64, k: int) -> u64 {
+@(require_results)
+rotate_left64 :: proc "contextless" (x: u64, k: int) -> u64 {
 	n :: 64
 	s := uint(k) & (n-1)
 	return x <<s | x>>(n-s)
 }
 
-rotate_left :: proc(x: uint, k: int) -> uint {
+@(require_results)
+rotate_left :: proc "contextless" (x: uint, k: int) -> uint {
 	n :: 8*size_of(uint)
 	s := uint(k) & (n-1)
 	return x <<s | x>>(n-s)
 }
 
-from_be_u8   :: proc(i:   u8) ->   u8 { return i }
-from_be_u16  :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-from_be_u32  :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-from_be_u64  :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-
-from_le_u8   :: proc(i:   u8) ->   u8 { return i }
-from_le_u16  :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-from_le_u32  :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-from_le_u64  :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-
-to_be_u8   :: proc(i:   u8) ->   u8 { return i }
-to_be_u16  :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-to_be_u32  :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-to_be_u64  :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
-
-
-to_le_u8   :: proc(i:   u8) ->   u8 { return i }
-to_le_u16  :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-to_le_u32  :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-to_le_u64  :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
-
-
-
-len_u8 :: proc(x: u8) -> int {
+@(require_results)
+from_be_u8   :: proc "contextless" (i:   u8) ->   u8 { return i }
+@(require_results)
+from_be_u16  :: proc "contextless" (i:  u16) ->  u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+from_be_u32  :: proc "contextless" (i:  u32) ->  u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+from_be_u64  :: proc "contextless" (i:  u64) ->  u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+from_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+
+@(require_results)
+from_le_u8   :: proc "contextless" (i:   u8) ->   u8 { return i }
+@(require_results)
+from_le_u16  :: proc "contextless" (i:  u16) ->  u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+from_le_u32  :: proc "contextless" (i:  u32) ->  u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+from_le_u64  :: proc "contextless" (i:  u64) ->  u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+from_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+
+@(require_results)
+to_be_u8   :: proc "contextless" (i:   u8) ->   u8 { return i }
+@(require_results)
+to_be_u16  :: proc "contextless" (i:  u16) ->  u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+to_be_u32  :: proc "contextless" (i:  u32) ->  u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+to_be_u64  :: proc "contextless" (i:  u64) ->  u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+@(require_results)
+to_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
+
+
+@(require_results)
+to_le_u8   :: proc "contextless" (i:   u8) ->   u8 { return i }
+@(require_results)
+to_le_u16  :: proc "contextless" (i:  u16) ->  u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+to_le_u32  :: proc "contextless" (i:  u32) ->  u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+to_le_u64  :: proc "contextless" (i:  u64) ->  u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+@(require_results)
+to_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
+
+
+
+@(require_results)
+len_u8 :: proc "contextless" (x: u8) -> int {
 	return int(len_u8_table[x])
 }
-len_u16 :: proc(x: u16) -> (n: int) {
+@(require_results)
+len_u16 :: proc "contextless" (x: u16) -> (n: int) {
 	x := x
 	if x >= 1<<8 {
 		x >>= 8
@@ -106,7 +134,8 @@ len_u16 :: proc(x: u16) -> (n: int) {
 	}
 	return n + int(len_u8_table[x])
 }
-len_u32 :: proc(x: u32) -> (n: int) {
+@(require_results)
+len_u32 :: proc "contextless" (x: u32) -> (n: int) {
 	x := x
 	if x >= 1<<16 {
 		x >>= 16
@@ -118,7 +147,8 @@ len_u32 :: proc(x: u32) -> (n: int) {
 	}
 	return n + int(len_u8_table[x])
 }
-len_u64 :: proc(x: u64) -> (n: int) {
+@(require_results)
+len_u64 :: proc "contextless" (x: u64) -> (n: int) {
 	x := x
 	if x >= 1<<32 {
 		x >>= 32
@@ -134,7 +164,8 @@ len_u64 :: proc(x: u64) -> (n: int) {
 	}
 	return n + int(len_u8_table[x])
 }
-len_uint :: proc(x: uint) -> (n: int) {
+@(require_results)
+len_uint :: proc "contextless" (x: uint) -> (n: int) {
 	when size_of(uint) == size_of(u64) {
 		return len_u64(u64(x))
 	} else {
@@ -146,21 +177,24 @@ len_uint :: proc(x: uint) -> (n: int) {
 len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint}
 
 
-add_u32 :: proc(x, y, carry: u32) -> (sum, carry_out: u32) {
+@(require_results)
+add_u32 :: proc "contextless" (x, y, carry: u32) -> (sum, carry_out: u32) {
 	tmp_carry, tmp_carry2: bool
 	sum, tmp_carry = intrinsics.overflow_add(x, y)
 	sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
 	carry_out = u32(tmp_carry | tmp_carry2)
 	return
 }
-add_u64 :: proc(x, y, carry: u64) -> (sum, carry_out: u64) {
+@(require_results)
+add_u64 :: proc "contextless" (x, y, carry: u64) -> (sum, carry_out: u64) {
 	tmp_carry, tmp_carry2: bool
 	sum, tmp_carry = intrinsics.overflow_add(x, y)
 	sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
 	carry_out = u64(tmp_carry | tmp_carry2)
 	return
 }
-add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) {
+@(require_results)
+add_uint :: proc "contextless" (x, y, carry: uint) -> (sum, carry_out: uint) {
 	when size_of(uint) == size_of(u64) {
 		a, b := add_u64(u64(x), u64(y), u64(carry))
 	} else {
@@ -172,21 +206,24 @@ add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) {
 add :: proc{add_u32, add_u64, add_uint}
 
 
-sub_u32 :: proc(x, y, borrow: u32) -> (diff, borrow_out: u32) {
+@(require_results)
+sub_u32 :: proc "contextless" (x, y, borrow: u32) -> (diff, borrow_out: u32) {
 	tmp_borrow, tmp_borrow2: bool
 	diff, tmp_borrow = intrinsics.overflow_sub(x, y)
 	diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
 	borrow_out = u32(tmp_borrow | tmp_borrow2)
 	return
 }
-sub_u64 :: proc(x, y, borrow: u64) -> (diff, borrow_out: u64) {
+@(require_results)
+sub_u64 :: proc "contextless" (x, y, borrow: u64) -> (diff, borrow_out: u64) {
 	tmp_borrow, tmp_borrow2: bool
 	diff, tmp_borrow = intrinsics.overflow_sub(x, y)
 	diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
 	borrow_out = u64(tmp_borrow | tmp_borrow2)
 	return
 }
-sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) {
+@(require_results)
+sub_uint :: proc "contextless" (x, y, borrow: uint) -> (diff, borrow_out: uint) {
 	when size_of(uint) == size_of(u64) {
 		a, b := sub_u64(u64(x), u64(y), u64(borrow))
 	} else {
@@ -198,18 +235,21 @@ sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) {
 sub :: proc{sub_u32, sub_u64, sub_uint}
 
 
-mul_u32 :: proc(x, y: u32) -> (hi, lo: u32) {
+@(require_results)
+mul_u32 :: proc "contextless" (x, y: u32) -> (hi, lo: u32) {
 	z := u64(x) * u64(y)
 	hi, lo = u32(z>>32), u32(z)
 	return
 }
-mul_u64 :: proc(x, y: u64) -> (hi, lo: u64) {
+@(require_results)
+mul_u64 :: proc "contextless" (x, y: u64) -> (hi, lo: u64) {
 	prod_wide := u128(x) * u128(y)
 	hi, lo = u64(prod_wide>>64), u64(prod_wide)
 	return
 }
 
-mul_uint :: proc(x, y: uint) -> (hi, lo: uint) {
+@(require_results)
+mul_uint :: proc "contextless" (x, y: uint) -> (hi, lo: uint) {
 	when size_of(uint) == size_of(u32) {
 		a, b := mul_u32(u32(x), u32(y))
 	} else {
@@ -222,13 +262,15 @@ mul_uint :: proc(x, y: uint) -> (hi, lo: uint) {
 mul :: proc{mul_u32, mul_u64, mul_uint}
 
 
-div_u32 :: proc(hi, lo, y: u32) -> (quo, rem: u32) {
+@(require_results)
+div_u32 :: proc "odin" (hi, lo, y: u32) -> (quo, rem: u32) {
 	assert(y != 0 && y <= hi)
 	z := u64(hi)<<32 | u64(lo)
 	quo, rem = u32(z/u64(y)), u32(z%u64(y))
 	return
 }
-div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) {
+@(require_results)
+div_u64 :: proc "odin" (hi, lo, y: u64) -> (quo, rem: u64) {
 	y := y
 	two32  :: 1 << 32
 	mask32 :: two32 - 1
@@ -273,7 +315,8 @@ div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) {
 
 	return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s
 }
-div_uint :: proc(hi, lo, y: uint) -> (quo, rem: uint) {
+@(require_results)
+div_uint :: proc "odin" (hi, lo, y: uint) -> (quo, rem: uint) {
 	when size_of(uint) == size_of(u32) {
 		a, b := div_u32(u32(hi), u32(lo), u32(y))
 	} else {
@@ -286,16 +329,26 @@ div :: proc{div_u32, div_u64, div_uint}
 
 
 
-is_power_of_two_u8   :: proc(i:   u8) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_i8   :: proc(i:   i8) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_u16  :: proc(i:  u16) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_i16  :: proc(i:  i16) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_u32  :: proc(i:  u32) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_i32  :: proc(i:  i32) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_u64  :: proc(i:  u64) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_i64  :: proc(i:  i64) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0 }
-is_power_of_two_int  :: proc(i:  int) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_u8   :: proc "contextless" (i:   u8) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_i8   :: proc "contextless" (i:   i8) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_u16  :: proc "contextless" (i:  u16) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_i16  :: proc "contextless" (i:  i16) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_u32  :: proc "contextless" (i:  u32) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_i32  :: proc "contextless" (i:  i32) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_u64  :: proc "contextless" (i:  u64) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_i64  :: proc "contextless" (i:  i64) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_uint :: proc "contextless" (i: uint) -> bool { return i > 0 && (i & (i-1)) == 0 }
+@(require_results)
+is_power_of_two_int  :: proc "contextless" (i:  int) -> bool { return i > 0 && (i & (i-1)) == 0 }
 
 is_power_of_two :: proc{
 	is_power_of_two_u8,   is_power_of_two_i8,
@@ -320,44 +373,56 @@ len_u8_table := [256]u8{
 }
 
 
-bitfield_extract_u8   :: proc(value:   u8, offset, bits: uint) ->   u8 { return (value >> offset) &   u8(1<<bits - 1) }
-bitfield_extract_u16  :: proc(value:  u16, offset, bits: uint) ->  u16 { return (value >> offset) &  u16(1<<bits - 1) }
-bitfield_extract_u32  :: proc(value:  u32, offset, bits: uint) ->  u32 { return (value >> offset) &  u32(1<<bits - 1) }
-bitfield_extract_u64  :: proc(value:  u64, offset, bits: uint) ->  u64 { return (value >> offset) &  u64(1<<bits - 1) }
-bitfield_extract_u128 :: proc(value: u128, offset, bits: uint) -> u128 { return (value >> offset) & u128(1<<bits - 1) }
-bitfield_extract_uint :: proc(value: uint, offset, bits: uint) -> uint { return (value >> offset) & uint(1<<bits - 1) }
+@(require_results)
+bitfield_extract_u8   :: proc "contextless" (value:   u8, offset, bits: uint) ->   u8 { return (value >> offset) &   u8(1<<bits - 1) }
+@(require_results)
+bitfield_extract_u16  :: proc "contextless" (value:  u16, offset, bits: uint) ->  u16 { return (value >> offset) &  u16(1<<bits - 1) }
+@(require_results)
+bitfield_extract_u32  :: proc "contextless" (value:  u32, offset, bits: uint) ->  u32 { return (value >> offset) &  u32(1<<bits - 1) }
+@(require_results)
+bitfield_extract_u64  :: proc "contextless" (value:  u64, offset, bits: uint) ->  u64 { return (value >> offset) &  u64(1<<bits - 1) }
+@(require_results)
+bitfield_extract_u128 :: proc "contextless" (value: u128, offset, bits: uint) -> u128 { return (value >> offset) & u128(1<<bits - 1) }
+@(require_results)
+bitfield_extract_uint :: proc "contextless" (value: uint, offset, bits: uint) -> uint { return (value >> offset) & uint(1<<bits - 1) }
 
-bitfield_extract_i8 :: proc(value: i8, offset, bits: uint) -> i8 {
+@(require_results)
+bitfield_extract_i8 :: proc "contextless" (value: i8, offset, bits: uint) -> i8 {
 	v := (u8(value) >> offset) & u8(1<<bits - 1)
 	m := u8(1<<(bits-1))
 	r := (v~m) - m
 	return i8(r)
 }
-bitfield_extract_i16 :: proc(value: i16, offset, bits: uint) -> i16 {
+@(require_results)
+bitfield_extract_i16 :: proc "contextless" (value: i16, offset, bits: uint) -> i16 {
 	v := (u16(value) >> offset) & u16(1<<bits - 1)
 	m := u16(1<<(bits-1))
 	r := (v~m) - m
 	return i16(r)
 }
-bitfield_extract_i32 :: proc(value: i32, offset, bits: uint) -> i32 {
+@(require_results)
+bitfield_extract_i32 :: proc "contextless" (value: i32, offset, bits: uint) -> i32 {
 	v := (u32(value) >> offset) & u32(1<<bits - 1)
 	m := u32(1<<(bits-1))
 	r := (v~m) - m
 	return i32(r)
 }
-bitfield_extract_i64 :: proc(value: i64, offset, bits: uint) -> i64 {
+@(require_results)
+bitfield_extract_i64 :: proc "contextless" (value: i64, offset, bits: uint) -> i64 {
 	v := (u64(value) >> offset) & u64(1<<bits - 1)
 	m := u64(1<<(bits-1))
 	r := (v~m) - m
 	return i64(r)
 }
-bitfield_extract_i128 :: proc(value: i128, offset, bits: uint) -> i128 {
+@(require_results)
+bitfield_extract_i128 :: proc "contextless" (value: i128, offset, bits: uint) -> i128 {
 	v := (u128(value) >> offset) & u128(1<<bits - 1)
 	m := u128(1<<(bits-1))
 	r := (v~m) - m
 	return i128(r)
 }
-bitfield_extract_int :: proc(value: int, offset, bits: uint) -> int {
+@(require_results)
+bitfield_extract_int :: proc "contextless" (value: int, offset, bits: uint) -> int {
 	v := (uint(value) >> offset) & uint(1<<bits - 1)
 	m := uint(1<<(bits-1))
 	r := (v~m) - m
@@ -381,52 +446,64 @@ bitfield_extract :: proc{
 }
 
 
-bitfield_insert_u8 :: proc(base, insert: u8, offset, bits: uint) -> u8 {
+@(require_results)
+bitfield_insert_u8 :: proc "contextless" (base, insert: u8, offset, bits: uint) -> u8 {
 	mask := u8(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_u16 :: proc(base, insert: u16, offset, bits: uint) -> u16 {
+@(require_results)
+bitfield_insert_u16 :: proc "contextless" (base, insert: u16, offset, bits: uint) -> u16 {
 	mask := u16(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_u32 :: proc(base, insert: u32, offset, bits: uint) -> u32 {
+@(require_results)
+bitfield_insert_u32 :: proc "contextless" (base, insert: u32, offset, bits: uint) -> u32 {
 	mask := u32(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_u64 :: proc(base, insert: u64, offset, bits: uint) -> u64 {
+@(require_results)
+bitfield_insert_u64 :: proc "contextless" (base, insert: u64, offset, bits: uint) -> u64 {
 	mask := u64(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_u128 :: proc(base, insert: u128, offset, bits: uint) -> u128 {
+@(require_results)
+bitfield_insert_u128 :: proc "contextless" (base, insert: u128, offset, bits: uint) -> u128 {
 	mask := u128(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_uint :: proc(base, insert: uint, offset, bits: uint) -> uint {
+@(require_results)
+bitfield_insert_uint :: proc "contextless" (base, insert: uint, offset, bits: uint) -> uint {
 	mask := uint(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
 
-bitfield_insert_i8 :: proc(base, insert: i8, offset, bits: uint) -> i8 {
+@(require_results)
+bitfield_insert_i8 :: proc "contextless" (base, insert: i8, offset, bits: uint) -> i8 {
 	mask := i8(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_i16 :: proc(base, insert: i16, offset, bits: uint) -> i16 {
+@(require_results)
+bitfield_insert_i16 :: proc "contextless" (base, insert: i16, offset, bits: uint) -> i16 {
 	mask := i16(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_i32 :: proc(base, insert: i32, offset, bits: uint) -> i32 {
+@(require_results)
+bitfield_insert_i32 :: proc "contextless" (base, insert: i32, offset, bits: uint) -> i32 {
 	mask := i32(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_i64 :: proc(base, insert: i64, offset, bits: uint) -> i64 {
+@(require_results)
+bitfield_insert_i64 :: proc "contextless" (base, insert: i64, offset, bits: uint) -> i64 {
 	mask := i64(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_i128 :: proc(base, insert: i128, offset, bits: uint) -> i128 {
+@(require_results)
+bitfield_insert_i128 :: proc "contextless" (base, insert: i128, offset, bits: uint) -> i128 {
 	mask := i128(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }
-bitfield_insert_int :: proc(base, insert: int, offset, bits: uint) -> int {
+@(require_results)
+bitfield_insert_int :: proc "contextless" (base, insert: int, offset, bits: uint) -> int {
 	mask := int(1<<bits - 1)
 	return (base &~ (mask<<offset)) | ((insert&mask) << offset)
 }

+ 76 - 41
core/math/ease/ease.odin

@@ -11,11 +11,13 @@ import "core:time"
 // with additional enum based call
 
 // Modeled after the parabola y = x^2
+@(require_results)
 quadratic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p * p
 }
 
 // Modeled after the parabola y = -x^2 + 2x
+@(require_results)
 quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return -(p * (p - 2))
 }
@@ -23,6 +25,7 @@ quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(
 // Modeled after the piecewise quadratic
 // y = (1/2)((2x)^2)             ; [0, 0.5)
 // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
+@(require_results)
 quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 2 * p * p
@@ -32,11 +35,13 @@ quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_flo
 }
 
 // Modeled after the cubic y = x^3
+@(require_results)
 cubic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p * p * p
 }
 
 // Modeled after the cubic y = (x - 1)^3 + 1
+@(require_results)
 cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	f := p - 1
 	return f * f * f + 1
@@ -45,6 +50,7 @@ cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 // Modeled after the piecewise cubic
 // y = (1/2)((2x)^3)       ; [0, 0.5)
 // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
+@(require_results)
 cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 4 * p * p * p
@@ -55,11 +61,13 @@ cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T
 }
 
 // Modeled after the quartic x^4
+@(require_results)
 quartic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p * p * p * p
 }
 
 // Modeled after the quartic y = 1 - (x - 1)^4
+@(require_results)
 quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	f := p - 1
 	return f * f * f * (1 - p) + 1
@@ -68,6 +76,7 @@ quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
 // Modeled after the piecewise quartic
 // y = (1/2)((2x)^4)        ; [0, 0.5)
 // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
+@(require_results)
 quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 8 * p * p * p * p
@@ -78,11 +87,13 @@ quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
 }
 
 // Modeled after the quintic y = x^5
+@(require_results)
 quintic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p * p * p * p * p
 }
 
 // Modeled after the quintic y = (x - 1)^5 + 1
+@(require_results)
 quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	f := p - 1
 	return f * f * f * f * f + 1
@@ -91,6 +102,7 @@ quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
 // Modeled after the piecewise quintic
 // y = (1/2)((2x)^5)       ; [0, 0.5)
 // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
+@(require_results)
 quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 16 * p * p * p * p * p
@@ -101,26 +113,31 @@ quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
 }
 
 // Modeled after quarter-cycle of sine wave
+@(require_results)
 sine_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return math.sin((p - 1) * PI_2) + 1
 }
 
 // Modeled after quarter-cycle of sine wave (different phase)
+@(require_results)
 sine_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return math.sin(p * PI_2)
 }
 
 // Modeled after half sine wave
+@(require_results)
 sine_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return 0.5 * (1 - math.cos(p * math.PI))
 }
 
 // Modeled after shifted quadrant IV of unit circle
+@(require_results)
 circular_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return 1 - math.sqrt(1 - (p * p))
 }
 
 // Modeled after shifted quadrant II of unit circle
+@(require_results)
 circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return math.sqrt((2 - p) * p)
 }
@@ -128,6 +145,7 @@ circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T
 // Modeled after the piecewise circular function
 // y = (1/2)(1 - sqrt(1 - 4x^2))           ; [0, 0.5)
 // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
+@(require_results)
 circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 0.5 * (1 - math.sqrt(1 - 4 * (p * p)))
@@ -137,11 +155,13 @@ circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_floa
 }
 
 // Modeled after the exponential function y = 2^(10(x - 1))
+@(require_results)
 exponential_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p == 0.0 ? p : math.pow(2, 10 * (p - 1))
 }
 
 // Modeled after the exponential function y = -2^(-10x) + 1
+@(require_results)
 exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p == 1.0 ? p : 1 - math.pow(2, -10 * p)
 }
@@ -149,6 +169,7 @@ exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_floa
 // Modeled after the piecewise exponential
 // y = (1/2)2^(10(2x - 1))         ; [0,0.5)
 // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
+@(require_results)
 exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p == 0.0 || p == 1.0 {
 		return p
@@ -162,11 +183,13 @@ exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_f
 }
 
 // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
+@(require_results)
 elastic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return math.sin(13 * PI_2 * p) * math.pow(2, 10 * (p - 1))
 }
 
 // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
+@(require_results)
 elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return math.sin(-13 * PI_2 * (p + 1)) * math.pow(2, -10 * p) + 1
 }
@@ -174,6 +197,7 @@ elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
 // Modeled after the piecewise exponentially-damped sine wave:
 // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1))      ; [0,0.5)
 // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
+@(require_results)
 elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 0.5 * math.sin(13 * PI_2 * (2 * p)) * math.pow(2, 10 * ((2 * p) - 1))
@@ -183,11 +207,13 @@ elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
 }
 
 // Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
+@(require_results)
 back_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return p * p * p - p * math.sin(p * math.PI)
 }
 
 // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
+@(require_results)
 back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	f := 1 - p
 	return 1 - (f * f * f - f * math.sin(f * math.PI))
@@ -196,6 +222,7 @@ back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 // Modeled after the piecewise overshooting cubic function:
 // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi))           ; [0, 0.5)
 // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
+@(require_results)
 back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		f := 2 * p
@@ -206,10 +233,12 @@ back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
 	}
 }
 
+@(require_results)
 bounce_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	return 1 - bounce_out(1 - p)
 }
 
+@(require_results)
 bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 4/11.0 {
 		return (121 * p * p)/16.0
@@ -222,6 +251,7 @@ bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
 	}
 }
 
+@(require_results)
 bounce_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
 	if p < 0.5 {
 		return 0.5 * bounce_in(p*2)
@@ -276,50 +306,51 @@ Ease :: enum {
 	Bounce_In_Out,
 }
 
+@(require_results)
 ease :: proc "contextless" (type: Ease, p: $T) -> T 
 	where intrinsics.type_is_float(T) {
 	switch type {
-		case .Linear: return p
-		
-		case .Quadratic_In: return quadratic_in(p)
-		case .Quadratic_Out: return quadratic_out(p)
-		case .Quadratic_In_Out: return quadratic_in_out(p)
-
-		case .Cubic_In: return cubic_in(p)
-		case .Cubic_Out: return cubic_out(p)
-		case .Cubic_In_Out: return cubic_in_out(p)
-
-		case .Quartic_In: return quartic_in(p)
-		case .Quartic_Out: return quartic_out(p)
-		case .Quartic_In_Out: return quartic_in_out(p)
-
-		case .Quintic_In: return quintic_in(p)
-		case .Quintic_Out: return quintic_out(p)
-		case .Quintic_In_Out: return quintic_in_out(p)
-
-		case .Sine_In: return sine_in(p)
-		case .Sine_Out: return sine_out(p)
-		case .Sine_In_Out: return sine_in_out(p)
-
-		case .Circular_In: return circular_in(p)
-		case .Circular_Out: return circular_out(p)
-		case .Circular_In_Out: return circular_in_out(p)
-
-		case .Exponential_In: return exponential_in(p)
-		case .Exponential_Out: return exponential_out(p)
-		case .Exponential_In_Out: return exponential_in_out(p)
-
-		case .Elastic_In: return elastic_in(p)
-		case .Elastic_Out: return elastic_out(p)
-		case .Elastic_In_Out: return elastic_in_out(p)
-
-		case .Back_In: return back_in(p)
-		case .Back_Out: return back_out(p)
-		case .Back_In_Out: return back_in_out(p)
-
-		case .Bounce_In: return bounce_in(p)
-		case .Bounce_Out: return bounce_out(p)
-		case .Bounce_In_Out: return bounce_in_out(p)
+	case .Linear: return p
+
+	case .Quadratic_In: return quadratic_in(p)
+	case .Quadratic_Out: return quadratic_out(p)
+	case .Quadratic_In_Out: return quadratic_in_out(p)
+
+	case .Cubic_In: return cubic_in(p)
+	case .Cubic_Out: return cubic_out(p)
+	case .Cubic_In_Out: return cubic_in_out(p)
+
+	case .Quartic_In: return quartic_in(p)
+	case .Quartic_Out: return quartic_out(p)
+	case .Quartic_In_Out: return quartic_in_out(p)
+
+	case .Quintic_In: return quintic_in(p)
+	case .Quintic_Out: return quintic_out(p)
+	case .Quintic_In_Out: return quintic_in_out(p)
+
+	case .Sine_In: return sine_in(p)
+	case .Sine_Out: return sine_out(p)
+	case .Sine_In_Out: return sine_in_out(p)
+
+	case .Circular_In: return circular_in(p)
+	case .Circular_Out: return circular_out(p)
+	case .Circular_In_Out: return circular_in_out(p)
+
+	case .Exponential_In: return exponential_in(p)
+	case .Exponential_Out: return exponential_out(p)
+	case .Exponential_In_Out: return exponential_in_out(p)
+
+	case .Elastic_In: return elastic_in(p)
+	case .Elastic_Out: return elastic_out(p)
+	case .Elastic_In_Out: return elastic_in_out(p)
+
+	case .Back_In: return back_in(p)
+	case .Back_Out: return back_out(p)
+	case .Back_In_Out: return back_in_out(p)
+
+	case .Bounce_In: return bounce_in(p)
+	case .Bounce_Out: return bounce_out(p)
+	case .Bounce_In_Out: return bounce_in_out(p)
 	}
 
 	// in case type was invalid
@@ -353,6 +384,7 @@ Flux_Tween :: struct($T: typeid) {
 }
 
 // init flux map to a float type and a wanted cap
+@(require_results)
 flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
 	return {
 		values = make(map[^T]Flux_Tween(T), value_capacity),
@@ -374,6 +406,7 @@ flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
 // append / overwrite existing tween value to parameters
 // rest is initialized in flux_tween_init, inside update
 // return value can be used to set callbacks
+@(require_results)
 flux_to :: proc(
 	flux: ^Flux_Map($T),
 	value: ^T, 
@@ -475,6 +508,7 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
 
 // stop a specific key inside the map
 // returns true when it successfully removed the key
+@(require_results)
 flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
 	if key in flux.values {
 		delete_key(&flux.values, key)
@@ -486,6 +520,7 @@ flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is
 
 // returns the amount of time left for the tween animation, if the key exists in the map
 // returns 0 if the tween doesnt exist on the map
+@(require_results)
 flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 {
 	if tween, ok := flux.values[key]; ok {
 		return ((1 - tween.progress) * tween.rate) + tween.delay

+ 11 - 0
core/math/fixed/fixed.odin

@@ -50,39 +50,48 @@ to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
 }
 
 
+@(require_results)
 add :: proc(x, y: $T/Fixed) -> T {
 	return {x.i + y.i}
 }
+@(require_results)
 sub :: proc(x, y: $T/Fixed) -> T {
 	return {x.i - y.i}
 }
 
+@(require_results)
 mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
 	z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width)
 	return
 }
+@(require_results)
 mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
 	z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width)
 	return
 }
 
+@(require_results)
 div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
 	z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width)
 	return
 }
+@(require_results)
 div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
 	z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width)
 	return
 }
 
 
+@(require_results)
 floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
 	return x.i >> Fraction_Width
 }
+@(require_results)
 ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
 	Integer :: 8*size_of(Backing) - Fraction_Width
 	return (x.i + (1 << Integer-1)) >> Fraction_Width
 }
+@(require_results)
 round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
 	Integer :: 8*size_of(Backing) - Fraction_Width
 	return (x.i + (1 << (Integer - 1))) >> Fraction_Width
@@ -90,6 +99,7 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
 
 
 
+@(require_results)
 append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
 	x := x
 	buf: [48]byte
@@ -123,6 +133,7 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
 }
 
 
+@(require_results)
 to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
 	buf: [48]byte
 	s := append(buf[:], x)

+ 124 - 65
core/math/linalg/extended.odin

@@ -3,7 +3,8 @@ package linalg
 import "core:builtin"
 import "core:math"
 
-to_radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = degrees[i] * RAD_PER_DEG
@@ -14,7 +15,8 @@ to_radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-to_degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+to_degrees :: proc "contextless" (radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = radians[i] * DEG_PER_RAD
@@ -25,7 +27,8 @@ to_degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+min_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = builtin.min(a[i], b[i])
@@ -36,7 +39,8 @@ min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-min_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+min_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		N :: len(T)
 
@@ -56,13 +60,15 @@ min_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
 	return
 }
 
-min_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+min_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
 	return min_double(a, min_double(b, c))
 }
 
 min :: proc{min_single, min_double, min_triple}
 
-max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+max_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = builtin.max(a[i], b[i])
@@ -73,7 +79,8 @@ max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+max_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		N :: len(T)
 
@@ -95,13 +102,15 @@ max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
 	return
 }
 
-max_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+max_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
 	return max_double(a, max_double(b, c))
 }
 
 max :: proc{max_single, max_double, max_triple}
 
-abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = auto_cast builtin.abs(a[i])
@@ -112,7 +121,8 @@ abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+sign :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = #force_inline math.sign(a[i])
@@ -123,7 +133,8 @@ sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	return
 }
 
-clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+@(require_results)
+clamp :: proc "contextless" (x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = builtin.clamp(x[i], a[i], b[i])
@@ -135,11 +146,13 @@ clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 }
 
 
-saturate :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+saturate :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	return clamp(x, 0.0, 1.0)
 }
 
-lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = a[i]*(1-t[i]) + b[i]*t[i]
@@ -149,7 +162,8 @@ lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	}
 	return
 }
-mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+mix :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = a[i]*(1-t[i]) + b[i]*t[i]
@@ -160,11 +174,13 @@ mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-unlerp :: proc(a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+unlerp :: proc "contextless" (a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	return (x - a) / (b - a)
 }
 
-step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+step :: proc "contextless" (e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = x[i] < e[i] ? 0.0 : 1.0
@@ -175,18 +191,21 @@ step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-smoothstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+smoothstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	t := saturate(unlerp(e0, e1, x))
 	return t * t * (3.0 - 2.0 * t)
 }
 
-smootherstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+smootherstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	t := saturate(unlerp(e0, e1, x))
 	return t * t * t * (t * (6*t - 15) + 10)
 }
 
 
-sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.sqrt(x[i])
@@ -197,7 +216,8 @@ sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+inverse_sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = 1.0/math.sqrt(x[i])
@@ -208,7 +228,8 @@ inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+cos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.cos(x[i])
@@ -219,7 +240,8 @@ cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+sin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.sin(x[i])
@@ -230,7 +252,8 @@ sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+tan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.tan(x[i])
@@ -241,7 +264,8 @@ tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+acos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.acos(x[i])
@@ -252,7 +276,8 @@ acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+asin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.asin(x[i])
@@ -263,7 +288,8 @@ asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+atan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.atan(x[i])
@@ -273,7 +299,8 @@ atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	}
 	return
 }
-atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+atan2 :: proc "contextless" (y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.atan2(y[i], x[i])
@@ -285,7 +312,8 @@ atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 }
 
 
-ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+ln :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.ln(x[i])
@@ -296,7 +324,8 @@ ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+log2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = INVLN2 * math.ln(x[i])
@@ -307,7 +336,8 @@ log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+log10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = INVLN10 * math.ln(x[i])
@@ -318,7 +348,8 @@ log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+log :: proc "contextless" (x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i])
@@ -329,7 +360,8 @@ log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+exp :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.exp(x[i])
@@ -340,7 +372,8 @@ exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+exp2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.exp(LN2 * x[i])
@@ -351,7 +384,8 @@ exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+exp10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.exp(LN10 * x[i])
@@ -362,7 +396,8 @@ exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+pow :: proc "contextless" (x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = math.pow(x[i], e[i])
@@ -374,7 +409,8 @@ pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 }
 
 
-ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+ceil :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = #force_inline math.ceil(x[i])
@@ -385,7 +421,8 @@ ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+floor :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = #force_inline math.floor(x[i])
@@ -396,7 +433,8 @@ floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+round :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
 			out[i] = #force_inline math.round(x[i])
@@ -407,30 +445,36 @@ round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
 	return
 }
 
-fract :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+fract :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	f := #force_inline floor(x)
 	return x - f
 }
 
-mod :: proc(x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+mod :: proc "contextless" (x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
 	f := #force_inline floor(x / m)
 	return x - f * m
 }
 
 
-face_forward :: proc(N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+face_forward :: proc "contextless" (N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
 	return dot(N_ref, I) < 0 ? N : -N
 }
 
-distance :: proc(p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
+@(require_results)
+distance :: proc "contextless" (p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
 	return length(p1 - p0)
 }
 
-reflect :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
+@(require_results)
+reflect :: proc "contextless" (I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
 	b := N * (2 * dot(N, I))
 	return I - b
 }
-refract :: proc(I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) {
+@(require_results)
+refract :: proc "contextless" (I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) {
 	dv := dot(Normal, I)
 	k := 1 - eta*eta * (1 - dv*dv)
 	a := I * eta
@@ -441,33 +485,39 @@ refract :: proc(I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_
 
 
 
-is_nan_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
+@(require_results)
+is_nan_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
 	return #force_inline math.is_nan(x)
 }
 
-is_nan_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
+@(require_results)
+is_nan_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
 	for i in 0..<N {
 		out[i] = #force_inline is_nan(x[i])
 	}
 	return
 }
 
-is_inf_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
+@(require_results)
+is_inf_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
 	return #force_inline math.is_inf(x)
 }
 
-is_inf_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
+@(require_results)
+is_inf_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
 	for i in 0..<N {
 		out[i] = #force_inline is_inf(x[i])
 	}
 	return
 }
 
-classify_single :: proc(x: $T) -> math.Float_Class where IS_FLOAT(T) {
+@(require_results)
+classify_single :: proc "contextless" (x: $T) -> math.Float_Class where IS_FLOAT(T) {
 	return #force_inline math.classify(x)
 }
 
-classify_array :: proc(x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
+@(require_results)
+classify_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
 	for i in 0..<N {
 		out[i] = #force_inline classify_single(x[i])
 	}
@@ -479,44 +529,50 @@ is_inf :: proc{is_inf_single, is_inf_array}
 classify :: proc{classify_single, classify_array}
 
 
-less_than_single          :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y }
-less_than_equal_single    :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y }
-greater_than_single       :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y }
-greater_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y }
-equal_single              :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y }
-not_equal_single          :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y }
+@(require_results) less_than_single          :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y }
+@(require_results) less_than_equal_single    :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y }
+@(require_results) greater_than_single       :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y }
+@(require_results) greater_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y }
+@(require_results) equal_single              :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y }
+@(require_results) not_equal_single          :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y }
 
-less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+less_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] < y[i]
 	}
 	return
 }
-less_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+less_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] <= y[i]
 	}
 	return
 }
-greater_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+greater_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] > y[i]
 	}
 	return
 }
-greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+greater_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] >= y[i]
 	}
 	return
 }
-equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] == y[i]
 	}
 	return
 }
-not_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
+@(require_results)
+not_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
 	for i in 0..<N {
 		out[i] = x[i] != y[i]
 	}
@@ -530,7 +586,8 @@ greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array}
 equal              :: proc{equal_single, equal_array}
 not_equal          :: proc{not_equal_single, not_equal_array}
 
-any :: proc(x: $A/[$N]bool) -> (out: bool) {
+@(require_results)
+any :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
 	for e in x {
 		if e {
 			return true
@@ -538,7 +595,8 @@ any :: proc(x: $A/[$N]bool) -> (out: bool) {
 	}
 	return false
 }
-all :: proc(x: $A/[$N]bool) -> (out: bool) {
+@(require_results)
+all :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
 	for e in x {
 		if !e {
 			return false
@@ -546,7 +604,8 @@ all :: proc(x: $A/[$N]bool) -> (out: bool) {
 	}
 	return true
 }
-not :: proc(x: $A/[$N]bool) -> (out: A) {
+@(require_results)
+not :: proc "contextless" (x: $A/[$N]bool) -> (out: A) {
 	for e, i in x {
 		out[i] = !e
 	}

+ 94 - 56
core/math/linalg/general.odin

@@ -38,23 +38,28 @@ DEG_PER_RAD :: 360.0/TAU
 @private ELEM_TYPE :: intrinsics.type_elem_type
 
 
-scalar_dot :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
+@(require_results)
+scalar_dot :: proc "contextless" (a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
 	return a * b
 }
 
-vector_dot :: proc(a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check {
+@(require_results)
+vector_dot :: proc "contextless" (a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check {
 	for i in 0..<N {
 		c += a[i] * b[i]
 	}
 	return
 }
-quaternion64_dot :: proc(a, b: $T/quaternion64) -> (c: f16) {
+@(require_results)
+quaternion64_dot :: proc "contextless" (a, b: $T/quaternion64) -> (c: f16) {
 	return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
 }
-quaternion128_dot :: proc(a, b: $T/quaternion128) -> (c: f32) {
+@(require_results)
+quaternion128_dot :: proc "contextless" (a, b: $T/quaternion128) -> (c: f32) {
 	return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
 }
-quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) {
+@(require_results)
+quaternion256_dot :: proc "contextless" (a, b: $T/quaternion256) -> (c: f64) {
 	return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
 }
 
@@ -63,27 +68,32 @@ dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quatern
 inner_product :: dot
 outer_product :: builtin.outer_product
 
-quaternion_inverse :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
 	return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
 }
 
 
-scalar_cross :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
+@(require_results)
+scalar_cross :: proc "contextless" (a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
 	return a * b
 }
 
-vector_cross2 :: proc(a, b: $T/[2]$E) -> E where IS_NUMERIC(E) {
+@(require_results)
+vector_cross2 :: proc "contextless" (a, b: $T/[2]$E) -> E where IS_NUMERIC(E) {
 	return a[0]*b[1] - b[0]*a[1]
 }
 
-vector_cross3 :: proc(a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) {
+@(require_results)
+vector_cross3 :: proc "contextless" (a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) {
 	c[0] = a[1]*b[2] - b[1]*a[2]
 	c[1] = a[2]*b[0] - b[2]*a[0]
 	c[2] = a[0]*b[1] - b[0]*a[1]
 	return
 }
 
-quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_cross :: proc "contextless" (q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
 	q3.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
 	q3.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
 	q3.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
@@ -94,49 +104,59 @@ quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
 vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}
 cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}
 
-vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
+@(require_results)
+vector_normalize :: proc "contextless" (v: $T/[$N]$E) -> T where IS_FLOAT(E) {
 	return v / length(v)
 }
-quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_normalize :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
 	return q/abs(q)
 }
 normalize :: proc{vector_normalize, quaternion_normalize}
 
-vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
+@(require_results)
+vector_normalize0 :: proc "contextless" (v: $T/[$N]$E) -> T where IS_FLOAT(E) {
 	m := length(v)
 	return 0 if m == 0 else v/m
 }
-quaternion_normalize0 :: proc(q: $Q) -> Q  where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_normalize0 :: proc "contextless" (q: $Q) -> Q  where IS_QUATERNION(Q) {
 	m := abs(q)
 	return 0 if m == 0 else q/m
 }
 normalize0 :: proc{vector_normalize0, quaternion_normalize0}
 
 
-vector_length :: proc(v: $T/[$N]$E) -> E where IS_FLOAT(E) {
+@(require_results)
+vector_length :: proc "contextless" (v: $T/[$N]$E) -> E where IS_FLOAT(E) {
 	return math.sqrt(dot(v, v))
 }
 
-vector_length2 :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
+@(require_results)
+vector_length2 :: proc "contextless" (v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
 	return dot(v, v)
 }
 
-quaternion_length :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_length :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
 	return abs(q)
 }
 
-quaternion_length2 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_length2 :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
 	return dot(q, q)
 }
 
-scalar_triple_product :: proc(a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) {
+@(require_results)
+scalar_triple_product :: proc "contextless" (a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) {
 	// a . (b x c)
 	// b . (c x a)
 	// c . (a x b)
 	return dot(a, cross(b, c))
 }
 
-vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
+@(require_results)
+vector_triple_product :: proc "contextless" (a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
 	// a x (b x c)
 	// (a . c)b - (a . b)c
 	return cross(a, cross(b, c))
@@ -146,11 +166,13 @@ vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
 length :: proc{vector_length, quaternion_length}
 length2 :: proc{vector_length2, quaternion_length2}
 
-projection :: proc(x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
+@(require_results)
+projection :: proc "contextless" (x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
 	return dot(x, normal) / dot(normal, normal) * normal
 }
 
-identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
+@(require_results)
+identity :: proc "contextless" ($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
 	for i in 0..<N {
 		m[i][i] = E(1)
 	}
@@ -160,32 +182,38 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
 trace :: builtin.matrix_trace
 transpose :: builtin.transpose
 
-matrix_mul :: proc(a, b: $M/matrix[$N, N]$E) -> (c: M)
+@(require_results)
+matrix_mul :: proc "contextless" (a, b: $M/matrix[$N, N]$E) -> (c: M)
 	where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
 	return a * b
 }
 
-matrix_comp_mul :: proc(a, b: $M/matrix[$I, $J]$E) -> (c: M)
+@(require_results)
+matrix_comp_mul :: proc "contextless" (a, b: $M/matrix[$I, $J]$E) -> (c: M)
 	where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
 	return hadamard_product(a, b)
 }
 
-matrix_mul_differ :: proc(a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E)
+@(require_results)
+matrix_mul_differ :: proc "contextless" (a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E)
 	where !IS_ARRAY(E), IS_NUMERIC(E), I != K #no_bounds_check {
 	return a * b
 }
 
 
-matrix_mul_vector :: proc(a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B)
+@(require_results)
+matrix_mul_vector :: proc "contextless" (a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B)
 	where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
 	return a * b
 }
 
-quaternion_mul_quaternion :: proc(q1, q2: $Q) -> Q where IS_QUATERNION(Q) {
+@(require_results)
+quaternion_mul_quaternion :: proc "contextless" (q1, q2: $Q) -> Q where IS_QUATERNION(Q) {
 	return q1 * q2
 }
 
-quaternion64_mul_vector3 :: proc(q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
+@(require_results)
+quaternion64_mul_vector3 :: proc "contextless" (q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
 	Raw_Quaternion :: struct {xyz: [3]f16, r: f16}
 
 	q := transmute(Raw_Quaternion)q
@@ -194,7 +222,8 @@ quaternion64_mul_vector3 :: proc(q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
 	t := cross(2*q.xyz, v)
 	return V(v + q.r*t + cross(q.xyz, t))
 }
-quaternion128_mul_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
+@(require_results)
+quaternion128_mul_vector3 :: proc "contextless" (q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
 	Raw_Quaternion :: struct {xyz: [3]f32, r: f32}
 
 	q := transmute(Raw_Quaternion)q
@@ -203,7 +232,8 @@ quaternion128_mul_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
 	t := cross(2*q.xyz, v)
 	return V(v + q.r*t + cross(q.xyz, t))
 }
-quaternion256_mul_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
+@(require_results)
+quaternion256_mul_vector3 :: proc "contextless" (q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
 	Raw_Quaternion :: struct {xyz: [3]f64, r: f64}
 
 	q := transmute(Raw_Quaternion)q
@@ -224,10 +254,12 @@ mul :: proc{
 	quaternion_mul_quaternion,
 }
 
-vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check {
+@(require_results)
+vector_to_ptr :: proc "contextless" (v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check {
 	return &v[0]
 }
-matrix_to_ptr :: proc(m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
+@(require_results)
+matrix_to_ptr :: proc "contextless" (m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
 	return &m[0, 0]
 }
 
@@ -239,7 +271,8 @@ to_ptr :: proc{vector_to_ptr, matrix_to_ptr}
 
 // Splines
 
-vector_slerp :: proc(x, y: $T/[$N]$E, a: E) -> T {
+@(require_results)
+vector_slerp :: proc "contextless" (x, y: $T/[$N]$E, a: E) -> T {
 	cos_alpha := dot(x, y)
 	alpha := math.acos(cos_alpha)
 	sin_alpha := math.sin(alpha)
@@ -250,7 +283,8 @@ vector_slerp :: proc(x, y: $T/[$N]$E, a: E) -> T {
 	return x * t1 + y * t2
 }
 
-catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
+@(require_results)
+catmull_rom :: proc "contextless" (v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
 	s2 := s*s
 	s3 := s2*s
 
@@ -262,7 +296,8 @@ catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
 	return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5
 }
 
-hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
+@(require_results)
+hermite :: proc "contextless" (v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
 	s2 := s*s
 	s3 := s2*s
 
@@ -274,20 +309,23 @@ hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
 	return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2
 }
 
-cubic :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
+@(require_results)
+cubic :: proc "contextless" (v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
 	return ((v1 * s + v2) * s + v3) * s + v4
 }
 
 
 
-array_cast :: proc(v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bounds_check {
+@(require_results)
+array_cast :: proc "contextless" (v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bounds_check {
 	for i in 0..<N {
 		w[i] = Elem_Type(v[i])
 	}
 	return
 }
 
-matrix_cast :: proc(v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M, N]Elem_Type) #no_bounds_check {
+@(require_results)
+matrix_cast :: proc "contextless" (v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M, N]Elem_Type) #no_bounds_check {
 	for j in 0..<N {
 		for i in 0..<M {
 			w[i, j] = Elem_Type(v[i, j])
@@ -296,24 +334,24 @@ matrix_cast :: proc(v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M,
 	return
 }
 
-to_f32  :: #force_inline proc(v: $A/[$N]$T) -> [N]f32  { return array_cast(v, f32)  }
-to_f64  :: #force_inline proc(v: $A/[$N]$T) -> [N]f64  { return array_cast(v, f64)  }
+@(require_results) to_f32  :: #force_inline proc(v: $A/[$N]$T) -> [N]f32  { return array_cast(v, f32)  }
+@(require_results) to_f64  :: #force_inline proc(v: $A/[$N]$T) -> [N]f64  { return array_cast(v, f64)  }
 
-to_i8   :: #force_inline proc(v: $A/[$N]$T) -> [N]i8   { return array_cast(v, i8)   }
-to_i16  :: #force_inline proc(v: $A/[$N]$T) -> [N]i16  { return array_cast(v, i16)  }
-to_i32  :: #force_inline proc(v: $A/[$N]$T) -> [N]i32  { return array_cast(v, i32)  }
-to_i64  :: #force_inline proc(v: $A/[$N]$T) -> [N]i64  { return array_cast(v, i64)  }
-to_int  :: #force_inline proc(v: $A/[$N]$T) -> [N]int  { return array_cast(v, int)  }
+@(require_results) to_i8   :: #force_inline proc(v: $A/[$N]$T) -> [N]i8   { return array_cast(v, i8)   }
+@(require_results) to_i16  :: #force_inline proc(v: $A/[$N]$T) -> [N]i16  { return array_cast(v, i16)  }
+@(require_results) to_i32  :: #force_inline proc(v: $A/[$N]$T) -> [N]i32  { return array_cast(v, i32)  }
+@(require_results) to_i64  :: #force_inline proc(v: $A/[$N]$T) -> [N]i64  { return array_cast(v, i64)  }
+@(require_results) to_int  :: #force_inline proc(v: $A/[$N]$T) -> [N]int  { return array_cast(v, int)  }
 
-to_u8   :: #force_inline proc(v: $A/[$N]$T) -> [N]u8   { return array_cast(v, u8)   }
-to_u16  :: #force_inline proc(v: $A/[$N]$T) -> [N]u16  { return array_cast(v, u16)  }
-to_u32  :: #force_inline proc(v: $A/[$N]$T) -> [N]u32  { return array_cast(v, u32)  }
-to_u64  :: #force_inline proc(v: $A/[$N]$T) -> [N]u64  { return array_cast(v, u64)  }
-to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, uint) }
+@(require_results) to_u8   :: #force_inline proc(v: $A/[$N]$T) -> [N]u8   { return array_cast(v, u8)   }
+@(require_results) to_u16  :: #force_inline proc(v: $A/[$N]$T) -> [N]u16  { return array_cast(v, u16)  }
+@(require_results) to_u32  :: #force_inline proc(v: $A/[$N]$T) -> [N]u32  { return array_cast(v, u32)  }
+@(require_results) to_u64  :: #force_inline proc(v: $A/[$N]$T) -> [N]u64  { return array_cast(v, u64)  }
+@(require_results) to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, uint) }
 
-to_complex32     :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32     { return array_cast(v, complex32)     }
-to_complex64     :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64     { return array_cast(v, complex64)     }
-to_complex128    :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128    { return array_cast(v, complex128)    }
-to_quaternion64  :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64  { return array_cast(v, quaternion64)  }
-to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) }
-to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) }
+@(require_results) to_complex32     :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32     { return array_cast(v, complex32)     }
+@(require_results) to_complex64     :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64     { return array_cast(v, complex64)     }
+@(require_results) to_complex128    :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128    { return array_cast(v, complex128)    }
+@(require_results) to_quaternion64  :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64  { return array_cast(v, quaternion64)  }
+@(require_results) to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) }
+@(require_results) to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) }

File diff suppressed because it is too large
+ 351 - 351
core/math/linalg/glsl/linalg_glsl.odin


+ 50 - 48
core/math/linalg/glsl/linalg_glsl_math.odin

@@ -2,30 +2,31 @@ package math_linalg_glsl
 
 import "core:math"
 
-cos_f32         :: proc "c" (x: f32) -> f32 { return math.cos(x) }
-sin_f32         :: proc "c" (x: f32) -> f32 { return math.sin(x) }
-tan_f32         :: proc "c" (x: f32) -> f32 { return math.tan(x) }
-acos_f32        :: proc "c" (x: f32) -> f32 { return math.acos(x) }
-asin_f32        :: proc "c" (x: f32) -> f32 { return math.asin(x) }
-atan_f32        :: proc "c" (x: f32) -> f32 { return math.atan(x) }
-atan2_f32       :: proc "c" (y, x: f32) -> f32 { return math.atan2(y, x) }
-cosh_f32        :: proc "c" (x: f32) -> f32 { return math.cosh(x) }
-sinh_f32        :: proc "c" (x: f32) -> f32 { return math.sinh(x) }
-tanh_f32        :: proc "c" (x: f32) -> f32 { return math.tanh(x) }
-acosh_f32       :: proc "c" (x: f32) -> f32 { return math.acosh(x) }
-asinh_f32       :: proc "c" (x: f32) -> f32 { return math.asinh(x) }
-atanh_f32       :: proc "c" (x: f32) -> f32 { return math.atanh(x) }
-sqrt_f32        :: proc "c" (x: f32) -> f32 { return math.sqrt(x) }
-inversesqrt_f32 :: proc "c" (x: f32) -> f32 { return 1.0/math.sqrt(x) }
-pow_f32         :: proc "c" (x, y: f32) -> f32 { return math.pow(x, y) }
-exp_f32         :: proc "c" (x: f32) -> f32 { return math.exp(x) }
-log_f32         :: proc "c" (x: f32) -> f32 { return math.ln(x) }
-exp2_f32        :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) }
-sign_f32        :: proc "c" (x: f32) -> f32 { return math.sign(x) }
-floor_f32       :: proc "c" (x: f32) -> f32 { return math.floor(x) }
-round_f32       :: proc "c" (x: f32) -> f32 { return math.round(x) }
-ceil_f32        :: proc "c" (x: f32) -> f32 { return math.ceil(x) }
-mod_f32         :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) }
+@(require_results) cos_f32         :: proc "c" (x: f32) -> f32 { return math.cos(x) }
+@(require_results) sin_f32         :: proc "c" (x: f32) -> f32 { return math.sin(x) }
+@(require_results) tan_f32         :: proc "c" (x: f32) -> f32 { return math.tan(x) }
+@(require_results) acos_f32        :: proc "c" (x: f32) -> f32 { return math.acos(x) }
+@(require_results) asin_f32        :: proc "c" (x: f32) -> f32 { return math.asin(x) }
+@(require_results) atan_f32        :: proc "c" (x: f32) -> f32 { return math.atan(x) }
+@(require_results) atan2_f32       :: proc "c" (y, x: f32) -> f32 { return math.atan2(y, x) }
+@(require_results) cosh_f32        :: proc "c" (x: f32) -> f32 { return math.cosh(x) }
+@(require_results) sinh_f32        :: proc "c" (x: f32) -> f32 { return math.sinh(x) }
+@(require_results) tanh_f32        :: proc "c" (x: f32) -> f32 { return math.tanh(x) }
+@(require_results) acosh_f32       :: proc "c" (x: f32) -> f32 { return math.acosh(x) }
+@(require_results) asinh_f32       :: proc "c" (x: f32) -> f32 { return math.asinh(x) }
+@(require_results) atanh_f32       :: proc "c" (x: f32) -> f32 { return math.atanh(x) }
+@(require_results) sqrt_f32        :: proc "c" (x: f32) -> f32 { return math.sqrt(x) }
+@(require_results) inversesqrt_f32 :: proc "c" (x: f32) -> f32 { return 1.0/math.sqrt(x) }
+@(require_results) pow_f32         :: proc "c" (x, y: f32) -> f32 { return math.pow(x, y) }
+@(require_results) exp_f32         :: proc "c" (x: f32) -> f32 { return math.exp(x) }
+@(require_results) log_f32         :: proc "c" (x: f32) -> f32 { return math.ln(x) }
+@(require_results) exp2_f32        :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) }
+@(require_results) sign_f32        :: proc "c" (x: f32) -> f32 { return math.sign(x) }
+@(require_results) floor_f32       :: proc "c" (x: f32) -> f32 { return math.floor(x) }
+@(require_results) round_f32       :: proc "c" (x: f32) -> f32 { return math.round(x) }
+@(require_results) ceil_f32        :: proc "c" (x: f32) -> f32 { return math.ceil(x) }
+@(require_results) mod_f32         :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) }
+@(require_results)
 fract_f32 :: proc "c" (x: f32) -> f32 {
 	if x >= 0 {
 		return x - math.trunc(x)
@@ -33,30 +34,31 @@ fract_f32 :: proc "c" (x: f32) -> f32 {
 	return math.trunc(-x) + x
 }
 
-cos_f64         :: proc "c" (x: f64) -> f64 { return math.cos(x) }
-sin_f64         :: proc "c" (x: f64) -> f64 { return math.sin(x) }
-tan_f64         :: proc "c" (x: f64) -> f64 { return math.tan(x) }
-acos_f64        :: proc "c" (x: f64) -> f64 { return math.acos(x) }
-asin_f64        :: proc "c" (x: f64) -> f64 { return math.asin(x) }
-atan_f64        :: proc "c" (x: f64) -> f64 { return math.atan(x) }
-atan2_f64       :: proc "c" (y, x: f64) -> f64 { return math.atan2(y, x) }
-cosh_f64        :: proc "c" (x: f64) -> f64 { return math.cosh(x) }
-sinh_f64        :: proc "c" (x: f64) -> f64 { return math.sinh(x) }
-tanh_f64        :: proc "c" (x: f64) -> f64 { return math.tanh(x) }
-acosh_f64       :: proc "c" (x: f64) -> f64 { return math.acosh(x) }
-asinh_f64       :: proc "c" (x: f64) -> f64 { return math.asinh(x) }
-atanh_f64       :: proc "c" (x: f64) -> f64 { return math.atanh(x) }
-sqrt_f64        :: proc "c" (x: f64) -> f64 { return math.sqrt(x) }
-inversesqrt_f64 :: proc "c" (x: f64) -> f64 { return 1.0/math.sqrt(x) }
-pow_f64         :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) }
-exp_f64         :: proc "c" (x: f64) -> f64 { return math.exp(x) }
-log_f64         :: proc "c" (x: f64) -> f64 { return math.ln(x) }
-exp2_f64        :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) }
-sign_f64        :: proc "c" (x: f64) -> f64 { return math.sign(x) }
-floor_f64       :: proc "c" (x: f64) -> f64 { return math.floor(x) }
-round_f64       :: proc "c" (x: f64) -> f64 { return math.round(x) }
-ceil_f64        :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
-mod_f64         :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
+@(require_results) cos_f64         :: proc "c" (x: f64) -> f64 { return math.cos(x) }
+@(require_results) sin_f64         :: proc "c" (x: f64) -> f64 { return math.sin(x) }
+@(require_results) tan_f64         :: proc "c" (x: f64) -> f64 { return math.tan(x) }
+@(require_results) acos_f64        :: proc "c" (x: f64) -> f64 { return math.acos(x) }
+@(require_results) asin_f64        :: proc "c" (x: f64) -> f64 { return math.asin(x) }
+@(require_results) atan_f64        :: proc "c" (x: f64) -> f64 { return math.atan(x) }
+@(require_results) atan2_f64       :: proc "c" (y, x: f64) -> f64 { return math.atan2(y, x) }
+@(require_results) cosh_f64        :: proc "c" (x: f64) -> f64 { return math.cosh(x) }
+@(require_results) sinh_f64        :: proc "c" (x: f64) -> f64 { return math.sinh(x) }
+@(require_results) tanh_f64        :: proc "c" (x: f64) -> f64 { return math.tanh(x) }
+@(require_results) acosh_f64       :: proc "c" (x: f64) -> f64 { return math.acosh(x) }
+@(require_results) asinh_f64       :: proc "c" (x: f64) -> f64 { return math.asinh(x) }
+@(require_results) atanh_f64       :: proc "c" (x: f64) -> f64 { return math.atanh(x) }
+@(require_results) sqrt_f64        :: proc "c" (x: f64) -> f64 { return math.sqrt(x) }
+@(require_results) inversesqrt_f64 :: proc "c" (x: f64) -> f64 { return 1.0/math.sqrt(x) }
+@(require_results) pow_f64         :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) }
+@(require_results) exp_f64         :: proc "c" (x: f64) -> f64 { return math.exp(x) }
+@(require_results) log_f64         :: proc "c" (x: f64) -> f64 { return math.ln(x) }
+@(require_results) exp2_f64        :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) }
+@(require_results) sign_f64        :: proc "c" (x: f64) -> f64 { return math.sign(x) }
+@(require_results) floor_f64       :: proc "c" (x: f64) -> f64 { return math.floor(x) }
+@(require_results) round_f64       :: proc "c" (x: f64) -> f64 { return math.round(x) }
+@(require_results) ceil_f64        :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
+@(require_results) mod_f64         :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
+@(require_results)
 fract_f64 :: proc "c" (x: f64) -> f64 {
 	if x >= 0 {
 		return x - math.trunc(x)

File diff suppressed because it is too large
+ 350 - 350
core/math/linalg/hlsl/linalg_hlsl.odin


+ 58 - 56
core/math/linalg/hlsl/linalg_hlsl_math.odin

@@ -2,34 +2,35 @@ package math_linalg_hlsl
 
 import "core:math"
 
-cos_float         :: proc "c" (x: float)    -> float { return math.cos(x) }
-sin_float         :: proc "c" (x: float)    -> float { return math.sin(x) }
-tan_float         :: proc "c" (x: float)    -> float { return math.tan(x) }
-acos_float        :: proc "c" (x: float)    -> float { return math.acos(x) }
-asin_float        :: proc "c" (x: float)    -> float { return math.asin(x) }
-atan_float        :: proc "c" (x: float)    -> float { return math.atan(x) }
-atan2_float       :: proc "c" (y, x: float) -> float { return math.atan2(y, x) }
-cosh_float        :: proc "c" (x: float)    -> float { return math.cosh(x) }
-sinh_float        :: proc "c" (x: float)    -> float { return math.sinh(x) }
-tanh_float        :: proc "c" (x: float)    -> float { return math.tanh(x) }
-acosh_float       :: proc "c" (x: float)    -> float { return math.acosh(x) }
-asinh_float       :: proc "c" (x: float)    -> float { return math.asinh(x) }
-atanh_float       :: proc "c" (x: float)    -> float { return math.atanh(x) }
-sqrt_float        :: proc "c" (x: float)    -> float { return math.sqrt(x) }
-rsqrt_float       :: proc "c" (x: float)    -> float { return 1.0/math.sqrt(x) }
-rcp_float         :: proc "c" (x: float)    -> float { return 1.0/x }
-pow_float         :: proc "c" (x, y: float) -> float { return math.pow(x, y) }
-exp_float         :: proc "c" (x: float)    -> float { return math.exp(x) }
-log_float         :: proc "c" (x: float)    -> float { return math.ln(x) }
-log2_float        :: proc "c" (x: float)    -> float { return math.log(x, 2) }
-log10_float       :: proc "c" (x: float)    -> float { return math.log(x, 10) }
-exp2_float        :: proc "c" (x: float)    -> float { return math.pow(float(2), x) }
-sign_float        :: proc "c" (x: float)    -> float { return math.sign(x) }
-floor_float       :: proc "c" (x: float)    -> float { return math.floor(x) }
-round_float       :: proc "c" (x: float)    -> float { return math.round(x) }
-ceil_float        :: proc "c" (x: float)    -> float { return math.ceil(x) }
-isnan_float       :: proc "c" (x: float)    -> bool  { return math.classify(x) == .NaN}
-fmod_float        :: proc "c" (x, y: float) -> float { return math.mod(x, y) }
+@(require_results) cos_float         :: proc "c" (x: float)    -> float { return math.cos(x) }
+@(require_results) sin_float         :: proc "c" (x: float)    -> float { return math.sin(x) }
+@(require_results) tan_float         :: proc "c" (x: float)    -> float { return math.tan(x) }
+@(require_results) acos_float        :: proc "c" (x: float)    -> float { return math.acos(x) }
+@(require_results) asin_float        :: proc "c" (x: float)    -> float { return math.asin(x) }
+@(require_results) atan_float        :: proc "c" (x: float)    -> float { return math.atan(x) }
+@(require_results) atan2_float       :: proc "c" (y, x: float) -> float { return math.atan2(y, x) }
+@(require_results) cosh_float        :: proc "c" (x: float)    -> float { return math.cosh(x) }
+@(require_results) sinh_float        :: proc "c" (x: float)    -> float { return math.sinh(x) }
+@(require_results) tanh_float        :: proc "c" (x: float)    -> float { return math.tanh(x) }
+@(require_results) acosh_float       :: proc "c" (x: float)    -> float { return math.acosh(x) }
+@(require_results) asinh_float       :: proc "c" (x: float)    -> float { return math.asinh(x) }
+@(require_results) atanh_float       :: proc "c" (x: float)    -> float { return math.atanh(x) }
+@(require_results) sqrt_float        :: proc "c" (x: float)    -> float { return math.sqrt(x) }
+@(require_results) rsqrt_float       :: proc "c" (x: float)    -> float { return 1.0/math.sqrt(x) }
+@(require_results) rcp_float         :: proc "c" (x: float)    -> float { return 1.0/x }
+@(require_results) pow_float         :: proc "c" (x, y: float) -> float { return math.pow(x, y) }
+@(require_results) exp_float         :: proc "c" (x: float)    -> float { return math.exp(x) }
+@(require_results) log_float         :: proc "c" (x: float)    -> float { return math.ln(x) }
+@(require_results) log2_float        :: proc "c" (x: float)    -> float { return math.log(x, 2) }
+@(require_results) log10_float       :: proc "c" (x: float)    -> float { return math.log(x, 10) }
+@(require_results) exp2_float        :: proc "c" (x: float)    -> float { return math.pow(float(2), x) }
+@(require_results) sign_float        :: proc "c" (x: float)    -> float { return math.sign(x) }
+@(require_results) floor_float       :: proc "c" (x: float)    -> float { return math.floor(x) }
+@(require_results) round_float       :: proc "c" (x: float)    -> float { return math.round(x) }
+@(require_results) ceil_float        :: proc "c" (x: float)    -> float { return math.ceil(x) }
+@(require_results) isnan_float       :: proc "c" (x: float)    -> bool  { return math.classify(x) == .NaN}
+@(require_results) fmod_float        :: proc "c" (x, y: float) -> float { return math.mod(x, y) }
+@(require_results)
 frac_float :: proc "c" (x: float) -> float {
 	if x >= 0 {
 		return x - math.trunc(x)
@@ -38,34 +39,35 @@ frac_float :: proc "c" (x: float) -> float {
 }
 
 
-cos_double         :: proc "c" (x: double)    -> double { return math.cos(x) }
-sin_double         :: proc "c" (x: double)    -> double { return math.sin(x) }
-tan_double         :: proc "c" (x: double)    -> double { return math.tan(x) }
-acos_double        :: proc "c" (x: double)    -> double { return math.acos(x) }
-asin_double        :: proc "c" (x: double)    -> double { return math.asin(x) }
-atan_double        :: proc "c" (x: double)    -> double { return math.atan(x) }
-atan2_double       :: proc "c" (y, x: double) -> double { return math.atan2(y, x) }
-cosh_double        :: proc "c" (x: double)    -> double { return math.cosh(x) }
-sinh_double        :: proc "c" (x: double)    -> double { return math.sinh(x) }
-tanh_double        :: proc "c" (x: double)    -> double { return math.tanh(x) }
-acosh_double       :: proc "c" (x: double)    -> double { return math.acosh(x) }
-asinh_double       :: proc "c" (x: double)    -> double { return math.asinh(x) }
-atanh_double       :: proc "c" (x: double)    -> double { return math.atanh(x) }
-sqrt_double        :: proc "c" (x: double)    -> double { return math.sqrt(x) }
-rsqrt_double       :: proc "c" (x: double)    -> double { return 1.0/math.sqrt(x) }
-rcp_double         :: proc "c" (x: double)    -> double { return 1.0/x }
-pow_double         :: proc "c" (x, y: double) -> double { return math.pow(x, y) }
-exp_double         :: proc "c" (x: double)    -> double { return math.exp(x) }
-log_double         :: proc "c" (x: double)    -> double { return math.ln(x) }
-log2_double        :: proc "c" (x: double)    -> double { return math.log(x, 2) }
-log10_double       :: proc "c" (x: double)    -> double { return math.log(x, 10) }
-exp2_double        :: proc "c" (x: double)    -> double { return math.pow(double(2), x) }
-sign_double        :: proc "c" (x: double)    -> double { return math.sign(x) }
-floor_double       :: proc "c" (x: double)    -> double { return math.floor(x) }
-round_double       :: proc "c" (x: double)    -> double { return math.round(x) }
-ceil_double        :: proc "c" (x: double)    -> double { return math.ceil(x) }
-isnan_double       :: proc "c" (x: double)    -> bool   { return math.classify(x) == .NaN}
-fmod_double        :: proc "c" (x, y: double) -> double { return math.mod(x, y) }
+@(require_results) cos_double         :: proc "c" (x: double)    -> double { return math.cos(x) }
+@(require_results) sin_double         :: proc "c" (x: double)    -> double { return math.sin(x) }
+@(require_results) tan_double         :: proc "c" (x: double)    -> double { return math.tan(x) }
+@(require_results) acos_double        :: proc "c" (x: double)    -> double { return math.acos(x) }
+@(require_results) asin_double        :: proc "c" (x: double)    -> double { return math.asin(x) }
+@(require_results) atan_double        :: proc "c" (x: double)    -> double { return math.atan(x) }
+@(require_results) atan2_double       :: proc "c" (y, x: double) -> double { return math.atan2(y, x) }
+@(require_results) cosh_double        :: proc "c" (x: double)    -> double { return math.cosh(x) }
+@(require_results) sinh_double        :: proc "c" (x: double)    -> double { return math.sinh(x) }
+@(require_results) tanh_double        :: proc "c" (x: double)    -> double { return math.tanh(x) }
+@(require_results) acosh_double       :: proc "c" (x: double)    -> double { return math.acosh(x) }
+@(require_results) asinh_double       :: proc "c" (x: double)    -> double { return math.asinh(x) }
+@(require_results) atanh_double       :: proc "c" (x: double)    -> double { return math.atanh(x) }
+@(require_results) sqrt_double        :: proc "c" (x: double)    -> double { return math.sqrt(x) }
+@(require_results) rsqrt_double       :: proc "c" (x: double)    -> double { return 1.0/math.sqrt(x) }
+@(require_results) rcp_double         :: proc "c" (x: double)    -> double { return 1.0/x }
+@(require_results) pow_double         :: proc "c" (x, y: double) -> double { return math.pow(x, y) }
+@(require_results) exp_double         :: proc "c" (x: double)    -> double { return math.exp(x) }
+@(require_results) log_double         :: proc "c" (x: double)    -> double { return math.ln(x) }
+@(require_results) log2_double        :: proc "c" (x: double)    -> double { return math.log(x, 2) }
+@(require_results) log10_double       :: proc "c" (x: double)    -> double { return math.log(x, 10) }
+@(require_results) exp2_double        :: proc "c" (x: double)    -> double { return math.pow(double(2), x) }
+@(require_results) sign_double        :: proc "c" (x: double)    -> double { return math.sign(x) }
+@(require_results) floor_double       :: proc "c" (x: double)    -> double { return math.floor(x) }
+@(require_results) round_double       :: proc "c" (x: double)    -> double { return math.round(x) }
+@(require_results) ceil_double        :: proc "c" (x: double)    -> double { return math.ceil(x) }
+@(require_results) isnan_double       :: proc "c" (x: double)    -> bool   { return math.classify(x) == .NaN}
+@(require_results) fmod_double        :: proc "c" (x, y: double) -> double { return math.mod(x, y) }
+@(require_results)
 frac_double :: proc "c" (x: double) -> double {
 	if x >= 0 {
 		return x - math.trunc(x)

File diff suppressed because it is too large
+ 224 - 112
core/math/linalg/specific.odin


+ 200 - 100
core/math/linalg/specific_euler_angles_f16.odin

@@ -2,7 +2,8 @@ package linalg
 
 import "core:math"
 
-euler_angles_from_matrix3_f16 :: proc(m: Matrix3f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f16 :: proc(m: Matrix3f16, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_matrix4_f16 :: proc(m: Matrix4f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f16 :: proc(m: Matrix4f16, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_quaternion_f16 :: proc(m: Quaternionf16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_from_quaternion_f16 :: proc "contextless" (m: Quaternionf16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f16 :: proc(m: Quaternionf16, order: Euler_Angle_Or
 	return
 }
 
-matrix3_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix3f16) {
 	switch order {
 	case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order)
 	}
 	return
 }
-matrix4_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix4f16) {
 	switch order {
 	case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order)
 	return
 }
 
-quaternion_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> Quaternionf16 {
+@(require_results)
+quaternion_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> Quaternionf16 {
 	X :: quaternion_from_euler_angle_x
 	Y :: quaternion_from_euler_angle_y
 	Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Ord
 
 // Quaternionf16s
 
-quaternion_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (q: Quaternionf16) {
+@(require_results)
+quaternion_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (q: Quaternionf16) {
 	return quaternion_angle_axis_f16(angle_x, {1, 0, 0})
 }
-quaternion_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (q: Quaternionf16) {
+@(require_results)
+quaternion_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (q: Quaternionf16) {
 	return quaternion_angle_axis_f16(angle_y, {0, 1, 0})
 }
-quaternion_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (q: Quaternionf16) {
+@(require_results)
+quaternion_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (q: Quaternionf16) {
 	return quaternion_angle_axis_f16(angle_z, {0, 0, 1})
 }
 
-quaternion_from_pitch_yaw_roll_f16 :: proc(pitch, yaw, roll: f16) -> Quaternionf16 {
+@(require_results)
+quaternion_from_pitch_yaw_roll_f16 :: proc "contextless" (pitch, yaw, roll: f16) -> Quaternionf16 {
 	a, b, c := pitch, yaw, roll
 
 	ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f16 :: proc(pitch, yaw, roll: f16) -> Quaternionf
 	return q
 }
 
-roll_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
+@(require_results)
+roll_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
 	return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
 }
 
-pitch_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
+@(require_results)
+pitch_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
 	y := 2 * (q.y*q.z + q.w*q.w)
 	x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
 
@@ -157,52 +169,66 @@ pitch_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
 	return math.atan2(y, x)
 }
 
-yaw_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
+@(require_results)
+yaw_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
 	return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
 }
 
 
-pitch_yaw_roll_from_quaternion_f16 :: proc(q: Quaternionf16) -> (pitch, yaw, roll: f16) {
+@(require_results)
+pitch_yaw_roll_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (pitch, yaw, roll: f16) {
 	pitch = pitch_from_quaternion(q)
 	yaw = yaw_from_quaternion(q)
 	roll = roll_from_quaternion(q)
 	return
 }
 
-euler_angles_xyz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xyx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
 	return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
 }
 
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f
 // Matrix3
 
 
-matrix3_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (m: Matrix3f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix3f16) {
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (m: Matrix3f16) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix3f16) {
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (m: Matrix3f16) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) {
 }
 
 
-matrix3_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_derived_euler_angle_x_f16 :: proc "contextless" (angle_x: f16, angular_velocity_x: f16) -> (m: Matrix3f16) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x:
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_derived_euler_angle_y_f16 :: proc "contextless" (angle_y: f16, angular_velocity_y: f16) -> (m: Matrix3f16) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y:
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_derived_euler_angle_z_f16 :: proc "contextless" (angle_z: f16, angular_velocity_z: f16) -> (m: Matrix3f16) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z:
 }
 
 
-matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xy_f16 :: proc "contextless" (angle_x, angle_y: f16) -> (m: Matrix3f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f1
 }
 
 
-matrix3_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yx_f16 :: proc "contextless" (angle_y, angle_x: f16) -> (m: Matrix3f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix3f1
 	return
 }
 
-matrix3_from_euler_angles_xz_f16 :: proc(angle_x, angle_z: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xz_f16 :: proc "contextless" (angle_x, angle_z: f16) -> (m: Matrix3f16) {
 	return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zx_f16 :: proc(angle_z, angle_x: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zx_f16 :: proc "contextless" (angle_z, angle_x: f16) -> (m: Matrix3f16) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
 }
-matrix3_from_euler_angles_yz_f16 :: proc(angle_y, angle_z: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yz_f16 :: proc "contextless" (angle_y, angle_z: f16) -> (m: Matrix3f16) {
 	return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zy_f16 :: proc(angle_z, angle_y: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zy_f16 :: proc "contextless" (angle_z, angle_y: f16) -> (m: Matrix3f16) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
 }
 
 
-matrix3_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yxz_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix3f16) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f
 	return
 }
 
-matrix3_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zxz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 }
 
 
-matrix3_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_xzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_yzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 	return
 }
 
-matrix3_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_euler_angles_zxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
 }
 
 
-matrix3_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16) {
+@(require_results)
+matrix3_from_yaw_pitch_roll_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix3f16) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16
 	return m
 }
 
-euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
 // Matrix4
 
 
-matrix4_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (m: Matrix4f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix4f16) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (m: Matrix4f16) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix4f16) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (m: Matrix4f16) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) {
 }
 
 
-matrix4_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_derived_euler_angle_x_f16 :: proc "contextless" (angle_x: f16, angular_velocity_x: f16) -> (m: Matrix4f16) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_derived_euler_angle_y_f16 :: proc "contextless" (angle_y: f16, angular_velocity_y: f16) -> (m: Matrix4f16) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_derived_euler_angle_z_f16 :: proc "contextless" (angle_z: f16, angular_velocity_z: f16) -> (m: Matrix4f16) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z:
 }
 
 
-matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xy_f16 :: proc "contextless" (angle_x, angle_y: f16) -> (m: Matrix4f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f1
 }
 
 
-matrix4_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yx_f16 :: proc "contextless" (angle_y, angle_x: f16) -> (m: Matrix4f16) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix4f1
 	return
 }
 
-matrix4_from_euler_angles_xz_f16 :: proc(angle_x, angle_z: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xz_f16 :: proc "contextless" (angle_x, angle_z: f16) -> (m: Matrix4f16) {
 	return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zx_f16 :: proc(angle_z, angle_x: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zx_f16 :: proc "contextless" (angle_z, angle_x: f16) -> (m: Matrix4f16) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
 }
-matrix4_from_euler_angles_yz_f16 :: proc(angle_y, angle_z: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yz_f16 :: proc "contextless" (angle_y, angle_z: f16) -> (m: Matrix4f16) {
 	return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zy_f16 :: proc(angle_z, angle_y: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zy_f16 :: proc "contextless" (angle_z, angle_y: f16) -> (m: Matrix4f16) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
 }
 
 
-matrix4_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yxz_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix4f16) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f
 	return
 }
 
-matrix4_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zxz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 }
 
 
-matrix4_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_xzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_yzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 	return
 }
 
-matrix4_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_euler_angles_zxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
 }
 
 
-matrix4_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16) {
+@(require_results)
+matrix4_from_yaw_pitch_roll_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix4f16) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16
 	return m
 }
 
-euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xyx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yxy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_xzy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_yzx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zyx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
 	return
 }
 
-euler_angles_zxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
+@(require_results)
+euler_angles_zxy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)

+ 200 - 100
core/math/linalg/specific_euler_angles_f32.odin

@@ -2,7 +2,8 @@ package linalg
 
 import "core:math"
 
-euler_angles_from_matrix3_f32 :: proc(m: Matrix3f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f32 :: proc(m: Matrix3f32, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_matrix4_f32 :: proc(m: Matrix4f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f32 :: proc(m: Matrix4f32, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_quaternion_f32 :: proc(m: Quaternionf32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_from_quaternion_f32 :: proc "contextless" (m: Quaternionf32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f32 :: proc(m: Quaternionf32, order: Euler_Angle_Or
 	return
 }
 
-matrix3_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix3f32) {
 	switch order {
 	case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order)
 	}
 	return
 }
-matrix4_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix4f32) {
 	switch order {
 	case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order)
 	return
 }
 
-quaternion_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> Quaternionf32 {
+@(require_results)
+quaternion_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> Quaternionf32 {
 	X :: quaternion_from_euler_angle_x
 	Y :: quaternion_from_euler_angle_y
 	Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Ord
 
 // Quaternionf32s
 
-quaternion_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (q: Quaternionf32) {
+@(require_results)
+quaternion_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (q: Quaternionf32) {
 	return quaternion_angle_axis_f32(angle_x, {1, 0, 0})
 }
-quaternion_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (q: Quaternionf32) {
+@(require_results)
+quaternion_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (q: Quaternionf32) {
 	return quaternion_angle_axis_f32(angle_y, {0, 1, 0})
 }
-quaternion_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (q: Quaternionf32) {
+@(require_results)
+quaternion_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (q: Quaternionf32) {
 	return quaternion_angle_axis_f32(angle_z, {0, 0, 1})
 }
 
-quaternion_from_pitch_yaw_roll_f32 :: proc(pitch, yaw, roll: f32) -> Quaternionf32 {
+@(require_results)
+quaternion_from_pitch_yaw_roll_f32 :: proc "contextless" (pitch, yaw, roll: f32) -> Quaternionf32 {
 	a, b, c := pitch, yaw, roll
 
 	ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f32 :: proc(pitch, yaw, roll: f32) -> Quaternionf
 	return q
 }
 
-roll_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
+@(require_results)
+roll_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
 	return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
 }
 
-pitch_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
+@(require_results)
+pitch_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
 	y := 2 * (q.y*q.z + q.w*q.w)
 	x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
 
@@ -157,52 +169,66 @@ pitch_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
 	return math.atan2(y, x)
 }
 
-yaw_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
+@(require_results)
+yaw_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
 	return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
 }
 
 
-pitch_yaw_roll_from_quaternion_f32 :: proc(q: Quaternionf32) -> (pitch, yaw, roll: f32) {
+@(require_results)
+pitch_yaw_roll_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (pitch, yaw, roll: f32) {
 	pitch = pitch_from_quaternion(q)
 	yaw = yaw_from_quaternion(q)
 	roll = roll_from_quaternion(q)
 	return
 }
 
-euler_angles_xyz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xyx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
 	return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
 }
 
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f
 // Matrix3
 
 
-matrix3_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (m: Matrix3f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix3f32) {
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (m: Matrix3f32) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix3f32) {
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (m: Matrix3f32) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) {
 }
 
 
-matrix3_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_derived_euler_angle_x_f32 :: proc "contextless" (angle_x: f32, angular_velocity_x: f32) -> (m: Matrix3f32) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x:
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_derived_euler_angle_y_f32 :: proc "contextless" (angle_y: f32, angular_velocity_y: f32) -> (m: Matrix3f32) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y:
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_derived_euler_angle_z_f32 :: proc "contextless" (angle_z: f32, angular_velocity_z: f32) -> (m: Matrix3f32) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z:
 }
 
 
-matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xy_f32 :: proc "contextless" (angle_x, angle_y: f32) -> (m: Matrix3f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f3
 }
 
 
-matrix3_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yx_f32 :: proc "contextless" (angle_y, angle_x: f32) -> (m: Matrix3f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix3f3
 	return
 }
 
-matrix3_from_euler_angles_xz_f32 :: proc(angle_x, angle_z: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xz_f32 :: proc "contextless" (angle_x, angle_z: f32) -> (m: Matrix3f32) {
 	return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zx_f32 :: proc(angle_z, angle_x: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zx_f32 :: proc "contextless" (angle_z, angle_x: f32) -> (m: Matrix3f32) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
 }
-matrix3_from_euler_angles_yz_f32 :: proc(angle_y, angle_z: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yz_f32 :: proc "contextless" (angle_y, angle_z: f32) -> (m: Matrix3f32) {
 	return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zy_f32 :: proc(angle_z, angle_y: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zy_f32 :: proc "contextless" (angle_z, angle_y: f32) -> (m: Matrix3f32) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
 }
 
 
-matrix3_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yxz_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix3f32) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f
 	return
 }
 
-matrix3_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zxz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 }
 
 
-matrix3_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_xzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_yzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 	return
 }
 
-matrix3_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_euler_angles_zxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
 }
 
 
-matrix3_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32) {
+@(require_results)
+matrix3_from_yaw_pitch_roll_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix3f32) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32
 	return m
 }
 
-euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
 // Matrix4
 
 
-matrix4_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (m: Matrix4f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix4f32) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (m: Matrix4f32) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix4f32) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (m: Matrix4f32) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) {
 }
 
 
-matrix4_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_derived_euler_angle_x_f32 :: proc "contextless" (angle_x: f32, angular_velocity_x: f32) -> (m: Matrix4f32) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_derived_euler_angle_y_f32 :: proc "contextless" (angle_y: f32, angular_velocity_y: f32) -> (m: Matrix4f32) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_derived_euler_angle_z_f32 :: proc "contextless" (angle_z: f32, angular_velocity_z: f32) -> (m: Matrix4f32) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z:
 }
 
 
-matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xy_f32 :: proc "contextless" (angle_x, angle_y: f32) -> (m: Matrix4f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f3
 }
 
 
-matrix4_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yx_f32 :: proc "contextless" (angle_y, angle_x: f32) -> (m: Matrix4f32) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix4f3
 	return
 }
 
-matrix4_from_euler_angles_xz_f32 :: proc(angle_x, angle_z: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xz_f32 :: proc "contextless" (angle_x, angle_z: f32) -> (m: Matrix4f32) {
 	return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zx_f32 :: proc(angle_z, angle_x: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zx_f32 :: proc "contextless" (angle_z, angle_x: f32) -> (m: Matrix4f32) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
 }
-matrix4_from_euler_angles_yz_f32 :: proc(angle_y, angle_z: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yz_f32 :: proc "contextless" (angle_y, angle_z: f32) -> (m: Matrix4f32) {
 	return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zy_f32 :: proc(angle_z, angle_y: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zy_f32 :: proc "contextless" (angle_z, angle_y: f32) -> (m: Matrix4f32) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
 }
 
 
-matrix4_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yxz_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix4f32) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f
 	return
 }
 
-matrix4_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zxz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 }
 
 
-matrix4_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_xzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_yzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 	return
 }
 
-matrix4_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_euler_angles_zxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
 }
 
 
-matrix4_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32) {
+@(require_results)
+matrix4_from_yaw_pitch_roll_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix4f32) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32
 	return m
 }
 
-euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xyx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yxy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_xzy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_yzx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zyx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
 	return
 }
 
-euler_angles_zxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
+@(require_results)
+euler_angles_zxy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)

+ 200 - 100
core/math/linalg/specific_euler_angles_f64.odin

@@ -2,7 +2,8 @@ package linalg
 
 import "core:math"
 
-euler_angles_from_matrix3_f64 :: proc(m: Matrix3f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f64 :: proc(m: Matrix3f64, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_matrix4_f64 :: proc(m: Matrix4f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f64 :: proc(m: Matrix4f64, order: Euler_Angle_Order) -
 	}
 	return
 }
-euler_angles_from_quaternion_f64 :: proc(m: Quaternionf64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_from_quaternion_f64 :: proc "contextless" (m: Quaternionf64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
 	switch order {
 	case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
 	case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f64 :: proc(m: Quaternionf64, order: Euler_Angle_Or
 	return
 }
 
-matrix3_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix3f64) {
 	switch order {
 	case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order)
 	}
 	return
 }
-matrix4_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix4f64) {
 	switch order {
 	case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
 	case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order)
 	return
 }
 
-quaternion_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> Quaternionf64 {
+@(require_results)
+quaternion_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> Quaternionf64 {
 	X :: quaternion_from_euler_angle_x
 	Y :: quaternion_from_euler_angle_y
 	Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Ord
 
 // Quaternionf64s
 
-quaternion_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (q: Quaternionf64) {
+@(require_results)
+quaternion_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (q: Quaternionf64) {
 	return quaternion_angle_axis_f64(angle_x, {1, 0, 0})
 }
-quaternion_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (q: Quaternionf64) {
+@(require_results)
+quaternion_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (q: Quaternionf64) {
 	return quaternion_angle_axis_f64(angle_y, {0, 1, 0})
 }
-quaternion_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (q: Quaternionf64) {
+@(require_results)
+quaternion_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (q: Quaternionf64) {
 	return quaternion_angle_axis_f64(angle_z, {0, 0, 1})
 }
 
-quaternion_from_pitch_yaw_roll_f64 :: proc(pitch, yaw, roll: f64) -> Quaternionf64 {
+@(require_results)
+quaternion_from_pitch_yaw_roll_f64 :: proc "contextless" (pitch, yaw, roll: f64) -> Quaternionf64 {
 	a, b, c := pitch, yaw, roll
 
 	ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f64 :: proc(pitch, yaw, roll: f64) -> Quaternionf
 	return q
 }
 
-roll_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
+@(require_results)
+roll_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
 	return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
 }
 
-pitch_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
+@(require_results)
+pitch_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
 	y := 2 * (q.y*q.z + q.w*q.w)
 	x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
 
@@ -157,52 +169,66 @@ pitch_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
 	return math.atan2(y, x)
 }
 
-yaw_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
+@(require_results)
+yaw_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
 	return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
 }
 
 
-pitch_yaw_roll_from_quaternion_f64 :: proc(q: Quaternionf64) -> (pitch, yaw, roll: f64) {
+@(require_results)
+pitch_yaw_roll_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (pitch, yaw, roll: f64) {
 	pitch = pitch_from_quaternion(q)
 	yaw = yaw_from_quaternion(q)
 	roll = roll_from_quaternion(q)
 	return
 }
 
-euler_angles_xyz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xyx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_xzy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_yzx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zyx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
 }
-euler_angles_zxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
 	return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
 }
 
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f
 // Matrix3
 
 
-matrix3_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (m: Matrix3f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix3f64) {
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (m: Matrix3f64) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix3f64) {
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (m: Matrix3f64) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) {
 }
 
 
-matrix3_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_derived_euler_angle_x_f64 :: proc "contextless" (angle_x: f64, angular_velocity_x: f64) -> (m: Matrix3f64) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x:
 	m[2, 2] = +cos_x
 	return
 }
-matrix3_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_derived_euler_angle_y_f64 :: proc "contextless" (angle_y: f64, angular_velocity_y: f64) -> (m: Matrix3f64) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y:
 	m[2, 2] = +cos_y
 	return
 }
-matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_derived_euler_angle_z_f64 :: proc "contextless" (angle_z: f64, angular_velocity_z: f64) -> (m: Matrix3f64) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z:
 }
 
 
-matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xy_f64 :: proc "contextless" (angle_x, angle_y: f64) -> (m: Matrix3f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f6
 }
 
 
-matrix3_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yx_f64 :: proc "contextless" (angle_y, angle_x: f64) -> (m: Matrix3f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix3f6
 	return
 }
 
-matrix3_from_euler_angles_xz_f64 :: proc(angle_x, angle_z: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xz_f64 :: proc "contextless" (angle_x, angle_z: f64) -> (m: Matrix3f64) {
 	return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zx_f64 :: proc(angle_z, angle_x: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zx_f64 :: proc "contextless" (angle_z, angle_x: f64) -> (m: Matrix3f64) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
 }
-matrix3_from_euler_angles_yz_f64 :: proc(angle_y, angle_z: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yz_f64 :: proc "contextless" (angle_y, angle_z: f64) -> (m: Matrix3f64) {
 	return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
 }
-matrix3_from_euler_angles_zy_f64 :: proc(angle_z, angle_y: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zy_f64 :: proc "contextless" (angle_z, angle_y: f64) -> (m: Matrix3f64) {
 	return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
 }
 
 
-matrix3_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yxz_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix3f64) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f
 	return
 }
 
-matrix3_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zxz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 }
 
 
-matrix3_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_xzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_yzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 	return
 }
 
-matrix3_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_euler_angles_zxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
 }
 
 
-matrix3_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64) {
+@(require_results)
+matrix3_from_yaw_pitch_roll_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix3f64) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64
 	return m
 }
 
-euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
 // Matrix4
 
 
-matrix4_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (m: Matrix4f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	m[0, 0] = 1
 	m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix4f64) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (m: Matrix4f64) {
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = +cos_y
 	m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix4f64) {
 	m[3, 3] = 1
 	return
 }
-matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (m: Matrix4f64) {
 	cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
 	m[0, 0] = +cos_z
 	m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) {
 }
 
 
-matrix4_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_derived_euler_angle_x_f64 :: proc "contextless" (angle_x: f64, angular_velocity_x: f64) -> (m: Matrix4f64) {
 	cos_x := math.cos(angle_x) * angular_velocity_x
 	sin_x := math.sin(angle_x) * angular_velocity_x
 	m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_derived_euler_angle_y_f64 :: proc "contextless" (angle_y: f64, angular_velocity_y: f64) -> (m: Matrix4f64) {
 	cos_y := math.cos(angle_y) * angular_velocity_y
 	sin_y := math.sin(angle_y) * angular_velocity_y
 	m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y:
 	m[3, 3] = 1
 	return
 }
-matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_derived_euler_angle_z_f64 :: proc "contextless" (angle_z: f64, angular_velocity_z: f64) -> (m: Matrix4f64) {
 	cos_z := math.cos(angle_z) * angular_velocity_z
 	sin_z := math.sin(angle_z) * angular_velocity_z
 	m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z:
 }
 
 
-matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xy_f64 :: proc "contextless" (angle_x, angle_y: f64) -> (m: Matrix4f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f6
 }
 
 
-matrix4_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yx_f64 :: proc "contextless" (angle_y, angle_x: f64) -> (m: Matrix4f64) {
 	cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
 	cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
 	m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix4f6
 	return
 }
 
-matrix4_from_euler_angles_xz_f64 :: proc(angle_x, angle_z: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xz_f64 :: proc "contextless" (angle_x, angle_z: f64) -> (m: Matrix4f64) {
 	return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zx_f64 :: proc(angle_z, angle_x: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zx_f64 :: proc "contextless" (angle_z, angle_x: f64) -> (m: Matrix4f64) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
 }
-matrix4_from_euler_angles_yz_f64 :: proc(angle_y, angle_z: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yz_f64 :: proc "contextless" (angle_y, angle_z: f64) -> (m: Matrix4f64) {
 	return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
 }
-matrix4_from_euler_angles_zy_f64 :: proc(angle_z, angle_y: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zy_f64 :: proc "contextless" (angle_z, angle_y: f64) -> (m: Matrix4f64) {
 	return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
 }
 
 
-matrix4_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(-t1)
 	c2 := math.cos(-t2)
 	c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yxz_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix4f64) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f
 	return
 }
 
-matrix4_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zxz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 }
 
 
-matrix4_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_xzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_yzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 	return
 }
 
-matrix4_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_euler_angles_zxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
 	c1 := math.cos(t1)
 	s1 := math.sin(t1)
 	c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
 }
 
 
-matrix4_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64) {
+@(require_results)
+matrix4_from_yaw_pitch_roll_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix4f64) {
 	ch := math.cos(yaw)
 	sh := math.sin(yaw)
 	cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64
 	return m
 }
 
-euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 2], m[2, 2])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
 	T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 2], m[2, 2])
 	C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
 	T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 0], m[1, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xyx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 0], -m[2, 0])
 	S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yxy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 1], m[2, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 1], -m[0, 1])
 	S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	t3 = T3
 	return
 }
-euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 2], m[0, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[0, 2], -m[1, 2])
 	S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
 	T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_xzy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[2, 1], m[1, 1])
 	C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
 	T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_yzx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(-m[2, 0], m[0, 0])
 	C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
 	T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zyx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(m[1, 0], m[0, 0])
 	C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
 	return
 }
 
-euler_angles_zxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
+@(require_results)
+euler_angles_zxy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
 	T1 := math.atan2(-m[0, 1], m[1, 1])
 	C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
 	T2 := math.atan2(m[2, 1], C2)

+ 64 - 32
core/math/linalg/swizzle.odin

@@ -37,110 +37,142 @@ Vector4_Components :: enum u8 {
 	a = 3,
 }
 
-scalar_f32_swizzle1 :: proc(f: f32, c0: Scalar_Components) -> f32 {
+@(require_results)
+scalar_f32_swizzle1 :: proc "contextless" (f: f32, c0: Scalar_Components) -> f32 {
 	return f
 }
-scalar_f32_swizzle2 :: proc(f: f32, c0, c1: Scalar_Components) -> Vector2f32 {
+@(require_results)
+scalar_f32_swizzle2 :: proc "contextless" (f: f32, c0, c1: Scalar_Components) -> Vector2f32 {
 	return {f, f}
 }
-scalar_f32_swizzle3 :: proc(f: f32, c0, c1, c2: Scalar_Components) -> Vector3f32 {
+@(require_results)
+scalar_f32_swizzle3 :: proc "contextless" (f: f32, c0, c1, c2: Scalar_Components) -> Vector3f32 {
 	return {f, f, f}
 }
-scalar_f32_swizzle4 :: proc(f: f32, c0, c1, c2, c3: Scalar_Components) -> Vector4f32 {
+@(require_results)
+scalar_f32_swizzle4 :: proc "contextless" (f: f32, c0, c1, c2, c3: Scalar_Components) -> Vector4f32 {
 	return {f, f, f, f}
 }
 
-vector2f32_swizzle1 :: proc(v: Vector2f32, c0: Vector2_Components) -> f32 {
+@(require_results)
+vector2f32_swizzle1 :: proc "contextless" (v: Vector2f32, c0: Vector2_Components) -> f32 {
 	return v[c0]
 }
-vector2f32_swizzle2 :: proc(v: Vector2f32, c0, c1: Vector2_Components) -> Vector2f32 {
+@(require_results)
+vector2f32_swizzle2 :: proc "contextless" (v: Vector2f32, c0, c1: Vector2_Components) -> Vector2f32 {
 	return {v[c0], v[c1]}
 }
-vector2f32_swizzle3 :: proc(v: Vector2f32, c0, c1, c2: Vector2_Components) -> Vector3f32 {
+@(require_results)
+vector2f32_swizzle3 :: proc "contextless" (v: Vector2f32, c0, c1, c2: Vector2_Components) -> Vector3f32 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector2f32_swizzle4 :: proc(v: Vector2f32, c0, c1, c2, c3: Vector2_Components) -> Vector4f32 {
+@(require_results)
+vector2f32_swizzle4 :: proc "contextless" (v: Vector2f32, c0, c1, c2, c3: Vector2_Components) -> Vector4f32 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 
 
-vector3f32_swizzle1 :: proc(v: Vector3f32, c0: Vector3_Components) -> f32 {
+@(require_results)
+vector3f32_swizzle1 :: proc "contextless" (v: Vector3f32, c0: Vector3_Components) -> f32 {
 	return v[c0]
 }
-vector3f32_swizzle2 :: proc(v: Vector3f32, c0, c1: Vector3_Components) -> Vector2f32 {
+@(require_results)
+vector3f32_swizzle2 :: proc "contextless" (v: Vector3f32, c0, c1: Vector3_Components) -> Vector2f32 {
 	return {v[c0], v[c1]}
 }
-vector3f32_swizzle3 :: proc(v: Vector3f32, c0, c1, c2: Vector3_Components) -> Vector3f32 {
+@(require_results)
+vector3f32_swizzle3 :: proc "contextless" (v: Vector3f32, c0, c1, c2: Vector3_Components) -> Vector3f32 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector3f32_swizzle4 :: proc(v: Vector3f32, c0, c1, c2, c3: Vector3_Components) -> Vector4f32 {
+@(require_results)
+vector3f32_swizzle4 :: proc "contextless" (v: Vector3f32, c0, c1, c2, c3: Vector3_Components) -> Vector4f32 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 
-vector4f32_swizzle1 :: proc(v: Vector4f32, c0: Vector4_Components) -> f32 {
+@(require_results)
+vector4f32_swizzle1 :: proc "contextless" (v: Vector4f32, c0: Vector4_Components) -> f32 {
 	return v[c0]
 }
-vector4f32_swizzle2 :: proc(v: Vector4f32, c0, c1: Vector4_Components) -> Vector2f32 {
+@(require_results)
+vector4f32_swizzle2 :: proc "contextless" (v: Vector4f32, c0, c1: Vector4_Components) -> Vector2f32 {
 	return {v[c0], v[c1]}
 }
-vector4f32_swizzle3 :: proc(v: Vector4f32, c0, c1, c2: Vector4_Components) -> Vector3f32 {
+@(require_results)
+vector4f32_swizzle3 :: proc "contextless" (v: Vector4f32, c0, c1, c2: Vector4_Components) -> Vector3f32 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector4f32_swizzle4 :: proc(v: Vector4f32, c0, c1, c2, c3: Vector4_Components) -> Vector4f32 {
+@(require_results)
+vector4f32_swizzle4 :: proc "contextless" (v: Vector4f32, c0, c1, c2, c3: Vector4_Components) -> Vector4f32 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 
 
-scalar_f64_swizzle1 :: proc(f: f64, c0: Scalar_Components) -> f64 {
+@(require_results)
+scalar_f64_swizzle1 :: proc "contextless" (f: f64, c0: Scalar_Components) -> f64 {
 	return f
 }
-scalar_f64_swizzle2 :: proc(f: f64, c0, c1: Scalar_Components) -> Vector2f64 {
+@(require_results)
+scalar_f64_swizzle2 :: proc "contextless" (f: f64, c0, c1: Scalar_Components) -> Vector2f64 {
 	return {f, f}
 }
-scalar_f64_swizzle3 :: proc(f: f64, c0, c1, c2: Scalar_Components) -> Vector3f64 {
+@(require_results)
+scalar_f64_swizzle3 :: proc "contextless" (f: f64, c0, c1, c2: Scalar_Components) -> Vector3f64 {
 	return {f, f, f}
 }
-scalar_f64_swizzle4 :: proc(f: f64, c0, c1, c2, c3: Scalar_Components) -> Vector4f64 {
+@(require_results)
+scalar_f64_swizzle4 :: proc "contextless" (f: f64, c0, c1, c2, c3: Scalar_Components) -> Vector4f64 {
 	return {f, f, f, f}
 }
 
-vector2f64_swizzle1 :: proc(v: Vector2f64, c0: Vector2_Components) -> f64 {
+@(require_results)
+vector2f64_swizzle1 :: proc "contextless" (v: Vector2f64, c0: Vector2_Components) -> f64 {
 	return v[c0]
 }
-vector2f64_swizzle2 :: proc(v: Vector2f64, c0, c1: Vector2_Components) -> Vector2f64 {
+@(require_results)
+vector2f64_swizzle2 :: proc "contextless" (v: Vector2f64, c0, c1: Vector2_Components) -> Vector2f64 {
 	return {v[c0], v[c1]}
 }
-vector2f64_swizzle3 :: proc(v: Vector2f64, c0, c1, c2: Vector2_Components) -> Vector3f64 {
+@(require_results)
+vector2f64_swizzle3 :: proc "contextless" (v: Vector2f64, c0, c1, c2: Vector2_Components) -> Vector3f64 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector2f64_swizzle4 :: proc(v: Vector2f64, c0, c1, c2, c3: Vector2_Components) -> Vector4f64 {
+@(require_results)
+vector2f64_swizzle4 :: proc "contextless" (v: Vector2f64, c0, c1, c2, c3: Vector2_Components) -> Vector4f64 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 
 
-vector3f64_swizzle1 :: proc(v: Vector3f64, c0: Vector3_Components) -> f64 {
+@(require_results)
+vector3f64_swizzle1 :: proc "contextless" (v: Vector3f64, c0: Vector3_Components) -> f64 {
 	return v[c0]
 }
-vector3f64_swizzle2 :: proc(v: Vector3f64, c0, c1: Vector3_Components) -> Vector2f64 {
+@(require_results)
+vector3f64_swizzle2 :: proc "contextless" (v: Vector3f64, c0, c1: Vector3_Components) -> Vector2f64 {
 	return {v[c0], v[c1]}
 }
-vector3f64_swizzle3 :: proc(v: Vector3f64, c0, c1, c2: Vector3_Components) -> Vector3f64 {
+@(require_results)
+vector3f64_swizzle3 :: proc "contextless" (v: Vector3f64, c0, c1, c2: Vector3_Components) -> Vector3f64 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector3f64_swizzle4 :: proc(v: Vector3f64, c0, c1, c2, c3: Vector3_Components) -> Vector4f64 {
+@(require_results)
+vector3f64_swizzle4 :: proc "contextless" (v: Vector3f64, c0, c1, c2, c3: Vector3_Components) -> Vector4f64 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 
-vector4f64_swizzle1 :: proc(v: Vector4f64, c0: Vector4_Components) -> f64 {
+@(require_results)
+vector4f64_swizzle1 :: proc "contextless" (v: Vector4f64, c0: Vector4_Components) -> f64 {
 	return v[c0]
 }
-vector4f64_swizzle2 :: proc(v: Vector4f64, c0, c1: Vector4_Components) -> Vector2f64 {
+@(require_results)
+vector4f64_swizzle2 :: proc "contextless" (v: Vector4f64, c0, c1: Vector4_Components) -> Vector2f64 {
 	return {v[c0], v[c1]}
 }
-vector4f64_swizzle3 :: proc(v: Vector4f64, c0, c1, c2: Vector4_Components) -> Vector3f64 {
+@(require_results)
+vector4f64_swizzle3 :: proc "contextless" (v: Vector4f64, c0, c1, c2: Vector4_Components) -> Vector3f64 {
 	return {v[c0], v[c1], v[c2]}
 }
-vector4f64_swizzle4 :: proc(v: Vector4f64, c0, c1, c2, c3: Vector4_Components) -> Vector4f64 {
+@(require_results)
+vector4f64_swizzle4 :: proc "contextless" (v: Vector4f64, c0, c1, c2, c3: Vector4_Components) -> Vector4f64 {
 	return {v[c0], v[c1], v[c2], v[c3]}
 }
 

File diff suppressed because it is too large
+ 289 - 225
core/math/math.odin


+ 27 - 23
core/math/math_basic.odin

@@ -5,54 +5,58 @@ import "core:intrinsics"
 
 @(default_calling_convention="none")
 foreign _ {
-	@(link_name="llvm.sin.f16")
+	@(link_name="llvm.sin.f16", require_results)
 	sin_f16 :: proc(θ: f16) -> f16 ---
-	@(link_name="llvm.sin.f32")
+	@(link_name="llvm.sin.f32", require_results)
 	sin_f32 :: proc(θ: f32) -> f32 ---
-	@(link_name="llvm.sin.f64")
+	@(link_name="llvm.sin.f64", require_results)
 	sin_f64 :: proc(θ: f64) -> f64 ---
 
-	@(link_name="llvm.cos.f16")
+	@(link_name="llvm.cos.f16", require_results)
 	cos_f16 :: proc(θ: f16) -> f16 ---
-	@(link_name="llvm.cos.f32")
+	@(link_name="llvm.cos.f32", require_results)
 	cos_f32 :: proc(θ: f32) -> f32 ---
-	@(link_name="llvm.cos.f64")
+	@(link_name="llvm.cos.f64", require_results)
 	cos_f64 :: proc(θ: f64) -> f64 ---
 
-	@(link_name="llvm.pow.f16")
+	@(link_name="llvm.pow.f16", require_results)
 	pow_f16 :: proc(x, power: f16) -> f16 ---
-	@(link_name="llvm.pow.f32")
+	@(link_name="llvm.pow.f32", require_results)
 	pow_f32 :: proc(x, power: f32) -> f32 ---
-	@(link_name="llvm.pow.f64")
+	@(link_name="llvm.pow.f64", require_results)
 	pow_f64 :: proc(x, power: f64) -> f64 ---
 
-	@(link_name="llvm.fmuladd.f16")
+	@(link_name="llvm.fmuladd.f16", require_results)
 	fmuladd_f16 :: proc(a, b, c: f16) -> f16 ---
-	@(link_name="llvm.fmuladd.f32")
+	@(link_name="llvm.fmuladd.f32", require_results)
 	fmuladd_f32 :: proc(a, b, c: f32) -> f32 ---
-	@(link_name="llvm.fmuladd.f64")
+	@(link_name="llvm.fmuladd.f64", require_results)
 	fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---
 
-	@(link_name="llvm.exp.f16")
+	@(link_name="llvm.exp.f16", require_results)
 	exp_f16 :: proc(x: f16) -> f16 ---
-	@(link_name="llvm.exp.f32")
+	@(link_name="llvm.exp.f32", require_results)
 	exp_f32 :: proc(x: f32) -> f32 ---
-	@(link_name="llvm.exp.f64")
+	@(link_name="llvm.exp.f64", require_results)
 	exp_f64 :: proc(x: f64) -> f64 ---
 }
 
+@(require_results)
 sqrt_f16 :: proc "contextless" (x: f16) -> f16 {
 	return intrinsics.sqrt(x)
 }
+@(require_results)
 sqrt_f32 :: proc "contextless" (x: f32) -> f32 {
 	return intrinsics.sqrt(x)
 }
+@(require_results)
 sqrt_f64 :: proc "contextless" (x: f64) -> f64 {
 	return intrinsics.sqrt(x)
 }
 
 
 
+@(require_results)
 ln_f64 :: proc "contextless" (x: f64) -> f64 {
 	// The original C code, the long comment, and the constants
 	// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
@@ -154,14 +158,14 @@ ln_f64 :: proc "contextless" (x: f64) -> f64 {
 	return k*LN2_HI - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f)
 }
 
-ln_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(ln_f64(f64(x))) }
-ln_f32 :: proc "contextless" (x: f32) -> f32 { return #force_inline f32(ln_f64(f64(x))) }
-ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
-ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
-ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
-ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
-ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
-ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
+@(require_results) ln_f16   :: proc "contextless" (x: f16)   -> f16   { return #force_inline f16(ln_f64(f64(x))) }
+@(require_results) ln_f32   :: proc "contextless" (x: f32)   -> f32   { return #force_inline f32(ln_f64(f64(x))) }
+@(require_results) ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
+@(require_results) ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
+@(require_results) ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
+@(require_results) ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
+@(require_results) ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
+@(require_results) ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
 ln :: proc{
 	ln_f16, ln_f16le, ln_f16be,
 	ln_f32, ln_f32le, ln_f32be,

+ 27 - 26
core/math/math_basic_js.odin

@@ -7,46 +7,47 @@ foreign import "odin_env"
 
 @(default_calling_convention="c")
 foreign odin_env {
-	@(link_name="sin")
+	@(link_name="sin", require_results)
 	sin_f64 :: proc(θ: f64) -> f64 ---
-	@(link_name="cos")
+	@(link_name="cos", require_results)
 	cos_f64 :: proc(θ: f64) -> f64 ---
-	@(link_name="pow")
+	@(link_name="pow", require_results)
 	pow_f64 :: proc(x, power: f64) -> f64 ---
-	@(link_name="fmuladd")
+	@(link_name="fmuladd", require_results)
 	fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---
-	@(link_name="ln")
+	@(link_name="ln", require_results)
 	ln_f64 :: proc(x: f64) -> f64 ---
-	@(link_name="exp")
+	@(link_name="exp", require_results)
 	exp_f64 :: proc(x: f64) -> f64 ---
 }
 
+@(require_results)
 sqrt_f64 :: proc "contextless" (x: f64) -> f64 {
 	return intrinsics.sqrt(x)
 }
 
-sqrt_f16    :: proc "c" (x: f16) -> f16             { return f16(sqrt_f64(f64(x)))                    }
-sin_f16     :: proc "c" (θ: f16) -> f16             { return f16(sin_f64(f64(θ)))                     }
-cos_f16     :: proc "c" (θ: f16) -> f16             { return f16(cos_f64(f64(θ)))                     }
-pow_f16     :: proc "c" (x, power: f16) -> f16      { return f16(pow_f64(f64(x), f64(power)))         }
-fmuladd_f16 :: proc "c" (a, b, c: f16) -> f16       { return f16(fmuladd_f64(f64(a), f64(a), f64(c))) }
-ln_f16      :: proc "c" (x: f16) -> f16             { return f16(ln_f64(f64(x)))                      }
-exp_f16     :: proc "c" (x: f16) -> f16             { return f16(exp_f64(f64(x)))                     }
+@(require_results) sqrt_f16    :: proc "c" (x: f16) -> f16             { return f16(sqrt_f64(f64(x)))                    }
+@(require_results) sin_f16     :: proc "c" (θ: f16) -> f16             { return f16(sin_f64(f64(θ)))                     }
+@(require_results) cos_f16     :: proc "c" (θ: f16) -> f16             { return f16(cos_f64(f64(θ)))                     }
+@(require_results) pow_f16     :: proc "c" (x, power: f16) -> f16      { return f16(pow_f64(f64(x), f64(power)))         }
+@(require_results) fmuladd_f16 :: proc "c" (a, b, c: f16) -> f16       { return f16(fmuladd_f64(f64(a), f64(a), f64(c))) }
+@(require_results) ln_f16      :: proc "c" (x: f16) -> f16             { return f16(ln_f64(f64(x)))                      }
+@(require_results) exp_f16     :: proc "c" (x: f16) -> f16             { return f16(exp_f64(f64(x)))                     }
 
-sqrt_f32    :: proc "c" (x: f32) -> f32             { return f32(sqrt_f64(f64(x)))                    }
-sin_f32     :: proc "c" (θ: f32) -> f32             { return f32(sin_f64(f64(θ)))                     }
-cos_f32     :: proc "c" (θ: f32) -> f32             { return f32(cos_f64(f64(θ)))                     }
-pow_f32     :: proc "c" (x, power: f32) -> f32      { return f32(pow_f64(f64(x), f64(power)))         }
-fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32       { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) }
-ln_f32      :: proc "c" (x: f32) -> f32             { return f32(ln_f64(f64(x)))                      }
-exp_f32     :: proc "c" (x: f32) -> f32             { return f32(exp_f64(f64(x)))                     }
+@(require_results) sqrt_f32    :: proc "c" (x: f32) -> f32             { return f32(sqrt_f64(f64(x)))                    }
+@(require_results) sin_f32     :: proc "c" (θ: f32) -> f32             { return f32(sin_f64(f64(θ)))                     }
+@(require_results) cos_f32     :: proc "c" (θ: f32) -> f32             { return f32(cos_f64(f64(θ)))                     }
+@(require_results) pow_f32     :: proc "c" (x, power: f32) -> f32      { return f32(pow_f64(f64(x), f64(power)))         }
+@(require_results) fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32       { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) }
+@(require_results) ln_f32      :: proc "c" (x: f32) -> f32             { return f32(ln_f64(f64(x)))                      }
+@(require_results) exp_f32     :: proc "c" (x: f32) -> f32             { return f32(exp_f64(f64(x)))                     }
 
-ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
-ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
-ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
-ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
-ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
-ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
+@(require_results) ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
+@(require_results) ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
+@(require_results) ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
+@(require_results) ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
+@(require_results) ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
+@(require_results) ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
 ln :: proc{
 	ln_f16, ln_f16le, ln_f16be,
 	ln_f32, ln_f32le, ln_f32be,

+ 14 - 12
core/math/math_erf.odin

@@ -117,13 +117,14 @@ erf :: proc{
 	erf_f64,
 }
 
-erf_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(erf_f64(f64(x))) }
-erf_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erf_f64(f64(x))) }
-erf_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erf_f64(f64(x))) }
-erf_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(erf_f64(f64(x))) }
-erf_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erf_f64(f64(x))) }
-erf_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erf_f64(f64(x))) }
+@(require_results) erf_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(erf_f64(f64(x))) }
+@(require_results) erf_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erf_f64(f64(x))) }
+@(require_results) erf_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erf_f64(f64(x))) }
+@(require_results) erf_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(erf_f64(f64(x))) }
+@(require_results) erf_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erf_f64(f64(x))) }
+@(require_results) erf_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erf_f64(f64(x))) }
 
+@(require_results)
 erf_f64 :: proc "contextless" (x: f64) -> f64 {
 	erx :: 0h3FEB0AC160000000
 	// Coefficients for approximation to  erf in [0, 0.84375]
@@ -268,13 +269,14 @@ erfc :: proc{
 	erfc_f64,
 }
 
-erfc_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(erfc_f64(f64(x))) }
-erfc_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erfc_f64(f64(x))) }
-erfc_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erfc_f64(f64(x))) }
-erfc_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(erfc_f64(f64(x))) }
-erfc_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erfc_f64(f64(x))) }
-erfc_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erfc_f64(f64(x))) }
+@(require_results) erfc_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(erfc_f64(f64(x))) }
+@(require_results) erfc_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erfc_f64(f64(x))) }
+@(require_results) erfc_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erfc_f64(f64(x))) }
+@(require_results) erfc_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(erfc_f64(f64(x))) }
+@(require_results) erfc_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erfc_f64(f64(x))) }
+@(require_results) erfc_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erfc_f64(f64(x))) }
 
+@(require_results)
 erfc_f64 :: proc "contextless" (x: f64) -> f64 {
 	erx :: 0h3FEB0AC160000000
 	// Coefficients for approximation to  erf in [0, 0.84375]

+ 10 - 9
core/math/math_gamma.odin

@@ -65,7 +65,7 @@ package math
 // The polynomial is valid for 33 <= x <= 172; larger values are only used
 // in reciprocal and produce denormalized floats. The lower precision there
 // masks any imprecision in the polynomial.
-@(private="file")
+@(private="file", require_results)
 stirling :: proc "contextless" (x: f64) -> (f64, f64) {
 	@(static) gamS := [?]f64{
 		+7.87311395793093628397e-04,
@@ -93,6 +93,7 @@ stirling :: proc "contextless" (x: f64) -> (f64, f64) {
 	return y1, SQRT_TWO_PI * w * y2
 }
 
+@(require_results)
 gamma_f64 :: proc "contextless" (x: f64) -> f64 {
 	is_neg_int :: proc "contextless" (x: f64) -> bool {
 		if x < 0 {
@@ -210,14 +211,14 @@ gamma_f64 :: proc "contextless" (x: f64) -> f64 {
 }
 
 
-gamma_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(gamma_f64(f64(x))) }
-gamma_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(gamma_f64(f64(x))) }
-gamma_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(gamma_f64(f64(x))) }
-gamma_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(gamma_f64(f64(x))) }
-gamma_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(gamma_f64(f64(x))) }
-gamma_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(gamma_f64(f64(x))) }
-gamma_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(gamma_f64(f64(x))) }
-gamma_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(gamma_f64(f64(x))) }
+@(require_results) gamma_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(gamma_f64(f64(x))) }
+@(require_results) gamma_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(gamma_f64(f64(x))) }
+@(require_results) gamma_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(gamma_f64(f64(x))) }
+@(require_results) gamma_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(gamma_f64(f64(x))) }
+@(require_results) gamma_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(gamma_f64(f64(x))) }
+@(require_results) gamma_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(gamma_f64(f64(x))) }
+@(require_results) gamma_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(gamma_f64(f64(x))) }
+@(require_results) gamma_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(gamma_f64(f64(x))) }
 
 gamma :: proc{
 	gamma_f16, gamma_f16le, gamma_f16be,

+ 10 - 8
core/math/math_lgamma.odin

@@ -80,7 +80,9 @@ package math
 //
 
 
+@(require_results)
 lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) {
+	@(require_results)
 	sin_pi :: proc "contextless" (x: f64) -> f64 {
 		if x < 0.25 {
 			return -sin(PI * x)
@@ -345,14 +347,14 @@ lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) {
 }
 
 
-lgamma_f16   :: proc "contextless" (x: f16)   -> (lgamma: f16, sign: int)   { r, s := lgamma_f64(f64(x)); return f16(r), s }
-lgamma_f32   :: proc "contextless" (x: f32)   -> (lgamma: f32, sign: int)   { r, s := lgamma_f64(f64(x)); return f32(r), s }
-lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s }
-lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s }
-lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s }
-lgamma_f32be :: proc "contextless" (x: f32be) -> (lgamma: f32be, sign: int) { r, s := lgamma_f64(f64(x)); return f32be(r), s }
-lgamma_f64le :: proc "contextless" (x: f64le) -> (lgamma: f64le, sign: int) { r, s := lgamma_f64(f64(x)); return f64le(r), s }
-lgamma_f64be :: proc "contextless" (x: f64be) -> (lgamma: f64be, sign: int) { r, s := lgamma_f64(f64(x)); return f64be(r), s }
+@(require_results) lgamma_f16   :: proc "contextless" (x: f16)   -> (lgamma: f16, sign: int)   { r, s := lgamma_f64(f64(x)); return f16(r), s }
+@(require_results) lgamma_f32   :: proc "contextless" (x: f32)   -> (lgamma: f32, sign: int)   { r, s := lgamma_f64(f64(x)); return f32(r), s }
+@(require_results) lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s }
+@(require_results) lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s }
+@(require_results) lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s }
+@(require_results) lgamma_f32be :: proc "contextless" (x: f32be) -> (lgamma: f32be, sign: int) { r, s := lgamma_f64(f64(x)); return f32be(r), s }
+@(require_results) lgamma_f64le :: proc "contextless" (x: f64le) -> (lgamma: f64le, sign: int) { r, s := lgamma_f64(f64(x)); return f64le(r), s }
+@(require_results) lgamma_f64be :: proc "contextless" (x: f64be) -> (lgamma: f64be, sign: int) { r, s := lgamma_f64(f64(x)); return f64be(r), s }
 
 lgamma :: proc{
 	lgamma_f16, lgamma_f16le, lgamma_f16be,

+ 9 - 8
core/math/math_log1p.odin

@@ -90,15 +90,16 @@ log1p :: proc {
 	log1p_f64le,
 	log1p_f64be,
 }
-log1p_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(log1p_f64(f64(x))) }
-log1p_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(log1p_f64(f64(x))) }
-log1p_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log1p_f64(f64(x))) }
-log1p_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log1p_f64(f64(x))) }
-log1p_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log1p_f64(f64(x))) }
-log1p_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log1p_f64(f64(x))) }
-log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f64(x))) }
-log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) }
+@(require_results) log1p_f16   :: proc "contextless" (x: f16)   -> f16   { return f16(log1p_f64(f64(x))) }
+@(require_results) log1p_f32   :: proc "contextless" (x: f32)   -> f32   { return f32(log1p_f64(f64(x))) }
+@(require_results) log1p_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log1p_f64(f64(x))) }
+@(require_results) log1p_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log1p_f64(f64(x))) }
+@(require_results) log1p_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log1p_f64(f64(x))) }
+@(require_results) log1p_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log1p_f64(f64(x))) }
+@(require_results) log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f64(x))) }
+@(require_results) log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) }
 
+@(require_results)
 log1p_f64 :: proc "contextless" (x: f64) -> f64 {
 	SQRT2_M1      :: 0h3fda827999fcef34 // sqrt(2)-1 
 	SQRT2_HALF_M1 :: 0hbfd2bec333018866 // sqrt(2)/2-1

+ 9 - 0
core/math/noise/opensimplex2.odin

@@ -20,6 +20,7 @@ Vec4 :: [4]f64
 /*
 	2D Simplex noise, standard lattice orientation.
 */
+@(require_results)
 noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
 	// Get points for A2* lattice
 	skew   := SKEW_2D * (coord.x + coord.y)
@@ -35,6 +36,7 @@ noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
 	unless your map is centered around an equator. It's a subtle
 	difference, but the option is here to make it an easy choice.
 */
+@(require_results)
 noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
 	// Skew transform and rotation baked into one.
 	xx := coord.x * ROOT_2_OVER_2
@@ -51,6 +53,7 @@ noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
 	If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`.
 	For a time varied animation, call `noise_3d_improve_xz(x, y, T)`.
 */
+@(require_results)
 noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	/*
 		Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal,
@@ -75,6 +78,7 @@ noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`.
 	For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`.
 */
+@(require_results)
 noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	/*
 		Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal,
@@ -96,6 +100,7 @@ noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate.
 	They have less diagonal bias. This function's best use is as a fallback.
 */
+@(require_results)
 noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	/*
 		Re-orient the cubic lattices via rotation, to produce a familiar look.
@@ -114,6 +119,7 @@ noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
 	Recommended for time-varied animations which texture a 3D object (W=time)
 	in a space where Z is vertical.
 */
+@(require_results)
 noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) {
 	xy := coord.x + coord.y
 	s2 := xy * -0.21132486540518699998
@@ -133,6 +139,7 @@ noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32)
 	Recommended for time-varied animations which texture a 3D object (W=time)
 	in a space where Y is vertical.
 */
+@(require_results)
 noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
 	xz := coord.x + coord.z
 	s2 := xz * -0.21132486540518699998
@@ -152,6 +159,7 @@ noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32)
 	Recommended for time-varied animations which texture a 3D object (W=time)
 	where there isn't a clear distinction between horizontal and vertical
 */
+@(require_results)
 noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
 	xyz := coord.x + coord.y + coord.z
 	ww  := coord.w * 0.2236067977499788
@@ -164,6 +172,7 @@ noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
 /*
 	4D OpenSimplex2 noise, fallback lattice orientation.
 */
+@(require_results)
 noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) {
 	// Get points for A4 lattice
 	skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w)

+ 26 - 0
core/math/rand/distributions.odin

@@ -7,6 +7,7 @@ float32_uniform :: float32_range
 
 // Triangular Distribution
 // See: http://wikipedia.org/wiki/Triangular_distribution
+@(require_results)
 float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 {
 	if hi-lo == 0 {
 		return lo
@@ -24,6 +25,7 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64
 }
 // Triangular Distribution
 // See: http://wikipedia.org/wiki/Triangular_distribution
+@(require_results)
 float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 {
 	if hi-lo == 0 {
 		return lo
@@ -41,20 +43,24 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32
 
 
 // Normal/Gaussian Distribution
+@(require_results)
 float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
 	return norm_float64(r) * stddev + mean
 }
 // Normal/Gaussian Distribution
+@(require_results)
 float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_normal(f64(mean), f64(stddev), r))
 }
 
 
 // Log Normal Distribution
+@(require_results)
 float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
 	return math.exp(float64_normal(mean, stddev, r))
 }
 // Log Normal Distribution
+@(require_results)
 float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_log_normal(f64(mean), f64(stddev), r))
 }
@@ -65,6 +71,7 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
 // Return values range from
 //     0 to positive infinity if lambda >  0
 //     negative infinity to 0 if lambda <= 0
+@(require_results)
 float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
 	return - math.ln(1 - float64(r)) / lambda
 }
@@ -73,6 +80,7 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
 // Return values range from
 //     0 to positive infinity if lambda >  0
 //     negative infinity to 0 if lambda <= 0
+@(require_results)
 float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_exponential(f64(lambda), r))
 }
@@ -87,6 +95,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
 //              math.gamma(alpha) * math.pow(beta, alpha)
 //
 // mean is alpha*beta, variance is math.pow(alpha*beta, 2)
+@(require_results)
 float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
 	if alpha <= 0 || beta <= 0 {
 		panic(#procedure + ": alpha and beta must be > 0.0")
@@ -152,6 +161,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
 //              math.gamma(alpha) * math.pow(beta, alpha)
 //
 // mean is alpha*beta, variance is math.pow(alpha*beta, 2)
+@(require_results)
 float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_gamma(f64(alpha), f64(beta), r))
 }
@@ -162,6 +172,7 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 // Required: alpha > 0 and beta > 0
 //
 // Return values range between 0 and 1
+@(require_results)
 float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
 	if alpha <= 0 || beta <= 0 {
 		panic(#procedure + ": alpha and beta must be > 0.0")
@@ -178,6 +189,7 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
 // Required: alpha > 0 and beta > 0
 //
 // Return values range between 0 and 1
+@(require_results)
 float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_beta(f64(alpha), f64(beta), r))
 }
@@ -185,22 +197,26 @@ float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 
 // Pareto distribution, `alpha` is the shape parameter.
 // https://wikipedia.org/wiki/Pareto_distribution
+@(require_results)
 float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 {
 	return math.pow(1 - float64(r), -1.0 / alpha)
 }
 // Pareto distribution, `alpha` is the shape parameter.
 // https://wikipedia.org/wiki/Pareto_distribution
+@(require_results)
 float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_pareto(f64(alpha), r))
 }
 
 
 // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
+@(require_results)
 float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
 	u := 1 - float64(r)
 	return alpha * math.pow(-math.ln(u), 1.0/beta)
 }
 // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
+@(require_results)
 float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_weibull(f64(alpha), f64(beta), r))
 }
@@ -210,6 +226,7 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
 // `mean_angle` is the in mean angle between 0 and 2pi radians
 // `kappa` is the concentration parameter which must be >= 0
 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
+@(require_results)
 float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
 	// Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993.
 
@@ -245,6 +262,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
 // `mean_angle` is the in mean angle between 0 and 2pi radians
 // `kappa` is the concentration parameter which must be >= 0
 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
+@(require_results)
 float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_von_mises(f64(mean_angle), f64(kappa), r))
 }
@@ -252,6 +270,7 @@ float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
 
 // Cauchy-Lorentz Distribution
 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
+@(require_results)
 float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
 	assert(gamma > 0)
 
@@ -261,6 +280,7 @@ float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
 }
 // Cauchy-Lorentz Distribution
 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
+@(require_results)
 float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r))
 }
@@ -268,12 +288,14 @@ float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
 
 // Log Cauchy-Lorentz Distribution
 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
+@(require_results)
 float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
 	assert(gamma > 0)
 	return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0)
 }
 // Log Cauchy-Lorentz Distribution
 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
+@(require_results)
 float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r))
 }
@@ -281,6 +303,7 @@ float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
 
 // Laplace Distribution
 // `b` is the scale where `b` > 0
+@(require_results)
 float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
 	assert(b > 0)
 	p := float64(r)-0.5
@@ -288,6 +311,7 @@ float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
 }
 // Laplace Distribution
 // `b` is the scale where `b` > 0
+@(require_results)
 float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_laplace(f64(mean), f64(b), r))
 }
@@ -296,6 +320,7 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
 // Gompertz Distribution
 // `eta` is the shape, `b` is the scale
 // Both `eta` and `b` must be > 0
+@(require_results)
 float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
 	if eta <= 0 || b <= 0 {
 		panic(#procedure + ": eta and b must be > 0.0")
@@ -307,6 +332,7 @@ float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
 // Gompertz Distribution
 // `eta` is the shape, `b` is the scale
 // Both `eta` and `b` must be > 0
+@(require_results)
 float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 {
 	return f32(float64_gompertz(f64(eta), f64(b), r))
 }

+ 1 - 0
core/math/rand/exp.odin

@@ -15,6 +15,7 @@ import "core:math"
 //    https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
 //    https://www.jstatsoft.org/article/view/v005i08 [web page]
 //
+@(require_results)
 exp_float64 :: proc(r: ^Rand = nil) -> f64 {
 	re :: 7.69711747013104972
 

+ 1 - 0
core/math/rand/normal.odin

@@ -17,6 +17,7 @@ import "core:math"
 //    https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
 //    https://www.jstatsoft.org/article/view/v005i08 [web page]
 //
+@(require_results)
 norm_float64 :: proc(r: ^Rand = nil) -> f64 {
 	rn :: 3.442619855899
 

+ 646 - 23
core/math/rand/rand.odin

@@ -1,6 +1,10 @@
+/*
+Package core:math/rand implements various random number generators
+*/
 package rand
 
 import "core:intrinsics"
+import "core:mem"
 
 Rand :: struct {
 	state: u64,
@@ -12,16 +16,82 @@ Rand :: struct {
 @(private)
 global_rand := create(u64(intrinsics.read_cycle_counter()))
 
+/*
+Sets the seed used by the global random number generator.
+
+Inputs:
+- seed: The seed value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	set_global_seed_example :: proc() {
+		rand.set_global_seed(1)
+		fmt.println(rand.uint64())
+	}
+
+Possible Output:
+
+	10
+
+*/
 set_global_seed :: proc(seed: u64) {
 	init(&global_rand, seed)
 }
 
-create :: proc(seed: u64) -> Rand {
+/*
+Creates a new random number generator.
+
+Inputs:
+- seed: The seed value to create the random number generator with
+
+Returns:
+- res: The created random number generator
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	create_example :: proc() {
+		my_rand := rand.create(1)
+		fmt.println(rand.uint64(&my_rand))
+	}
+
+Possible Output:
+
+	10
+
+*/
+@(require_results)
+create :: proc(seed: u64) -> (res: Rand) {
 	r: Rand
 	init(&r, seed)
 	return r
 }
 
+/*
+Initialises a random number generator.
+
+Inputs:
+- r: The random number generator to initialise
+- seed: The seed value to initialise this random number generator
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	init_example :: proc() {
+		my_rand: rand.Rand
+		rand.init(&my_rand, 1)
+		fmt.println(rand.uint64(&my_rand))
+	}
+
+Possible Output:
+
+	10
+
+*/
 init :: proc(r: ^Rand, seed: u64) {
 	r.state = 0
 	r.inc = (seed << 1) | 1
@@ -30,6 +100,35 @@ init :: proc(r: ^Rand, seed: u64) {
 	_random(r)
 }
 
+/*
+Initialises a random number generator to use the system random number generator.  
+The system random number generator is platform specific.  
+On `linux` refer to the `getrandom` syscall.  
+On `darwin` refer to `getentropy`.  
+On `windows` refer to `BCryptGenRandom`.
+
+All other platforms wi
+
+Inputs:
+- r: The random number generator to use the system random number generator
+
+WARNING: Panics if the system is not either `windows`, `darwin` or `linux`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	init_as_system_example :: proc() {
+		my_rand: rand.Rand
+		rand.init_as_system(&my_rand)
+		fmt.println(rand.uint64(&my_rand))
+	}
+
+Possible Output:
+
+	10
+
+*/
 init_as_system :: proc(r: ^Rand) {
 	if !#defined(_system_random) {
 		panic(#procedure + " is not supported on this platform yet")
@@ -60,15 +159,99 @@ _random :: proc(r: ^Rand) -> u32 {
 	return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
 }
 
-uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) }
+/*
+Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random unsigned 32 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	uint32_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.uint32())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.uint32(&my_rand))
+	}
+
+Possible Output:
+
+	10
+	389
+
+*/
+@(require_results)
+uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) }
+
+/*
+Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random unsigned 64 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	uint64_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.uint64())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.uint64(&my_rand))
+	}
+
+Possible Output:
 
-uint64 :: proc(r: ^Rand = nil) -> u64 {
+	10
+	389
+
+*/
+@(require_results)
+uint64 :: proc(r: ^Rand = nil) -> (val: u64) {
 	a := u64(_random(r))
 	b := u64(_random(r))
 	return (a<<32) | b
 }
 
-uint128 :: proc(r: ^Rand = nil) -> u128 {
+/*
+Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random unsigned 128 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	uint128_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.uint128())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.uint128(&my_rand))
+	}
+
+Possible Output:
+
+	10
+	389
+
+*/
+@(require_results)
+uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
 	a := u128(_random(r))
 	b := u128(_random(r))
 	c := u128(_random(r))
@@ -76,11 +259,126 @@ uint128 :: proc(r: ^Rand = nil) -> u128 {
 	return (a<<96) | (b<<64) | (c<<32) | d
 }
 
-int31  :: proc(r: ^Rand = nil) -> i32  { return i32(uint32(r) << 1 >> 1) }
-int63  :: proc(r: ^Rand = nil) -> i64  { return i64(uint64(r) << 1 >> 1) }
-int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) }
+/*
+Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
+The sign bit will always be set to 0, thus all generated numbers will be positive.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 31 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int31_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int31())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int31(&my_rand))
+	}
+
+Possible Output:
+
+	10
+	389
+
+*/
+@(require_results) int31  :: proc(r: ^Rand = nil) -> (val: i32)  { return i32(uint32(r) << 1 >> 1) }
+/*
+Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
+The sign bit will always be set to 0, thus all generated numbers will be positive.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 63 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int63_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int63())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int63(&my_rand))
+	}
+
+Possible Output:
 
-int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
+	10
+	389
+
+*/
+@(require_results) int63  :: proc(r: ^Rand = nil) -> (val: i64)  { return i64(uint64(r) << 1 >> 1) }
+/*
+Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
+The sign bit will always be set to 0, thus all generated numbers will be positive.
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 127 bit value
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int127_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int127())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int127(&my_rand))
+	}
+
+Possible Output:
+
+	10
+	389
+
+*/
+@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
+
+/*
+Generates a random 31 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- n: The upper bound of the generated number, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 31 bit value in the range `(0, n]`
+
+WARNING: Panics if n is less than 0
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int31_max_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int31_max(16))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int31_max(1024, &my_rand))
+	}
+
+Possible Output:
+
+	6
+	500
+
+*/
+@(require_results)
+int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
 	if n <= 0 {
 		panic("Invalid argument to int31_max")
 	}
@@ -94,8 +392,38 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
 	}
 	return v % n
 }
+/*
+Generates a random 63 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- n: The upper bound of the generated number, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 63 bit value in the range `(0, n]`
+
+WARNING: Panics if n is less than 0
 
-int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int63_max_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int63_max(16))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int63_max(1024, &my_rand))
+	}
+
+Possible Output:
+
+	6
+	500
+
+*/
+@(require_results)
+int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
 	if n <= 0 {
 		panic("Invalid argument to int63_max")
 	}
@@ -109,8 +437,38 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
 	}
 	return v % n
 }
+/*
+Generates a random 127 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- n: The upper bound of the generated number, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random 127 bit value in the range `(0, n]`
+
+WARNING: Panics if n is less than 0
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int127_max_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int127_max(16))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int127_max(1024, &my_rand))
+	}
+
+Possible Output:
 
-int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
+	6
+	500
+
+*/
+@(require_results)
+int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
 	if n <= 0 {
 		panic("Invalid argument to int127_max")
 	}
@@ -124,8 +482,38 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
 	}
 	return v % n
 }
+/*
+Generates a random integer value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- n: The upper bound of the generated number, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random integer value in the range `(0, n]`
 
-int_max :: proc(n: int, r: ^Rand = nil) -> int {
+WARNING: Panics if n is less than 0
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	int_max_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.int_max(16))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.int_max(1024, &my_rand))
+	}
+
+Possible Output:
+
+	6
+	500
+
+*/
+@(require_results)
+int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
 	if n <= 0 {
 		panic("Invalid argument to int_max")
 	}
@@ -136,14 +524,154 @@ int_max :: proc(n: int, r: ^Rand = nil) -> int {
 	}
 }
 
-// Uniform random distribution [0, 1)
-float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) }
-// Uniform random distribution [0, 1)
-float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) }
+/*
+Generates a random double floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random double floating point value in the range `(0, 1]`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	float64_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.float64())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.float64(&my_rand))
+	}
+
+Possible Output:
+
+	0.043
+	0.511
+
+*/
+@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
+
+/*
+Generates a random single floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random single floating point value in the range `(0, 1]`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	float32_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.float32())
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.float32(&my_rand))
+	}
+
+Possible Output:
+
+	0.043
+	0.511
+
+*/
+@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
+
+/*
+Generates a random double floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- low: The lower bounds of the value, this value is inclusive
+- high: The upper bounds of the value, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random double floating point value in the range `(low, high]`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	float64_range_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.float64_range(-10, 300))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.float64_range(600, 900, &my_rand))
+	}
+
+Possible Output:
 
-float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo }
-float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo }
+	15.312
+	673.130
 
+*/
+@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
+/*
+Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- low: The lower bounds of the value, this value is inclusive
+- high: The upper bounds of the value, this value is exclusive
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- val: A random single floating point value in the range `(low, high]`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	float32_range_example :: proc() {
+		// Using the global random number generator
+		fmt.println(rand.float32_range(-10, 300))
+		// Using local random number generator
+		my_rand := rand.create(1)
+		fmt.println(rand.float32_range(600, 900, &my_rand))
+	}
+
+Possible Output:
+
+	15.312
+	673.130
+
+*/
+@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
+
+/*
+Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- p: The byte slice to fill
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- n: The number of bytes generated
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	read_example :: proc() {
+		// Using the global random number generator
+		data: [8]byte
+		n := rand.read(data[:])
+		fmt.println(n)
+		fmt.println(data)
+	}
+
+Possible Output:
+
+	8
+	[32, 4, 59, 7, 1, 2, 2, 119]
+
+*/
+@(require_results)
 read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
 	pos := i8(0)
 	val := i64(0)
@@ -159,18 +687,81 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
 	return
 }
 
-// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
-perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int {
-	m := make([]int, n, allocator)
+/*
+Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.  
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- n: The size of the created slice
+- r: The random number generator to use, or nil for the global generator
+- allocator: (default: context.allocator)
+
+Returns:
+- res: A slice filled with random values
+- err: An allocator error if one occured, `nil` otherwise
+
+Example:
+	import "core:math/rand"
+	import "core:mem"
+	import "core:fmt"
+
+	perm_example :: proc() -> (err: mem.Allocator_Error) {
+		// Using the global random number generator and using the context allocator
+		data := rand.perm(4) or_return
+		fmt.println(data)
+		defer delete(data, context.allocator)
+
+		// Using local random number generator and temp allocator
+		my_rand := rand.create(1)
+		data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return
+		fmt.println(data_tmp)
+
+		return
+	}
+
+Possible Output:
+
+	[7201011, 3, 9123, 231131]
+	[19578, 910081, 131, 7]
+
+*/
+@(require_results)
+perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
+	m := make([]int, n, allocator) or_return
 	for i := 0; i < n; i += 1 {
 		j := int_max(i+1, r)
 		m[i] = m[j]
 		m[j] = i
 	}
-	return m
+	return m, {}
 }
 
+/*
+Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- array: The slice to randomize
+- r: The random number generator to use, or nil for the global generator
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	shuffle_example :: proc() {
+		// Using the global random number generator
+		data: [4]int = { 1, 2, 3, 4 }
+		fmt.println(data) // the contents are in order
+		rand.shuffle(data[:])
+		fmt.println(data) // the contents have been shuffled
+	}
+
+Possible Output:
 
+	[1, 2, 3, 4]
+	[2, 4, 3, 1]
+
+*/
 shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
 	n := i64(len(array))
 	if n < 2 {
@@ -183,11 +774,43 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
 	}
 }
 
-// Returns a random element from the given slice
+/*
+Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.  
+
+Inputs:
+- array: The slice to choose an element from
+- r: The random number generator to use, or nil for the global generator
+
+Returns:
+- res: A random element from `array`
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	choice_example :: proc() {
+		// Using the global random number generator
+		data: [4]int = { 1, 2, 3, 4 }
+		fmt.println(rand.choice(data[:]))
+		fmt.println(rand.choice(data[:]))
+		fmt.println(rand.choice(data[:]))
+		fmt.println(rand.choice(data[:]))
+	}
+
+
+Possible Output:
+
+	3
+	2
+	2
+	4
+
+*/
+@(require_results)
 choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
 	n := i64(len(array))
 	if n < 1 {
 		return E{}
 	}
 	return array[int63_max(n, r)]
-}
+}

+ 1 - 0
core/math/rand/system_darwin.odin

@@ -2,6 +2,7 @@ package rand
 
 import "core:sys/darwin"
 
+@(require_results)
 _system_random :: proc() -> u32 {
 	for {
 		value: u32

+ 1 - 0
core/math/rand/system_linux.odin

@@ -2,6 +2,7 @@ package rand
 
 import "core:sys/unix"
 
+@(require_results)
 _system_random :: proc() -> u32 {
 	for {
 		value: u32

+ 1 - 0
core/math/rand/system_windows.odin

@@ -2,6 +2,7 @@ package rand
 
 import win32 "core:sys/windows"
 
+@(require_results)
 _system_random :: proc() -> u32 {
 	value: u32
 	status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)

+ 33 - 33
core/mem/alloc.odin

@@ -60,15 +60,18 @@ DEFAULT_PAGE_SIZE ::
 	16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
 	4 * 1024
 
-alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
-	data, _ := runtime.mem_alloc(size, alignment, allocator, loc)
-	return raw_data(data)
+@(require_results)
+alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
+	data, err := runtime.mem_alloc(size, alignment, allocator, loc)
+	return raw_data(data), err
 }
 
+@(require_results)
 alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
 	return runtime.mem_alloc(size, alignment, allocator, loc)
 }
 
+@(require_results)
 alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
 	return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
 }
@@ -93,15 +96,18 @@ free_all :: proc(allocator := context.allocator, loc := #caller_location) -> All
 	return runtime.mem_free_all(allocator, loc)
 }
 
-resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
-	data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
-	return raw_data(data)
+@(require_results)
+resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
+	data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
+	return raw_data(data), err
 }
 
+@(require_results)
 resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
 	return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
 }
 
+@(require_results)
 query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
 	if allocator.procedure != nil {
 		allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
@@ -110,6 +116,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
 	return nil
 }
 
+@(require_results)
 query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
 	props.pointer = pointer
 	if allocator.procedure != nil {
@@ -146,14 +153,17 @@ delete :: proc{
 }
 
 
+@(require_results)
 new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) {
 	return new_aligned(T, align_of(T), allocator, loc)
 }
+@(require_results)
 new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
 	data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return
 	t = (^T)(raw_data(data))
 	return
 }
+@(require_results)
 new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
 	backing := alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
 	t = (^T)(raw_data(backing))
@@ -164,6 +174,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
 	return nil, .Out_Of_Memory
 }
 
+@(require_results)
 make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
 	runtime.make_slice_error_loc(loc, len)
 	data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return
@@ -173,15 +184,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
 	slice = transmute(T)Raw_Slice{raw_data(data), len}
 	return
 }
+@(require_results)
 make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
 	return make_aligned(T, len, align_of(E), allocator, loc)
 }
+@(require_results)
 make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
 	return make_dynamic_array_len_cap(T, 0, 16, allocator, loc)
 }
+@(require_results)
 make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
 	return make_dynamic_array_len_cap(T, len, len, allocator, loc)
 }
+@(require_results)
 make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) {
 	runtime.make_dynamic_array_error_loc(loc, len, cap)
 	data := alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
@@ -192,14 +207,15 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
 	array = transmute(T)s
 	return
 }
-make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
+@(require_results)
+make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
 	runtime.make_map_expr_error_loc(loc, cap)
 	context.allocator = allocator
 
-	m: T
-	reserve_map(&m, cap, loc)
-	return m
+	err = reserve_map(&m, cap, loc)
+	return
 }
+@(require_results)
 make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
 	runtime.make_slice_error_loc(loc, len)
 	data := alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
@@ -220,30 +236,14 @@ make :: proc{
 }
 
 
-
-default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> rawptr {
-	if old_memory == nil {
-		return alloc(new_size, alignment, allocator, loc)
-	}
-
-	if new_size == 0 {
-		free(old_memory, allocator, loc)
-		return nil
-	}
-
-	if new_size == old_size {
-		return old_memory
-	}
-
-	new_memory := alloc(new_size, alignment, allocator, loc)
-	if new_memory == nil {
-		return nil
-	}
-
-	copy(new_memory, old_memory, min(old_size, new_size))
-	free(old_memory, allocator, loc)
-	return new_memory
+@(require_results)
+default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) {
+	data: []byte
+	data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc)
+	res = raw_data(data)
+	return
 }
+@(require_results)
 default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
 	old_memory := raw_data(old_data)
 	old_size := len(old_data)

+ 19 - 3
core/mem/allocators.odin

@@ -2,6 +2,7 @@ package mem
 
 import "core:intrinsics"
 import "core:runtime"
+import "core:sync"
 
 nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
                            size, alignment: int,
@@ -46,6 +47,7 @@ init_arena :: proc(a: ^Arena, data: []byte) {
 	a.temp_count = 0
 }
 
+@(require_results)
 arena_allocator :: proc(arena: ^Arena) -> Allocator {
 	return Allocator{
 		procedure = arena_allocator_proc,
@@ -100,6 +102,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 	return nil, nil
 }
 
+@(require_results)
 begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
 	tmp: Arena_Temp_Memory
 	tmp.arena = a
@@ -286,6 +289,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 	return nil, nil
 }
 
+@(require_results)
 scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> Allocator {
 	return Allocator{
 		procedure = scratch_allocator_proc,
@@ -325,6 +329,7 @@ init_stack :: proc(s: ^Stack, data: []byte) {
 	s.peak_used = 0
 }
 
+@(require_results)
 stack_allocator :: proc(stack: ^Stack) -> Allocator {
 	return Allocator{
 		procedure = stack_allocator_proc,
@@ -490,6 +495,7 @@ init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
 	s.peak_used = 0
 }
 
+@(require_results)
 small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
 	return Allocator{
 		procedure = small_stack_allocator_proc,
@@ -673,6 +679,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
 }
 
 
+@(require_results)
 dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator {
 	return Allocator{
 		procedure = dynamic_pool_allocator_proc,
@@ -705,12 +712,13 @@ dynamic_pool_destroy :: proc(using pool: ^Dynamic_Pool) {
 }
 
 
-dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> rawptr {
+@(require_results)
+dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> (rawptr, Allocator_Error) {
 	data, err := dynamic_pool_alloc_bytes(pool, bytes)
-	assert(err == nil)
-	return raw_data(data)
+	return raw_data(data), err
 }
 
+@(require_results)
 dynamic_pool_alloc_bytes :: proc(using pool: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) {
 	cycle_new_block :: proc(using pool: ^Dynamic_Pool) -> (err: Allocator_Error) {
 		if block_allocator.procedure == nil {
@@ -836,6 +844,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 	return nil, nil
 }
 
+@(require_results)
 panic_allocator :: proc() -> Allocator {
 	return Allocator{
 		procedure = panic_allocator_proc,
@@ -860,6 +869,7 @@ Tracking_Allocator :: struct {
 	backing:           Allocator,
 	allocation_map:    map[rawptr]Tracking_Allocator_Entry,
 	bad_free_array:    [dynamic]Tracking_Allocator_Bad_Free_Entry,
+	mutex:             sync.Mutex,
 	clear_on_free_all: bool,
 }
 
@@ -880,11 +890,14 @@ tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
 
 
 tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
+	sync.mutex_lock(&t.mutex)
 	clear(&t.allocation_map)
 	clear(&t.bad_free_array)
+	sync.mutex_unlock(&t.mutex)
 }
 
 
+@(require_results)
 tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
 	return Allocator{
 		data = data,
@@ -896,6 +909,9 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
                                 size, alignment: int,
                                 old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
 	data := (^Tracking_Allocator)(allocator_data)
+
+	sync.mutex_guard(&data.mutex)
+
 	if mode == .Query_Info {
 		info := (^Allocator_Query_Info)(old_memory)
 		if info != nil && info.pointer != nil {

+ 2 - 1
core/mem/doc.odin

@@ -18,6 +18,7 @@ _main :: proc() {
 main :: proc() {
 	track: mem.Tracking_Allocator
 	mem.tracking_allocator_init(&track, context.allocator)
+	defer mem.tracking_allocator_destroy(&track)
 	context.allocator = mem.tracking_allocator(&track)
 
 	_main()
@@ -31,4 +32,4 @@ main :: proc() {
 }
 ```
 */
-package mem
+package mem

+ 28 - 0
core/mem/mem.odin

@@ -53,14 +53,17 @@ compare :: proc "contextless" (a, b: []byte) -> int {
 	return res
 }
 
+@(require_results)
 compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
 	return runtime.memory_compare(a, b, n)
 }
 
+@(require_results)
 check_zero :: proc(data: []byte) -> bool {
 	return check_zero_ptr(raw_data(data), len(data))
 }
 
+@(require_results)
 check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
 	switch {
 	case len <= 0:
@@ -101,11 +104,13 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
 	return true
 }
 
+@(require_results)
 simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) {
 	a, b := a, b
 	return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0
 }
 
+@(require_results)
 compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
 	return compare_byte_ptrs((^byte)(a), (^byte)(b), n)
 }
@@ -113,20 +118,24 @@ compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
 ptr_offset :: intrinsics.ptr_offset
 ptr_sub :: intrinsics.ptr_sub
 
+@(require_results)
 slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
 	return ([^]T)(ptr)[:len]
 }
 
+@(require_results)
 byte_slice :: #force_inline proc "contextless" (data: rawptr, #any_int len: int) -> []byte {
 	return ([^]u8)(data)[:max(len, 0)]
 }
 
+@(require_results)
 slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
 	s := transmute(Raw_Slice)slice
 	s.len *= size_of(T)
 	return transmute([]byte)s
 }
 
+@(require_results)
 slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
 	when size_of(A) == 0 || size_of(B) == 0 {
 		return nil
@@ -137,11 +146,13 @@ slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
 	}
 }
 
+@(require_results)
 slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) {
 	s := transmute(Raw_Slice)slice
 	return (^T)(s.data), s.len
 }
 
+@(require_results)
 buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
 	return transmute([dynamic]E)Raw_Dynamic_Array{
 		data      = raw_data(backing),
@@ -154,10 +165,12 @@ buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
 	}
 }
 
+@(require_results)
 ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
 	return transmute([]byte)Raw_Slice{ptr, len*size_of(T)}
 }
 
+@(require_results)
 any_to_bytes :: proc "contextless" (val: any) -> []byte {
 	ti := type_info_of(val.id)
 	size := ti != nil ? ti.size : 0
@@ -165,6 +178,7 @@ any_to_bytes :: proc "contextless" (val: any) -> []byte {
 }
 
 
+@(require_results)
 is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
 	if x <= 0 {
 		return false
@@ -172,10 +186,12 @@ is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
 	return (x & (x-1)) == 0
 }
 
+@(require_results)
 align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
 	return rawptr(align_forward_uintptr(uintptr(ptr), align))
 }
 
+@(require_results)
 align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
 	assert(is_power_of_two(align))
 
@@ -187,33 +203,41 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
 	return p
 }
 
+@(require_results)
 align_forward_int :: proc(ptr, align: int) -> int {
 	return int(align_forward_uintptr(uintptr(ptr), uintptr(align)))
 }
+@(require_results)
 align_forward_uint :: proc(ptr, align: uint) -> uint {
 	return uint(align_forward_uintptr(uintptr(ptr), uintptr(align)))
 }
 
+@(require_results)
 align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
 	return rawptr(align_backward_uintptr(uintptr(ptr), align))
 }
 
+@(require_results)
 align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
 	return align_forward_uintptr(ptr - align + 1, align)
 }
 
+@(require_results)
 align_backward_int :: proc(ptr, align: int) -> int {
 	return int(align_backward_uintptr(uintptr(ptr), uintptr(align)))
 }
+@(require_results)
 align_backward_uint :: proc(ptr, align: uint) -> uint {
 	return uint(align_backward_uintptr(uintptr(ptr), uintptr(align)))
 }
 
+@(require_results)
 context_from_allocator :: proc(a: Allocator) -> type_of(context) {
 	context.allocator = a
 	return context
 }
 
+@(require_results)
 reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) {
 	copy(&value, ptr, size_of(T))
 	return
@@ -222,6 +246,7 @@ reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) {
 
 Fixed_Byte_Buffer :: distinct [dynamic]byte
 
+@(require_results)
 make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer {
 	s := transmute(Raw_Slice)backing
 	d: Raw_Dynamic_Array
@@ -237,11 +262,13 @@ make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buf
 
 
 
+@(require_results)
 align_formula :: proc "contextless" (size, align: int) -> int {
 	result := size + align-1
 	return result - result%align
 }
 
+@(require_results)
 calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, header_size: int) -> int {
 	p, a := ptr, align
 	modulo := p & (a-1)
@@ -267,6 +294,7 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he
 
 
 
+@(require_results, deprecated="prefer 'slice.clone'")
 clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) {
 	new_slice, _ = make(T, len(slice), allocator, loc)
 	runtime.copy(new_slice, slice)

+ 4 - 0
core/net/dns.odin

@@ -392,6 +392,10 @@ load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocato
 		}
 
 		addr := parse_address(server_ip_str)
+		if addr == nil {
+			continue
+		}
+
 		endpoint := Endpoint{
 			addr,
 			53,

+ 19 - 2
core/net/socket_darwin.odin

@@ -303,8 +303,25 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 
 @(private)
 _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
-	// TODO: Implement
-	unimplemented()
+	socket := any_socket_to_socket(socket)
+
+	flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0)
+	if getfl_err != os.ERROR_NONE {
+		return Set_Blocking_Error(getfl_err)
+	}
+
+	if should_block {
+		flags &= ~int(os.O_NONBLOCK)
+	} else {
+		flags |= int(os.O_NONBLOCK)
+	}
+
+	_, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags)
+	if setfl_err != os.ERROR_NONE {
+		return Set_Blocking_Error(setfl_err)
+	}
+
+	return nil
 }
 
 @private

+ 5 - 1
core/odin/ast/clone.odin

@@ -82,7 +82,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
 		panic("Cannot clone this node type")
 	}
 
-	res := cast(^Node)mem.alloc(size, align)
+	res := cast(^Node)(mem.alloc(size, align) or_else nil)
+	if res == nil {
+		// allocation failure
+		return nil
+	}
 	src: rawptr = node
 	if node.derived != nil {
 		src = (^rawptr)(&node.derived)^

+ 22 - 3
core/os/os_darwin.odin

@@ -267,6 +267,8 @@ SHUT_RD   :: 0
 SHUT_WR   :: 1
 SHUT_RDWR :: 2
 
+F_GETFL: int : 3 /* Get file flags */
+F_SETFL: int : 4 /* Set file flags */
 
 // "Argv" arguments converted to Odin strings
 args := _alloc_command_line_arguments()
@@ -413,7 +415,7 @@ F_OK :: 0 // Test for file existance
 F_GETPATH :: 50 // return the full path of the fd
 
 foreign libc {
-	@(link_name="__error") __error :: proc() -> ^int ---
+	@(link_name="__error") __error :: proc() -> ^c.int ---
 
 	@(link_name="open")             _unix_open          :: proc(path: cstring, flags: i32, mode: u16) -> Handle ---
 	@(link_name="close")            _unix_close         :: proc(handle: Handle) -> c.int ---
@@ -438,7 +440,7 @@ foreign libc {
 	@(link_name="closedir")         _unix_closedir      :: proc(dirp: Dir) -> c.int ---
 	@(link_name="rewinddir")        _unix_rewinddir     :: proc(dirp: Dir) ---
 
-	@(link_name="__fcntl")          _unix__fcntl        :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int ---
+	@(link_name="__fcntl")          _unix__fcntl        :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int ---
 
 	@(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int ---
 	@(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int ---
@@ -464,6 +466,7 @@ foreign libc {
 	@(link_name="connect")          _unix_connect       :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
 	@(link_name="bind")             _unix_bind          :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
 	@(link_name="setsockopt")       _unix_setsockopt    :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
+	@(link_name="getsockopt")       _unix_getsockopt    :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
 	@(link_name="recvfrom")         _unix_recvfrom      :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t ---
 	@(link_name="recv")             _unix_recv          :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
 	@(link_name="sendto")           _unix_sendto        :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t ---
@@ -489,7 +492,7 @@ foreign dl {
 }
 
 get_last_error :: proc "contextless" () -> int {
-	return __error()^
+	return int(__error()^)
 }
 
 get_last_error_string :: proc() -> string {
@@ -1016,6 +1019,14 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen:
 	return ERROR_NONE
 }
 
+getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Errno {
+	result := _unix_getsockopt(int(sd), level, optname, optval, optlen)
+	if result < 0 {
+		return Errno(get_last_error())
+	}
+	return ERROR_NONE
+}
+
 recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) {
 	result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size)
 	if result < 0 {
@@ -1055,3 +1066,11 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) {
 	}
 	return ERROR_NONE
 }
+
+fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) {
+	result := _unix__fcntl(Handle(fd), c.int(cmd), c.int(arg))
+	if result < 0 {
+		return 0, Errno(get_last_error())
+	}
+	return int(result), ERROR_NONE
+}

+ 190 - 83
core/runtime/core_builtin.odin

@@ -6,7 +6,7 @@ import "core:intrinsics"
 Maybe :: union($T: typeid) {T}
 
 
-@builtin
+@(builtin, require_results)
 container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T
 	where intrinsics.type_has_field(T, field_name),
 	      intrinsics.type_field_type(T, field_name) == Field_Type {
@@ -27,6 +27,11 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a
 }
 
 
+// `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`.
+// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
+// of len(src) and len(dst).
+//
+// Prefer the procedure group `copy`.
 @builtin
 copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
 	n := max(0, min(len(dst), len(src)))
@@ -35,6 +40,11 @@ copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
 	}
 	return n
 }
+// `copy_from_string` is a built-in procedure that copies elements from a source slice `src` to a destination string `dst`.
+// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
+// of len(src) and len(dst).
+//
+// Prefer the procedure group `copy`.
 @builtin
 copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
 	n := max(0, min(len(dst), len(src)))
@@ -43,11 +53,20 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
 	}
 	return n
 }
+// `copy` is a built-in procedure that copies elements from a source slice `src` to a destination slice/string `dst`.
+// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
+// of len(src) and len(dst).
 @builtin
 copy :: proc{copy_slice, copy_from_string}
 
 
 
+// `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value
+// with the old value, and reducing the length of the dynamic array by 1.
+//
+// Note: This is an O(1) operation.
+// Note: If you the elements to remain in their order, use `ordered_remove`.
+// Note: If the index is out of bounds, this procedure will panic.
 @builtin
 unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
 	bounds_check_error_loc(loc, index, len(array))
@@ -57,7 +76,11 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
 	}
 	(^Raw_Dynamic_Array)(array).len -= 1
 }
-
+// `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements.
+//
+// Note: This is an O(N) operation.
+// Note: If you the elements do not have to remain in their order, prefer `unordered_remove`.
+// Note: If the index is out of bounds, this procedure will panic.
 @builtin
 ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
 	bounds_check_error_loc(loc, index, len(array))
@@ -67,6 +90,10 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_locati
 	(^Raw_Dynamic_Array)(array).len -= 1
 }
 
+// `remove_range` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements.
+//
+// Note: This is an O(N) operation.
+// Note: If the range is out of bounds, this procedure will panic.
 @builtin
 remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
 	slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
@@ -80,6 +107,9 @@ remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_locatio
 }
 
 
+// `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
+//
+// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
 @builtin
 pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
 	assert(len(array) > 0, "", loc)
@@ -89,6 +119,8 @@ pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bou
 }
 
 
+// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
+// If the operation is not possible, it will return false.
 @builtin
 pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
 	if len(array) == 0 {
@@ -99,6 +131,9 @@ pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check
 	return
 }
 
+// `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1.
+//
+// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
 @builtin
 pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
 	assert(len(array) > 0, "", loc)
@@ -110,6 +145,8 @@ pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #
 	return res
 }
 
+// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1.
+// If the operation is not possible, it will return false.
 @builtin
 pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
 	if len(array) == 0 {
@@ -124,12 +161,15 @@ pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_
 }
 
 
+// `clear` will set the length of a passed dynamic array or map to `0`
 @builtin
 clear :: proc{clear_dynamic_array, clear_map}
 
+// `reserve` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
 @builtin
 reserve :: proc{reserve_dynamic_array, reserve_map}
 
+// `resize` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
 @builtin
 resize :: proc{resize_dynamic_array}
 
@@ -137,36 +177,56 @@ resize :: proc{resize_dynamic_array}
 @builtin
 shrink :: proc{shrink_dynamic_array, shrink_map}
 
+// `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation.
 @builtin
 free :: proc{mem_free}
 
+// `free_all` will try to free/reset all of the memory of the given `allocator` if the allocator supports this operation.
 @builtin
 free_all :: proc{mem_free_all}
 
 
 
+// `delete_string` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer the procedure group `delete`.
 @builtin
 delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
 	return mem_free_with_size(raw_data(str), len(str), allocator, loc)
 }
+// `delete_cstring` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer the procedure group `delete`.
 @builtin
 delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
 	return mem_free((^byte)(str), allocator, loc)
 }
+// `delete_dynamic_array` will try to free the underlying data of the passed dynamic array, with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer the procedure group `delete`.
 @builtin
 delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
 	return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
 }
+// `delete_slice` will try to free the underlying data of the passed sliced, with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer the procedure group `delete`.
 @builtin
 delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
 	return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
 }
+// `delete_map` will try to free the underlying data of the passed map, with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer the procedure group `delete`.
 @builtin
 delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
 	return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc)
 }
 
 
+// `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
+//
+// Note: Prefer `delete` over the specific `delete_*` procedures where possible.
 @builtin
 delete :: proc{
 	delete_string,
@@ -179,17 +239,18 @@ delete :: proc{
 
 // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
 // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
-@builtin
+@(builtin, require_results)
 new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
 	return new_aligned(T, align_of(T), allocator, loc)
 }
+@(require_results)
 new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
 	data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
 	t = (^T)(raw_data(data))
 	return
 }
 
-@builtin
+@(builtin, require_results)
 new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
 	t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
 	t = (^T)(raw_data(t_data))
@@ -201,6 +262,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
 
 DEFAULT_RESERVE_CAPACITY :: 16
 
+@(require_results)
 make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
 	make_slice_error_loc(loc, len)
 	data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
@@ -211,19 +273,35 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
 	return transmute(T)s, err
 }
 
-@(builtin)
+// `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
 	return make_aligned(T, len, align_of(E), allocator, loc)
 }
-@(builtin)
+// `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
 	return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
 }
-@(builtin)
+// `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
 	return make_dynamic_array_len_cap(T, len, len, allocator, loc)
 }
-@(builtin)
+// `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	make_dynamic_array_error_loc(loc, len, cap)
 	data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
@@ -234,7 +312,11 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
 	array = transmute(T)s
 	return
 }
-@(builtin)
+// `make_map` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
 	make_map_expr_error_loc(loc, capacity)
 	context.allocator = allocator
@@ -242,7 +324,13 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_
 	err = reserve_map(&m, capacity, loc)
 	return
 }
-@(builtin)
+// `make_multi_pointer` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
+// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
+//
+// This is "similar" to doing `raw_data(make([]E, len, allocator))`.
+//
+// Note: Prefer using the procedure group `make`.
+@(builtin, require_results)
 make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error {
 	make_slice_error_loc(loc, len)
 	data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
@@ -254,8 +342,9 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
 }
 
 
-// The make built-in procedure allocates and initializes a value of type slice, dynamic array, or map (only)
-// Similar to new, the first argument is a type, not a value. Unlike new, make's return type is the same as the
+// `make` built-in procedure allocates and initializes a value of type slice, dynamic array, map, or multi-pointer (only).
+//
+// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
 // type of its argument, not a pointer to it.
 // Make uses the specified allocator, default is context.allocator, default is context.allocator
 @builtin
@@ -270,6 +359,9 @@ make :: proc{
 
 
 
+// `clear_map` will set the length of a passed map to `0`
+//
+// Note: Prefer the procedure group `clear`
 @builtin
 clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
 	if m == nil {
@@ -278,19 +370,21 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
 	map_clear_dynamic((^Raw_Map)(m), map_info(T))
 }
 
+// `reserve_map` will try to reserve memory of a passed map to the requested element count (setting the `cap`).
+//
+// Note: Prefer the procedure group `reserve`
 @builtin
 reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error {
 	return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
 }
 
-/*
-	Shrinks the capacity of a map down to the current length.
-*/
+// Shrinks the capacity of a map down to the current length.
+//
+// Note: Prefer the procedure group `shrink`
 @builtin
-shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool) {
+shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
 	if m != nil {
-		err := map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
-		did_shrink = err == nil
+		return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
 	}
 	return
 }
@@ -313,18 +407,18 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
 
 
 @builtin
-append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
+append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 	when size_of(E) == 0 {
 		array := (^Raw_Dynamic_Array)(array)
 		array.len += 1
-		return 1
+		return 1, nil
 	} else {
 		if cap(array) < len(array)+1 {
 			cap := 2 * cap(array) + max(8, 1)
-			_ = reserve(array, cap, loc)
+			err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
 		}
 		if cap(array)-len(array) > 0 {
 			a := (^Raw_Dynamic_Array)(array)
@@ -334,31 +428,31 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
 				data[a.len] = arg
 			}
 			a.len += 1
-			return 1
+			return 1, err
 		}
-		return 0
+		return 0, err
 	}
 }
 
 @builtin
-append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
+append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 
 	arg_len := len(args)
 	if arg_len <= 0 {
-		return 0
+		return 0, nil
 	}
 
 	when size_of(E) == 0 {
 		array := (^Raw_Dynamic_Array)(array)
 		array.len += arg_len
-		return arg_len
+		return arg_len, nil
 	} else {
 		if cap(array) < len(array)+arg_len {
 			cap := 2 * cap(array) + max(8, arg_len)
-			_ = reserve(array, cap, loc)
+			err = reserve(array, cap, loc)  // do not 'or_return' here as it could be a partial success
 		}
 		arg_len = min(cap(array)-len(array), arg_len)
 		if arg_len > 0 {
@@ -370,13 +464,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
 			}
 			a.len += arg_len
 		}
-		return arg_len
+		return arg_len, err
 	}
 }
 
 // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
 @builtin
-append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
+append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	args := transmute([]E)arg
 	return append_elems(array=array, args=args, loc=loc)
 }
@@ -384,9 +478,14 @@ append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #ca
 
 // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
 @builtin
-append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
+append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
+	n_arg: int
 	for arg in args {
-		n += append(array = array, args = transmute([]E)(arg), loc = loc)
+		n_arg, err = append(array = array, args = transmute([]E)(arg), loc = loc)
+		n += n_arg
+		if err != nil {
+			return
+		}
 	}
 	return
 }
@@ -396,18 +495,18 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
 
 
 @builtin
-append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
+append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 	prev_len := len(array)
-	resize(array, len(array)+1, loc)
-	return len(array)-prev_len
+	resize(array, len(array)+1, loc) or_return
+	return len(array)-prev_len, nil
 }
 
 
 @builtin
-inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 		return
 	}
@@ -415,18 +514,17 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
 	m :: 1
 	new_size := n + m
 
-	if resize(array, new_size, loc) {
-		when size_of(E) != 0 {
-			copy(array[index + m:], array[index:])
-			array[index] = arg
-		}
-		ok = true
+	resize(array, new_size, loc) or_return
+	when size_of(E) != 0 {
+		copy(array[index + m:], array[index:])
+		array[index] = arg
 	}
+	ok = true
 	return
 }
 
 @builtin
-inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 		return
 	}
@@ -439,18 +537,17 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
 	m := len(args)
 	new_size := n + m
 
-	if resize(array, new_size, loc) {
-		when size_of(E) != 0 {
-			copy(array[index + m:], array[index:])
-			copy(array[index:], args)
-		}
-		ok = true
+	resize(array, new_size, loc) or_return
+	when size_of(E) != 0 {
+		copy(array[index + m:], array[index:])
+		copy(array[index:], args)
 	}
+	ok = true
 	return
 }
 
 @builtin
-inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 		return
 	}
@@ -463,11 +560,10 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
 	m := len(arg)
 	new_size := n + m
 
-	if resize(array, new_size, loc) {
-		copy(array[index+m:], array[index:])
-		copy(array[index:], arg)
-		ok = true
-	}
+	resize(array, new_size, loc) or_return
+	copy(array[index+m:], array[index:])
+	copy(array[index:], arg)
+	ok = true
 	return
 }
 
@@ -476,11 +572,12 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
 
 
 @builtin
-assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if index < len(array) {
 		array[index] = arg
 		ok = true
-	} else if resize(array, index+1, loc) {
+	} else {
+		resize(array, index+1, loc) or_return
 		array[index] = arg
 		ok = true
 	}
@@ -489,11 +586,12 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
 
 
 @builtin
-assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if index+len(args) < len(array) {
 		copy(array[index:], args)
 		ok = true
-	} else if resize(array, index+1+len(args), loc) {
+	} else {
+		resize(array, index+1+len(args), loc) or_return
 		copy(array[index:], args)
 		ok = true
 	}
@@ -502,13 +600,14 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
 
 
 @builtin
-assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if len(args) == 0 {
 		ok = true
 	} else if index+len(args) < len(array) {
 		copy(array[index:], args)
 		ok = true
-	} else if resize(array, index+1+len(args), loc) {
+	} else {
+		resize(array, index+1+len(args), loc) or_return
 		copy(array[index:], args)
 		ok = true
 	}
@@ -520,6 +619,9 @@ assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
 
 
 
+// `clear_dynamic_array` will set the length of a passed dynamic array to `0`
+//
+// Note: Prefer the procedure group `clear`.
 @builtin
 clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
 	if array != nil {
@@ -527,15 +629,18 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
 	}
 }
 
+// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
+//
+// Note: Prefer the procedure group `reserve`.
 @builtin
-reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
+reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
+		return nil
 	}
 	a := (^Raw_Dynamic_Array)(array)
 
 	if capacity <= a.cap {
-		return true
+		return nil
 	}
 
 	if a.allocator.procedure == nil {
@@ -547,26 +652,29 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
 	new_size  := capacity * size_of(E)
 	allocator := a.allocator
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
-	if new_data == nil || err != nil {
-		return false
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
+	if new_data == nil && new_size > 0 {
+		return .Out_Of_Memory
 	}
 
 	a.data = raw_data(new_data)
 	a.cap = capacity
-	return true
+	return nil
 }
 
+// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
+//
+// Note: Prefer the procedure group `resize`
 @builtin
-resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
+resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
+		return nil
 	}
 	a := (^Raw_Dynamic_Array)(array)
 
 	if length <= a.cap {
 		a.len = max(length, 0)
-		return true
+		return nil
 	}
 
 	if a.allocator.procedure == nil {
@@ -578,15 +686,15 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
 	new_size  := length * size_of(E)
 	allocator := a.allocator
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
-	if new_data == nil || err != nil {
-		return false
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
+	if new_data == nil && new_size > 0 {
+		return .Out_Of_Memory
 	}
 
 	a.data = raw_data(new_data)
 	a.len = length
 	a.cap = length
-	return true
+	return nil
 }
 
 /*
@@ -597,8 +705,10 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
 	Returns false if `cap(array) < new_cap`, or the allocator report failure.
 
 	If `len(array) < new_cap`, then `len(array)` will be left unchanged.
+
+	Note: Prefer the procedure group `shrink`
 */
-shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) {
+shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
 	if array == nil {
 		return
 	}
@@ -618,15 +728,12 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
 	old_size := a.cap * size_of(E)
 	new_size := new_cap * size_of(E)
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
-	if err != nil {
-		return
-	}
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) or_return
 
 	a.data = raw_data(new_data)
 	a.len = min(new_cap, a.len)
 	a.cap = new_cap
-	return true
+	return true, nil
 }
 
 @builtin

+ 19 - 19
core/runtime/core_builtin_matrix.odin

@@ -37,12 +37,12 @@ inverse :: proc{
 	matrix4x4_inverse,
 }
 
-@(builtin)
+@(builtin, require_results)
 hermitian_adjoint :: proc "contextless" (m: $M/matrix[$N, N]$T) -> M where intrinsics.type_is_complex(T), N >= 1 {
 	return conj(transpose(m))
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix_trace :: proc "contextless" (m: $M/matrix[$N, N]$T) -> (trace: T) {
 	for i in 0..<N {
 		trace += m[i, i]
@@ -50,7 +50,7 @@ matrix_trace :: proc "contextless" (m: $M/matrix[$N, N]$T) -> (trace: T) {
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix_minor :: proc "contextless" (m: $M/matrix[$N, N]$T, row, column: int) -> (minor: T) where N > 1 {
 	K :: N-1
 	cut_down: matrix[K, K]T
@@ -66,23 +66,23 @@ matrix_minor :: proc "contextless" (m: $M/matrix[$N, N]$T, row, column: int) ->
 
 
 
-@(builtin)
+@(builtin, require_results)
 matrix1x1_determinant :: proc "contextless" (m: $M/matrix[1, 1]$T) -> (det: T) {
 	return m[0, 0]
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix2x2_determinant :: proc "contextless" (m: $M/matrix[2, 2]$T) -> (det: T) {
 	return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0]
 }
-@(builtin)
+@(builtin, require_results)
 matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
 	a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1])
 	b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0])
 	c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0])
 	return a + b + c
 }
-@(builtin)
+@(builtin, require_results)
 matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
 	a := adjugate(m)
 	#no_bounds_check for i in 0..<4 {
@@ -94,13 +94,13 @@ matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
 
 
 
-@(builtin)
+@(builtin, require_results)
 matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
 	y = x
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	y[0, 0] = +x[1, 1]
 	y[0, 1] = -x[1, 0]
@@ -109,7 +109,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
@@ -124,7 +124,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 }
 
 
-@(builtin)
+@(builtin, require_results)
 matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
 	for i in 0..<4 {
 		for j in 0..<4 {
@@ -135,13 +135,13 @@ matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix1x1_inverse_transpose :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
 	y[0, 0] = 1/x[0, 0]
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
 	when intrinsics.type_is_integer(T) {
@@ -159,7 +159,7 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 	a := adjugate(x)
 	d := determinant(x)
@@ -180,7 +180,7 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 	a := adjugate(x)
 	d: T
@@ -204,13 +204,13 @@ matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y:
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix1x1_inverse :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
 	y[0, 0] = 1/x[0, 0]
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
 	when intrinsics.type_is_integer(T) {
@@ -228,7 +228,7 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 	a := adjugate(x)
 	d := determinant(x)
@@ -249,7 +249,7 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
 	return
 }
 
-@(builtin)
+@(builtin, require_results)
 matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 	a := adjugate(x)
 	d: T

+ 48 - 51
core/runtime/core_builtin_soa.odin

@@ -50,6 +50,7 @@ Raw_SOA_Footer_Dynamic_Array :: struct {
 	allocator: Allocator,
 }
 
+@(builtin, require_results)
 raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) {
 	if array == nil {
 		return nil
@@ -58,6 +59,7 @@ raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Sl
 	footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr))
 	return
 }
+@(builtin, require_results)
 raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) {
 	if array == nil {
 		return nil
@@ -78,7 +80,7 @@ raw_soa_footer :: proc{
 
 
 
-@builtin
+@(builtin, require_results)
 make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	if length <= 0 {
 		return
@@ -137,32 +139,31 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
 	return
 }
 
-@builtin
+@(builtin, require_results)
 make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	return make_soa_aligned(T, length, align_of(E), allocator, loc)
 }
 
-@builtin
-make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+@(builtin, require_results)
+make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
-	return
+	reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return
+	return array, nil
 }
 
-@builtin
-make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+@(builtin, require_results)
+make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	resize_soa(&array, length, loc)
-	return
+	resize_soa(&array, length, loc) or_return
+	return array, nil
 }
 
-@builtin
-make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+@(builtin, require_results)
+make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	if reserve_soa(&array, capacity, loc) {
-		resize_soa(&array, length, loc)
-	}
-	return
+	reserve_soa(&array, capacity, loc) or_return
+	resize_soa(&array, length, loc) or_return
+	return array, nil
 }
 
 
@@ -176,27 +177,25 @@ make_soa :: proc{
 
 
 @builtin
-resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool {
+resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
-	}
-	if !reserve_soa(array, length, loc) {
-		return false
+		return nil
 	}
+	reserve_soa(array, length, loc) or_return
 	footer := raw_soa_footer(array)
 	footer.len = length
-	return true
+	return nil
 }
 
 @builtin
-reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
+reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
+		return nil
 	}
 
 	old_cap := cap(array)
 	if capacity <= old_cap {
-		return true
+		return nil
 	}
 
 	if array.allocator.procedure == nil {
@@ -207,7 +206,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 	footer := raw_soa_footer(array)
 	if size_of(E) == 0 {
 		footer.cap = capacity
-		return true
+		return nil
 	}
 
 	ti := type_info_of(typeid_of(T))
@@ -238,13 +237,10 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 
 	old_data := (^rawptr)(array)^
 
-	new_bytes, err := array.allocator.procedure(
+	new_bytes := array.allocator.procedure(
 		array.allocator.data, .Alloc, new_size, max_align,
 		nil, old_size, loc,
-	)
-	if new_bytes == nil || err != nil {
-		return false
-	}
+	) or_return
 	new_data := raw_data(new_bytes)
 
 
@@ -269,31 +265,28 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 		new_offset += type.size * capacity
 	}
 
-	_, err = array.allocator.procedure(
+	array.allocator.procedure(
 		array.allocator.data, .Free, 0, max_align,
 		old_data, old_size, loc,
-	)
+	) or_return
 
-	return true
+	return nil
 }
 
 @builtin
-append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) {
+append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
-		return
+		return 0, nil
 	}
 
-	arg_len := 1
-
-	if cap(array) <= len(array)+arg_len {
-		cap := 2 * cap(array) + max(8, arg_len)
-		_ = reserve_soa(array, cap, loc)
+	if cap(array) <= len(array) + 1 {
+		cap := 2 * cap(array) + 8
+		err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
 	}
-	arg_len = min(cap(array)-len(array), arg_len)
 
 	footer := raw_soa_footer(array)
 
-	if size_of(E) > 0 && arg_len > 0 {
+	if size_of(E) > 0 && cap(array)-len(array) > 0 {
 		ti := type_info_of(typeid_of(T))
 		ti = type_info_base(ti)
 		si := &ti.variant.(Type_Info_Struct)
@@ -326,12 +319,14 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
 			soa_offset  += type.size * cap(array)
 			item_offset += type.size
 		}
+		footer.len += 1
+		return 1, err
 	}
-	footer.len += arg_len
+	return 0, err
 }
 
 @builtin
-append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) {
+append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
 		return
 	}
@@ -343,7 +338,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
 
 	if cap(array) <= len(array)+arg_len {
 		cap := 2 * cap(array) + max(8, arg_len)
-		_ = reserve_soa(array, cap, loc)
+		err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
 	}
 	arg_len = min(cap(array)-len(array), arg_len)
 
@@ -380,8 +375,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
 			item_offset += type.size
 		}
 	}
-
 	footer.len += arg_len
+	return arg_len, err
 }
 
 
@@ -393,21 +388,23 @@ append_soa :: proc{
 }
 
 
-delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) {
+delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
 	when intrinsics.type_struct_field_count(E) != 0 {
 		array := array
 		ptr := (^rawptr)(&array)^
-		free(ptr, allocator, loc)
+		free(ptr, allocator, loc) or_return
 	}
+	return nil
 }
 
-delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) {
+delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error {
 	when intrinsics.type_struct_field_count(E) != 0 {
 		array := array
 		ptr := (^rawptr)(&array)^
 		footer := raw_soa_footer(&array)
-		free(ptr, footer.allocator, loc)
+		free(ptr, footer.allocator, loc) or_return
 	}
+	return nil
 }
 
 

+ 89 - 24
core/runtime/dynamic_map_internal.odin

@@ -251,6 +251,26 @@ map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
 	return (hash != 0) & (hash & TOMBSTONE_MASK == 0)
 }
 
+@(require_results)
+map_seed :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
+	return map_seed_from_map_data(map_data(m))
+}
+
+// splitmix for uintptr
+@(require_results)
+map_seed_from_map_data :: #force_inline proc "contextless" (data: uintptr) -> uintptr {
+	when size_of(uintptr) == size_of(u64) {
+		mix := data + 0x9e3779b97f4a7c15
+		mix = (mix ~ (mix >> 30)) * 0xbf58476d1ce4e5b9
+		mix = (mix ~ (mix >> 27)) * 0x94d049bb133111eb
+		return mix ~ (mix >> 31)
+	} else {
+		mix := data + 0x9e3779b9
+		mix = (mix ~ (mix >> 16)) * 0x21f0aaad
+		mix = (mix ~ (mix >> 15)) * 0x735a2d97
+		return mix ~ (mix >> 15)
+	}
+}
 
 // Computes the desired position in the array. This is just index % capacity,
 // but a procedure as there's some math involved here to recover the capacity.
@@ -394,32 +414,71 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
 	tk := map_cell_index_dynamic(sk, info.ks, 1)
 	tv := map_cell_index_dynamic(sv, info.vs, 1)
 
-
 	for {
 		hp := &hs[pos]
 		element_hash := hp^
 
 		if map_hash_is_empty(element_hash) {
-			k_dst := map_cell_index_dynamic(ks, info.ks, pos)
-			v_dst := map_cell_index_dynamic(vs, info.vs, pos)
-			intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
-			intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
+			kp := map_cell_index_dynamic(ks, info.ks, pos)
+			vp := map_cell_index_dynamic(vs, info.vs, pos)
+			intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
+			intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
 			hp^ = h
 
-			return result if result != 0 else v_dst
+			return result if result != 0 else vp
 		}
 
-		if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
-			if map_hash_is_deleted(element_hash) {
-				k_dst := map_cell_index_dynamic(ks, info.ks, pos)
-				v_dst := map_cell_index_dynamic(vs, info.vs, pos)
-				intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
-				intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
-				hp^ = h
-
-				return result if result != 0 else v_dst
+		if map_hash_is_deleted(element_hash) {
+			next_pos := (pos + 1) & mask
+
+			// backward shift
+			for !map_hash_is_empty(hs[next_pos]) {
+				probe_distance := map_probe_distance(m^, hs[next_pos], next_pos)
+				if probe_distance == 0 {
+					break
+				}
+				probe_distance -= 1
+
+				kp := map_cell_index_dynamic(ks, info.ks, pos)
+				vp := map_cell_index_dynamic(vs, info.vs, pos)
+				kn := map_cell_index_dynamic(ks, info.ks, next_pos)
+				vn := map_cell_index_dynamic(vs, info.vs, next_pos)
+
+				if distance > probe_distance {
+					if result == 0 {
+						result = vp
+					}
+					// move stored into pos; store next
+					intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
+					intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
+					hs[pos] = h
+
+					intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(kn), size_of_k)
+					intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(vn), size_of_v)
+					h = hs[next_pos]
+				} else {
+					// move next back 1
+					intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(kn), size_of_k)
+					intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(vn), size_of_v)
+					hs[pos] = hs[next_pos]
+					distance = probe_distance
+				}
+				hs[next_pos] = 0
+				pos = (pos + 1) & mask
+				next_pos = (next_pos + 1) & mask
+				distance += 1
 			}
 
+			kp := map_cell_index_dynamic(ks, info.ks, pos)
+			vp := map_cell_index_dynamic(vs, info.vs, pos)
+			intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
+			intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
+			hs[pos] = h
+
+			return result if result != 0 else vp
+		}
+
+		if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
 			if result == 0 {
 				result = map_cell_index_dynamic(vs, info.vs, pos)
 			}
@@ -503,6 +562,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
 		}
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
+		hash = info.key_hasher(rawptr(k), map_seed(resized))
 		_ = map_insert_hash_dynamic(&resized, info, hash, k, v)
 		// Only need to do this comparison on each actually added pair, so do not
 		// fold it into the for loop comparator as a micro-optimization.
@@ -550,6 +610,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
 
 		k := map_cell_index_dynamic(ks, info.ks, i)
 		v := map_cell_index_dynamic(vs, info.vs, i)
+		hash = info.key_hasher(rawptr(k), map_seed(shrunk))
 		_ = map_insert_hash_dynamic(&shrunk, info, hash, k, v)
 		// Only need to do this comparison on each actually added pair, so do not
 		// fold it into the for loop comparator as a micro-optimization.
@@ -581,7 +642,7 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
 	if map_len(m) == 0 {
 		return 0, false
 	}
-	h := info.key_hasher(rawptr(k), 0)
+	h := info.key_hasher(rawptr(k), map_seed(m))
 	p := map_desired_position(m, h)
 	d := uintptr(0)
 	c := (uintptr(1) << map_log2_cap(m)) - 1
@@ -604,7 +665,7 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
 	if map_len(m) == 0 {
 		return false
 	}
-	h := info.key_hasher(rawptr(k), 0)
+	h := info.key_hasher(rawptr(k), map_seed(m))
 	p := map_desired_position(m, h)
 	d := uintptr(0)
 	c := (uintptr(1) << map_log2_cap(m)) - 1
@@ -637,7 +698,6 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
 
 	{ // coalesce tombstones
 		// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
-		// TODO(bill): we should do backward shift deletion and not rely on tombstone slots
 		mask := (uintptr(1)<<map_log2_cap(m^)) - 1
 		curr_index := uintptr(index)
 
@@ -711,7 +771,7 @@ map_get :: proc "contextless" (m: $T/map[$K]$V, key: K) -> (stored_key: K, store
 	info := intrinsics.type_map_info(T)
 	key := key
 
-	h := info.key_hasher(&key, 0)
+	h := info.key_hasher(&key, map_seed(rm))
 	pos := map_desired_position(rm, h)
 	distance := uintptr(0)
 	mask := (uintptr(1) << map_log2_cap(rm)) - 1
@@ -762,15 +822,15 @@ __dynamic_map_get :: proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info:
 }
 
 // IMPORTANT: USED WITHIN THE COMPILER
-__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
+__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (err: Allocator_Error, has_grown: bool) {
 	if m.len >= map_resize_threshold(m^) {
-		return map_grow_dynamic(m, info, loc)
+		return map_grow_dynamic(m, info, loc), true
 	}
-	return nil
+	return nil, false
 }
 
 __dynamic_map_set_without_hash :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> rawptr {
-	return __dynamic_map_set(m, info, info.key_hasher(key, 0), key, value, loc)
+	return __dynamic_map_set(m, info, info.key_hasher(key, map_seed(m^)), key, value, loc)
 }
 
 
@@ -781,9 +841,14 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In
 		return found
 	}
 
-	if __dynamic_map_check_grow(m, info, loc) != nil {
+	hash := hash
+	err, has_grown := __dynamic_map_check_grow(m, info, loc)
+	if err != nil {
 		return nil
 	}
+	if has_grown {
+		hash = info.key_hasher(key, map_seed(m^))
+	}
 
 	result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
 	m.len += 1

+ 36 - 0
core/runtime/internal.odin

@@ -500,6 +500,42 @@ string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int
 	return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
 }
 
+string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
+	RUNE_ERROR :: '\ufffd'
+	RUNE_SELF  :: 0x80
+	UTF_MAX    :: 4
+
+	r: rune
+	size: int
+	start, end, limit: int
+
+	end = len(s)
+	if end == 0 {
+		return RUNE_ERROR, 0
+	}
+	start = end-1
+	r = rune(s[start])
+	if r < RUNE_SELF {
+		return r, 1
+	}
+
+	limit = max(end - UTF_MAX, 0)
+
+	for start-=1; start >= limit; start-=1 {
+		if (s[start] & 0xc0) != RUNE_SELF {
+			break
+		}
+	}
+
+	start = max(start, 0)
+	r, size = string_decode_rune(s[start:end])
+	if start+size != end {
+		return RUNE_ERROR, 1
+	}
+	return r, size
+}
+
+
 abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
 	return -x if x < 0 else x
 }

+ 1 - 1
core/runtime/os_specific_js.odin

@@ -5,7 +5,7 @@ foreign import "odin_env"
 
 _os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
 	foreign odin_env {
-		write :: proc "c" (fd: u32, p: []byte) ---
+		write :: proc "contextless" (fd: u32, p: []byte) ---
 	}
 	write(1, data)
 	return len(data), 0

+ 2 - 2
core/runtime/procs_wasm32.odin

@@ -8,7 +8,7 @@ ti_int :: struct #raw_union {
 }
 
 @(link_name="__ashlti3", linkage="strong")
-__ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 {
+__ashlti3 :: proc "contextless" (a: i128, b_: u32) -> i128 {
 	bits_in_dword :: size_of(u32)*8
 	b := u32(b_)
 	
@@ -29,7 +29,7 @@ __ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 {
 
 
 @(link_name="__multi3", linkage="strong")
-__multi3 :: proc "c" (a, b: i128) -> i128 {
+__multi3 :: proc "contextless" (a, b: i128) -> i128 {
 	x, y, r: ti_int
 	
 	x.all = a

+ 67 - 19
core/slice/slice.odin

@@ -13,6 +13,7 @@ _ :: mem
 /*
 	Turn a pointer and a length into a slice.
 */
+@(require_results)
 from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
 	return ([^]T)(ptr)[:count]
 }
@@ -20,6 +21,7 @@ from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
 /*
 	Turn a pointer and a length into a byte slice.
 */
+@(require_results)
 bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
 	return ([^]byte)(ptr)[:byte_count]
 }
@@ -29,6 +31,7 @@ bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
 
 	See `slice.reinterpret` to go the other way.
 */
+@(require_results)
 to_bytes :: proc "contextless" (s: []$T) -> []byte {
 	return ([^]byte)(raw_data(s))[:len(s) * size_of(T)]
 }
@@ -51,10 +54,15 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
 	assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
 	```
 */
+@(require_results)
 reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U {
-	bytes := to_bytes(s)
-	n := len(bytes) / size_of(U)
-	return ([^]U)(raw_data(bytes))[:n]
+	when size_of(U) == 0 || size_of(V) == 0 {
+		return nil
+	} else {
+		bytes := to_bytes(s)
+		n := len(bytes) / size_of(U)
+		return ([^]U)(raw_data(bytes))[:n]
+	}
 }
 
 
@@ -82,11 +90,13 @@ reverse :: proc(array: $T/[]$E) {
 }
 
 
+@(require_results)
 contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) {
 	_, found := linear_search(array, value)
 	return found
 }
 
+@(require_results)
 linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 	where intrinsics.type_is_comparable(T) #no_bounds_check {
 	for x, i in array {
@@ -97,6 +107,7 @@ linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 	return -1, false
 }
 
+@(require_results)
 linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check {
 	for x, i in array {
 		if f(x) {
@@ -106,6 +117,7 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
 	return -1, false
 }
 
+@(require_results)
 binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 	where intrinsics.type_is_ordered(T) #no_bounds_check {
 
@@ -146,6 +158,7 @@ binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 }
 
 
+@(require_results)
 equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
 	if len(a) != len(b) {
 		return false
@@ -162,6 +175,7 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
 	}
 }
 
+@(require_results)
 simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) {
 	if len(a) != len(b) {
 		return false
@@ -176,6 +190,7 @@ simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_comp
 	slice.prefix_length([]u8{1, 2, 3, 4}, []u8{1, 2, 3}) -> 3
 	slice.prefix_length([]u8{1, 2, 3, 4}, []u8{2, 3, 4}) -> 0
 */
+@(require_results)
 prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) {
 	_len := builtin.min(len(a), len(b))
 
@@ -185,6 +200,7 @@ prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_compar
 	return
 }
 
+@(require_results)
 has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) {
 	n := len(needle)
 	if len(array) >= n {
@@ -194,6 +210,7 @@ has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_c
 }
 
 
+@(require_results)
 has_suffix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) {
 	array := array
 	m, n := len(array), len(needle)
@@ -232,7 +249,8 @@ swap_with_slice :: proc(a, b: $T/[]$E, loc := #caller_location) {
 	ptr_swap_non_overlapping(raw_data(a), raw_data(b), len(a)*size_of(E))
 }
 
-concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) {
+@(require_results)
+concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: mem.Allocator_Error) #optional_allocator_error {
 	if len(a) == 0 {
 		return
 	}
@@ -240,7 +258,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) {
 	for s in a {
 		n += len(s)
 	}
-	res = make(T, n, allocator)
+	res = make(T, n, allocator) or_return
 	i := 0
 	for s in a {
 		i += copy(res[i:], s)
@@ -249,22 +267,24 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) {
 }
 
 // copies a slice into a new slice
-clone :: proc(a: $T/[]$E, allocator := context.allocator) -> []E {
-	d := make([]E, len(a), allocator)
+@(require_results)
+clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, mem.Allocator_Error) #optional_allocator_error {
+	d, err := make([]E, len(a), allocator)
 	copy(d[:], a)
-	return d
+	return d, err
 }
 
 
 // copies slice into a new dynamic array
-clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> [dynamic]E {
-	d := make([dynamic]E, len(a), allocator)
+clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> ([dynamic]E, mem.Allocator_Error) #optional_allocator_error {
+	d, err := make([dynamic]E, len(a), allocator)
 	copy(d[:], a)
-	return d
+	return d, err
 }
 to_dynamic :: clone_to_dynamic
 
 // Converts slice into a dynamic array without cloning or allocating memory
+@(require_results)
 into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E {
 	s := transmute(mem.Raw_Slice)a
 	d := mem.Raw_Dynamic_Array{
@@ -277,43 +297,51 @@ into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E {
 }
 
 
+@(require_results)
 length :: proc(a: $T/[]$E) -> int {
 	return len(a)
 }
+@(require_results)
 is_empty :: proc(a: $T/[]$E) -> bool {
 	return len(a) == 0
 }
 
 
 
-
+@(require_results)
 split_at :: proc(array: $T/[]$E, index: int) -> (a, b: T) {
 	return array[:index], array[index:]
 }
 
 
+@(require_results)
 split_first :: proc(array: $T/[]$E) -> (first: E, rest: T) {
 	return array[0], array[1:]
 }
+@(require_results)
 split_last :: proc(array: $T/[]$E) -> (rest: T, last: E) {
 	n := len(array)-1
 	return array[:n], array[n]
 }
 
+@(require_results)
 first :: proc(array: $T/[]$E) -> E {
 	return array[0]
 }
+@(require_results)
 last :: proc(array: $T/[]$E) -> E {
 	return array[len(array)-1]
 }
 
 
+@(require_results)
 first_ptr :: proc(array: $T/[]$E) -> ^E {
 	if len(array) != 0 {
 		return &array[0]
 	}
 	return nil
 }
+@(require_results)
 last_ptr :: proc(array: $T/[]$E) -> ^E {
 	if len(array) != 0 {
 		return &array[len(array)-1]
@@ -321,6 +349,7 @@ last_ptr :: proc(array: $T/[]$E) -> ^E {
 	return nil
 }
 
+@(require_results)
 get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) {
 	if uint(index) < len(array) {
 		value = array[index]
@@ -328,6 +357,7 @@ get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) {
 	}
 	return
 }
+@(require_results)
 get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) {
 	if uint(index) < len(array) {
 		value = &array[index]
@@ -336,19 +366,22 @@ get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) {
 	return
 }
 
+@(require_results)
 as_ptr :: proc(array: $T/[]$E) -> [^]E {
 	return raw_data(array)
 }
 
 
-mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> []V {
-	r := make([]V, len(s), allocator)
+@(require_results)
+mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: mem.Allocator_Error) #optional_allocator_error {
+	r = make([]V, len(s), allocator) or_return
 	for v, i in s {
 		r[i] = f(v)
 	}
-	return r
+	return
 }
 
+@(require_results)
 reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
 	r := initializer
 	for v in s {
@@ -357,6 +390,7 @@ reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
 	return r
 }
 
+@(require_results)
 filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S {
 	r := make([dynamic]U, 0, 0, allocator)
 	for v in s {
@@ -367,10 +401,11 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -
 	return r[:]
 }
 
-scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> []V {
-	if len(s) == 0 { return {} }
+@(require_results)
+scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: mem.Allocator_Error) #optional_allocator_error {
+	if len(s) == 0 { return }
 
-	res := make([]V, len(s), allocator)
+	res = make([]V, len(s), allocator) or_return
 	p := as_ptr(s)
 	q := as_ptr(res)
 	r := initializer
@@ -382,10 +417,11 @@ scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := c
 		q = q[1:]
 	}
 
-	return res
+	return
 }
 
 
+@(require_results)
 min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
 	if len(s) != 0 {
 		res = s[0]
@@ -396,6 +432,7 @@ min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T
 	}
 	return
 }
+@(require_results)
 max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
 	if len(s) != 0 {
 		res = s[0]
@@ -407,6 +444,7 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T
 	return
 }
 
+@(require_results)
 min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) {
 	if len(s) != 0 {
 		min, max = s[0], s[0]
@@ -419,6 +457,7 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_
 	return
 }
 
+@(require_results)
 any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
 	for v in s {
 		if v == value {
@@ -428,6 +467,7 @@ any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable
 	return false
 }
 
+@(require_results)
 none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
 	for v in s {
 		if v == value {
@@ -437,6 +477,7 @@ none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparabl
 	return true
 }
 
+@(require_results)
 all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
 	if len(s) == 0 {
 		return false
@@ -450,6 +491,7 @@ all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable
 }
 
 
+@(require_results)
 any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 	for v in s {
 		if f(v) {
@@ -459,6 +501,7 @@ any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 	return false
 }
 
+@(require_results)
 none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 	for v in s {
 		if f(v) {
@@ -468,6 +511,7 @@ none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 	return true
 }
 
+@(require_results)
 all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 	if len(s) == 0 {
 		return false
@@ -481,6 +525,7 @@ all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
 }
 
 
+@(require_results)
 count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) {
 	for v in s {
 		if v == value {
@@ -490,6 +535,7 @@ count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_compara
 	return
 }
 
+@(require_results)
 count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) {
 	for v in s {
 		if f(v) {
@@ -500,6 +546,7 @@ count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) {
 }
 
 
+@(require_results)
 dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
 	where intrinsics.type_is_numeric(T) {
 	if len(a) != len(b) {
@@ -513,6 +560,7 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
 
 
 // Convert a pointer to an enumerated array to a slice of the element type
+@(require_results)
 enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
 	where intrinsics.type_is_enumerated_array(T) {
 	return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]

+ 8 - 1
core/slice/sort.odin

@@ -6,6 +6,7 @@ Ordering :: enum {
 	Greater = +1,
 }
 
+@(require_results)
 cmp :: proc(a, b: $E) -> Ordering where ORD(E) {
 	switch {
 	case a < b:
@@ -16,6 +17,7 @@ cmp :: proc(a, b: $E) -> Ordering where ORD(E) {
 	return .Equal
 }
 
+@(require_results)
 cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) {
 	return proc(a, b: E) -> Ordering {
 		switch {
@@ -144,6 +146,7 @@ stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
 	}
 }
 
+@(require_results)
 is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) {
 	for i := len(array)-1; i > 0; i -= 1 {
 		if array[i] < array[i-1] {
@@ -153,6 +156,7 @@ is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) {
 	return true
 }
 
+@(require_results)
 is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
 	for i := len(array)-1; i > 0; i -= 1 {
 		if less(array[i], array[i-1]) {
@@ -163,6 +167,8 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
 }
 
 is_sorted_by_cmp :: is_sorted_cmp
+
+@(require_results)
 is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool {
 	for i := len(array)-1; i > 0; i -= 1 {
 		if cmp(array[i], array[i-1]) == .Less {
@@ -215,6 +221,7 @@ reverse_sort_by_key :: proc(data: $T/[]$E, key: proc(E) -> $K) where ORD(K) {
 	})
 }
 
+@(require_results)
 is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K) {
 	for i := len(array)-1; i > 0; i -= 1 {
 		if key(array[i]) < key(array[i-1]) {
@@ -224,7 +231,7 @@ is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K
 	return true
 }
 
-@(private)
+@(private, require_results)
 _max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1))
 	for i := n; i > 0; i >>= 1 {
 		depth += 1

+ 7 - 3
core/sync/futex_openbsd.odin

@@ -3,7 +3,6 @@
 package sync
 
 import "core:c"
-import "core:os"
 import "core:time"
 
 FUTEX_WAIT :: 1
@@ -14,11 +13,16 @@ FUTEX_PRIVATE_FLAG :: 128
 FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
 FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
 
+ETIMEDOUT :: 60
+
+
 foreign import libc "system:c"
 
 foreign libc {
 	@(link_name="futex")
 	_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
+
+	@(link_name="__errno")	__errno :: proc() -> ^int ---
 }
 
 _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
@@ -28,7 +32,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
 		return true
 	}
 
-	if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
+	if __errno()^ == ETIMEDOUT {
 		return false
 	}
 
@@ -54,7 +58,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
 		return true
 	}
 
-	if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
+	if __errno()^ == ETIMEDOUT {
 		return false
 	}
 

+ 8 - 2
core/sync/primitives_openbsd.odin

@@ -2,8 +2,14 @@
 //+private
 package sync
 
-import "core:os"
+foreign import libc "system:c"
+
+@(default_calling_convention="c")
+foreign libc {
+	@(link_name="getthrid", private="file")
+	_unix_getthrid :: proc() -> int ---
+}
 
 _current_thread_id :: proc "contextless" () -> int {
-	return os.current_thread_id()
+	return _unix_getthrid()
 }

+ 22 - 22
core/sys/wasm/wasi/wasi_api.odin

@@ -968,7 +968,7 @@ prestat_t :: struct {
 	},
 }
 
-@(default_calling_convention="c")
+@(default_calling_convention="contextless")
 foreign wasi {
 	/**
 	 * Read command-line argument data.
@@ -1306,7 +1306,7 @@ foreign wasi {
  * Returns the number of arguments and the size of the argument string
  * data, or an error.
  */
-args_sizes_get :: proc "c" () -> (num_args, size_of_args: size_t, err: errno_t) {
+args_sizes_get :: proc "contextless" () -> (num_args, size_of_args: size_t, err: errno_t) {
 	err = wasi_args_sizes_get(&num_args, &size_of_args)
 	return
 }
@@ -1316,7 +1316,7 @@ args_sizes_get :: proc "c" () -> (num_args, size_of_args: size_t, err: errno_t)
  * Returns the number of environment variable arguments and the size of the
  * environment variable data.
  */
-environ_sizes_get :: proc "c" () -> (num_envs, size_of_envs: size_t, err: errno_t) {
+environ_sizes_get :: proc "contextless" () -> (num_envs, size_of_envs: size_t, err: errno_t) {
 	err = wasi_environ_sizes_get(&num_envs, &size_of_envs)
 	return
 }
@@ -1328,7 +1328,7 @@ environ_sizes_get :: proc "c" () -> (num_envs, size_of_envs: size_t, err: errno_
  * @return
  * The resolution of the clock, or an error if one happened.
  */
-clock_res_get :: proc "c" (
+clock_res_get :: proc "contextless" (
 	/**
 	 * The clock for which to return the resolution.
 	 */
@@ -1343,7 +1343,7 @@ clock_res_get :: proc "c" (
  * @return
  * The time value of the clock.
  */
-clock_time_get :: proc "c" (
+clock_time_get :: proc "contextless" (
 	/**
 	 * The clock for which to return the time.
 	 */
@@ -1362,7 +1362,7 @@ clock_time_get :: proc "c" (
  * @return
  * The buffer where the file descriptor's attributes are stored.
  */
-fd_fdstat_get :: proc "c" (
+fd_fdstat_get :: proc "contextless" (
 	fd: fd_t,
 ) -> (stat: fdstat_t, err: errno_t) {
 	err = wasi_fd_fdstat_get(fd, &stat)
@@ -1373,7 +1373,7 @@ fd_fdstat_get :: proc "c" (
  * @return
  * The buffer where the file's attributes are stored.
  */
-fd_filestat_get :: proc "c" (
+fd_filestat_get :: proc "contextless" (
 	fd: fd_t,
 ) -> (stat: filestat_t, err: errno_t) {
 	err = wasi_fd_filestat_get(fd, &stat)
@@ -1389,7 +1389,7 @@ fd_filestat_get :: proc "c" (
  * @return
  * The number of bytes read.
  */
-fd_pread :: proc "c" (
+fd_pread :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors in which to store data.
@@ -1408,7 +1408,7 @@ fd_pread :: proc "c" (
  * @return
  * The buffer where the description is stored.
  */
-fd_prestat_get :: proc "c" (
+fd_prestat_get :: proc "contextless" (
 	fd: fd_t,
 ) -> (desc: prestat_t, err: errno_t) {
 	err = wasi_fd_prestat_get(fd, &desc)
@@ -1420,7 +1420,7 @@ fd_prestat_get :: proc "c" (
  * @return
  * The number of bytes written.
  */
-fd_pwrite :: proc "c" (
+fd_pwrite :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors from which to retrieve data.
@@ -1440,7 +1440,7 @@ fd_pwrite :: proc "c" (
  * @return
  * The number of bytes read.
  */
-fd_read :: proc "c" (
+fd_read :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors to which to store data.
@@ -1463,7 +1463,7 @@ fd_read :: proc "c" (
  * @return
  * The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached.
  */
-fd_readdir :: proc "c" (
+fd_readdir :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * The buffer where directory entries are stored
@@ -1483,7 +1483,7 @@ fd_readdir :: proc "c" (
  * @return
  * The new offset of the file descriptor, relative to the start of the file.
  */
-fd_seek :: proc "c" (
+fd_seek :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * The number of bytes to move.
@@ -1503,7 +1503,7 @@ fd_seek :: proc "c" (
  * @return
  * The current offset of the file descriptor, relative to the start of the file.
  */
-fd_tell :: proc "c" (
+fd_tell :: proc "contextless" (
 	fd: fd_t,
 ) -> (offset: filesize_t, err: errno_t) {
 	err = wasi_fd_tell(fd, &offset)
@@ -1513,7 +1513,7 @@ fd_tell :: proc "c" (
  * Write to a file descriptor.
  * Note: This is similar to `writev` in POSIX.
  */
-fd_write :: proc "c" (
+fd_write :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors from which to retrieve data.
@@ -1529,7 +1529,7 @@ fd_write :: proc "c" (
  * @return
  * The buffer where the file's attributes are stored.
  */
-path_filestat_get :: proc "c" (
+path_filestat_get :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * Flags determining the method of how the path is resolved.
@@ -1554,7 +1554,7 @@ path_filestat_get :: proc "c" (
  * @return
  * The file descriptor of the file that has been opened.
  */
-path_open :: proc "c" (
+path_open :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * Flags determining the method of how the path is resolved.
@@ -1591,7 +1591,7 @@ path_open :: proc "c" (
  * @return
  * The number of bytes placed in the buffer.
  */
-path_readlink :: proc "c" (
+path_readlink :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * The path of the symbolic link from which to read.
@@ -1610,7 +1610,7 @@ path_readlink :: proc "c" (
  * @return
  * The number of events stored.
  */
-poll_oneoff :: proc "c" (
+poll_oneoff :: proc "contextless" (
 	/**
 	 * The events to which to subscribe.
 	 */
@@ -1634,7 +1634,7 @@ poll_oneoff :: proc "c" (
  * @return
  * Number of bytes stored in ri_data and message flags.
  */
-sock_recv :: proc "c" (
+sock_recv :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors to which to store data.
@@ -1655,7 +1655,7 @@ sock_recv :: proc "c" (
  * @return
  * Number of bytes transmitted.
  */
-sock_send :: proc "c" (
+sock_send :: proc "contextless" (
 	fd: fd_t,
 	/**
 	 * List of scatter/gather vectors to which to retrieve data
@@ -1675,7 +1675,7 @@ sock_send :: proc "c" (
 
 
 
-@(default_calling_convention="c")
+@(default_calling_convention="contextless")
 foreign wasi {
 	@(link_name="args_sizes_get")
 	wasi_args_sizes_get :: proc(

+ 2 - 1
core/sys/windows/kernel32.odin

@@ -2,6 +2,7 @@
 package sys_windows
 
 foreign import kernel32 "system:Kernel32.lib"
+foreign import one_core "system:OneCore.lib"
 
 FOREGROUND_BLUE            :: WORD(0x0001)
 FOREGROUND_GREEN           :: WORD(0x0002)
@@ -891,7 +892,7 @@ WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG
 }*/
 
 @(default_calling_convention="stdcall")
-foreign kernel32 {
+foreign one_core {
 	QueryVirtualMemoryInformation :: proc(
 		Process: HANDLE,
 		VirtualAddress: PVOID,

+ 3 - 1
core/sys/windows/user32.odin

@@ -52,6 +52,8 @@ foreign user32 {
 	TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL ---
 	DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
 
+	WaitMessage :: proc() -> BOOL ---
+
 	PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
 	PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
 
@@ -222,6 +224,7 @@ foreign user32 {
 
 	GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL ---
 	GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
+	SetWindowPlacement :: proc(hwnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
 	SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
 	CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
 	GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
@@ -463,7 +466,6 @@ WINDOWPLACEMENT :: struct {
 	ptMinPosition: POINT,
   	ptMaxPosition: POINT,
   	rcNormalPosition: RECT,
-  	rcDevice: RECT,
 }
 
 WINDOWINFO :: struct {

+ 0 - 1
core/thread/thread_windows.odin

@@ -62,7 +62,6 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 	thread.procedure       = procedure
 	thread.win32_thread    = win32_thread
 	thread.win32_thread_id = win32_thread_id
-	thread.init_context = context
 
 	ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority])
 	assert(ok == true)

+ 23 - 18
core/unicode/utf8/utf8.odin

@@ -10,6 +10,11 @@ UTF_MAX    :: 4
 SURROGATE_MIN :: 0xd800
 SURROGATE_MAX :: 0xdfff
 
+// A high/leading surrogate is in range SURROGATE_MIN..SURROGATE_HIGH_MAX,
+// A low/trailing surrogate is in range SURROGATE_LOW_MIN..SURROGATE_MAX.
+SURROGATE_HIGH_MAX :: 0xdbff
+SURROGATE_LOW_MIN  :: 0xdc00
+
 T1 :: 0b0000_0000
 TX :: 0b1000_0000
 T2 :: 0b1100_0000
@@ -54,7 +59,7 @@ accept_sizes := [256]u8{
 	0xf5..=0xff = 0xf1,
 }
 
-encode_rune :: proc(c: rune) -> ([4]u8, int) {
+encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
 	r := c
 
 	buf: [4]u8
@@ -95,10 +100,10 @@ decode_rune :: proc{
 	decode_rune_in_string,
 	decode_rune_in_bytes,
 }
-decode_rune_in_string :: #force_inline proc(s: string) -> (rune, int) {
+decode_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
 	return decode_rune_in_bytes(transmute([]u8)s)
 }
-decode_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
+decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
 	n := len(s)
 	if n < 1 {
 		return RUNE_ERROR, 0
@@ -135,7 +140,7 @@ decode_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
 	return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
 }
 
-string_to_runes :: proc(s: string, allocator := context.allocator) -> (runes: []rune) {
+string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (runes: []rune) {
 	n := rune_count_in_string(s)
 
 	runes = make([]rune, n, allocator)
@@ -147,7 +152,7 @@ string_to_runes :: proc(s: string, allocator := context.allocator) -> (runes: []
 	return
 }
 
-runes_to_string :: proc(runes: []rune, allocator := context.allocator) -> string {
+runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) -> string {
 	byte_count := 0
 	for r in runes {
 		_, w := encode_rune(r)
@@ -171,10 +176,10 @@ decode_last_rune :: proc{
 	decode_last_rune_in_bytes,
 }
 
-decode_last_rune_in_string :: #force_inline proc(s: string) -> (rune, int) {
+decode_last_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
 	return decode_last_rune_in_bytes(transmute([]u8)s)
 }
-decode_last_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
+decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
 	r: rune
 	size: int
 	start, end, limit: int
@@ -206,7 +211,7 @@ decode_last_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
 	return r, size
 }
 
-rune_at_pos :: proc(s: string, pos: int) -> rune {
+rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune {
 	if pos < 0 {
 		return RUNE_ERROR
 	}
@@ -221,7 +226,7 @@ rune_at_pos :: proc(s: string, pos: int) -> rune {
 	return RUNE_ERROR
 }
 
-rune_string_at_pos :: proc(s: string, pos: int) -> string {
+rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string {
 	if pos < 0 {
 		return ""
 	}
@@ -237,14 +242,14 @@ rune_string_at_pos :: proc(s: string, pos: int) -> string {
 	return ""
 }
 
-rune_at :: proc(s: string, byte_index: int) -> rune {
+rune_at :: proc "contextless" (s: string, byte_index: int) -> rune {
 	r, _ := decode_rune_in_string(s[byte_index:])
 	return r
 }
 
 // Returns the byte position of rune at position pos in s with an optional start byte position.
 // Returns -1 if it runs out of the string.
-rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
+rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int {
 	if pos < 0 {
 		return -1
 	}
@@ -259,7 +264,7 @@ rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
 	return -1
 }
 
-valid_rune :: proc(r: rune) -> bool {
+valid_rune :: proc "contextless" (r: rune) -> bool {
 	if r < 0 {
 		return false
 	} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -270,7 +275,7 @@ valid_rune :: proc(r: rune) -> bool {
 	return true
 }
 
-valid_string :: proc(s: string) -> bool {
+valid_string :: proc "contextless" (s: string) -> bool {
 	n := len(s)
 	for i := 0; i < n; {
 		si := s[i]
@@ -303,7 +308,7 @@ valid_string :: proc(s: string) -> bool {
 	return true
 }
 
-rune_start :: #force_inline proc(b: u8) -> bool {
+rune_start :: #force_inline proc "contextless" (b: u8) -> bool {
 	return b&0xc0 != 0x80
 }
 
@@ -315,7 +320,7 @@ rune_count :: proc{
 rune_count_in_string :: #force_inline proc(s: string) -> int {
 	return rune_count_in_bytes(transmute([]u8)s)
 }
-rune_count_in_bytes :: proc(s: []u8) -> int {
+rune_count_in_bytes :: proc "contextless" (s: []u8) -> int {
 	count := 0
 	n := len(s)
 
@@ -354,7 +359,7 @@ rune_count_in_bytes :: proc(s: []u8) -> int {
 }
 
 
-rune_size :: proc(r: rune) -> int {
+rune_size :: proc "contextless" (r: rune) -> int {
 	switch {
 	case r < 0:          return -1
 	case r <= 1<<7  - 1: return 1
@@ -375,7 +380,7 @@ full_rune :: proc{
 
 // full_rune_in_bytes reports if the bytes in b begin with a full utf-8 encoding of a rune or not
 // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
-full_rune_in_bytes :: proc(b: []byte) -> bool {
+full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool {
 	n := len(b)
 	if n == 0 {
 		return false
@@ -395,7 +400,7 @@ full_rune_in_bytes :: proc(b: []byte) -> bool {
 
 // full_rune_in_string reports if the bytes in s begin with a full utf-8 encoding of a rune or not
 // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
-full_rune_in_string :: proc(s: string) -> bool {
+full_rune_in_string :: proc "contextless" (s: string) -> bool {
 	return full_rune_in_bytes(transmute([]byte)s)
 }
 

+ 2 - 0
examples/all/all_vendor.odin

@@ -24,6 +24,7 @@ import vk         "vendor:vulkan"
 
 import NS         "vendor:darwin/Foundation"
 import MTL        "vendor:darwin/Metal"
+import MTK        "vendor:darwin/MetalKit"
 import CA         "vendor:darwin/QuartzCore"
 
 // NOTE(bill): only one can be checked at a time
@@ -53,6 +54,7 @@ _ :: vk
 
 _ :: NS
 _ :: MTL
+_ :: MTK
 _ :: CA
 
 _ :: lua_5_4

+ 1 - 3
examples/demo/demo.odin

@@ -2145,10 +2145,8 @@ or_return_operator :: proc() {
 			return -345 * z, zerr
 		}
 
-		// If the other return values need to be set depending on what the end value is,
-		// the 'defer if' idiom is can be used
 		defer if err != nil {
-			n = -1
+			fmt.println("Error in", #procedure, ":" , err)
 		}
 
 		n = 123

+ 21 - 3
src/build_settings.cpp

@@ -1538,13 +1538,23 @@ gb_internal bool init_build_paths(String init_filename) {
 	} else if (is_arch_wasm()) {
 		output_extension = STR_LIT("wasm");
 	} else if (build_context.build_mode == BuildMode_Executable) {
-		// By default use a .bin executable extension.
-		output_extension = STR_LIT("bin");
+		// By default use no executable extension.
+		output_extension = make_string(nullptr, 0);
+		String const single_file_extension = str_lit(".odin");
 
 		if (build_context.metrics.os == TargetOs_windows) {
 			output_extension = STR_LIT("exe");
 		} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
-			output_extension = make_string(nullptr, 0);
+			// Do nothing: we don't want the .bin extension
+			// when cross compiling
+		} else if (path_is_directory(last_path_element(bc->build_paths[BuildPath_Main_Package].basename))) {
+			// Add .bin extension to avoid collision
+			// with package directory name
+			output_extension = STR_LIT("bin");
+		} else if (string_ends_with(init_filename, single_file_extension) && path_is_directory(remove_extension_from_path(init_filename))) {
+			// Add bin extension if compiling single-file package
+			// with same output name as a directory
+			output_extension = STR_LIT("bin");
 		}
 	} else if (build_context.build_mode == BuildMode_DynamicLibrary) {
 		// By default use a .so shared library extension.
@@ -1656,6 +1666,14 @@ gb_internal bool init_build_paths(String init_filename) {
 		return false;
 	}
 
+	if (!write_directory(bc->build_paths[BuildPath_Output].basename)) {
+		String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
+		defer (gb_free(ha, output_file.text));
+		gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
+		return false;
+	}
+
+
 	if (bc->target_features_string.len != 0) {
 		enable_target_feature({}, bc->target_features_string);
 	}

+ 83 - 0
src/check_builtin.cpp

@@ -4843,6 +4843,89 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 		}
 		operand->mode = Addressing_Type;
 		break;
+	case BuiltinProc_type_merge:
+		{
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+
+			Operand x = {};
+			Operand y = {};
+			check_expr_or_type(c, &x, ce->args[0]);
+			check_expr_or_type(c, &y, ce->args[1]);
+			if (x.mode != Addressing_Type) {
+				error(x.expr, "Expected a type for '%.*s'", LIT(builtin_name));
+				return false;
+			}
+			if (y.mode != Addressing_Type) {
+				error(y.expr, "Expected a type for '%.*s'", LIT(builtin_name));
+				return false;
+			}
+
+			if (is_type_polymorphic(x.type)) {
+				gbString t = type_to_string(x.type);
+				error(x.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+			if (is_type_polymorphic(y.type)) {
+				gbString t = type_to_string(y.type);
+				error(y.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+			if (!is_type_union(x.type)) {
+				gbString t = type_to_string(x.type);
+				error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+			if (!is_type_union(y.type)) {
+				gbString t = type_to_string(y.type);
+				error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+			Type *ux = base_type(x.type);
+			Type *uy = base_type(y.type);
+			GB_ASSERT(ux->kind == Type_Union);
+			GB_ASSERT(uy->kind == Type_Union);
+
+			i64 custom_align = gb_max(ux->Union.custom_align, uy->Union.custom_align);
+			if (ux->Union.kind != uy->Union.kind) {
+				error(x.expr, "Union kinds must match, got %s vs %s", union_type_kind_strings[ux->Union.kind], union_type_kind_strings[uy->Union.kind]);
+			}
+
+			Type *merged_union = alloc_type_union();
+
+			merged_union->Union.node = call;
+			merged_union->Union.scope = create_scope(c->info, c->scope);
+			merged_union->Union.kind = ux->Union.kind;
+			merged_union->Union.custom_align = custom_align;
+
+			auto variants = array_make<Type *>(permanent_allocator(), 0, ux->Union.variants.count+uy->Union.variants.count);
+			for (Type *t : ux->Union.variants) {
+				array_add(&variants, t);
+			}
+			for (Type *t : uy->Union.variants) {
+				bool ok = true;
+				for (Type *other_t : ux->Union.variants) {
+					if (are_types_identical(other_t, t)) {
+						ok = false;
+						break;
+					}
+				}
+				if (ok) {
+					array_add(&variants, t);
+				}
+
+			}
+			merged_union->Union.variants = slice_from_array(variants);
+
+			operand->mode = Addressing_Type;
+			operand->type = merged_union;
+		}
+		break;
+
 
 	case BuiltinProc_type_is_boolean:
 	case BuiltinProc_type_is_integer:

+ 14 - 10
src/check_decl.cpp

@@ -43,14 +43,20 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
 	}
 
 	if (operand->mode == Addressing_Type) {
-		if (e->type != nullptr && is_type_typeid(e->type)) {
+		if (e->type != nullptr && is_type_typeid(e->type) && !is_type_polymorphic(operand->type)) {
 			add_type_info_type(ctx, operand->type);
 			add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
 			return e->type;
 		} else {
+			ERROR_BLOCK();
+
 			gbString t = type_to_string(operand->type);
 			defer (gb_string_free(t));
-			error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
+			if (is_type_polymorphic(operand->type)) {
+				error(operand->expr, "Cannot assign a non-specialized polymorphic type '%s' to variable '%.*s'", t, LIT(e->token.string));
+			} else {
+				error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
+			}
 			if (e->type == nullptr) {
 				error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string));
 			}
@@ -59,20 +65,17 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
 		}
 	}
 
-
-
 	if (e->type == nullptr) {
 
 		// NOTE(bill): Use the type of the operand
 		Type *t = operand->type;
 		if (is_type_untyped(t)) {
-			if (t == t_invalid || is_type_untyped_nil(t)) {
-				error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
+			if (is_type_untyped_uninit(t)) {
+				error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
 				e->type = t_invalid;
 				return nullptr;
-			}
-			if (t == t_invalid || is_type_untyped_undef(t)) {
-				error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
+			} else if (t == t_invalid || is_type_untyped_nil(t)) {
+				error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
 				e->type = t_invalid;
 				return nullptr;
 			}
@@ -119,7 +122,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
 	// an extra allocation
 	TEMPORARY_ALLOCATOR_GUARD();
 	auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
-	check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
+	check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, UnpackFlag_AllowOk|UnpackFlag_AllowUndef);
 
 	isize rhs_count = operands.count;
 	isize max = gb_min(lhs_count, rhs_count);
@@ -947,6 +950,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 
 	if (ac.require_declaration) {
 		e->flags |= EntityFlag_Require;
+		pl->inlining = ProcInlining_no_inline;
 	}
 
 

+ 48 - 29
src/check_expr.cpp

@@ -646,11 +646,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
 	Type *src = base_type(s);
 	Type *dst = base_type(type);
 
-	if (is_type_untyped_undef(src)) {
-		if (type_has_undef(dst)) {
-			return 1;
-		}
-		return -1;
+	if (is_type_untyped_uninit(src)) {
+		return 1;
 	}
 
 	if (is_type_untyped_nil(src)) {
@@ -993,13 +990,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
 	if (is_type_untyped(operand->type)) {
 		Type *target_type = type;
 		if (type == nullptr || is_type_any(type)) {
-			if (type == nullptr && is_type_untyped_nil(operand->type)) {
-				error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
+			if (type == nullptr && is_type_untyped_uninit(operand->type)) {
+				error(operand->expr, "Use of --- in %.*s", LIT(context_name));
 				operand->mode = Addressing_Invalid;
 				return;
 			}
-			if (type == nullptr && is_type_untyped_undef(operand->type)) {
-				error(operand->expr, "Use of --- in %.*s", LIT(context_name));
+			if (type == nullptr && is_type_untyped_nil(operand->type)) {
+				error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
 				operand->mode = Addressing_Invalid;
 				return;
 			}
@@ -1067,7 +1064,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
 
 	if (check_is_assignable_to(c, operand, type)) {
 		if (operand->mode == Addressing_Type && is_type_typeid(type)) {
-			add_type_info_type(c, operand->type);
+		 	add_type_info_type(c, operand->type);
 			add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
 		}
 	} else {
@@ -3969,7 +3966,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 		
 
 	case Type_Union:
-		if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
+		if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) {
 			TEMPORARY_ALLOCATOR_GUARD();
 
 			isize count = t->Union.variants.count;
@@ -4036,8 +4033,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 				error_line("\n\n");
 
 				return;
-			} else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
-				target_type = t_untyped_undef;
+			} else if (is_type_untyped_uninit(operand->type)) {
+				target_type = t_untyped_uninit;
 			} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
 				begin_error_block();
 				defer (end_error_block());
@@ -4070,8 +4067,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 
 
 	default:
-		if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
-			target_type = t_untyped_undef;
+		if (is_type_untyped_uninit(operand->type)) {
+			target_type = t_untyped_uninit;
 		} else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) {
 			target_type = t_untyped_nil;
 		} else {
@@ -4083,8 +4080,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 	}
 	
 	if (is_type_any(target_type) && is_type_untyped(operand->type)) {
-		if (is_type_untyped_nil(operand->type) && is_type_untyped_undef(operand->type)) {
-				
+		if (is_type_untyped_nil(operand->type) && is_type_untyped_uninit(operand->type)) {
+
 		} else {
 			target_type = default_type(operand->type);
 		}
@@ -5144,8 +5141,20 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand>
 }
 
 
+typedef u32 UnpackFlags;
+enum UnpackFlag : u32 {
+	UnpackFlag_None       = 0,
+	UnpackFlag_AllowOk    = 1<<0,
+	UnpackFlag_IsVariadic = 1<<1,
+	UnpackFlag_AllowUndef = 1<<2,
+};
+
+
+gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, UnpackFlags flags) {
+	bool allow_ok    = (flags & UnpackFlag_AllowOk) != 0;
+	bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
+	bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
 
-gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, bool allow_ok, bool is_variadic) {
 	bool optional_ok = false;
 	isize tuple_index = 0;
 	for_array(i, rhs) {
@@ -5184,7 +5193,16 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
 			}
 		}
 
-		check_expr_base(c, &o, rhs[i], type_hint);
+		Ast *rhs_expr = unparen_expr(rhs[i]);
+		if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Uninit) {
+			// NOTE(bill): Just handle this very specific logic here
+			o.type = t_untyped_uninit;
+			o.mode = Addressing_Value;
+			o.expr = rhs[i];
+			add_type_and_value(c, rhs[i], o.mode, o.type, o.value);
+		} else {
+			check_expr_base(c, &o, rhs[i], type_hint);
+		}
 		if (o.mode == Addressing_NoValue) {
 			error_operand_no_value(&o);
 			o.mode = Addressing_Invalid;
@@ -5968,7 +5986,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
 			lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
 		}
 		if (operand->mode != Addressing_ProcGroup) {
-			check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic);
+			check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
 		}
 	}
 
@@ -6025,7 +6043,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
 			isize lhs_count = -1;
 			bool is_variadic = false;
 			lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
-			check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic);
+			check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
 
 			CallArgumentData data = {};
 			CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data);
@@ -6101,7 +6119,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
 		}
 
 
-		check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, false);
+		check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None);
 
 		if (lhs != nullptr) {
 			gb_free(heap_allocator(), lhs);
@@ -6462,7 +6480,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
 				lhs_count = params->variables.count;
 			}
 
-			check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false);
+			check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, UnpackFlag_None);
 		}
 
 	}
@@ -7146,11 +7164,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
 }
 
 gb_internal bool ternary_compare_types(Type *x, Type *y) {
-	if (is_type_untyped_undef(x) && type_has_undef(y)) {
+	if (is_type_untyped_uninit(x)) {
 		return true;
 	} else if (is_type_untyped_nil(x) && type_has_nil(y)) {
 		return true;
-	} else if (is_type_untyped_undef(y) && type_has_undef(x)) {
+	} else if (is_type_untyped_uninit(y)) {
 		return true;
 	} else if (is_type_untyped_nil(y) && type_has_nil(x)) {
 		return true;
@@ -7687,7 +7705,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
 	}
 
 	o->type = x.type;
-	if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) {
+	if (is_type_untyped_nil(o->type) || is_type_untyped_uninit(o->type)) {
 		o->type = y.type;
 	}
 
@@ -9580,9 +9598,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
 		check_ident(c, o, node, nullptr, type_hint, false);
 	case_end;
 
-	case_ast_node(u, Undef, node);
+	case_ast_node(u, Uninit, node);
 		o->mode = Addressing_Value;
-		o->type = t_untyped_undef;
+		o->type = t_untyped_uninit;
+		error(node, "Use of --- outside of variable declaration");
 	case_end;
 
 
@@ -10145,7 +10164,7 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
 		str = string_append_string(str, bd->name.string);
 	case_end;
 
-	case_ast_node(ud, Undef, node);
+	case_ast_node(ud, Uninit, node);
 		str = gb_string_appendc(str, "---");
 	case_end;
 

+ 26 - 2
src/check_stmt.cpp

@@ -402,6 +402,12 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
 
 	Type *assignment_type = lhs->type;
 
+	if (rhs->mode == Addressing_Type && is_type_polymorphic(rhs->type)) {
+		gbString t = type_to_string(rhs->type);
+		error(rhs->expr, "Invalid use of a non-specialized polymorphic type '%s'", t);
+		gb_string_free(t);
+	}
+
 	switch (lhs->mode) {
 	case Addressing_Invalid:
 		return nullptr;
@@ -1455,6 +1461,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 	bool is_map = false;
 	bool use_by_reference_for_value = false;
 	bool is_soa = false;
+	bool is_reverse = rs->reverse;
 
 	Ast *expr = unparen_expr(rs->expr);
 
@@ -1470,6 +1477,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 		}
 		array_add(&vals, x.type);
 		array_add(&vals, t_int);
+
+		if (is_reverse) {
+			error(node, "#reverse for is not supported with ranges, prefer an explicit for loop with init, condition, and post arguments");
+		}
 	} else {
 		Operand operand = {Addressing_Invalid};
 		check_expr_base(ctx, &operand, expr, nullptr);
@@ -1482,6 +1493,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 				gb_string_free(t);
 				goto skip_expr_range_stmt;
 			} else {
+				if (is_reverse) {
+					error(node, "#reverse for is not supported for enum types");
+				}
 				array_add(&vals, operand.type);
 				array_add(&vals, t_int);
 				add_type_info_type(ctx, operand.type);
@@ -1495,7 +1509,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 				if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
 					array_add(&vals, t_rune);
 					array_add(&vals, t_int);
-					add_package_dependency(ctx, "runtime", "string_decode_rune");
+					if (is_reverse) {
+						add_package_dependency(ctx, "runtime", "string_decode_last_rune");
+					} else {
+						add_package_dependency(ctx, "runtime", "string_decode_rune");
+					}
 				}
 				break;
 
@@ -1528,6 +1546,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 				is_map = true;
 				array_add(&vals, t->Map.key);
 				array_add(&vals, t->Map.value);
+				if (is_reverse) {
+					error(node, "#reverse for is not supported for map types, as maps are unordered");
+				}
 				break;
 
 			case Type_Tuple:
@@ -1564,6 +1585,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 						break;
 					}
 
+					if (is_reverse) {
+						error(node, "#reverse for is not supported for multiple return valued parameters");
+					}
 				}
 				break;
 
@@ -2170,7 +2194,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
 	auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
 	defer (array_free(&operands));
 
-	check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, true, false);
+	check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
 
 	if (result_count == 0 && rs->results.count > 0) {
 		error(rs->results[0], "No return values expected");

+ 3 - 3
src/check_type.cpp

@@ -135,7 +135,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
 			type = t_invalid;
 		}
 		if (is_type_untyped(type)) {
-			if (is_type_untyped_undef(type)) {
+			if (is_type_untyped_uninit(type)) {
 				error(params[i], "Cannot determine parameter type from ---");
 			} else {
 				error(params[i], "Cannot determine parameter type from a nil");
@@ -473,7 +473,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
 				type = t_invalid;
 			}
 			if (is_type_untyped(type)) {
-				if (is_type_untyped_undef(type)) {
+				if (is_type_untyped_uninit(type)) {
 					error(params[i], "Cannot determine parameter type from ---");
 				} else {
 					error(params[i], "Cannot determine parameter type from a nil");
@@ -1528,7 +1528,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
 			type = t_invalid;
 		}
 		if (is_type_untyped(type)) {
-			if (is_type_untyped_undef(type)) {
+			if (is_type_untyped_uninit(type)) {
 				error(param, "Cannot determine parameter type from ---");
 			} else {
 				error(param, "Cannot determine parameter type from a nil");

+ 30 - 5
src/checker.cpp

@@ -27,8 +27,8 @@ gb_internal bool is_operand_value(Operand o) {
 gb_internal bool is_operand_nil(Operand o) {
 	return o.mode == Addressing_Value && o.type == t_untyped_nil;
 }
-gb_internal bool is_operand_undef(Operand o) {
-	return o.mode == Addressing_Value && o.type == t_untyped_undef;
+gb_internal bool is_operand_uninit(Operand o) {
+	return o.mode == Addressing_Value && o.type == t_untyped_uninit;
 }
 
 gb_internal bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) {
@@ -3469,6 +3469,19 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
 	StringSet set = {};
 	defer (string_set_destroy(&set));
 
+	bool is_runtime = false;
+	if (c->scope && c->scope->file && (c->scope->flags & ScopeFlag_File) &&
+	    c->scope->file->pkg &&
+	    c->scope->file->pkg->kind == Package_Runtime) {
+		is_runtime = true;
+	} else if (c->scope && c->scope->parent &&
+		(c->scope->flags & ScopeFlag_Proc) &&
+		(c->scope->parent->flags & ScopeFlag_File) &&
+		c->scope->parent->file->pkg &&
+		c->scope->parent->file->pkg->kind == Package_Runtime) {
+		is_runtime = true;
+	}
+
 	for_array(i, attributes) {
 		Ast *attr = attributes[i];
 		if (attr->kind != Ast_Attribute) continue;
@@ -3504,9 +3517,14 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
 				continue;
 			}
 
+			if (name == "builtin" && is_runtime) {
+				continue;
+			}
+
 			if (!proc(c, elem, name, value, ac)) {
 				if (!build_context.ignore_unknown_attributes) {
 					error(elem, "Unknown attribute element name '%.*s'", LIT(name));
+					error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n");
 				}
 			}
 		}
@@ -3663,9 +3681,9 @@ gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array<
 					error(value, "'builtin' cannot have a field value");
 				}
 				// Remove the builtin tag
-				attr->Attribute.elems[k] = attr->Attribute.elems[attr->Attribute.elems.count-1];
-				attr->Attribute.elems.count -= 1;
-				k--;
+				// attr->Attribute.elems[k] = attr->Attribute.elems[attr->Attribute.elems.count-1];
+				// attr->Attribute.elems.count -= 1;
+				// k--;
 
 				mutex_unlock(&ctx->info->builtin_mutex);
 			}
@@ -3874,6 +3892,13 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 						cc = ProcCC_CDecl;
 						if (c->foreign_context.default_cc > 0) {
 							cc = c->foreign_context.default_cc;
+						} else if (is_arch_wasm()) {
+							begin_error_block();
+							error(init, "For wasm related targets, it is required that you either define the"
+							            " @(default_calling_convention=<string>) on the foreign block or"
+							            " explicitly assign it on the procedure signature");
+							error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
+							end_error_block();
 						}
 					}
 					e->Procedure.link_prefix = c->foreign_context.link_prefix;

+ 2 - 0
src/checker_builtin_procs.hpp

@@ -203,6 +203,7 @@ BuiltinProc__type_begin,
 	BuiltinProc_type_elem_type,
 
 	BuiltinProc_type_convert_variants_to_pointers,
+	BuiltinProc_type_merge,
 
 BuiltinProc__type_simple_boolean_begin,
 	BuiltinProc_type_is_boolean,
@@ -501,6 +502,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("type_core_type"),            1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_elem_type"),            1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("type_merge"),                2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 
 	{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_is_boolean"),           1, false, Expr_Expr, BuiltinProcPkg_intrinsics},

+ 68 - 12
src/docs_writer.cpp

@@ -30,6 +30,7 @@ struct OdinDocWriter {
 	PtrMap<AstPackage *, OdinDocPkgIndex>    pkg_cache;
 	PtrMap<Entity *,     OdinDocEntityIndex> entity_cache;
 	PtrMap<Type *,       OdinDocTypeIndex>   type_cache;
+	PtrMap<Type *,       Type *>             stable_type_cache;
 
 	OdinDocWriterItemTracker<OdinDocFile>   files;
 	OdinDocWriterItemTracker<OdinDocPkg>    pkgs;
@@ -51,6 +52,7 @@ gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *
 
 
 gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
+	debugf("odin_doc_writer_prepare\n");
 	w->state = OdinDocWriterState_Preparing;
 
 	string_map_init(&w->string_cache);
@@ -59,6 +61,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
 	map_init(&w->pkg_cache);
 	map_init(&w->entity_cache);
 	map_init(&w->type_cache);
+	map_init(&w->stable_type_cache);
 
 	odin_doc_writer_item_tracker_init(&w->files,    1);
 	odin_doc_writer_item_tracker_init(&w->pkgs,     1);
@@ -70,6 +73,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
 
 
 gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
+	debugf("odin_doc_writer_destroy\n");
 	gb_free(heap_allocator(), w->data);
 
 	string_map_destroy(&w->string_cache);
@@ -77,6 +81,7 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
 	map_destroy(&w->pkg_cache);
 	map_destroy(&w->entity_cache);
 	map_destroy(&w->type_cache);
+	map_destroy(&w->stable_type_cache);
 }
 
 
@@ -102,6 +107,7 @@ gb_internal isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
 }
 
 gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) {
+	debugf("odin_doc_writer_start_writing\n");
 	w->state = OdinDocWriterState_Writing;
 
 	string_map_clear(&w->string_cache);
@@ -138,6 +144,7 @@ gb_internal void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocW
 
 
 gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) {
+	debugf("odin_doc_writer_end_writing\n");
 	OdinDocHeader *h = w->header;
 
 	gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
@@ -471,22 +478,60 @@ gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDo
 	return odin_write_item_as_slice(w, index);
 }
 
+
+
 gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
 	if (type == nullptr) {
 		return 0;
 	}
+
+	// Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself
+	// if (mapped_type && *mapped_type) {
+	// 	type = *mapped_type;
+	// }
+
 	OdinDocTypeIndex *found = map_get(&w->type_cache, type);
 	if (found) {
 		return *found;
 	}
 	for (auto const &entry : w->type_cache) {
 		// NOTE(bill): THIS IS SLOW
-		Type *other = entry.key;
-		if (are_types_identical_unique_tuples(type, other)) {
-			OdinDocTypeIndex index = entry.value;
-			map_set(&w->type_cache, type, index);
-			return index;
+		Type *x = type;
+		Type *y = entry.key;
+
+		if (x == y) {
+			goto do_set;
+		}
+
+		if (!x | !y) {
+			continue;
+		}
+
+		if (x->kind == Type_Named) {
+			Entity *e = x->Named.type_name;
+			if (e->TypeName.is_type_alias) {
+				x = x->Named.base;
+			}
+		}
+		if (y->kind == Type_Named) {
+			Entity *e = y->Named.type_name;
+			if (e->TypeName.is_type_alias) {
+				y = y->Named.base;
+			}
 		}
+		if (x->kind != y->kind) {
+			continue;
+		}
+
+		if (!are_types_identical_internal(x, y, true)) {
+			continue;
+		}
+
+	do_set:
+		OdinDocTypeIndex index = entry.value;
+		map_set(&w->type_cache, type, index);
+		map_set(&w->stable_type_cache, type, entry.key);
+		return index;
 	}
 
 
@@ -495,6 +540,7 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
 	OdinDocTypeIndex type_index = 0;
 	type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
 	map_set(&w->type_cache, type, type_index);
+	map_set(&w->stable_type_cache, type, type);
 
 	switch (type->kind) {
 	case Type_Basic:
@@ -856,13 +902,12 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
 		break;
 	}
 
-	if (e->flags & EntityFlag_Param) {
-		if (e->flags & EntityFlag_Using)      { flags |= OdinDocEntityFlag_Param_Using;    }
-		if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const;    }
-		if (e->flags & EntityFlag_Ellipsis)   { flags |= OdinDocEntityFlag_Param_Ellipsis; }
-		if (e->flags & EntityFlag_NoAlias)    { flags |= OdinDocEntityFlag_Param_NoAlias;  }
-		if (e->flags & EntityFlag_AnyInt)     { flags |= OdinDocEntityFlag_Param_AnyInt;   }
-	}
+	if (e->flags & EntityFlag_Using)      { flags |= OdinDocEntityFlag_Param_Using;    }
+	if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const;    }
+	if (e->flags & EntityFlag_Ellipsis)   { flags |= OdinDocEntityFlag_Param_Ellipsis; }
+	if (e->flags & EntityFlag_NoAlias)    { flags |= OdinDocEntityFlag_Param_NoAlias;  }
+	if (e->flags & EntityFlag_AnyInt)     { flags |= OdinDocEntityFlag_Param_AnyInt;   }
+
 	if (e->scope && (e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) && !is_entity_exported(e)) {
 		flags |= OdinDocEntityFlag_Private;
 	}
@@ -910,6 +955,8 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
 }
 
 gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
+	debugf("odin_doc_update_entities %s\n", w->state ? "preparing" : "writing");
+
 	{
 		// NOTE(bill): Double pass, just in case entities are created on odin_doc_type
 		auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
@@ -974,6 +1021,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
 		return {};
 	}
 
+	debugf("odin_doc_add_pkg_entries %s -> package %.*s\n", w->state ? "preparing" : "writing", LIT(pkg->name));
+
 	auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count);
 	defer (array_free(&entries));
 
@@ -1017,6 +1066,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
 
 
 gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
+	debugf("odin_doc_write_docs %s", w->state ? "preparing" : "writing");
+
 	auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
 	defer (array_free(&pkgs));
 	for (auto const &entry : w->info->packages) {
@@ -1032,6 +1083,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
 		}
 	}
 
+	debugf("odin_doc_update_entities sort pkgs %s\n", w->state ? "preparing" : "writing");
 	gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
 
 	for_array(i, pkgs) {
@@ -1092,6 +1144,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
 
 
 gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
+	debugf("odin_doc_write_to_file %s\n", filename);
 	gbFile f = {};
 	gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
 	if (err != gbFileError_None) {
@@ -1102,6 +1155,7 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename)
 	defer (gb_file_close(&f));
 	if (gb_file_write(&f, w->data, w->data_len)) {
 		err = gb_file_truncate(&f, w->data_len);
+		debugf("Wrote .odin-doc file to: %s\n", filename);
 		gb_printf("Wrote .odin-doc file to: %s\n", filename);
 	}
 }
@@ -1112,6 +1166,8 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
 	defer (odin_doc_writer_destroy(w));
 	w->info = info;
 
+	debugf("odin_doc_write %s\n", filename);
+
 	odin_doc_writer_prepare(w);
 	odin_doc_write_docs(w);
 

+ 27 - 10
src/llvm_abi.cpp

@@ -1179,7 +1179,11 @@ namespace lbAbiArm64 {
 			if (is_register(type)) {
 				args[i] = non_struct(c, type);
 			} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
-				args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
+				if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
+					args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
+				} else {
+					args[i] = lb_arg_type_indirect(type, nullptr);;
+				}
 			} else {
 				i64 size = lb_sizeof(type);
 				if (size <= 16) {
@@ -1213,7 +1217,7 @@ namespace lbAbiWasm {
 		            The approach taken optimizes for passing things in multiple
 		            registers/arguments if possible rather than by pointer.
 	*/
-	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
+	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
 	gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
 
 	enum {MAX_DIRECT_STRUCT_SIZE = 32};
@@ -1221,7 +1225,7 @@ namespace lbAbiWasm {
 	gb_internal LB_ABI_INFO(abi_info) {
 		lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
 		ft->ctx = c;
-		ft->args = compute_arg_types(c, arg_types, arg_count);
+		ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
 		ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
 		ft->calling_convention = calling_convention;
 		return ft;
@@ -1258,13 +1262,26 @@ namespace lbAbiWasm {
 		return false;
 	}
 
-	gb_internal bool type_can_be_direct(LLVMTypeRef type) {
+	gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
 		LLVMTypeKind kind = LLVMGetTypeKind(type);
 		i64 sz = lb_sizeof(type);
 		if (sz == 0) {
 			return false;
 		}
-		if (sz <= MAX_DIRECT_STRUCT_SIZE) {
+		if (calling_convention == ProcCC_CDecl) {
+			// WASM Basic C ABI:
+			// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md#function-signatures
+			if (kind == LLVMArrayTypeKind) {
+				return false;
+			} else if (kind == LLVMStructTypeKind) {
+				unsigned count = LLVMCountStructElementTypes(type);
+				if (count == 1) {
+					return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
+				}
+			} else if (is_basic_register_type(type)) {
+				return true;
+			}
+		} else if (sz <= MAX_DIRECT_STRUCT_SIZE) {
 			if (kind == LLVMArrayTypeKind) {
 				if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
 					return true;
@@ -1284,7 +1301,7 @@ namespace lbAbiWasm {
 		return false;
 	}
 
-	gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
+	gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
 		LLVMTypeKind kind = LLVMGetTypeKind(type);
 		GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
 		
@@ -1292,21 +1309,21 @@ namespace lbAbiWasm {
 		if (sz == 0) {
 			return lb_arg_type_ignore(type);
 		}
-		if (type_can_be_direct(type)) {
+		if (type_can_be_direct(type, calling_convention)) {
 			return lb_arg_type_direct(type);
 		}
 		return lb_arg_type_indirect(type, nullptr);
 	}
 	
 
-	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
+	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
 		auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
 
 		for (unsigned i = 0; i < arg_count; i++) {
 			LLVMTypeRef t = arg_types[i];
 			LLVMTypeKind kind = LLVMGetTypeKind(t);
 			if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
-				args[i] = is_struct(c, t);
+				args[i] = is_struct(c, t, calling_convention);
 			} else {
 				args[i] = non_struct(c, t, false);
 			}
@@ -1318,7 +1335,7 @@ namespace lbAbiWasm {
 		if (!return_is_defined) {
 			return lb_arg_type_direct(LLVMVoidTypeInContext(c));
 		} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
-			if (type_can_be_direct(return_type)) {
+			if (type_can_be_direct(return_type, ft->calling_convention)) {
 				return lb_arg_type_direct(return_type);
 			}
 

+ 26 - 15
src/llvm_backend.cpp

@@ -720,6 +720,7 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
 	lbBlock *check_grow_block = lb_create_block(p, "check-grow");
 	lbBlock *grow_fail_block  = lb_create_block(p, "grow-fail");
 	lbBlock *insert_block     = lb_create_block(p, "insert");
+	lbBlock *rehash_block     = lb_create_block(p, "rehash");
 
 	lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, found_ptr), found_block, check_grow_block);
 	lb_start_block(p, found_block);
@@ -737,12 +738,19 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
 		args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
 		args[1] = map_info;
 		args[2] = lb_emit_load(p, location_ptr);
-		lbValue grow_err = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args);
+		lbValue grow_err_and_has_grown = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args);
+		lbValue grow_err = lb_emit_struct_ev(p, grow_err_and_has_grown, 0);
+		lbValue has_grown = lb_emit_struct_ev(p, grow_err_and_has_grown, 1);
 
 		lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, grow_err), grow_fail_block, insert_block);
 
 		lb_start_block(p, grow_fail_block);
 		LLVMBuildRet(p->builder, LLVMConstNull(lb_type(m, t_rawptr)));
+
+		lb_emit_if(p, has_grown, grow_fail_block, rehash_block);
+		lb_start_block(p, rehash_block);
+		lbValue key = lb_emit_load(p, key_ptr);
+		hash = lb_gen_map_key_hash(p, map_ptr, key, nullptr);
 	}
 
 	lb_start_block(p, insert_block);
@@ -916,7 +924,7 @@ gb_internal lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
 	return hashed_key;
 }
 
-gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
+gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_) {
 	TEMPORARY_ALLOCATOR_GUARD();
 
 	lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
@@ -924,13 +932,22 @@ gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_t
 
 	if (key_ptr_) *key_ptr_ = key_ptr;
 
+	Type* key_type = base_type(type_deref(map_ptr.type))->Map.key;
+
 	lbValue hashed_key = lb_const_hash(p->module, key, key_type);
 	if (hashed_key.value == nullptr) {
 		lbValue hasher = lb_hasher_proc_for_type(p->module, key_type);
 
+		lbValue seed = {};
+		{
+			auto args = array_make<lbValue>(temporary_allocator(), 1);
+			args[0] = lb_map_data_uintptr(p, lb_emit_load(p, map_ptr));
+			seed = lb_emit_runtime_call(p, "map_seed_from_map_data", args);
+		}
+
 		auto args = array_make<lbValue>(temporary_allocator(), 2);
 		args[0] = key_ptr;
-		args[1] = lb_const_int(p->module, t_uintptr, 0);
+		args[1] = seed;
 		hashed_key = lb_emit_call(p, hasher, args);
 	}
 
@@ -945,7 +962,7 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons
 
 	lbValue ptr = {};
 	lbValue key_ptr = {};
-	lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
+	lbValue hash = lb_gen_map_key_hash(p, map_ptr, key, &key_ptr);
 
 	if (build_context.dynamic_map_calls) {
 		auto args = array_make<lbValue>(temporary_allocator(), 4);
@@ -976,7 +993,7 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
 	GB_ASSERT(map_type->kind == Type_Map);
 
 	lbValue key_ptr = {};
-	lbValue hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
+	lbValue hash = lb_gen_map_key_hash(p, map_ptr, map_key, &key_ptr);
 
 	lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
 	lbValue value_ptr = lb_address_from_load_or_generate_local(p, v);
@@ -1129,12 +1146,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
 			lbValue init = lb_build_expr(p, init_expr);
 			if (init.value == nullptr) {
 				LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
-				if (is_type_untyped_undef(init.type)) {
-					// LLVMSetInitializer(var.var.value, LLVMGetUndef(global_type));
-					LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
-					var.is_initialized = true;
-					continue;
-				} else if (is_type_untyped_nil(init.type)) {
+				if (is_type_untyped_nil(init.type)) {
 					LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
 					var.is_initialized = true;
 					continue;
@@ -1365,7 +1377,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
 
 gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default) {
 	LLVMPassManagerRef pass_manager = module->function_pass_managers[pass_manager_kind];
-	lb_run_function_pass_manager(pass_manager, p);
+	lb_run_function_pass_manager(pass_manager, p, pass_manager_kind);
 }
 
 gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
@@ -1899,7 +1911,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
 		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
 	}
 
-	lb_run_function_pass_manager(default_function_pass_manager, p);
+	lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
 	return p;
 }
 
@@ -2363,8 +2375,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 					}
 				}
 			}
-			if (!var.is_initialized &&
-			    (is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) {
+			if (!var.is_initialized && is_type_untyped_nil(tav.type)) {
 				var.is_initialized = true;
 			}
 		}

+ 1 - 1
src/llvm_backend.hpp

@@ -477,7 +477,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value);
 
 gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
 gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
-gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
+gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_);
 gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
 gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
 

+ 10 - 5
src/llvm_backend_const.cpp

@@ -1,6 +1,6 @@
 gb_internal bool lb_is_const(lbValue value) {
 	LLVMValueRef v = value.value;
-	if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
+	if (is_type_untyped_nil(value.type)) {
 		// TODO(bill): Is this correct behaviour?
 		return true;
 	}
@@ -107,7 +107,11 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
 	case LLVMPointerTypeKind:
 		return LLVMConstPointerCast(val, dst);
 	case LLVMStructTypeKind:
-		return LLVMConstBitCast(val, dst);
+		// GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst));
+		// NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place?
+		// It seems mostly to exist to get around the "anonymous -> named" struct assignments
+		// return LLVMConstBitCast(val, dst);
+		return val;
 	default:
 		GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
 	}
@@ -1036,9 +1040,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
 											}
 											cv_type = cvt->Struct.fields[index]->type;
 
-											if (is_type_struct(cv_type)) {
-												auto cv_field_remapping = lb_get_struct_remapping(m, cv_type);
-												idx_list[j-1] = cast(unsigned)cv_field_remapping[index];
+											if (is_type_struct(cvt)) {
+												auto cv_field_remapping = lb_get_struct_remapping(m, cvt);
+												unsigned remapped_index = cast(unsigned)cv_field_remapping[index];
+												idx_list[j-1] = remapped_index;
 											} else {
 												idx_list[j-1] = cast(unsigned)index;
 											}

+ 1 - 1
src/llvm_backend_debug.cpp

@@ -283,7 +283,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		case Basic_UntypedString:     GB_PANIC("Basic_UntypedString");     break;
 		case Basic_UntypedRune:       GB_PANIC("Basic_UntypedRune");       break;
 		case Basic_UntypedNil:        GB_PANIC("Basic_UntypedNil");        break;
-		case Basic_UntypedUndef:      GB_PANIC("Basic_UntypedUndef");      break;
+		case Basic_UntypedUninit:     GB_PANIC("Basic_UntypedUninit");     break;
 
 		default: GB_PANIC("Basic Unhandled"); break;
 		}

+ 41 - 53
src/llvm_backend_expr.cpp

@@ -1,20 +1,18 @@
 gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
 
-gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
+gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) {
 	lbModule *m = p->module;
 
 	lbBlock *rhs  = lb_create_block(p, "logical.cmp.rhs");
 	lbBlock *done = lb_create_block(p, "logical.cmp.done");
 
-	type = default_type(type);
-
 	lbValue short_circuit = {};
 	if (op == Token_CmpAnd) {
 		lb_build_cond(p, left, rhs, done);
-		short_circuit = lb_const_bool(m, type, false);
+		short_circuit = lb_const_bool(m, t_llvm_bool, false);
 	} else if (op == Token_CmpOr) {
 		lb_build_cond(p, left, done, rhs);
-		short_circuit = lb_const_bool(m, type, true);
+		short_circuit = lb_const_bool(m, t_llvm_bool, true);
 	}
 
 	if (rhs->preds.count == 0) {
@@ -25,7 +23,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
 	if (done->preds.count == 0) {
 		lb_start_block(p, rhs);
 		if (lb_is_expr_untyped_const(right)) {
-			return lb_expr_untyped_const_to_typed(m, right, type);
+			return lb_expr_untyped_const_to_typed(m, right, default_type(final_type));
 		}
 		return lb_build_expr(p, right);
 	}
@@ -43,10 +41,11 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
 	lb_start_block(p, rhs);
 	lbValue edge = {};
 	if (lb_is_expr_untyped_const(right)) {
-		edge = lb_expr_untyped_const_to_typed(m, right, type);
+		edge = lb_expr_untyped_const_to_typed(m, right, t_llvm_bool);
 	} else {
-		edge = lb_build_expr(p, right);
+		edge = lb_emit_conv(p, lb_build_expr(p, right), t_llvm_bool);
 	}
+	GB_ASSERT(edge.type == t_llvm_bool);
 
 	incoming_values[done->preds.count] = edge.value;
 	incoming_blocks[done->preds.count] = p->curr_block->block;
@@ -54,7 +53,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
 	lb_emit_jump(p, done);
 	lb_start_block(p, done);	
 	
-	LLVMTypeRef dst_type = lb_type(m, type);
+	LLVMTypeRef dst_type = lb_type(m, t_llvm_bool);
 	LLVMValueRef phi = nullptr;
 	
 	GB_ASSERT(incoming_values.count == incoming_blocks.count);
@@ -67,48 +66,36 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
 			break;
 		}
 	}
+
+	lbValue res = {};
 	
 	if (phi_type == nullptr) {
 		phi = LLVMBuildPhi(p->builder, dst_type, "");
 		LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
-		lbValue res = {};
-		res.type = type;
 		res.value = phi;
-		return res;
-	}
-	
-	for_array(i, incoming_values) {
-		LLVMValueRef incoming_value = incoming_values[i];
-		LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
-		
-		if (phi_type != incoming_type) {
-			GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
-			bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
-			incoming_values[i] = LLVMConstInt(phi_type, ok, false);
+		res.type = t_llvm_bool;
+	} else {
+		for_array(i, incoming_values) {
+			LLVMValueRef incoming_value = incoming_values[i];
+			LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
+
+			if (phi_type != incoming_type) {
+				GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
+				bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
+				incoming_values[i] = LLVMConstInt(phi_type, ok, false);
+			}
+
 		}
-		
+
+		// NOTE(bill): this now only uses i1 for the logic to prevent issues with corrupted booleans which are not of value 0 or 1 (e.g. 2)
+		// Doing this may produce slightly worse code as a result but it will be correct behaviour
+
+		phi = LLVMBuildPhi(p->builder, phi_type, "");
+		LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
+		res.value = phi;
+		res.type = t_llvm_bool;
 	}
-	
-	phi = LLVMBuildPhi(p->builder, phi_type, "");
-	LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
-	
-	LLVMTypeRef i1 = LLVMInt1TypeInContext(m->ctx);
-	if ((phi_type == i1) ^ (dst_type == i1)) {
-		if (phi_type == i1) {
-			phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
-		} else {
-			phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
-		}
-	} else if (lb_sizeof(phi_type) < lb_sizeof(dst_type)) {
-		phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
-	} else {
-		phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");	
-	}		
-	
-	lbValue res = {};
-	res.type = type;
-	res.value = phi;
-	return res;
+	return lb_emit_conv(p, res, default_type(final_type));
 }
 
 
@@ -1499,12 +1486,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 	GB_ASSERT(src != nullptr);
 	GB_ASSERT(dst != nullptr);
 
+	if (is_type_untyped_uninit(src)) {
+		return lb_const_undef(m, t);
+	}
 	if (is_type_untyped_nil(src)) {
 		return lb_const_nil(m, t);
 	}
-	if (is_type_untyped_undef(src)) {
-		return lb_const_undef(m, t);
-	}
 
 	if (LLVMIsConstant(value.value)) {
 		if (is_type_any(dst)) {
@@ -1566,7 +1553,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 	// bool <-> llvm bool
 	if (is_type_boolean(src) && dst == t_llvm_bool) {
 		lbValue res = {};
-		res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
+		res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, src)), "");
 		res.type = t;
 		return res;
 	}
@@ -2145,12 +2132,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 
 
 	if (is_type_any(dst)) {
+		if (is_type_untyped_uninit(src)) {
+			return lb_const_undef(p->module, t);
+		}
 		if (is_type_untyped_nil(src)) {
 			return lb_const_nil(p->module, t);
 		}
-		if (is_type_untyped_undef(src)) {
-			return lb_const_undef(p->module, t);
-		}
 
 		lbAddr result = lb_add_local_generated(p, t, true);
 
@@ -3149,11 +3136,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
 		return lb_addr_load(p, lb_build_addr(p, expr));
 	case_end;
 
-	case_ast_node(u, Undef, expr)
+	case_ast_node(u, Uninit, expr)
 		lbValue res = {};
 		if (is_type_untyped(type)) {
 			res.value = nullptr;
-			res.type  = t_untyped_undef;
+			res.type  = t_untyped_uninit;
 		} else {
 			res.value = LLVMGetUndef(lb_type(m, type));
 			res.type  = type;
@@ -3783,6 +3770,7 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
 			multi_ptr = lb_emit_load(p, multi_ptr);
 		}
 		lbValue index = lb_build_expr(p, ie->index);
+		index = lb_emit_conv(p, index, t_int);
 		lbValue v = {};
 
 		LLVMValueRef indices[1] = {index.value};

+ 2 - 2
src/llvm_backend_general.cpp

@@ -677,7 +677,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
 		return;
 	}
 	GB_ASSERT(value.type != nullptr);
-	if (is_type_untyped_undef(value.type)) {
+	if (is_type_untyped_uninit(value.type)) {
 		Type *t = lb_addr_type(addr);
 		value.type = t;
 		value.value = LLVMGetUndef(lb_type(p->module, t));
@@ -1830,7 +1830,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		case Basic_UntypedString:     GB_PANIC("Basic_UntypedString"); break;
 		case Basic_UntypedRune:       GB_PANIC("Basic_UntypedRune"); break;
 		case Basic_UntypedNil:        GB_PANIC("Basic_UntypedNil"); break;
-		case Basic_UntypedUndef:      GB_PANIC("Basic_UntypedUndef"); break;
+		case Basic_UntypedUninit:     GB_PANIC("Basic_UntypedUninit"); break;
 		}
 		break;
 	case Type_Named:

+ 11 - 1
src/llvm_backend_opt.cpp

@@ -370,11 +370,21 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
 }
 
 
-gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
+gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind) {
 	if (p == nullptr) {
 		return;
 	}
 	LLVMRunFunctionPassManager(fpm, p->value);
+	switch (pass_manager_kind) {
+	case lbFunctionPassManager_none:
+		return;
+	case lbFunctionPassManager_default:
+	case lbFunctionPassManager_default_without_memcpy:
+		if (build_context.optimization_level < 0) {
+			return;
+		}
+		break;
+	}
 	// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
 	// which means we cannot rely upon it
 	// This is also useful for read the .ll for debug purposes because a lot of instructions

+ 4 - 4
src/llvm_backend_proc.cpp

@@ -3218,10 +3218,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
 			Entity *e = params->variables[i];
 			if (args[i].type == nullptr) {
 				continue;
+			} else if (is_type_untyped_uninit(args[i].type)) {
+				args[i] = lb_const_undef(m, e->type);
 			} else if (is_type_untyped_nil(args[i].type)) {
 				args[i] = lb_const_nil(m, e->type);
-			} else if (is_type_untyped_undef(args[i].type)) {
-				args[i] = lb_const_undef(m, e->type);
 			}
 		}
 
@@ -3409,10 +3409,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
 			Entity *e = param_tuple->variables[i];
 			if (args[i].type == nullptr) {
 				continue;
+			} else if (is_type_untyped_uninit(args[i].type)) {
+				args[i] = lb_const_undef(m, e->type);
 			} else if (is_type_untyped_nil(args[i].type)) {
 				args[i] = lb_const_nil(m, e->type);
-			} else if (is_type_untyped_undef(args[i].type)) {
-				args[i] = lb_const_undef(m, e->type);
 			}
 		}
 	}

+ 206 - 46
src/llvm_backend_stmt.cpp

@@ -249,7 +249,8 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
 
 
 gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
-                                        lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
+                                        lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
+                                        bool is_reverse) {
 	lbModule *m = p->module;
 
 	lbValue count = {};
@@ -266,25 +267,78 @@ gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_
 	lbBlock *done = nullptr;
 	lbBlock *body = nullptr;
 
+	loop = lb_create_block(p, "for.index.loop");
+	body = lb_create_block(p, "for.index.body");
+	done = lb_create_block(p, "for.index.done");
 
 	lbAddr index = lb_add_local_generated(p, t_int, false);
-	lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
 
-	loop = lb_create_block(p, "for.index.loop");
-	lb_emit_jump(p, loop);
-	lb_start_block(p, loop);
+	if (!is_reverse) {
+		/*
+			for x, i in array {
+				...
+			}
 
-	lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
-	lb_addr_store(p, index, incr);
+			i := -1
+			for {
+				i += 1
+				if !(i < len(array)) {
+					break
+				}
+				#no_bounds_check x := array[i]
+				...
+			}
+		*/
 
-	body = lb_create_block(p, "for.index.body");
-	done = lb_create_block(p, "for.index.done");
-	if (count.value == nullptr) {
-		GB_ASSERT(count_ptr.value != nullptr);
-		count = lb_emit_load(p, count_ptr);
+		lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
+
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
+
+		lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
+		lb_addr_store(p, index, incr);
+
+		if (count.value == nullptr) {
+			GB_ASSERT(count_ptr.value != nullptr);
+			count = lb_emit_load(p, count_ptr);
+		}
+		lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
+		lb_emit_if(p, cond, body, done);
+	} else {
+		// NOTE(bill): REVERSED LOGIC
+		/*
+			#reverse for x, i in array {
+				...
+			}
+
+			i := len(array)
+			for {
+				i -= 1
+				if i < 0 {
+					break
+				}
+				#no_bounds_check x := array[i]
+				...
+			}
+		*/
+
+		if (count.value == nullptr) {
+			GB_ASSERT(count_ptr.value != nullptr);
+			count = lb_emit_load(p, count_ptr);
+		}
+		count = lb_emit_conv(p, count, t_int);
+		lb_addr_store(p, index, count);
+
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
+
+		lbValue incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
+		lb_addr_store(p, index, incr);
+
+		lbValue anti_cond = lb_emit_comp(p, Token_Lt, incr, lb_const_int(m, t_int, 0));
+		lb_emit_if(p, anti_cond, done, body);
 	}
-	lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
-	lb_emit_if(p, cond, body, done);
+
 	lb_start_block(p, body);
 
 	idx = lb_addr_load(p, index);
@@ -452,7 +506,8 @@ gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type
 
 
 gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
-                                       lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
+                                       lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
+                                       bool is_reverse) {
 	lbModule *m = p->module;
 	lbValue count = lb_const_int(m, t_int, 0);
 	Type *expr_type = base_type(expr.type);
@@ -471,35 +526,88 @@ gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_t
 	lbBlock *done = nullptr;
 	lbBlock *body = nullptr;
 
+	loop = lb_create_block(p, "for.string.loop");
+	body = lb_create_block(p, "for.string.body");
+	done = lb_create_block(p, "for.string.done");
 
 	lbAddr offset_ = lb_add_local_generated(p, t_int, false);
-	lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
+	lbValue offset = {};
+	lbValue cond = {};
 
-	loop = lb_create_block(p, "for.string.loop");
-	lb_emit_jump(p, loop);
-	lb_start_block(p, loop);
+	if (!is_reverse) {
+		/*
+			for c, offset in str {
+				...
+			}
+
+			offset := 0
+			for offset < len(str) {
+				c, _w := string_decode_rune(str[offset:])
+				...
+				offset += _w
+			}
+		*/
+		lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
 
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
 
 
-	body = lb_create_block(p, "for.string.body");
-	done = lb_create_block(p, "for.string.done");
+		offset = lb_addr_load(p, offset_);
+		cond = lb_emit_comp(p, Token_Lt, offset, count);
+	} else {
+		// NOTE(bill): REVERSED LOGIC
+		/*
+			#reverse for c, offset in str {
+				...
+			}
 
-	lbValue offset = lb_addr_load(p, offset_);
-	lbValue cond = lb_emit_comp(p, Token_Lt, offset, count);
+			offset := len(str)
+			for offset > 0 {
+				c, _w := string_decode_last_rune(str[:offset])
+				offset -= _w
+				...
+			}
+		*/
+		lb_addr_store(p, offset_, count);
+
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
+
+		offset = lb_addr_load(p, offset_);
+		cond = lb_emit_comp(p, Token_Gt, offset, lb_const_int(m, t_int, 0));
+	}
 	lb_emit_if(p, cond, body, done);
 	lb_start_block(p, body);
 
 
-	lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
-	lbValue str_len  = lb_emit_arith(p, Token_Sub, count, offset, t_int);
-	auto args = array_make<lbValue>(permanent_allocator(), 1);
-	args[0] = lb_emit_string(p, str_elem, str_len);
-	lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
-	lbValue len  = lb_emit_struct_ev(p, rune_and_len, 1);
-	lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
+	lbValue rune_and_len = {};
+	if (!is_reverse) {
+		lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
+		lbValue str_len  = lb_emit_arith(p, Token_Sub, count, offset, t_int);
+		auto args = array_make<lbValue>(permanent_allocator(), 1);
+		args[0] = lb_emit_string(p, str_elem, str_len);
+
+		rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
+		lbValue len  = lb_emit_struct_ev(p, rune_and_len, 1);
+		lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
+
+		idx = offset;
+	} else {
+		// NOTE(bill): REVERSED LOGIC
+		lbValue str_elem = lb_string_elem(p, expr);
+		lbValue str_len  = offset;
+		auto args = array_make<lbValue>(permanent_allocator(), 1);
+		args[0] = lb_emit_string(p, str_elem, str_len);
+
+		rune_and_len = lb_emit_runtime_call(p, "string_decode_last_rune", args);
+		lbValue len  = lb_emit_struct_ev(p, rune_and_len, 1);
+		lb_addr_store(p, offset_, lb_emit_arith(p, Token_Sub, offset, len, t_int));
+
+		idx = lb_addr_load(p, offset_);
+	}
 
 
-	idx = offset;
 	if (val_type != nullptr) {
 		val = lb_emit_struct_ev(p, rune_and_len, 0);
 	}
@@ -702,6 +810,8 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
 	lbBlock *body = nullptr;
 	lbBlock *done = nullptr;
 
+	bool is_reverse = rs->reverse;
+
 	lb_open_scope(p, scope);
 
 
@@ -723,20 +833,70 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
 
 
 	lbAddr index = lb_add_local_generated(p, t_int, false);
-	lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
 
-	loop = lb_create_block(p, "for.soa.loop");
-	lb_emit_jump(p, loop);
-	lb_start_block(p, loop);
+	if (!is_reverse) {
+		/*
+			for x, i in array {
+				...
+			}
 
-	lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
-	lb_addr_store(p, index, incr);
+			i := -1
+			for {
+				i += 1
+				if !(i < len(array)) {
+					break
+				}
+				x := array[i] // but #soa-ified
+				...
+			}
+		*/
 
-	body = lb_create_block(p, "for.soa.body");
-	done = lb_create_block(p, "for.soa.done");
+		lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
 
-	lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
-	lb_emit_if(p, cond, body, done);
+		loop = lb_create_block(p, "for.soa.loop");
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
+
+		lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
+		lb_addr_store(p, index, incr);
+
+		body = lb_create_block(p, "for.soa.body");
+		done = lb_create_block(p, "for.soa.done");
+
+		lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
+		lb_emit_if(p, cond, body, done);
+	} else {
+		// NOTE(bill): REVERSED LOGIC
+		/*
+			#reverse for x, i in array {
+				...
+			}
+
+			i := len(array)
+			for {
+				i -= 1
+				if i < 0 {
+					break
+				}
+				#no_bounds_check x := array[i] // but #soa-ified
+				...
+			}
+		*/
+		lb_addr_store(p, index, count);
+
+		loop = lb_create_block(p, "for.soa.loop");
+		lb_emit_jump(p, loop);
+		lb_start_block(p, loop);
+
+		lbValue incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
+		lb_addr_store(p, index, incr);
+
+		body = lb_create_block(p, "for.soa.body");
+		done = lb_create_block(p, "for.soa.done");
+
+		lbValue cond = lb_emit_comp(p, Token_Lt, incr, lb_const_int(p->module, t_int, 0));
+		lb_emit_if(p, cond, done, body);
+	}
 	lb_start_block(p, body);
 
 
@@ -820,7 +980,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 			}
 			lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
 			lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
-			lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
+			lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
 			break;
 		}
 		case Type_EnumeratedArray: {
@@ -830,7 +990,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 			}
 			lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
 			lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count));
-			lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
+			lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
 			break;
 		}
 		case Type_DynamicArray: {
@@ -840,7 +1000,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 				array = lb_emit_load(p, array);
 			}
 			count_ptr = lb_emit_struct_ep(p, array, 1);
-			lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done);
+			lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
 			break;
 		}
 		case Type_Slice: {
@@ -853,7 +1013,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 				count_ptr = lb_add_local_generated(p, t_int, false).addr;
 				lb_emit_store(p, count_ptr, lb_slice_len(p, slice));
 			}
-			lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done);
+			lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
 			break;
 		}
 		case Type_Basic: {
@@ -868,7 +1028,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 			}
 			Type *t = base_type(string.type);
 			GB_ASSERT(!is_type_cstring(t));
-			lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done);
+			lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse);
 			break;
 		}
 		case Type_Tuple:

+ 36 - 11
src/parser.cpp

@@ -115,7 +115,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
 		n->Ident.entity = nullptr;
 		break;
 	case Ast_Implicit:       break;
-	case Ast_Undef:          break;
+	case Ast_Uninit:         break;
 	case Ast_BasicLit:       break;
 	case Ast_BasicDirective: break;
 
@@ -646,9 +646,9 @@ gb_internal Ast *ast_implicit(AstFile *f, Token token) {
 	result->Implicit = token;
 	return result;
 }
-gb_internal Ast *ast_undef(AstFile *f, Token token) {
-	Ast *result = alloc_ast_node(f, Ast_Undef);
-	result->Undef = token;
+gb_internal Ast *ast_uninit(AstFile *f, Token token) {
+	Ast *result = alloc_ast_node(f, Ast_Uninit);
+	result->Uninit = token;
 	return result;
 }
 
@@ -2092,8 +2092,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
 	case Token_Ident:
 		return parse_ident(f);
 
-	case Token_Undef:
-		return ast_undef(f, expect_token(f, Token_Undef));
+	case Token_Uninit:
+		return ast_uninit(f, expect_token(f, Token_Uninit));
 
 	case Token_context:
 		return ast_implicit(f, expect_token(f, Token_context));
@@ -2292,7 +2292,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
 
 		skip_possible_newline_for_literal(f);
 
-		if (allow_token(f, Token_Undef)) {
+		if (allow_token(f, Token_Uninit)) {
 			if (where_token.kind != Token_Invalid) {
 				syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
 			}
@@ -3744,8 +3744,18 @@ gb_internal bool allow_field_separator(AstFile *f) {
 	if (allow_token(f, Token_Comma)) {
 		return true;
 	}
-	if (ALLOW_NEWLINE && token.kind == Token_Semicolon) {
-		if (!token_is_newline(token)) {
+	if (token.kind == Token_Semicolon) {
+		bool ok = false;
+		if (ALLOW_NEWLINE && token_is_newline(token)) {
+			TokenKind next = peek_token(f).kind;
+			switch (next) {
+			case Token_CloseBrace:
+			case Token_CloseParen:
+				ok = true;
+				break;
+			}
+		}
+		if (!ok) {
 			String p = token_to_string(token);
 			syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p));
 		}
@@ -4509,7 +4519,7 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
 	return ast_bad_decl(f, token, f->curr_token);
 }
 
-gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind) {
+gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind, CommentGroup *docs) {
 	Array<Ast *> elems = {};
 	Token open = {};
 	Token close = {};
@@ -4550,6 +4560,9 @@ gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, T
 
 	Ast *decl = parse_stmt(f);
 	if (decl->kind == Ast_ValueDecl) {
+		if (decl->ValueDecl.docs == nullptr && docs != nullptr) {
+			decl->ValueDecl.docs = docs;
+		}
 		array_add(&decl->ValueDecl.attributes, attribute);
 	} else if (decl->kind == Ast_ForeignBlockDecl) {
 		array_add(&decl->ForeignBlockDecl.attributes, attribute);
@@ -4698,8 +4711,9 @@ gb_internal Ast *parse_stmt(AstFile *f) {
 	} break;
 
 	case Token_At: {
+		CommentGroup *docs = f->lead_comment;
 		Token token = expect_token(f, Token_At);
-		return parse_attribute(f, token, Token_OpenParen, Token_CloseParen);
+		return parse_attribute(f, token, Token_OpenParen, Token_CloseParen, docs);
 	}
 
 	case Token_Hash: {
@@ -4749,6 +4763,17 @@ gb_internal Ast *parse_stmt(AstFile *f) {
 			return stmt;
 		} else if (tag == "unroll") {
 			return parse_unrolled_for_loop(f, name);
+		} else if (tag == "reverse") {
+			Ast *for_stmt = parse_for_stmt(f);
+			if (for_stmt->kind == Ast_RangeStmt) {
+				if (for_stmt->RangeStmt.reverse) {
+					syntax_error(token, "#reverse already applied to a 'for in' statement");
+				}
+				for_stmt->RangeStmt.reverse = true;
+			} else {
+				syntax_error(token, "#reverse can only be applied to a 'for in' statement");
+			}
+			return for_stmt;
 		} else if (tag == "include") {
 			syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
 			s = ast_bad_stmt(f, token, f->curr_token);

+ 11 - 1
src/parser.hpp

@@ -356,6 +356,15 @@ enum UnionTypeKind : u8 {
 	UnionType_Normal     = 0,
 	UnionType_no_nil     = 2,
 	UnionType_shared_nil = 3,
+
+	UnionType_COUNT
+};
+
+gb_global char const *union_type_kind_strings[UnionType_COUNT] = {
+	"(normal)",
+	"#maybe",
+	"#no_nil",
+	"#shared_nil",
 };
 
 #define AST_KINDS \
@@ -364,7 +373,7 @@ enum UnionTypeKind : u8 {
 		Entity *entity; \
 	}) \
 	AST_KIND(Implicit,       "implicit",        Token) \
-	AST_KIND(Undef,          "undef",           Token) \
+	AST_KIND(Uninit,         "uninitialized value", Token) \
 	AST_KIND(BasicLit,       "basic literal",   struct { \
 		Token token; \
 	}) \
@@ -520,6 +529,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
 		Token in_token; \
 		Ast *expr; \
 		Ast *body; \
+		bool reverse; \
 	}) \
 	AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \
 		Scope *scope; \

+ 2 - 2
src/parser_pos.cpp

@@ -2,7 +2,7 @@ gb_internal Token ast_token(Ast *node) {
 	switch (node->kind) {
 	case Ast_Ident:          return node->Ident.token;
 	case Ast_Implicit:       return node->Implicit;
-	case Ast_Undef:          return node->Undef;
+	case Ast_Uninit:         return node->Uninit;
 	case Ast_BasicLit:       return node->BasicLit.token;
 	case Ast_BasicDirective: return node->BasicDirective.token;
 	case Ast_ProcGroup:      return node->ProcGroup.token;
@@ -137,7 +137,7 @@ Token ast_end_token(Ast *node) {
 		return empty_token;
 	case Ast_Ident:          return node->Ident.token;
 	case Ast_Implicit:       return node->Implicit;
-	case Ast_Undef:          return node->Undef;
+	case Ast_Uninit:         return node->Uninit;
 	case Ast_BasicLit:       return node->BasicLit.token;
 	case Ast_BasicDirective: return node->BasicDirective.token;
 	case Ast_ProcGroup:      return node->ProcGroup.close;

+ 63 - 0
src/path.cpp

@@ -1,6 +1,10 @@
 /*
 	Path handling utilities.
 */
+#if !defined(GB_SYSTEM_WINDOWS)
+#include <unistd.h>
+#endif
+
 gb_internal String remove_extension_from_path(String const &s) {
 	if (s.len != 0 && s.text[s.len-1] == '.') {
 		return s;
@@ -25,6 +29,29 @@ gb_internal String remove_directory_from_path(String const &s) {
 	return substring(s, s.len-len, s.len);
 }
 
+
+// NOTE(Mark Naughton): getcwd as String
+#if !defined(GB_SYSTEM_WINDOWS)
+gb_internal String get_current_directory(void) {
+	char cwd[256];
+	getcwd(cwd, 256);
+
+	return make_string_c(cwd);
+}
+
+#else
+gb_internal String get_current_directory(void) {
+	gbAllocator a = heap_allocator();
+
+	wchar_t cwd[256];
+	GetCurrentDirectoryW(256, cwd);
+
+	String16 wstr = make_string16_c(cwd);
+
+	return string16_to_string(a, wstr);
+}
+#endif
+
 gb_internal bool path_is_directory(String path);
 
 gb_internal String directory_from_path(String const &s) {
@@ -392,7 +419,43 @@ gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi)
 
 	return ReadDirectory_None;
 }
+
+
 #else
 #error Implement read_directory
 #endif
 
+#if !defined(GB_SYSTEM_WINDOWS)
+gb_internal bool write_directory(String path) {
+	char const *pathname = (char *) path.text;
+
+	if (access(pathname, W_OK) < 0) {
+		return false;
+	}
+
+	return true;
+}
+#else
+gb_internal bool write_directory(String path) {
+	String16 wstr = string_to_string16(heap_allocator(), path);
+	LPCWSTR wdirectory_name = wstr.text;
+
+	HANDLE directory = CreateFileW(wdirectory_name,
+			GENERIC_WRITE,
+			0,
+			NULL,
+			OPEN_EXISTING,
+			FILE_FLAG_BACKUP_SEMANTICS,
+			NULL);
+
+	if (directory == INVALID_HANDLE_VALUE) {
+		DWORD error_code = GetLastError();
+		if (error_code == ERROR_ACCESS_DENIED) {
+			return false;
+		}
+	}
+
+	CloseHandle(directory);
+	return true;
+}
+#endif

+ 3 - 3
src/tokenizer.cpp

@@ -54,7 +54,7 @@ TOKEN_KIND(Token__AssignOpEnd, ""), \
 	TOKEN_KIND(Token_Increment, "++"), \
 	TOKEN_KIND(Token_Decrement, "--"), \
 	TOKEN_KIND(Token_ArrowRight,"->"), \
-	TOKEN_KIND(Token_Undef,     "---"), \
+	TOKEN_KIND(Token_Uninit,    "---"), \
 \
 TOKEN_KIND(Token__ComparisonBegin, ""), \
 	TOKEN_KIND(Token_CmpEq, "=="), \
@@ -917,7 +917,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
 				token->kind = Token_Decrement;
 				if (t->curr_rune == '-') {
 					advance_to_next_rune(t);
-					token->kind = Token_Undef;
+					token->kind = Token_Uninit;
 				}
 				break;
 			case '>':
@@ -1078,7 +1078,7 @@ semicolon_check:;
 	case Token_Imag:
 	case Token_Rune:
 	case Token_String:
-	case Token_Undef:
+	case Token_Uninit:
 		/*fallthrough*/
 	case Token_Question:
 	case Token_Pointer:

+ 19 - 12
src/types.cpp

@@ -83,7 +83,7 @@ enum BasicKind {
 	Basic_UntypedString,
 	Basic_UntypedRune,
 	Basic_UntypedNil,
-	Basic_UntypedUndef,
+	Basic_UntypedUninit,
 
 	Basic_COUNT,
 
@@ -515,7 +515,7 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_UntypedString,     BasicFlag_String     | BasicFlag_Untyped,   0, STR_LIT("untyped string")}},
 	{Type_Basic, {Basic_UntypedRune,       BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped rune")}},
 	{Type_Basic, {Basic_UntypedNil,        BasicFlag_Untyped,                          0, STR_LIT("untyped nil")}},
-	{Type_Basic, {Basic_UntypedUndef,      BasicFlag_Untyped,                          0, STR_LIT("untyped undefined")}},
+	{Type_Basic, {Basic_UntypedUninit,     BasicFlag_Untyped,                          0, STR_LIT("untyped uninitialized")}},
 };
 
 // gb_global Type basic_type_aliases[] = {
@@ -589,7 +589,7 @@ gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
 gb_global Type *t_untyped_string     = &basic_types[Basic_UntypedString];
 gb_global Type *t_untyped_rune       = &basic_types[Basic_UntypedRune];
 gb_global Type *t_untyped_nil        = &basic_types[Basic_UntypedNil];
-gb_global Type *t_untyped_undef      = &basic_types[Basic_UntypedUndef];
+gb_global Type *t_untyped_uninit     = &basic_types[Basic_UntypedUninit];
 
 
 
@@ -1866,14 +1866,15 @@ gb_internal bool is_type_typeid(Type *t) {
 }
 gb_internal bool is_type_untyped_nil(Type *t) {
 	t = base_type(t);
-	return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedNil);
+	// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
+	return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit));
 }
-gb_internal bool is_type_untyped_undef(Type *t) {
+gb_internal bool is_type_untyped_uninit(Type *t) {
 	t = base_type(t);
-	return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUndef);
+	// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
+	return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit);
 }
 
-
 gb_internal bool is_type_empty_union(Type *t) {
 	t = base_type(t);
 	return t->kind == Type_Union && t->Union.variants.count == 0;
@@ -2206,10 +2207,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
 }
 
 
-gb_internal gb_inline bool type_has_undef(Type *t) {
-	return true;
-}
-
 gb_internal bool type_has_nil(Type *t) {
 	t = base_type(t);
 	switch (t->kind) {
@@ -2769,13 +2766,23 @@ gb_internal Type *default_type(Type *type) {
 	return type;
 }
 
+gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
+	if (are_types_identical(v, vt)) {
+		return true;
+	}
+	if (is_type_proc(v) && is_type_proc(vt)) {
+		return are_types_identical(base_type(v), base_type(vt));
+	}
+	return false;
+}
+
 gb_internal i64 union_variant_index(Type *u, Type *v) {
 	u = base_type(u);
 	GB_ASSERT(u->kind == Type_Union);
 
 	for_array(i, u->Union.variants) {
 		Type *vt = u->Union.variants[i];
-		if (are_types_identical(v, vt)) {
+		if (union_variant_index_types_equal(v, vt)) {
 			if (u->Union.kind == UnionType_no_nil) {
 				return cast(i64)(i+0);
 			} else {

+ 1 - 1
tests/core/crypto/test_core_crypto_modern.odin

@@ -272,7 +272,7 @@ test_x25519 :: proc(t: ^testing.T) {
 	// Local copy of this so that the base point doesn't need to be exported.
 	_BASE_POINT: [32]byte = {
 		9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	}
 
 	test_vectors := [?]TestECDH {

+ 15 - 1
tests/core/encoding/json/test_core_json.odin

@@ -32,6 +32,7 @@ main :: proc() {
 	parse_json(&t)
 	marshal_json(&t)
 	unmarshal_json(&t)
+	surrogate(&t)
 
 	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
 	if TEST_fail > 0 {
@@ -344,4 +345,17 @@ unmarshal_json :: proc(t: ^testing.T) {
 	for p, i in g.products {
 		expect(t, p == original_data.products[i], "Producted unmarshaled improperly")
 	}
-}
+}
+
+@test
+surrogate :: proc(t: ^testing.T) {
+	input := `+ + * 😃 - /`
+
+	out, err := json.marshal(input)
+	expect(t, err == nil, fmt.tprintf("Expected `json.marshal(%q)` to return a nil error, got %v", input, err))
+
+	back: string
+	uerr := json.unmarshal(out, &back)
+	expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr))
+	expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr))
+}

+ 32 - 18
tests/documentation/documentation_tester.odin

@@ -14,6 +14,7 @@ Example_Test :: struct {
 	package_name: string,
 	example_code: []string,
 	expected_output: []string,
+	skip_output_check: bool,
 }
 
 g_header:   ^doc.Header
@@ -145,6 +146,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
 	curr_block_kind := Block_Kind.Other
 	start := 0
 
+	found_possible_output: bool
 	example_block: Block // when set the kind should be Example
 	output_block: Block // when set the kind should be Output
 	// rely on zii that the kinds have not been set
@@ -178,10 +180,16 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
 			switch {
 			case strings.has_prefix(line, "Example:"): next_block_kind = .Example
 			case strings.has_prefix(line, "Output:"): next_block_kind = .Output
+			case strings.has_prefix(line, "Possible Output:"):
+				next_block_kind = .Output
+				found_possible_output = true
 			}
 		case .Example:
 			switch {
 			case strings.has_prefix(line, "Output:"): next_block_kind = .Output
+			case strings.has_prefix(line, "Possible Output:"):
+				next_block_kind = .Output
+				found_possible_output = true
 			case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
 			}
 		case .Output:
@@ -219,8 +227,9 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
 		{
 			// Output block starts with
 			// `Output:` and a number of white spaces,
+			// `Possible Output:` and a number of white spaces,
 			lines := &output_block.lines
-			for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:")) {
+			for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:") || strings.has_prefix(lines[0], "Possible Output:")) {
 				lines^ = lines[1:]
 			}
 			// Additionally we need to strip all empty lines at the end of output to not include those in the expected output
@@ -240,6 +249,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
 			package_name = package_name,
 			example_code = example_block.lines,
 			expected_output = output_block.lines,
+			skip_output_check = found_possible_output,
 		})
 	}
 }
@@ -404,25 +414,29 @@ main :: proc() {
 			continue
 		}
 
-		fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
-		fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
-		had_line_error: bool
-		for line in test.expected_output {
-			// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
-			// I don't think any examples would really need this specific character so let's just make it forbidden and change
-			// in the future if we really need to
-			if strings.contains_rune(line, '`') {
-				fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
-				g_bad_doc = true
-				had_line_error = true
+		// NOTE: packages like 'rand' are random by nature, in these cases we cannot verify against the output string
+		// in these cases we just mark the output as 'Possible Output' and we simply skip checking against the output
+		if ! test.skip_output_check {
+			fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
+			fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
+			had_line_error: bool
+			for line in test.expected_output {
+				// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
+				// I don't think any examples would really need this specific character so let's just make it forbidden and change
+				// in the future if we really need to
+				if strings.contains_rune(line, '`') {
+					fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
+					g_bad_doc = true
+					had_line_error = true
+				}
+				strings.write_string(&test_runner, line)
+				strings.write_string(&test_runner, "\n")
 			}
-			strings.write_string(&test_runner, line)
-			strings.write_string(&test_runner, "\n")
-		}
-		if had_line_error {
-			continue
+			if had_line_error {
+				continue
+			}
+			strings.write_string(&test_runner, "`)\n")
 		}
-		strings.write_string(&test_runner, "`)\n")
 		save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name)
 
 		test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 {

+ 53 - 53
vendor/darwin/Foundation/NSApplication.odin

@@ -58,38 +58,38 @@ ApplicationPresentationOptionsDisableCursorLocationAssistance :: ApplicationPres
 Application :: struct {using _: Object}
 
 @(objc_type=Application, objc_name="sharedApplication", objc_is_class_method=true)
-Application_sharedApplication :: proc() -> ^Application {
+Application_sharedApplication :: proc "c" () -> ^Application {
 	return msgSend(^Application, Application, "sharedApplication")
 }
 
 @(objc_type=Application, objc_name="setActivationPolicy")
-Application_setActivationPolicy :: proc(self: ^Application, activationPolicy: ActivationPolicy) -> BOOL {
+Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolicy: ActivationPolicy) -> BOOL {
 	return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy)
 }
 
 @(objc_type=Application, objc_name="activateIgnoringOtherApps")
-Application_activateIgnoringOtherApps :: proc(self: ^Application, ignoreOtherApps: BOOL) {
+Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
 	msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
 }
 
 @(objc_type=Application, objc_name="setMainMenu")
-Application_setMainMenu :: proc(self: ^Application, menu: ^Menu) {
+Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) {
 	msgSend(nil, self, "setMainMenu:", menu)
 }
 
 @(objc_type=Application, objc_name="windows")
-Application_windows :: proc(self: ^Application) -> ^Array {
+Application_windows :: proc "c" (self: ^Application) -> ^Array {
 	return msgSend(^Array, self, "windows")
 }
 
 @(objc_type=Application, objc_name="run")
-Application_run :: proc(self: ^Application) {
+Application_run :: proc "c" (self: ^Application) {
 	msgSend(nil, self, "run")
 }
 
 
 @(objc_type=Application, objc_name="terminate")
-Application_terminate :: proc(self: ^Application, sender: ^Object) {
+Application_terminate :: proc "c" (self: ^Application, sender: ^Object) {
 	msgSend(nil, self, "terminate:", sender)
 }
 
@@ -99,81 +99,81 @@ Application_terminate :: proc(self: ^Application, sender: ^Object) {
 RunningApplication :: struct {using _: Object}
 
 @(objc_type=RunningApplication, objc_name="currentApplication", objc_is_class_method=true)
-RunningApplication_currentApplication :: proc() -> ^RunningApplication {
+RunningApplication_currentApplication :: proc "c" () -> ^RunningApplication {
 	return msgSend(^RunningApplication, RunningApplication, "currentApplication")
 }
 
 @(objc_type=RunningApplication, objc_name="localizedName")
-RunningApplication_localizedName :: proc(self: ^RunningApplication) -> ^String {
+RunningApplication_localizedName :: proc "c" (self: ^RunningApplication) -> ^String {
 	return msgSend(^String, self, "localizedName")
 }
 
 ApplicationDelegateTemplate :: struct {
 	// Launching Applications
-	applicationWillFinishLaunching: proc(notification: ^Notification),
-	applicationDidFinishLaunching: proc(notification: ^Notification),
+	applicationWillFinishLaunching:                              proc(notification: ^Notification),
+	applicationDidFinishLaunching:                               proc(notification: ^Notification),
 	// Managing Active Status
-	applicationWillBecomeActive: proc(notification: ^Notification),
-	applicationDidBecomeActive: proc(notification: ^Notification),
-	applicationWillResignActive: proc(notification: ^Notification),
-	applicationDidResignActive: proc(notification: ^Notification),
+	applicationWillBecomeActive:                                 proc(notification: ^Notification),
+	applicationDidBecomeActive:                                  proc(notification: ^Notification),
+	applicationWillResignActive:                                 proc(notification: ^Notification),
+	applicationDidResignActive:                                  proc(notification: ^Notification),
 	// Terminating Applications
-	applicationShouldTerminate: proc(sender: ^Application) -> ApplicationTerminateReply,
-	applicationShouldTerminateAfterLastWindowClosed: proc(sender: ^Application) -> BOOL,
-	applicationWillTerminate: proc(notification: ^Notification),
+	applicationShouldTerminate:                                  proc(sender: ^Application) -> ApplicationTerminateReply,
+	applicationShouldTerminateAfterLastWindowClosed:             proc(sender: ^Application) -> BOOL,
+	applicationWillTerminate:                                    proc(notification: ^Notification),
 	// Hiding Applications
-	applicationWillHide: proc(notification: ^Notification),
-	applicationDidHide: proc(notification: ^Notification),
-	applicationWillUnhide: proc(notification: ^Notification),
-	applicationDidUnhide: proc(notification: ^Notification),
+	applicationWillHide:                                         proc(notification: ^Notification),
+	applicationDidHide:                                          proc(notification: ^Notification),
+	applicationWillUnhide:                                       proc(notification: ^Notification),
+	applicationDidUnhide:                                        proc(notification: ^Notification),
 	// Managing Windows
-	applicationWillUpdate: proc(notification: ^Notification),
-	applicationDidUpdate: proc(notification: ^Notification),
-	applicationShouldHandleReopenHasVisibleWindows: proc(sender: ^Application, flag: BOOL) -> BOOL,
+	applicationWillUpdate:                                       proc(notification: ^Notification),
+	applicationDidUpdate:                                        proc(notification: ^Notification),
+	applicationShouldHandleReopenHasVisibleWindows:              proc(sender: ^Application, flag: BOOL) -> BOOL,
 	// Managing the Dock Menu
-	applicationDockMenu: proc(sender: ^Application) -> ^Menu,
+	applicationDockMenu:                                         proc(sender: ^Application) -> ^Menu,
 	// Localizing Keyboard Shortcuts
-	applicationShouldAutomaticallyLocalizeKeyEquivalents: proc(application: ^Application) -> BOOL,
+	applicationShouldAutomaticallyLocalizeKeyEquivalents:        proc(application: ^Application) -> BOOL,
 	// Displaying Errors
-	applicationWillPresentError: proc(application: ^Application, error: ^Error) -> ^Error,
+	applicationWillPresentError:                                 proc(application: ^Application, error: ^Error) -> ^Error,
 	// Managing the Screen
-	applicationDidChangeScreenParameters: proc(notification: ^Notification),
+	applicationDidChangeScreenParameters:                        proc(notification: ^Notification),
 	// Continuing User Activities
-	applicationWillContinueUserActivityWithType: proc(application: ^Application, userActivityType: ^String) -> BOOL,
-	applicationContinueUserActivityRestorationHandler: proc(application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL,
-	applicationDidFailToContinueUserActivityWithTypeError: proc(application: ^Application, userActivityType: ^String, error: ^Error),
-	applicationDidUpdateUserActivity: proc(application: ^Application, userActivity: ^UserActivity),
+	applicationWillContinueUserActivityWithType:                 proc(application: ^Application, userActivityType: ^String) -> BOOL,
+	applicationContinueUserActivityRestorationHandler:           proc(application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL,
+	applicationDidFailToContinueUserActivityWithTypeError:       proc(application: ^Application, userActivityType: ^String, error: ^Error),
+	applicationDidUpdateUserActivity:                            proc(application: ^Application, userActivity: ^UserActivity),
 	// Handling Push Notifications
 	applicationDidRegisterForRemoteNotificationsWithDeviceToken: proc(application: ^Application, deviceToken: ^Data),
 	applicationDidFailToRegisterForRemoteNotificationsWithError: proc(application: ^Application, error: ^Error),
-	applicationDidReceiveRemoteNotification: proc(application: ^Application, userInfo: ^Dictionary),
+	applicationDidReceiveRemoteNotification:                     proc(application: ^Application, userInfo: ^Dictionary),
 	// Handling CloudKit Invitations
 	// TODO: if/when we have cloud kit bindings implement
-	// applicationUserDidAcceptCloudKitShareWithMetadata: proc(application: ^Application, metadata: ^CKShareMetadata),
+	// applicationUserDidAcceptCloudKitShareWithMetadata:        proc(application: ^Application, metadata: ^CKShareMetadata),
 	// Handling SiriKit Intents
 	// TODO: if/when we have siri kit bindings implement
-	// applicationHandlerForIntent: proc(application: ^Application, intent: ^INIntent) -> id,
+	// applicationHandlerForIntent:                              proc(application: ^Application, intent: ^INIntent) -> id,
 	// Opening Files
-	applicationOpenURLs: proc(application: ^Application, urls: ^Array),
-	applicationOpenFile: proc(sender: ^Application, filename: ^String) -> BOOL,
-	applicationOpenFileWithoutUI: proc(sender: id, filename: ^String) -> BOOL,
-	applicationOpenTempFile: proc(sender: ^Application, filename: ^String) -> BOOL,
-	applicationOpenFiles: proc(sender: ^Application, filenames: ^Array),
-	applicationShouldOpenUntitledFile: proc(sender: ^Application) -> BOOL,
-	applicationOpenUntitledFile: proc(sender: ^Application) -> BOOL,
+	applicationOpenURLs:                                         proc(application: ^Application, urls: ^Array),
+	applicationOpenFile:                                         proc(sender: ^Application, filename: ^String) -> BOOL,
+	applicationOpenFileWithoutUI:                                proc(sender: id, filename: ^String) -> BOOL,
+	applicationOpenTempFile:                                     proc(sender: ^Application, filename: ^String) -> BOOL,
+	applicationOpenFiles:                                        proc(sender: ^Application, filenames: ^Array),
+	applicationShouldOpenUntitledFile:                           proc(sender: ^Application) -> BOOL,
+	applicationOpenUntitledFile:                                 proc(sender: ^Application) -> BOOL,
 	// Printing
-	applicationPrintFile: proc(sender: ^Application, filename: ^String) -> BOOL,
-	applicationPrintFilesWithSettingsShowPrintPanels: proc(application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply,
+	applicationPrintFile:                                        proc(sender: ^Application, filename: ^String) -> BOOL,
+	applicationPrintFilesWithSettingsShowPrintPanels:            proc(application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply,
 	// Restoring Application State
-	applicationSupportsSecureRestorableState: proc(app: ^Application) -> BOOL,
-	applicationProtectedDataDidBecomeAvailable: proc(notification: ^Notification),
-	applicationProtectedDataWillBecomeUnavailable: proc(notification: ^Notification),
-	applicationWillEncodeRestorableState: proc(app: ^Application, coder: ^Coder),
-	applicationDidDecodeRestorableState: proc(app: ^Application, coder: ^Coder),
+	applicationSupportsSecureRestorableState:                    proc(app: ^Application) -> BOOL,
+	applicationProtectedDataDidBecomeAvailable:                  proc(notification: ^Notification),
+	applicationProtectedDataWillBecomeUnavailable:               proc(notification: ^Notification),
+	applicationWillEncodeRestorableState:                        proc(app: ^Application, coder: ^Coder),
+	applicationDidDecodeRestorableState:                         proc(app: ^Application, coder: ^Coder),
 	// Handling Changes to the Occlusion State
-	applicationDidChangeOcclusionState: proc(notification: ^Notification),
+	applicationDidChangeOcclusionState:                          proc(notification: ^Notification),
 	// Scripting Your App
-	applicationDelegateHandlesKey: proc(sender: ^Application, key: ^String) -> BOOL,
+	applicationDelegateHandlesKey:                               proc(sender: ^Application, key: ^String) -> BOOL,
 }
 
 ApplicationDelegate :: struct { using _: Object }
@@ -559,6 +559,6 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
 }
 
 @(objc_type=Application, objc_name="setDelegate")
-Application_setDelegate :: proc(self: ^Application, delegate: ^ApplicationDelegate) {
+Application_setDelegate :: proc "c" (self: ^Application, delegate: ^ApplicationDelegate) {
 	msgSend(nil, self, "setDelegate:", delegate)
 }

+ 7 - 7
vendor/darwin/Foundation/NSArray.odin

@@ -8,35 +8,35 @@ Array :: struct {
 }
 
 @(objc_type=Array, objc_name="alloc", objc_is_class_method=true)
-Array_alloc :: proc() -> ^Array {
+Array_alloc :: proc "c" () -> ^Array {
 	return msgSend(^Array, Array, "alloc")
 }
 
 @(objc_type=Array, objc_name="init")
-Array_init :: proc(self: ^Array) -> ^Array {
+Array_init :: proc "c" (self: ^Array) -> ^Array {
 	return msgSend(^Array, self, "init")
 }
 
 @(objc_type=Array, objc_name="initWithObjects")
-Array_initWithObjects :: proc(self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array {
+Array_initWithObjects :: proc "c" (self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array {
 	return msgSend(^Array, self, "initWithObjects:count:", objects, count)
 }
 
 @(objc_type=Array, objc_name="initWithCoder")
-Array_initWithCoder :: proc(self: ^Array, coder: ^Coder) -> ^Array {
+Array_initWithCoder :: proc "c" (self: ^Array, coder: ^Coder) -> ^Array {
 	return msgSend(^Array, self, "initWithCoder:", coder)
 }
 
 @(objc_type=Array, objc_name="object")
-Array_object :: proc(self: ^Array, index: UInteger) -> ^Object {
+Array_object :: proc "c" (self: ^Array, index: UInteger) -> ^Object {
 	return msgSend(^Object, self, "objectAtIndex:", index)
 }
 @(objc_type=Array, objc_name="objectAs")
-Array_objectAs :: proc(self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object)  {
+Array_objectAs :: proc "c" (self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object)  {
 	return (T)(Array_object(self, index))
 }
 
 @(objc_type=Array, objc_name="count")
-Array_count :: proc(self: ^Array) -> UInteger {
+Array_count :: proc "c" (self: ^Array) -> UInteger {
 	return msgSend(UInteger, self, "count")
 }

+ 6 - 6
vendor/darwin/Foundation/NSAutoreleasePool.odin

@@ -4,30 +4,30 @@ package objc_Foundation
 AutoreleasePool :: struct {using _: Object}
 
 @(objc_type=AutoreleasePool, objc_name="alloc", objc_is_class_method=true)
-AutoreleasePool_alloc :: proc() -> ^AutoreleasePool {
+AutoreleasePool_alloc :: proc "c" () -> ^AutoreleasePool {
 	return msgSend(^AutoreleasePool, AutoreleasePool, "alloc")
 }
 
 @(objc_type=AutoreleasePool, objc_name="init")
-AutoreleasePool_init :: proc(self: ^AutoreleasePool) -> ^AutoreleasePool {
+AutoreleasePool_init :: proc "c" (self: ^AutoreleasePool) -> ^AutoreleasePool {
 	return msgSend(^AutoreleasePool, self, "init")
 }
 
 @(objc_type=AutoreleasePool, objc_name="drain")
-AutoreleasePool_drain :: proc(self: ^AutoreleasePool) {
+AutoreleasePool_drain :: proc "c" (self: ^AutoreleasePool) {
 	msgSend(nil, self, "drain")
 }
 @(objc_type=AutoreleasePool, objc_name="addObject")
-AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) {
+AutoreleasePool_addObject :: proc "c" (self: ^AutoreleasePool, obj: ^Object) {
 	msgSend(nil, self, "addObject:", obj)
 }
 @(objc_type=AutoreleasePool, objc_name="showPools")
-AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) {
+AutoreleasePool_showPools :: proc "c" (self: ^AutoreleasePool, obj: ^Object) {
 	msgSend(nil, self, "showPools")
 }
 
 
 @(deferred_out=AutoreleasePool_drain)
-scoped_autoreleasepool :: proc() -> ^AutoreleasePool {
+scoped_autoreleasepool :: proc "c" () -> ^AutoreleasePool {
 	return AutoreleasePool.alloc()->init()
 }

+ 37 - 37
vendor/darwin/Foundation/NSBundle.odin

@@ -4,188 +4,188 @@ package objc_Foundation
 Bundle :: struct { using _: Object }
 
 @(objc_type=Bundle, objc_name="mainBundle", objc_is_class_method=true)
-Bundle_mainBundle :: proc() -> ^Bundle {
+Bundle_mainBundle :: proc "c" () -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "mainBundle")
 }
 
 @(objc_type=Bundle, objc_name="bundleWithPath", objc_is_class_method=true)
-Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle {
+Bundle_bundleWithPath :: proc "c" (path: ^String) -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "bundleWithPath:", path)
 }
 
 @(objc_type=Bundle, objc_name="bundleWithURL", objc_is_class_method=true)
-Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle {
+Bundle_bundleWithURL :: proc "c" (url: ^URL) -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "bundleWithUrl:", url)
 }
 
 
 @(objc_type=Bundle, objc_name="alloc", objc_is_class_method=true)
-Bundle_alloc :: proc() -> ^Bundle {
+Bundle_alloc :: proc "c" () -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "alloc")
 }
 
 @(objc_type=Bundle, objc_name="init")
-Bundle_init :: proc(self: ^Bundle) -> ^Bundle {
+Bundle_init :: proc "c" (self: ^Bundle) -> ^Bundle {
 	return msgSend(^Bundle, self, "init")
 }
 
 @(objc_type=Bundle, objc_name="initWithPath")
-Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle {
+Bundle_initWithPath :: proc "c" (self: ^Bundle, path: ^String) -> ^Bundle {
 	return msgSend(^Bundle, self, "initWithPath:", path)
 }
 
 @(objc_type=Bundle, objc_name="initWithURL")
-Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle {
+Bundle_initWithURL :: proc "c" (self: ^Bundle, url: ^URL) -> ^Bundle {
 	return msgSend(^Bundle, self, "initWithUrl:", url)
 }
 
 @(objc_type=Bundle, objc_name="allBundles")
-Bundle_allBundles :: proc() -> (all: ^Array) {
+Bundle_allBundles :: proc "c" () -> (all: ^Array) {
 	return msgSend(type_of(all), Bundle, "allBundles")
 }
 
 @(objc_type=Bundle, objc_name="allFrameworks")
-Bundle_allFrameworks :: proc() -> (all: ^Array) {
+Bundle_allFrameworks :: proc "c" () -> (all: ^Array) {
 	return msgSend(type_of(all), Bundle, "allFrameworks")
 }
 
 @(objc_type=Bundle, objc_name="load")
-Bundle_load :: proc(self: ^Bundle) -> BOOL {
+Bundle_load :: proc "c" (self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "load")
 }
 @(objc_type=Bundle, objc_name="unload")
-Bundle_unload :: proc(self: ^Bundle) -> BOOL {
+Bundle_unload :: proc "c" (self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "unload")
 }
 
 @(objc_type=Bundle, objc_name="isLoaded")
-Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL {
+Bundle_isLoaded :: proc "c" (self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "isLoaded")
 }
 
 @(objc_type=Bundle, objc_name="preflightAndReturnError")
-Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
+Bundle_preflightAndReturnError :: proc "contextless" (self: ^Bundle) -> (ok: BOOL, error: ^Error) {
 	ok = msgSend(BOOL, self, "preflightAndReturnError:", &error)
 	return
 }
 
 @(objc_type=Bundle, objc_name="loadAndReturnError")
-Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
+Bundle_loadAndReturnError :: proc "contextless" (self: ^Bundle) -> (ok: BOOL, error: ^Error) {
 	ok = msgSend(BOOL, self, "loadAndReturnError:", &error)
 	return
 }
 
 @(objc_type=Bundle, objc_name="bundleURL")
-Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_bundleURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "bundleURL")
 }
 
 @(objc_type=Bundle, objc_name="resourceURL")
-Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_resourceURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "resourceURL")
 }
 
 @(objc_type=Bundle, objc_name="executableURL")
-Bundle_executableURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_executableURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "executableURL")
 }
 
 @(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable")
-Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL {
+Bundle_URLForAuxiliaryExecutable :: proc "c" (self: ^Bundle, executableName: ^String) -> ^URL {
 	return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName)
 }
 
 @(objc_type=Bundle, objc_name="privateFrameworksURL")
-Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_privateFrameworksURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "privateFrameworksURL")
 }
 
 @(objc_type=Bundle, objc_name="sharedFrameworksURL")
-Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_sharedFrameworksURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "sharedFrameworksURL")
 }
 
 @(objc_type=Bundle, objc_name="sharedSupportURL")
-Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_sharedSupportURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "sharedSupportURL")
 }
 
 @(objc_type=Bundle, objc_name="builtInPlugInsURL")
-Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_builtInPlugInsURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "builtInPlugInsURL")
 }
 
 @(objc_type=Bundle, objc_name="appStoreReceiptURL")
-Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL {
+Bundle_appStoreReceiptURL :: proc "c" (self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "appStoreReceiptURL")
 }
 
 @(objc_type=Bundle, objc_name="bundlePath")
-Bundle_bundlePath :: proc(self: ^Bundle) -> ^String {
+Bundle_bundlePath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "bundlePath")
 }
 
 @(objc_type=Bundle, objc_name="resourcePath")
-Bundle_resourcePath :: proc(self: ^Bundle) -> ^String {
+Bundle_resourcePath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "resourcePath")
 }
 
 @(objc_type=Bundle, objc_name="executablePath")
-Bundle_executablePath :: proc(self: ^Bundle) -> ^String {
+Bundle_executablePath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "executablePath")
 }
 
 @(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable")
-Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String {
+Bundle_PathForAuxiliaryExecutable :: proc "c" (self: ^Bundle, executableName: ^String) -> ^String {
 	return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName)
 }
 
 @(objc_type=Bundle, objc_name="privateFrameworksPath")
-Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String {
+Bundle_privateFrameworksPath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "privateFrameworksPath")
 }
 
 @(objc_type=Bundle, objc_name="sharedFrameworksPath")
-Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String {
+Bundle_sharedFrameworksPath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "sharedFrameworksPath")
 }
 
 @(objc_type=Bundle, objc_name="sharedSupportPath")
-Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String {
+Bundle_sharedSupportPath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "sharedSupportPath")
 }
 
 @(objc_type=Bundle, objc_name="builtInPlugInsPath")
-Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String {
+Bundle_builtInPlugInsPath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "builtInPlugInsPath")
 }
 
 @(objc_type=Bundle, objc_name="appStoreReceiptPath")
-Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String {
+Bundle_appStoreReceiptPath :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "appStoreReceiptPath")
 }
 
 @(objc_type=Bundle, objc_name="bundleIdentifier")
-Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String {
+Bundle_bundleIdentifier :: proc "c" (self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "bundleIdentifier")
 }
 
 @(objc_type=Bundle, objc_name="infoDictionary")
-Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
+Bundle_infoDictionary :: proc "c" (self: ^Bundle) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "infoDictionary")
 }
 
 @(objc_type=Bundle, objc_name="localizedInfoDictionary")
-Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
+Bundle_localizedInfoDictionary :: proc "c" (self: ^Bundle) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "localizedInfoDictionary")
 }
 
 @(objc_type=Bundle, objc_name="objectForInfoDictionaryKey")
-Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object {
+Bundle_objectForInfoDictionaryKey :: proc "c" (self: ^Bundle, key: ^String) -> ^Object {
 	return msgSend(^Object, self, "objectForInfoDictionaryKey:", key)
 }
 
 @(objc_type=Bundle, objc_name="localizedStringForKey")
-Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String {
+Bundle_localizedStringForKey :: proc "c" (self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String {
 	return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName)
 }

Some files were not shown because too many files changed in this diff