Browse Source

Merge branch 'odin-lang:master' into attr_error

jon lipstate 2 năm trước cách đây
mục cha
commit
b223bc0302
100 tập tin đã thay đổi với 3902 bổ sung2491 xóa
  1. 12 12
      .github/workflows/ci.yml
  2. 3 3
      .github/workflows/nightly.yml
  3. 9 4
      build_odin.sh
  4. 5 0
      core/bytes/buffer.odin
  5. 4 8
      core/compress/shoco/shoco.odin
  6. 137 78
      core/container/bit_array/bit_array.odin
  7. 11 11
      core/container/queue/queue.odin
  8. 73 0
      core/encoding/hex/hex.odin
  9. 3 3
      core/encoding/json/marshal.odin
  10. 10 1
      core/encoding/json/parser.odin
  11. 4 12
      core/fmt/fmt.odin
  12. 5 5
      core/image/common.odin
  13. 5 5
      core/image/png/png.odin
  14. 2 2
      core/image/qoi/qoi.odin
  15. 2 2
      core/image/tga/tga.odin
  16. 1 0
      core/intrinsics/intrinsics.odin
  17. 21 8
      core/io/util.odin
  18. 161 84
      core/math/bits/bits.odin
  19. 76 41
      core/math/ease/ease.odin
  20. 11 0
      core/math/fixed/fixed.odin
  21. 124 65
      core/math/linalg/extended.odin
  22. 94 56
      core/math/linalg/general.odin
  23. 351 351
      core/math/linalg/glsl/linalg_glsl.odin
  24. 50 48
      core/math/linalg/glsl/linalg_glsl_math.odin
  25. 350 350
      core/math/linalg/hlsl/linalg_hlsl.odin
  26. 58 56
      core/math/linalg/hlsl/linalg_hlsl_math.odin
  27. 224 112
      core/math/linalg/specific.odin
  28. 200 100
      core/math/linalg/specific_euler_angles_f16.odin
  29. 200 100
      core/math/linalg/specific_euler_angles_f32.odin
  30. 200 100
      core/math/linalg/specific_euler_angles_f64.odin
  31. 64 32
      core/math/linalg/swizzle.odin
  32. 289 225
      core/math/math.odin
  33. 27 23
      core/math/math_basic.odin
  34. 27 26
      core/math/math_basic_js.odin
  35. 14 12
      core/math/math_erf.odin
  36. 10 9
      core/math/math_gamma.odin
  37. 10 8
      core/math/math_lgamma.odin
  38. 9 8
      core/math/math_log1p.odin
  39. 9 0
      core/math/noise/opensimplex2.odin
  40. 26 0
      core/math/rand/distributions.odin
  41. 1 0
      core/math/rand/exp.odin
  42. 1 0
      core/math/rand/normal.odin
  43. 18 7
      core/math/rand/rand.odin
  44. 1 0
      core/math/rand/system_darwin.odin
  45. 1 0
      core/math/rand/system_linux.odin
  46. 1 0
      core/math/rand/system_windows.odin
  47. 33 33
      core/mem/alloc.odin
  48. 19 3
      core/mem/allocators.odin
  49. 28 0
      core/mem/mem.odin
  50. 4 0
      core/net/dns.odin
  51. 19 2
      core/net/socket_darwin.odin
  52. 14 40
      core/net/url.odin
  53. 5 1
      core/odin/ast/clone.odin
  54. 27 10
      core/os/file_windows.odin
  55. 1 1
      core/os/os.odin
  56. 1 1
      core/os/os2/env_linux.odin
  57. 39 86
      core/os/os2/file_linux.odin
  58. 1 1
      core/os/os2/heap_linux.odin
  59. 1 1
      core/os/os2/heap_windows.odin
  60. 5 17
      core/os/os2/path_linux.odin
  61. 5 12
      core/os/os2/stat_linux.odin
  62. 6 6
      core/os/os2/user.odin
  63. 22 3
      core/os/os_darwin.odin
  64. 12 5
      core/prof/spall/spall.odin
  65. 80 77
      core/runtime/core_builtin.odin
  66. 19 19
      core/runtime/core_builtin_matrix.odin
  67. 7 5
      core/runtime/core_builtin_soa.odin
  68. 89 24
      core/runtime/dynamic_map_internal.odin
  69. 36 0
      core/runtime/internal.odin
  70. 1 1
      core/runtime/os_specific_windows.odin
  71. 67 19
      core/slice/slice.odin
  72. 8 1
      core/slice/sort.odin
  73. 3 3
      core/strings/strings.odin
  74. 7 3
      core/sync/futex_openbsd.odin
  75. 8 2
      core/sync/primitives_openbsd.odin
  76. 9 2
      core/sys/info/cpu_intel.odin
  77. 22 22
      core/sys/wasm/wasi/wasi_api.odin
  78. 2 1
      core/sys/windows/kernel32.odin
  79. 3 1
      core/sys/windows/user32.odin
  80. 2 2
      core/text/edit/text_edit.odin
  81. 2 2
      core/time/perf.odin
  82. 6 0
      core/time/time.odin
  83. 23 18
      core/unicode/utf8/utf8.odin
  84. 2 0
      examples/all/all_vendor.odin
  85. 1 3
      examples/demo/demo.odin
  86. 28 6
      src/build_settings.cpp
  87. 83 0
      src/check_builtin.cpp
  88. 14 10
      src/check_decl.cpp
  89. 53 31
      src/check_expr.cpp
  90. 26 2
      src/check_stmt.cpp
  91. 3 3
      src/check_type.cpp
  92. 2 2
      src/checker.cpp
  93. 2 0
      src/checker_builtin_procs.hpp
  94. 68 12
      src/docs_writer.cpp
  95. 14 3
      src/error.cpp
  96. 27 10
      src/llvm_abi.cpp
  97. 26 15
      src/llvm_backend.cpp
  98. 1 1
      src/llvm_backend.hpp
  99. 1 1
      src/llvm_backend_const.cpp
  100. 1 1
      src/llvm_backend_debug.cpp

+ 12 - 12
.github/workflows/ci.yml

@@ -104,13 +104,13 @@ jobs:
         run: ./odin check examples/all -vet -strict-style -target:linux_arm64
         timeout-minutes: 10
   build_windows:
