diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index 85e956129..44e13920c 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -1,6 +1,6 @@ module std::collections::enummap(); -struct EnumMap +struct EnumMap (Printable) { ValueType[Enum.len] values; } @@ -13,7 +13,7 @@ fn void EnumMap.init(&self, ValueType init_value) } } -fn usz! EnumMap.to_format(&self, Formatter* formatter) : Printable +fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic { usz n = formatter.print("{ ")!; foreach (i, &value : self.values) @@ -25,7 +25,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) : Printable return n; } -fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) @dynamic { return string::printf("%s", *self); } diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index 8c9a53afe..1ec82542a 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -10,7 +10,7 @@ module std::collections::enumset(); def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private ; const IS_CHAR_ARRAY = Enum.elements > 128; -def EnumSet = distinct EnumSetType; +distinct EnumSet (Printable) = EnumSetType; fn void EnumSet.add(&self, Enum v) { @@ -125,7 +125,7 @@ fn EnumSet EnumSet.xor_of(&self, EnumSet s) $endif } -fn usz! EnumSet.to_format(&set, Formatter* formatter) : Printable +fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic { usz n = formatter.print("[")!; bool found; @@ -140,7 +140,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) : Printable return n; } -fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) : Printable +fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) @dynamic { return string::printf("%s", *set); } diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index a4173df87..c48dd1f89 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -10,7 +10,7 @@ def ElementTest = fn bool(Type *type, any* context); const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type); const ELEMENT_IS_POINTER = Type.kindof == POINTER; -struct List +struct List (Printable) { usz size; usz capacity; @@ -42,7 +42,7 @@ fn void List.tinit(&self, usz initial_capacity = 16) self.init(initial_capacity, mem::temp()) @inline; } -fn usz! List.to_format(&self, Formatter* formatter) : Printable +fn usz! List.to_format(&self, Formatter* formatter) @dynamic { switch (self.size) { @@ -62,7 +62,7 @@ fn usz! List.to_format(&self, Formatter* formatter) : Printable } } -fn String List.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String List.to_string(&self, Allocator* using = mem::heap()) @dynamic { return string::printf("%s", *self); } diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 7d3c99837..88fb72e05 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -10,7 +10,7 @@ const Object TRUE_OBJECT = { .b = true, .type = bool.typeid }; const Object FALSE_OBJECT = { .b = false, .type = bool.typeid }; const Object NULL_OBJECT = { .type = void*.typeid }; -struct Object +struct Object (Printable) { typeid type; Allocator* allocator; @@ -27,7 +27,7 @@ struct Object } -fn usz! Object.to_format(&self, Formatter* formatter) : Printable +fn usz! Object.to_format(&self, Formatter* formatter) @dynamic { switch (self.type) { diff --git a/lib/std/collections/priorityqueue.c3 b/lib/std/collections/priorityqueue.c3 index 7e8362261..2f6b9a086 100644 --- a/lib/std/collections/priorityqueue.c3 +++ b/lib/std/collections/priorityqueue.c3 @@ -23,8 +23,8 @@ module std::collections::priorityqueue(); import std::collections::priorityqueue::private; -def PriorityQueue = distinct inline PrivatePriorityQueue(); -def PriorityQueueMax = distinct inline PrivatePriorityQueue(); +distinct PriorityQueue = inline PrivatePriorityQueue(); +distinct PriorityQueueMax = inline PrivatePriorityQueue(); module std::collections::priorityqueue::private(); import std::collections::list; @@ -133,12 +133,13 @@ fn Type PrivatePriorityQueue.peek_at(&self, usz index) @operator([]) return self.heap[index]; } -fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) : Printable +fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) { return self.heap.to_format(formatter); } -fn String PrivatePriorityQueue.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String PrivatePriorityQueue.to_string(&self, Allocator* using = mem::heap()) { return self.heap.to_string(using); -} \ No newline at end of file +} + diff --git a/lib/std/collections/range.c3 b/lib/std/collections/range.c3 index 9a21361d6..0da93df94 100644 --- a/lib/std/collections/range.c3 +++ b/lib/std/collections/range.c3 @@ -4,7 +4,7 @@ **/ module std::collections::range(); -struct Range +struct Range (Printable) { Type start; Type end; @@ -29,17 +29,17 @@ fn Type Range.get(&self, usz index) @operator([]) return self.start + (Type)index; } -fn String Range.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String Range.to_string(&self, Allocator* using = mem::heap()) @dynamic { return string::printf("[%s..%s]", self.start, self.end); } -fn usz! Range.to_format(&self, Formatter* formatter) : Printable +fn usz! Range.to_format(&self, Formatter* formatter) @dynamic { return formatter.printf("[%s..%s]", self.start, self.end)!; } -struct ExclusiveRange +struct ExclusiveRange (Printable) { Type start; Type end; @@ -56,12 +56,12 @@ fn bool ExclusiveRange.contains(&self, Type value) @inline return value >= self.start && value < self.end; } -fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) : Printable +fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic { return formatter.printf("[%s..<%s]", self.start, self.end)!; } -fn String ExclusiveRange.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String ExclusiveRange.to_string(&self, Allocator* using = mem::heap()) @dynamic { return string::printf("[%s..<%s]", self.start, self.end); } diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index 3bb02a960..cbac0991f 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -1,6 +1,6 @@ module std::core::dstring; -def DString = distinct void*; +distinct DString = void*; const usz MIN_CAPACITY @private = 16; diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 44fc8bed4..612a08650 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -1,8 +1,8 @@ module std::core::string; import std::ascii; -def ZString = distinct inline char*; -def WString = distinct inline Char16*; +distinct ZString = inline char*; +distinct WString = inline Char16*; def Char32 = uint; def Char16 = ushort; diff --git a/lib/std/hash/fnv32a.c3 b/lib/std/hash/fnv32a.c3 index c172eb0d8..dbc517fc2 100644 --- a/lib/std/hash/fnv32a.c3 +++ b/lib/std/hash/fnv32a.c3 @@ -3,7 +3,7 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::hash::fnv32a; -def Fnv32a = distinct uint; +distinct Fnv32a = uint; const FNV32A_START @private = 0x811c9dc5; const FNV32A_MUL @private = 0x01000193; diff --git a/lib/std/hash/fnv64a.c3 b/lib/std/hash/fnv64a.c3 index 6ea6a9592..7c8093312 100644 --- a/lib/std/hash/fnv64a.c3 +++ b/lib/std/hash/fnv64a.c3 @@ -3,7 +3,7 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::hash::fnv64a; -def Fnv64a = distinct ulong; +distinct Fnv64a = ulong; const FNV64A_START @private = 0xcbf29ce484222325; const FNV64A_MUL @private = 0x00000100000001b3; diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index 9b55c9bce..09c9f1c55 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -6,8 +6,8 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256; protocol Printable { - fn String to_string(&self, Allocator *using); - fn usz! to_format(&self, Formatter* formatter); + fn String to_string(&self, Allocator *using) @optional; + fn usz! to_format(&self, Formatter* formatter) @optional; } fault PrintFault diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 4beaf788d..3c4dbebea 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -14,7 +14,7 @@ fault PathResult NO_PARENT, } -struct Path +struct Path (Printable) { String path_string; PathEnv env; @@ -449,12 +449,12 @@ fn void Path.free(self) } -fn usz! Path.to_format(&self, Formatter* formatter) : Printable +fn usz! Path.to_format(&self, Formatter* formatter) @dynamic { return formatter.print(self.str_view()); } -fn String Path.to_string(&self, Allocator* using = mem::heap()) : Printable +fn String Path.to_string(&self, Allocator* using = mem::heap()) @dynamic { return self.str_view().copy(using); } diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index 1e7f2d043..1a143777b 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -31,7 +31,7 @@ fn void errno_set(Errno e) os::errno_set((int)e); } -def Errno = distinct inline CInt; +distinct Errno = inline CInt; def TerminateFunction = fn void(); def CompareFunction = fn int(void*, void*); def JmpBuf = uptr[$$JMP_BUF_SIZE]; diff --git a/lib/std/math/random/math.lcg.c3 b/lib/std/math/random/math.lcg.c3 index 399e079c0..4ea4a4cb1 100644 --- a/lib/std/math/random/math.lcg.c3 +++ b/lib/std/math/random/math.lcg.c3 @@ -13,15 +13,15 @@ const MUL_LCG16 @local = 0x915d; // TODO: Find good constant // Lcg128_64 -def Lcg128Random = distinct uint128; +distinct Lcg128Random (Random) = uint128; -fn void Lcg128Random.set_seed(&self, char[] input) : Random +fn void Lcg128Random.set_seed(&self, char[] input) @dynamic { *self = (Lcg128Random)random::make_seed(uint128, input); } -fn ulong Lcg128Random.next_long(&self) : Random +fn ulong Lcg128Random.next_long(&self) @dynamic { uint128* s = (uint128*)self; ulong result = (ulong)(*s >> 64); @@ -32,23 +32,23 @@ fn ulong Lcg128Random.next_long(&self) : Random /** * @require bytes.len > 0 **/ -fn void Lcg128Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_long, bytes); -fn uint128 Lcg128Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn uint Lcg128Random.next_int(&self) : Random => (uint)self.next_long(); -fn ushort Lcg128Random.next_short(&self) : Random => (ushort)self.next_long(); -fn char Lcg128Random.next_byte(&self) : Random => (char)self.next_long(); +fn void Lcg128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); +fn uint128 Lcg128Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn uint Lcg128Random.next_int(&self) @dynamic => (uint)self.next_long(); +fn ushort Lcg128Random.next_short(&self) @dynamic => (ushort)self.next_long(); +fn char Lcg128Random.next_byte(&self) @dynamic => (char)self.next_long(); // -------------------------------- Lcg64_32 -------------------------------- -def Lcg64Random = distinct ulong; +distinct Lcg64Random (Random) = ulong; -fn void Lcg64Random.set_seed(&self, char[] seed) : Random +fn void Lcg64Random.set_seed(&self, char[] seed) @dynamic { *self = (Lcg64Random)random::make_seed(ulong, seed); } -fn uint Lcg64Random.next_int(&self) : Random +fn uint Lcg64Random.next_int(&self) @dynamic { ulong* s = (ulong*)self; uint result = (uint)(*s >> 32); @@ -59,22 +59,22 @@ fn uint Lcg64Random.next_int(&self) : Random /** * @require bytes.len > 0 **/ -fn void Lcg64Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int, bytes); -fn uint128 Lcg64Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Lcg64Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort Lcg64Random.next_short(&self) : Random => (ushort)self.next_int(); -fn char Lcg64Random.next_byte(&self) : Random => (char)self.next_int(); +fn void Lcg64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 Lcg64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Lcg64Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Lcg64Random.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Lcg64Random.next_byte(&self) @dynamic => (char)self.next_int(); // -------------------------------- Lcg32_16 -------------------------------- -def Lcg32Random = distinct uint; +distinct Lcg32Random (Random) = uint; -fn void Lcg32Random.set_seed(&self, char[] seed) : Random +fn void Lcg32Random.set_seed(&self, char[] seed) @dynamic { *self = (Lcg32Random)random::make_seed(uint, seed); } -fn ushort Lcg32Random.next_short(&self) : Random +fn ushort Lcg32Random.next_short(&self) @dynamic { uint* s = (uint*)self; ushort result = (ushort)(*s >> 16); @@ -82,22 +82,22 @@ fn ushort Lcg32Random.next_short(&self) : Random return result; } -fn void Lcg32Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_short, bytes); -fn uint128 Lcg32Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Lcg32Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Lcg32Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn char Lcg32Random.next_byte(&self) : Random => (char)self.next_short(); +fn void Lcg32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); +fn uint128 Lcg32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Lcg32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Lcg32Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn char Lcg32Random.next_byte(&self) @dynamic => (char)self.next_short(); // -------------------------------- Lcg16_8 -------------------------------- -def Lcg16Random = distinct ushort; +distinct Lcg16Random (Random) = ushort; -fn void Lcg16Random.set_seed(&self, char[] seed) : Random +fn void Lcg16Random.set_seed(&self, char[] seed) @dynamic { *self = (Lcg16Random)random::make_seed(ushort, seed); } -fn char Lcg16Random.next_byte(&self) : Random +fn char Lcg16Random.next_byte(&self) @dynamic { ushort* s = (ushort*)self; char result = (char)(*s >> 8); @@ -105,8 +105,8 @@ fn char Lcg16Random.next_byte(&self) : Random return result; } -fn void Lcg16Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_byte, bytes); -fn uint128 Lcg16Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Lcg16Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Lcg16Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn ushort Lcg16Random.next_short(&self) : Random => @char_to_short(self.next_byte()); +fn void Lcg16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_byte, bytes); +fn uint128 Lcg16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Lcg16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Lcg16Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn ushort Lcg16Random.next_short(&self) @dynamic => @char_to_short(self.next_byte()); diff --git a/lib/std/math/random/math.mcg.c3 b/lib/std/math/random/math.mcg.c3 index 764a6eeb8..b1b4e8745 100644 --- a/lib/std/math/random/math.mcg.c3 +++ b/lib/std/math/random/math.mcg.c3 @@ -7,9 +7,9 @@ const MUL_MCG16 @local = 0x93d5; // TODO: Find good constant // Mcg128_64 -def Mcg128Random = distinct uint128; +distinct Mcg128Random (Random) = uint128; -fn void Mcg128Random.set_seed(&self, char[] seed) : Random +fn void Mcg128Random.set_seed(&self, char[] seed) @dynamic { *self = (Mcg128Random)(random::make_seed(uint128, seed) | 1); } @@ -17,12 +17,12 @@ fn void Mcg128Random.set_seed(&self, char[] seed) : Random /** * @require bytes.len > 0 **/ -fn void Mcg128Random.next_bytes(&self, char[] bytes) : Random +fn void Mcg128Random.next_bytes(&self, char[] bytes) @dynamic { @random_value_to_bytes(self.next_long, bytes); } -fn ulong Mcg128Random.next_long(&self) : Random +fn ulong Mcg128Random.next_long(&self) @dynamic { uint128* s = (uint128*)self; ulong result = (ulong)(*s >> 64); @@ -30,19 +30,19 @@ fn ulong Mcg128Random.next_long(&self) : Random return result; } -fn uint128 Mcg128Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn uint Mcg128Random.next_int(&self) : Random => (uint)self.next_long(); -fn ushort Mcg128Random.next_short(&self) : Random => (ushort)self.next_long(); -fn char Mcg128Random.next_byte(&self) : Random => (char)self.next_long(); +fn uint128 Mcg128Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn uint Mcg128Random.next_int(&self) @dynamic => (uint)self.next_long(); +fn ushort Mcg128Random.next_short(&self) @dynamic => (ushort)self.next_long(); +fn char Mcg128Random.next_byte(&self) @dynamic => (char)self.next_long(); // Mcg64RandomState -def Mcg64Random = distinct ulong; +distinct Mcg64Random (Random) = ulong; -fn void Mcg64Random.set_seed(&self, char[] seed) : Random +fn void Mcg64Random.set_seed(&self, char[] seed) @dynamic { *self = (Mcg64Random)random::make_seed(ulong, seed) | 1; } @@ -50,12 +50,12 @@ fn void Mcg64Random.set_seed(&self, char[] seed) : Random /** * @require bytes.len > 0 **/ -fn void Mcg64Random.next_bytes(&self, char[] bytes) : Random +fn void Mcg64Random.next_bytes(&self, char[] bytes) @dynamic { @random_value_to_bytes(self.next_int, bytes); } -fn uint Mcg64Random.next_int(&self) : Random +fn uint Mcg64Random.next_int(&self) @dynamic { ulong* s = (ulong*)self; uint result = (uint)(*s >> 32); @@ -63,22 +63,22 @@ fn uint Mcg64Random.next_int(&self) : Random return result; } -fn uint128 Mcg64Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Mcg64Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort Mcg64Random.next_short(&self) : Random => (ushort)self.next_int(); -fn char Mcg64Random.next_byte(&self) : Random => (char)self.next_int(); +fn uint128 Mcg64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Mcg64Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Mcg64Random.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Mcg64Random.next_byte(&self) @dynamic => (char)self.next_int(); // Mcg32Random -def Mcg32Random = distinct uint; +distinct Mcg32Random (Random) = uint; -fn void Mcg32Random.set_seed(&self, char[] seed) : Random +fn void Mcg32Random.set_seed(&self, char[] seed) @dynamic { *self = (Mcg32Random)random::make_seed(uint, seed) | 1; } -fn ushort Mcg32Random.next_short(&self) +fn ushort Mcg32Random.next_short(&self) @dynamic { uint* s = (uint*)self; ushort result = (ushort)(*s >> 16); @@ -89,22 +89,22 @@ fn ushort Mcg32Random.next_short(&self) /** * @require bytes.len > 0 **/ -fn void Mcg32Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_short, bytes); -fn uint128 Mcg32Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Mcg32Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Mcg32Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn char Mcg32Random.next_byte(&self) : Random => (char)self.next_short(); +fn void Mcg32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); +fn uint128 Mcg32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Mcg32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Mcg32Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn char Mcg32Random.next_byte(&self) @dynamic => (char)self.next_short(); // -------------------------------- Mcg16RandomState -------------------------------- -def Mcg16Random = distinct ushort; +distinct Mcg16Random (Random) = ushort; -fn void Mcg16Random.set_seed(&self, char[] seed) : Random +fn void Mcg16Random.set_seed(&self, char[] seed) @dynamic { *self = (Mcg16Random)random::make_seed(ushort, seed) | 1; } -fn char Mcg16Random.next_byte(&self) : Random +fn char Mcg16Random.next_byte(&self) @dynamic { ushort* s = (ushort*)self; char result = (char)(*s >> 8); @@ -112,8 +112,8 @@ fn char Mcg16Random.next_byte(&self) : Random return result; } -fn void Mcg16Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_byte, bytes); -fn uint128 Mcg16Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Mcg16Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Mcg16Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn ushort Mcg16Random.next_short(&self) : Random => @char_to_short(self.next_byte()); +fn void Mcg16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_byte, bytes); +fn uint128 Mcg16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Mcg16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Mcg16Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn ushort Mcg16Random.next_short(&self) @dynamic => @char_to_short(self.next_byte()); diff --git a/lib/std/math/random/math.msws.c3 b/lib/std/math/random/math.msws.c3 index 3cdb91a9b..efa3e3c67 100644 --- a/lib/std/math/random/math.msws.c3 +++ b/lib/std/math/random/math.msws.c3 @@ -8,19 +8,19 @@ const ODD_PHI16 @local = 0x9e37; const ODD_PHI8 @local = 0x9f; // Msws128 -struct Msws128Random +struct Msws128Random (Random) { uint128 state0, state1; uint128 weyl0, weyl1; } -fn void Msws128Random.set_seed(&self, char[] input) : Random +fn void Msws128Random.set_seed(&self, char[] input) @dynamic { *self = bitcast(random::make_seed(uint128[4], input), Msws128Random); } -fn uint128 Msws128Random.next_int128(&self) +fn uint128 Msws128Random.next_int128(&self) @dynamic { uint128 s0 = self.state0; self.state0 = self.state0 * self.state0 + self.weyl0; @@ -38,26 +38,26 @@ fn uint128 Msws128Random.next_int128(&self) /** * @require bytes.len > 0 **/ -fn void Msws128Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int128, bytes); -fn ulong Msws128Random.next_long(&self) : Random => (ulong)self.next_int128(); -fn uint Msws128Random.next_int(&self) : Random => (uint)self.next_int128(); -fn ushort Msws128Random.next_short(&self) : Random => (ushort)self.next_int128(); -fn char Msws128Random.next_byte(&self) : Random => (char)self.next_int128(); +fn void Msws128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int128, bytes); +fn ulong Msws128Random.next_long(&self) @dynamic => (ulong)self.next_int128(); +fn uint Msws128Random.next_int(&self) @dynamic => (uint)self.next_int128(); +fn ushort Msws128Random.next_short(&self) @dynamic => (ushort)self.next_int128(); +fn char Msws128Random.next_byte(&self) @dynamic => (char)self.next_int128(); // Msws64 -struct Msws64Random +struct Msws64Random (Random) { ulong state0, state1; ulong weyl0, weyl1; } -fn void Msws64Random.set_seed(&self, char[] input) : Random +fn void Msws64Random.set_seed(&self, char[] input) @dynamic { *self = bitcast(random::make_seed(ulong[4], input), Msws64Random); } -fn ulong Msws64Random.next_long(&self) : Random +fn ulong Msws64Random.next_long(&self) @dynamic { ulong s0 = self.state0; self.state0 = self.state0 * self.state0 + self.weyl0; @@ -75,26 +75,26 @@ fn ulong Msws64Random.next_long(&self) : Random /** * @require bytes.len > 0 **/ -fn void Msws64Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_long, bytes); -fn uint128 Msws64Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn uint Msws64Random.next_int(&self) : Random => (uint)self.next_long(); -fn ushort Msws64Random.next_short(&self) : Random => (ushort)self.next_long(); -fn char Msws64Random.next_byte(&self) : Random => (char)self.next_long(); +fn void Msws64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); +fn uint128 Msws64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn uint Msws64Random.next_int(&self) @dynamic => (uint)self.next_long(); +fn ushort Msws64Random.next_short(&self) @dynamic => (ushort)self.next_long(); +fn char Msws64Random.next_byte(&self) @dynamic => (char)self.next_long(); // Msws32 -struct Msws32Random +struct Msws32Random (Random) { uint state0, state1; uint weyl0, weyl1; } -fn void Msws32Random.set_seed(&self, char[] input) : Random +fn void Msws32Random.set_seed(&self, char[] input) @dynamic { *self = bitcast(random::make_seed(uint[4], input), Msws32Random); } -fn uint Msws32Random.next_int(&self) : Random +fn uint Msws32Random.next_int(&self) @dynamic { uint s0 = self.state0; self.state0 = self.state0 * self.state0 + self.weyl0; @@ -112,27 +112,27 @@ fn uint Msws32Random.next_int(&self) : Random /** * @require bytes.len > 0 **/ -fn void Msws32Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int, bytes); -fn uint128 Msws32Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Msws32Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort Msws32Random.next_short(&self) : Random => (ushort)self.next_int(); -fn char Msws32Random.next_byte(&self) : Random => (char)self.next_int(); +fn void Msws32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 Msws32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Msws32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Msws32Random.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Msws32Random.next_byte(&self) @dynamic => (char)self.next_int(); // Msws16 -struct Msws16Random +struct Msws16Random (Random) { ushort state0, state1; ushort weyl0, weyl1; } -fn void Msws16Random.set_seed(&self, char[] input) : Random +fn void Msws16Random.set_seed(&self, char[] input) @dynamic { *self = bitcast(random::make_seed(ushort[4], input), Msws16Random); } -fn ushort Msws16Random.next_short(&self) : Random +fn ushort Msws16Random.next_short(&self) @dynamic { ushort s0 = self.state0; self.state0 = self.state0 * self.state0 + self.weyl0; @@ -150,25 +150,25 @@ fn ushort Msws16Random.next_short(&self) : Random /** * @require bytes.len > 0 **/ -fn void Msws16Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_short, bytes); -fn uint128 Msws16Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Msws16Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Msws16Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn char Msws16Random.next_byte(&self) : Random => (char)self.next_short(); +fn void Msws16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); +fn uint128 Msws16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Msws16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Msws16Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn char Msws16Random.next_byte(&self) @dynamic => (char)self.next_short(); // Msws8 -struct Msws8Random +struct Msws8Random (Random) { char state0, state1; char weyl0, weyl1; } -fn void Msws8Random.set_seed(&self, char[] input) : Random +fn void Msws8Random.set_seed(&self, char[] input) @dynamic { *self = bitcast(random::make_seed(char[4], input), Msws8Random); } -fn char Msws8Random.next_byte(&self) : Random +fn char Msws8Random.next_byte(&self) @dynamic { char s0 = self.state0; self.state0 = self.state0 * self.state0 + self.weyl0; @@ -183,8 +183,8 @@ fn char Msws8Random.next_byte(&self) : Random return s0 + s1; } -fn void Msws8Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_byte, bytes); -fn uint128 Msws8Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Msws8Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Msws8Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn ushort Msws8Random.next_short(&self) : Random => @char_to_short(self.next_byte()); +fn void Msws8Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_byte, bytes); +fn uint128 Msws8Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Msws8Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Msws8Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn ushort Msws8Random.next_short(&self) @dynamic => @char_to_short(self.next_byte()); diff --git a/lib/std/math/random/math.pcg.c3 b/lib/std/math/random/math.pcg.c3 index 1cf3226fa..bafa3ebdd 100644 --- a/lib/std/math/random/math.pcg.c3 +++ b/lib/std/math/random/math.pcg.c3 @@ -15,15 +15,15 @@ const MUL_LCG16 @local = 0x915d; // TODO: Find good constant // -------------------------------- Pcg128_64 -------------------------------- -def Pcg128Random = distinct uint128; +distinct Pcg128Random (Random) = uint128; -fn void Pcg128Random.set_seed(&self, char[] input) : Random +fn void Pcg128Random.set_seed(&self, char[] input) @dynamic { *self = (Pcg128Random)random::make_seed(uint128, input); } -fn ulong Pcg128Random.next_long(&self) +fn ulong Pcg128Random.next_long(&self) @dynamic { const ROT_SHIFT = 64 - 6; uint128* s = (uint128*)self; @@ -36,22 +36,22 @@ fn ulong Pcg128Random.next_long(&self) /** * @require bytes.len > 0 **/ -fn void Pcg128Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_long, bytes); -fn uint128 Pcg128Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn uint Pcg128Random.next_int(&self) : Random => (uint)self.next_long(); -fn ushort Pcg128Random.next_short(&self) : Random => (ushort)self.next_long(); -fn char Pcg128Random.next_byte(&self) : Random => (char)self.next_long(); +fn void Pcg128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); +fn uint128 Pcg128Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn uint Pcg128Random.next_int(&self) @dynamic => (uint)self.next_long(); +fn ushort Pcg128Random.next_short(&self) @dynamic => (ushort)self.next_long(); +fn char Pcg128Random.next_byte(&self) @dynamic => (char)self.next_long(); // -------------------------------- Pcg64_32 -------------------------------- -def Pcg64Random = distinct ulong; +distinct Pcg64Random (Random) = ulong; -fn void Pcg64Random.set_seed(&self, char[] input) : Random +fn void Pcg64Random.set_seed(&self, char[] input) @dynamic { *self = (Pcg64Random)random::make_seed(ulong, input); } -fn uint Pcg64Random.next_int(&self) : Random +fn uint Pcg64Random.next_int(&self) @dynamic { const ROT_SHIFT = 32 - 5; ulong* s = (ulong*)self; @@ -64,23 +64,23 @@ fn uint Pcg64Random.next_int(&self) : Random /** * @require bytes.len > 0 **/ -fn void Pcg64Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int, bytes); -fn uint128 Pcg64Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Pcg64Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort Pcg64Random.next_short(&self) : Random => (ushort)self.next_int(); -fn char Pcg64Random.next_byte(&self) : Random => (char)self.next_int(); +fn void Pcg64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 Pcg64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Pcg64Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Pcg64Random.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Pcg64Random.next_byte(&self) @dynamic => (char)self.next_int(); // -------------------------------- Pcg32_16 -------------------------------- -def Pcg32Random = distinct uint; +distinct Pcg32Random (Random) = uint; -fn void Pcg32Random.set_seed(&self, char[] input) : Random +fn void Pcg32Random.set_seed(&self, char[] input) @dynamic { *self = (Pcg32Random)random::make_seed(uint, input); } -fn ushort Pcg32Random.next_short(&self) : Random +fn ushort Pcg32Random.next_short(&self) @dynamic { const ROT_SHIFT = 16 - 4; uint* s = (uint*)self; @@ -93,22 +93,22 @@ fn ushort Pcg32Random.next_short(&self) : Random /** * @require bytes.len > 0 **/ -fn void Pcg32Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_short, bytes); -fn uint128 Pcg32Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Pcg32Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Pcg32Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn char Pcg32Random.next_byte(&self) : Random => (char)self.next_short(); +fn void Pcg32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); +fn uint128 Pcg32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Pcg32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Pcg32Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn char Pcg32Random.next_byte(&self) @dynamic => (char)self.next_short(); // -------------------------------- Pcg16_8 -------------------------------- -def Pcg16Random = distinct ushort; +distinct Pcg16Random (Random) = ushort; -fn void Pcg16Random.set_seed(&self, char[] input) : Random +fn void Pcg16Random.set_seed(&self, char[] input) @dynamic { *self = (Pcg16Random)random::make_seed(ushort, input); } -fn char Pcg16Random.next_byte(&self) : Random +fn char Pcg16Random.next_byte(&self) @dynamic { const ROT_SHIFT = 8 - 3; ushort* s = (ushort*)self; @@ -118,8 +118,8 @@ fn char Pcg16Random.next_byte(&self) : Random return ((char)(xor >> ROT_SHIFT)).rotr(rot); } -fn void Pcg16Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_byte, bytes); -fn uint128 Pcg16Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Pcg16Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Pcg16Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn ushort Pcg16Random.next_short(&self) : Random => @char_to_short(self.next_byte()); +fn void Pcg16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_byte, bytes); +fn uint128 Pcg16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Pcg16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Pcg16Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn ushort Pcg16Random.next_short(&self) @dynamic => @char_to_short(self.next_byte()); diff --git a/lib/std/math/random/math.sfc.c3 b/lib/std/math/random/math.sfc.c3 index 2b3bb84d9..19f1ca6eb 100644 --- a/lib/std/math/random/math.sfc.c3 +++ b/lib/std/math/random/math.sfc.c3 @@ -10,14 +10,14 @@ const ODD_PHI8 @local = 0x9f; // Sfc128 -def Sfc128Random = distinct uint128[4]; +distinct Sfc128Random (Random) = uint128[4]; -fn void Sfc128Random.set_seed(&self, char[] input) : Random +fn void Sfc128Random.set_seed(&self, char[] input) @dynamic { *self = (Sfc128Random)random::make_seed(uint128[4], input); } -fn uint128 Sfc128Random.next_int128(&self) : Random // TODO: Find good constant +fn uint128 Sfc128Random.next_int128(&self) @dynamic // TODO: Find good constant { uint128* s = (uint128[4]*)self; uint128 result = s[0] + s[1] + s[3]; @@ -31,23 +31,23 @@ fn uint128 Sfc128Random.next_int128(&self) : Random // TODO: Find good constant /** * @require bytes.len > 0 **/ -fn void Sfc128Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int128, bytes); -fn ulong Sfc128Random.next_long(&self) : Random => (uint)self.next_int128(); -fn uint Sfc128Random.next_int(&self) : Random => (uint)self.next_int128(); -fn ushort Sfc128Random.next_short(&self) : Random => (ushort)self.next_int128(); -fn char Sfc128Random.next_byte(&self) : Random => (char)self.next_int128(); +fn void Sfc128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int128, bytes); +fn ulong Sfc128Random.next_long(&self) @dynamic => (uint)self.next_int128(); +fn uint Sfc128Random.next_int(&self) @dynamic => (uint)self.next_int128(); +fn ushort Sfc128Random.next_short(&self) @dynamic => (ushort)self.next_int128(); +fn char Sfc128Random.next_byte(&self) @dynamic => (char)self.next_int128(); // -------------------------------- Sfc64 -------------------------------- -def Sfc64Random = distinct ulong[4]; +distinct Sfc64Random (Random) = ulong[4]; -fn void Sfc64Random.set_seed(&self, char[] input) : Random +fn void Sfc64Random.set_seed(&self, char[] input) @dynamic { *self = (Sfc64Random)random::make_seed(ulong[4], input); } -fn ulong Sfc64Random.next_long(&self) : Random +fn ulong Sfc64Random.next_long(&self) @dynamic { ulong* s = (ulong[4]*)self; ulong result = s[0] + s[1] + s[3]; @@ -61,22 +61,22 @@ fn ulong Sfc64Random.next_long(&self) : Random /** * @require bytes.len > 0 **/ -fn void Sfc64Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_long, bytes); -fn uint128 Sfc64Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn uint Sfc64Random.next_int(&self) : Random => (uint)self.next_long(); -fn ushort Sfc64Random.next_short(&self) : Random => (ushort)self.next_long(); -fn char Sfc64Random.next_byte(&self) : Random => (char)self.next_long(); +fn void Sfc64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); +fn uint128 Sfc64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn uint Sfc64Random.next_int(&self) @dynamic => (uint)self.next_long(); +fn ushort Sfc64Random.next_short(&self) @dynamic => (ushort)self.next_long(); +fn char Sfc64Random.next_byte(&self) @dynamic => (char)self.next_long(); // -------------------------------- Sfc32 -------------------------------- -def Sfc32Random = distinct uint[4]; +distinct Sfc32Random (Random) = uint[4]; -fn void Sfc32Random.set_seed(&self, char[] input) : Random +fn void Sfc32Random.set_seed(&self, char[] input) @dynamic { *self = (Sfc32Random)random::make_seed(uint[4], input); } -fn uint Sfc32Random.next_int(&sfc) : Random +fn uint Sfc32Random.next_int(&sfc) @dynamic { uint* s = (uint[4]*)sfc; uint result = s[0] + s[1] + s[3]; @@ -90,23 +90,23 @@ fn uint Sfc32Random.next_int(&sfc) : Random /** * @require bytes.len > 0 **/ -fn void Sfc32Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int, bytes); -fn uint128 Sfc32Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Sfc32Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort Sfc32Random.next_short(&self) : Random => (ushort)self.next_int(); -fn char Sfc32Random.next_byte(&self) : Random => (char)self.next_int(); +fn void Sfc32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 Sfc32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Sfc32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Sfc32Random.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Sfc32Random.next_byte(&self) @dynamic => (char)self.next_int(); // -------------------------------- Sfc16 -------------------------------- -def Sfc16Random = distinct ushort[4]; +distinct Sfc16Random (Random) = ushort[4]; -fn void Sfc16Random.set_seed(&self, char[] input) : Random +fn void Sfc16Random.set_seed(&self, char[] input) @dynamic { *self = (Sfc16Random)random::make_seed(ushort[4], input); } -fn ushort Sfc16Random.next_short(&seed) : Random +fn ushort Sfc16Random.next_short(&seed) @dynamic { ushort* s = (ushort[4]*)seed; ushort result = s[0] + s[1] + s[3]; @@ -120,23 +120,23 @@ fn ushort Sfc16Random.next_short(&seed) : Random /** * @require bytes.len > 0 **/ -fn void Sfc16Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_short, bytes); -fn uint128 Sfc16Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Sfc16Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Sfc16Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn char Sfc16Random.next_byte(&self) : Random => (char)self.next_short(); +fn void Sfc16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); +fn uint128 Sfc16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Sfc16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Sfc16Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn char Sfc16Random.next_byte(&self) @dynamic => (char)self.next_short(); // -------------------------------- Sfc8 -------------------------------- -def Sfc8Random = distinct char[4]; +distinct Sfc8Random (Random) = char[4]; -fn void Sfc8Random.set_seed(&self, char[] input) : Random +fn void Sfc8Random.set_seed(&self, char[] input) @dynamic { *self = (Sfc8Random)random::make_seed(char[4], input); } -fn char Sfc8Random.next_byte(&self) : Random // TODO: Find better constants +fn char Sfc8Random.next_byte(&self) @dynamic // TODO: Find better constants { char* s = (char[4]*)self; char result = s[0] + s[1] + s[3]; @@ -147,8 +147,8 @@ fn char Sfc8Random.next_byte(&self) : Random // TODO: Find better constants return result; } -fn void Sfc8Random.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_byte, bytes); -fn uint128 Sfc8Random.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong Sfc8Random.next_long(&self) : Random => @int_to_long(self.next_int()); -fn uint Sfc8Random.next_int(&self) : Random => @short_to_int(self.next_short()); -fn ushort Sfc8Random.next_short(&self) : Random => @char_to_short(self.next_byte()); \ No newline at end of file +fn void Sfc8Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_byte, bytes); +fn uint128 Sfc8Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Sfc8Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn uint Sfc8Random.next_int(&self) @dynamic => @short_to_int(self.next_short()); +fn ushort Sfc8Random.next_short(&self) @dynamic => @char_to_short(self.next_byte()); \ No newline at end of file diff --git a/lib/std/math/random/math.simple_random.c3 b/lib/std/math/random/math.simple_random.c3 index 2bf48a542..06e751d94 100644 --- a/lib/std/math/random/math.simple_random.c3 +++ b/lib/std/math/random/math.simple_random.c3 @@ -1,9 +1,9 @@ module std::math::random; -def SimpleRandom = distinct ulong; +distinct SimpleRandom (Random) = ulong; -fn void SimpleRandom.set_seed(&self, char[] seed) : Random +fn void SimpleRandom.set_seed(&self, char[] seed) @dynamic { char[8] full; foreach (i, c : seed) @@ -13,7 +13,7 @@ fn void SimpleRandom.set_seed(&self, char[] seed) : Random *self = (SimpleRandom)(bitcast(full, ulong) ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK; } -fn uint SimpleRandom.next_int(&self) : Random +fn uint SimpleRandom.next_int(&self) @dynamic { ulong nextseed = ((ulong)*self * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK; *self = (SimpleRandom)nextseed; @@ -23,11 +23,11 @@ fn uint SimpleRandom.next_int(&self) : Random /** * @require bytes.len > 0 **/ -fn void SimpleRandom.next_bytes(&self, char[] bytes) : Random => @random_value_to_bytes(self.next_int, bytes); -fn uint128 SimpleRandom.next_int128(&self) : Random => @long_to_int128(self.next_long()); -fn ulong SimpleRandom.next_long(&self) : Random => @int_to_long(self.next_int()); -fn ushort SimpleRandom.next_short(&self) : Random => (ushort)self.next_int(); -fn char SimpleRandom.next_byte(&self) : Random => (char)self.next_int(); +fn void SimpleRandom.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 SimpleRandom.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong SimpleRandom.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort SimpleRandom.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char SimpleRandom.next_byte(&self) @dynamic => (char)self.next_int(); const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D; const long SIMPLE_RANDOM_ADDEND @local = 0xB; diff --git a/lib/std/net/inetaddr.c3 b/lib/std/net/inetaddr.c3 index ea0ca243b..250a61c28 100644 --- a/lib/std/net/inetaddr.c3 +++ b/lib/std/net/inetaddr.c3 @@ -9,7 +9,7 @@ enum IpProtocol : char (AIFamily ai_family) IPV6 (os::AF_INET6), } -struct InetAddress +struct InetAddress (Printable) { bool is_ipv6; union @@ -45,7 +45,7 @@ struct InetAddress } -fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) : Printable +fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic { if (addr.is_ipv6) { @@ -56,7 +56,7 @@ fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) : Printab return formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!; } -fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) : Printable +fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic { if (addr.is_ipv6) { diff --git a/lib/std/net/os/common.c3 b/lib/std/net/os/common.c3 index c375f6ba4..650304b72 100644 --- a/lib/std/net/os/common.c3 +++ b/lib/std/net/os/common.c3 @@ -1,15 +1,15 @@ module std::net::os; const bool SUPPORTS_INET = env::LIBC && (env::WIN32 || env::DARWIN || env::LINUX); -def AIFamily = distinct CInt; -def AIProtocol = distinct CInt; -def AISockType = distinct CInt; -def AIFlags = distinct CInt; +distinct AIFamily = CInt; +distinct AIProtocol = CInt; +distinct AISockType = CInt; +distinct AIFlags = CInt; def Socklen_t = CUInt @if(!env::WIN32); def Socklen_t = usz @if(env::WIN32); -def SockAddrPtr = distinct void*; +distinct SockAddrPtr = void*; struct AddrInfo { diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index 0fa1ed077..4369383e5 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -4,7 +4,7 @@ import libc; const int F_GETFL = 3; const int F_SETFL = 4; -def NativeSocket = distinct inline Fd; +distinct NativeSocket = inline Fd; struct Posix_pollfd { diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index 83eb96a85..886693de4 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -13,7 +13,7 @@ const int FIONREAD = 1074030207; const int FIONBIO = -2147195266; const int FIOASYNC = -2147195267; -def NativeSocket = distinct uptr; +distinct NativeSocket = uptr; extern fn CInt ioctlsocket(NativeSocket, CLong cmd, CULong *argp); extern fn WSAError closesocket(NativeSocket); diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index dc35b5583..64ed9fbcc 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -27,8 +27,8 @@ macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai)) const Duration POLL_FOREVER = -1; -def PollSubscribes = distinct ushort; -def PollEvents = distinct ushort; +distinct PollSubscribes = ushort; +distinct PollEvents = ushort; const PollSubscribes SUBSCRIBE_ANY_READ = os::POLLIN; const PollSubscribes SUBSCRIBE_PRIO_READ = os::POLLPRI; diff --git a/lib/std/net/tcp.c3 b/lib/std/net/tcp.c3 index 4a2c6530e..5e92c756a 100644 --- a/lib/std/net/tcp.c3 +++ b/lib/std/net/tcp.c3 @@ -2,8 +2,8 @@ module std::net::tcp @if(os::SUPPORTS_INET); import std::net @public; import libc; -def TcpSocket = distinct inline Socket; -def TcpServerSocket = distinct inline Socket; +distinct TcpSocket = inline Socket; +distinct TcpServerSocket = inline Socket; fn TcpSocket! connect(String host, uint port, Duration timeout = 0, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED) { diff --git a/lib/std/net/udp.c3 b/lib/std/net/udp.c3 index 451205f33..3ecace47d 100644 --- a/lib/std/net/udp.c3 +++ b/lib/std/net/udp.c3 @@ -1,7 +1,7 @@ module std::net::udp @if(os::SUPPORTS_INET); import std::net @public; -def UdpSocket = distinct inline Socket; +distinct UdpSocket = inline Socket; fn UdpSocket! connect(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED) { diff --git a/lib/std/os/backtrace.c3 b/lib/std/os/backtrace.c3 index 2efaee571..73820abfe 100644 --- a/lib/std/os/backtrace.c3 +++ b/lib/std/os/backtrace.c3 @@ -10,7 +10,7 @@ fault BacktraceFault const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null }; -struct Backtrace +struct Backtrace (Printable) { uptr offset; String function; @@ -30,7 +30,7 @@ fn bool Backtrace.is_unknown(&self) return !self.object_file.len; } -fn usz! Backtrace.to_format(&self, Formatter* formatter) : Printable +fn usz! Backtrace.to_format(&self, Formatter* formatter) @dynamic { if (self.has_file()) { diff --git a/lib/std/os/macos/cf_allocator.c3 b/lib/std/os/macos/cf_allocator.c3 index c43ef2c90..1654b2bde 100644 --- a/lib/std/os/macos/cf_allocator.c3 +++ b/lib/std/os/macos/cf_allocator.c3 @@ -1,7 +1,7 @@ module std::os::macos::cf @if(env::DARWIN); -def CFAllocatorRef = distinct void*; -def CFAllocatorContextRef = distinct void*; +distinct CFAllocatorRef = void*; +distinct CFAllocatorContextRef = void*; def CFOptionFlags = usz; macro CFAllocatorRef default_allocator() => _macos_CFAllocatorGetDefault(); diff --git a/lib/std/os/macos/cf_array.c3 b/lib/std/os/macos/cf_array.c3 index 912024610..391289225 100644 --- a/lib/std/os/macos/cf_array.c3 +++ b/lib/std/os/macos/cf_array.c3 @@ -1,8 +1,8 @@ module std::os::macos::cf @if(env::DARWIN); -def CFArrayRef = distinct void*; -def CFArrayCallBacksRef = distinct void*; -def CFMutableArrayRef = distinct void*; +distinct CFArrayRef = void*; +distinct CFArrayCallBacksRef = void*; +distinct CFMutableArrayRef = void*; extern fn CFArrayRef _macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @extern("CFArrayCreate"); extern fn CFArrayRef _macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @extern("CFArrayCopy"); extern fn CFIndex _macos_CFArrayGetCount(CFArrayRef array) @extern("CFArrayGetCount"); diff --git a/lib/std/os/macos/core_foundation.c3 b/lib/std/os/macos/core_foundation.c3 index 435f04ce9..ae4bfd2db 100644 --- a/lib/std/os/macos/core_foundation.c3 +++ b/lib/std/os/macos/core_foundation.c3 @@ -1,6 +1,6 @@ module std::os::macos::cf @if(env::DARWIN); -def CFTypeRef = distinct void*; +distinct CFTypeRef = void*; def CFIndex = isz; struct CFRange { diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index eb3c56e1d..35c18f32f 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -1,9 +1,9 @@ module std::os::macos::objc @if(env::DARWIN); -def Class = distinct void*; -def Method = distinct void*; -def Ivar = distinct void*; -def Selector = distinct void*; +distinct Class = void*; +distinct Method = void*; +distinct Ivar = void*; +distinct Selector = void*; fault ObjcFailure { diff --git a/lib/std/os/posix/files.c3 b/lib/std/os/posix/files.c3 index 38911424c..1aa5d4b6f 100644 --- a/lib/std/os/posix/files.c3 +++ b/lib/std/os/posix/files.c3 @@ -2,7 +2,7 @@ module std::os::posix @if(env::POSIX); import libc; def Mode_t = uint; -def DIRPtr = distinct void*; +distinct DIRPtr = void*; struct Posix_dirent { diff --git a/lib/std/os/posix/threads.c3 b/lib/std/os/posix/threads.c3 index b1ce5823d..310286583 100644 --- a/lib/std/os/posix/threads.c3 +++ b/lib/std/os/posix/threads.c3 @@ -6,7 +6,7 @@ const PTHREAD_MUTEX_ERRORCHECK = 1; const PTHREAD_MUTEX_RECURSIVE = 2; def PosixThreadFn = fn void*(void*); -def Pthread_t = distinct void*; +distinct Pthread_t = void*; extern fn CInt pthread_create(Pthread_t*, Pthread_attr_t*, PosixThreadFn, void*); extern fn CInt pthread_cancel(Pthread_t*); @@ -88,25 +88,25 @@ extern fn void pthread_cleanup_push(PosixThreadFn routine, void* routine_arg); extern fn int sched_yield(); module std::thread::os @if(env::POSIX && !env::LINUX); -def Pthread_attr_t = distinct ulong[8]; -def Pthread_cond_t = distinct ulong[6]; -def Pthread_condattr_t = distinct ulong[8]; -def Pthread_key_t = distinct ulong; -def Pthread_mutex_t = distinct ulong[8]; -def Pthread_mutexattr_t = distinct ulong[2]; -def Pthread_once_t = distinct ulong[2]; -def Pthread_rwlock_t = distinct ulong[25]; -def Pthread_rwlockattr_t = distinct ulong[3]; -def Pthread_sched_param = distinct ulong; +distinct Pthread_attr_t = ulong[8]; +distinct Pthread_cond_t = ulong[6]; +distinct Pthread_condattr_t = ulong[8]; +distinct Pthread_key_t = ulong; +distinct Pthread_mutex_t = ulong[8]; +distinct Pthread_mutexattr_t = ulong[2]; +distinct Pthread_once_t = ulong[2]; +distinct Pthread_rwlock_t = ulong[25]; +distinct Pthread_rwlockattr_t = ulong[3]; +distinct Pthread_sched_param = ulong; module std::thread::os @if(env::LINUX); -def Pthread_attr_t = distinct ulong[7]; // 24 on 32bit -def Pthread_cond_t = distinct ulong[6]; -def Pthread_condattr_t = distinct uint; -def Pthread_key_t = distinct uint; -def Pthread_mutex_t = distinct ulong[5]; // 24 on 32 bit -def Pthread_mutexattr_t = distinct uint; -def Pthread_once_t = distinct int; -def Pthread_rwlock_t = distinct ulong[7]; // 32 on 3bit -def Pthread_rwlockattr_t = distinct uint; -def Pthread_sched_param = distinct uint; +distinct Pthread_attr_t = ulong[7]; // 24 on 32bit +distinct Pthread_cond_t = ulong[6]; +distinct Pthread_condattr_t = uint; +distinct Pthread_key_t = uint; +distinct Pthread_mutex_t = ulong[5]; // 24 on 32 bit +distinct Pthread_mutexattr_t = uint; +distinct Pthread_once_t = int; +distinct Pthread_rwlock_t = ulong[7]; // 32 on 3bit +distinct Pthread_rwlockattr_t = uint; +distinct Pthread_sched_param = uint; diff --git a/lib/std/os/win32/types.c3 b/lib/std/os/win32/types.c3 index ad6017c78..d1ad70cbe 100644 --- a/lib/std/os/win32/types.c3 +++ b/lib/std/os/win32/types.c3 @@ -188,7 +188,7 @@ union Win32_LARGE_INTEGER ulong quadPart; } -def Win32_CRITICAL_SECTION = distinct ulong[5]; +distinct Win32_CRITICAL_SECTION = ulong[5]; struct Win32_SECURITY_ATTRIBUTES { diff --git a/lib/std/os/win32/wsa.c3 b/lib/std/os/win32/wsa.c3 index cdac04199..9262d0f48 100644 --- a/lib/std/os/win32/wsa.c3 +++ b/lib/std/os/win32/wsa.c3 @@ -2,7 +2,7 @@ module std::os::win32 @if(env::WIN32); // See https://github.com/wine-mirror/wine/blob/master/include/winsock2.h -def WSAError = distinct int; +distinct WSAError = int; struct Win32_pollfd { Win32_SOCKET fd; diff --git a/lib/std/threads/os/thread_none.c3 b/lib/std/threads/os/thread_none.c3 index 17f0f623c..6b916ad74 100644 --- a/lib/std/threads/os/thread_none.c3 +++ b/lib/std/threads/os/thread_none.c3 @@ -1,6 +1,6 @@ module std::thread::os @if (!env::POSIX && !env::WIN32); -def NativeMutex = distinct int; -def NativeConditionVariable = distinct int; -def NativeOnceFlag = distinct int; -def NativeThread = distinct int; \ No newline at end of file +distinct NativeMutex = int; +distinct NativeConditionVariable = int; +distinct NativeOnceFlag = int; +distinct NativeThread = int; \ No newline at end of file diff --git a/lib/std/threads/os/thread_win32.c3 b/lib/std/threads/os/thread_win32.c3 index 19ce1d529..39836491a 100644 --- a/lib/std/threads/os/thread_win32.c3 +++ b/lib/std/threads/os/thread_win32.c3 @@ -1,7 +1,7 @@ module std::thread::os @if(env::WIN32); import std::os::win32; -def NativeThread = distinct inline Win32_HANDLE; +distinct NativeThread = inline Win32_HANDLE; struct NativeMutex { diff --git a/lib/std/threads/thread.c3 b/lib/std/threads/thread.c3 index 7309f272a..2b3d49bf2 100644 --- a/lib/std/threads/thread.c3 +++ b/lib/std/threads/thread.c3 @@ -1,19 +1,19 @@ module std::thread; import std::thread::os; -def MutexType = distinct int; +distinct MutexType = int; const MutexType MUTEX_PLAIN = 0; const MutexType MUTEX_TIMED = 1; const MutexType MUTEX_RECURSIVE = 2; -def Mutex = distinct NativeMutex; -def TimedMutex = distinct inline Mutex; -def RecursiveMutex = distinct inline Mutex; -def TimedRecursiveMutex = distinct inline Mutex; -def ConditionVariable = distinct NativeConditionVariable; -def Thread = distinct NativeThread; -def OnceFlag = distinct NativeOnceFlag; +distinct Mutex = NativeMutex; +distinct TimedMutex = inline Mutex; +distinct RecursiveMutex = inline Mutex; +distinct TimedRecursiveMutex = inline Mutex; +distinct ConditionVariable = NativeConditionVariable; +distinct Thread = NativeThread; +distinct OnceFlag = NativeOnceFlag; def OnceFn = fn void(); def ThreadFn = fn int(void* arg); diff --git a/lib/std/time/time.c3 b/lib/std/time/time.c3 index 055846e7f..9e669076a 100644 --- a/lib/std/time/time.c3 +++ b/lib/std/time/time.c3 @@ -1,9 +1,9 @@ module std::time; -def Time = distinct long; -def Duration = distinct long; -def Clock = distinct ulong; -def NanoDuration = distinct long; +distinct Time = long; +distinct Duration = long; +distinct Clock = ulong; +distinct NanoDuration (Printable) = long; const Duration MS = 1_000; const Duration SEC = 1_000_000; @@ -97,7 +97,7 @@ fn Duration NanoDuration.to_duration(nd) => (Duration)nd / 1_000; fn NanoDuration Duration.to_nano(td) => (NanoDuration)td * 1_000; fn long Duration.to_ms(td) => (long)td / 1_000; -fn usz! NanoDuration.to_format(&self, Formatter* formatter) : Printable +fn usz! NanoDuration.to_format(&self, Formatter* formatter) @dynamic { NanoDuration nd = *self; if (nd == 0) diff --git a/resources/grammar/c3.l b/resources/grammar/c3.l index 6e24cb5de..77f44f40e 100644 --- a/resources/grammar/c3.l +++ b/resources/grammar/c3.l @@ -130,6 +130,7 @@ int comment_level = 0; "module" { count(); return(MODULE); } "nextcase" { count(); return(NEXTCASE); } "null" { count(); return(NUL); } +"protocol" { count(); return(PROTOCOL); } "return" { count(); return(RETURN); } "short" { count(); return(SHORT); } "struct" { count(); return(STRUCT); } diff --git a/resources/grammar/grammar.y b/resources/grammar/grammar.y index dafba720e..a280b6da4 100644 --- a/resources/grammar/grammar.y +++ b/resources/grammar/grammar.y @@ -25,7 +25,7 @@ void yyerror(char *s); %token STRUCT UNION ENUM ELLIPSIS DOTDOT BYTES %token CT_ERROR -%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR CONTINUE BREAK RETURN FOREACH_R FOREACH +%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR CONTINUE BREAK RETURN FOREACH_R FOREACH PROTOCOL %token FN FAULT MACRO CT_IF CT_ENDIF CT_ELSE CT_SWITCH CT_CASE CT_DEFAULT CT_FOR CT_FOREACH CT_ENDFOREACH %token CT_ENDFOR CT_ENDSWITCH BUILTIN IMPLIES INITIALIZE FINALIZE CT_ECHO CT_ASSERT CT_EVALTYPE CT_VATYPE %token TRY CATCH SCOPE DEFER LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF TLOCAL @@ -454,6 +454,16 @@ opt_arg_list_trailing | empty ; +protocols + : TYPE_IDENT opt_generic_parameters + | protocols ',' TYPE_IDENT opt_generic_parameters + ; + +opt_protocol_impl + : '(' protocols ')' + | '(' ')' + | empty + ; enum_constants : enum_constant | enum_constants ',' enum_constant @@ -888,7 +898,7 @@ ct_echo_stmt : CT_ECHO constant_expr ';' bitstruct_declaration - : BITSTRUCT TYPE_IDENT ':' type opt_attributes bitstruct_body + : BITSTRUCT TYPE_IDENT opt_protocol_impl ':' type opt_attributes bitstruct_body bitstruct_body : '{' '}' @@ -981,7 +991,7 @@ struct_or_union ; struct_declaration - : struct_or_union TYPE_IDENT opt_attributes struct_body + : struct_or_union TYPE_IDENT opt_protocol_impl opt_attributes struct_body ; struct_body @@ -1021,7 +1031,7 @@ enum_spec ; enum_declaration - : ENUM TYPE_IDENT enum_spec opt_attributes '{' enum_list '}' + : ENUM TYPE_IDENT opt_protocol_impl enum_spec opt_attributes '{' enum_list '}' ; faults @@ -1030,8 +1040,8 @@ faults ; fault_declaration - : FAULT TYPE_IDENT opt_attributes '{' faults '}' - | FAULT TYPE_IDENT opt_attributes '{' faults ',' '}' + : FAULT TYPE_IDENT opt_protocol_impl opt_attributes '{' faults '}' + | FAULT TYPE_IDENT opt_protocol_impl opt_attributes '{' faults ',' '}' ; func_macro_name @@ -1044,7 +1054,6 @@ func_header | optional_type func_macro_name ; - macro_header : func_header | type '.' func_macro_name @@ -1095,11 +1104,8 @@ func_typedef : FN optional_type fn_parameter_list ; -opt_distinct_inline - : DISTINCT - | DISTINCT INLINE - | INLINE DISTINCT - | INLINE +opt_inline + : INLINE | empty ; @@ -1174,7 +1180,21 @@ define_ident define_declaration : DEF define_ident opt_attributes ';' | DEF define_attribute opt_attributes';' - | DEF TYPE_IDENT opt_attributes '=' opt_distinct_inline typedef_type opt_attributes ';' + | DEF TYPE_IDENT opt_attributes '=' typedef_type opt_attributes ';' + ; + +protocol_body + : func_typedef + | protocol_body func_typedef + ; + +protocol_declaration + : PROTOCOL TYPE_IDENT '{' '}' + | PROTOCOL TYPE_IDENT '{' protocol_body '}' + ; + +distinct_declaration + : DISTINCT TYPE_IDENT opt_protocol_impl opt_attributes '=' opt_inline type opt_generic_parameters ';' ; tl_ct_if @@ -1243,6 +1263,8 @@ top_level | define_declaration | static_declaration | bitstruct_declaration + | distinct_declaration + | protocol_declaration ; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index bef954a6b..73be2bcbe 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -414,7 +414,7 @@ Decl *decl_find_enum_constant(Decl *decl, const char *name) AlignSize decl_find_member_offset(Decl *decl, Decl *member) { static const AlignSize NO_MATCH = ~(AlignSize)0; - while (decl->decl_kind == DECL_DISTINCT) decl = decl->distinct_decl.base_type->decl; + while (decl->decl_kind == DECL_DISTINCT) decl = decl->distinct->type->decl; Decl **members = NULL; switch (decl->decl_kind) { diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index cd0aa0ce5..0b79e7c06 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -31,7 +31,7 @@ static inline Type *type_lowering(Type *type) type = type->optional; continue; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; continue; case TYPE_ENUM: type = type->decl->enums.type_info->type; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 3fd20a6cb..b05f1351b 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -562,12 +562,11 @@ typedef struct bool attr_init : 1; bool attr_finalizer : 1; bool attr_protocol_method : 1; + bool attr_dynamic : 1; bool is_lambda : 1; - bool is_dynamic : 1; union { uint32_t priority; - TypeInfoId protocol_unresolved; DeclId protocol_method; Decl **generated_lambda; Decl **lambda_ct_parameters; @@ -591,7 +590,6 @@ typedef struct typedef struct { bool is_func : 1; - bool is_distinct : 1; union { Decl *decl; @@ -600,17 +598,6 @@ typedef struct } TypedefDecl; -typedef struct -{ - union - { - TypedefDecl typedef_decl; - Type *base_type; - }; -} DistinctDecl; - - - typedef enum { DEFINE_IDENT_ALIAS, @@ -711,14 +698,14 @@ typedef struct Decl_ Decl** decl_list; struct { - Decl **protocols; + TypeInfo **protocols; Decl **methods; union { BitStructDecl bitstruct; // Enums and Fault EnumDecl enums; - DistinctDecl distinct_decl; + TypeInfo *distinct; // Unions, Struct use strukt StructDecl strukt; }; @@ -2608,6 +2595,7 @@ INLINE bool type_is_any_raw(Type *type) return false; } } + INLINE bool type_is_any_protocol_ptr(Type *type) { switch (type->canonical->type_kind) @@ -2636,6 +2624,23 @@ INLINE bool type_is_optional(Type *type) return kind == TYPE_OPTIONAL; } +INLINE bool type_may_implement_protocol(Type *type) +{ + DECL_TYPE_KIND_REAL(kind, type); + switch (kind) + { + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ENUM: + case TYPE_DISTINCT: + case TYPE_FAULTTYPE: + case TYPE_BITSTRUCT: + return true; + default: + return false; + } +} + INLINE bool type_is_void(Type *type) { return type->canonical == type_void; @@ -2756,7 +2761,7 @@ INLINE bool type_may_negate(Type *type) case ALL_INTS: return true; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_TYPEDEF: type = type->canonical; @@ -2880,7 +2885,7 @@ INLINE Type *type_flatten_for_bitstruct(Type *type) RETRY: while (type->type_kind == TYPE_DISTINCT) { - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; } if (type->type_kind == TYPE_ENUM) { @@ -2898,7 +2903,7 @@ static inline Type *type_base(Type *type) switch (type->type_kind) { case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; break; case TYPE_ENUM: type = type->decl->enums.type_info->type; @@ -2921,7 +2926,7 @@ static inline Type *type_flat_inline(Type *type) if (type->type_kind != TYPE_DISTINCT) break; Decl *decl = type->decl; if (!decl->is_substruct) break; - type = decl->distinct_decl.base_type; + type = decl->distinct->type; } while (1); return type; } @@ -2934,7 +2939,7 @@ static inline Type *type_flatten(Type *type) switch (type->type_kind) { case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; break; case TYPE_OPTIONAL: type = type->optional; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 2009088e8..4753ec8ce 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -895,6 +895,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) case DECL_UNION: case DECL_STRUCT: copy_decl_type(copy); + MACRO_COPY_TYPE_LIST(copy->protocols); MACRO_COPY_DECL_LIST(copy->strukt.members); MACRO_COPY_DECL_LIST(copy->methods); break; @@ -903,6 +904,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) UNREACHABLE case DECL_BITSTRUCT: copy_decl_type(copy); + MACRO_COPY_TYPE_LIST(copy->protocols); MACRO_COPY_DECL_LIST(copy->bitstruct.members); MACRO_COPY_TYPE(copy->bitstruct.base_type); MACRO_COPY_DECL_LIST(copy->methods); @@ -910,6 +912,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) case DECL_ENUM: case DECL_FAULT: copy_decl_type(copy); + MACRO_COPY_TYPE_LIST(copy->protocols); MACRO_COPY_DECL_LIST(copy->methods); MACRO_COPY_DECL_LIST(copy->enums.parameters); MACRO_COPY_TYPE(copy->enums.type_info); @@ -965,13 +968,9 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) break; case DECL_DISTINCT: copy_decl_type(copy); + MACRO_COPY_TYPE_LIST(copy->protocols); MACRO_COPY_DECL_LIST(copy->methods); - if (copy->distinct_decl.typedef_decl.is_func) - { - MACRO_COPY_DECL(copy->distinct_decl.typedef_decl.decl); - break; - } - MACRO_COPY_TYPE(copy->distinct_decl.typedef_decl.type_info); + MACRO_COPY_TYPE(copy->distinct); break; case DECL_CT_ECHO: MACRO_COPY_AST(decl->ct_echo_decl); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 5b9ae3c34..883393596 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -775,6 +775,7 @@ typedef enum ATTRIBUTE_BUILTIN, ATTRIBUTE_CALLCONV, ATTRIBUTE_DEPRECATED, + ATTRIBUTE_DYNAMIC, ATTRIBUTE_EXPORT, ATTRIBUTE_EXTERN, ATTRIBUTE_FINALIZER, @@ -832,6 +833,7 @@ typedef enum ANALYSIS_CT_ECHO, ANALYSIS_CT_ASSERT, ANALYSIS_FUNCTIONS, + ANALYSIS_PROTOCOL, ANALYSIS_FINALIZE, ANALYSIS_LAST = ANALYSIS_FINALIZE } AnalysisStage; diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 96585b366..bfc19d2b6 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -609,7 +609,7 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) return; } case TYPE_DISTINCT: - expr_rewrite_to_const_zero(expr, type->decl->distinct_decl.base_type); + expr_rewrite_to_const_zero(expr, type->decl->distinct->type); break; } expr->type = type; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index cb3e1f236..2e5bf887c 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -117,6 +117,24 @@ INLINE void llvm_emit_xtor(GenContext *c, LLVMValueRef *list, const char *name) LLVMSetLinkage(global, LLVMAppendingLinkage); LLVMSetInitializer(global, array); } + +LLVMValueRef llvm_get_selector(GenContext *c, const char *name) +{ + scratch_buffer_clear(); + scratch_buffer_printf("$sel.%s", name); + const char *sel_name = scratch_buffer_to_string(); + LLVMValueRef selector_old = LLVMGetNamedGlobal(c->module, sel_name); + if (selector_old) return selector_old; + size_t name_len = strlen(name); + LLVMTypeRef char_array_type = LLVMArrayType(c->byte_type, name_len + 1); + LLVMValueRef selector = llvm_add_global_raw(c, sel_name, char_array_type, 0); + LLVMSetGlobalConstant(selector, 1); + LLVMSetInitializer(selector, llvm_get_zstring(c, name, name_len)); + LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage); + llvm_set_comdat(c, selector); + return selector; +} + void llvm_emit_constructors_and_destructors(GenContext *c) { llvm_emit_xtor(c, c->constructors, "llvm.global_ctors"); @@ -1082,14 +1100,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl) case DECL_FUNC: if (decl->func_decl.attr_protocol_method) { - size_t name_len = strlen(decl->name); - LLVMTypeRef char_array_type = LLVMArrayType(c->byte_type, name_len + 1); - LLVMValueRef selector = llvm_add_global_raw(c, decl_get_extname(decl), char_array_type, 0); - LLVMSetGlobalConstant(selector, 1); - LLVMSetInitializer(selector, llvm_get_zstring(c, decl->name, name_len)); - LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage); - llvm_set_comdat(c, selector); - return decl->backend_ref = selector; + return decl->backend_ref = llvm_get_selector(c, decl->name); } backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type)); llvm_append_function_attributes(c, decl); diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index ccfb4f2dc..e59bb93e8 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -465,7 +465,7 @@ static LLVMMetadataRef llvm_debug_typedef_type(GenContext *c, Type *type) NULL, 0, NULL, 0); } - Type *original_type = type->type_kind == TYPE_TYPEDEF ? type->canonical : decl->distinct_decl.base_type; + Type *original_type = type->type_kind == TYPE_TYPEDEF ? type->canonical : decl->distinct->type; // Use forward references in case we haven't resolved the original type, since we could have this: if (!type->canonical->backend_debug_type) diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index fadfa2ba6..91c631034 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -411,7 +411,7 @@ void llvm_emit_return_implicit(GenContext *c) void llvm_emit_function_body(GenContext *c, Decl *decl, StacktraceType type) { DEBUG_LOG("Generating function %s.", decl->extname); - if (decl->func_decl.is_dynamic) vec_add(c->dynamic_functions, decl); + if (decl->func_decl.attr_dynamic) vec_add(c->dynamic_functions, decl); assert(decl->backend_ref); if (decl->func_decl.attr_init || decl->func_decl.attr_finalizer) { @@ -692,8 +692,8 @@ void llvm_emit_dynamic_functions(GenContext *c, Decl **funcs) scratch_buffer_append("$ct.dyn."); scratch_buffer_append(decl_get_extname(decl)); LLVMValueRef global = llvm_add_global_raw(c, scratch_buffer_to_string(), c->dtable_type, 0); - Decl *proto = declptr(decl->func_decl.protocol_method); - LLVMValueRef proto_ref = llvm_get_ref(c, proto); + Decl *proto = declptrzero(decl->func_decl.protocol_method); + LLVMValueRef proto_ref = proto ? llvm_get_ref(c, proto) : llvm_get_selector(c, decl->name); LLVMValueRef vals[3] = { llvm_get_ref(c, decl), proto_ref, LLVMConstNull(c->ptr_type) }; LLVMSetInitializer(global, LLVMConstNamedStruct(c->dtable_type, vals, 3)); LLVMValueRef type_id_ptr = LLVMBuildIntToPtr(builder, llvm_get_typeid(c, type), c->ptr_type, ""); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 15eb1899e..edbfde1b5 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -492,6 +492,9 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_ref, ABIArgInfo *info, BEValue *be_value, Type *type); void llvm_emit_vararg_parameter(GenContext *c, BEValue *value, Type *vararg_type, ABIArgInfo *abi_info, Expr **varargs, Expr *vararg_splat); +// -- Dynamic protocol -- +LLVMValueRef llvm_get_selector(GenContext *c, const char *name); + // -- C3 Lowering -- void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 9980a5115..eec389a76 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -26,7 +26,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) case DECL_TYPEDEF: return llvm_get_type(c, decl->typedef_decl.type_info->type); case DECL_DISTINCT: - return llvm_get_type(c, decl->distinct_decl.base_type); + return llvm_get_type(c, decl->distinct->type); case DECL_STRUCT: { LLVMTypeRef *types = NULL; @@ -649,7 +649,7 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) case TYPE_POINTER: return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_POINTER, type->pointer, 0, NULL, false); case TYPE_DISTINCT: - return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct_decl.base_type, 0, NULL, false); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct->type, 0, NULL, false); case TYPE_ENUM: return llvm_get_introspection_for_enum(c, type); case TYPE_FAULTTYPE: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index d68731151..188cde5d9 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -139,15 +139,6 @@ static Expr *parse_precedence(ParseContext *c, Precedence precedence) return parse_precedence_with_left_side(c, left_side, precedence); } -/** - * Since generic parameters can't be longer expressions, we require they have - * ADDITIVE precedence or higher. This excludes <> and we can use those safely. - */ -Expr *parse_generic_parameter(ParseContext *c) -{ - return parse_precedence(c, PREC_ADDITIVE); -} - /* * Parse anything with higher precedence than &&, that means <= >= etc are ok. */ @@ -156,8 +147,6 @@ static inline Expr *parse_relational_expr(ParseContext *c) return parse_precedence(c, PREC_RELATIONAL); } - - /** * catch_unwrap ::= CATCH (IDENT | type? IDENT '=' catch_chain) | catch_chain * catch_chain ::= try_rhs_expr (',' try_rhs_expr)* diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 863e9326c..9baed5880 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -141,13 +141,9 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t *tokens_ref = NULL; - SourceSpan span = c->span; - bool is_old_style = try_consume(c, TOKEN_LESS); - if (!is_old_style && !try_consume(c, TOKEN_LGENPAR)) return true; + if (!try_consume(c, TOKEN_LGENPAR)) return true; - // TODO remove after deprecation time - TokenType end_token = is_old_style ? TOKEN_GREATER : TOKEN_RGENPAR; - if (try_consume(c, end_token)) RETURN_SEMA_ERROR_HERE("Generic parameter list cannot be empty."); + if (try_consume(c, TOKEN_RGENPAR)) RETURN_SEMA_ERROR_HERE("Generic parameter list cannot be empty."); // No params while (1) @@ -171,12 +167,7 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t advance(c); if (!try_consume(c, TOKEN_COMMA)) { - if (!consume(c, end_token, "Expected '>)'.")) return false; - if (is_old_style) - { - span = extend_span_with_token(span, c->prev_span); - sema_warning_at(span, "Generics with <...> syntax is deprecated, use (<...>) instead."); - } + if (!consume(c, TOKEN_RGENPAR, "Expected '>)'.")) return false; return true; } } @@ -704,6 +695,24 @@ TypeInfo *parse_optional_type(ParseContext *c) // --- Decl parsing +bool parse_protocol_impls(ParseContext *c, TypeInfo ***protocols_ref) +{ + if (!try_consume(c, TOKEN_LPAREN)) return true; + TypeInfo **protocols = NULL; + while (!try_consume(c, TOKEN_RPAREN)) + { + ASSIGN_TYPE_OR_RET(TypeInfo *protocol, parse_type(c), false); + vec_add(protocols, protocol); + if (!try_consume(c, TOKEN_COMMA)) + { + CONSUME_OR_RET(TOKEN_RPAREN, false); + break; + } + } + *protocols_ref = protocols; + return true; +} + /** * after_type ::= (CT_IDENT | IDENT) attributes? ('=' decl_initializer)? */ @@ -1525,9 +1534,39 @@ bool parse_struct_body(ParseContext *c, Decl *parent) } +/** + * distinct_declaration ::= 'distinct' TYPE_IDENT opt_protocols '=' 'inline'? type ';' + */ +static inline Decl *parse_distinct_declaration(ParseContext *c) +{ + advance_and_verify(c, TOKEN_DISTINCT); + + Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_DISTINCT); + + if (!consume_type_name(c, "distinct type")) return poisoned_decl; + if (!parse_protocol_impls(c, &decl->protocols)) return poisoned_decl; + + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + + decl->type->type_kind = TYPE_DISTINCT; + decl->decl_kind = DECL_DISTINCT; + + CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); + + decl->is_substruct = try_consume(c, TOKEN_INLINE); + + // 2. Now parse the type which we know is here. + ASSIGN_TYPE_OR_RET(decl->distinct, parse_type(c), poisoned_decl); + + assert(!tok_is(c, TOKEN_LGENPAR)); + + RANGE_EXTEND_PREV(decl); + CONSUME_EOS_OR_RET(poisoned_decl); + return decl; +} /** - * struct_declaration ::= struct_or_union TYPE_IDENT opt_attributes struct_body + * struct_declaration ::= struct_or_union TYPE_IDENT opt_protocols opt_attributes struct_body */ static inline Decl *parse_struct_declaration(ParseContext *c) { @@ -1539,7 +1578,9 @@ static inline Decl *parse_struct_declaration(ParseContext *c) Decl *decl = decl_new_with_type(symstr(c), c->span, decl_from_token(type)); if (!consume_type_name(c, type_name)) return poisoned_decl; + if (!parse_protocol_impls(c, &decl->protocols)) return poisoned_decl; if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + if (!parse_struct_body(c, decl)) return poisoned_decl; DEBUG_LOG("Parsed %s %s completely.", type_name, decl->name); @@ -1726,17 +1767,15 @@ static bool parse_macro_params(ParseContext *c, Decl *macro) * * @return NULL if parsing failed, otherwise a list of Type* */ -static inline Expr **parse_generic_parameters(ParseContext *c, bool old_style) +static inline Expr **parse_generic_parameters(ParseContext *c) { Expr **params = NULL; - // TODO remove deprecation - TokenType end_token = old_style ? TOKEN_GREATER : TOKEN_RGENPAR; - while (!try_consume(c, end_token)) + while (!try_consume(c, TOKEN_RGENPAR)) { - ASSIGN_EXPR_OR_RET(Expr *arg, old_style ? parse_generic_parameter(c) : parse_expr(c), NULL); + ASSIGN_EXPR_OR_RET(Expr *arg, parse_expr(c), NULL); vec_add(params, arg); TokenType tok = c->tok; - if (tok != end_token) + if (tok != TOKEN_RGENPAR) { TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected ',' after the argument.", NULL); } @@ -1781,18 +1820,6 @@ static inline Decl *parse_def_type(ParseContext *c) } CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); - bool distinct = false; - bool is_inline = false; - if (tok_is(c, TOKEN_INLINE)) - { - SEMA_ERROR_HERE("'inline' must always follow 'distinct'."); - return poisoned_decl; - } - if (try_consume(c, TOKEN_DISTINCT)) - { - distinct = true; - is_inline = try_consume(c, TOKEN_INLINE); - } // 1. Did we have `fn`? In that case it's a function pointer. if (try_consume(c, TOKEN_FN)) @@ -1800,8 +1827,6 @@ static inline Decl *parse_def_type(ParseContext *c) decl->decl_kind = DECL_TYPEDEF; decl_add_type(decl, TYPE_TYPEDEF); decl->typedef_decl.is_func = true; - decl->typedef_decl.is_distinct = distinct; - decl->is_substruct = is_inline; Decl *decl_type = decl_new(DECL_FNTYPE, decl->name, c->prev_span); decl->typedef_decl.decl = decl_type; ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl); @@ -1821,26 +1846,10 @@ static inline Decl *parse_def_type(ParseContext *c) assert(!tok_is(c, TOKEN_LGENPAR)); - REMINDER("Distinct fn??"); decl->typedef_decl.type_info = type_info; decl->typedef_decl.is_func = false; - if (distinct) - { - decl->decl_kind = DECL_DISTINCT; - decl_add_type(decl, TYPE_DISTINCT); - decl->is_substruct = is_inline; - TypedefDecl typedef_decl = decl->typedef_decl; // Ensure value semantics. - decl->distinct_decl.typedef_decl = typedef_decl; - decl->protocols = NULL; - decl->methods = NULL; - decl->type->type_kind = TYPE_DISTINCT; - decl->decl_kind = DECL_DISTINCT; - } - else - { - decl->decl_kind = DECL_TYPEDEF; - decl_add_type(decl, TYPE_TYPEDEF); - } + decl->decl_kind = DECL_TYPEDEF; + decl_add_type(decl, TYPE_TYPEDEF); if (!parse_attributes_for_global(c, decl)) return poisoned_decl; RANGE_EXTEND_PREV(decl); @@ -1933,22 +1942,16 @@ static inline Decl *parse_def_ident(ParseContext *c) decl->define_decl.span = c->span; advance(c); - bool old_style_encountered = try_consume(c, TOKEN_LESS); - - if (old_style_encountered || try_consume(c, TOKEN_LGENPAR) ) + if (try_consume(c, TOKEN_LGENPAR)) { decl->define_decl.define_kind = DEFINE_IDENT_GENERIC; - Expr **params = parse_generic_parameters(c, old_style_encountered); + Expr **params = parse_generic_parameters(c); if (!params) return poisoned_decl; decl->define_decl.generic_params = params; } if (!parse_attributes_for_global(c, decl)) return poisoned_decl; RANGE_EXTEND_PREV(decl); - if (old_style_encountered) - { - sema_warning_at(decl->span, "Use of <...> for generics is deprecated, please use (<...>) instead."); - } CONSUME_EOS_OR_RET(poisoned_decl); return decl; } @@ -2111,7 +2114,7 @@ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs) /** - * fault_declaration ::= FAULT TYPE_IDENT opt_attributes '{' faults ','? '}' + * fault_declaration ::= FAULT TYPE_IDENT opt_protocols opt_attributes '{' faults ','? '}' */ static inline Decl *parse_fault_declaration(ParseContext *c) { @@ -2119,6 +2122,7 @@ static inline Decl *parse_fault_declaration(ParseContext *c) Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_FAULT); if (!consume_type_name(c, "fault")) return poisoned_decl; + if (!parse_protocol_impls(c, &decl->protocols)) return poisoned_decl; if (!parse_attributes_for_global(c, decl)) return poisoned_decl; @@ -2189,7 +2193,7 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref /** * Parse an enum declaration (after "enum") * - * enum ::= ENUM TYPE_IDENT (':' type enum_param_list)? opt_attributes '{' enum_body '}' + * enum ::= ENUM TYPE_IDENT opt_protocols (':' type enum_param_list)? opt_attributes '{' enum_body '}' * enum_body ::= enum_def (',' enum_def)* ','? * enum_def ::= CONST_IDENT ('(' arg_list ')')? */ @@ -2199,6 +2203,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c) Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_ENUM); if (!consume_type_name(c, "enum")) return poisoned_decl; + if (!parse_protocol_impls(c, &decl->protocols)) return poisoned_decl; TypeInfo *type = NULL; // Parse the spec @@ -2294,11 +2299,6 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool } if (!parse_fn_parameter_list(c, &(func->func_decl.signature), is_interface)) return poisoned_decl; if (!parse_attributes_for_global(c, func)) return poisoned_decl; - if (try_consume(c, TOKEN_COLON)) - { - ASSIGN_TYPEID_OR_RET(func->func_decl.protocol_unresolved, parse_type(c), poisoned_decl); - func->func_decl.is_dynamic = true; - } if (is_interface) { if (tok_is(c, TOKEN_LBRACE) || tok_is(c, TOKEN_IMPLIES)) @@ -2684,8 +2684,8 @@ static Decl *parse_exec(ParseContext *c) * top_level_statement ::= struct_declaration | enum_declaration | fault_declaration | const_declaration * | global_declaration | macro_declaration | func_definition | typedef_declaration * | conditional_compilation | define_declaration | import_declaration | module_declaration + * | distinct_declaration | protocol_declaration * | static_declaration | ct_assert_declaration | ct_echo_declaration | bitstruct_declaration - * | protocol_declaration * * @return Decl* or a poison value if parsing failed */ @@ -2806,6 +2806,10 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) if (contracts) goto CONTRACT_NOT_ALLOWED; decl = parse_protocol_declaration(c); break; + case TOKEN_DISTINCT: + if (contracts) goto CONTRACT_NOT_ALLOWED; + decl = parse_distinct_declaration(c); + break; case TOKEN_CONST: if (contracts) goto CONTRACT_NOT_ALLOWED; decl = parse_top_level_const_declaration(c); diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 12fcbd538..d6bdb7d28 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -80,7 +80,6 @@ bool try_consume(ParseContext *c, TokenType type); bool consume(ParseContext *c, TokenType type, const char *message, ...); bool consume_const_name(ParseContext *c, const char* type); Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, Precedence precedence); -Expr *parse_generic_parameter(ParseContext *c); INLINE const char *symstr(ParseContext *c) { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 0d4ef3396..da055596d 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -958,6 +958,26 @@ static bool rule_vecarr_to_infer(CastContext *cc, bool is_explicit, bool is_sile return cast_is_allowed(cc, is_explicit, is_silent); } +static bool rule_ptr_to_protocol(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (is_explicit) return true; + + Type *pointee = cc->from_type->pointer; + if (type_may_implement_protocol(pointee)) + { + Type *protocol = cc->to->pointer; + Decl *pointee_decl = pointee->decl; + FOREACH_BEGIN(TypeInfo *protocol_type, pointee_decl->protocols) + if (!sema_resolve_type_info(cc->context, protocol_type, RESOLVE_TYPE_ALLOW_ANY)) return false; + if (protocol_type->type == protocol) return true; + FOREACH_END(); + } + if (is_silent) return false; + RETURN_SEMA_ERROR(cc->expr, "%s cannot be implicitly cast to %s, but you can use an explicit " + "cast to (unsafely) assume the protocol is implemented.", + type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type)); +} + static bool rule_ptr_to_infer(CastContext *cc, bool is_explicit, bool is_silent) { if (cc->to->type_kind != TYPE_POINTER) return sema_cast_error(cc, false, is_silent); @@ -1367,7 +1387,7 @@ static inline Type *type_flatten_to_int(Type *type) switch (type->type_kind) { case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; break; case TYPE_OPTIONAL: type = type->optional; @@ -1891,6 +1911,7 @@ static void cast_typeid_to_bool(Expr *expr, Type *to_type) #define RSAFE &rule_sa_to_infer /* Subarray -> infer (only if subarray is constant or can infer) */ #define RVAFE &rule_vecarr_to_infer /* Vec/arr -> infer (if base matches) */ #define RPTFE &rule_ptr_to_infer /* Ptr -> infer (if pointee may infer) */ +#define RPTPR &rule_ptr_to_protocol /* Ptr -> Protocol if the pointee implements it */ CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { // void, wildc, bool, int, float, ptr, sarr, vec, bitst, distc, array, strct, union, any, prot, fault, enum, typid, afaul, voidp, arrpt, infer (to) @@ -1899,7 +1920,7 @@ CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { {REXPL, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BOOL {REXPL, _NO__, REXPL, RIFIF, RINFL, RINPT, _NO__, ROKOK, RINBS, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RINEN, _NO__, _NO__, RINPT, RINPT, _NO__}, // INT {REXPL, _NO__, REXPL, REXPL, RIFIF, _NO__, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // FLOAT - {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE}, // PTR + {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RPTPR, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE}, // PTR {REXPL, _NO__, REXPL, _NO__, _NO__, RSAPT, RSASA, RSAVA, _NO__, RXXDI, RSAVA, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, RSAPT, RSAFE}, // SARRAY {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVCVC, _NO__, RXXDI, RVCAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE}, // VECTOR {REXPL, _NO__, _NO__, RBSIN, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, RBSAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BITSTRUCT diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 15545b587..7ce9e3db3 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -43,7 +43,7 @@ static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **att bool *erase_decl); static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_check_section(SemaContext *context, Attr *attr); -static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl); +static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl, bool *erase_decl); static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl); bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span); @@ -57,7 +57,7 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param, bool *has_default); static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl); -static inline bool sema_analyse_error(SemaContext *context, Decl *decl); +static inline bool sema_analyse_error(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_check_section(SemaContext *context, Attr *attr) @@ -132,6 +132,30 @@ static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *curr return true; } +static inline bool sema_analyse_protocols(SemaContext *context, Decl *decl) +{ + TypeInfo **protocols = decl->protocols; + unsigned count = vec_size(protocols); + for (unsigned i = 0; i < count; i++) + { + TypeInfo *proto = protocols[i]; + if (!sema_resolve_type_info(context, proto, RESOLVE_TYPE_ALLOW_ANY)) return false; + Type *proto_type = proto->type->canonical; + if (proto_type->type_kind != TYPE_PROTOCOL) + { + RETURN_SEMA_ERROR(proto, "Expected a protocol name."); + } + for (unsigned j = 0; j < i; j++) + { + if (protocols[j]->type->canonical == proto_type) + { + RETURN_SEMA_ERROR(proto, "Included protocol '%s' more than once, please remove duplicates.", proto_type->name); + } + } + } + return true; +} + static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl, bool *erase_decl) { if (decl->resolve_status == RESOLVE_DONE) @@ -468,6 +492,7 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *er if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); if (*erase_decl) return true; + if (!sema_analyse_protocols(context, decl)) return decl_poison(decl); DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : ".anon"); bool success; @@ -750,6 +775,7 @@ static bool sema_analyse_protocol(SemaContext *context, Decl *decl, bool *erase_ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_BITSTRUCT, erase_decl)) return decl_poison(decl); + if (!sema_analyse_protocols(context, decl)) return decl_poison(decl); if (*erase_decl) return true; DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : ".anon"); if (!sema_resolve_type_info(context, decl->bitstruct.base_type, RESOLVE_TYPE_DEFAULT)) return false; @@ -1088,24 +1114,17 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl, bool { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_DISTINCT, erase)) return false; if (*erase) return true; + if (!sema_analyse_protocols(context, decl)) return decl_poison(decl); - if (decl->distinct_decl.typedef_decl.is_func) - { - Decl *fn_decl = decl->distinct_decl.typedef_decl.decl; - fn_decl->unit = decl->unit; - fn_decl->type = type_new_func(fn_decl, &fn_decl->fntype_decl); - decl->distinct_decl.base_type = type_get_ptr(fn_decl->type); - return true; - } - TypeInfo *info = decl->distinct_decl.typedef_decl.type_info; + TypeInfo *info = decl->distinct; if (!sema_resolve_type_info(context, info, RESOLVE_TYPE_DEFAULT)) return false; if (type_is_optional(info->type)) { SEMA_ERROR(decl, "You cannot create a distinct type from an optional."); return false; } - Type *base = info->type->canonical; - decl->distinct_decl.base_type = base; + // Distinct types drop the canonical + Type *base = info->type = info->type->canonical; switch (base->type_kind) { case TYPE_FUNC: @@ -1210,6 +1229,7 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM, erase_decl)) return decl_poison(decl); if (*erase_decl) return true; + if (!sema_analyse_protocols(context, decl)) return decl_poison(decl); // Resolve the type of the enum. if (!sema_resolve_type_info(context, decl->enums.type_info, RESOLVE_TYPE_DEFAULT)) return false; @@ -1353,8 +1373,12 @@ ERR: return false; } -static inline bool sema_analyse_error(SemaContext *context, Decl *decl) +static inline bool sema_analyse_error(SemaContext *context, Decl *decl, bool *erase_decl) { + if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FAULT, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; + if (!sema_analyse_protocols(context, decl)) return decl_poison(decl); + bool success = true; unsigned enums = vec_size(decl->enums.values); @@ -1651,32 +1675,44 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type } -static inline Decl *sema_find_protocol_for_method(SemaContext *context, Decl **protocols, Decl *decl) + +static inline Decl *sema_find_protocol_for_method(SemaContext *context, Type *parent_type, Decl *method) { - const char *name = decl->name; + // Can the parent even implement a protocol? + switch (parent_type->type_kind) + { + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_DISTINCT: + case TYPE_FAULTTYPE: + case TYPE_ENUM: + break; + default: + return NULL; + } + const char *name = method->name; Decl *first_match = NULL; Decl *first_protocol = NULL; - FOREACH_BEGIN(Decl *proto, protocols) - FOREACH_BEGIN(Decl *method, proto->protocol_decl.protocol_methods) - if (method->name == name) + FOREACH_BEGIN(TypeInfo *proto, parent_type->decl->protocols) + FOREACH_BEGIN(Decl *proto_method, proto->type->decl->protocol_decl.protocol_methods) + if (proto_method->name == name) { if (first_match) { - SEMA_ERROR(decl, "Both '%s' and '%s' protocols have a method matching '%s', which prevents it from being implemented.", - first_protocol->name, proto->name, name); - return NULL; + SEMA_ERROR(method, "Both '%s' and '%s' protocols have a method matching '%s', which prevents it from being implemented.", + first_protocol->name, proto->type->name, name); + return poisoned_decl; } - first_match = method; - first_protocol = proto; + first_match = proto_method; + first_protocol = proto->type->decl; } FOREACH_END(); FOREACH_END(); if (!first_match) { - SEMA_ERROR(decl, "No matching implemented protocol has the method '%s'", name); return NULL; } - if (!sema_analyse_decl(context, first_protocol)) return NULL; + if (!sema_analyse_decl(context, first_protocol)) return poisoned_decl; return first_match; } @@ -1697,76 +1733,66 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) if (!sema_resolve_type_info(context, parent_type, RESOLVE_TYPE_FUNC_METHOD)) return false; Type *par_type = parent_type->type->canonical; Decl **params = decl->func_decl.signature.params; - bool is_dynamic = decl->func_decl.is_dynamic; + bool is_dynamic = decl->func_decl.attr_dynamic; if (!vec_size(params)) RETURN_SEMA_ERROR(decl, "A method must start with an argument of the type " "it is a method of, e.g. 'fn Foo.test(Foo* foo)'."); if (!sema_is_valid_method_param(context, params[0], par_type, is_dynamic)) return false; if (is_dynamic) { - TypeInfo *parent = type_infoptr(decl->func_decl.protocol_unresolved); - if (!sema_resolve_type_info(context, parent, RESOLVE_TYPE_ALLOW_ANY)) return false; - Type *protocol = parent->type; - if (protocol->type_kind != TYPE_PROTOCOL) RETURN_SEMA_ERROR(parent, "Expected a protocol not a normal type."); - Decl *proto_decl = protocol->decl; - if (!sema_analyse_decl(context, proto_decl)) return false; - const char *name = decl->name; - Decl *implemented_method = NULL; - FOREACH_BEGIN(Decl *method, proto_decl->protocol_decl.protocol_methods) - if (method->name == name) + if (!sema_resolve_type_decl(context, par_type)) return false; + Decl *implemented_method = sema_find_protocol_for_method(context, par_type, decl); + if (!decl_ok(implemented_method)) return false; + if (implemented_method) + { + Signature protocol_sig = implemented_method->func_decl.signature; + Signature this_sig = decl->func_decl.signature; + Type *any_rtype = typeget(protocol_sig.rtype); + Type *this_rtype = typeget(this_sig.rtype); + if (any_rtype->canonical != this_rtype->canonical) { - implemented_method = method; - break; - } - FOREACH_END(); - if (!implemented_method) - { - RETURN_SEMA_ERROR(decl, "No method named '%s' was found in protocol '%s'.", name, proto_decl->name); - } - - Signature protocol_sig = implemented_method->func_decl.signature; - Signature this_sig = decl->func_decl.signature; - Type *any_rtype = typeget(protocol_sig.rtype); - Type *this_rtype = typeget(this_sig.rtype); - if (any_rtype->canonical != this_rtype->canonical) - { - SEMA_ERROR(type_infoptr(this_sig.rtype), "The prototype method has a return type %s, but this function returns %s, they need to match.", - type_quoted_error_string(any_rtype), type_quoted_error_string(this_rtype)); - SEMA_NOTE(type_infoptr(protocol_sig.rtype), "The interface definition is here."); - return false; - } - Decl **any_params = protocol_sig.params; - Decl **this_params = this_sig.params; - unsigned any_param_count = vec_size(any_params); - unsigned this_param_count = vec_size(this_params); - if (any_param_count != this_param_count) - { - if (any_param_count > this_param_count) - { - SEMA_ERROR(decl, "This function is missing parameters, %d parameters were expected.", any_param_count); - SEMA_NOTE(any_params[this_param_count], "Compare with the interface definition."); + SEMA_ERROR(type_infoptr(this_sig.rtype), "The prototype method has a return type %s, but this function returns %s, they need to match.", + type_quoted_error_string(any_rtype), type_quoted_error_string(this_rtype)); + SEMA_NOTE(type_infoptr(protocol_sig.rtype), "The interface definition is here."); return false; } - else + Decl **any_params = protocol_sig.params; + Decl **this_params = this_sig.params; + unsigned any_param_count = vec_size(any_params); + unsigned this_param_count = vec_size(this_params); + if (any_param_count != this_param_count) { - SEMA_ERROR(this_params[any_param_count], "This function has too many parameters (%d).", this_param_count); - SEMA_NOTE(decl, "Compare with the interface, which has only %d parameter%s.", - any_param_count, any_param_count == 1 ? "" : "s"); - } - return false; - } - FOREACH_BEGIN_IDX(i, Decl *param, this_params) - if (i == 0) continue; - if (param->type->canonical != any_params[i]->type->canonical) - { - SEMA_ERROR(vartype(param), "The prototype argument has type %s, but in this function it has type %s. Please make them match.", - type_quoted_error_string(any_params[i]->type), type_quoted_error_string(param->type)); - SEMA_NOTE(vartype(any_params[i]), "The interface definition is here."); + if (any_param_count > this_param_count) + { + SEMA_ERROR(decl, "This function is missing parameters, %d parameters were expected.", any_param_count); + SEMA_NOTE(any_params[this_param_count], "Compare with the interface definition."); + return false; + } + else + { + SEMA_ERROR(this_params[any_param_count], "This function has too many parameters (%d).", this_param_count); + SEMA_NOTE(decl, "Compare with the interface, which has only %d parameter%s.", + any_param_count, any_param_count == 1 ? "" : "s"); + } return false; } - FOREACH_END(); + FOREACH_BEGIN_IDX(i, Decl *param, this_params) + if (i == 0) continue; + if (param->type->canonical != any_params[i]->type->canonical) + { + SEMA_ERROR(vartype(param), "The prototype argument has type %s, but in this function it has type %s. Please make them match.", + type_quoted_error_string(any_params[i]->type), type_quoted_error_string(param->type)); + SEMA_NOTE(vartype(any_params[i]), "The interface definition is here."); + return false; + } + FOREACH_END(); - decl->func_decl.protocol_method = declid(implemented_method); + decl->func_decl.protocol_method = declid(implemented_method); + } + else + { + decl->func_decl.protocol_method = 0; + } } return unit_add_method_like(context->unit, par_type, decl); } @@ -1870,6 +1896,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST, [ATTRIBUTE_CALLCONV] = ATTR_FUNC | ATTR_PROTOCOL_METHOD, [ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | CALLABLE_TYPE | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER | ATTR_BITSTRUCT_MEMBER, + [ATTRIBUTE_DYNAMIC] = ATTR_FUNC, [ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_EXTERN] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES, [ATTRIBUTE_FINALIZER] = ATTR_FUNC, @@ -1887,6 +1914,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_OBFUSCATE] = ATTR_ENUM | ATTR_FAULT, [ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC, + [ATTRIBUTE_OPTIONAL] = ATTR_PROTOCOL_METHOD, [ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT, [ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION, [ATTRIBUTE_PRIVATE] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEF, @@ -2139,6 +2167,9 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_OVERLAP: decl->bitstruct.overlap = true; break; + case ATTRIBUTE_DYNAMIC: + decl->func_decl.attr_dynamic = true; + break; case ATTRIBUTE_BIGENDIAN: if (decl->bitstruct.little_endian) { @@ -2733,7 +2764,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era } else if (!is_protocol_method) { - if (decl->func_decl.is_dynamic) + if (decl->func_decl.attr_dynamic) { SEMA_ERROR(decl, "Only methods may implement protocols."); return decl_poison(decl); @@ -3533,8 +3564,11 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con return symbol; } -static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl) +static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl, bool *erase_decl) { + if (!sema_analyse_attributes(c, decl, decl->attributes, ATTR_DEF, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; + Decl **params = decl->attr_decl.params; unsigned param_count = vec_size(params); for (unsigned i = 0; i < param_count; i++) @@ -3571,6 +3605,7 @@ static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl) static inline bool sema_analyse_define(SemaContext *c, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(c, decl, decl->attributes, ATTR_DEF, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; // 1. The plain define if (decl->define_decl.define_kind == DEFINE_IDENT_ALIAS) @@ -3624,7 +3659,7 @@ RETRY: goto RETRY; case TYPE_DISTINCT: if (!sema_analyse_decl(context, type->decl)) return false; - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_ARRAY: case TYPE_SUBARRAY: @@ -3690,7 +3725,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) set_external_name = true; break; case DECL_ATTRIBUTE: - if (!sema_analyse_attribute_decl(context, decl)) goto FAILED; + if (!sema_analyse_attribute_decl(context, decl, &erase_decl)) goto FAILED; break; case DECL_DISTINCT: if (!sema_analyse_distinct(context, decl, &erase_decl)) goto FAILED; @@ -3704,7 +3739,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) set_external_name = true; break; case DECL_FAULT: - if (!sema_analyse_error(context, decl)) goto FAILED; + if (!sema_analyse_error(context, decl, &erase_decl)) goto FAILED; set_external_name = true; break; case DECL_DEFINE: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8a0a2781d..6c741c767 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3230,7 +3230,7 @@ static inline bool sema_create_const_inner(SemaContext *context, Expr *expr, Typ inner = type->optional; break; case TYPE_DISTINCT: - inner = type->decl->distinct_decl.base_type->canonical; + inner = type->decl->distinct->type->canonical; break; case TYPE_ENUM: inner = type->decl->enums.type_info->type->canonical; @@ -4128,7 +4128,7 @@ CHECK_DEEPER: if (type->type_kind == TYPE_DISTINCT && decl->is_substruct) { Expr *inner_expr = expr_copy(current_parent); - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; inner_expr->type = type; current_parent = inner_expr; goto CHECK_DEEPER; @@ -8330,7 +8330,7 @@ RETRY: type = type->canonical; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_UNTYPED_LIST: UNREACHABLE diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 38dc959d9..90205aae1 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -59,6 +59,7 @@ void sema_analysis_pass_decls(Module *module); void sema_analysis_pass_ct_assert(Module *module); void sema_analysis_pass_ct_echo(Module *module); void sema_analysis_pass_functions(Module *module); +void sema_analysis_pass_protocol(Module *module); void sema_analysis_pass_lambda(Module *module); void sema_analyze_stage(Module *module, AnalysisStage stage); diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index e98b0d4fd..d5be4196d 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -502,7 +502,7 @@ void sema_trace_liveness(void) bool keep_tests = active_target.testing; bool keep_benchmarks = active_target.benchmarking; FOREACH_BEGIN(Decl *function, global_context.method_extensions) - if (function->func_decl.is_dynamic) function->no_strip = true; + if (function->func_decl.attr_dynamic) function->no_strip = true; if (function->is_export || function->no_strip) sema_trace_decl_liveness(function); FOREACH_END(); FOREACH_BEGIN(Module *module, global_context.module_list) @@ -534,7 +534,7 @@ INLINE void sema_trace_decl_dynamic_methods(Decl *decl) for (unsigned i = 0; i < method_count; i++) { Decl *method = methods[i]; - if (method->decl_kind == DECL_MACRO || !method->func_decl.is_dynamic) continue; + if (method->decl_kind == DECL_MACRO || !method->func_decl.attr_dynamic) continue; sema_trace_decl_liveness(method); } } @@ -562,7 +562,7 @@ RETRY: decl = decl->define_decl.alias; goto RETRY; case DECL_DISTINCT: - sema_trace_type_liveness(decl->distinct_decl.base_type); + sema_trace_type_liveness(decl->distinct->type); FALLTHROUGH; case DECL_ENUM: case DECL_BITSTRUCT: diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 396241ce5..d9bf3bb12 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -75,7 +75,7 @@ static void add_members_to_decl_stack(Decl *decl) } while (decl->decl_kind == DECL_DISTINCT) { - Type *type = decl->distinct_decl.base_type->canonical; + Type *type = decl->distinct->type->canonical; if (!type_is_user_defined(type)) break; decl = type->decl; } @@ -730,7 +730,7 @@ bool sema_resolve_type_decl(SemaContext *context, Type *type) return sema_resolve_type_decl(context, type->canonical); case TYPE_DISTINCT: if (!sema_analyse_decl(context, type->decl)) return false; - return sema_resolve_type_decl(context, type->decl->distinct_decl.base_type); + return sema_resolve_type_decl(context, type->decl->distinct->type); case TYPE_FUNC: if (!type->function.prototype && type->function.decl->decl_kind == DECL_FNTYPE) return sema_analyse_decl(context, type->function.decl); return true; diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 7662d1014..b0de4ba93 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -500,7 +500,7 @@ INLINE void sema_analyse_inner_func_ptr(SemaContext *c, Decl *decl) switch (decl->decl_kind) { case DECL_DISTINCT: - inner = decl->distinct_decl.base_type; + inner = decl->distinct->type; break; case DECL_TYPEDEF: inner = decl->type->canonical; @@ -603,6 +603,77 @@ void sema_analysis_pass_lambda(Module *module) DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } +static inline bool sema_check_protocols(Decl *decl) +{ + Decl **store = sema_decl_stack_store(); + FOREACH_BEGIN(Decl *method, decl->methods) + sema_decl_stack_push(method); + FOREACH_END(); + FOREACH_BEGIN(TypeInfo *protocol_type, decl->protocols) + Decl *protocol = protocol_type->type->decl; + FOREACH_BEGIN(Decl *method, protocol->methods) + if (method->func_decl.attr_optional) continue; + Decl *matching_method = sema_decl_stack_resolve_symbol(method->name); + if (!matching_method) + { + SEMA_ERROR(protocol_type, "'%s' was not fully implemented, required method '%s' needs to be implemented, did you forget it?", + protocol->name, method->name); + sema_decl_stack_restore(store); + return false; + } + if (matching_method->decl_kind != DECL_FUNC) + { + SEMA_ERROR(matching_method, "'%s' was not fully implemented, it requires '%s' to be a function marked '@dynamic'.", + protocol->name, method->name); + sema_decl_stack_restore(store); + return false; + } + if (!matching_method->func_decl.attr_dynamic) + { + SEMA_ERROR(matching_method, "'%s' was not fully implemented, you need to mark '%s' as '@dynamic'.", + protocol->name, method->name); + sema_decl_stack_restore(store); + return false; + } + FOREACH_END(); + FOREACH_END(); + sema_decl_stack_restore(store); + return true; +} + +void sema_analysis_pass_protocol(Module *module) +{ + DEBUG_LOG("Pass: Protocol analysis %s", module->name->module); + + VECEACH(module->units, index) + { + CompilationUnit *unit = module->units[index]; + SemaContext context; + sema_context_init(&context, unit); + FOREACH_BEGIN(Decl *decl, unit->types) + switch (decl->decl_kind) + { + case DECL_DISTINCT: + case DECL_STRUCT: + case DECL_UNION: + case DECL_ENUM: + case DECL_FAULT: + case DECL_BITSTRUCT: + break; + default: + continue; + } + if (decl->protocols) + { + sema_check_protocols(decl); + } + } + sema_context_destroy(&context); + } + + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); +} + void sema_analysis_pass_functions(Module *module) { DEBUG_LOG("Pass: Function analysis %s", module->name->module); diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 46edce2d4..4c9d18d7e 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -163,6 +163,9 @@ void sema_analyze_stage(Module *module, AnalysisStage stage) case ANALYSIS_FUNCTIONS: sema_analysis_pass_functions(module); break; + case ANALYSIS_PROTOCOL: + sema_analysis_pass_protocol(module); + break; case ANALYSIS_FINALIZE: break; } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 0a0bf3c82..ef7bba7f5 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -322,6 +322,7 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_BUILTIN] = KW_DEF("@builtin"); attribute_list[ATTRIBUTE_CALLCONV] = KW_DEF("@callconv"); attribute_list[ATTRIBUTE_DEPRECATED] = KW_DEF("@deprecated"); + attribute_list[ATTRIBUTE_DYNAMIC] = KW_DEF("@dynamic"); attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export"); attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern"); attribute_list[ATTRIBUTE_FINALIZER] = KW_DEF("@finalizer"); diff --git a/src/compiler/tilde_codegen_type.c b/src/compiler/tilde_codegen_type.c index 8a952b6d8..8ac5ff6f2 100644 --- a/src/compiler/tilde_codegen_type.c +++ b/src/compiler/tilde_codegen_type.c @@ -298,7 +298,7 @@ TB_Global *tilde_get_typeid(TildeContext *c, Type *type) case TYPE_POINTER: return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_POINTER, type->pointer, 0, NULL, false); case TYPE_DISTINCT: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct_decl.base_type, 0, NULL, false); + return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct->type, 0, NULL, false); case TYPE_ENUM: return tilde_generate_introspection_global(c, type); case TYPE_FAULTTYPE: diff --git a/src/compiler/types.c b/src/compiler/types.c index 5751ebff8..831007d3f 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -279,7 +279,7 @@ RETRY: goto RETRY; case TYPE_DISTINCT: assert(type->decl->resolve_status == RESOLVE_DONE); - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_VECTOR: { @@ -395,7 +395,7 @@ bool type_is_abi_aggregate(Type *type) type = type->optional; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_TYPEDEF: type = type->canonical; @@ -464,7 +464,7 @@ bool type_is_ordered(Type *type) type = type->canonical; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; default: return false; @@ -499,7 +499,7 @@ bool type_is_comparable(Type *type) type = type->array.base; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_BOOL: case ALL_INTS: @@ -672,7 +672,7 @@ AlignSize type_abi_alignment(Type *type) type = type->optional; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_TYPEDEF: type = type->canonical; @@ -1043,7 +1043,7 @@ Type *type_get_indexed_type(Type *type) case TYPE_VECTOR: return type->array.base->canonical; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_OPTIONAL: type = type->optional; @@ -1125,7 +1125,7 @@ bool type_is_valid_for_vector(Type *type) return true; case TYPE_DISTINCT: assert(type->decl->resolve_status == RESOLVE_DONE); - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_TYPEDEF: type = type->canonical; @@ -1142,7 +1142,7 @@ bool type_is_valid_for_array(Type *type) { case TYPE_DISTINCT: assert(!type->decl || type->decl->resolve_status == RESOLVE_DONE); - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_ANYPTR: case TYPE_PROPTR: @@ -1557,7 +1557,7 @@ void type_setup(PlatformTarget *target) Decl *string_decl = decl_new_with_type(symtab_preset("String", TOKEN_TYPE_IDENT), INVALID_SPAN, DECL_DISTINCT); string_decl->extname = string_decl->name; string_decl->is_substruct = true; - string_decl->distinct_decl.base_type = type_chars; + string_decl->distinct = type_info_new_base(type_chars, INVALID_SPAN); string_decl->resolve_status = RESOLVE_DONE; type_string = string_decl->type; global_context_add_type(string_decl->type); @@ -1624,7 +1624,7 @@ bool type_is_scalar(Type *type) type = type->decl->bitstruct.base_type->type; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; + type = type->decl->distinct->type; goto RETRY; case TYPE_OPTIONAL: type = type->optional; @@ -1645,7 +1645,7 @@ Type *type_find_parent_type(Type *type) case TYPE_DISTINCT: { Decl *decl = type->decl; - return decl->is_substruct ? decl->distinct_decl.base_type : NULL; + return decl->is_substruct ? decl->distinct->type : NULL; } case TYPE_STRUCT: { @@ -2044,8 +2044,8 @@ Type *type_find_max_type(Type *type, Type *other) if (other == type_wildcard) return type; // Lower inlined distinct types. - while (type->type_kind == TYPE_DISTINCT && type->decl->is_substruct) type = type->decl->distinct_decl.base_type; - while (other->type_kind == TYPE_DISTINCT && other->decl->is_substruct) other = other->decl->distinct_decl.base_type; + while (type->type_kind == TYPE_DISTINCT && type->decl->is_substruct) type = type->decl->distinct->type; + while (other->type_kind == TYPE_DISTINCT && other->decl->is_substruct) other = other->decl->distinct->type; // We may now have a match. if (type == other) return type; @@ -2087,7 +2087,7 @@ Type *type_find_max_type(Type *type, Type *other) if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case ALL_FLOATS: - if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other; + if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct->type)) return other; if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case TYPE_POINTER: diff --git a/src/version.h b/src/version.h index c7a06d668..effe7e474 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.671" \ No newline at end of file +#define COMPILER_VERSION "0.4.672" \ No newline at end of file diff --git a/test/test_suite/bitstruct/invalid_bitstruct_member_types.c3 b/test/test_suite/bitstruct/invalid_bitstruct_member_types.c3 index 0f218df19..95c33992d 100644 --- a/test/test_suite/bitstruct/invalid_bitstruct_member_types.c3 +++ b/test/test_suite/bitstruct/invalid_bitstruct_member_types.c3 @@ -5,8 +5,8 @@ bitstruct Test : int float a : 1..3; // #error: 'float' is not supported in a bitstruct, only enums, integer and boolean values may be used. } -def Baz = distinct float; -def Foo = distinct bool; +distinct Baz = float; +distinct Foo = bool; enum Boo { BAR diff --git a/test/test_suite/cast/cast_subarray.c3t b/test/test_suite/cast/cast_subarray.c3t index 796806599..3ed733ca8 100644 --- a/test/test_suite/cast/cast_subarray.c3t +++ b/test/test_suite/cast/cast_subarray.c3t @@ -1,7 +1,7 @@ // #target: macos-x64 module test; -def Foo = distinct int; +distinct Foo = int; fn void main() { int*[] abc = { }; diff --git a/test/test_suite/compile_time/compile_time_access_subscript.c3t b/test/test_suite/compile_time/compile_time_access_subscript.c3t index b910ef16c..6e89db8f7 100644 --- a/test/test_suite/compile_time/compile_time_access_subscript.c3t +++ b/test/test_suite/compile_time/compile_time_access_subscript.c3t @@ -22,7 +22,7 @@ macro check_type($Type) enum Blurb { FOO } -def Bdd = distinct Abc; +distinct Bdd = Abc; fn void main() { var $i = int[4] { 1, 2, 3, 4 }; diff --git a/test/test_suite/distinct/distinct_inline_access.c3 b/test/test_suite/distinct/distinct_inline_access.c3 index 3b706703a..617ff2c63 100644 --- a/test/test_suite/distinct/distinct_inline_access.c3 +++ b/test/test_suite/distinct/distinct_inline_access.c3 @@ -7,7 +7,7 @@ fn void main() FooInt foo; } -def FooInt = distinct inline Foo; +distinct FooInt = inline Foo; struct Bar { diff --git a/test/test_suite/distinct/distinct_invalid.c3 b/test/test_suite/distinct/distinct_invalid.c3 index 03a1d3401..66518f58a 100644 --- a/test/test_suite/distinct/distinct_invalid.c3 +++ b/test/test_suite/distinct/distinct_invalid.c3 @@ -3,8 +3,8 @@ fault Error ABC } -def Foo1 = distinct Error; // #error: You cannot create a distinct type +distinct Foo1 = Error; // #error: You cannot create a distinct type -def Foo3 = distinct void; // #error: create a distinct type from 'void' +distinct Foo3 = void; // #error: create a distinct type from 'void' -def Foo4 = distinct typeid; // #error: create a distinct type from 'typeid' +distinct Foo4 = typeid; // #error: create a distinct type from 'typeid' diff --git a/test/test_suite/distinct/distinct_shift.c3t b/test/test_suite/distinct/distinct_shift.c3t index afe04c023..61fdaeb5a 100644 --- a/test/test_suite/distinct/distinct_shift.c3t +++ b/test/test_suite/distinct/distinct_shift.c3t @@ -4,7 +4,7 @@ import std::io; const ODD_PHI16 @local = 0x9e37; -def Lcg16_8 = distinct ushort; +distinct Lcg16_8 = ushort; fn void Lcg16_8.seed(Lcg16_8* lcg, char[2] seed) { diff --git a/test/test_suite/distinct/distinct_slicing.c3 b/test/test_suite/distinct/distinct_slicing.c3 index c3920c71f..0bc172857 100644 --- a/test/test_suite/distinct/distinct_slicing.c3 +++ b/test/test_suite/distinct/distinct_slicing.c3 @@ -1,4 +1,4 @@ -def Foo = distinct double[]; +distinct Foo = double[]; fn void main() { diff --git a/test/test_suite/distinct/distinct_struct.c3 b/test/test_suite/distinct/distinct_struct.c3 index b5b1f447d..11a18d1f5 100644 --- a/test/test_suite/distinct/distinct_struct.c3 +++ b/test/test_suite/distinct/distinct_struct.c3 @@ -5,7 +5,7 @@ struct Struct double y; } -def Foo = distinct Struct; +distinct Foo = Struct; struct Struct2 { diff --git a/test/test_suite/distinct/distinct_struct_array.c3 b/test/test_suite/distinct/distinct_struct_array.c3 index 605fa3f1f..a8b1dee82 100644 --- a/test/test_suite/distinct/distinct_struct_array.c3 +++ b/test/test_suite/distinct/distinct_struct_array.c3 @@ -1,6 +1,6 @@ module test; -def Foo = distinct int; +distinct Foo = int; struct Struct { @@ -8,8 +8,8 @@ struct Struct int y; } -def Struct2 = distinct Struct; -def StructArr = distinct Struct2[3]; +distinct Struct2 = Struct; +distinct StructArr = Struct2[3]; fn void test(int x) { diff --git a/test/test_suite/distinct/distinct_union.c3 b/test/test_suite/distinct/distinct_union.c3 index 56db83e4f..855d509ff 100644 --- a/test/test_suite/distinct/distinct_union.c3 +++ b/test/test_suite/distinct/distinct_union.c3 @@ -6,7 +6,7 @@ union Union double y; } -def Foo = distinct Union; +distinct Foo = Union; union Union2 { @@ -19,9 +19,9 @@ union Union2 } Foo f = { .x = 1 }; -def Union3 = distinct Union2; +distinct Union3 = Union2; -def UnionArr = distinct Union3[3]; +distinct UnionArr = Union3[3]; fn void test(int x) { diff --git a/test/test_suite/distinct/test_errors.c3 b/test/test_suite/distinct/test_errors.c3 index e640cdcbf..c98887c28 100644 --- a/test/test_suite/distinct/test_errors.c3 +++ b/test/test_suite/distinct/test_errors.c3 @@ -1,6 +1,6 @@ module test; -def Int2 = distinct int; +distinct Int2 = int; fn void test() { diff --git a/test/test_suite/distinct/test_ops_on_int.c3 b/test/test_suite/distinct/test_ops_on_int.c3 index 69347c3c7..4013b7c92 100644 --- a/test/test_suite/distinct/test_ops_on_int.c3 +++ b/test/test_suite/distinct/test_ops_on_int.c3 @@ -1,6 +1,6 @@ module test; -def Foo = distinct int; +distinct Foo = int; fn int test1() { diff --git a/test/test_suite/distinct/test_ops_on_struct.c3 b/test/test_suite/distinct/test_ops_on_struct.c3 index 23fe19ca8..ddd8255da 100644 --- a/test/test_suite/distinct/test_ops_on_struct.c3 +++ b/test/test_suite/distinct/test_ops_on_struct.c3 @@ -6,7 +6,7 @@ struct Struct double y; } -def Foo = distinct Struct; +distinct Foo = Struct; struct Struct2 { diff --git a/test/test_suite/dynamic/dynamic_mismatch.c3 b/test/test_suite/dynamic/dynamic_mismatch.c3 index 442d3655b..d4a54ef65 100644 --- a/test/test_suite/dynamic/dynamic_mismatch.c3 +++ b/test/test_suite/dynamic/dynamic_mismatch.c3 @@ -4,22 +4,22 @@ protocol TestProto } -struct Foo { int a; } +struct Foo (TestProto) { int a; } -fn int! Foo.test(Foo* f) : TestProto { return 1; } // #error: The prototype method has a return type 'int' +fn int! Foo.test(Foo* f) @dynamic { return 1; } // #error: The prototype method has a return type 'int' -struct Foo1 { int a; } +struct Foo1 (TestProto) { int a; } -fn int Foo1.test(Foo1* f, int a) : TestProto { return 1; } +fn int Foo1.test(Foo1* f, int a) @dynamic { return 1; } -struct Foo2 { int a; } +struct Foo2 (TestProto) { int a; } -fn int Foo2.test(Foo2* f) : TestProto { return 1; } // #error: This function is missing parameters, 2 +fn int Foo2.test(Foo2* f) @dynamic { return 1; } // #error: This function is missing parameters, 2 -struct Foo3 { int a; } +struct Foo3 (TestProto) { int a; } -fn int Foo3.test(Foo3* f, double a) : TestProto { return 1; } // #error: The prototype argument has type 'int' +fn int Foo3.test(Foo3* f, double a) @dynamic { return 1; } // #error: The prototype argument has type 'int' -struct Foo4 { int a; } +struct Foo4 (TestProto) { int a; } -fn int Foo4.test(Foo4* f, double a, int x) : TestProto { return 1; } // #error: This function has too many parameters +fn int Foo4.test(Foo4* f, double a, int x) @dynamic { return 1; } // #error: This function has too many parameters diff --git a/test/test_suite/enumerations/enum_add_sub.c3t b/test/test_suite/enumerations/enum_add_sub.c3t index bec428891..0d0b5eec1 100644 --- a/test/test_suite/enumerations/enum_add_sub.c3t +++ b/test/test_suite/enumerations/enum_add_sub.c3t @@ -4,8 +4,8 @@ enum Foo { ABC } -def Abc = distinct Foo; -def BarInt = distinct int; +distinct Abc = Foo; +distinct BarInt = int; enum Bar : BarInt { ABC diff --git a/test/test_suite/errors/general_error_regression.c3t b/test/test_suite/errors/general_error_regression.c3t index 213cfc8d2..7ffcc44d9 100644 --- a/test/test_suite/errors/general_error_regression.c3t +++ b/test/test_suite/errors/general_error_regression.c3t @@ -19,7 +19,7 @@ fault Foob Y2 } -def Bar = distinct int; +distinct Bar = int; enum MyEnum { diff --git a/test/test_suite/expressions/addr_of_fails.c3 b/test/test_suite/expressions/addr_of_fails.c3 index 45603e0e6..f8c1fcbb3 100644 --- a/test/test_suite/expressions/addr_of_fails.c3 +++ b/test/test_suite/expressions/addr_of_fails.c3 @@ -61,7 +61,7 @@ fn void test6() } def Baz = Foo; -def Bar = distinct int; +distinct Bar = int; fault Err { FOO } union Un { int x; } enum MyEnum { BAR } diff --git a/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 b/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 index 016194eaf..3d2b4fd8a 100644 --- a/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 +++ b/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 @@ -2,7 +2,7 @@ enum Foo { ABC } -def Abc = distinct int; +distinct Abc = int; fn void main() { Abc d = Foo.ABC; // #error: to 'Abc' diff --git a/test/test_suite/expressions/casts/explicit_cast.c3 b/test/test_suite/expressions/casts/explicit_cast.c3 index 3b1abb0db..9839e33e6 100644 --- a/test/test_suite/expressions/casts/explicit_cast.c3 +++ b/test/test_suite/expressions/casts/explicit_cast.c3 @@ -1,6 +1,6 @@ def Number8 = char; def Number32 = int; -def DNumber32 = distinct int; +distinct DNumber32 = int; fn void test1() { int a = (ichar)(10); diff --git a/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 b/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 index c3a147cde..ba1d99002 100644 --- a/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 +++ b/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 @@ -1,5 +1,5 @@ -def Foo = distinct double; -def Bar = distinct void*; +distinct Foo = double; +distinct Bar = void*; fn int main() { float f = 1; diff --git a/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 index d94d4aba6..c18c228fc 100644 --- a/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 +++ b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 @@ -1,6 +1,6 @@ module test; -def Foo = distinct int; +distinct Foo = int; fn void test1() { diff --git a/test/test_suite/expressions/enum_ct_sub.c3t b/test/test_suite/expressions/enum_ct_sub.c3t index f32d27d41..f3c0432de 100644 --- a/test/test_suite/expressions/enum_ct_sub.c3t +++ b/test/test_suite/expressions/enum_ct_sub.c3t @@ -3,7 +3,7 @@ enum Foo : char ABC, BCD } -def Abc = distinct int; +distinct Abc = int; fn void main() { $assert (Foo.ABC - Foo.BCD) == 255; diff --git a/test/test_suite/functions/c_vararg_expansion.c3t b/test/test_suite/functions/c_vararg_expansion.c3t index 1c36240ef..650a79681 100644 --- a/test/test_suite/functions/c_vararg_expansion.c3t +++ b/test/test_suite/functions/c_vararg_expansion.c3t @@ -1,7 +1,7 @@ // #target: macos-x64 module test; extern fn void printf(char*,...); -def Foo = distinct float; +distinct Foo = float; fn void main() { Foo a = 12.3; diff --git a/test/test_suite/functions/distinct_fn_ptr_and_lambda.c3t b/test/test_suite/functions/distinct_fn_ptr_and_lambda.c3t index 3e0376272..c3e58a7da 100644 --- a/test/test_suite/functions/distinct_fn_ptr_and_lambda.c3t +++ b/test/test_suite/functions/distinct_fn_ptr_and_lambda.c3t @@ -1,10 +1,8 @@ def Foo = fn void(int x); -def Bar = distinct Foo; -def Baz = distinct fn void(int x); +distinct Bar = Foo; fn void main() { Bar t = fn (x) { }; - Baz w = fn (x) { }; } \ No newline at end of file diff --git a/test/test_suite/generic/generic_local.c3 b/test/test_suite/generic/generic_local.c3 index de8a42b88..6bd601425 100644 --- a/test/test_suite/generic/generic_local.c3 +++ b/test/test_suite/generic/generic_local.c3 @@ -13,7 +13,7 @@ module foo; import foo::private; // Bug #856 -def Foo = distinct inline PrivateFoo(); // #error: could not be found +distinct Foo = inline PrivateFoo(); // #error: could not be found module foo::private() @local; diff --git a/test/test_suite/methods/enum_distinct_err_methods.c3t b/test/test_suite/methods/enum_distinct_err_methods.c3t index 9f805874e..99cc0ab68 100644 --- a/test/test_suite/methods/enum_distinct_err_methods.c3t +++ b/test/test_suite/methods/enum_distinct_err_methods.c3t @@ -8,7 +8,7 @@ fault Foo X } -def Bar = distinct int; +distinct Bar = int; enum MyEnum { diff --git a/test/test_suite/methods/methods_with_inferred_type.c3t b/test/test_suite/methods/methods_with_inferred_type.c3t index 9d2530e04..60687b3b9 100644 --- a/test/test_suite/methods/methods_with_inferred_type.c3t +++ b/test/test_suite/methods/methods_with_inferred_type.c3t @@ -1,7 +1,7 @@ // #target: macos-x64 module test; -def Foo = distinct int; +distinct Foo = int; struct Abc { diff --git a/test/test_suite/statements/foreach_custom_errors.c3 b/test/test_suite/statements/foreach_custom_errors.c3 index 9577dd2d5..08c581ab9 100644 --- a/test/test_suite/statements/foreach_custom_errors.c3 +++ b/test/test_suite/statements/foreach_custom_errors.c3 @@ -4,7 +4,7 @@ fn void test1() foreach (a : x) { }; // #error: It's not possible to enumerate an expression of type 'int' } -def Test1 = distinct int; +distinct Test1 = int; fn void test2() { diff --git a/test/test_suite/statements/foreach_r_custom_errors.c3 b/test/test_suite/statements/foreach_r_custom_errors.c3 index 66f4d8a94..1ef972b44 100644 --- a/test/test_suite/statements/foreach_r_custom_errors.c3 +++ b/test/test_suite/statements/foreach_r_custom_errors.c3 @@ -4,7 +4,7 @@ fn void test1() foreach_r (a : x) { }; // #error: It's not possible to enumerate an expression of type 'int' } -def Test1 = distinct int; +distinct Test1 = int; fn void test2() { diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t index 2da09fbee..f4d1e5629 100644 --- a/test/test_suite/stdlib/map.c3t +++ b/test/test_suite/stdlib/map.c3t @@ -4,12 +4,12 @@ module test; import std::io; import std::collections::map; -struct Foo { int x; void* bar; } +struct Foo (Printable) { int x; void* bar; } def IntFooMap = HashMap(); def IntDoubleMap = HashMap(); -fn String Foo.to_string(Foo* foo, Allocator* allocator = mem::heap()) : Printable +fn String Foo.to_string(Foo* foo, Allocator* allocator = mem::heap()) @dynamic { DString s = dstring::new_with_capacity(128, allocator); s.printf("{%s, %p}", foo.x, foo.bar); diff --git a/test/unit/regression/liveness_any.c3 b/test/unit/regression/liveness_any.c3 index d7243bdb8..f2d3d8a36 100644 --- a/test/unit/regression/liveness_any.c3 +++ b/test/unit/regression/liveness_any.c3 @@ -5,10 +5,10 @@ protocol TestProto fn void tesT(&self); } -fn void Test.tesT(&self) : TestProto +fn void Test.tesT(&self) @dynamic {} -struct Test +struct Test (TestProto) { void* abc; }