From dad97fc2d9a25b22d72c9c129b8f858f093a6408 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 8 Jan 2025 12:55:13 +0100 Subject: [PATCH] Improved `#foo` resolution inside of the compiler. Deprecation of several `&` macros. --- lib/std/hash/fnv32a.c3 | 8 +- lib/std/hash/fnv64a.c3 | 8 +- lib/std/hash/sha1.c3 | 184 ++++++++++---------- lib/std/io/stream.c3 | 34 +++- lib/std/math/bigint.c3 | 14 +- lib/std/net/socket.c3 | 2 +- lib/std/sort/binarysearch.c3 | 2 +- lib/std/sort/countingsort.c3 | 2 +- lib/std/sort/insertionsort.c3 | 2 +- lib/std/sort/quicksort.c3 | 4 +- lib/std/sort/sort.c3 | 7 +- lib/std/sort/sorted.c3 | 2 +- releasenotes.md | 2 + src/compiler/abi/c_abi_wasm.c | 2 +- src/compiler/c_codegen.c | 2 +- src/compiler/compiler_internal.h | 24 ++- src/compiler/llvm_codegen.c | 2 +- src/compiler/llvm_codegen_expr.c | 2 +- src/compiler/llvm_codegen_stmt.c | 2 +- src/compiler/sema_casts.c | 2 +- src/compiler/sema_expr.c | 100 ++++++----- src/compiler/sema_initializers.c | 3 +- src/compiler/sema_stmts.c | 2 +- test/test_suite/generic/generic_over_fn.c3t | 22 ++- 24 files changed, 247 insertions(+), 187 deletions(-) diff --git a/lib/std/hash/fnv32a.c3 b/lib/std/hash/fnv32a.c3 index ec20d3e38..24e7a1bf7 100644 --- a/lib/std/hash/fnv32a.c3 +++ b/lib/std/hash/fnv32a.c3 @@ -8,7 +8,7 @@ distinct Fnv32a = uint; const FNV32A_START @private = 0x811c9dc5; const FNV32A_MUL @private = 0x01000193; -macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV32A_MUL; +macro void update(h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV32A_MUL; fn void Fnv32a.init(&self) { @@ -20,14 +20,14 @@ fn void Fnv32a.update(&self, char[] data) Fnv32a h = *self; foreach (char x : data) { - @update(h, x); + update(&h, x); } *self = h; } macro void Fnv32a.update_char(&self, char c) { - @update(*self, c); + update(self, c); } fn uint encode(char[] data) @@ -35,7 +35,7 @@ fn uint encode(char[] data) uint h = FNV32A_START; foreach (char x : data) { - @update(h, x); + update(&h, x); } return h; } diff --git a/lib/std/hash/fnv64a.c3 b/lib/std/hash/fnv64a.c3 index 62da516e8..9b4f36378 100644 --- a/lib/std/hash/fnv64a.c3 +++ b/lib/std/hash/fnv64a.c3 @@ -8,7 +8,7 @@ distinct Fnv64a = ulong; const FNV64A_START @private = 0xcbf29ce484222325; const FNV64A_MUL @private = 0x00000100000001b3; -macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV64A_MUL; +macro void update(h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV64A_MUL; fn void Fnv64a.init(&self) { @@ -20,14 +20,14 @@ fn void Fnv64a.update(&self, char[] data) Fnv64a h = *self; foreach (char x : data) { - @update(h, x); + update(&h, x); } *self = h; } macro void Fnv64a.update_char(&self, char c) { - @update(*self, c); + update(self, c); } fn ulong encode(char[] data) @@ -35,7 +35,7 @@ fn ulong encode(char[] data) ulong h = FNV64A_START; foreach (char x : data) { - @update(h, x); + update(&h, x); } return h; } diff --git a/lib/std/hash/sha1.c3 b/lib/std/hash/sha1.c3 index 1bba448e0..473f60853 100644 --- a/lib/std/hash/sha1.c3 +++ b/lib/std/hash/sha1.c3 @@ -103,13 +103,13 @@ union Long16 @local uint[16] l; } -macro @blk(&block, i) @local +macro blk(block, i) @local { return (block.l[i & 15] = (block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ block.l[i & 15]).rotl(1)); } -macro @blk0(&block, i) @local +macro blk0(block, i) @local { $if env::BIG_ENDIAN: return block.l[i]; @@ -119,38 +119,38 @@ macro @blk0(&block, i) @local $endif } -macro @r0(&block, v, &wref, x, y, &z, i) @local +macro r0(block, v, wref, x, y, z, i) @local { var w = *wref; - *z += ((w & (x ^ y)) ^ y) + @blk0(*block, i) + 0x5A827999 + v.rotl(5); + *z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + v.rotl(5); *wref = w.rotl(30); } -macro @r1(&block, v, &wref, x, y, &z, i) @local +macro r1(block, v, wref, x, y, z, i) @local { var w = *wref; - *z += ((w & (x ^ y)) ^ y) + @blk(*block, i) + 0x5A827999 + v.rotl(5); + *z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + v.rotl(5); *wref = w.rotl(30); } -macro @r2(&block, v, &wref, x, y, &z, i) @local +macro r2(block, v, wref, x, y, z, i) @local { var w = *wref; - *z += (w ^ x ^ y) + @blk(*block, i) + 0x6ED9EBA1 + v.rotl(5); + *z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + v.rotl(5); *wref = w.rotl(30); } -macro @r3(&block, v, &wref, x, y, &z, i) @local +macro r3(block, v, wref, x, y, z, i) @local { var w = *wref; - *z += (((w | x) & y) | (w & x)) + @blk(*block, i) + 0x8F1BBCDC + v.rotl(5); + *z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + v.rotl(5); *wref = w.rotl(30); } -macro @r4(&block, v, &wref, x, y, &z, i) @local +macro r4(block, v, wref, x, y, z, i) @local { var w = *wref; - *z += (w ^ x ^ y) + @blk(*block, i) + 0xCA62C1D6 + v.rotl(5); + *z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + v.rotl(5); *wref = w.rotl(30); } @@ -167,86 +167,86 @@ fn void sha1_transform(uint* state, char* buffer) @local uint c = state[2]; uint d = state[3]; uint e = state[4]; - @r0(block, a, b, c, d, e, 0); - @r0(block, e, a, b, c, d, 1); - @r0(block, d, e, a, b, c, 2); - @r0(block, c, d, e, a, b, 3); - @r0(block, b, c, d, e, a, 4); - @r0(block, a, b, c, d, e, 5); - @r0(block, e, a, b, c, d, 6); - @r0(block, d, e, a, b, c, 7); - @r0(block, c, d, e, a, b, 8); - @r0(block, b, c, d, e, a, 9); - @r0(block, a, b, c, d, e, 10); - @r0(block, e, a, b, c, d, 11); - @r0(block, d, e, a, b, c, 12); - @r0(block, c, d, e, a, b, 13); - @r0(block, b, c, d, e, a, 14); - @r0(block, a, b, c, d, e, 15); - @r1(block, e, a, b, c, d, 16); - @r1(block, d, e, a, b, c, 17); - @r1(block, c, d, e, a, b, 18); - @r1(block, b, c, d, e, a, 19); - @r2(block, a, b, c, d, e, 20); - @r2(block, e, a, b, c, d, 21); - @r2(block, d, e, a, b, c, 22); - @r2(block, c, d, e, a, b, 23); - @r2(block, b, c, d, e, a, 24); - @r2(block, a, b, c, d, e, 25); - @r2(block, e, a, b, c, d, 26); - @r2(block, d, e, a, b, c, 27); - @r2(block, c, d, e, a, b, 28); - @r2(block, b, c, d, e, a, 29); - @r2(block, a, b, c, d, e, 30); - @r2(block, e, a, b, c, d, 31); - @r2(block, d, e, a, b, c, 32); - @r2(block, c, d, e, a, b, 33); - @r2(block, b, c, d, e, a, 34); - @r2(block, a, b, c, d, e, 35); - @r2(block, e, a, b, c, d, 36); - @r2(block, d, e, a, b, c, 37); - @r2(block, c, d, e, a, b, 38); - @r2(block, b, c, d, e, a, 39); - @r3(block, a, b, c, d, e, 40); - @r3(block, e, a, b, c, d, 41); - @r3(block, d, e, a, b, c, 42); - @r3(block, c, d, e, a, b, 43); - @r3(block, b, c, d, e, a, 44); - @r3(block, a, b, c, d, e, 45); - @r3(block, e, a, b, c, d, 46); - @r3(block, d, e, a, b, c, 47); - @r3(block, c, d, e, a, b, 48); - @r3(block, b, c, d, e, a, 49); - @r3(block, a, b, c, d, e, 50); - @r3(block, e, a, b, c, d, 51); - @r3(block, d, e, a, b, c, 52); - @r3(block, c, d, e, a, b, 53); - @r3(block, b, c, d, e, a, 54); - @r3(block, a, b, c, d, e, 55); - @r3(block, e, a, b, c, d, 56); - @r3(block, d, e, a, b, c, 57); - @r3(block, c, d, e, a, b, 58); - @r3(block, b, c, d, e, a, 59); - @r4(block, a, b, c, d, e, 60); - @r4(block, e, a, b, c, d, 61); - @r4(block, d, e, a, b, c, 62); - @r4(block, c, d, e, a, b, 63); - @r4(block, b, c, d, e, a, 64); - @r4(block, a, b, c, d, e, 65); - @r4(block, e, a, b, c, d, 66); - @r4(block, d, e, a, b, c, 67); - @r4(block, c, d, e, a, b, 68); - @r4(block, b, c, d, e, a, 69); - @r4(block, a, b, c, d, e, 70); - @r4(block, e, a, b, c, d, 71); - @r4(block, d, e, a, b, c, 72); - @r4(block, c, d, e, a, b, 73); - @r4(block, b, c, d, e, a, 74); - @r4(block, a, b, c, d, e, 75); - @r4(block, e, a, b, c, d, 76); - @r4(block, d, e, a, b, c, 77); - @r4(block, c, d, e, a, b, 78); - @r4(block, b, c, d, e, a, 79); + r0(&block, a, &b, c, d, &e, 0); + r0(&block, e, &a, b, c, &d, 1); + r0(&block, d, &e, a, b, &c, 2); + r0(&block, c, &d, e, a, &b, 3); + r0(&block, b, &c, d, e, &a, 4); + r0(&block, a, &b, c, d, &e, 5); + r0(&block, e, &a, b, c, &d, 6); + r0(&block, d, &e, a, b, &c, 7); + r0(&block, c, &d, e, a, &b, 8); + r0(&block, b, &c, d, e, &a, 9); + r0(&block, a, &b, c, d, &e, 10); + r0(&block, e, &a, b, c, &d, 11); + r0(&block, d, &e, a, b, &c, 12); + r0(&block, c, &d, e, a, &b, 13); + r0(&block, b, &c, d, e, &a, 14); + r0(&block, a, &b, c, d, &e, 15); + r1(&block, e, &a, b, c, &d, 16); + r1(&block, d, &e, a, b, &c, 17); + r1(&block, c, &d, e, a, &b, 18); + r1(&block, b, &c, d, e, &a, 19); + r2(&block, a, &b, c, d, &e, 20); + r2(&block, e, &a, b, c, &d, 21); + r2(&block, d, &e, a, b, &c, 22); + r2(&block, c, &d, e, a, &b, 23); + r2(&block, b, &c, d, e, &a, 24); + r2(&block, a, &b, c, d, &e, 25); + r2(&block, e, &a, b, c, &d, 26); + r2(&block, d, &e, a, b, &c, 27); + r2(&block, c, &d, e, a, &b, 28); + r2(&block, b, &c, d, e, &a, 29); + r2(&block, a, &b, c, d, &e, 30); + r2(&block, e, &a, b, c, &d, 31); + r2(&block, d, &e, a, b, &c, 32); + r2(&block, c, &d, e, a, &b, 33); + r2(&block, b, &c, d, e, &a, 34); + r2(&block, a, &b, c, d, &e, 35); + r2(&block, e, &a, b, c, &d, 36); + r2(&block, d, &e, a, b, &c, 37); + r2(&block, c, &d, e, a, &b, 38); + r2(&block, b, &c, d, e, &a, 39); + r3(&block, a, &b, c, d, &e, 40); + r3(&block, e, &a, b, c, &d, 41); + r3(&block, d, &e, a, b, &c, 42); + r3(&block, c, &d, e, a, &b, 43); + r3(&block, b, &c, d, e, &a, 44); + r3(&block, a, &b, c, d, &e, 45); + r3(&block, e, &a, b, c, &d, 46); + r3(&block, d, &e, a, b, &c, 47); + r3(&block, c, &d, e, a, &b, 48); + r3(&block, b, &c, d, e, &a, 49); + r3(&block, a, &b, c, d, &e, 50); + r3(&block, e, &a, b, c, &d, 51); + r3(&block, d, &e, a, b, &c, 52); + r3(&block, c, &d, e, a, &b, 53); + r3(&block, b, &c, d, e, &a, 54); + r3(&block, a, &b, c, d, &e, 55); + r3(&block, e, &a, b, c, &d, 56); + r3(&block, d, &e, a, b, &c, 57); + r3(&block, c, &d, e, a, &b, 58); + r3(&block, b, &c, d, e, &a, 59); + r4(&block, a, &b, c, d, &e, 60); + r4(&block, e, &a, b, c, &d, 61); + r4(&block, d, &e, a, b, &c, 62); + r4(&block, c, &d, e, a, &b, 63); + r4(&block, b, &c, d, e, &a, 64); + r4(&block, a, &b, c, d, &e, 65); + r4(&block, e, &a, b, c, &d, 66); + r4(&block, d, &e, a, b, &c, 67); + r4(&block, c, &d, e, a, &b, 68); + r4(&block, b, &c, d, e, &a, 69); + r4(&block, a, &b, c, d, &e, 70); + r4(&block, e, &a, b, c, &d, 71); + r4(&block, d, &e, a, b, &c, 72); + r4(&block, c, &d, e, a, &b, 73); + r4(&block, b, &c, d, e, &a, 74); + r4(&block, a, &b, c, d, &e, 75); + r4(&block, e, &a, b, c, &d, 76); + r4(&block, d, &e, a, b, &c, 77); + r4(&block, c, &d, e, a, &b, 78); + r4(&block, b, &c, d, e, &a, 79); state[0] += a; state[1] += b; state[2] += c; diff --git a/lib/std/io/stream.c3 b/lib/std/io/stream.c3 index 6e7fe49e0..04e0ceb50 100644 --- a/lib/std/io/stream.c3 +++ b/lib/std/io/stream.c3 @@ -105,6 +105,11 @@ macro usz! write_all(stream, char[] buffer) } macro usz! @read_using_read_byte(&s, char[] buffer) +{ + return read_using_read_byte(*s, buffer); +} + +macro usz! read_using_read_byte(s, char[] buffer) { usz len = 0; foreach (&cptr : buffer) @@ -121,17 +126,26 @@ macro usz! @read_using_read_byte(&s, char[] buffer) return len; } -macro void! @write_byte_using_write(&s, char c) +macro void! write_byte_using_write(s, char c) { char[1] buff = { c }; - (*s).write(&buff)!; + s.write(&buff)!; } +macro void! @write_byte_using_write(&s, char c) @deprecated +{ + return write_byte_using_write(*s, c); +} macro char! @read_byte_using_read(&s) +{ + return read_byte_using_read(*s); +} + +macro char! read_byte_using_read(s) { char[1] buffer; - usz read = (*s).read(&buffer)!; + usz read = s.read(&buffer)!; if (read != 1) return IoError.EOF?; return buffer[0]; } @@ -139,13 +153,23 @@ macro char! @read_byte_using_read(&s) def ReadByteFn = fn char!(); -macro usz! @write_using_write_byte(&s, char[] bytes) +macro usz! write_using_write_byte(s, char[] bytes) { foreach (c : bytes) s.write_byte(self, c)!; return bytes.len; } -macro void! @pushback_using_seek(&s) +macro usz! @write_using_write_byte(&s, char[] bytes) @deprecated +{ + return write_using_write_byte(*s, bytes); +} + +macro void! pushback_using_seek(s) +{ + s.seek(-1, CURSOR)!; +} + +macro void! @pushback_using_seek(&s) @deprecated { s.seek(-1, CURSOR)!; } diff --git a/lib/std/math/bigint.c3 b/lib/std/math/bigint.c3 index 14ac8212f..efb0fdca1 100644 --- a/lib/std/math/bigint.c3 +++ b/lib/std/math/bigint.c3 @@ -445,13 +445,13 @@ fn BigInt BigInt.shl(self, int shift) return self; } -macro bool BigInt.equals(&self, BigInt* &other) @safemacro +macro bool BigInt.equals(&self, BigInt other) { if (self.len != other.len) return false; return self.data[:self.len] == other.data[:self.len]; } -macro bool BigInt.greater_than(&self, BigInt* &other) @safemacro +macro bool BigInt.greater_than(&self, BigInt other) { if (self.is_negative() && !other.is_negative()) return false; if (!self.is_negative() && other.is_negative()) return true; @@ -461,7 +461,7 @@ macro bool BigInt.greater_than(&self, BigInt* &other) @safemacro for (pos = len - 1; pos >= 0 && self.data[pos] == other.data[pos]; pos--); return pos >= 0 && self.data[pos] > other.data[pos]; } -macro bool BigInt.less_than(&self, BigInt* &other) @safemacro +macro bool BigInt.less_than(&self, BigInt other) { if (self.is_negative() && !other.is_negative()) return true; if (!self.is_negative() && other.is_negative()) return false; @@ -485,14 +485,14 @@ fn bool BigInt.is_one(&self) } -macro bool BigInt.greater_or_equal(&self, BigInt* &other) @safemacro +macro bool BigInt.greater_or_equal(&self, BigInt other) { - return self.greater_than(*other) || self.equals(*other); + return self.greater_than(other) || self.equals(other); } -macro bool BigInt.less_or_equal(&self, BigInt* &other) @safemacro +macro bool BigInt.less_or_equal(&self, BigInt) { - return self.less_than(*other) || self.equals(*other); + return self.less_than(other) || self.equals(other); } fn BigInt BigInt.abs(&self) diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index 1e0d5048f..d6b798288 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -145,7 +145,7 @@ $endif return (usz)n; } -fn void! Socket.write_byte(&self, char byte) @dynamic => io::@write_byte_using_write(self, byte); +fn void! Socket.write_byte(&self, char byte) @dynamic => io::write_byte_using_write(self, byte); fn void! Socket.destroy(&self) @dynamic { diff --git a/lib/std/sort/binarysearch.c3 b/lib/std/sort/binarysearch.c3 index 0a58c24ec..931a3afe8 100644 --- a/lib/std/sort/binarysearch.c3 +++ b/lib/std/sort/binarysearch.c3 @@ -10,7 +10,7 @@ in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { usz i; - usz len = @len_from_list(list); + usz len = len_from_list(list); var $no_cmp = @is_empty_macro_slot(cmp); var $has_context = @is_valid_macro_slot(context); for (usz j = len; i < j;) diff --git a/lib/std/sort/countingsort.c3 b/lib/std/sort/countingsort.c3 index fed1870ab..fa28f2cb9 100644 --- a/lib/std/sort/countingsort.c3 +++ b/lib/std/sort/countingsort.c3 @@ -10,7 +10,7 @@ Sort list using the counting sort algorithm. *> macro countingsort(list, key_fn = EMPTY_MACRO_SLOT) @builtin { - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); cs::csort(<$typeof(list), $typeof(key_fn)>)(list, 0, len, key_fn, ~((uint)0)); } diff --git a/lib/std/sort/insertionsort.c3 b/lib/std/sort/insertionsort.c3 index 51dca7b73..c705afeec 100644 --- a/lib/std/sort/insertionsort.c3 +++ b/lib/std/sort/insertionsort.c3 @@ -8,7 +8,7 @@ Sort list using the quick sort algorithm. *> macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context); } diff --git a/lib/std/sort/quicksort.c3 b/lib/std/sort/quicksort.c3 index fc1b28348..1568b8921 100644 --- a/lib/std/sort/quicksort.c3 +++ b/lib/std/sort/quicksort.c3 @@ -9,7 +9,7 @@ Sort list using the quick sort algorithm. *> macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context); } @@ -24,7 +24,7 @@ list will be partially sorted. *> macro quickselect(list, isz k, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); return qs::qselect(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, k, cmp, context); } diff --git a/lib/std/sort/sort.c3 b/lib/std/sort/sort.c3 index 44eda87dd..948645039 100644 --- a/lib/std/sort/sort.c3 +++ b/lib/std/sort/sort.c3 @@ -1,6 +1,11 @@ module std::sort; -macro usz @len_from_list(&list) +macro usz @len_from_list(&list) @deprecated +{ + return len_from_list(*list); +} + +macro usz len_from_list(list) { $if $defined(list.len()): return list.len(); diff --git a/lib/std/sort/sorted.c3 b/lib/std/sort/sorted.c3 index 8718e3ca4..40bc1f801 100644 --- a/lib/std/sort/sorted.c3 +++ b/lib/std/sort/sorted.c3 @@ -9,7 +9,7 @@ Returns true if list is sorted in either ascending or descending order. macro bool is_sorted(list, cmp = EMPTY_MACRO_SLOT, ctx = EMPTY_MACRO_SLOT) @builtin { var $Type = $typeof(list); - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); if (len <= 1) return true; var check_sort = fn bool($Type list, usz start, usz end, $typeof(cmp) cmp, $typeof(ctx) ctx) { diff --git a/releasenotes.md b/releasenotes.md index 4bf6df708..6b28b2780 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -20,6 +20,7 @@ - Improved error message when accessing `@private` from other modules #1769. - Include `@name` when searching for possible matches to `name` in the error message. #1779 - Improve `@param` parse errors #1777 +- Improved `#foo` resolution inside of the compiler. ### Fixes - Fix case trying to initialize a `char[*]*` from a String. @@ -73,6 +74,7 @@ - Added URL parser. - Added convenience functions to `Maybe`. - Added `String.trim_left()` and `.trim_right()`. +- Deprecation of several `&` macros. ## 0.6.5 Change list diff --git a/src/compiler/abi/c_abi_wasm.c b/src/compiler/abi/c_abi_wasm.c index 7f06dd2ad..47169c9b8 100644 --- a/src/compiler/abi/c_abi_wasm.c +++ b/src/compiler/abi/c_abi_wasm.c @@ -18,7 +18,7 @@ static ABIArgInfo *wasm_classify_argument_type(Type *type) // For the experimental multivalue ABI, fully expand all other aggregates /*if (Kind == ABIKind::ExperimentalMV) { const RecordType *RT = Ty->getAs(); - assert(RT); + ASSERT0(RT); bool HasBitField = false; for (auto *Field : RT->getDecl()->fields()) { if (Field->isBitField()) { diff --git a/src/compiler/c_codegen.c b/src/compiler/c_codegen.c index 474c593ad..92f2ec908 100644 --- a/src/compiler/c_codegen.c +++ b/src/compiler/c_codegen.c @@ -516,7 +516,7 @@ static void c_emit_expr(GenContext *c, CValue *value, Expr *expr) case EXPR_OPTIONAL: break; case EXPR_OTHER_CONTEXT: - break; + UNREACHABLE case EXPR_POINTER_OFFSET: break; case EXPR_POISONED: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index fda8b783c..cff77f3bf 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -430,11 +430,6 @@ typedef struct VarDecl_ { int32_t index; struct - { - SemaContext *context; - SourceSpan span; - } hash_var; - struct { void *backend_debug_ref; union @@ -1115,6 +1110,7 @@ typedef struct { Expr *inner; SemaContext *context; + SourceSpan inline_at; } ExprOtherContext; typedef struct @@ -3741,7 +3737,7 @@ INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type) INLINE void expr_rewrite_ptr_access(Expr *expr, Expr *inner, Type *type) { - assert(inner->resolve_status == RESOLVE_DONE); + ASSERT0(inner->resolve_status == RESOLVE_DONE); expr->expr_kind = EXPR_PTR_ACCESS; expr->inner_expr = inner; expr->type = type; @@ -3751,7 +3747,7 @@ INLINE void expr_rewrite_ptr_access(Expr *expr, Expr *inner, Type *type) INLINE void expr_rewrite_enum_from_ord(Expr *expr, Type *type) { Expr *inner = expr_copy(expr); - assert(inner->resolve_status == RESOLVE_DONE); + ASSERT0(inner->resolve_status == RESOLVE_DONE); expr->expr_kind = EXPR_ENUM_FROM_ORD; expr->inner_expr = inner; expr->type = type; @@ -3761,7 +3757,7 @@ INLINE void expr_rewrite_enum_from_ord(Expr *expr, Type *type) INLINE void expr_rewrite_slice_len(Expr *expr, Expr *inner, Type *type) { - assert(inner->resolve_status == RESOLVE_DONE); + ASSERT0(inner->resolve_status == RESOLVE_DONE); expr->expr_kind = EXPR_SLICE_LEN; expr->inner_expr = inner; expr->type = type_add_optional(type, IS_OPTIONAL(inner)); @@ -3957,6 +3953,7 @@ INLINE unsigned arg_bits_max(AsmArgBits bits, unsigned limit) INLINE bool expr_is_empty_const_slice(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_SLICE && expr->const_expr.slice_init == NULL; @@ -3991,56 +3988,67 @@ static inline bool decl_is_var_local(Decl *decl) INLINE bool expr_is_const_string(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_STRING; } INLINE bool expr_is_const_enum(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ENUM; } INLINE bool expr_is_const_fault(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ERR; } INLINE bool expr_is_const_pointer(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER; } INLINE bool expr_is_const_bool(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_BOOL; } INLINE bool expr_is_const_initializer(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER; } INLINE bool expr_is_const_slice(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_SLICE; } INLINE bool expr_is_const_bytes(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_BYTES; } INLINE bool expr_is_const_untyped_list(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_UNTYPED_LIST; } INLINE bool expr_is_const_int(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INTEGER; } INLINE bool expr_is_const_member(Expr *expr) { + ASSERT0(expr->resolve_status == RESOLVE_DONE); return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_MEMBER; } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 848905b19..6d50d4d3c 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -377,7 +377,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ LLVMTypeRef expected_type = llvm_get_type(c, const_init->init_struct[i]->type); LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i]); LLVMTypeRef element_type = LLVMTypeOf(element); - //assert(LLVMIsConstant(element)); + //ASSERT0(LLVMIsConstant(element)); if (expected_type != element_type) { was_modified = true; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index d056da6bb..60e25ec2e 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6826,7 +6826,7 @@ static void llvm_emit_int_to_bool(GenContext *c, BEValue *value, Expr *expr) Type *inner_type = value->type; if (inner_type->type_kind == TYPE_ARRAY) { - assert(inner_type->array.base == type_char || inner_type->array.base == type_ichar); + ASSERT0(inner_type->array.base == type_char || inner_type->array.base == type_ichar); llvm_value_addr(c, value); unsigned len = type_size(value->type); ASSERT0(len > 0); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index aa40c2065..42773304b 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -117,7 +117,7 @@ void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value) if (decl->var.is_temp && !IS_OPTIONAL(decl) && !decl->var.is_addr && !decl->var.is_written && !type_is_user_defined( type_low) && type_low->type_kind != TYPE_ARRAY) { - assert(decl->var.init_expr); + ASSERT0(decl->var.init_expr); llvm_emit_expr(c, value, decl->var.init_expr); llvm_value_rvalue(c, value); decl->backend_value = value->value; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 7ac4ea2f8..3d1ad972c 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1810,7 +1810,7 @@ static void cast_anyfault_to_fault(SemaContext *context, Expr *expr, Type *type) expr->resolve_status = RESOLVE_DONE; return; } - assert(expr_is_const_fault(expr)); + ASSERT0(expr_is_const_fault(expr)); Decl *value = expr->const_expr.enum_err_val; ASSERT0(value->type != type); expr->type = type; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 260618f4f..2aa1e68c4 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -40,7 +40,7 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_eval(SemaContext *context, Expr *expr, CheckType check); static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr); static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr, CheckType check); -static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Type *infer_type, Expr *expr); + static inline bool sema_expr_analyse_ternary(SemaContext *context, Type *infer_type, Expr *expr); static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool *invalid_cast_ref); static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr); @@ -184,6 +184,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, Expr *identifier, bool *missing_ref); static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member); static inline bool sema_expr_fold_to_index(Expr *expr, Expr *parent, SubscriptIndex index); +static inline bool sema_expr_fold_hash(SemaContext *context, Expr *expr); static inline void sema_expr_flatten_const_ident(Expr *expr); static inline bool sema_analyse_expr_check(SemaContext *context, Expr *expr, CheckType check); @@ -191,6 +192,7 @@ static inline bool sema_analyse_expr_check(SemaContext *context, Expr *expr, Che static inline Expr **sema_prepare_splat_insert(Expr **exprs, unsigned added, unsigned insert_point); static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool is_dead, Type *infer_type); + // -- implementations // Limit folding to integers and floats, exclude vectors. @@ -1145,34 +1147,6 @@ static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *e return true; } -static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Type *infer_type, Expr *expr) -{ - ASSERT0(expr && expr->hash_ident_expr.identifier); - DEBUG_LOG("Resolving identifier '%s'", expr->hash_ident_expr.identifier); - Decl *decl = sema_resolve_symbol(context, expr->hash_ident_expr.identifier, NULL, expr->span); - - // Already handled - if (!decl) return expr_poison(expr); - - ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR); - expr_replace(expr, copy_expr_single(decl->var.init_expr)); - SemaContext *hash_context = decl->var.hash_var.context; - InliningSpan *old_span = hash_context->inlined_at; - hash_context->inlined_at = context->inlined_at; - bool success; - if (infer_type) - { - success = sema_analyse_inferred_expr(decl->var.hash_var.context, infer_type, expr); - } - else - { - success = sema_analyse_expr_value(decl->var.hash_var.context, expr); - } - hash_context->inlined_at = old_span; - if (!success) return decl_poison(decl); - return true; -} - static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *binary, Expr *left, Expr *right) { @@ -1415,8 +1389,11 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param, context = MALLOCS(SemaContext); *context = *temp; } - param->var.hash_var.context = context; - param->var.hash_var.span = arg->span; + { + Expr *inner = expr_copy(arg); + arg->expr_kind = EXPR_OTHER_CONTEXT; + arg->expr_other_context = (ExprOtherContext) { .context = context, .inner = inner }; + } break; case VARDECL_PARAM_CT: // $foo @@ -3667,8 +3644,15 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, Che Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing) { RETRY: + if (!sema_expr_fold_hash(context, child)) return false; switch (child->expr_kind) { + case EXPR_OTHER_CONTEXT: + { + Expr *inner = child->expr_other_context.inner; + SemaContext *c2 = child->expr_other_context.context; + return sema_expr_resolve_access_child(c2, inner, missing); + } case EXPR_IDENTIFIER: // A path is not allowed. ASSERT_SPAN(child, child->resolve_status != RESOLVE_DONE); @@ -3681,13 +3665,7 @@ RETRY: if (child->type_expr->kind == TYPE_INFO_CT_IDENTIFIER) return child; break; case EXPR_HASH_IDENT: - { - ASSERT_SPAN(child, child->resolve_status != RESOLVE_DONE); - Decl *decl = sema_resolve_symbol(context, child->hash_ident_expr.identifier, NULL, child->span); - if (!decl) return NULL; - Expr *expr = copy_expr_single(decl->var.init_expr); - return sema_expr_resolve_access_child(decl->var.hash_var.context, expr, missing); - } + UNREACHABLE case EXPR_CT_EVAL: { ASSERT_SPAN(child, child->resolve_status != RESOLVE_DONE); @@ -5676,12 +5654,32 @@ static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Ex return true; } +static bool sema_expr_fold_hash(SemaContext *context, Expr *expr) +{ + if (expr->expr_kind == EXPR_HASH_IDENT) + { + ASSERT0(expr && expr->hash_ident_expr.identifier); + DEBUG_LOG("Resolving identifier '%s'", expr->hash_ident_expr.identifier); + Decl *decl = sema_resolve_symbol(context, expr->hash_ident_expr.identifier, NULL, expr->span); + + // Already handled + if (!decl) return expr_poison(expr); + + ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR); + expr_replace(expr, copy_expr_single(decl->var.init_expr)); + ASSERT0(expr->expr_kind == EXPR_OTHER_CONTEXT); + REMINDER("Handle inlining at"); + return true; + } + return true; +} /** * Analyse a = b * @return true if analysis works */ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right) { + if (!sema_expr_fold_hash(context, left)) return false; // 1. Evaluate left side switch (left->expr_kind) { @@ -7014,10 +7012,27 @@ static inline bool sema_expr_analyse_addr(SemaContext *context, Expr *expr, bool { // 1. Evaluate the expression Expr *inner = expr->unary_expr.expr; + if (!sema_expr_fold_hash(context, inner)) return false; switch (inner->expr_kind) { case EXPR_POISONED: return false; + case EXPR_OTHER_CONTEXT: + { + Expr *inner_c = inner->expr_other_context.inner; + SemaContext *c2 = inner->expr_other_context.context; + expr_replace(inner, inner_c); + return sema_expr_analyse_addr(c2, expr, failed_ref, check); + } + case EXPR_HASH_IDENT: + { + Decl *decl = sema_resolve_symbol(context, inner->hash_ident_expr.identifier, NULL, inner->span); + if (!decl) return expr_poison(expr); + ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR); + expr_replace(inner, copy_expr_single(decl->var.init_expr)); + if (!sema_expr_analyse_addr(context, expr, failed_ref, check)) return decl_poison(decl); + return true; + } case EXPR_SUBSCRIPT: inner->expr_kind = EXPR_SUBSCRIPT_ADDR; if (failed_ref) @@ -9236,7 +9251,7 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex ASSERT_SPAN(expr, inner->expr_kind == EXPR_HASH_IDENT); Decl *decl = sema_resolve_symbol(context, inner->ct_ident_expr.identifier, NULL, inner->span); if (!decl) return false; - const char *desc = span_to_string(decl->var.hash_var.span); + const char *desc = span_to_string(decl->var.init_expr->span); if (!desc) { SEMA_ERROR(expr, "Failed to stringify hash variable contents - they must be a single line and not exceed 255 characters."); @@ -9493,7 +9508,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_CT_CALL: return sema_expr_analyse_ct_call(context, expr); case EXPR_HASH_IDENT: - return sema_expr_analyse_hash_identifier(context, NULL, expr); + if (!sema_expr_fold_hash(context, expr)) return false; + return sema_analyse_expr_dispatch(context, expr, check); case EXPR_CT_IDENT: return sema_expr_analyse_ct_identifier(context, expr, check); case EXPR_OPTIONAL: @@ -9983,6 +9999,7 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex UNREACHABLE } + if (!sema_expr_fold_hash(context, expr)) return false; expr->resolve_status = RESOLVE_RUNNING; switch (expr->expr_kind) { @@ -10014,8 +10031,7 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex if (!sema_expr_analyse_ternary(context, infer_type, expr)) return expr_poison(expr); break; case EXPR_HASH_IDENT: - if (!sema_expr_analyse_hash_identifier(context, infer_type, expr)) return expr_poison(expr); - break; + UNREACHABLE case EXPR_CT_ARG: if (!sema_expr_analyse_ct_arg(context, infer_type, expr)) return expr_poison(expr); break; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 51e1d086d..294e40444 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -784,7 +784,8 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex if (!to) to = type_untypedlist; ASSERT0(to); Type *flattened = type_flatten(to); - bool is_zero_init = (expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list)) || sema_initializer_list_is_empty(expr); + bool is_zero_init = (expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list)) || + (expr->resolve_status == RESOLVE_DONE && sema_initializer_list_is_empty(expr)); if (!sema_resolve_type_structure(context, to, expr->span)) return false; switch (flattened->type_kind) diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 11a0f9f52..c2faf80fe 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -119,7 +119,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement } CondResult result_no_resolve = COND_MISSING; - if (expr_is_const_bool(expr) && expr->resolve_status == RESOLVE_DONE) + if (expr->resolve_status == RESOLVE_DONE && expr_is_const_bool(expr)) { result_no_resolve = expr->const_expr.b ? COND_TRUE : COND_FALSE; } diff --git a/test/test_suite/generic/generic_over_fn.c3t b/test/test_suite/generic/generic_over_fn.c3t index 0c9eff922..156627ce2 100644 --- a/test/test_suite/generic/generic_over_fn.c3t +++ b/test/test_suite/generic/generic_over_fn.c3t @@ -12,7 +12,7 @@ macro quicksort(list, cmp = null) { var $Type = $typeof(list); var $CmpType = $typeof(cmp); - usz len = sort::@len_from_list(list); + usz len = sort::len_from_list(list); test_generic::sort(<$Type, $CmpType>)(list, 0, (isz)len - 1, cmp); } @@ -70,6 +70,7 @@ entry: %tc = alloca %"int[]", align 8 %list = alloca %"int[]", align 8 %len = alloca i64, align 8 + %list9 = alloca %"int[]", align 8 store %"int[]" zeroinitializer, ptr %literal, align 8 %ptradd = getelementptr inbounds i8, ptr %literal, i64 16 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal1, ptr align 4 @.__const, i32 8, i1 false) @@ -110,14 +111,15 @@ loop.body: ; preds = %loop.cond %ptroffset = getelementptr inbounds [16 x i8], ptr %12, i64 %13 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %tc, ptr align 8 %ptroffset, i32 16, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %list, ptr align 8 %tc, i32 16, i1 false) - %ptradd9 = getelementptr inbounds i8, ptr %list, i64 8 - %14 = load i64, ptr %ptradd9, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %list9, ptr align 8 %list, i32 16, i1 false) + %ptradd10 = getelementptr inbounds i8, ptr %list9, i64 8 + %14 = load i64, ptr %ptradd10, align 8 store i64 %14, ptr %len, align 8 %15 = load i64, ptr %len, align 8 %sub = sub i64 %15, 1 %lo = load ptr, ptr %list, align 8 - %ptradd10 = getelementptr inbounds i8, ptr %list, i64 8 - %hi = load i64, ptr %ptradd10, align 8 + %ptradd11 = getelementptr inbounds i8, ptr %list, i64 8 + %hi = load i64, ptr %ptradd11, align 8 call void @"test_generic$sa$int$fn$int$int$$int$$.sort"(ptr %lo, i64 %hi, i64 0, i64 %sub, ptr @sort_test.cmp_int_value) %16 = load i64, ptr %.anon, align 8 %addnuw = add nuw i64 %16, 1 @@ -141,6 +143,7 @@ entry: %tc = alloca %"int[]", align 8 %list = alloca %"int[]", align 8 %len = alloca i64, align 8 + %list9 = alloca %"int[]", align 8 store %"int[]" zeroinitializer, ptr %literal, align 8 %ptradd = getelementptr inbounds i8, ptr %literal, i64 16 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal1, ptr align 4 @.__const.4, i32 8, i1 false) @@ -181,14 +184,15 @@ loop.body: ; preds = %loop.cond %ptroffset = getelementptr inbounds [16 x i8], ptr %12, i64 %13 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %tc, ptr align 8 %ptroffset, i32 16, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %list, ptr align 8 %tc, i32 16, i1 false) - %ptradd9 = getelementptr inbounds i8, ptr %list, i64 8 - %14 = load i64, ptr %ptradd9, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %list9, ptr align 8 %list, i32 16, i1 false) + %ptradd10 = getelementptr inbounds i8, ptr %list9, i64 8 + %14 = load i64, ptr %ptradd10, align 8 store i64 %14, ptr %len, align 8 %15 = load i64, ptr %len, align 8 %sub = sub i64 %15, 1 %lo = load ptr, ptr %list, align 8 - %ptradd10 = getelementptr inbounds i8, ptr %list, i64 8 - %hi = load i64, ptr %ptradd10, align 8 + %ptradd11 = getelementptr inbounds i8, ptr %list, i64 8 + %hi = load i64, ptr %ptradd11, align 8 call void @"test_generic$sa$int$fn$int$int$$int$$.sort"(ptr %lo, i64 %hi, i64 0, i64 %sub, ptr @sort_test.cmp_int_value2) %16 = load i64, ptr %.anon, align 8 %addnuw = add nuw i64 %16, 1