-    runs-on: windows-2019
+    runs-on: windows-2022
     steps:
       - uses: actions/checkout@v1
       - name: build Odin
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           ./build.bat 1
       - name: Odin version
         run: ./odin version
@@ -121,65 +121,65 @@ jobs:
       - name: Odin check
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin check examples/demo -vet
         timeout-minutes: 10
       - name: Odin run
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin run examples/demo
         timeout-minutes: 10
       - name: Odin run -debug
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin run examples/demo -debug
         timeout-minutes: 10
       - name: Odin check examples/all
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin check examples/all -strict-style
         timeout-minutes: 10
       - name: Core library tests
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           cd tests\core
           call build.bat
         timeout-minutes: 10
       - name: Vendor library tests
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           cd tests\vendor
           call build.bat
         timeout-minutes: 10
       - name: Odin internals tests
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           cd tests\internal
           call build.bat
         timeout-minutes: 10
       - name: Odin documentation tests
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           cd tests\documentation
           call build.bat
         timeout-minutes: 10
       - name: core:math/big tests
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           cd tests\core\math\big
           call build.bat
         timeout-minutes: 10
       - name: Odin check examples/all for Windows 32bits
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin check examples/all -strict-style -target:windows_i386
         timeout-minutes: 10

+ 3 - 3
.github/workflows/nightly.yml

@@ -7,18 +7,18 @@ on:
 
 jobs:
   build_windows:
-    runs-on: windows-2019
+    runs-on: windows-2022
     steps:
       - uses: actions/checkout@v1
       - name: build Odin
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           ./build.bat 1 1
       - name: Odin run
         shell: cmd
         run: |
-          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin run examples/demo
       - name: Copy artifacts
         run: |

+ 9 - 4
build_odin.sh

@@ -4,14 +4,12 @@ set -eu
 : ${CXX=clang++}
 : ${CPPFLAGS=}
 : ${CXXFLAGS=}
-: ${INCLUDE_DIRECTORIES=}
 : ${LDFLAGS=}
 : ${ODIN_VERSION=dev-$(date +"%Y-%m")}
 : ${GIT_SHA=}
 
 CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
 CXXFLAGS="$CXXFLAGS -std=c++14"
-INCLUDE_DIRECTORIES="$INCLUDE_DIRECTORIES -Isrc/"
 LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
 
 if [ -d ".git" ]; then
@@ -137,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"
@@ -148,7 +153,7 @@ build_odin() {
 	esac
 
 	set -x
-	$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $INCLUDE_DIRECTORIES $EXTRAFLAGS $LDFLAGS -o odin
+	$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
 	set +x
 }
 

+ 5 - 0
core/bytes/buffer.odin

@@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
 }
 
 buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
+	if b.buf == nil {
+		b.buf = make([dynamic]byte, len, cap, allocator)
+		return
+	}
+
 	b.buf.allocator = allocator
 	reserve(&b.buf, cap)
 	resize(&b.buf, len)

+ 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}

+ 137 - 78
core/container/bit_array/bit_array.odin

@@ -27,27 +27,28 @@ Bit_Array_Iterator :: struct {
 	word_idx: int,
 	bit_idx:  uint,
 }
-
 /*
-	In:
-		- ba:   ^Bit_Array - the array to iterate over
+Wraps a `Bit_Array` into an Iterator
+
+Inputs:
+- ba: Pointer to the Bit_Array
 
-	Out:
-		- it:   ^Bit_Array_Iterator - the iterator that holds iteration state
+Returns:
+- it: Iterator struct
 */
 make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
 	return Bit_Array_Iterator { array = ba }
 }
-
 /*
-	In:
-		- it:    ^Bit_Array_Iterator - the iterator struct that holds the state.
-
-	Out:
-		- set:    bool - the state of the bit at `index`
-		- index:  int - the next bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more bits
+Returns the next bit, including its set-state. ok=false once exhausted
+
+Inputs:
+- it: The iterator that holds the state.
+
+Returns:
+- set: `true` if the bit at `index` is set.
+- index: The next bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
 	index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
@@ -64,39 +65,51 @@ iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok:
 
 	return set, index, true
 }
-
 /*
-	In:
-		- it:     ^Bit_Array_Iterator - the iterator struct that holds the state.
+Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
+
+Inputs:
+- it: The iterator that holds the state.
 
-	Out:
-		- index:  int - the next set bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more bits set
+Returns:
+- index: The next *set* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
 	return iterate_internal_(it, true)
 }
-
 /*
-	In:
-		- it:	  ^Bit_Array_Iterator - the iterator struct that holds the state.
+Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
+
+Inputs:
+- it: The iterator that holds the state.
 
-	Out:
-		- index:  int - the next unset bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more unset bits
+Returns:
+- index: The next *unset* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
 	return iterate_internal_(it, false)
 }
+/*
+Iterates through set/unset bits
 
+*Private*
+
+Inputs:
+- it: The iterator that holds the state.
+- ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
+
+Returns:
+- index: The next *unset* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
+*/
 @(private="file")
 iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
 	word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
 	when ! ITERATE_SET_BITS { word = ~word }
 
-	// if the word is empty or we have already gone over all the bits in it,
+	// If the word is empty or we have already gone over all the bits in it,
 	// b.bit_idx is greater than the index of any set bit in the word,
 	// meaning that word >> b.bit_idx == 0.
 	for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
@@ -106,14 +119,14 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
 		when ! ITERATE_SET_BITS { word = ~word }
 	}
 
-	// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
+	// If we are iterating the set bits, reaching the end of the array means we have no more bits to check
 	when ITERATE_SET_BITS {
 		if it.word_idx >= len(it.array.bits) {
 			return 0, false
 		}
 	}
 
-	// reaching here means that the word has some set bits
+	// Reaching here means that the word has some set bits
 	it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
 	index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
 
@@ -124,24 +137,21 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
 	}
 	return index, index <= it.array.max_index
 }
-
-
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Gets the state of a bit in the bit-array
 
-	Out:
-		- res:   The bit you're interested in.
-		- ok:    Whether the index was valid. Returns `false` if the index is smaller than the bias.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 
-	The `ok` return value may be ignored.
+Returns:
+- res: `true` if the bit at `index` is set.
+- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
 */
-get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
+get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
 	idx := int(index) - ba.bias
 
 	if ba == nil || int(index) < ba.bias { return false, false }
-	context.allocator = allocator
 
 	leg_index := idx >> INDEX_SHIFT
 	bit_index := idx &  INDEX_MASK
@@ -157,18 +167,36 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
 
 	return res, true
 }
+/*
+Gets the state of a bit in the bit-array
+
+*Bypasses all Checks*
+
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 
+Returns:
+- `true` if bit is set
+*/
+unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
+	return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
+}
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Sets the state of a bit in the bit-array
+
+*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
 
-	Out:
-		- ok:    Whether or not we managed to set requested bit.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+- set_to: `true` sets the bit on, `false` to turn it off
+- allocator: (default is context.allocator)
 
-	`set` automatically resizes the Bit Array to accommodate the requested index if needed.
+Returns:
+- ok: Whether the set was successful, `false` on allocation failure or bad index
 */
-set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
 
 	idx := int(index) - ba.bias
 
@@ -181,65 +209,97 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
 	resize_if_needed(ba, leg_index) or_return
 
 	ba.max_index = max(idx, ba.max_index)
-	ba.bits[leg_index] |= 1 << uint(bit_index)
+
+	if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) }
+	else { ba.bits[leg_index] &= ~(1 << uint(bit_index)) }
+
 	return true
 }
-
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Sets the state of a bit in the bit-array
 
-	Out:
-		- ok:    Whether or not we managed to unset requested bit.
+*Bypasses all checks*
 
-	`unset` automatically resizes the Bit Array to accommodate the requested index if needed.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 */
-unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
+	ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
+}
+/*
+Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
 
-	idx := int(index) - ba.bias
+*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
 
-	if ba == nil || int(index) < ba.bias { return false }
-	context.allocator = allocator
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+- allocator: (default is context.allocator)
 
-	leg_index := idx >> INDEX_SHIFT
-	bit_index := idx &  INDEX_MASK
+Returns:
+- ok: Whether the unset was successful, `false` on allocation failure or bad index
+*/
+unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+	return set(ba, index, false, allocator)
+}
+/*
+Unsets the state of a bit in the bit-array
 
-	resize_if_needed(ba, leg_index) or_return
+*Bypasses all Checks*
 
-	ba.max_index = max(idx, ba.max_index)
-	ba.bits[leg_index] &= ~(1 << uint(bit_index))
-	return true
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+*/
+unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
+	b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK))
 }
-
 /*
-	A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
+A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
+
+*Allocates (`new(Bit_Array) & make(ba.bits)`)*
+
+Inputs:
+- max_index: maximum starting index
+- min_index: minimum starting index (used as a bias)
+- allocator: (default is context.allocator)
+
+Returns:
+- ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
 */
-create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
+create :: proc(max_index: int, min_index: int = 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
 	context.allocator = allocator
 	size_in_bits := max_index - min_index
 
 	if size_in_bits < 1 { return {}, false }
 
 	legs := size_in_bits >> INDEX_SHIFT
-
+	if size_in_bits & INDEX_MASK > 0 {legs+=1}
+	bits, err := make([dynamic]u64, legs)
+	ok = err == mem.Allocator_Error.None
 	res = new(Bit_Array)
+	res.bits         = bits
 	res.bias         = min_index
 	res.max_index    = max_index
 	res.free_pointer = true
-	return res, resize_if_needed(res, legs)
+	return
 }
-
 /*
-	Sets all bits to `false`.
+Sets all values in the Bit_Array to zero.
+
+Inputs:
+- ba: The target Bit_Array
 */
 clear :: proc(ba: ^Bit_Array) {
 	if ba == nil { return }
 	mem.zero_slice(ba.bits[:])
 }
-
 /*
-	Releases the memory used by the Bit Array.
+Deallocates the Bit_Array and its backing storage
+
+Inputs:
+- ba: The target Bit_Array
 */
 destroy :: proc(ba: ^Bit_Array) {
 	if ba == nil { return }
@@ -248,9 +308,8 @@ destroy :: proc(ba: ^Bit_Array) {
 		free(ba)
 	}
 }
-
 /*
-	Resizes the Bit Array. For internal use.
+	Resizes the Bit Array. For internal use. Provisions needed capacity+1
 	If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
 */
 @(private="file")

+ 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
 }

+ 73 - 0
core/encoding/hex/hex.odin

@@ -0,0 +1,73 @@
+package hex
+
+import "core:strings"
+
+encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check {
+	dst := make([]byte, len(src) * 2, allocator)
+	for i, j := 0, 0; i < len(src); i += 1 {
+		v := src[i]
+		dst[j]   = HEXTABLE[v>>4]
+		dst[j+1] = HEXTABLE[v&0x0f]
+		j += 2
+	}
+
+	return dst
+}
+
+
+decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check {
+	if len(src) % 2 == 1 {
+		return
+	}
+
+	dst = make([]byte, len(src) / 2, allocator)
+	for i, j := 0, 1; j < len(src); j += 2 {
+		p := src[j-1]
+		q := src[j]
+
+		a := hex_digit(p) or_return
+		b := hex_digit(q) or_return
+
+		dst[i] = (a << 4) | b
+		i += 1
+	}
+
+	return dst, true
+}
+
+// Decodes the given sequence into one byte.
+// Should be called with one byte worth of the source, eg: 0x23 -> '#'.
+decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
+	str := str
+	if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
+		str = str[2:]
+	}
+
+	if len(str) != 2 {
+		return 0, false
+	}
+
+	upper := hex_digit(str[0]) or_return
+	lower := hex_digit(str[1]) or_return
+
+	return upper << 4 | lower, true
+}
+
+@(private)
+HEXTABLE := [16]byte {
+	'0', '1', '2', '3',
+	'4', '5', '6', '7',
+	'8', '9', 'a', 'b',
+	'c', 'd', 'e', 'f',
+}
+
+@(private)
+hex_digit :: proc(char: byte) -> (u8, bool) {
+	switch char {
+	case '0' ..= '9': return char - '0', true
+	case 'a' ..= 'f': return char - 'a' + 10, true
+	case 'A' ..= 'F': return char - 'A' + 10, true
+	case:             return 0, false
+	}
+}
+

+ 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'

+ 4 - 12
core/fmt/fmt.odin

@@ -2647,18 +2647,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

+ 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) }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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)

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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)

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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]}
 }
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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
 

+ 18 - 7
core/math/rand/rand.odin

@@ -16,6 +16,7 @@ set_global_seed :: proc(seed: u64) {
 	init(&global_rand, seed)
 }
 
+@(require_results)
 create :: proc(seed: u64) -> Rand {
 	r: Rand
 	init(&r, seed)
@@ -60,14 +61,17 @@ _random :: proc(r: ^Rand) -> u32 {
 	return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
 }
 
+@(require_results)
 uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) }
 
+@(require_results)
 uint64 :: proc(r: ^Rand = nil) -> u64 {
 	a := u64(_random(r))
 	b := u64(_random(r))
 	return (a<<32) | b
 }
 
+@(require_results)
 uint128 :: proc(r: ^Rand = nil) -> u128 {
 	a := u128(_random(r))
 	b := u128(_random(r))
@@ -76,10 +80,11 @@ 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) }
+@(require_results) int31  :: proc(r: ^Rand = nil) -> i32  { return i32(uint32(r) << 1 >> 1) }
+@(require_results) int63  :: proc(r: ^Rand = nil) -> i64  { return i64(uint64(r) << 1 >> 1) }
+@(require_results) int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) }
 
+@(require_results)
 int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
 	if n <= 0 {
 		panic("Invalid argument to int31_max")
@@ -95,6 +100,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
 	return v % n
 }
 
+@(require_results)
 int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
 	if n <= 0 {
 		panic("Invalid argument to int63_max")
@@ -110,6 +116,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
 	return v % n
 }
 
+@(require_results)
 int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
 	if n <= 0 {
 		panic("Invalid argument to int127_max")
@@ -125,6 +132,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
 	return v % n
 }
 
+@(require_results)
 int_max :: proc(n: int, r: ^Rand = nil) -> int {
 	if n <= 0 {
 		panic("Invalid argument to int_max")
@@ -137,13 +145,14 @@ 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) }
+@(require_results) 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)) }
+@(require_results) float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) }
 
-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 }
+@(require_results) float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo }
+@(require_results) float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo }
 
+@(require_results)
 read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
 	pos := i8(0)
 	val := i64(0)
@@ -160,6 +169,7 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
 }
 
 // perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
+@(require_results)
 perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int {
 	m := make([]int, n, allocator)
 	for i := 0; i < n; i += 1 {
@@ -184,6 +194,7 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
 }
 
 // Returns a random element from the given slice
+@(require_results)
 choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
 	n := i64(len(array))
 	if n < 1 {

+ 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 {

+ 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

+ 14 - 40
core/net/url.odin

@@ -19,7 +19,7 @@ package net
 import "core:strings"
 import "core:strconv"
 import "core:unicode/utf8"
-import "core:mem"
+import "core:encoding/hex"
 
 split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) {
 	s := url
@@ -36,9 +36,11 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
 		s = s[:i]
 		if query_str != "" {
 			queries_parts := strings.split(query_str, "&")
+			defer delete(queries_parts)
 			queries = make(map[string]string, len(queries_parts), allocator)
 			for q in queries_parts {
 				parts := strings.split(q, "=")
+				defer delete(parts)
 				switch len(parts) {
 				case 1:  queries[parts[0]] = ""        // NOTE(tetra): Query not set to anything, was but present.
 				case 2:  queries[parts[0]] = parts[1]  // NOTE(tetra): Query set to something.
@@ -76,13 +78,19 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat
 	}
 
 
-	if len(queries) > 0 do write_string(&b, "?")
+	query_length := len(queries)
+	if query_length > 0 do write_string(&b, "?")
+	i := 0
 	for query_name, query_value in queries {
 		write_string(&b, query_name)
 		if query_value != "" {
 			write_string(&b, "=")
 			write_string(&b, query_value)
 		}
+		if i < query_length - 1 {
+			write_string(&b, "&")
+		}
+		i += 1
 	}
 
 	return to_string(b)
@@ -119,12 +127,10 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
 	builder_grow(&b, len(encoded_string))
 	defer if !ok do builder_destroy(&b)
 
-	stack_buf: [4]u8
-	pending := mem.buffer_from_slice(stack_buf[:])
 	s := encoded_string
 
 	for len(s) > 0 {
-		i := index_rune(s, '%')
+		i := index_byte(s, '%')
 		if i == -1 {
 			write_string(&b, s) // no '%'s; the string is already decoded
 			break
@@ -137,47 +143,15 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
 		s = s[1:]
 
 		if s[0] == '%' {
-			write_rune(&b, '%')
+			write_byte(&b, '%')
 			s = s[1:]
 			continue
 		}
 
 		if len(s) < 2 do return // percent without encoded value
 
-		n: int
-		n, _ = strconv.parse_int(s[:2], 16)
-		switch n {
-		case 0x20:  write_rune(&b, ' ')
-		case 0x21:  write_rune(&b, '!')
-		case 0x23:  write_rune(&b, '#')
-		case 0x24:  write_rune(&b, '$')
-		case 0x25:  write_rune(&b, '%')
-		case 0x26:  write_rune(&b, '&')
-		case 0x27:  write_rune(&b, '\'')
-		case 0x28:  write_rune(&b, '(')
-		case 0x29:  write_rune(&b, ')')
-		case 0x2A:  write_rune(&b, '*')
-		case 0x2B:  write_rune(&b, '+')
-		case 0x2C:  write_rune(&b, ',')
-		case 0x2F:  write_rune(&b, '/')
-		case 0x3A:  write_rune(&b, ':')
-		case 0x3B:  write_rune(&b, ';')
-		case 0x3D:  write_rune(&b, '=')
-		case 0x3F:  write_rune(&b, '?')
-		case 0x40:  write_rune(&b, '@')
-		case 0x5B:  write_rune(&b, '[')
-		case 0x5D:  write_rune(&b, ']')
-		case:
-			// utf-8 bytes
-			// TODO(tetra): Audit this - 4 bytes???
-			append(&pending, s[0])
-			append(&pending, s[1])
-			if len(pending) == 4 {
-				r, _ := utf8.decode_rune(pending[:])
-				write_rune(&b, r)
-				clear(&pending)
-			}
-		}
+		val := hex.decode_sequence(s[:2]) or_return
+		write_byte(&b, val)
 		s = s[2:]
 	}
 

+ 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)^

+ 27 - 10
core/os/file_windows.odin

@@ -220,6 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
 
 @(private)
 MAX_RW :: 1<<30
+ERROR_EOF :: 38
 
 @(private)
 pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
@@ -228,11 +229,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 		buf = buf[:MAX_RW]
 
 	}
-	curr_offset, e := seek(fd, offset, 1)
-	if e != 0 {
-		return 0, e
-	}
-	defer seek(fd, curr_offset, 0)
 
 	o := win32.OVERLAPPED{
 		OffsetHigh = u32(offset>>32),
@@ -243,6 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 
 	h := win32.HANDLE(fd)
 	done: win32.DWORD
+	e: Errno
 	if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
 		e = Errno(win32.GetLastError())
 		done = 0
@@ -256,11 +253,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 		buf = buf[:MAX_RW]
 
 	}
-	curr_offset, e := seek(fd, offset, 1)
-	if e != 0 {
-		return 0, e
-	}
-	defer seek(fd, curr_offset, 0)
 
 	o := win32.OVERLAPPED{
 		OffsetHigh = u32(offset>>32),
@@ -269,6 +261,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 
 	h := win32.HANDLE(fd)
 	done: win32.DWORD
+	e: Errno
 	if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
 		e = Errno(win32.GetLastError())
 		done = 0
@@ -276,6 +269,16 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 	return int(done), e
 }
 
+/*
+read_at returns n: 0, err: 0 on EOF
+on Windows, read_at changes the position of the file cursor, on *nix, it does not.
+
+	bytes: [8]u8{}
+	read_at(fd, bytes, 0)
+	read(fd, bytes)
+
+will read from the location twice on *nix, and from two different locations on Windows
+*/
 read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
 	if offset < 0 {
 		return 0, ERROR_NEGATIVE_OFFSET
@@ -284,6 +287,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
 	b, offset := data, offset
 	for len(b) > 0 {
 		m, e := pread(fd, b, offset)
+		if e == ERROR_EOF {
+			err = 0
+			break
+		}
 		if e != 0 {
 			err = e
 			break
@@ -294,6 +301,16 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
 	}
 	return
 }
+
+/*
+on Windows, write_at changes the position of the file cursor, on *nix, it does not.
+
+	bytes: [8]u8{}
+	write_at(fd, bytes, 0)
+	write(fd, bytes)
+
+will write to the location twice on *nix, and to two different locations on Windows
+*/
 write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
 	if offset < 0 {
 		return 0, ERROR_NEGATIVE_OFFSET

+ 1 - 1
core/os/os.odin

@@ -194,7 +194,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 		ptr := uintptr(aligned_mem)
 		aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
 		diff := int(aligned_ptr - ptr)
-		if (size + diff) > space {
+		if (size + diff) > space || allocated_mem == nil {
 			return nil, .Out_Of_Memory
 		}
 

+ 1 - 1
core/os/os2/env_linux.odin

@@ -3,7 +3,7 @@ package os2
 
 import "core:runtime"
 
-_get_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	//TODO
 	return
 }

+ 39 - 86
core/os/os2/file_linux.odin

@@ -9,19 +9,20 @@ import "core:sys/unix"
 
 INVALID_HANDLE :: -1
 
-_O_RDONLY    :: 0o0
-_O_WRONLY    :: 0o1
-_O_RDWR      :: 0o2
-_O_CREAT     :: 0o100
-_O_EXCL      :: 0o200
-_O_TRUNC     :: 0o1000
-_O_APPEND    :: 0o2000
-_O_NONBLOCK  :: 0o4000
-_O_LARGEFILE :: 0o100000
-_O_DIRECTORY :: 0o200000
-_O_NOFOLLOW  :: 0o400000
-_O_SYNC      :: 0o4010000
-_O_CLOEXEC   :: 0o2000000
+_O_RDONLY    :: 0o00000000
+_O_WRONLY    :: 0o00000001
+_O_RDWR      :: 0o00000002
+_O_CREAT     :: 0o00000100
+_O_EXCL      :: 0o00000200
+_O_NOCTTY    :: 0o00000400
+_O_TRUNC     :: 0o00001000
+_O_APPEND    :: 0o00002000
+_O_NONBLOCK  :: 0o00004000
+_O_LARGEFILE :: 0o00100000
+_O_DIRECTORY :: 0o00200000
+_O_NOFOLLOW  :: 0o00400000
+_O_SYNC      :: 0o04010000
+_O_CLOEXEC   :: 0o02000000
 _O_PATH      :: 0o10000000
 
 _AT_FDCWD :: -100
@@ -40,9 +41,12 @@ _file_allocator :: proc() -> runtime.Allocator {
 
 _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
 	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
-	name_cstr := _name_to_cstring(name)
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 
-	flags_i: int
+	// Just default to using O_NOCTTY because needing to open a controlling
+	// terminal would be incredibly rare. This has no effect on files while
+	// allowing us to open serial devices.
+	flags_i: int = _O_NOCTTY
 	switch flags & O_RDONLY|O_WRONLY|O_RDWR {
 	case O_RDONLY: flags_i = _O_RDONLY
 	case O_WRONLY: flags_i = _O_WRONLY
@@ -56,7 +60,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error
 	flags_i |= (_O_TRUNC * int(.Trunc in flags))
 	flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags))
 
-	fd := unix.sys_open(name_cstr, flags_i, int(perm))
+	fd := unix.sys_open(name_cstr, flags_i, uint(perm))
 	if fd < 0 {
 		return nil, _get_platform_error(fd)
 	}
@@ -196,10 +200,7 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
 }
 
 _remove :: proc(name: string) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 
 	fd := unix.sys_open(name_cstr, int(File_Flags.Read))
 	if fd < 0 {
@@ -214,40 +215,22 @@ _remove :: proc(name: string) -> Error {
 }
 
 _rename :: proc(old_name, new_name: string) -> Error {
-	old_name_cstr, old_allocated := _name_to_cstring(old_name)
-	new_name_cstr, new_allocated := _name_to_cstring(new_name)
-	defer if old_allocated {
-		delete(old_name_cstr)
-	}
-	defer if new_allocated {
-		delete(new_name_cstr)
-	}
+	old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
+	new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
 
 	return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr))
 }
 
 _link :: proc(old_name, new_name: string) -> Error {
-	old_name_cstr, old_allocated := _name_to_cstring(old_name)
-	new_name_cstr, new_allocated := _name_to_cstring(new_name)
-	defer if old_allocated {
-		delete(old_name_cstr)
-	}
-	defer if new_allocated {
-		delete(new_name_cstr)
-	}
+	old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
+	new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
 
 	return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
 }
 
 _symlink :: proc(old_name, new_name: string) -> Error {
-	old_name_cstr, old_allocated := _name_to_cstring(old_name)
-	new_name_cstr, new_allocated := _name_to_cstring(new_name)
-	defer if old_allocated {
-		delete(old_name_cstr)
-	}
-	defer if new_allocated {
-		delete(new_name_cstr)
-	}
+	old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
+	new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
 
 	return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
 }
@@ -271,26 +254,17 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st
 }
 
 _read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return _read_link_cstr(name_cstr, allocator)
 }
 
 _unlink :: proc(name: string) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return _ok_or_error(unix.sys_unlink(name_cstr))
 }
 
 _chdir :: proc(name: string) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return _ok_or_error(unix.sys_chdir(name_cstr))
 }
 
@@ -299,32 +273,23 @@ _fchdir :: proc(f: ^File) -> Error {
 }
 
 _chmod :: proc(name: string, mode: File_Mode) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
-	return _ok_or_error(unix.sys_chmod(name_cstr, int(mode)))
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
+	return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode)))
 }
 
 _fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
-	return _ok_or_error(unix.sys_fchmod(f.impl.fd, int(mode)))
+	return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode)))
 }
 
 // NOTE: will throw error without super user priviledges
 _chown :: proc(name: string, uid, gid: int) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return _ok_or_error(unix.sys_chown(name_cstr, uid, gid))
 }
 
 // NOTE: will throw error without super user priviledges
 _lchown :: proc(name: string, uid, gid: int) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid))
 }
 
@@ -334,10 +299,7 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
 }
 
 _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	times := [2]Unix_File_Time {
 		{ atime._nsec, 0 },
 		{ mtime._nsec, 0 },
@@ -354,18 +316,12 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
 }
 
 _exists :: proc(name: string) -> bool {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	return unix.sys_access(name_cstr, F_OK) == 0
 }
 
 _is_file :: proc(name: string) -> bool {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	s: _Stat
 	res := unix.sys_stat(name_cstr, &s)
 	if res < 0 {
@@ -384,10 +340,7 @@ _is_file_fd :: proc(fd: int) -> bool {
 }
 
 _is_dir :: proc(name: string) -> bool {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	s: _Stat
 	res := unix.sys_stat(name_cstr, &s)
 	if res < 0 {

+ 1 - 1
core/os/os2/heap_linux.odin

@@ -166,7 +166,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 		ptr := uintptr(aligned_mem)
 		aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
 		diff := int(aligned_ptr - ptr)
-		if (size + diff) > space {
+		if (size + diff) > space || allocated_mem == nil {
 			return nil, .Out_Of_Memory
 		}
 

+ 1 - 1
core/os/os2/heap_windows.odin

@@ -52,7 +52,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 		ptr := uintptr(aligned_mem)
 		aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
 		diff := int(aligned_ptr - ptr)
-		if (size + diff) > space {
+		if (size + diff) > space || allocated_mem == nil {
 			return nil, .Out_Of_Memory
 		}
 

+ 5 - 17
core/os/os2/path_linux.odin

@@ -31,11 +31,8 @@ _mkdir :: proc(path: string, perm: File_Mode) -> Error {
 		return .Invalid_Argument
 	}
 
-	path_cstr, allocated := _name_to_cstring(path)
-	defer if allocated {
-		delete(path_cstr)
-	}
-	return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777)))
+	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+	return _ok_or_error(unix.sys_mkdir(path_cstr, uint(perm & 0o777)))
 }
 
 _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
@@ -49,7 +46,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 		new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
 		switch new_dfd {
 		case -ENOENT:
-			if res := unix.sys_mkdirat(dfd, cstring(&path[0]), perm); res < 0 {
+			if res := unix.sys_mkdirat(dfd, cstring(&path[0]), uint(perm)); res < 0 {
 				return _get_platform_error(res)
 			}
 			has_created^ = true
@@ -83,9 +80,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 	} else {
 		path_bytes = make([]u8, len(path) + 1, context.temp_allocator)
 	}
-	defer if allocated {
-		delete(path_bytes)
-	}
 
 	// NULL terminate the byte slice to make it a valid cstring
 	copy(path_bytes, path)
@@ -182,10 +176,7 @@ _remove_all :: proc(path: string) -> Error {
 		return nil
 	}
 
-	path_cstr, allocated := _name_to_cstring(path)
-	defer if allocated {
-		delete(path_cstr)
-	}
+	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS)
 	switch fd {
@@ -222,10 +213,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) {
 }
 
 _setwd :: proc(dir: string) -> Error {
-	dir_cstr, allocated := _name_to_cstring(dir)
-	defer if allocated {
-		delete(dir_cstr)
-	}
+	dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator)
 	return _ok_or_error(unix.sys_chdir(dir_cstr))
 }
 

+ 5 - 12
core/os/os2/stat_linux.odin

@@ -3,6 +3,7 @@ package os2
 
 import "core:time"
 import "core:runtime"
+import "core:strings"
 import "core:sys/unix"
 import "core:path/filepath"
 
@@ -112,10 +113,7 @@ _fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Er
 
 // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
 _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 
 	fd := unix.sys_open(name_cstr, _O_RDONLY)
 	if fd < 0 {
@@ -126,10 +124,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error)
 }
 
 _lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
+
 	fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
 	if fd < 0 {
 		return {}, _get_platform_error(fd)
@@ -143,10 +139,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
 }
 
 _stat_internal :: proc(name: string) -> (s: _Stat, res: int) {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	res = unix.sys_stat(name_cstr, &s)
 	return
 }

+ 6 - 6
core/os/os2/user.odin

@@ -8,12 +8,12 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
 	case .Windows:
 		dir = get_env("LocalAppData", allocator)
 		if dir != "" {
-			dir = strings.clone_safe(dir, allocator) or_return
+			dir = strings.clone(dir, allocator) or_return
 		}
 	case .Darwin:
 		dir = get_env("HOME", allocator)
 		if dir != "" {
-			dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
+			dir = strings.concatenate({dir, "/Library/Caches"}, allocator) or_return
 		}
 	case: // All other UNIX systems
 		dir = get_env("XDG_CACHE_HOME", allocator)
@@ -22,7 +22,7 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
 			if dir == "" {
 				return
 			}
-			dir = strings.concatenate_safe({dir, "/.cache"}, allocator) or_return
+			dir = strings.concatenate({dir, "/.cache"}, allocator) or_return
 		}
 	}
 	if dir == "" {
@@ -36,12 +36,12 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
 	case .Windows:
 		dir = get_env("AppData", allocator)
 		if dir != "" {
-			dir = strings.clone_safe(dir, allocator) or_return
+			dir = strings.clone(dir, allocator) or_return
 		}
 	case .Darwin:
 		dir = get_env("HOME", allocator)
 		if dir != "" {
-			dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
+			dir = strings.concatenate({dir, "/Library/Application Support"}, allocator) or_return
 		}
 	case: // All other UNIX systems
 		dir = get_env("XDG_CACHE_HOME", allocator)
@@ -50,7 +50,7 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
 			if dir == "" {
 				return
 			}
-			dir = strings.concatenate_safe({dir, "/.config"}, allocator) or_return
+			dir = strings.concatenate({dir, "/.config"}, allocator) or_return
 		}
 	}
 	if dir == "" {

+ 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
+}

+ 12 - 5
core/prof/spall/spall.odin

@@ -67,16 +67,15 @@ Buffer :: struct {
 BUFFER_DEFAULT_SIZE :: 0x10_0000
 
 
-context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok {
+context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (ctx: Context, ok: bool) #optional_ok {
 	fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600)
 	if err != os.ERROR_NONE {
 		return
 	}
-	ctx.fd = fd
 
-	freq, freq_ok := time.tsc_frequency()
-	ctx.precise_time = freq_ok
-	ctx.timestamp_scale = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1
+	ctx.fd = fd
+	ctx.precise_time = precise_time
+	ctx.timestamp_scale = timestamp_scale
 
 	temp := [size_of(Manual_Header)]u8{}
 	_build_header(temp[:], ctx.timestamp_scale)
@@ -85,6 +84,14 @@ context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_o
 	return
 }
 
+context_create_with_sleep :: proc(filename: string, sleep := 2 * time.Second) -> (ctx: Context, ok: bool) #optional_ok {
+	freq, freq_ok := time.tsc_frequency(sleep)
+	timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1
+	return context_create_with_scale(filename, freq_ok, timestamp_scale)
+}
+
+context_create :: proc{context_create_with_scale, context_create_with_sleep}
+
 context_destroy :: proc(ctx: ^Context) {
 	if ctx == nil {
 		return

+ 80 - 77
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 {
@@ -179,17 +179,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 +202,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 +213,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
 	return transmute(T)s, err
 }
 
-@(builtin)
+@(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)
+@(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)
+@(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)
+@(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 +236,7 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
 	array = transmute(T)s
 	return
 }
-@(builtin)
+@(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 +244,7 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_
 	err = reserve_map(&m, capacity, loc)
 	return
 }
-@(builtin)
+@(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
@@ -287,10 +289,9 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) ->
 	Shrinks the capacity of a map down to the current length.
 */
 @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 +314,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 +335,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 +371,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 +385,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 +402,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)
-	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 +421,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 +444,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 +467,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 +479,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 +493,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 +507,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
 	}
@@ -528,14 +534,14 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
 }
 
 @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 +553,26 @@ 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
 }
 
 @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 +584,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
 }
 
 /*
@@ -598,7 +604,7 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
 
 	If `len(array) < new_cap`, then `len(array)` will be left unchanged.
 */
-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 +624,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

+ 7 - 5
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,26 +139,26 @@ 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
+@(builtin, require_results)
 make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) {
 	context.allocator = allocator
 	reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
 	return
 }
 
-@builtin
+@(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) {
 	context.allocator = allocator
 	resize_soa(&array, length, loc)
 	return
 }
 
-@builtin
+@(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) {
 	context.allocator = allocator
 	if reserve_soa(&array, capacity, loc) {

+ 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(m))
 	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_windows.odin

@@ -112,7 +112,7 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
 	ptr := uintptr(aligned_mem)
 	aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
 	diff := int(aligned_ptr - ptr)
-	if (size + diff) > space {
+	if (size + diff) > space || allocated_mem == nil {
 		return nil, .Out_Of_Memory
 	}
 

+ 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

+ 3 - 3
core/strings/strings.odin

@@ -41,7 +41,7 @@ Returns:
 */
 @(deprecated="Prefer clone. It now returns an optional allocator error")
 clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) {
-    return clone(s, allocator, loc)
+	return clone(s, allocator, loc)
 }
 /*
 Clones a string and appends a null-byte to make it a cstring
@@ -629,7 +629,7 @@ Returns:
 */
 @(deprecated="Prefer join. It now returns an optional allocator error")
 join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
-    return join(a, sep, allocator)
+	return join(a, sep, allocator)
 }
 /*
 Returns a combined string from the slice of strings `a` without a separator
@@ -689,7 +689,7 @@ The concatenated string, and an error if allocation fails
 */
 @(deprecated="Prefer concatenate. It now returns an optional allocator error")
 concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
-    return concatenate(a, allocator)
+	return concatenate(a, allocator)
 }
 /*
 Returns a substring of the input string `s` with the specified rune offset and length

+ 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()
 }

+ 9 - 2
core/sys/info/cpu_intel.odin

@@ -38,7 +38,7 @@ cpu_name:     Maybe(string)
 @(init, private)
 init_cpu_features :: proc "c" () {
 	is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool {
-		return hwc&value != 0
+		return hwc&(1 << value) != 0
 	}
 	try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) {
 		if is_set(hwc, value) {
@@ -74,8 +74,15 @@ init_cpu_features :: proc "c" () {
 		return
 	}
 
+	// In certain rare cases (reason unknown), XGETBV generates an
+	// illegal instruction, even if OSXSAVE is set per CPUID.
+	//
+	// When Chrome ran into this problem, the problem went away
+	// after they started checking both OSXSAVE and XSAVE.
+	//
+	// See: crbug.com/375968
 	os_supports_avx := false
-	if .os_xsave in set {
+	if .os_xsave in set && is_set(26, ecx1) {
 		eax, _ := xgetbv(0)
 		os_supports_avx = is_set(1, eax) && is_set(2, eax)
 	}

+ 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 {

+ 2 - 2
core/text/edit/text_edit.odin

@@ -219,7 +219,7 @@ selection_delete :: proc(s: ^State) {
 
 translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
 	is_continuation_byte :: proc(b: byte) -> bool {
-		return b <= 0x80 && b < 0xc0
+		return b >= 0x80 && b < 0xc0
 	}
 	is_space :: proc(b: byte) -> bool {
 		return b == ' ' || b == '\t' || b == '\n'
@@ -410,4 +410,4 @@ perform_command :: proc(s: ^State, cmd: Command) {
 	case .Select_Line_Start: select_to(s, .Soft_Line_Start)
 	case .Select_Line_End:   select_to(s, .Soft_Line_End)
 	}
-}
+}

+ 2 - 2
core/time/perf.odin

@@ -70,7 +70,7 @@ has_invariant_tsc :: proc "contextless" () -> bool {
 	return false
 }
 
-tsc_frequency :: proc "contextless" () -> (u64, bool) {
+tsc_frequency :: proc "contextless" (fallback_sleep := 2 * Second) -> (u64, bool) {
 	if !has_invariant_tsc() {
 		return 0, false
 	}
@@ -81,7 +81,7 @@ tsc_frequency :: proc "contextless" () -> (u64, bool) {
 		tsc_begin := intrinsics.read_cycle_counter()
 		tick_begin := tick_now()
 
-		sleep(2 * Second)
+		sleep(fallback_sleep)
 
 		tsc_end := intrinsics.read_cycle_counter()
 		tick_end := tick_now()

+ 6 - 0
core/time/time.odin

@@ -170,6 +170,12 @@ day :: proc "contextless" (t: Time) -> (day: int) {
 	return
 }
 
+weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
+    abs := _time_abs(t)
+    sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
+    return Weekday(int(sec) / SECONDS_PER_DAY)
+}
+
 clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
 
 clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {

+ 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

+ 28 - 6
src/build_settings.cpp

@@ -262,6 +262,7 @@ struct BuildContext {
 	String microarch;
 	BuildModeKind build_mode;
 	bool   generate_docs;
+	bool   custom_optimization_level;
 	i32    optimization_level;
 	bool   show_timings;
 	TimingsExportFormat export_timings_format;
@@ -1272,6 +1273,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 		gb_exit(1);
 	}
 
+	if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
+		// NOTE(bill): when building with `-debug` but not specifying an optimization level
+		// default to `-o:none` to improve the debug symbol generation by default
+		bc->optimization_level = -1; // -o:none
+	}
+
 	bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
 
 	// ENFORCE DYNAMIC MAP CALLS
@@ -1285,9 +1292,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 			break;
 		}
 	}
-
-	#undef LINK_FLAG_X64
-	#undef LINK_FLAG_386
 }
 
 #if defined(GB_SYSTEM_WINDOWS)
@@ -1497,13 +1501,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.
@@ -1615,6 +1629,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;
 	}
 
 

+ 53 - 31
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;
 	}
 
@@ -7887,8 +7905,11 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
 			rhs.type = right_type;
 			rhs.mode = Addressing_Value;
 
-			// TODO(bill): better error message
-			if (!check_is_assignable_to(c, &rhs, end_type)) {
+			if (is_type_boolean(right_type) && is_type_boolean(end_type)) {
+				// NOTE(bill): allow implicit conversion between boolean types
+				// within 'or_return' to improve the experience using third-party code
+			} else if (!check_is_assignable_to(c, &rhs, end_type)) {
+				// TODO(bill): better error message
 				gbString a = type_to_string(right_type);
 				gbString b = type_to_string(end_type);
 				gbString ret_type = type_to_string(result_type);
@@ -9577,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;
 
 
@@ -10142,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");

+ 2 - 2
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) {

+ 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);
 

+ 14 - 3
src/error.cpp

@@ -8,8 +8,9 @@ struct ErrorCollector {
 	BlockingMutex     string_mutex;
 	RecursiveMutex    block_mutex;
 
-	Array<u8> error_buffer;
-	Array<String> errors;
+	RecursiveMutex error_buffer_mutex;
+	Array<u8>      error_buffer;
+	Array<String>  errors;
 };
 
 gb_global ErrorCollector global_error_collector;
@@ -119,6 +120,7 @@ gb_internal void begin_error_block(void) {
 }
 
 gb_internal void end_error_block(void) {
+	mutex_lock(&global_error_collector.error_buffer_mutex);
 	isize n = global_error_collector.error_buffer.count;
 	if (n > 0) {
 		u8 *text = global_error_collector.error_buffer.data;
@@ -150,11 +152,16 @@ gb_internal void end_error_block(void) {
 		text = gb_alloc_array(permanent_allocator(), u8, n+1);
 		gb_memmove(text, global_error_collector.error_buffer.data, n);
 		text[n] = 0;
+
+
+		mutex_lock(&global_error_collector.error_out_mutex);
 		String s = {text, n};
 		array_add(&global_error_collector.errors, s);
+		mutex_unlock(&global_error_collector.error_out_mutex);
+
 		global_error_collector.error_buffer.count = 0;
 	}
-
+	mutex_unlock(&global_error_collector.error_buffer_mutex);
 	global_error_collector.in_block.store(false);
 	mutex_unlock(&global_error_collector.block_mutex);
 }
@@ -172,11 +179,15 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
 	isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
 	isize n = len-1;
 	if (global_error_collector.in_block) {
+		mutex_lock(&global_error_collector.error_buffer_mutex);
+
 		isize cap = global_error_collector.error_buffer.count + n;
 		array_reserve(&global_error_collector.error_buffer, cap);
 		u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count;
 		gb_memmove(data, buf, n);
 		global_error_collector.error_buffer.count += n;
+
+		mutex_unlock(&global_error_collector.error_buffer_mutex);
 	} else {
 		mutex_lock(&global_error_collector.error_out_mutex);
 		{

+ 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);
 

+ 1 - 1
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;
 	}

+ 1 - 1
src/llvm_backend_debug.cpp

@@ -282,7 +282,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;
 		}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác