diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 75e2d6e73..3e46119ed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,6 +34,7 @@ jobs: run: | cd resources ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\hello_world_many.c3 + ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\time.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\fannkuch-redux.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\contextfree\boolerr.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3 @@ -101,6 +102,7 @@ jobs: run: | cd resources ../build/c3c compile-run examples/hello_world_many.c3 + ../build/c3c compile-run examples/time.c3 ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 ../build/c3c compile-run examples/load_world.c3 @@ -127,7 +129,7 @@ jobs: build-msys2-clang: runs-on: windows-latest - if: ${{ false }} + #if: ${{ false }} strategy: # Don't abort runners if a single one fails fail-fast: false @@ -155,6 +157,7 @@ jobs: run: | cd resources ../build/c3c compile-run examples/hello_world_many.c3 + ../build/c3c compile-run examples/time.c3 ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 ../build/c3c compile-run examples/load_world.c3 @@ -181,7 +184,7 @@ jobs: fail-fast: false matrix: build_type: [Release, Debug] - llvm_version: [15, 16, 17] + llvm_version: [16, 17] steps: - uses: actions/checkout@v3 @@ -218,7 +221,28 @@ jobs: - name: Compile and run some examples run: | cd resources + ../build/c3c compile examples/base64.c3 + ../build/c3c compile examples/binarydigits.c3 + ../build/c3c compile examples/brainfk.c3 + ../build/c3c compile examples/factorial_macro.c3 + ../build/c3c compile examples/fasta.c3 + ../build/c3c compile examples/gameoflife.c3 + ../build/c3c compile examples/hash.c3 + ../build/c3c compile examples/levenshtein.c3 + ../build/c3c compile examples/load_world.c3 + ../build/c3c compile examples/map.c3 + ../build/c3c compile examples/mandelbrot.c3 + ../build/c3c compile examples/plus_minus.c3 + ../build/c3c compile examples/nbodies.c3 + ../build/c3c compile examples/spectralnorm.c3 + ../build/c3c compile examples/swap.c3 + ../build/c3c compile examples/contextfree/boolerr.c3 + ../build/c3c compile examples/contextfree/dynscope.c3 + ../build/c3c compile examples/contextfree/guess_number.c3 + ../build/c3c compile examples/contextfree/multi.c3 + ../build/c3c compile examples/contextfree/cleanup.c3 ../build/c3c compile-run examples/hello_world_many.c3 + ../build/c3c compile-run examples/time.c3 ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 ../build/c3c compile-run examples/load_world.c3 @@ -272,7 +296,6 @@ jobs: - uses: actions/checkout@v3 - name: Download LLVM run: | - brew update brew install llvm@${{ matrix.llvm_version }} ninja curl echo "/usr/local/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH TMP_PATH=$(xcrun --show-sdk-path)/user/include @@ -291,6 +314,7 @@ jobs: run: | cd resources ../build/c3c compile-run examples/hello_world_many.c3 + ../build/c3c compile-run examples/time.c3 ../build/c3c compile-run examples/fannkuch-redux.c3 ../build/c3c compile-run examples/contextfree/boolerr.c3 ../build/c3c compile-run examples/load_world.c3 diff --git a/CMakeLists.txt b/CMakeLists.txt index bf3c52a82..869de5ec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,12 +171,8 @@ if (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL 16) ${LLD_WASM} ${LLD_MINGW} ${LLD_ELF} - ${LLD_DRIVER} - ${LLD_READER_WRITER} ${LLD_LOONG} ${LLD_MACHO} - ${LLD_YAML} - ${LLD_CORE} ) else() set(lld_libs @@ -185,11 +181,7 @@ else() ${LLD_WASM} ${LLD_MINGW} ${LLD_ELF} - ${LLD_DRIVER} - ${LLD_READER_WRITER} ${LLD_MACHO} - ${LLD_YAML} - ${LLD_CORE} ) endif() diff --git a/README.md b/README.md index da36bd214..a33d1d5e8 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ fn void Stack.push(Stack* this, Type element) if (this.capacity == this.size) { this.capacity *= 2; + if (this.capacity < 16) this.capacity = 16; this.elems = mem::realloc(this.elems, Type.sizeof * this.capacity); } this.elems[this.size++] = element; @@ -78,9 +79,9 @@ import stack; // Define our new types, the first will implicitly create // a complete copy of the entire Stack module with "Type" set to "int" -define IntStack = Stack; +typedef IntStack = Stack; // The second creates another copy with "Type" set to "double" -define DoubleStack = Stack; +typedef DoubleStack = Stack; // If we had added "define IntStack2 = Stack" // no additional copy would have been made (since we already diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index a864a8b60..93188f06e 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -87,13 +87,13 @@ fn Type! peek_last(LinkedList* list) => list.last() @inline; fn Type! LinkedList.first(LinkedList *list) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT!; + if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; return list._first.value; } fn Type! LinkedList.last(LinkedList* list) { - if (!list._last) return IteratorResult.NO_MORE_ELEMENT!; + if (!list._last) return IteratorResult.NO_MORE_ELEMENT?; return list._last.value; } @@ -240,7 +240,7 @@ fn bool LinkedList.remove_last_value(LinkedList* list, Type t) **/ fn Type! LinkedList.pop(LinkedList* list) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT!; + if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; defer list.unlink_first(); return list._first.value; } @@ -250,7 +250,7 @@ fn Type! LinkedList.pop(LinkedList* list) **/ fn void! LinkedList.remove_last(LinkedList* list) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT!; + if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; list.unlink_last(); } @@ -259,7 +259,7 @@ fn void! LinkedList.remove_last(LinkedList* list) **/ fn void! LinkedList.remove_first(LinkedList* list) { - if (!list._first) return IteratorResult.NO_MORE_ELEMENT!; + if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; list.unlink_first(); } diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 3b9ad3424..c037bcdc6 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -79,6 +79,50 @@ fn void List.remove_at(List* list, usz index) list.size--; } +fn void List.add_all(List* list, List* other_list) +{ + if (!other_list.size) return; + list.reserve(other_list.size); + foreach (&value : other_list) + { + list.entries[list.size++] = *value; + } +} + +fn Type[] List.to_array(List* list, Allocator* using = mem::heap()) +{ + if (!list.size) return Type[] {}; + Type[] result = malloc(Type, list.size, .using = using); + result[..] = list.entries[:list.size]; + return result; +} + +fn void List.reverse(List* list) +{ + if (list.size < 2) return; + usz half = list.size / 2U; + usz end = list.size - 1; + for (usz i = 0; i < half; i++) + { + @swap(list.entries[i], list.entries[end - i]); + } +} + +fn Type[] List.array_view(List* list) +{ + return list.entries[:list.size]; +} + +fn void List.add_array(List* list, Type[] array) +{ + if (!array.len) return; + list.reserve(array.len); + foreach (&value : array) + { + list.entries[list.size++] = *value; + } +} + fn void List.push_front(List* list, Type type) @inline { list.insert_at(0, type); @@ -175,11 +219,45 @@ fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline return &list.entries[index]; } +$if (types::is_equatable_type(Type)) -fn void List.ensure_capacity(List* list) @inline @private +fn usz! List.index_of(List* list, Type type) { - if (list.capacity == list.size) - { - list.reserve(list.capacity ? 2 * list.capacity : 16); - } + foreach (i, v : list) + { + if (v == type) return i; + } + return SearchResult.MISSING?; +} + +fn bool List.equals(List* list, List other_list) +{ + if (list.size != other_list.size) return false; + foreach (i, v : list) + { + if (v != other_list.entries[i]) return false; + } + return true; +} + +fn bool List.contains(List* list, Type type) +{ + foreach (i, v : list) + { + if (v == type) return true; + } + return false; +} + +$endif + +fn void List.ensure_capacity(List* list, usz added = 1) @inline @private +{ + usz new_size = list.size + added; + if (list.capacity > new_size) return; + + assert(new_size < usz.max / 2U); + usz new_capacity = list.capacity ? 2U * list.capacity : 16U; + while (new_size >= new_capacity) new_capacity *= 2U; + list.reserve(new_capacity); } diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index c8fdd1453..cf136e8aa 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -63,24 +63,24 @@ fn bool HashMap.is_empty(HashMap* map) @inline fn Value*! HashMap.get_ref(HashMap* map, Key key) { - if (!map.count) return SearchResult.MISSING!; + if (!map.count) return SearchResult.MISSING?; uint hash = rehash(key.hash()); for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next) { if (e.hash == hash && equals(key, e.key)) return &e.value; } - return SearchResult.MISSING!; + return SearchResult.MISSING?; } fn Entry*! HashMap.get_entry(HashMap* map, Key key) { - if (!map.count) return SearchResult.MISSING!; + if (!map.count) return SearchResult.MISSING?; uint hash = rehash(key.hash()); for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next) { if (e.hash == hash && equals(key, e.key)) return e; } - return SearchResult.MISSING!; + return SearchResult.MISSING?; } /** @@ -112,7 +112,7 @@ fn Value! HashMap.get(HashMap* map, Key key) @operator([]) fn bool HashMap.has_key(HashMap* map, Key key) { - return try? map.get_ref(key); + return @ok(map.get_ref(key)); } fn bool HashMap.set(HashMap* map, Key key, Value value) @operator([]=) @@ -138,7 +138,7 @@ fn bool HashMap.set(HashMap* map, Key key, Value value) @operator([]=) fn void! HashMap.remove(HashMap* map, Key key) @maydiscard { - if (!map.remove_entry_for_key(key)) return SearchResult.MISSING!; + if (!map.remove_entry_for_key(key)) return SearchResult.MISSING?; } fn void HashMap.clear(HashMap* map) diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 55679c703..1f8279e2e 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -36,46 +36,46 @@ fn void! Object.to_format(Object* o, Formatter* formatter) switch (o.type) { case void: - formatter.printf("{}")?; + formatter.printf("{}")!; case void*: - formatter.printf("null")?; + formatter.printf("null")!; case String: - formatter.printf(`"%s"`, o.s)?; + formatter.printf(`"%s"`, o.s)!; case bool: - formatter.printf(o.b ? "true" : "false")?; + formatter.printf(o.b ? "true" : "false")!; case ObjectInternalList: - formatter.printf("[")?; + formatter.printf("[")!; foreach (i, ol : o.array) { - formatter.printf(i == 0 ? " " : ", ")?; - ol.to_format(formatter)?; + formatter.printf(i == 0 ? " " : ", ")!; + ol.to_format(formatter)!; } - formatter.printf(" ]")?; + formatter.printf(" ]")!; case ObjectInternalMap: - formatter.printf("{")?; + formatter.printf("{")!; @pool() { foreach (i, key : o.map.key_tlist()) { - formatter.printf(i == 0 ? " " : ", ")?; - formatter.printf(`"%s": `, key)?; - o.map.get(key).to_format(formatter)?; + formatter.printf(i == 0 ? " " : ", ")!; + formatter.printf(`"%s": `, key)!; + o.map.get(key).to_format(formatter)!; } }; - formatter.printf(" }")?; + formatter.printf(" }")!; default: switch (o.type.kindof) { case SIGNED_INT: - formatter.printf("%d", o.i)?; + formatter.printf("%d", o.i)!; case UNSIGNED_INT: - formatter.printf("%d", (uint128)o.i)?; + formatter.printf("%d", (uint128)o.i)!; case FLOAT: - formatter.printf("%d", o.f)?; + formatter.printf("%d", o.f)!; case ENUM: - formatter.printf("%d", o.i)?; + formatter.printf("%d", o.i)!; default: - formatter.printf("<>")?; + formatter.printf("<>")!; } } } @@ -266,7 +266,7 @@ macro Object* Object.append(Object* o, value) /** * @require o.is_keyable() **/ -fn Object*! Object.get(Object* o, String key) => o.is_empty() ? SearchResult.MISSING! : o.map.get(key); +fn Object*! Object.get(Object* o, String key) => o.is_empty() ? SearchResult.MISSING? : o.map.get(key); fn bool Object.has_key(Object* o, String key) => o.is_map() && o.map.has_key(key); @@ -316,12 +316,12 @@ macro get_integer_value(Object* value, $Type) if (value.is_string()) { $if ($Type.kindof == TypeKind.SIGNED_INT) - return ($Type)str::to_int128(value.s); + return ($Type)value.s.to_int128(); $else - return ($Type)str::to_uint128(value.s); + return ($Type)value.s.to_uint128(); $endif } - if (!value.is_int()) return NumberConversion.MALFORMED_INTEGER!; + if (!value.is_int()) return NumberConversion.MALFORMED_INTEGER?; return ($Type)value.i; } @@ -370,7 +370,7 @@ fn uint128! Object.get_uint128_at(Object* o, usz index) => o.get_integer_at(uint **/ fn String! Object.get_string(Object* o, String key) { - Object* value = o.get(key)?; + Object* value = o.get(key)!; assert(value.is_string()); return value.s; } @@ -390,7 +390,7 @@ fn String Object.get_string_at(Object* o, usz index) **/ macro String! Object.get_enum(Object* o, $EnumType, String key) { - Object value = o.get(key)?; + Object value = o.get(key)!; assert($EnumType.typeid == value.type); return ($EnumType)value.i; } @@ -410,7 +410,7 @@ macro String Object.get_enum_at(Object* o, $EnumType, usz index) **/ fn bool! Object.get_bool(Object* o, String key) { - Object* value = o.get(key)?; + Object* value = o.get(key)!; assert(value.is_bool()); return value.b; } @@ -431,7 +431,7 @@ fn bool Object.get_bool_at(Object* o, usz index) **/ fn double! Object.get_float(Object* o, String key) { - Object* value = o.get(key)?; + Object* value = o.get(key)!; switch (value.type.kindof) { case SIGNED_INT: diff --git a/lib/std/collections/priorityqueue.c3 b/lib/std/collections/priorityqueue.c3 index e6c2b9828..beb98cc12 100644 --- a/lib/std/collections/priorityqueue.c3 +++ b/lib/std/collections/priorityqueue.c3 @@ -55,7 +55,7 @@ fn Type! PriorityQueue.pop(PriorityQueue* pq) { usz i = 0; usz len = pq.heap.len() @inline; - if (!len) return IteratorResult.NO_MORE_ELEMENT!; + if (!len) return IteratorResult.NO_MORE_ELEMENT?; usz newCount = len - 1; pq.heap.swap(0, newCount); while ((2 * i + 1) < newCount) @@ -84,7 +84,7 @@ fn Type! PriorityQueue.pop(PriorityQueue* pq) */ fn Type! PriorityQueue.peek(PriorityQueue* pq) { - if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT!; + if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT?; return pq.heap.get(0); } diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index 7efd18c1a..d0c637421 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -54,7 +54,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz assert(!old_pointer, "Unexpected old pointer for alloc."); if (!size) return null; alignment = alignment_for_allocation(alignment); - void* mem = arena._alloc(size, alignment, offset)?; + void* mem = arena._alloc(size, alignment, offset)!; if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; case ALIGNED_REALLOC: @@ -62,7 +62,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz if (!size) nextcase FREE; if (!old_pointer) nextcase ALLOC; alignment = alignment_for_allocation(alignment); - return arena._realloc(old_pointer, size, alignment, offset)?; + return arena._realloc(old_pointer, size, alignment, offset)!; case ALIGNED_FREE: case FREE: if (!old_pointer) return null; @@ -96,12 +96,12 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, usz offset) @private { usz total_len = this.data.len; - if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE!; + if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?; void* start_mem = this.data.ptr; void* unaligned_pointer_to_offset = start_mem + this.used + ArenaAllocatorHeader.sizeof + offset; void* aligned_pointer_to_offset = mem::aligned_pointer(unaligned_pointer_to_offset, alignment); usz end = (usz)(aligned_pointer_to_offset - this.data.ptr) + size - offset; - if (end > total_len) return AllocationFailure.OUT_OF_MEMORY!; + if (end > total_len) return AllocationFailure.OUT_OF_MEMORY?; this.used = end; void *mem = aligned_pointer_to_offset - offset; ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof; @@ -123,7 +123,7 @@ fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz s { assert(old_pointer >= this.data.ptr, "Pointer originates from a different allocator."); usz total_len = this.data.len; - if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE!; + if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?; ArenaAllocatorHeader* header = old_pointer - ArenaAllocatorHeader.sizeof; usz old_size = header.size; // Do last allocation and alignment match? @@ -136,14 +136,14 @@ fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz s else { usz new_used = this.used + size - old_size; - if (new_used > total_len) return AllocationFailure.OUT_OF_MEMORY!; + if (new_used > total_len) return AllocationFailure.OUT_OF_MEMORY?; this.used = new_used; } header.size = size; return old_pointer; } // Otherwise just allocate new memory. - void* mem = this._alloc(size, alignment, offset)?; + void* mem = this._alloc(size, alignment, offset)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } \ No newline at end of file diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index ed2547238..8804d18cd 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -106,7 +106,7 @@ fn void*! DynamicArenaAllocator._realloc(DynamicArenaAllocator* this, void* old_ current_page.used += add_size; return old_pointer; } - void* new_mem = this._alloc(size, alignment, offset)?; + void* new_mem = this._alloc(size, alignment, offset)!; mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT); return new_mem; } @@ -137,12 +137,12 @@ fn void*! DynamicArenaAllocator._alloc_new(DynamicArenaAllocator* this, usz size usz page_size = max(this.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + offset, alignment) - offset); // Grab the page without alignment (we do it ourselves) - void* mem = this.backing_allocator.alloc(page_size)?; + void* mem = this.backing_allocator.alloc(page_size)!; DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = this.backing_allocator); if (catch err = page) { free(mem, .using = this.backing_allocator); - return err!; + return err?; } page.memory = mem; void* mem_start = mem::aligned_pointer(mem + offset + DynamicArenaChunk.sizeof, alignment) - offset; @@ -213,7 +213,7 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm case ALIGNED_CALLOC: assert(!old_pointer, "Unexpected no old pointer for calloc."); if (!size) return null; - void* mem = allocator._alloc(size, alignment, offset)?; + void* mem = allocator._alloc(size, alignment, offset)!; mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; case ALLOC: @@ -230,7 +230,7 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm return null; } if (!old_pointer) return allocator._alloc(size, alignment, offset); - void* mem = allocator._realloc(old_pointer, size, alignment, offset)?; + void* mem = allocator._realloc(old_pointer, size, alignment, offset)!; return mem; case ALIGNED_FREE: case FREE: diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index 780296706..fcb443eaa 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -51,9 +51,9 @@ fn void*! simple_heap_allocator_function(Allocator* this, usz size, usz alignmen if (!old_pointer) nextcase CALLOC; return heap._realloc(old_pointer, size); case RESET: - return AllocationFailure.UNSUPPORTED_OPERATION!; + return AllocationFailure.UNSUPPORTED_OPERATION?; case ALIGNED_FREE: - @aligned_free(heap._free, old_pointer)?; + @aligned_free(heap._free, old_pointer)!; return null; case FREE: heap._free(old_pointer); @@ -71,7 +71,7 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin // Find the block header. Header* block = (Header*)old_pointer - 1; if (block.size >= bytes) return old_pointer; - void* new = this._alloc(bytes)?; + void* new = this._alloc(bytes)!; usz max_to_copy = math::min(block.size, bytes); mem::copy(new, old_pointer, max_to_copy); this._free(old_pointer); @@ -80,7 +80,7 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin fn void*! SimpleHeapAllocator._calloc(SimpleHeapAllocator* this, usz bytes) @local { - void* data = this._alloc(bytes)?; + void* data = this._alloc(bytes)!; mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT); return data; } @@ -90,7 +90,7 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @loca usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT); if (!this.free_list) { - this.add_block(aligned_bytes)?; + this.add_block(aligned_bytes)!; } Header* current = this.free_list; @@ -130,14 +130,14 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @loca current = current.next; } } - this.add_block(aligned_bytes)?; + this.add_block(aligned_bytes)!; return this.alloc(aligned_bytes); } fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_bytes) @local { assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes); - char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)?; + char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)!; Header* new_block = (Header*)result.ptr; new_block.size = result.len - Header.sizeof; new_block.next = null; diff --git a/lib/std/core/allocators/mem_allocator_fn.c3 b/lib/std/core/allocators/mem_allocator_fn.c3 index fac11fade..2190580c6 100644 --- a/lib/std/core/allocators/mem_allocator_fn.c3 +++ b/lib/std/core/allocators/mem_allocator_fn.c3 @@ -18,7 +18,7 @@ fn void*! null_allocator_fn(Allocator* this, usz bytes, usz alignment, usz offse case ALIGNED_ALLOC: case ALIGNED_REALLOC: case ALIGNED_CALLOC: - return AllocationFailure.OUT_OF_MEMORY!; + return AllocationFailure.OUT_OF_MEMORY?; default: return null; } @@ -37,8 +37,8 @@ struct AlignedBlock macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment, usz offset) { usz header = mem::aligned_offset(AlignedBlock.sizeof + offset, alignment) - offset; - $if ($checks(#alloc_fn(bytes)?)) - void* data = #alloc_fn(header + bytes)?; + $if ($checks(#alloc_fn(bytes)!)) + void* data = #alloc_fn(header + bytes)!; $else void* data = #alloc_fn(header + bytes); $endif @@ -56,8 +56,8 @@ macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment, usz offset) macro void*! @aligned_calloc(#calloc_fn, usz bytes, usz alignment, usz offset) { usz header = mem::aligned_offset(AlignedBlock.sizeof + offset, alignment) - offset; - $if ($checks(#calloc_fn(bytes)?)) - void* data = #calloc_fn(header + bytes)?; + $if ($checks(#calloc_fn(bytes)!)) + void* data = #calloc_fn(header + bytes)!; $else void* data = #calloc_fn(header + bytes); $endif @@ -76,10 +76,10 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes { AlignedBlock* desc = (AlignedBlock*)old_pointer - 1; void* data_start = desc.start; - void* new_data = @aligned_calloc(#calloc_fn, bytes, alignment, offset)?; + void* new_data = @aligned_calloc(#calloc_fn, bytes, alignment, offset)!; mem::copy(new_data, old_pointer, desc.len > bytes ? desc.len : bytes, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); - $if ($checks(#free_fn(data_start)?)) - #free_fn(data_start)?; + $if ($checks(#free_fn(data_start)!)) + #free_fn(data_start)!; $else #free_fn(data_start); $endif @@ -89,8 +89,8 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes macro void! @aligned_free(#free_fn, void* old_pointer) { AlignedBlock* desc = (AlignedBlock*)old_pointer - 1; - $if ($checks(#free_fn(desc.start)?)) - #free_fn(desc.start)?; + $if ($checks(#free_fn(desc.start)!)) + #free_fn(desc.start)!; $else #free_fn(desc.start); $endif @@ -121,7 +121,7 @@ fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz off if (!old_pointer) nextcase CALLOC; data = libc::realloc(old_pointer, bytes); case RESET: - return AllocationFailure.UNSUPPORTED_OPERATION!; + return AllocationFailure.UNSUPPORTED_OPERATION?; case ALIGNED_FREE: @aligned_free(libc::free, old_pointer)!!; return null; @@ -131,6 +131,6 @@ fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz off default: unreachable(); } - if (!data) return AllocationFailure.OUT_OF_MEMORY!; + if (!data) return AllocationFailure.OUT_OF_MEMORY?; return data; } diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index 6264ee1eb..8891b16fe 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -111,16 +111,16 @@ fn void*! on_stack_allocator_function(Allocator* data, usz size, usz alignment, on_stack_allocator_remove_chunk(allocator, old_pointer); if (kind == AllocationKind.ALIGNED_FREE) { - allocator.backing_allocator.free_aligned(old_pointer)?; + allocator.backing_allocator.free_aligned(old_pointer)!; } else { - allocator.backing_allocator.free(old_pointer)?; + allocator.backing_allocator.free(old_pointer)!; } return null; case MARK: case RESET: - return AllocationFailure.UNSUPPORTED_OPERATION!; + return AllocationFailure.UNSUPPORTED_OPERATION?; } unreachable(); } @@ -175,14 +175,14 @@ fn void*! on_stack_allocator_realloc(OnStackAllocator* a, void* old_pointer, usz assert(chunk, "Tried to realloc pointer not belonging to the allocator"); if (aligned) { - return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)?; + return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)!; } - return chunk.data = a.backing_allocator.realloc(old_pointer, size)?; + return chunk.data = a.backing_allocator.realloc(old_pointer, size)!; } OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof; usz old_size = header.size; - void* mem = on_stack_allocator_alloc(a, size, alignment, offset, true, aligned)?; + void* mem = on_stack_allocator_alloc(a, size, alignment, offset, true, aligned)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } @@ -209,7 +209,7 @@ fn void*! on_stack_allocator_alloc(OnStackAllocator* a, usz size, usz alignment, if (end > total_len) { - OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)?; + OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)!; defer catch backing_allocator.free(chunk)!!; defer try a.chunk = chunk; *chunk = { .prev = a.chunk, .is_aligned = aligned }; @@ -217,13 +217,13 @@ fn void*! on_stack_allocator_alloc(OnStackAllocator* a, usz size, usz alignment, switch { case !aligned && !clear: - data = backing_allocator.alloc(size)?; + data = backing_allocator.alloc(size)!; case aligned && !clear: - data = backing_allocator.alloc_aligned(size, alignment, offset)?; + data = backing_allocator.alloc_aligned(size, alignment, offset)!; case !aligned && clear: - data = backing_allocator.calloc(size)?; + data = backing_allocator.calloc(size)!; case aligned && clear: - data = backing_allocator.calloc_aligned(size, alignment, offset)?; + data = backing_allocator.calloc_aligned(size, alignment, offset)!; } return chunk.data = data; } diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 2bfe82970..4a0a26af8 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -39,7 +39,7 @@ macro bool TempAllocatorPage.is_aligned(TempAllocatorPage* page) => page.size & **/ fn TempAllocator*! new_temp(usz size, Allocator* backing_allocator) { - TempAllocator* allocator = malloc_checked(TempAllocator, .using = backing_allocator, .end_padding = size)?; + TempAllocator* allocator = malloc_checked(TempAllocator, .using = backing_allocator, .end_padding = size)!; allocator.last_page = null; allocator.function = &temp_allocator_function; allocator.backing_allocator = backing_allocator; @@ -75,12 +75,12 @@ fn void*! temp_allocator_function(Allocator* data, usz size, usz alignment, usz case FREE: case ALIGNED_FREE: if (!old_pointer) return null; - arena._free(old_pointer)?; + arena._free(old_pointer)!; return null; case MARK: return (void*)(uptr)arena.used; case RESET: - arena._reset(size)?; + arena._reset(size)!; return null; } unreachable(); @@ -103,7 +103,7 @@ fn void! TempAllocator._reset(TempAllocator* this, usz mark) @local { TempAllocatorPage *to_free = last_page; last_page = last_page.prev_page; - this._free_page(to_free)?; + this._free_page(to_free)!; } this.last_page = last_page; this.used = mark; @@ -131,15 +131,15 @@ fn void*! TempAllocator._realloc_page(TempAllocator* this, TempAllocatorPage* pa *pointer_to_prev = page.prev_page; usz page_size = page.pagesize(); // Clear on size > original size. - void* data = this._alloc(size, alignment, offset, false)?; + void* data = this._alloc(size, alignment, offset, false)!; mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); if (page.is_aligned()) { - this.backing_allocator.free_aligned(real_pointer)?; + this.backing_allocator.free_aligned(real_pointer)!; } else { - this.backing_allocator.free(real_pointer)?; + this.backing_allocator.free(real_pointer)!; } return data; } @@ -156,7 +156,7 @@ fn void*! TempAllocator._realloc(TempAllocator* this, void* pointer, usz size, u } // TODO optimize last allocation - TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)?; + TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)!; mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return data; @@ -200,11 +200,11 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz usz total_alloc_size = TempAllocatorPage.sizeof + size; if (clear) { - page = this.backing_allocator.calloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)?; + page = this.backing_allocator.calloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!; } else { - page = this.backing_allocator.alloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)?; + page = this.backing_allocator.alloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!; } page.start = page; page.size = size | PAGE_IS_ALIGNED; @@ -214,7 +214,7 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz // Here we might need to pad usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT); usz total_alloc_size = padded_header_size + size; - void* alloc = (clear ? this.backing_allocator.calloc(total_alloc_size) : this.backing_allocator.alloc(total_alloc_size))?; + void* alloc = (clear ? this.backing_allocator.calloc(total_alloc_size) : this.backing_allocator.alloc(total_alloc_size))!; // Find the page. page = alloc + padded_header_size - TempAllocatorPage.sizeof; diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 2cb58dd39..22176955b 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -43,7 +43,7 @@ fn void TrackingAllocator.free(TrackingAllocator* this) fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private { TrackingAllocator* this = (TrackingAllocator*)data; - void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)?; + void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)!; switch (kind) { case CALLOC: diff --git a/lib/std/core/array.c3 b/lib/std/core/array.c3 index c8cf732af..833ec238e 100644 --- a/lib/std/core/array.c3 +++ b/lib/std/core/array.c3 @@ -1,33 +1,34 @@ module std::core::array; -macro tconcat(arr1, arr2) -{ - var $Type = $typeof(arr1[0]); - $Type[] result = array::talloc($Type, arr1.len + arr2.len); - if (arr1.len > 0) - { - mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof); - } - if (arr2.len > 0) - { - mem::copy(&result[arr1.len], &arr2[0], arr2.len * $Type.sizeof, $Type.alignof, $Type.alignof); - } - return result; -} - +/** + * @param [in] array + * @param [in] element + * @return "the index of the element" + * @return! SearchResult.MISSING + **/ macro index_of(array, element) { foreach (i, &e : array) { if (*e == element) return i; } - return SearchResult.MISSING!; + return SearchResult.MISSING?; } -macro concat(arr1, arr2) +/** + * Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them. + * + * @param [in] arr1 + * @param [in] arr2 + * @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY + * @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY + * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" + * @ensure result.len == arr1.len + arr2.len + **/ +macro concat(arr1, arr2, Allocator* using = mem::heap()) { var $Type = $typeof(arr1[0]); - $Type[] result = array::alloc($Type, arr1.len + arr2.len); + $Type[] result = malloc($Type, arr1.len + arr2.len, .using = using); if (arr1.len > 0) { mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof); @@ -37,4 +38,6 @@ macro concat(arr1, arr2) mem::copy(&result[arr1.len], &arr2[0], arr2.len * $Type.sizeof, $Type.alignof, $Type.alignof); } return result; -} \ No newline at end of file +} + +macro tconcat(arr1, arr2) => concat(arr1, arr2, mem::temp()); diff --git a/lib/std/core/bitorder.c3 b/lib/std/core/bitorder.c3 index 1aabbcc5d..6238ac534 100644 --- a/lib/std/core/bitorder.c3 +++ b/lib/std/core/bitorder.c3 @@ -1,5 +1,12 @@ +// Copyright (c) 2023 Christoffer Lerno and contributors. All rights reserved. +// Use of this source code is governed by the MIT license +// a copy of which can be found in the LICENSE_STDLIB file. module std::core::bitorder; +// This module contains types of different endianness. +// *BE types represent big-endian types +// *LE types represent little-endian types. + bitstruct ShortBE : short @bigendian { short val : 0..15; diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index c895ef476..19b613531 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -5,17 +5,26 @@ module std::core::builtin; import libc; import std::hash; +/** + * Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds. + **/ fault IteratorResult { NO_MORE_ELEMENT } +/** + * Use `SearchResult` when trying to return a value from some collection but the element is missing. + **/ fault SearchResult { MISSING } -fault VarCastResult +/** + * Use `CastResult` when an attempt at conversion fails. + **/ +fault CastResult { TYPE_MISMATCH } @@ -33,6 +42,9 @@ macro void @scope(&variable; @body) @builtin @body(); } +/** + * Swap two variables + **/ macro void @swap(&a, &b) @builtin { var temp = a; @@ -41,15 +53,17 @@ macro void @swap(&a, &b) @builtin } /** - * Convert a variant type to a type, returning an failure if there is a type mismatch. + * Convert an `any` type to a type, returning an failure if there is a type mismatch. * - * @param v `the variant to convert to the given type.` + * @param v `the any to convert to the given type.` * @param $Type `the type to convert to` - * @return `The variant.ptr converted to its type.` + * @return `The any.ptr converted to its type.` + * @ensure @typeis(return, $Type*) + * @return! CastResult.TYPE_MISMATCH **/ -macro varcast(variant v, $Type) @builtin +macro anycast(any v, $Type) @builtin { - if (v.type != $Type.typeid) return VarCastResult.TYPE_MISMATCH!; + if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?; return ($Type*)v.ptr; } @@ -64,22 +78,24 @@ struct CallstackElement fn void default_panic(String message, String file, String function, uint line) { CallstackElement* stack = $$stacktrace(); - $if ($defined(libc::stderr) && $defined(libc::fprintf)) + $if ($defined(io::stderr) && $defined(File.printf)) if (stack) stack = stack.prev; if (stack) { - libc::fprintf(libc::stderr(), "\nERROR: '%.*s'\n", (int)message.len, message.ptr); + (void)io::stderr().print("\nERROR: '"); + (void)io::stderr().print(message); + (void)io::stderr().printn("'"); } else { - libc::fprintf(libc::stderr(), "\nERROR: '%.*s', function %.*s (%.*s:%d)\n", - (int)message.len, message.ptr, (int)function.len, function.ptr, (int)file.len, file.ptr, line); + (void)io::stderr().print("\nERROR: '"); + (void)io::stderr().print(message); + (void)io::stderr().printfn("', in function %s (%s:%d)", function, file, line); } while (stack) { - libc::fprintf(libc::stderr(), " at function %.*s (%.*s:%u)\n", (int)stack.function.len, stack.function.ptr, - (int)stack.file.len, stack.file.ptr, stack.line); + (void)io::stderr().printfn(" in function %s (%s:%d)", stack.function, stack.file, stack.line); if (stack == stack.prev) break; stack = stack.prev; } @@ -92,62 +108,103 @@ typedef PanicFn = fn void(String message, String file, String function, uint lin PanicFn panic = &default_panic; -macro void unreachable($string = "Unreachable statement reached.") @builtin @noreturn +fn void panicf(String fmt, String file, String function, uint line, args...) { - panic($string, $$FILE, $$FUNC, $$LINE); + @stack_mem(512; Allocator* mem) + { + DString s; + s.init(.using = mem); + s.printf(fmt, ...args); + panic(s.str(), file, function, line); + }; +} + +/** + * Marks the path as unreachable. This will panic in safe mode, and in fast will simply be assumed + * never happens. + * @param [in] string "The panic message" + **/ +macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn +{ + panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat()); $$unreachable(); } +/** + * @param expr "the expression to cast" + * @param $Type "the type to cast to" + * + * @require $sizeof(expr) == $Type.sizeof "Cannot bitcast between types of different size." + * @ensure @typeis(result, $Type) + **/ macro bitcast(expr, $Type) @builtin { - var $size = (usz)($sizeof(expr)); - $assert($size == $Type.sizeof, "Cannot bitcast between types of different size."); + usz $size = $sizeof(expr); $Type x @noinit; mem::copy(&x, &expr, $size, $Type.alignof, $alignof(expr)); return x; } /** - * @require $Type.kindof == TypeKind.ENUM `Only enums may be used` + * @param $Type `The type of the enum` + * @param [in] enum_name `The name of the enum to search for` + * @require $Type.kindof == ENUM `Only enums may be used` + * @ensure @typeis(return, $Type) + * @return! SearchResult.MISSING **/ macro enum_by_name($Type, String enum_name) @builtin { typeid x = $Type.typeid; foreach (i, name : x.names) { - if (str::compare(name, enum_name)) return ($Type)i; + if (name == enum_name) return ($Type)i; } - return SearchResult.MISSING!; -} - -macro bool @likely(bool value, $probability = 1.0) @builtin -{ - $if ($probability == 1.0) - return $$expect(value, true); - $else - return $$expect_with_probability(value, true, $probability); - $endif -} - -macro bool @unlikely(bool value, $probability = 1.0) @builtin -{ - $if ($probability == 1.0) - return $$expect(value, false); - $else - return $$expect_with_probability(value, false, $probability); - $endif + return SearchResult.MISSING?; } /** - * @require values::@is_int(value) || values::@is_bool(value) - * @checked $typeof(value) a = expected + * Mark an expression as likely to be true + * + * @param #value "expression to be marked likely" + * @param $probability "in the range 0 - 1" + * @require $probability >= 0 && $probability <= 1.0 **/ -macro @expect(value, expected, $probability = 1.0) @builtin +macro bool @likely(bool #value, $probability = 1.0) @builtin +{ +$if ($probability == 1.0) + return $$expect(#value, true); +$else + return $$expect_with_probability(#value, true, $probability); +$endif +} + +/** + * Mark an expression as unlikely to be true + * + * @param #value "expression to be marked unlikely" + * @param $probability "in the range 0 - 1" + * @require $probability >= 0 && $probability <= 1.0 + **/ +macro bool @unlikely(bool #value, $probability = 1.0) @builtin +{ +$if ($probability == 1.0) + return $$expect(#value, false); +$else + return $$expect_with_probability(#value, false, $probability); +$endif +} + +/** + * @require values::@is_int(#value) || values::@is_bool(#value) + * @checked $typeof(#value) a = expected + * @require $probability >= 0 && $probability <= 1.0 + **/ +macro @expect(#value, expected, $probability = 1.0) @builtin { $if ($probability == 1.0) - return $$expect(value, ($typeof(value))expected); + return $$expect(#value, ($typeof(#value))expected); $else - return $$expect_with_probability(value, expected, $probability); + return $$expect_with_probability(#value, expected, $probability); $endif } @@ -195,6 +252,18 @@ macro bool @convertible(#expr, $To) @builtin return $checks($To x = #expr); } +macro anyfault @catchof(#expr) @builtin +{ + if (catch f = #expr) return f; + return anyfault {}; +} + +macro bool @ok(#expr) @builtin +{ + if (catch #expr) return false; + return true; +} + macro uint int.hash(int i) => i; macro uint uint.hash(uint i) => i; macro uint short.hash(short s) => s; @@ -203,7 +272,9 @@ macro uint char.hash(char c) => c; macro uint ichar.hash(ichar c) => c; macro uint long.hash(long i) => (uint)((i >> 32) ^ i); macro uint ulong.hash(ulong i) => (uint)((i >> 32) ^ i); +macro uint int128.hash(int128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i); +macro uint uint128.hash(uint128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i); macro uint bool.hash(bool b) => (uint)b; -macro uint typeid.hash(typeid t) => (uint)(((uptr)t >> 32) ^ (uptr)t); +macro uint typeid.hash(typeid t) => ((ulong)(uptr)t).hash(); macro uint String.hash(String c) => (uint)fnv32a::encode(c); macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c); \ No newline at end of file diff --git a/lib/std/core/conv.c3 b/lib/std/core/conv.c3 index 962a9855e..01a5302ca 100644 --- a/lib/std/core/conv.c3 +++ b/lib/std/core/conv.c3 @@ -16,25 +16,25 @@ const uint UTF16_SURROGATE_HIGH_VALUE @private = 0xD800; **/ fn usz! char32_to_utf8(Char32 c, char* output, usz available) { - if (!available) return UnicodeResult.CONVERSION_FAILED!; + if (!available) return UnicodeResult.CONVERSION_FAILED?; switch (true) { case c <= 0x7f: output[0] = (char)c; return 1; case c <= 0x7ff: - if (available < 2) return UnicodeResult.CONVERSION_FAILED!; + if (available < 2) return UnicodeResult.CONVERSION_FAILED?; output[0] = (char)(0xC0 | c >> 6); output[1] = (char)(0x80 | (c & 0x3F)); return 2; case c <= 0xffff: - if (available < 3) return UnicodeResult.CONVERSION_FAILED!; + if (available < 3) return UnicodeResult.CONVERSION_FAILED?; output[0] = (char)(0xE0 | c >> 12); output[1] = (char)(0x80 | (c >> 6 & 0x3F)); output[2] = (char)(0x80 | (c & 0x3F)); return 3; case c <= 0x10ffff: - if (available < 4) return UnicodeResult.CONVERSION_FAILED!; + if (available < 4) return UnicodeResult.CONVERSION_FAILED?; output[0] = (char)(0xF0 | c >> 18); output[1] = (char)(0x80 | (c >> 12 & 0x3F)); output[2] = (char)(0x80 | (c >> 6 & 0x3F)); @@ -42,7 +42,7 @@ fn usz! char32_to_utf8(Char32 c, char* output, usz available) return 4; default: // 0x10FFFF and above is not defined. - return UnicodeResult.CONVERSION_FAILED!; + return UnicodeResult.CONVERSION_FAILED?; } } @@ -84,15 +84,15 @@ fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output) return; } // Low surrogate first is an error - if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16!; + if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16?; // Unmatched high surrogate is an error - if (*available == 1) return UnicodeResult.INVALID_UTF16!; + if (*available == 1) return UnicodeResult.INVALID_UTF16?; Char16 low = ptr[1]; // Unmatched high surrogate, invalid - if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16!; + if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16?; // The high bits of the codepoint are the value bits of the high surrogate // The low bits of the codepoint are the value bits of the low surrogate @@ -134,7 +134,7 @@ fn void char32_to_utf8_unsafe(Char32 c, char** output) fn Char32! utf8_to_char32(char* ptr, usz* size) { usz max_size = *size; - if (max_size < 1) return UnicodeResult.INVALID_UTF8!; + if (max_size < 1) return UnicodeResult.INVALID_UTF8?; char c = (ptr++)[0]; if ((c & 0x80) == 0) @@ -144,40 +144,40 @@ fn Char32! utf8_to_char32(char* ptr, usz* size) } if ((c & 0xE0) == 0xC0) { - if (max_size < 2) return UnicodeResult.INVALID_UTF8!; + if (max_size < 2) return UnicodeResult.INVALID_UTF8?; *size = 2; Char32 uc = (c & 0x1F) << 6; c = *ptr; // Overlong sequence or invalid second. - if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; return uc + c & 0x3F; } if ((c & 0xF0) == 0xE0) { - if (max_size < 3) return UnicodeResult.INVALID_UTF8!; + if (max_size < 3) return UnicodeResult.INVALID_UTF8?; *size = 3; Char32 uc = (c & 0x0F) << 12; c = ptr++[0]; - if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; uc += (c & 0x3F) << 6; c = ptr++[0]; // Overlong sequence or invalid last - if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; return uc + c & 0x3F; } - if (max_size < 4) return UnicodeResult.INVALID_UTF8!; - if ((c & 0xF8) != 0xF0) return UnicodeResult.INVALID_UTF8!; + if (max_size < 4) return UnicodeResult.INVALID_UTF8?; + if ((c & 0xF8) != 0xF0) return UnicodeResult.INVALID_UTF8?; *size = 4; Char32 uc = (c & 0x07) << 18; c = ptr++[0]; - if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; uc += (c & 0x3F) << 12; c = ptr++[0]; - if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; uc += (c & 0x3F) << 6; c = ptr++[0]; // Overlong sequence or invalid last - if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!; + if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?; return uc + c & 0x3F; } @@ -303,7 +303,7 @@ fn usz! utf32to8(Char32[] utf32, String utf8_buffer) char* ptr = utf8_buffer.ptr; foreach (Char32 uc : utf32) { - usz used = char32_to_utf8(uc, ptr, len) @inline?; + usz used = char32_to_utf8(uc, ptr, len) @inline!; len -= used; ptr += used; } @@ -327,9 +327,9 @@ fn usz! utf8to32(String utf8, Char32[] utf32_buffer) usz buf_len = utf32_buffer.len; for (usz i = 0; i < len;) { - if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED!; + if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED?; usz width = len - i; - Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?; + Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!; i += width; ptr[len32++] = uc; } @@ -352,7 +352,7 @@ fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer) for (usz i = 0; i < len16;) { usz available = len16 - i; - char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline?; + char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline!; i += available; } } @@ -371,7 +371,7 @@ fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer) for (usz i = 0; i < len;) { usz width = len - i; - Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?; + Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!; i += width; (utf32_buffer++)[0] = uc; } @@ -391,7 +391,7 @@ fn void! utf8to16_unsafe(String utf8, Char16* utf16_buffer) for (usz i = 0; i < len;) { usz width = len - i; - Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?; + Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!; char32_to_utf16_unsafe(uc, &utf16_buffer) @inline; i += width; } diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index a49d759b3..6d7bc39b6 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -261,7 +261,7 @@ fn void DString.append_chars(DString* this, String str) fn Char32[] DString.copy_utf32(DString* this, Allocator* using = mem::heap()) { - return str::utf8to32(this.str(), using) @inline!!; + return this.str().to_utf32(using) @inline!!; } fn void DString.append_string(DString* this, DString str) @@ -325,7 +325,7 @@ fn usz! DString.printfn(DString* str, String format, args...) @maydiscard { Formatter formatter; formatter.init(&out_string_append_fn, str); - usz len = formatter.vprintf(format, args)?; + usz len = formatter.vprintf(format, args)!; str.append('\n'); return len + 1; } @@ -350,7 +350,7 @@ fn DString new_join(String[] s, String joiner, Allocator* using = mem::heap()) fn void! out_string_append_fn(char c, void* data) @private { - DynString* s = data; + DString* s = data; s.append_char(c); } @@ -380,11 +380,11 @@ fn usz! DString.read_from_stream(DString* string, Stream* reader) if (reader.supports_available()) { usz total_read = 0; - while (usz available = reader.available()?) + while (usz available = reader.available()!) { string.reserve(available); StringData* data = string.data(); - usz len = reader.read(data.chars[data.len..(data.capacity - 1)])?; + usz len = reader.read(data.chars[data.len..(data.capacity - 1)])!; total_read += len; data.len += len; } @@ -397,7 +397,7 @@ fn usz! DString.read_from_stream(DString* string, Stream* reader) string.reserve(16); StringData* data = string.data(); // Read into the rest of the buffer - usz read = reader.read(data.chars[data.len..(data.capacity - 1)])?; + usz read = reader.read(data.chars[data.len..(data.capacity - 1)])!; data.len += read; // Ok, we reached the end. if (read < 16) return total_read; diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 90034f1dc..8ee1ee924 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -32,7 +32,7 @@ enum OsType KFREEBSD, LINUX, PS3, - MACOSX, + MACOS, NETBSD, OPENBSD, SOLARIS, @@ -137,7 +137,7 @@ macro bool os_is_darwin() { $switch (OS_TYPE) $case IOS: - $case MACOSX: + $case MACOS: $case TVOS: $case WATCHOS: return true; @@ -150,7 +150,7 @@ macro bool os_is_posix() { $switch (OS_TYPE) $case IOS: - $case MACOSX: + $case MACOS: $case NETBSD: $case LINUX: $case KFREEBSD: @@ -181,7 +181,7 @@ $if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32) @pool() { ZString val = libc::getenv(name.zstr_tcopy()); - return val ? val.as_str() : SearchResult.MISSING!; + return val ? val.as_str() : SearchResult.MISSING?; }; $else return ""; diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 2521b6b49..fe8c75689 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -241,10 +241,6 @@ macro malloc_aligned(..., usz alignment = 0, usz end_padding = 0, Allocator* usi $endif } -macro alloc($Type) @deprecated => malloc($Type); - -macro char[] alloc_bytes(usz bytes) @deprecated => malloc(char, bytes); - /** * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" @@ -329,8 +325,6 @@ macro void @scoped(Allocator* using; @body()) @body(); } -macro talloc($Type) @builtin @deprecated => tmalloc($Type); - /** * @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len" * @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'" diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 87c789a90..d0f2b43e0 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -83,12 +83,12 @@ fn void*! Allocator.calloc_aligned(Allocator* allocator, usz size, usz alignment fn void! Allocator.free(Allocator* allocator, void* old_pointer) @inline { - allocator.function(allocator, 0, 0, 0, old_pointer, FREE)?; + allocator.function(allocator, 0, 0, 0, old_pointer, FREE)!; } fn void! Allocator.free_aligned(Allocator* allocator, void* old_pointer) @inline { - allocator.function(allocator, 0, 0, 0, old_pointer, ALIGNED_FREE)?; + allocator.function(allocator, 0, 0, 0, old_pointer, ALIGNED_FREE)!; } fn void Allocator.reset(Allocator* allocator, usz mark = 0) diff --git a/lib/std/core/mem_array.c3 b/lib/std/core/mem_array.c3 deleted file mode 100644 index f179965e7..000000000 --- a/lib/std/core/mem_array.c3 +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2021-2023 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by the MIT license -// a copy of which can be found in the LICENSE_STDLIB file. - -module std::core::mem::array; - -/** - * @require usz.max / elements > $Type.sizeof - **/ -macro alloc($Type, usz elements) @deprecated => malloc($Type, elements); - -/** - * @require usz.max / elements > $Type.sizeof - **/ -macro talloc($Type, usz elements) @deprecated => tmalloc($Type, elements); - -/** - * @require (usz.max / elements > $Type.sizeof) - **/ -macro make($Type, usz elements, Allocator* using = mem::heap()) @deprecated -{ - return calloc($Type, elements, .using = using); -} - -/** - * @require (usz.max / elements > $Type.sizeof) - **/ -macro tmake($Type, usz elements) @deprecated -{ - return tcalloc($Type, elements); -} diff --git a/lib/std/core/os/wasm_memory.c3 b/lib/std/core/os/wasm_memory.c3 index e0be13900..fa45ba875 100644 --- a/lib/std/core/os/wasm_memory.c3 +++ b/lib/std/core/os/wasm_memory.c3 @@ -25,7 +25,7 @@ fn char[]! WasmMemory.allocate_block(WasmMemory* this, usz bytes) } usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE; - if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY!; + if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY?; this.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE; defer this.use += bytes; return ((char*)this.use)[:bytes]; diff --git a/lib/std/core/private/main_stub.c3 b/lib/std/core/private/main_stub.c3 index 20d3a9a2b..d77f7f278 100644 --- a/lib/std/core/private/main_stub.c3 +++ b/lib/std/core/private/main_stub.c3 @@ -7,7 +7,11 @@ macro usz _strlen(ptr) @private return len; } -macro int @main_to_err_main(#m, int, char**) => catch? #m() ? 1 : 0; +macro int @main_to_err_main(#m, int, char**) +{ + if (catch #m()) return 1; + return 0; +} macro int @main_to_int_main(#m, int, char**) => #m(); macro int @main_to_void_main(#m, int, char**) { @@ -32,7 +36,8 @@ macro int @main_to_err_main_args(#m, int argc, char** argv) { String[] list = args_to_strings(argc, argv); defer free(list.ptr); - return catch? #m(list) ? 1 : 0; + if (catch #m(list)) return 1; + return 0; } macro int @main_to_int_main_args(#m, int argc, char** argv) @@ -79,7 +84,11 @@ macro void release_wargs(String[] list) @private free(list.ptr); } -macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => catch? #m() ? 1 : 0; +macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) +{ + if (catch #m()) return 1; + return 0; +} macro int @win_to_int_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => #m(); macro int @win_to_void_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) { @@ -91,7 +100,8 @@ macro int @win_to_err_main_args(#m, void* handle, Char16* cmd_line, int show_cmd { String[] args = win_command_line_to_strings(cmd_line); defer release_wargs(args); - return catch? #m(args) ? 1 : 0; + if (catch #m(args)) return 1; + return 0; } macro int @win_to_int_main_args(#m, void* handle, Char16* cmd_line, int show_cmd) @@ -113,7 +123,8 @@ macro int @win_to_err_main(#m, void* handle, Char16* cmd_line, int show_cmd) { String[] args = win_command_line_to_strings(cmd_line); defer release_wargs(args); - return catch? #m(handle, args, show_cmd) ? 1 : 0; + if (catch #m(handle, args, show_cmd)) return 1; + return 0; } macro int @win_to_int_main(#m, void* handle, Char16* cmd_line, int show_cmd) @@ -135,7 +146,8 @@ macro int @wmain_to_err_main_args(#m, int argc, Char16** argv) { String[] args = wargs_strings(argc, argv); defer release_wargs(args); - return catch? #m(args) ? 1 : 0; + if (catch #m(args)) return 1; + return 1; } macro int @wmain_to_int_main_args(#m, int argc, Char16** argv) diff --git a/lib/std/core/runtime.c3 b/lib/std/core/runtime.c3 index a9855528c..672e80252 100644 --- a/lib/std/core/runtime.c3 +++ b/lib/std/core/runtime.c3 @@ -9,25 +9,12 @@ struct VirtualAny typeid type_id; } -struct VirtualContainer -{ - void* ptr; - void* impl_ptr; -} - struct SubArrayContainer { void* ptr; usz len; } -struct VarArrayHeader -{ - usz size; - usz capacity; - void *allocator; -} - typedef TestFn = fn void!(); struct TestRunner @@ -48,10 +35,13 @@ fn TestRunner test_runner_create() import libc; TestRunner* current_runner @private; + fn void test_panic(String message, String file, String function, uint line) { io::printn("[error]"); - io::printfn("\n Error: %s", message); + io::print("\n Error: "); + io::print(message); + io::printn(); io::printfn(" - in %s %s:%s.\n", function, file, line); libc::longjmp(¤t_runner.buf, 1); } diff --git a/lib/std/core/str.c3 b/lib/std/core/str.c3 deleted file mode 100644 index df4e201f1..000000000 --- a/lib/std/core/str.c3 +++ /dev/null @@ -1,259 +0,0 @@ -module std::core::str; - -fn VarString join(String[] s, String joiner) -{ - if (!s.len) return (VarString)null; - usz total_size = joiner.len * s.len; - foreach (String* &str : s) - { - total_size += str.len; - } - VarString res = string::new_with_capacity(total_size); - res.append(s[0]); - foreach (String* &str : s[1..]) - { - res.append(joiner); - res.append(*str); - } - return res; -} - -macro bool char_in_set(char c, String set) -{ - foreach (ch : set) - { - if (ch == c) return true; - } - return false; -} - -macro char_is_space_tab(char c) @private -{ - return c == ' ' || c == '\t'; -} - -macro to_integer($Type, String string) @private -{ - usz len = string.len; - usz index = 0; - char* ptr = string.ptr; - while (index < len && char_is_space_tab(ptr[index])) index++; - if (len == index) return NumberConversion.EMPTY_STRING!; - bool is_negative; - switch (string[index]) - { - case '-': - if ($Type.min == 0) return NumberConversion.NEGATIVE_VALUE!; - is_negative = true; - index++; - case '+': - index++; - default: - break; - } - if (len == index) return NumberConversion.MALFORMED_INTEGER!; - $Type base = 10; - if (string[index] == '0') - { - index++; - if (index == len) return ($Type)0; - switch (string[index]) - { - case 'x': - case 'X': - base = 16; - index++; - case 'b': - case 'B': - base = 2; - index++; - case 'o': - case 'O': - base = 8; - index++; - default: - break; - } - if (len == index) return NumberConversion.MALFORMED_INTEGER!; - } - $Type value = 0; - while (index != len) - { - char c = {| - char ch = string[index++]; - if (base != 16 || ch < 'A') return (char)(ch - '0'); - if (ch <= 'F') return (char)(ch - 'A'); - if (ch < 'a') return NumberConversion.MALFORMED_INTEGER!; - if (ch > 'f') return NumberConversion.MALFORMED_INTEGER!; - return (char)(ch - 'a'); - |}?; - if (c >= base) return NumberConversion.MALFORMED_INTEGER!; - value = {| - if (is_negative) - { - $Type new_value = value * base - c; - if (new_value > value) return NumberConversion.INTEGER_OVERFLOW!; - return new_value; - } - $Type new_value = value * base + c; - if (new_value < value) return NumberConversion.INTEGER_OVERFLOW!; - return new_value; - |}?; - } - return value; -} - -fn float! to_float(String string) => floatparse(string, float); -fn double! to_double(String string) => floatparse(string, double); -fn int128! to_int128(String string) => to_integer(int128, string); -fn long! to_long(String string) => to_integer(long, string); -fn int! to_int(String string) => to_integer(int, string); -fn short! to_short(String string) => to_integer(short, string); -fn ichar! to_ichar(String string) => to_integer(ichar, string); - -fn uint128! to_uint128(String str) => to_integer(uint128, str); -fn ulong! to_ulong(String str) => to_integer(ulong, str); -fn uint! to_uint(String str) => to_integer(uint, str); -fn ushort! to_ushort(String str) => to_integer(ushort, str); -fn char! to_uchar(String str) => to_integer(char, str); - -fn String trim(String string, String to_trim = "\t\n\r ") @deprecated => string.trim(to_trim); - -fn bool starts_with(String s, String needle) @deprecated => s.starts_with(needle); - -fn String[] tsplit(String s, String needle) @deprecated => s.split(needle, .using = mem::temp()) @inline; -fn String[] split(String s, String needle, Allocator* using = mem::heap()) @deprecated => s.split(needle, .using = using); -fn usz! rindex_of(String s, String needle) @deprecated => s.rindex_of(needle); -fn usz! index_of(String s, String needle) @deprecated => s.index_of(needle); - -fn ZString String.zstrcopy(String s, Allocator* using = mem::heap()) @deprecated => s.zstr_copy(using); -fn ZString String.zstrtcopy(String s) @deprecated => s.zstr_tcopy(); - -fn ZString copy_zstring(String s, Allocator* using = mem::heap()) @deprecated => s.zstr_copy(using); -fn String copyz(String s, Allocator* using = mem::heap()) @deprecated => s.copy(using); -fn ZString tcopy_zstring(String s) @deprecated => s.zstr_tcopy(); - -fn bool compare(String a, String b) -{ - if (a.len != b.len) return false; - foreach (i, c : a) - { - if (c != b[i]) return false; - } - return true; -} - -fault UnicodeResult -{ - INVALID_UTF8, - INVALID_UTF16, - CONVERSION_FAILED, -} - -fn usz utf8_codepoints(String utf8) -{ - usz len = 0; - foreach (char c : utf8) - { - if (c & 0xC0 != 0x80) len++; - } - return len; -} - -fn Char32[]! utf8to32(String utf8, Allocator* using = mem::heap()) -{ - usz codepoints = conv::utf8_codepoints(utf8); - Char32* data = malloc_checked(Char32, codepoints + 1, .using = using)?; - conv::utf8to32_unsafe(utf8, data)?; - data[codepoints] = 0; - return data[:codepoints]; -} - -fn String utf32to8(Char32[] utf32, Allocator* using = mem::heap()) -{ - usz len = conv::utf8len_for_utf32(utf32); - char* data = malloc_checked(len + 1, .using = using)!!; - conv::utf32to8_unsafe(utf32, data); - data[len] = 0; - return (String)data[:len]; -} - -fn Char16[]! utf8to16(String utf8, Allocator* using = mem::heap()) -{ - usz len16 = conv::utf16len_for_utf8(utf8); - Char16* data = malloc_checked(Char16, len16 + 1, .using = using)?; - conv::utf8to16_unsafe(utf8, data)?; - data[len16] = 0; - return data[:len16]; -} - - -fn String! utf16to8(Char16[] utf16, Allocator* using = mem::heap()) -{ - usz len = conv::utf8len_for_utf16(utf16); - char* data = malloc_checked(len + 1, .using = using)?; - conv::utf16to8_unsafe(utf16, data)?; - data[len] = 0; - return (String)data[:len]; -} - -fn String copy(String s, Allocator* using = mem::heap()) @deprecated -{ - usz len = s.len; - ZString str_copy = s.zstr_copy(using) @inline; - return (String)str_copy[:len]; -} - -fn String tcopy(String s) @deprecated -{ - usz len = s.len; - ZString str_copy = s.zstr_tcopy() @inline; - return (String)str_copy[:len]; -} - -fn String tconcat(String s1, String s2) -{ - usz full_len = s1.len + s2.len; - char* str = tmalloc(full_len + 1); - usz s1_len = s1.len; - mem::copy(str, s1.ptr, s1_len); - mem::copy(str + s1_len, s2.ptr, s2.len); - str[full_len] = 0; - return (String)str[:full_len]; -} - -fn String concat(String s1, String s2) -{ - usz full_len = s1.len + s2.len; - char* str = malloc(full_len + 1); - usz s1_len = s1.len; - mem::copy(str, s1.ptr, s1_len); - mem::copy(str + s1_len, s2.ptr, s2.len); - str[full_len] = 0; - return (String)str[:full_len]; -} - -fn String ZString.as_str(ZString str) -{ - return (String)((char*)str)[:str.len()]; -} - -fn usz ZString.char_len(ZString str) -{ - usz len = 0; - char* ptr = (char*)str; - while (char c = ptr++[0]) - { - if (c & 0xC0 != 0x80) len++; - } - return len; -} - -fn usz ZString.len(ZString str) -{ - usz len = 0; - char* ptr = (char*)str; - while (char c = ptr++[0]) len++; - return len; -} - diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 8398ec4fe..e68433183 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -1,9 +1,17 @@ module std::core::string; +import std::ascii; typedef ZString = distinct inline char*; typedef Char32 = uint; typedef Char16 = ushort; +fault UnicodeResult +{ + INVALID_UTF8, + INVALID_UTF16, + CONVERSION_FAILED, +} + const uint SURROGATE_OFFSET @private = 0x10000; const uint SURROGATE_GENERIC_MASK @private = 0xF800; const uint SURROGATE_MASK @private = 0xFC00; @@ -47,6 +55,31 @@ macro bool char_in_set(char c, String set) return false; } +fn String join(String[] s, String joiner, Allocator* using = mem::heap()) +{ + if (!s) + { + return (String)(calloc(char, 2, .using = using)[:0]); + } + + usz total_size = joiner.len * s.len; + foreach (String* &str : s) + { + total_size += str.len; + } + @stack_mem(256; Allocator* mem) + { + DString res = dstring::new_with_capacity(total_size, .using = mem); + res.append(s[0]); + foreach (String* &str : s[1..]) + { + res.append(joiner); + res.append(*str); + } + return res.copy_str(using); + }; +} + /** * @param [in] string * @param [in] to_trim @@ -128,7 +161,7 @@ fn String[] String.split(String s, String needle, usz max = 0, Allocator* using bool no_more = false; while (!no_more) { - usz! index = i == max - 1 ? SearchResult.MISSING! : s.index_of(needle); + usz! index = i == max - 1 ? SearchResult.MISSING? : s.index_of(needle); String res @noinit; if (try index) { @@ -163,6 +196,11 @@ fn String[] String.tsplit(String s, String needle, usz max = 0) return s.split(needle, max, mem::temp()) @inline; } +fn bool String.contains(String s, String needle) +{ + return @ok(s.index_of(needle)); +} + /** * Find the index of the first incidence of a string. * @@ -170,7 +208,9 @@ fn String[] String.tsplit(String s, String needle, usz max = 0) * @param [in] needle * @pure * @ensure return < s.len - * @require needle.len > 0 "The needle must be len 1 or more" + * @require needle.len > 0 : "The needle must be len 1 or more" + * @return "the index of the needle" + * @return! SearchResult.MISSING "if the needle cannot be found" **/ fn usz! String.index_of(String s, String needle) { @@ -194,7 +234,7 @@ fn usz! String.index_of(String s, String needle) search = needle[0]; } } - return SearchResult.MISSING!; + return SearchResult.MISSING?; } /** @@ -205,6 +245,8 @@ fn usz! String.index_of(String s, String needle) * @pure * @ensure return < s.len * @require needle.len > 0 "The needle must be len 1 or more" + * @return "the index of the needle" + * @return! SearchResult.MISSING "if the needle cannot be found" **/ fn usz! String.rindex_of(String s, String needle) { @@ -228,9 +270,34 @@ fn usz! String.rindex_of(String s, String needle) search = needle[^1]; } } - return SearchResult.MISSING!; + return SearchResult.MISSING?; } +fn String ZString.as_str(ZString str) +{ + return (String)((char*)str)[:str.len()]; +} + +fn usz ZString.char_len(ZString str) +{ + usz len = 0; + char* ptr = (char*)str; + while (char c = ptr++[0]) + { + if (c & 0xC0 != 0x80) len++; + } + return len; +} + +fn usz ZString.len(ZString str) +{ + usz len = 0; + char* ptr = (char*)str; + while (char c = ptr++[0]) len++; + return len; +} + + fn ZString String.zstr_copy(String s, Allocator* using = mem::heap()) { usz len = s.len; @@ -270,23 +337,154 @@ fn String String.tcopy(String s) => s.copy(mem::temp()) @inline; fn String ZString.copy(ZString z, Allocator* using = mem::heap()) => z.as_str().copy(using) @inline; fn String ZString.tcopy(ZString z) => z.as_str().copy(mem::temp()) @inline; +/** + * Convert an UTF-8 string to UTF-16 + * @return "The UTF-16 string as a slice, allocated using the given allocator" + * @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" + * @return! AllocationFailure "If allocation of the string fails" + **/ fn Char16[]! String.to_utf16(String s, Allocator* using = mem::heap()) { usz len16 = conv::utf16len_for_utf8(s); - Char16* data = malloc_checked(Char16, len16 + 1, .using = using)?; - conv::utf8to16_unsafe(s, data)?; + Char16* data = malloc_checked(Char16, len16 + 1, .using = using)!; + conv::utf8to16_unsafe(s, data)!; data[len16] = 0; return data[:len16]; } +fn Char32[]! String.to_utf32(String s, Allocator* using = mem::heap()) +{ + usz codepoints = conv::utf8_codepoints(s); + Char32* data = malloc_checked(Char32, codepoints + 1, .using = using)!; + conv::utf8to32_unsafe(s, data)!; + data[codepoints] = 0; + return data[:codepoints]; +} + +fn String! from_utf32(Char32[] utf32, Allocator* using = mem::heap()) +{ + usz len = conv::utf8len_for_utf32(utf32); + char* data = malloc_checked(len + 1, .using = using)!; + defer catch free(data, .using = using); + conv::utf32to8_unsafe(utf32, data); + data[len] = 0; + return (String)data[:len]; +} + fn String! from_utf16(Char16[] utf16, Allocator* using = mem::heap()) { usz len = conv::utf8len_for_utf16(utf16); - char* data = malloc_checked(len + 1, .using = using)?; - conv::utf16to8_unsafe(utf16, data)?; + char* data = malloc_checked(len + 1, .using = using)!; + defer catch free(data, .using = using); + conv::utf16to8_unsafe(utf16, data)!; data[len] = 0; return (String)data[:len]; } +fn String! from_zutf16(Char16* utf16_pointer, Allocator* using = mem::heap()) +{ + usz utf16_len; + while (utf16_pointer[utf16_len] != 0) utf16_len++; + Char16[] utf16 = utf16_pointer[:utf16_len]; + return from_utf16(utf16, using); +} + +fn usz String.utf8_codepoints(String s) +{ + usz len = 0; + foreach (char c : s) + { + if (c & 0xC0 != 0x80) len++; + } + return len; +} + + +macro String.to_integer(String string, $Type) +{ + usz len = string.len; + usz index = 0; + char* ptr = string.ptr; + while (index < len && ascii::is_blank_m(ptr[index])) index++; + if (len == index) return NumberConversion.EMPTY_STRING?; + bool is_negative; + switch (string[index]) + { + case '-': + if ($Type.min == 0) return NumberConversion.NEGATIVE_VALUE?; + is_negative = true; + index++; + case '+': + index++; + default: + break; + } + if (len == index) return NumberConversion.MALFORMED_INTEGER?; + $Type base = 10; + if (string[index] == '0') + { + index++; + if (index == len) return ($Type)0; + switch (string[index]) + { + case 'x': + case 'X': + base = 16; + index++; + case 'b': + case 'B': + base = 2; + index++; + case 'o': + case 'O': + base = 8; + index++; + default: + break; + } + if (len == index) return NumberConversion.MALFORMED_INTEGER?; + } + $Type value = 0; + while (index != len) + { + char c = {| + char ch = string[index++]; + if (base != 16 || ch < 'A') return (char)(ch - '0'); + if (ch <= 'F') return (char)(ch - 'A'); + if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?; + if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?; + return (char)(ch - 'a'); + |}!; + if (c >= base) return NumberConversion.MALFORMED_INTEGER?; + value = {| + if (is_negative) + { + $Type new_value = value * base - c; + if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?; + return new_value; + } + $Type new_value = value * base + c; + if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?; + return new_value; + |}!; + } + return value; +} + fn Char16[]! String.to_temp_utf16(String s) => s.to_utf16(mem::temp()); + +fn int128! String.to_int128(String s) => s.to_integer(int128); +fn long! String.to_long(String s) => s.to_integer(long); +fn int! String.to_int(String s) => s.to_integer(int); +fn short! String.to_short(String s) => s.to_integer(short); +fn ichar! String.to_ichar(String s) => s.to_integer(ichar); + +fn uint128! String.to_uint128(String s) => s.to_integer(uint128); +fn ulong! String.to_ulong(String s) => s.to_integer(ulong); +fn uint! String.to_uint(String s) => s.to_integer(uint); +fn ushort! String.to_ushort(String s) => s.to_integer(ushort); +fn char! String.to_uchar(String s) => s.to_integer(char); + +fn double! String.to_double(String s) => s.to_real(double); +fn float! String.to_float(String s) => s.to_real(float); diff --git a/lib/std/core/string_iterator.c3 b/lib/std/core/string_iterator.c3 index f2df2ac42..96ea6b4da 100644 --- a/lib/std/core/string_iterator.c3 +++ b/lib/std/core/string_iterator.c3 @@ -15,9 +15,9 @@ fn Char32! StringIterator.next(StringIterator* this) { usz len = this.utf8.len; usz current = this.current; - if (current >= len) return IteratorResult.NO_MORE_ELEMENT!; + if (current >= len) return IteratorResult.NO_MORE_ELEMENT?; usz read = (len - current < 4 ? len - current : 4); - Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)?; + Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)!; this.current += read; return res; } \ No newline at end of file diff --git a/lib/std/core/floatparse.c3 b/lib/std/core/string_to_real.c3 similarity index 91% rename from lib/std/core/floatparse.c3 rename to lib/std/core/string_to_real.c3 index f0c62145f..aa8362685 100644 --- a/lib/std/core/floatparse.c3 +++ b/lib/std/core/string_to_real.c3 @@ -1,4 +1,4 @@ -module std::core::str; +module std::core::string; import std::math; // Float parsing based on code in Musl floatscan.c by Rich Felker. @@ -64,7 +64,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) got_rad = true; if (index == last_char) { - if (!got_digit) return NumberConversion.MALFORMED_FLOAT!; + if (!got_digit) return NumberConversion.MALFORMED_FLOAT?; return sign * 0.0; } if (index != last_char && (c = chars[++index]) == '0') @@ -83,7 +83,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) switch { case c == '.': - if (got_rad) return NumberConversion.MALFORMED_FLOAT!; + if (got_rad) return NumberConversion.MALFORMED_FLOAT?; got_rad = true; lrp = dc; case k < KMAX - 3: @@ -113,24 +113,24 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) c = chars[++index]; } if (!got_rad) lrp = dc; - if (!got_digit) return NumberConversion.MALFORMED_FLOAT!; + if (!got_digit) return NumberConversion.MALFORMED_FLOAT?; if ((c | 32) == 'e') { - if (last_char == index) return NumberConversion.MALFORMED_FLOAT!; - long e10 = str::to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT!?; + if (last_char == index) return NumberConversion.MALFORMED_FLOAT?; + long e10 = String.to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT?!; lrp += e10; } else if (index != last_char) { - return NumberConversion.MALFORMED_FLOAT!; + return NumberConversion.MALFORMED_FLOAT?; } // Handle zero specially to avoid nasty special cases later if (!x[0]) return sign * 0.0; // Optimize small integers (w/no exponent) and over/under-flow if (lrp == dc && dc < 10 && ($bits > 30 || (ulong)x[0] >> $bits == 0)) return sign * (double)x[0]; - if (lrp > - $emin / 2) return NumberConversion.FLOAT_OUT_OF_RANGE!; - if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE!; + if (lrp > - $emin / 2) return NumberConversion.FLOAT_OUT_OF_RANGE?; + if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?; // Align incomplete final B1B digit if (j) @@ -320,7 +320,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) y *= 0.5; e2++; } - if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return NumberConversion.MALFORMED_FLOAT!; + if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return NumberConversion.MALFORMED_FLOAT?; } return math::scalbn(y, e2); } @@ -351,7 +351,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) got_rad = true; if (index == last_char) { - if (!got_digit) return NumberConversion.MALFORMED_FLOAT!; + if (!got_digit) return NumberConversion.MALFORMED_FLOAT?; return sign * 0.0; } if (index != last_char && (c = chars[++index]) == '0') @@ -369,7 +369,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) { if (c == '.') { - if (got_rad) return NumberConversion.MALFORMED_FLOAT!; + if (got_rad) return NumberConversion.MALFORMED_FLOAT?; got_rad = true; rp = dc; } @@ -396,20 +396,20 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) if (index == last_char) break; c = chars[++index]; } - if (!got_digit) return NumberConversion.MALFORMED_FLOAT!; + if (!got_digit) return NumberConversion.MALFORMED_FLOAT?; if (!got_rad) rp = dc; for (; dc < 8; dc++) x *= 16; long e2; if ((c | 32) == 'p') { - long e2val = str::to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT!?; + long e2val = String.to_long((String)chars[index + 1..]) ?? (NumberConversion.MALFORMED_FLOAT?)!; e2 = e2val; } e2 += 4 * rp - 32; if (!x) return sign * 0.0; - if (e2 > -$emin) return NumberConversion.FLOAT_OUT_OF_RANGE!; - if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE!; + if (e2 > -$emin) return NumberConversion.FLOAT_OUT_OF_RANGE?; + if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?; while (x < 0x80000000) { @@ -444,12 +444,12 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) } y = bias + sign * (double)x + sign * y; y -= bias; - if (!y) return NumberConversion.FLOAT_OUT_OF_RANGE!; + if (!y) return NumberConversion.FLOAT_OUT_OF_RANGE?; return math::scalbn(y, (int)e2); } -macro floatparse(String chars, $Type) @private +macro String.to_real(String chars, $Type) @private { int sign = 1; $switch ($Type) @@ -466,7 +466,7 @@ macro floatparse(String chars, $Type) @private $endswitch while (chars.len && chars[0] == ' ') chars = chars[1..]; - if (!chars.len) return NumberConversion.MALFORMED_FLOAT!; + if (!chars.len) return NumberConversion.MALFORMED_FLOAT?; switch (chars[0]) { case '-': diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 1f948e98e..089f5105e 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -1,3 +1,4 @@ + module std::core::types; import libc; @@ -10,63 +11,63 @@ fault ConversionResult /** * @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer" **/ -macro variant_to_int(variant v, $Type) +macro any_to_int(any v, $Type) { - typeid variant_type = v.type; - TypeKind kind = variant_type.kindof; + typeid any_type = v.type; + TypeKind kind = any_type.kindof; if (kind == TypeKind.ENUM) { - variant_type = variant_type.inner; - kind = variant_type.kindof; + any_type = any_type.inner; + kind = any_type.kindof; } - bool is_mixed_signed = $Type.kindof != variant_type.kindof; + bool is_mixed_signed = $Type.kindof != any_type.kindof; $Type max = $Type.max; $Type min = $Type.min; - switch (variant_type) + switch (any_type) { case ichar: ichar c = *(char*)v.ptr; - if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?; return ($Type)c; case short: short s = *(short*)v.ptr; - if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; - if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?; + if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)s; case int: int i = *(int*)v.ptr; - if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)i; case long: long l = *(long*)v.ptr; - if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; - if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?; + if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)l; case int128: int128 i = *(int128*)v.ptr; - if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)i; case char: char c = *(char*)v.ptr; - if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)c; case ushort: ushort s = *(ushort*)v.ptr; - if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)s; case uint: uint i = *(uint*)v.ptr; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)i; case ulong: ulong l = *(ulong*)v.ptr; - if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)l; case uint128: uint128 i = *(uint128*)v.ptr; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?; return ($Type)i; default: unreachable(); @@ -219,15 +220,20 @@ macro bool is_same_vector_type($Type1, $Type2) $endif } -macro bool is_equatable_value(value) +macro bool is_equatable_type($Type) { - $if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)) + $if ($defined($Type.less) || $defined($Type.compare_to) || $defined($Type.equals)) return true; $else - return is_equatable($typeof(value)); + return is_equatable($Type); $endif } +macro bool is_equatable_value(value) +{ + return is_equatable_type($typeof(value)); +} + macro bool is_comparable_value(value) { $if ($defined(value.less) || $defined(value.compare_to)) @@ -245,8 +251,8 @@ enum TypeKind : char UNSIGNED_INT, FLOAT, TYPEID, - ANYERR, - VARIANT, + ANYFAULT, + ANY, ENUM, FAULT, STRUCT, diff --git a/lib/std/core/values.c3 b/lib/std/core/values.c3 index 847c461e6..efce6c743 100644 --- a/lib/std/core/values.c3 +++ b/lib/std/core/values.c3 @@ -20,3 +20,4 @@ macro promote_int(x) } macro TypeKind @inner_kind(#value) => types::inner_kind($typeof(#value)); + diff --git a/lib/std/core/varstring.c3 b/lib/std/core/varstring.c3 deleted file mode 100644 index e71e48e05..000000000 --- a/lib/std/core/varstring.c3 +++ /dev/null @@ -1,327 +0,0 @@ -module std::core::string; -import libc; - -typedef VarString = distinct void*; -typedef DynStr = VarString; -typedef DynString = VarString; -typedef VString = VarString; -typedef Text = VarString; - -const usz MIN_CAPACITY = 16; - -fn VarString new_with_capacity(usz capacity, Allocator* allocator = mem::heap()) -{ - if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; - StringData* data = malloc(StringData, 1, .using = allocator, .end_padding = capacity); - data.allocator = allocator; - data.len = 0; - data.capacity = capacity; - return (VarString)data; -} - -fn VarString new(String c) -{ - usz len = c.len; - VarString str = new_with_capacity(len); - StringData* data = str.data(); - if (len) - { - data.len = len; - mem::copy(&data.chars, c.ptr, len); - } - return (VarString)data; -} - -fn ZString VarString.zstr(VarString str) -{ - StringData* data = str.data(); - if (!data) return (ZString)""; - if (data.capacity == data.len) - { - str.reserve(1); - data.chars[data.len] = 0; - } - else if (data.chars[data.len] != 0) - { - data.chars[data.len] = 0; - } - return (ZString)&data.chars[0]; -} - -fn usz VarString.capacity(VarString this) -{ - if (!this) return 0; - return this.data().capacity; -} - -fn usz VarString.len(VarString this) -{ - if (!this) return 0; - return this.data().len; -} - -/** - * @require new_size <= this.len() - */ -fn void VarString.chop(VarString this, usz new_size) -{ - if (!this) return; - this.data().len = new_size; -} - -fn String VarString.str(VarString str) -{ - StringData* data = (StringData*)str; - if (!data) return ""; - return (String)data.chars[:data.len]; -} - -fn void VarString.append_utf32(VarString* str, Char32[] chars) -{ - str.reserve(chars.len); - foreach (Char32 c : chars) - { - str.append_char32(c); - } -} - -/** - * @require index < str.len() - **/ -fn void VarString.set(VarString str, usz index, char c) -{ - str.data().chars[index] = c; -} - -fn void VarString.append_repeat(VarString* str, char c, usz times) -{ - if (times == 0) return; - str.reserve(times); - StringData* data = str.data(); - for (usz i = 0; i < times; i++) - { - data.chars[data.len++] = c; - } -} - -/** - * @require c <= 0x10ffff - */ -fn void VarString.append_char32(VarString* str, Char32 c) -{ - if (c < 0x7f) - { - str.reserve(1); - StringData* data = str.data(); - data.chars[data.len++] = (char)c; - return; - } - if (c < 0x7ff) - { - str.reserve(2); - StringData* data = str.data(); - data.chars[data.len++] = (char)(0xC0 | c >> 6); - data.chars[data.len++] = (char)(0x80 | (c & 0x3F)); - return; - } - if (c < 0xffff) - { - str.reserve(3); - StringData* data = str.data(); - data.chars[data.len++] = (char)(0xE0 | c >> 12); - data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F)); - data.chars[data.len++] = (char)(0x80 | (c & 0x3F)); - return; - } - str.reserve(4); - StringData* data = str.data(); - data.chars[data.len++] = (char)(0xF0 | c >> 18); - data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F)); - data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F)); - data.chars[data.len++] = (char)(0x80 | (c & 0x3F)); -} - -fn VarString VarString.tcopy(VarString* str) => str.copy(mem::temp()); - -fn VarString VarString.copy(VarString* str, Allocator* allocator = null) -{ - if (!str) - { - if (allocator) return new_with_capacity(0, allocator); - return (VarString)null; - } - if (!allocator) allocator = mem::heap(); - StringData* data = str.data(); - VarString new_string = new_with_capacity(data.capacity, allocator); - mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len); - return new_string; -} - -fn ZString VarString.copy_zstr(VarString* str, Allocator* allocator = mem::heap()) -{ - usz str_len = str.len(); - if (!str_len) - { - return (ZString)calloc(1, .using = allocator); - } - char* zstr = malloc(str_len + 1, .using = allocator); - StringData* data = str.data(); - mem::copy(zstr, &data.chars, str_len); - zstr[str_len] = 0; - return (ZString)zstr; -} - -fn String VarString.copy_str(VarString* str, Allocator* allocator = mem::heap()) -{ - return (String)str.copy_zstr(allocator)[:str.len()]; -} - -fn String VarString.tcopy_str(VarString* str) => str.copy_str(mem::temp()) @inline; - -fn bool VarString.equals(VarString str, VarString other_string) -{ - StringData *str1 = str.data(); - StringData *str2 = other_string.data(); - if (str1 == str2) return true; - if (!str1) return str2.len == 0; - if (!str2) return str1.len == 0; - usz str1_len = str1.len; - if (str1_len != str2.len) return false; - for (int i = 0; i < str1_len; i++) - { - if (str1.chars[i] != str2.chars[i]) return false; - } - return true; -} - -fn void VarString.destroy(VarString* str) -{ - if (!*str) return; - StringData* data = str.data(); - if (!data) return; - free(data, .using = data.allocator); - *str = (VarString)null; -} - -fn bool VarString.less(VarString str, VarString other_string) -{ - StringData* str1 = str.data(); - StringData* str2 = other_string.data(); - if (str1 == str2) return false; - if (!str1) return str2.len != 0; - if (!str2) return str1.len == 0; - usz str1_len = str1.len; - usz str2_len = str2.len; - if (str1_len != str2_len) return str1_len < str2_len; - for (int i = 0; i < str1_len; i++) - { - if (str1.chars[i] >= str2.chars[i]) return false; - } - return true; -} - -fn void VarString.append_chars(VarString* this, String str) -{ - usz other_len = str.len; - if (!other_len) return; - if (!*this) - { - *this = new(str); - return; - } - this.reserve(other_len); - StringData* data = (StringData*)*this; - mem::copy(&data.chars[data.len], str.ptr, other_len); - data.len += other_len; -} - -fn Char32[] VarString.copy_utf32(VarString* this, Allocator* allocator = mem::heap()) -{ - return str::utf8to32(this.str(), allocator) @inline!!; -} - -fn void VarString.append_string(VarString* this, VarString str) -{ - StringData* other = (StringData*)str; - if (!other) return; - this.append(str.str()); -} - -fn void VarString.clear(VarString* str) -{ - str.data().len = 0; -} - -fn void VarString.append_char(VarString* str, char c) -{ - if (!*str) - { - *str = new_with_capacity(MIN_CAPACITY); - } - str.reserve(1); - StringData* data = (StringData*)*str; - data.chars[data.len++] = c; -} - - -macro void VarString.append(VarString* str, value) -{ - var $Type = $typeof(value); - $switch ($Type) - $case char: - $case ichar: - str.append_char(value); - $case VarString: - str.append_string(value); - $case String: - str.append_chars(value); - $case Char32: - str.append_char32(value); - $default: - $switch - $case @convertible(value, Char32): - str.append_char32(value); - $case @convertible(value, String): - str.append_chars(value); - $default: - $assert(false, "Unsupported type for append – use printf instead."); - $endswitch - $endswitch -} - - -fn StringData* VarString.data(VarString str) @inline @private -{ - return (StringData*)str; -} - -fn void VarString.reserve(VarString* str, usz addition) @private -{ - StringData* data = str.data(); - if (!data) - { - *str = string::new_with_capacity(addition); - return; - } - usz len = data.len + addition; - if (data.capacity >= len) return; - usz new_capacity = data.capacity *= 2; - if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY; - *str = (VarString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator); -} - -fn VarString VarString.new_concat(VarString a, VarString b, Allocator* allocator = mem::heap()) -{ - VarString string = new_with_capacity(a.len() + b.len(), allocator); - string.append(a); - string.append(b); - return string; -} - -struct StringData @private -{ - Allocator* allocator; - usz len; - usz capacity; - char[*] chars; -} diff --git a/lib/std/encoding/json.c3 b/lib/std/encoding/json.c3 index 25d7e401f..5440a583f 100644 --- a/lib/std/encoding/json.c3 +++ b/lib/std/encoding/json.c3 @@ -32,7 +32,7 @@ struct JsonParser DString last_string; double last_number; char current; - anyerr current_err; + anyfault current_err; bool skip_comments; bool reached_end; } @@ -61,13 +61,13 @@ fn Object*! JsonParser.parse_from_token(JsonParser* this, JsonTokenType token) case COMMA: case RBRACE: case RBRACKET: - case COLON: return JsonParsingError.UNEXPECTED_CHARACTER!; + case COLON: return JsonParsingError.UNEXPECTED_CHARACTER?; case STRING: return object::new_string(this.last_string.str(), this.allocator); case NUMBER: return object::new_float(this.last_number, this.allocator); case TRUE: return object::new_bool(true); case FALSE: return object::new_bool(false); case NULL: return object::new_null(); - case EOF: return JsonParsingError.EOF!; + case EOF: return JsonParsingError.EOF?; } unreachable(); } @@ -85,17 +85,17 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c) if (negate) { t.append(c); - c = this.read_next()?; + c = this.read_next()!; } while (c >= '0' && c <= '9') { t.append(c); - c = this.read_next()?; + c = this.read_next()!; } if (c == '.') { t.append(c); - while (c = this.read_next()?, c >= '0' && c <= '9') + while (c = this.read_next()!, c >= '0' && c <= '9') { t.append(c); } @@ -103,24 +103,24 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c) if ((c | 32) == 'e') { t.append(c); - c = this.read_next()?; + c = this.read_next()!; switch (c) { case '-': case '+': t.append(c); - c = this.read_next()?; + c = this.read_next()!; } - if (c < '0' || c > '9') return JsonParsingError.INVALID_NUMBER!; + if (c < '0' || c > '9') return JsonParsingError.INVALID_NUMBER?; while (c >= '0' && c <= '9') { t.append(c); - c = this.read_next()?; + c = this.read_next()!; } } this.pushback(); - double! d = str::to_double(t.str()) ?? JsonParsingError.INVALID_NUMBER!; - this.last_number = d?; + double! d = t.str().to_double() ?? JsonParsingError.INVALID_NUMBER?; + this.last_number = d!; return NUMBER; }; } @@ -128,30 +128,30 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c) fn Object*! JsonParser.parse_map(JsonParser* this) { Object* map = object::new_obj(this.allocator); - JsonTokenType token = this.advance()?; + JsonTokenType token = this.advance()!; defer catch map.free(); DString temp_key = dstring::new_with_capacity(32, this.allocator); defer temp_key.free(); while (token != JsonTokenType.RBRACE) { - if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER!; + if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER?; DString string = this.last_string; - if (map.has_key(string.str())) return JsonParsingError.DUPLICATE_MEMBERS!; + if (map.has_key(string.str())) return JsonParsingError.DUPLICATE_MEMBERS?; // Copy the key to our temp holder. We do this to work around the issue // if the temp allocator should be used as the default allocator. temp_key.clear(); temp_key.append(string); - this.parse_expected(COLON)?; - Object* element = this.parse_any()?; + this.parse_expected(COLON)!; + Object* element = this.parse_any()!; map.set(temp_key.str(), element); - token = this.advance()?; + token = this.advance()!; if (token == JsonTokenType.COMMA) { - token = this.advance()?; + token = this.advance()!; continue; } - if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER!; + if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER?; } return map; } @@ -160,18 +160,18 @@ fn Object*! JsonParser.parse_array(JsonParser* this) { Object* list = object::new_obj(this.allocator); defer catch list.free(); - JsonTokenType token = this.advance()?; + JsonTokenType token = this.advance()!; while (token != JsonTokenType.RBRACKET) { - Object* element = this.parse_from_token(token)?; + Object* element = this.parse_from_token(token)!; list.append(element); - token = this.advance()?; + token = this.advance()!; if (token == JsonTokenType.COMMA) { - token = this.advance()?; + token = this.advance()!; continue; } - if (token != JsonTokenType.RBRACKET) return JsonParsingError.UNEXPECTED_CHARACTER!; + if (token != JsonTokenType.RBRACKET) return JsonParsingError.UNEXPECTED_CHARACTER?; } return list; } @@ -191,7 +191,7 @@ fn char! JsonParser.read_next(JsonParser* this) this.reached_end = true; return '\0'; default: - return err!; + return err?; } if (c == 0) { @@ -204,7 +204,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this) { char c; // Skip whitespace - while WS: (c = this.read_next()?) + while WS: (c = this.read_next()!) { switch (c) { @@ -218,7 +218,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this) continue; case '/': if (!this.skip_comments) break; - c = this.read_next()?; + c = this.read_next()!; if (c != '*') { this.pushback(); @@ -227,12 +227,12 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this) while COMMENT: (1) { // Skip to */ - while (c = this.read_next()?) + while (c = this.read_next()!) { if (c == '\n') this.line++; if (c != '*') continue; // Skip through all the '*' - while (c = this.read_next()?) + while (c = this.read_next()!) { if (c == '\n') this.line++; if (c != '*') break; @@ -248,7 +248,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this) switch (c) { case '\0': - return IoError.EOF!; + return IoError.EOF?; case '{': return LBRACE; case '}': @@ -267,16 +267,16 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this) case '0'..'9': return this.lex_number(c); case 't': - this.match("rue")?; + this.match("rue")!; return TRUE; case 'f': - this.match("alse")?; + this.match("alse")!; return FALSE; case 'n': - this.match("ull")?; + this.match("ull")!; return NULL; default: - return JsonParsingError.UNEXPECTED_CHARACTER!; + return JsonParsingError.UNEXPECTED_CHARACTER?; } } @@ -284,14 +284,14 @@ fn void! JsonParser.match(JsonParser* this, String str) { foreach (c : str) { - char l = this.read_next()?; - if (l != c) return JsonParsingError.UNEXPECTED_CHARACTER!; + char l = this.read_next()!; + if (l != c) return JsonParsingError.UNEXPECTED_CHARACTER?; } } fn void! JsonParser.parse_expected(JsonParser* this, JsonTokenType token) @local { - if (this.advance()? != token) return JsonParsingError.UNEXPECTED_CHARACTER!; + if (this.advance()! != token) return JsonParsingError.UNEXPECTED_CHARACTER?; } fn JsonTokenType! JsonParser.lex_string(JsonParser *this) @@ -299,13 +299,13 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this) this.last_string.clear(); while LOOP: (1) { - char c = this.read_next()?; + char c = this.read_next()!; switch (c) { case '\0': - return JsonParsingError.EOF!; + return JsonParsingError.EOF?; case 1..31: - return JsonParsingError.UNEXPECTED_CHARACTER!; + return JsonParsingError.UNEXPECTED_CHARACTER?; case '"': break LOOP; case '\\': @@ -314,13 +314,13 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this) this.last_string.append(c); continue; } - c = this.read_next()?; + c = this.read_next()!; switch (c) { case '\0': - return JsonParsingError.EOF!; + return JsonParsingError.EOF?; case 1..31: - return JsonParsingError.UNEXPECTED_CHARACTER!; + return JsonParsingError.UNEXPECTED_CHARACTER?; case '"': case '\\': case '/': @@ -339,14 +339,14 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this) uint val; for (int i = 0; i < 4; i++) { - c = this.read_next()?; - if (!c.is_xdigit()) return JsonParsingError.INVALID_ESCAPE_SEQUENCE!; + c = this.read_next()!; + if (!c.is_xdigit()) return JsonParsingError.INVALID_ESCAPE_SEQUENCE?; val = val << 4 + (c > '9' ? (c | 32) - 'a' + 10 : c - '0'); } this.last_string.append_char32(val); continue; default: - return JsonParsingError.INVALID_ESCAPE_SEQUENCE!; + return JsonParsingError.INVALID_ESCAPE_SEQUENCE?; } } return STRING; diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 242718472..ffd220cbc 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -25,6 +25,7 @@ fault IoError FILE_IS_PIPE, FILE_EOF, INCOMPLETE_WRITE, + BUSY, NO_PERMISSION, OUT_OF_SPACE, INVALID_PUSHBACK, @@ -39,6 +40,7 @@ fault IoError NOT_SEEKABLE, NAME_TOO_LONG, WOULD_BLOCK, + DIR_NOT_EMPTY, INTERRUPTED, GENERAL_ERROR, UNKNOWN_ERROR, @@ -55,18 +57,16 @@ macro void print(x) var $Type = $typeof(x); $switch ($Type) $case String: - catch? stdout().print(x); + (void)stdout().print(x); $case ZString: - catch? stdout().print(x.as_str()); + (void)stdout().print(x.as_str()); $case DString: - catch? stdout().print(x.str()); - $case VarString: - catch? stdout().print(x.str()); + (void)stdout().print(x.str()); $default: $if (@convertible(x, String)) - catch? stdout().print((String)x); + (void)stdout().print((String)x); $else - catch? stdout().printf("%s", x); + (void)stdout().printf("%s", x); $endif $endswitch } @@ -76,24 +76,20 @@ macro void printn(x = "") var $Type = $typeof(x); $switch ($Type) $case String: - catch? stdout().printn(x); + (void)stdout().printn(x); $case ZString: - catch? stdout().printn(x.as_str()); + (void)stdout().printn(x.as_str()); $case DString: - catch? stdout().printn(x.str()); - $case VarString: - catch? stdout().printn(x.str()); + (void)stdout().printn(x.str()); $default: $if (@convertible(x, String)) - catch? stdout().printn((String)x); + (void)stdout().printn((String)x); $else - catch? stdout().printfn("%s", x); + (void)stdout().printfn("%s", x); $endif $endswitch } -macro void println(x = "") @deprecated => printn(x); - fn File stdout() { return { libc::stdout() }; diff --git a/lib/std/io/io_file.c3 b/lib/std/io/io_file.c3 index 3d8f67c2f..22bb9545e 100644 --- a/lib/std/io/io_file.c3 +++ b/lib/std/io/io_file.c3 @@ -6,9 +6,9 @@ fn File! open(String filename, String mode) return { .file = os::native_fopen(filename, mode) }; } -fn void! File.open(File* file, String filename, String mode) @deprecated +fn File! open_path(Path path, String mode) { - file.file = os::native_fopen(filename, mode)?; + return { .file = os::native_fopen(path.as_str(), mode) }; } /** @@ -16,7 +16,7 @@ fn void! File.open(File* file, String filename, String mode) @deprecated **/ fn void! File.reopen(File* file, String filename, String mode) { - file.file = os::native_freopen(file.file, filename, mode)?; + file.file = os::native_freopen(file.file, filename, mode)!; } /** @@ -24,7 +24,7 @@ fn void! File.reopen(File* file, String filename, String mode) **/ fn usz! File.seek(File file, isz offset, Seek seek_mode = Seek.SET) { - os::native_fseek(file.file, offset, seek_mode)?; + os::native_fseek(file.file, offset, seek_mode)!; return os::native_ftell(file.file); } @@ -50,7 +50,7 @@ fn void! File.memopen(File* file, char[] data, String mode) */ fn void! File.putc(File *file, char c) { - if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!; + if (!libc::fputc(c, file.file)) return IoError.FILE_EOF?; } /** @@ -63,8 +63,8 @@ fn void! File.close(File *file) @inline switch (libc::errno()) { case errno::ECONNRESET: - case errno::EBADF: return IoError.FILE_NOT_VALID!; - case errno::EINTR: return IoError.INTERRUPTED!; + case errno::EBADF: return IoError.FILE_NOT_VALID?; + case errno::EINTR: return IoError.INTERRUPTED?; case errno::EDQUOT: case errno::EFAULT: case errno::EAGAIN: @@ -72,8 +72,8 @@ fn void! File.close(File *file) @inline case errno::ENETDOWN: case errno::ENETUNREACH: case errno::ENOSPC: - case errno::EIO: return IoError.INCOMPLETE_WRITE!; - default: return IoError.UNKNOWN_ERROR!; + case errno::EIO: return IoError.INCOMPLETE_WRITE?; + default: return IoError.UNKNOWN_ERROR?; } } file.file = null; @@ -111,8 +111,8 @@ fn usz! File.write(File file, char[] buffer) */ fn usz! File.printn(File file, String string) { - usz len = file.print(string)?; - if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!; + usz len = file.print(string)!; + if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR?; return len + 1; } @@ -123,12 +123,10 @@ fn usz! File.printn(File file, String string) fn usz! File.print(File file, String string) { usz len = string.len; - if (len != file.write((char[])string)?) return IoError.UNKNOWN_ERROR!; + if (len != file.write((char[])string)!) return IoError.UNKNOWN_ERROR?; return len; } -fn usz! File.println(File file, String string) @deprecated => file.printn(string); - /** * @param [&in] file * @require file.file `File must be initialized` @@ -159,7 +157,7 @@ fn String File.tgetline(File* file) fn char! File.getc(File* file) { int c = libc::fgetc(file.file); - if (c == -1) return IoError.FILE_EOF!; + if (c == -1) return IoError.FILE_EOF?; return (char)c; } diff --git a/lib/std/io/io_formatter_private.c3 b/lib/std/io/io_formatter_private.c3 index efdf6cddc..8b925b089 100644 --- a/lib/std/io/io_formatter_private.c3 +++ b/lib/std/io/io_formatter_private.c3 @@ -6,17 +6,17 @@ const char[16] XDIGITS_L = "0123456789abcdef"; fn void! Formatter.left_adjust(Formatter* this, usz len) @local { if (!this.flags.left) return; - for (usz l = len; l < this.width; l++) this.out(' ')?; + for (usz l = len; l < this.width; l++) this.out(' ')!; } fn void! Formatter.right_adjust(Formatter* this, usz len) @local { if (this.flags.left) return; - for (usz l = len; l < this.width; l++) this.out(' ')?; + for (usz l = len; l < this.width; l++) this.out(' ')!; } -fn uint128! int_from_variant(variant arg, bool *is_neg) @private +fn uint128! int_from_any(any arg, bool *is_neg) @private { *is_neg = false; if (arg.type.kindof == TypeKind.POINTER) @@ -25,7 +25,7 @@ fn uint128! int_from_variant(variant arg, bool *is_neg) @private } if (arg.type.kindof == TypeKind.DISTINCT) { - return int_from_variant(variant { arg.ptr, arg.type.inner }, is_neg); + return int_from_any(any { arg.ptr, arg.type.inner }, is_neg); } switch (arg) { @@ -63,11 +63,11 @@ fn uint128! int_from_variant(variant arg, bool *is_neg) @private double d = *arg; return (uint128)((*is_neg = d < 0) ? -d : d); default: - return PrintFault.INVALID_ARGUMENT_TYPE!; + return PrintFault.INVALID_ARGUMENT_TYPE?; } } -fn FloatType! float_from_variant(variant arg) @private +fn FloatType! float_from_any(any arg) @private { $if (env::F128_SUPPORT) if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr); @@ -77,7 +77,7 @@ fn FloatType! float_from_variant(variant arg) @private $endif if (arg.type.kindof == TypeKind.DISTINCT) { - return float_from_variant(variant { arg.ptr, arg.type.inner }); + return float_from_any(any { arg.ptr, arg.type.inner }); } switch (arg) { @@ -108,7 +108,7 @@ fn FloatType! float_from_variant(variant arg) @private case double: return (FloatType)*arg; default: - return PrintFault.INVALID_ARGUMENT_TYPE!; + return PrintFault.INVALID_ARGUMENT_TYPE?; } } @@ -141,7 +141,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private usz l = conv::utf8_codepoints(str); uint prec = this.prec; if (this.flags.precision && l < prec) l = prec; - this.right_adjust(' ')?; + this.right_adjust(' ')!; usz index = 0; usz chars = str.len; char* ptr = str.ptr; @@ -150,7 +150,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private char c = ptr[index]; // Break if we have precision set and we ran out... if (c & 0xC0 != 0x80 && this.flags.precision && !prec--) break; - this.out(c)?; + this.out(c)!; index++; } return this.left_adjust(l); @@ -158,7 +158,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private fn void! Formatter.pad(Formatter* this, char c, isz width, isz len) @inline { - for (isz i = len; i < width; i++) this.out(c)?; + for (isz i = len; i < width; i++) this.out(c)!; } fn char* fmt_u(uint128 x, char* s) @@ -170,7 +170,7 @@ fn char* fmt_u(uint128 x, char* s) fn void! Formatter.out_chars(Formatter* this, char[] s) { - foreach (c : s) this.out(c)?; + foreach (c : s) this.out(c)!; } enum FloatFormatting @@ -203,12 +203,12 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub if (!math::is_finite(y)) { // Add padding - if (!this.flags.left) this.pad(' ', this.width, 3 + pl)?; + if (!this.flags.left) this.pad(' ', this.width, 3 + pl)!; String s = this.flags.uppercase ? "INF" : "inf"; if (y != y) this.flags.uppercase ? "NAN" : "nan"; - if (pl) this.out(is_neg ? '-' : '+')?; - this.out_chars(s)?; - if (this.flags.left) this.pad(' ', this.width, 3 + pl)?; + if (pl) this.out(is_neg ? '-' : '+')!; + this.out_chars(s)!; + if (this.flags.left) this.pad(' ', this.width, 3 + pl)!; return; } // Rescale @@ -260,18 +260,18 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub } while (y); isz outlen = s - buf; isz explen = ebuf - estr; - if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; usz l = p && outlen - 2 < p ? p + 2 + explen : outlen + explen; - if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)?; - if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')?; - this.out_chars(this.flags.uppercase ? "0X" : "0x")?; - if (this.flags.zeropad) this.pad('0', this.width, pl + l)?; - this.out_chars(buf[:outlen])?; - this.pad('0', l - outlen - explen, 0)?; - this.out_chars(estr[:explen])?; - if (this.flags.left) this.pad(' ', this.width, pl + l)?; + if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!; + if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!; + this.out_chars(this.flags.uppercase ? "0X" : "0x")!; + if (this.flags.zeropad) this.pad('0', this.width, pl + l)!; + this.out_chars(buf[:outlen])!; + this.pad('0', l - outlen - explen, 0)!; + this.out_chars(estr[:explen])!; + if (this.flags.left) this.pad(' ', this.width, pl + l)!; return; } if (p < 0) p = 6; @@ -427,12 +427,12 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub } } } - if (p > int.max - 1 - (isz)(p || this.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (p > int.max - 1 - (isz)(p || this.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; int l = (int)(1 + p + (isz)(p || this.flags.hash)); char* estr @noinit; if (formatting == FLOAT) { - if (e > int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (e > int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; if (e > 0) l += e; } else @@ -441,13 +441,13 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub while (ebuf - estr < 2) (--estr)[0] = '0'; *--estr = (e < 0 ? '-' : '+'); *--estr = this.flags.uppercase ? 'E' : 'e'; - if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; l += (int)(ebuf - estr); } - if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; - if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)?; - if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')?; - if (this.flags.zeropad) this.pad('0', this.width, pl + l)?; + if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; + if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!; + if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!; + if (this.flags.zeropad) this.pad('0', this.width, pl + l)!; if (formatting == FLOAT) { if (a > r) a = r; @@ -462,16 +462,16 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub case s == buf + 9: *--s = '0'; } - this.out_chars(s[:buf + 9 - s])?; + this.out_chars(s[:buf + 9 - s])!; } - if (p || this.flags.hash) this.out('.')?; + if (p || this.flags.hash) this.out('.')!; for (; d < z && p > 0; d++, p -= 9) { char* s = fmt_u(*d, buf + 9); while (s > buf) *--s = '0'; - this.out_chars(s[:math::min((isz)9, p)])?; + this.out_chars(s[:math::min((isz)9, p)])!; } - this.pad('0', p + 9, 9)?; + this.pad('0', p + 9, 9)!; } else { @@ -486,17 +486,17 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub } else { - this.out(s++[0])?; - if (p > 0 || this.flags.hash) this.out('.')?; + this.out(s++[0])!; + if (p > 0 || this.flags.hash) this.out('.')!; } - this.out_chars(s[:math::min(buf + 9 - s, p)])?; + this.out_chars(s[:math::min(buf + 9 - s, p)])!; p -= buf + 9 - s; } - this.pad('0', p + 18, 18)?; - this.out_chars(estr[:ebuf - estr])?; + this.pad('0', p + 18, 18)!; + this.out_chars(estr[:ebuf - estr])!; } - if (this.flags.left) this.pad(' ', this.width, pl + l)?; + if (this.flags.left) this.pad(' ', this.width, pl + l)!; return; } @@ -515,7 +515,7 @@ fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base char past_10 = (this.flags.uppercase ? 'A' : 'a') - 10; do { - if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; char digit = (char)(value % base); buf[len++] = digit + (digit < 10 ? '0' : past_10); value /= base; @@ -533,12 +533,12 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati if (this.width && this.flags.zeropad && (negative || this.flags.plus || this.flags.space)) this.width--; while (len < this.prec) { - if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; buf[len++] = '0'; } while (this.flags.zeropad && len < this.width) { - if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; buf[len++] = '0'; } } @@ -553,7 +553,7 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati } if (base != 10) { - if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; switch (base) { case 16: @@ -572,13 +572,13 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati switch (true) { case negative: - if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; buf[len++] = '-'; case this.flags.plus: - if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; buf[len++] = '+'; case this.flags.space: - if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; + if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?; buf[len++] = ' '; } if (!len) return; @@ -586,36 +586,36 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati } -fn void! Formatter.ntoa_variant(Formatter* this, variant arg, uint base) @private +fn void! Formatter.ntoa_any(Formatter* this, any arg, uint base) @private { bool is_neg; - uint128 val = int_from_variant(arg, &is_neg)!!; + uint128 val = int_from_any(arg, &is_neg)!!; return this.ntoa(val, is_neg, base) @inline; } -fn void! Formatter.out_char(Formatter* this, variant arg) @private +fn void! Formatter.out_char(Formatter* this, any arg) @private { uint l = 1; // pre padding - this.right_adjust(l)?; + this.right_adjust(l)!; // char output - Char32 c = types::variant_to_int(arg, uint) ?? 0xFFFD; + Char32 c = types::any_to_int(arg, uint) ?? 0xFFFD; switch (true) { case c < 0x7f: - this.out((char)c)?; + this.out((char)c)!; case c < 0x7ff: - this.out((char)(0xC0 | c >> 6))?; - this.out((char)(0x80 | (c & 0x3F)))?; + this.out((char)(0xC0 | c >> 6))!; + this.out((char)(0x80 | (c & 0x3F)))!; case c < 0xffff: - this.out((char)(0xE0 | c >> 12))?; - this.out((char)(0x80 | (c >> 6 & 0x3F)))?; - this.out((char)(0x80 | (c & 0x3F)))?; + this.out((char)(0xE0 | c >> 12))!; + this.out((char)(0x80 | (c >> 6 & 0x3F)))!; + this.out((char)(0x80 | (c & 0x3F)))!; default: - this.out((char)(0xF0 | c >> 18))?; - this.out((char)(0x80 | (c >> 12 & 0x3F)))?; - this.out((char)(0x80 | (c >> 6 & 0x3F)))?; - this.out((char)(0x80 | (c & 0x3F)))?; + this.out((char)(0xF0 | c >> 18))!; + this.out((char)(0x80 | (c >> 12 & 0x3F)))!; + this.out((char)(0x80 | (c >> 6 & 0x3F)))!; + this.out((char)(0x80 | (c & 0x3F)))!; } return this.left_adjust(l); } @@ -630,11 +630,11 @@ fn void! Formatter.out_reverse(Formatter* this, char[] buf) @private { for (usz i = len; i < this.width; i++) { - this.out(' ')?; + this.out(' ')!; } } // reverse string - while (len) this.out(buf[--len])?; + while (len) this.out(buf[--len])!; // append pad spaces up to given width return this.left_adjust(this.idx - buffer_start_idx); @@ -643,25 +643,25 @@ fn void! Formatter.out_reverse(Formatter* this, char[] buf) @private fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private { usz val = ++(*index_ptr); - if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT!; + if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?; } -fn variant! next_variant(variant* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private +fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private { - if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!; + if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?; return args_ptr[(*arg_index_ptr)++]; } fn int! printf_parse_format_field( - variant* args_ptr, usz args_len, usz* args_index_ptr, + any* args_ptr, usz args_len, usz* args_index_ptr, char* format_ptr, usz format_len, usz* index_ptr) @inline @private { char c = format_ptr[*index_ptr]; if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr); if (c != '*') return 0; - printf_advance_format(format_len, index_ptr)?; - variant val = next_variant(args_ptr, args_len, args_index_ptr)?; - if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG!; - uint! intval = types::variant_to_int(val, int); - return intval ?? FormattingFault.INVALID_WIDTH_ARG!; + printf_advance_format(format_len, index_ptr)!; + any val = next_any(args_ptr, args_len, args_index_ptr)!; + if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?; + uint! intval = types::any_to_int(val, int); + return intval ?? FormattingFault.INVALID_WIDTH_ARG?; } diff --git a/lib/std/io/io_printf.c3 b/lib/std/io/io_printf.c3 index 5080b492d..32bc43196 100644 --- a/lib/std/io/io_printf.c3 +++ b/lib/std/io/io_printf.c3 @@ -33,39 +33,21 @@ fn usz! printf(String format, args...) @maydiscard return formatter.vprintf(format, args); } -define printfln = printfn; - fn usz! printfn(String format, args...) @maydiscard { Formatter formatter; formatter.init(&out_putchar_fn); - usz len = formatter.vprintf(format, args)?; + usz len = formatter.vprintf(format, args)!; putchar('\n'); return len + 1; } -fn usz! VarString.printf(VarString* str, String format, args...) @maydiscard -{ - Formatter formatter; - formatter.init(&out_string_append_fn, str); - return formatter.vprintf(format, args); -} - -fn usz! VarString.printfn(VarString* str, String format, args...) @maydiscard -{ - Formatter formatter; - formatter.init(&out_string_append_fn, str); - usz len = formatter.vprintf(format, args)?; - str.append('\n'); - return len + 1; -} - fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard { Formatter formatter; BufferData data = { .buffer = buffer }; formatter.init(&out_buffer_fn, &data); - usz size = formatter.vprintf(format, args)?; + usz size = formatter.vprintf(format, args)!; return buffer[:data.written]; } @@ -73,15 +55,15 @@ fn usz! File.printf(File file, String format, args...) @maydiscard { Formatter formatter; formatter.init(&out_fputchar_fn, &file); - return formatter.vprintf(format, args)?; + return formatter.vprintf(format, args)!; } fn usz! File.printfn(File file, String format, args...) @maydiscard { Formatter formatter; formatter.init(&out_fputchar_fn, &file); - usz len = formatter.vprintf(format, args)?; - file.putc('\n')?; + usz len = formatter.vprintf(format, args)!; + file.putc('\n')!; file.flush(); return len + 1; } @@ -157,10 +139,10 @@ static initialize @priority(101) fn void! Formatter.out(Formatter* this, char c) @private { - this.out_fn(c, this.data)?; + this.out_fn(c, this.data)!; } -macro bool! Formatter.print_with_function(Formatter* this, variant arg) +macro bool! Formatter.print_with_function(Formatter* this, any arg) { if (try to_format = toformat_functions.get(arg.type)) { @@ -173,7 +155,7 @@ macro bool! Formatter.print_with_function(Formatter* this, variant arg) this.width = old_width; this.prec = old_prec; } - to_format(arg.ptr, this)?; + to_format(arg.ptr, this)!; return true; } if (try to_string = tostring_functions.get(arg.type)) @@ -189,96 +171,92 @@ macro bool! Formatter.print_with_function(Formatter* this, variant arg) } @pool() { - this.out_substr(to_string(arg.ptr, mem::temp()))?; + this.out_substr(to_string(arg.ptr, mem::temp()))!; return true; }; } return false; } -fn void! Formatter.out_str(Formatter* this, variant arg) @private +fn void! Formatter.out_str(Formatter* this, any arg) @private { switch (arg.type.kindof) { case TYPEID: - return this.out_substr(""); + return this.out_substr("typeid"); case VOID: return this.out_substr("void"); - case ANYERR: + case ANYFAULT: case FAULT: - return this.out_substr((*(anyerr*)arg.ptr).nameof); - case VARIANT: - return this.out_str(*(variant*)arg); + return this.out_substr((*(anyfault*)arg.ptr).nameof); + case ANY: + return this.out_str(*(any*)arg); case ENUM: - if (this.print_with_function(arg)?) return; - return this.out_substr(arg.type.names[types::variant_to_int(arg, usz)!!]); + if (this.print_with_function(arg)!) return; + return this.out_substr(arg.type.names[types::any_to_int(arg, usz)!!]); case STRUCT: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; return this.out_substr(""); case UNION: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; return this.out_substr(""); case BITSTRUCT: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; return this.out_substr(""); case FUNC: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; return this.out_substr(""); case OPTIONAL: unreachable(); case DISTINCT: - if (this.print_with_function(arg)?) return; - if (arg.type == VarString.typeid) - { - return this.out_substr(((VarString*)arg).str()); - } + if (this.print_with_function(arg)!) return; if (arg.type == DString.typeid) { return this.out_substr(((DString*)arg).str()); } - return this.out_str(variant { arg.ptr, arg.type.inner }); + return this.out_str(any { arg.ptr, arg.type.inner }); case POINTER: - if (this.print_with_function(arg)?) return; - return this.ntoa_variant(arg, 16); + if (this.print_with_function(arg)!) return; + return this.ntoa_any(arg, 16); case SIGNED_INT: case UNSIGNED_INT: - return this.ntoa_variant(arg, 10); + return this.ntoa_any(arg, 10); case FLOAT: - return this.ftoa(float_from_variant(arg)!!); + return this.ftoa(float_from_any(arg)!!); case ARRAY: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; // this is SomeType[*] so grab the "SomeType" typeid inner = arg.type.inner; usz size = inner.sizeof; usz len = arg.type.len; // Pretend this is a String void* ptr = (void*)arg.ptr; - this.out('[')?; + this.out('[')!; for (usz i = 0; i < len; i++) { - if (i != 0) this.out_substr(", ")?; - this.out_str(variant { ptr, inner })?; + if (i != 0) this.out_substr(", ")!; + this.out_str(any { ptr, inner })!; ptr += size; } return this.out(']'); case VECTOR: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; // this is SomeType[*] so grab the "SomeType" typeid inner = arg.type.inner; usz size = inner.sizeof; usz len = arg.type.len; // Pretend this is a String void* ptr = (void*)arg.ptr; - this.out_substr("[<")?; + this.out_substr("[<")!; for (usz i = 0; i < len; i++) { - if (i != 0) this.out_substr(", ")?; - this.out_str(variant { ptr, inner })?; + if (i != 0) this.out_substr(", ")!; + this.out_str(any { ptr, inner })!; ptr += size; } return this.out_substr(">]"); case SUBARRAY: - if (this.print_with_function(arg)?) return; + if (this.print_with_function(arg)!) return; // this is SomeType[] so grab the "SomeType" typeid inner = arg.type.inner; if (inner == char.typeid) @@ -290,14 +268,14 @@ fn void! Formatter.out_str(Formatter* this, variant arg) @private String* temp = (void*)arg.ptr; void* ptr = (void*)temp.ptr; usz len = temp.len; - this.out('[')?; + this.out('[')!; for (usz i = 0; i < len; i++) { - if (i != 0) this.out_substr(", ")?; - this.out_str(variant { ptr, inner })?; + if (i != 0) this.out_substr(", ")!; + this.out_str(any { ptr, inner })!; ptr += size; } - this.out(']')?; + this.out(']')!; case BOOL: if (*(bool*)arg.ptr) { @@ -308,7 +286,13 @@ fn void! Formatter.out_str(Formatter* this, variant arg) @private return this.out_substr("false"); } default: - if (this.print_with_function(arg)?) return; + switch (arg) + { + case Object: + arg.to_format(this)!; + return; + } + if (this.print_with_function(arg)!) return; return this.out_substr("Invalid type"); } } @@ -318,7 +302,7 @@ fn void! Formatter.out_str(Formatter* this, variant arg) @private fn void! out_buffer_fn(char c, void *data) @private { BufferData *buffer_data = data; - if (buffer_data.written >= buffer_data.buffer.len) return PrintFault.BUFFER_EXCEEDED!; + if (buffer_data.written >= buffer_data.buffer.len) return PrintFault.BUFFER_EXCEEDED?; buffer_data.buffer[buffer_data.written++] = c; } @@ -334,16 +318,9 @@ fn void! out_putchar_fn(char c, void* data @unused) @private fn void! out_fputchar_fn(char c, void* data) @private { File* f = data; - f.putc(c)?; + f.putc(c)!; } -fn void! out_string_append_fn(char c, void* data) @private -{ - VarString* s = data; - s.append_char(c); -} - - struct BufferData @private { char[] buffer; @@ -351,7 +328,7 @@ struct BufferData @private } -fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) +fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys) { if (!this.out_fn) { @@ -367,15 +344,15 @@ fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) if (c != '%') { // no - this.out(c)?; + this.out(c)!; continue; } i++; - if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING!; + if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING?; c = format[i]; if (c == '%') { - this.out(c)?; + this.out(c)!; continue; } // evaluate flags @@ -391,11 +368,11 @@ fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) case '#': this.flags.hash = true; default: break FLAG_EVAL; } - if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!; + if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?; c = format[i]; } // evaluate width field - int w = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?; + int w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!; c = format[i]; if (w < 0) { @@ -408,16 +385,16 @@ fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) if (c == '.') { this.flags.precision = true; - if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!; - int prec = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?; + if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?; + int prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!; this.prec = prec < 0 ? 0 : prec; c = format[i]; } // evaluate specifier uint base = 0; - if (variant_index >= variants.len) return PrintFault.MISSING_ARG!; - variant current = variants[variant_index++]; + if (variant_index >= anys.len) return PrintFault.MISSING_ARG?; + any current = anys[variant_index++]; switch (c) { case 'd': @@ -442,38 +419,38 @@ fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) this.flags.uppercase = true; nextcase; case 'a': - this.atoa(float_from_variant(current)!!)?; + this.atoa(float_from_any(current)!!)!; continue; case 'F' : this.flags.uppercase = true; nextcase; case 'f': - this.ftoa(float_from_variant(current)!!)?; + this.ftoa(float_from_any(current)!!)!; continue; case 'E': this.flags.uppercase = true; nextcase; case 'e': - this.etoa(float_from_variant(current)!!)?; + this.etoa(float_from_any(current)!!)!; continue; case 'G': this.flags.uppercase = true; nextcase; case 'g': - this.gtoa(float_from_variant(current)!!)?; + this.gtoa(float_from_any(current)!!)!; continue; case 'c': - this.out_char(current)?; + this.out_char(current)!; continue; case 's': - this.out_str(current)?; + this.out_str(current)!; continue; case 'p': this.flags.zeropad = true; this.flags.hash = true; base = 16; default: - return PrintFault.INVALID_FORMAT_STRING!; + return PrintFault.INVALID_FORMAT_STRING?; } if (base != 10) { @@ -484,9 +461,9 @@ fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants) if (this.flags.precision) this.flags.zeropad = false; bool is_neg; - uint128 v = int_from_variant(current, &is_neg)!!; + uint128 v = int_from_any(current, &is_neg)!!; - this.ntoa(v, is_neg, base)?; + this.ntoa(v, is_neg, base)!; } // termination // out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); diff --git a/lib/std/io/io_stream.c3 b/lib/std/io/io_stream.c3 index 3feec3b57..689ff8839 100644 --- a/lib/std/io/io_stream.c3 +++ b/lib/std/io/io_stream.c3 @@ -60,7 +60,7 @@ fn void! Stream.close(Stream* s) @inline @maydiscard fn usz! Stream.seek(Stream* s, isz offset, Seek seek) @inline { if (SeekStreamFn func = s.fns.seek_fn) return func(s, offset, seek); - return IoError.NOT_SEEKABLE!; + return IoError.NOT_SEEKABLE?; } fn usz! Stream.available(Stream* s) @inline @@ -68,12 +68,12 @@ fn usz! Stream.available(Stream* s) @inline if (AvailableStreamFn func = s.fns.available_fn) return func(s); if (SeekStreamFn func = s.fns.seek_fn) { - usz curr = func(s, 0, Seek.CURSOR)?; - usz len = func(s, 0, Seek.END)?; - func(s, curr, Seek.SET)?; + usz curr = func(s, 0, Seek.CURSOR)!; + usz len = func(s, 0, Seek.END)!; + func(s, curr, Seek.SET)!; return len - curr; } - return IoError.NOT_SEEKABLE!; + return IoError.NOT_SEEKABLE?; } fn usz! Stream.read(Stream* s, char[] buffer) @@ -88,19 +88,19 @@ fn usz! Stream.read(Stream* s, char[] buffer) if (catch err = c) { case IoError.EOF: return len; - default: return err!; + default: return err?; } *cptr = c; len++; } } - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn char! Stream.read_byte(Stream* s) @inline { if (ReadByteStreamFn func = s.fns.read_byte_fn) return func(s); - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn usz! Stream.write(Stream* s, char[] bytes) @inline @@ -108,34 +108,34 @@ fn usz! Stream.write(Stream* s, char[] bytes) @inline if (WriteStreamFn func = s.fns.write_fn) return func(s, bytes); if (WriteByteStreamFn func = s.fns.write_byte_fn) { - foreach (c : bytes) func(s, c)?; + foreach (c : bytes) func(s, c)!; return bytes.len; } - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn void! Stream.write_byte(Stream* s, char b) @inline { if (WriteByteStreamFn func = s.fns.write_byte_fn) return func(s, b); - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn usz! Stream.write_to(Stream* s, Stream* to) @inline { if (WriteToStreamFn func = s.fns.write_stream_fn) return func(s, to); - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn usz! Stream.read_from(Stream* s, Stream* from) @inline { if (ReadFromStreamFn func = s.fns.read_stream_fn) return func(s, from); - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn void! Stream.flush(Stream* s) @inline @maydiscard { if (FlushStreamFn func = s.fns.flush_fn) return func(s); - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } fn usz! Stream.len(Stream* s) @inline @@ -143,12 +143,12 @@ fn usz! Stream.len(Stream* s) @inline if (LenStreamFn func = s.fns.len_fn) return func(s); if (SeekStreamFn func = s.fns.seek_fn) { - usz curr = func(s, 0, Seek.CURSOR)?; - usz len = func(s, 0, Seek.END)?; - func(s, curr, Seek.SET)?; + usz curr = func(s, 0, Seek.CURSOR)!; + usz len = func(s, 0, Seek.END)!; + func(s, curr, Seek.SET)!; return len; } - return IoError.NOT_SEEKABLE!; + return IoError.NOT_SEEKABLE?; } fn void! Stream.pushback_byte(Stream* s) @inline @@ -156,13 +156,13 @@ fn void! Stream.pushback_byte(Stream* s) @inline if (PushbackByteStreamFn func = s.fns.pushback_byte_fn) return func(s); if (SeekStreamFn func = s.fns.seek_fn) { - func(s, -1, CURSOR)?; + func(s, -1, CURSOR)!; return; } - return IoError.UNSUPPORTED_OPERATION!; + return IoError.UNSUPPORTED_OPERATION?; } -fn void! Stream.write_string(Stream* s, String str) @inline => (void)(s.write((char[])str)?); +fn void! Stream.write_string(Stream* s, String str) @inline => (void)(s.write((char[])str)!); fn usz! Stream.copy_to(Stream* s, Stream* dst, char[] buffer = {}) { @@ -195,11 +195,11 @@ macro usz! copy_through_buffer(Stream* s, Stream* dst, char[] buffer) @local if (catch err = len) { case IoError.EOF: return total_copied; - default: return err!; + default: return err?; } if (!len) return total_copied; - usz written = dst.write(buffer[:len])?; + usz written = dst.write(buffer[:len])!; total_copied += len; - if (written != len) return IoError.INCOMPLETE_WRITE!; + if (written != len) return IoError.INCOMPLETE_WRITE?; } } diff --git a/lib/std/io/os/chdir.c3 b/lib/std/io/os/chdir.c3 index b5ce77f47..b7bba0476 100644 --- a/lib/std/io/os/chdir.c3 +++ b/lib/std/io/os/chdir.c3 @@ -3,41 +3,42 @@ import libc; $switch - $case !env::COMPILER_LIBC_AVAILABLE: + +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): + +macro void! native_chdir(Path p) +{ + if (posix::chdir(p.as_zstr())) + { + switch (libc::errno()) + { + case errno::EACCES: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::ENOTDIR: return IoError.FILE_NOT_DIR?; + case errno::ENOENT: return IoError.FILE_NOT_FOUND?; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + default: return IoError.GENERAL_ERROR?; + } + } +} + +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): + +macro void! native_chdir(Path path) +{ + @pool() + { + // TODO improve with better error handling. + if (win32::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return; + }; + return IoError.GENERAL_ERROR?; +} + +$default: fn void! native_chdir(Path path) { unreachable("'getcwd' not available"); } - $case env::os_is_win32(): - -macro void! native_chdir(Path path) -{ - @pool() - { - if (files::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return; - }; - return IoError.GENERAL_ERROR!; -} - - $default: - -extern fn int _chdir(ZString) @extern("chdir"); -macro void! native_chdir(Path p) -{ - if (_chdir((ZString)p.as_str())) - { - switch (libc::errno()) - { - case errno::EACCES: return IoError.NO_PERMISSION!; - case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG!; - case errno::ENOTDIR: return IoError.FILE_NOT_DIR!; - case errno::ENOENT: return IoError.FILE_NOT_FOUND!; - case errno::ELOOP: return IoError.SYMLINK_FAILED!; - default: return IoError.GENERAL_ERROR!; - } - } -} - $endswitch \ No newline at end of file diff --git a/lib/std/io/os/file.c3 b/lib/std/io/os/file.c3 index 8703bb879..d3df2ca7b 100644 --- a/lib/std/io/os/file.c3 +++ b/lib/std/io/os/file.c3 @@ -45,11 +45,11 @@ $else @pool() { $if (env::os_is_win32()) - void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())?; + void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())!; $else void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy()); $endif - return file ?: file_open_errno()!; + return file ?: file_open_errno()?; }; $endif } @@ -67,11 +67,11 @@ $else @pool() { $if (env::os_is_win32()) - file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)?; + file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)!; $else file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file); $endif - return file ?: file_open_errno()!; + return file ?: file_open_errno()?; }; $endif } @@ -87,7 +87,7 @@ $else $else bool success = libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode) == 0; $endif - if (!success) return file_seek_errno()!; + if (!success) return file_seek_errno()?; $endif } @@ -99,10 +99,10 @@ $if (!env::COMPILER_LIBC_AVAILABLE) $else $if (env::os_is_win32()) long index = _ftelli64(file); - return index >= 0 ? index : file_seek_errno()!; + return index >= 0 ? index : file_seek_errno()?; $else SeekIndex index = libc::ftell(file); - return index >= 0 ? index : file_seek_errno()!; + return index >= 0 ? index : file_seek_errno()?; $endif $endif } @@ -127,7 +127,7 @@ $else $endif } -macro anyerr file_open_errno() @local +macro anyfault file_open_errno() @local { switch (libc::errno()) { @@ -155,7 +155,7 @@ macro anyerr file_open_errno() @local } } -macro anyerr file_seek_errno() @local +macro anyfault file_seek_errno() @local { switch (libc::errno()) { diff --git a/lib/std/io/os/fileinfo_darwin.c3 b/lib/std/io/os/fileinfo_darwin.c3 index 1b751568a..701151118 100644 --- a/lib/std/io/os/fileinfo_darwin.c3 +++ b/lib/std/io/os/fileinfo_darwin.c3 @@ -44,26 +44,26 @@ const S_IFSOCK = 0o140000; // socket fn usz! native_file_size(String path) { Darwin64Stat stat; - read_stat(&stat, path)?; + read_stat(&stat, path)!; return stat.st_size; } fn bool native_file_or_dir_exists(String path) { Darwin64Stat stat; - return try? read_stat(&stat, path); + return @ok(read_stat(&stat, path)); } fn bool native_is_file(String path) { Darwin64Stat stat; - return try? read_stat(&stat, path) && (stat.st_mode & S_IFREG); + return @ok(read_stat(&stat, path)) && stat.st_mode & S_IFREG; } fn bool native_is_dir(String path) { Darwin64Stat stat; - return try? read_stat(&stat, path) && (stat.st_mode & S_IFDIR); + return @ok(read_stat(&stat, path)) && stat.st_mode & S_IFDIR; } fn void! read_stat(Darwin64Stat* stat, String path) @local @@ -76,25 +76,25 @@ fn void! read_stat(Darwin64Stat* stat, String path) @local switch (libc::errno()) { case errno::EBADF: - return IoError.FILE_NOT_VALID!; + return IoError.FILE_NOT_VALID?; case errno::EFAULT: unreachable("Invalid stat"); case errno::EIO: - return IoError.GENERAL_ERROR!; + return IoError.GENERAL_ERROR?; case errno::EACCES: - return IoError.NO_PERMISSION!; + return IoError.NO_PERMISSION?; case errno::ELOOP: - return IoError.NO_PERMISSION!; + return IoError.NO_PERMISSION?; case errno::ENAMETOOLONG: - return IoError.NAME_TOO_LONG!; + return IoError.NAME_TOO_LONG?; case errno::ENOENT: - return IoError.FILE_NOT_FOUND!; + return IoError.FILE_NOT_FOUND?; case errno::ENOTDIR: - return IoError.FILE_NOT_DIR!; + return IoError.FILE_NOT_DIR?; case errno::EOVERFLOW: - return IoError.GENERAL_ERROR!; + return IoError.GENERAL_ERROR?; default: - return IoError.UNKNOWN_ERROR!; + return IoError.UNKNOWN_ERROR?; } } }; diff --git a/lib/std/io/os/fileinfo_other.c3 b/lib/std/io/os/fileinfo_other.c3 index a61c5be55..b87803902 100644 --- a/lib/std/io/os/fileinfo_other.c3 +++ b/lib/std/io/os/fileinfo_other.c3 @@ -17,6 +17,7 @@ $if (env::COMPILER_LIBC_AVAILABLE) extern fn void* opendir(ZString); extern fn void closedir(void*); +extern fn int remove(ZString); const DT_UNKNOWN = 0; const DT_FIFO = 1; @@ -34,7 +35,7 @@ fn PathList! native_readdir(Path dir, bool no_dirs, bool no_symlinks, String mas list.init(.using = using); void* directory = opendir(dir.as_str() ? dir.as_zstr() : (ZString)"."); defer if (directory) closedir(directory); - if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)!; + if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?; NativeDirentry* entry; while ((entry = readdir(directory))) { @@ -48,6 +49,37 @@ fn PathList! native_readdir(Path dir, bool no_dirs, bool no_symlinks, String mas return list; } +/** + * @require dir.as_str() + **/ +fn void! native_rmtree(Path dir) +{ + void* directory = opendir(dir.as_zstr()); + defer if (directory) closedir(directory); + if (!directory) return path::is_dir(dir) ? IoError.CANNOT_READ_DIR? : IoError.FILE_NOT_DIR?; + NativeDirentry* entry; + while ((entry = readdir(directory))) + { + @pool() + { + String name = ((ZString)&entry.name).as_str(); + if (!name || name == "." || name == "..") continue; + Path new_path = dir.tappend(name)!; + if (entry.type == DT_DIR) + { + native_rmtree(new_path)!; + continue; + } + if (remove(new_path.as_zstr())) + { + // TODO improve + return IoError.GENERAL_ERROR?; + } + }; + } + os::native_rmdir(dir)!; +} + $endif $endif @@ -56,9 +88,9 @@ $if (!env::os_is_darwin() && !env::os_is_win32()) fn usz! native_file_size(String path) { - File f = file::open(path, "r")?; + File f = file::open(path, "r")!; defer (void)f.close(); - return f.seek(0, Seek.END)?; + return f.seek(0, Seek.END)!; } $if (env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE) @@ -75,7 +107,7 @@ fn bool native_is_file(String path) { File! f = file::open(path, "r"); defer (void)f.close(); - return try? f; + return @ok(f); } fn bool native_is_dir(String path) @@ -106,7 +138,7 @@ $endif $switch (env::OS_TYPE) $case IOS: -$case MACOSX: +$case MACOS: $case TVOS: $case WATCHOS: diff --git a/lib/std/io/os/fileinfo_win32.c3 b/lib/std/io/os/fileinfo_win32.c3 index 120428dbd..001dba7d3 100644 --- a/lib/std/io/os/fileinfo_win32.c3 +++ b/lib/std/io/os/fileinfo_win32.c3 @@ -1,15 +1,38 @@ module std::io::file::os; -import std::os::win32::files; +import std::os::win32; $if (env::os_is_win32()) +const Win32_DWORD FILE_ATTRIBUTE_READONLY = 0x01; +const Win32_DWORD FILE_ATTRIBUTE_HIDDEN = 0x02; +const Win32_DWORD FILE_ATTRIBUTE_SYSTEM = 0x04; +const Win32_DWORD FILE_ATTRIBUTE_DIRECTORY = 0x10; +const Win32_DWORD FILE_ATTRIBUTE_ARCHIVE = 0x20; +const Win32_DWORD FILE_ATTRIBUTE_DEVICE = 0x40; +const Win32_DWORD FILE_ATTRIBUTE_NORMAL = 0x80; +const Win32_DWORD FILE_ATTRIBUTE_TEMPORARY = 0x100; +const Win32_DWORD FILE_ATTRIBUTE_SPARSE_FILE = 0x200; +const Win32_DWORD FILE_ATTRIBUTE_REPARSE_POINT = 0x400; +const Win32_DWORD FILE_ATTRIBUTE_COMPRESSED = 0x800; +const Win32_DWORD FILE_ATTRIBUTE_OFFLINE = 0x1000; +const Win32_DWORD FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000; +const Win32_DWORD FILE_ATTRIBUTE_ENCRYPTED = 0x4000; +const Win32_DWORD FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000; +const Win32_DWORD FILE_ATTRIBUTE_VIRTUAL = 0x10000; +const Win32_DWORD FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000; +const Win32_DWORD FILE_ATTRIBUTE_EA = 0x40000; +const Win32_DWORD FILE_ATTRIBUTE_PINNED = 0x80000; +const Win32_DWORD FILE_ATTRIBUTE_UNPINNED = 0x100000; +const Win32_DWORD FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000; +const Win32_DWORD FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000; + fn usz! native_file_size(String path) { @pool() { - Char16[] path16 = path.to_temp_utf16()?; + Char16[] path16 = path.to_temp_utf16()!; Win32_FILE_ATTRIBUTE_DATA data; - files::win32_GetFileAttributesExW(path16, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data); + win32::win32_GetFileAttributesExW(path16, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data); Win32_LARGE_INTEGER size; size.lowPart = data.nFileSizeLow; size.highPart = data.nFileSizeHigh; @@ -21,7 +44,7 @@ fn bool native_file_or_dir_exists(String path) { @pool() { - return (bool)files::win32_PathFileExistsW(path.to_temp_utf16()) ?? false; + return (bool)win32::win32_PathFileExistsW(path.to_temp_utf16()) ?? false; }; } @@ -30,7 +53,7 @@ fn bool native_is_file(String path) { File! f = file::open(path, "r"); defer (void)f.close(); - return try? f; + return @ok(f); } fn bool native_is_dir(String path) @@ -38,14 +61,41 @@ fn bool native_is_dir(String path) return native_file_or_dir_exists(path) && !native_is_file(path); } +fn void! native_rmtree(Path path) +{ + Win32_WIN32_FIND_DATAW find_data; + + String s = path.as_str().tconcat("\\*"); + Win32_HANDLE find = win32::win32_FindFirstFileW(s.to_utf16(mem::temp()), &find_data)!; + + if (find == win32::INVALID_HANDLE_VALUE) return IoError.CANNOT_READ_DIR?; + + defer win32::win32_FindClose(find); + do + { + String filename = string::from_zutf16(&find_data.cFileName, mem::temp())!; + if (filename == "." || filename == "..") continue; + Path file_path = path.tappend(filename)!; + if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + native_rmtree(file_path)!; + } + else + { + win32::win32_DeleteFileW(file_path.as_str().to_utf16(mem::temp())); + } + } while (win32::win32_FindNextFileW(find, &find_data) != 0); + os::native_rmdir(path)!; +} + fn Path! native_temp_directory(Allocator* using = mem::heap()) { @stack_mem(256; Allocator* mem) { - Win32_DWORD len = files::win32_GetTempPathW(0, null); - if (!len) return IoError.GENERAL_ERROR!; + Win32_DWORD len = win32::win32_GetTempPathW(0, null); + if (!len) return IoError.GENERAL_ERROR?; Char16[] buff = malloc(Char16, len + 1, .using = mem); - if (!files::win32_GetTempPathW(len, buff)) return IoError.GENERAL_ERROR!; + if (!win32::win32_GetTempPathW(len, buff)) return IoError.GENERAL_ERROR?; return path::new(string::from_utf16(buff[:len], .using = mem), using); }; } diff --git a/lib/std/io/os/getcwd.c3 b/lib/std/io/os/getcwd.c3 index fd23aa42f..4f0240f2e 100644 --- a/lib/std/io/os/getcwd.c3 +++ b/lib/std/io/os/getcwd.c3 @@ -2,53 +2,50 @@ module std::io::os; import libc; $switch -$case !env::COMPILER_LIBC_AVAILABLE: -fn String! getcwd(Allocator* using = mem::heap()) -{ - unreachable("'getcwd' not available"); -} - -$case env::os_is_win32(): - -extern fn Char16* _wgetcwd(Char16* buffer, int maxlen); -extern fn usz wcslen(Char16* str); +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): macro String! getcwd(Allocator* using = mem::heap()) { const DEFAULT_BUFFER = 256; Char16[DEFAULT_BUFFER] buffer; - Char16 *res = _wgetcwd(&buffer, DEFAULT_BUFFER); + Char16 *res = win32::_wgetcwd(&buffer, DEFAULT_BUFFER); bool free = false; defer if (free) libc::free(res); if (!res) { - if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR!; - res = _wgetcwd(null, 0); + if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; + res = win32::_wgetcwd(null, 0); free = true; } - Char16[] str16 = res[:wcslen(res)]; - return str::utf16to8(str16, using); + Char16[] str16 = res[:win32::wcslen(res)]; + return string::from_utf16(str16, using); } -$default: +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): -extern fn ZString _getcwd(char* pwd, usz len) @extern("getcwd"); macro String! getcwd(Allocator* using = mem::heap()) { const usz DEFAULT_BUFFER = 256; char[DEFAULT_BUFFER] buffer; - ZString res = _getcwd(&buffer, DEFAULT_BUFFER); + ZString res = posix::getcwd(&buffer, DEFAULT_BUFFER); bool free = false; if (!res) { // Improve error - if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR!; - res = _getcwd(null, 0); + if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; + res = posix::getcwd(null, 0); free = true; } defer if (free) libc::free((void*)res); return res.copy(using); } +$default: + +fn String! getcwd(Allocator* using = mem::heap()) +{ + unreachable("'getcwd' not available"); +} + $endswitch \ No newline at end of file diff --git a/lib/std/io/os/mkdir.c3 b/lib/std/io/os/mkdir.c3 new file mode 100644 index 000000000..7b65813fb --- /dev/null +++ b/lib/std/io/os/mkdir.c3 @@ -0,0 +1,63 @@ +module std::io::os; +import libc; +import std::io::path; +import std::os::win32; +import std::os::posix; + +$switch + $case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): + +macro bool! native_mkdir(Path path, MkdirPermissions permissions) +{ + if (!posix::mkdir(path.as_zstr(), permissions == NORMAL ? 0o777 : 0o700)) return true; + switch (libc::errno()) + { + case errno::EACCES: + case errno::EPERM: + case errno::EROFS: + case errno::EFAULT: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::EDQUOT: + case errno::ENOSPC: return IoError.OUT_OF_SPACE?; + case errno::EISDIR: + case errno::EEXIST: return false; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + case errno::ENOTDIR: return IoError.FILE_NOT_FOUND?; + default: return IoError.GENERAL_ERROR?; + } +} + + $case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): + +macro bool! native_mkdir(Path path, MkdirPermissions permissions) +{ + @pool() + { + // TODO security attributes + if (win32::win32_CreateDirectoryW(path.as_str().to_temp_utf16()!!, null)) return true; + switch (win32::win32_GetLastError()) + { + case win32::ERROR_ACCESS_DENIED: + return IoError.NO_PERMISSION?; + case win32::ERROR_DISK_FULL: + return IoError.OUT_OF_SPACE?; + case win32::ERROR_ALREADY_EXISTS: + return false; + case win32::ERROR_PATH_NOT_FOUND: + return IoError.FILE_NOT_FOUND?; + default: + return IoError.GENERAL_ERROR?; + } + }; +} + + $default: + +fn bool! native_mkdir(Path path, MkdirPermissions permissions) +{ + unreachable("'mkdir' not available"); + return false; +} + + +$endswitch \ No newline at end of file diff --git a/lib/std/io/os/rmdir.c3 b/lib/std/io/os/rmdir.c3 new file mode 100644 index 000000000..0aa3f4d19 --- /dev/null +++ b/lib/std/io/os/rmdir.c3 @@ -0,0 +1,61 @@ +module std::io::os; +import libc; +import std::io::path; +import std::os::win32; +import std::os::posix; + +$switch + +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): + +macro bool! native_rmdir(Path path) +{ + if (!posix::rmdir(path.as_zstr())) return true; + switch (libc::errno()) + { + case errno::EBUSY: return IoError.BUSY?; + case errno::EACCES: + case errno::EPERM: + case errno::EROFS: + case errno::EFAULT: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::ENOTDIR: + case errno::ENOENT: return false; + case errno::ENOTEMPTY: return IoError.DIR_NOT_EMPTY?; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + default: return IoError.GENERAL_ERROR?; + } +} + +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): + +macro bool! native_rmdir(Path path) +{ + @pool() + { + if (win32::win32_RemoveDirectoryW(path.as_str().to_temp_utf16()!!)) return true; + switch (win32::win32_GetLastError()) + { + case win32::ERROR_ACCESS_DENIED: + return IoError.NO_PERMISSION?; + case win32::ERROR_CURRENT_DIRECTORY: + return IoError.BUSY?; + case win32::ERROR_DIR_NOT_EMPTY: + return IoError.DIR_NOT_EMPTY?; + case win32::ERROR_DIRECTORY: + case win32::ERROR_PATH_NOT_FOUND: + return false; + default: + return IoError.GENERAL_ERROR?; + } + }; +} + +$default: + +fn bool! native_rmdir(Path path) +{ + unreachable("'rmdir' not available"); +} + +$endswitch \ No newline at end of file diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 20cac6977..099d0d066 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -58,6 +58,51 @@ macro bool is_win32_separator(char c) return c == '/' || c == '\\'; } +fn Path[]! ls(Path path) +{ + unreachable(); +} + +enum MkdirPermissions +{ + NORMAL, + USER_ONLY, + USER_AND_ADMIN +} + + + +fn bool! mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL) +{ + if (!path.path_string.len) return PathResult.INVALID_PATH?; + if (is_dir(path)) return false; + if (exists(path)) return IoError.FILE_NOT_DIR?; + + if (recursive) + { + if (try parent = path.parent()) mkdir(parent, true, permissions)!; + } + if (!is_dir(path.parent()) ?? false) return IoError.CANNOT_READ_DIR?; + + return os::native_mkdir(path, permissions); +} + +fn bool! rmdir(Path path) +{ + if (!path.path_string.len) return PathResult.INVALID_PATH?; + return os::native_rmdir(path); +} + +fn void! rmtree(Path path) +{ + if (!path.path_string.len) return PathResult.INVALID_PATH?; +$if ($defined(os::native_rmtree)) + return os::native_rmtree(path); +$else + assert(false, "rmtree is not available"); +$endif +} + fn Path! new(String path, Allocator* using = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV) { return { normalize(path.copy(using), path_env), path_env }; @@ -87,7 +132,7 @@ fn bool Path.equals(Path p1, Path p2) **/ fn Path! Path.append(Path path, String filename, Allocator* using = mem::heap()) { - if (!path.path_string.len) return new(filename, using, path.env)?; + if (!path.path_string.len) return new(filename, using, path.env)!; assert(!is_separator(path.path_string[^1], path.env)); @stack_mem(256; Allocator* mem) @@ -134,9 +179,9 @@ fn String Path.dirname(Path path) fn String! Path.extension(Path path) { String basename = path.basename(); - usz index = basename.rindex_of(".")?; + usz index = basename.rindex_of(".")!; // Plain ".foo" does not have an - if (index == 0) return SearchResult.MISSING!; + if (index == 0) return SearchResult.MISSING?; if (index == basename.len) return ""; return basename[index + 1..]; } @@ -166,9 +211,9 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local { char c = path[i]; if (is_win32_separator(c)) return i; - if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH!; + if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH?; } - return PathResult.INVALID_PATH!; + return PathResult.INVALID_PATH?; case 'A'..'Z': case 'a'..'z': return path[1] == ':' ? 2 : 0; @@ -179,7 +224,7 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local fn Path! Path.parent(Path path) { - if (path.path_string.len == 1 && is_separator(path.path_string[0], path.env)) return PathResult.NO_PARENT!; + if (path.path_string.len == 1 && is_separator(path.path_string[0], path.env)) return PathResult.NO_PARENT?; foreach_r(i, c : path.path_string) { if (is_separator(c, path.env)) @@ -187,13 +232,13 @@ fn Path! Path.parent(Path path) return { path.path_string[:i], path.env }; } } - return PathResult.NO_PARENT!; + return PathResult.NO_PARENT?; } fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) { if (!path_str.len) return path_str; - usz path_start = volume_name_len(path_str, path_env)?; + usz path_start = volume_name_len(path_str, path_env)!; usz path_len = path_str.len; if (path_start == path_len) return path_str; char path_separator = path_env == PathEnv.WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX; @@ -225,7 +270,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) // The rest are names of the path elements, so check that the // characters are valid. - if (is_reserved_path_char(c, path_env)) return PathResult.INVALID_PATH!; + if (is_reserved_path_char(c, path_env)) return PathResult.INVALID_PATH?; // If we have '.' after a separator if (c == '.' && previous_was_separator) @@ -251,7 +296,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) continue; case 2: // This is an error: /a/../.. - if (len == path_start && has_root) return PathResult.INVALID_PATH!; + if (len == path_start && has_root) return PathResult.INVALID_PATH?; // If this .. at the start, or after ../? If so, we just copy .. if (len == path_start || diff --git a/lib/std/io/stream/bytereader.c3 b/lib/std/io/stream/bytereader.c3 index a486644ee..cfbfb3e78 100644 --- a/lib/std/io/stream/bytereader.c3 +++ b/lib/std/io/stream/bytereader.c3 @@ -19,7 +19,7 @@ fn Stream ByteReader.as_stream(ByteReader* reader) fn usz! ByteReader.read(ByteReader* reader, char[] bytes) { - if (reader.index >= reader.bytes.len) return IoError.EOF!; + if (reader.index >= reader.bytes.len) return IoError.EOF?; usz len = math::min(reader.bytes.len - reader.index, bytes.len); if (len == 0) return 0; mem::copy(bytes.ptr, &reader.bytes[reader.index], len); @@ -29,13 +29,13 @@ fn usz! ByteReader.read(ByteReader* reader, char[] bytes) fn char! ByteReader.read_byte(ByteReader* reader) { - if (reader.index >= reader.bytes.len) return IoError.EOF!; + if (reader.index >= reader.bytes.len) return IoError.EOF?; return reader.bytes[reader.index++]; } fn void! ByteReader.pushback_byte(ByteReader* reader) { - if (!reader.index) return IoError.INVALID_PUSHBACK!; + if (!reader.index) return IoError.INVALID_PUSHBACK?; reader.index--; } @@ -48,7 +48,7 @@ fn usz! ByteReader.seek(ByteReader* reader, isz offset, Seek seek) case CURSOR: new_index = reader.index + offset; case END: new_index = reader.bytes.len + offset; } - if (new_index < 0) return IoError.INVALID_POSITION!; + if (new_index < 0) return IoError.INVALID_POSITION?; reader.index = new_index; return new_index; } @@ -56,7 +56,7 @@ fn usz! ByteReader.seek(ByteReader* reader, isz offset, Seek seek) fn usz! ByteReader.write_stream(ByteReader* reader, Stream* writer) { if (reader.index >= reader.bytes.len) return 0; - usz written = writer.write(reader.bytes[reader.index..])?; + usz written = writer.write(reader.bytes[reader.index..])!; reader.index += written; assert(reader.index <= reader.bytes.len); return written; diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index 644957b15..c3ef7cc2f 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -52,16 +52,16 @@ fn String ByteWriter.as_str(ByteWriter* writer) fn void! ByteWriter.ensure_capacity(ByteWriter* writer, usz len) @inline { if (writer.bytes.len > len) return; - if (!writer.allocator) return IoError.OUT_OF_SPACE!; + if (!writer.allocator) return IoError.OUT_OF_SPACE?; if (len < 16) len = 16; usz new_capacity = math::next_power_of_2(len); - char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)?; + char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)!; writer.bytes = new_ptr[:new_capacity]; } fn usz! ByteWriter.write(ByteWriter* writer, char[] bytes) { - writer.ensure_capacity(writer.index + bytes.len)?; + writer.ensure_capacity(writer.index + bytes.len)!; mem::copy(&writer.bytes[writer.index], bytes.ptr, bytes.len); writer.index += bytes.len; return bytes.len; @@ -69,7 +69,7 @@ fn usz! ByteWriter.write(ByteWriter* writer, char[] bytes) fn void! ByteWriter.write_byte(ByteWriter* writer, char c) { - writer.ensure_capacity(writer.index + 1)?; + writer.ensure_capacity(writer.index + 1)!; writer.bytes[writer.index++] = c; } @@ -82,10 +82,10 @@ fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader) if (reader.supports_available()) { usz total_read = 0; - while (usz available = reader.available()?) + while (usz available = reader.available()!) { - writer.ensure_capacity(writer.index + available)?; - usz len = reader.read(writer.bytes[writer.index..])?; + writer.ensure_capacity(writer.index + available)!; + usz len = reader.read(writer.bytes[writer.index..])!; total_read += len; writer.index += len; } @@ -99,10 +99,10 @@ fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader) // Less than 16 bytes? Double the capacity if (len_to_read < 16) { - writer.ensure_capacity(writer.bytes.len * 2)?; + writer.ensure_capacity(writer.bytes.len * 2)!; } // Read into the rest of the buffer - usz read = reader.read(writer.bytes[writer.index..])?; + usz read = reader.read(writer.bytes[writer.index..])!; writer.index += read; // Ok, we reached the end. if (read < len_to_read) return total_read; diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index ceaf1197d..d0677bc82 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -162,7 +162,7 @@ $case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.LINUX: macro CFile stdin() { return __stdin; } macro CFile stdout() { return __stdout; } macro CFile stderr() { return __stderr; } -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOSX: +$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOS: extern CFile __stdinp; extern CFile __stdoutp; extern CFile __stderrp; @@ -187,7 +187,7 @@ $endswitch const HAS_MALLOC_SIZE = env::OS_TYPE == OsType.LINUX || env::OS_TYPE == OsType.WIN32 - || env::OS_TYPE == OsType.MACOSX; + || env::OS_TYPE == OsType.MACOS; // The following needs to be set per arch+os // For now I have simply pulled the defaults from MacOS @@ -320,9 +320,7 @@ $endif // time.h -typedef TimeOffset = CLong; - -struct Tm +struct TmCommon @private { int tm_sec; /* seconds after the minute [0-60] */ int tm_min; /* minutes after the hour [0-59] */ @@ -333,18 +331,70 @@ struct Tm int tm_wday; /* days since Sunday [0-6] */ int tm_yday; /* days since January 1 [0-365] */ int tm_isdst; /* Daylight Savings Time flag */ +} + + +$switch (env::OS_TYPE) + +$case WIN32: + +typedef Tm = TmCommon; + +$case WASI: + +typedef TimeOffset = int; +struct Tm +{ + inline TmCommon common; + TimeOffset tm_gmtoff; /* offset from UTC in seconds */ + char *tm_zone; /* timezone abbreviation */ + int tm_nsec; +} + +$case MACOS: +$case IOS: +$case TVOS: +$case WATCHOS: +$case OPENBSD: +$case FREEBSD: +$default: + +typedef TimeOffset = CLong; +struct Tm +{ + inline TmCommon common; TimeOffset tm_gmtoff; /* offset from UTC in seconds */ char *tm_zone; /* timezone abbreviation */ } +$endswitch + + +$if (env::os_is_win32()) + struct TimeSpec { - Time s; + Time_t s; ulong ns; } -const int TIME_UTC = 1; +typedef Time_t = long; +typedef Clock_t = ulong; +$else + +struct TimeSpec +{ + Time_t s; + CLong ns; +} + +typedef Time_t = CLong; +typedef Clock_t = CULong; + +$endif + +const int TIME_UTC = 1; extern fn int timespec_get(TimeSpec* ts, int base); extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining); @@ -352,19 +402,34 @@ extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining); // Likely wrong, must be per platform. const CLOCKS_PER_SEC = 1000000; -// Time also needs to be per platform -typedef Time = long; -typedef Clock = ulong; extern fn ZString asctime(Tm *timeptr); -extern fn Clock clock(); -extern fn ZString ctime(Time *timer); -extern fn double difftime(Time time1, Time time2); -extern fn Tm* gmtime(Time *timer); -extern fn Tm* localtime(Time *timer); -extern fn Time mktime(Tm *timeptr); +extern fn Clock_t clock(); +extern fn ZString ctime(Time_t *timer); +extern fn double difftime(Time_t time1, Time_t time2); +extern fn Tm* gmtime(Time_t *timer); + +extern fn Tm* localtime(Time_t *timer); + +$if (env::os_is_win32()) +extern fn Tm* _gmtime64_s(Tm* buf, Time_t *timer); +extern fn Tm* _localtime64_s(Tm* buf, Time_t *timer); +extern fn void _get_timezone(CLong *timezone); + +macro Tm* gmtime_r(Time_t *timer, Tm* buf) => _gmtime64_s(buf, timer); +macro Tm* localtime_r(Time_t *timer, Tm* buf) => _localtime64_s(buf, timer); + +extern fn Time_t mktime(Tm *timeptr) @extern("_mktime64"); +extern fn Time_t timegm(Tm *timeptr) @extern("_mkgmtime64"); +$else +extern fn Tm* gmtime_r(Time_t *timer, Tm* buf); +extern fn Tm* localtime_r(Time_t *timer, Tm* buf); +extern fn Time_t mktime(Tm *timeptr); +extern fn Time_t timegm(Tm *timeptr); +$endif + extern fn usz strftime(char* str, usz maxsize, char* format, Tm *timeptr); -extern fn Time time(Time *timer); +extern fn Time_t time(Time_t *timer); // signal typedef SignalFunction = fn void(int); @@ -386,7 +451,7 @@ const Errno ENOEXEC = 8; // Exec format error const Errno EBADF = 9; // Bad file number const Errno ECHILD = 10; // No child processes -$if (env::OS_TYPE == MACOSX) +$if (env::OS_TYPE == MACOS) const Errno EAGAIN = 35; // Try again Macos $else const Errno EAGAIN = 11; // Try again @@ -418,7 +483,7 @@ const Errno ERANGE = 34; // Math result not representable $switch (env::OS_TYPE) -$case MACOSX: +$case MACOS: const Errno EDEADLK = 11; // Resource deadlock would occur MacOS const Errno ENAMETOOLONG = 63; // File name too long MacOS const Errno ELOOP = 62; // Too many symbolic links encountered @@ -428,6 +493,7 @@ const Errno ENETDOWN = 50; // Network is down MacOS const Errno ENETUNREACH = 51; // Network is unreachable MacOS const Errno ENETRESET = 52; // Network dropped connection because of reset MacOS const Errno EOPNOTSUPP = 45; // Operation not supported on transport endpoint +const Errno ENOTEMPTY = 66; // Directory not empty $case WIN32: const Errno EDEADLK = 36; // Resource deadlock would occur Win32 @@ -439,6 +505,7 @@ const Errno ECONNRESET = 108; // Connection reset by peer const Errno ENETUNREACH = 118; // Network is unreachable const Errno ENETRESET = 117; // Network dropped connection because of reset const Errno EOPNOTSUPP = 130; // Operation not supported on transport endpoint +const Errno ENOTEMPTY = 41; // Directory not empty $default: const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?) @@ -450,6 +517,7 @@ const Errno ECONNRESET = 104; // Connection reset by peer const Errno ENETUNREACH = 101; // Network is unreachable const Errno ENETRESET = 102; // Network dropped connection because of reset const Errno EOPNOTSUPP = 95; // Operation not supported on transport endpoint +const Errno ENOTEMPTY = 39; // Directory not empty $endswitch @@ -458,7 +526,6 @@ $endswitch /* const Errno ENOLCK = 37; /* No record locks available */ const Errno ENOSYS = 38; /* Function not implemented */ -const Errno ENOTEMPTY = 39; /* Directory not empty */ const Errno ENOMSG = 42; /* No message of desired type */ const Errno EIDRM = 43; /* Identifier removed */ @@ -529,7 +596,7 @@ const Errno EHOSTUNREACH = 113; /* No route to host */ $switch (env::OS_TYPE) -$case MACOSX: +$case MACOS: const Errno ETIMEDOUT = 60; // Connection timed out const Errno EINPROGRESS = 36; // Operation now in progress MacOS const Errno EALREADY = 37; // Operation already in progress MacOS diff --git a/lib/std/libc/os/errno.c3 b/lib/std/libc/os/errno.c3 index df755ce3a..0325b56d0 100644 --- a/lib/std/libc/os/errno.c3 +++ b/lib/std/libc/os/errno.c3 @@ -9,7 +9,7 @@ extern fn int* __errno_location(); macro int errno() => *__errno_location(); macro void errno_set(int err) => *(__errno_location()) = err; -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == MACOSX: +$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == MACOS: extern fn int* __error(); macro int errno() => *__error(); diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index a6953e53b..4644d7ba0 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -441,7 +441,7 @@ macro is_nan(x) $case float16: return bitcast((float)x, uint) & 0x7fffffff > 0x7f800000; $default: - return bitcast((double)x, ulong) & (~0u64 >> 1) > 0x7ff << 52; + return bitcast((double)x, ulong) & (~0u64 >> 1) > 0x7ffu64 << 52; $endswitch } @@ -455,7 +455,7 @@ macro is_inf(x) $case float16: return bitcast((float)x, uint) & 0x7fffffff == 0x7f800000; $default: - return bitcast((double)x, ulong) & (~0u64 >> 1) == 0x7ff << 52; + return bitcast((double)x, ulong) & (~0u64 >> 1) == 0x7ffu64 << 52; $endswitch } diff --git a/lib/std/math/math.matrix.c3 b/lib/std/math/math.matrix.c3 index e495eef93..282ab02c2 100644 --- a/lib/std/math/math.matrix.c3 +++ b/lib/std/math/math.matrix.c3 @@ -276,7 +276,7 @@ fn Matrix4x4 Matrix4x4.adjoint(Matrix4x4* mat) fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m) { Real det = m.determinant(); - if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!; + if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?; Matrix2x2 adj = m.adjoint(); return adj.component_mul(1 / det).transpose(); } @@ -284,7 +284,7 @@ fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m) fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m) { Real det = m.determinant(); - if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!; + if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?; Matrix3x3 adj = m.adjoint(); return adj.component_mul(1 / det).transpose(); } @@ -292,7 +292,7 @@ fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m) fn Matrix4x4! Matrix4x4.inverse(Matrix4x4* m) { Real det = m.determinant(); - if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!; + if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?; Matrix4x4 adj = m.adjoint(); return adj.component_mul(1 / det).transpose(); } diff --git a/lib/std/math/math_vector.c3 b/lib/std/math/math_vector.c3 index f52d52764..f0c3e610b 100644 --- a/lib/std/math/math_vector.c3 +++ b/lib/std/math/math_vector.c3 @@ -138,8 +138,9 @@ macro cross3(v1, v2) @private macro transform2(v, mat) @private { - return $typeof(v) { mat.m00 * v[0] + mat.m10 * v[1] + mat.30, - mat.m01 * v[0] + mar.m11 * v[1] + mat.31 }; + return $typeof(v) { + mat.m00 * v[0] + mat.m10 * v[1] + mat.m30 , + mat.m01 * v[0] + mat.m11 * v[1] + mat.m31 }; } macro transform3(v, mat) @private diff --git a/lib/std/net/inetaddr.c3 b/lib/std/net/inetaddr.c3 index 79ee91aa6..1bbd12bfb 100644 --- a/lib/std/net/inetaddr.c3 +++ b/lib/std/net/inetaddr.c3 @@ -48,10 +48,10 @@ fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) { formatter.printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d, - addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)?; + addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!; return; } - formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)?; + 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()) @@ -61,22 +61,22 @@ fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap char[8 * 5 + 1] buffer; String res = (String)io::bprintf(&buffer, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d, - addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)?; + addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!; return res.copy(using); } char[3 * 4 + 3 + 1] buffer; - String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)?; + String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!; return res.copy(using); } fn InetAddress! ipv6_from_str(String s) { uint sections = 0; - if (s.len < 2) return NetError.INVALID_IP_STRING!; + if (s.len < 2) return NetError.INVALID_IP_STRING?; foreach (c : s) if (c == ':') sections++; int zero_segment_len = s[0] == ':' || s[^1] == ':' ? 9 - sections : 8 - sections; if (zero_segment_len == 7 && s.len == 2) return { .is_ipv6 = true }; - if (zero_segment_len > 7) return NetError.INVALID_IP_STRING!; + if (zero_segment_len > 7) return NetError.INVALID_IP_STRING?; usz index = 0; bool last_was_colon, found_zero; int current = -1; @@ -92,7 +92,7 @@ fn InetAddress! ipv6_from_str(String s) last_was_colon = true; continue; } - if (current < 0 || current > 65535) return NetError.INVALID_IP_STRING!; + if (current < 0 || current > 65535) return NetError.INVALID_IP_STRING?; addr.ipv6arr[index++].val = (ushort)current; current = -1; last_was_colon = true; @@ -100,9 +100,9 @@ fn InetAddress! ipv6_from_str(String s) } assert(current == -1); // Check that this is the first :: - if (found_zero) return NetError.INVALID_IP_STRING!; + if (found_zero) return NetError.INVALID_IP_STRING?; // Also check that the zeroed section is at least 2 - if (zero_segment_len < 2) return NetError.INVALID_IP_STRING!; + if (zero_segment_len < 2) return NetError.INVALID_IP_STRING?; // Skip (will be zero by default index += zero_segment_len; found_zero = true; @@ -110,7 +110,7 @@ fn InetAddress! ipv6_from_str(String s) continue; } last_was_colon = false; - if (index > 7 || !c.is_xdigit()) return NetError.INVALID_IP_STRING!; + if (index > 7 || !c.is_xdigit()) return NetError.INVALID_IP_STRING?; if (current < 0) current = 0; current = current * 16 + (c <= '9' ? c - '0' : (c | 32) - 'a' + 10); } @@ -118,7 +118,7 @@ fn InetAddress! ipv6_from_str(String s) if (index == 8 && current == -1) return addr; // Ends with number - if (index != 7 || current < 0 || current > 65535) return NetError.INVALID_IP_STRING!; + if (index != 7 || current < 0 || current > 65535) return NetError.INVALID_IP_STRING?; addr.ipv6arr[7].val = (ushort)current; return addr; } @@ -132,20 +132,20 @@ fn InetAddress! ipv4_from_str(String s) { if (c == '.') { - if (current < 0) return NetError.INVALID_IP_STRING!; - if (current > 255) return NetError.INVALID_IP_STRING!; + if (current < 0) return NetError.INVALID_IP_STRING?; + if (current > 255) return NetError.INVALID_IP_STRING?; switch (element) { case 0: addr.ipv4.a = (char)current; case 1: addr.ipv4.b = (char)current; case 2: addr.ipv4.c = (char)current; - default: return NetError.INVALID_IP_STRING!; + default: return NetError.INVALID_IP_STRING?; } current = -1; element++; continue; } - if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING!; + if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?; if (current < 0) { current = c - '0'; @@ -153,7 +153,7 @@ fn InetAddress! ipv4_from_str(String s) } current = current * 10 + c - '0'; } - if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING!; + if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING?; addr.ipv4.d = (char)current; return addr; } diff --git a/lib/std/net/net.c3 b/lib/std/net/net.c3 index 19231767b..225d88c62 100644 --- a/lib/std/net/net.c3 +++ b/lib/std/net/net.c3 @@ -19,13 +19,13 @@ fn uint! ipv4toint(String s) { if (c == '.') { - if (current < 0) return NetError.INVALID_IP_STRING!; + if (current < 0) return NetError.INVALID_IP_STRING?; out = out << 8 + current; current = -1; element++; continue; } - if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING!; + if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?; if (current < 0) { current = c - '0'; @@ -33,7 +33,7 @@ fn uint! ipv4toint(String s) } current = current * 10 + c - '0'; } - if (element != 3 || current < 0) return NetError.INVALID_IP_STRING!; + if (element != 3 || current < 0) return NetError.INVALID_IP_STRING?; out = out << 8 + current; return out; } @@ -41,6 +41,6 @@ fn uint! ipv4toint(String s) fn String! inttoipv4(uint val, Allocator* using = mem::heap()) { char[3 * 4 + 3 + 1] buffer; - String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)?; + String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!; return res.copy(using); } \ No newline at end of file diff --git a/lib/std/net/os/darwin.c3 b/lib/std/net/os/darwin.c3 index edd10878a..e73353a3d 100644 --- a/lib/std/net/os/darwin.c3 +++ b/lib/std/net/os/darwin.c3 @@ -1,7 +1,7 @@ module std::net::os; import libc; -$if (env::OS_TYPE == OsType.MACOSX) +$if (env::OS_TYPE == OsType.MACOS) const AI_NUMERICSERV = 0x1000; const AI_ALL = 0x100; diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index 16e295141..d07bc2baa 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -19,8 +19,8 @@ macro void! NativeSocket.close(NativeSocket this) { if (close(this)) { - if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET!; - return NetError.GENERAL_ERROR!; + if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?; + return NetError.GENERAL_ERROR?; } } @@ -29,8 +29,8 @@ macro void! NativeSocket.set_non_blocking(NativeSocket this) int flags = fcntl(this, F_GETFL, 0); if (fcntl(this, F_SETFL, flags | O_NONBLOCK) == -1) { - if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET!; - return NetError.GENERAL_ERROR!; + if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?; + return NetError.GENERAL_ERROR?; } } diff --git a/lib/std/os/macos/cf_allocator.c3 b/lib/std/os/macos/cf_allocator.c3 index 59f7891b9..f0b468fc6 100644 --- a/lib/std/os/macos/cf_allocator.c3 +++ b/lib/std/os/macos/cf_allocator.c3 @@ -1,6 +1,6 @@ module std::os::macos::cf; -$if (env::OS_TYPE == OsType.MACOSX) +$if (env::OS_TYPE == OsType.MACOS) typedef CFAllocatorRef = distinct void*; typedef CFAllocatorContextRef = distinct void*; diff --git a/lib/std/os/macos/cf_array.c3 b/lib/std/os/macos/cf_array.c3 index 615f3802b..2d45deab4 100644 --- a/lib/std/os/macos/cf_array.c3 +++ b/lib/std/os/macos/cf_array.c3 @@ -1,6 +1,6 @@ module std::os::macos::cf; -$if (env::OS_TYPE == OsType.MACOSX) +$if (env::OS_TYPE == OsType.MACOS) typedef CFArrayRef = distinct void*; typedef CFArrayCallBacksRef = distinct void*; diff --git a/lib/std/os/macos/core_foundation.c3 b/lib/std/os/macos/core_foundation.c3 index 5439407dc..8143f9519 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::OS_TYPE == OsType.MACOSX) +$if (env::OS_TYPE == OsType.MACOS) typedef CFTypeRef = distinct void*; typedef CFIndex = isz; diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index 07eca2887..f4afdb476 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -1,6 +1,6 @@ module std::os::macos::objc; -$if (env::OS_TYPE == OsType.MACOSX) +$if (env::OS_TYPE == OsType.MACOS) typedef Class = distinct void*; typedef Method = distinct void*; @@ -24,7 +24,7 @@ macro Selector selector_register(char* c) => _macos_sel_registerName(c); macro Class! class_by_name(char* c) { Class cls = _macos_objc_lookUpClass(c); - if (!cls) return ObjcFailure.CLASS_NOT_FOUND!; + if (!cls) return ObjcFailure.CLASS_NOT_FOUND?; return cls; } diff --git a/lib/std/os/posix/files.c3 b/lib/std/os/posix/files.c3 new file mode 100644 index 000000000..fb2e045fc --- /dev/null +++ b/lib/std/os/posix/files.c3 @@ -0,0 +1,10 @@ +module std::os::posix; + +$if (env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE) + +extern fn int rmdir(ZString); +extern fn int mkdir(ZString, ushort mode_t); +extern fn int chdir(ZString); +extern fn ZString getcwd(char* pwd, usz len); + +$endif \ No newline at end of file diff --git a/lib/std/os/win32/error.c3 b/lib/std/os/win32/error.c3 deleted file mode 100644 index 966d93d75..000000000 --- a/lib/std/os/win32/error.c3 +++ /dev/null @@ -1,29 +0,0 @@ -module std::os::win32::wsa; - -$if (env::OS_TYPE == OsType.WIN32) -extern fn int get_last_error() @extern("WSAGetLastError"); -extern fn void set_last_error(int error) @extern("WSASetLastError"); - -const int INVALID_HANDLE = 6; -const int NOT_ENOUGHT_MEMORY = 8; -const int INVALID_PARAMETER = 87; -const int OPERATION_ABORTED = 995; -const int IO_INCOMPLETE = 996; -const int IO_PENDING = 997; -const int EINTR = 10004; -const int EBADF = 10009; -const int ACCESS = 10013; -const int EFAULT = 10014; -const int EINVAL = 10022; -const int EMFILE = 10024; -const int EWOULDBLOCK = 10035; -const int EINPROGRESS = 10036; -const int EALREADY = 10037; -const int ENOTSOCK = 10038; -const int EDESTADDRREQ = 10039; -const int EMSGSIZE = 10040; -const int EPROTOTYPE = 10041; -const int ENOPROTOOPT = 10042; -const int EPROTONOSUPPORT = 10043; -const int ESOCKTNOSUPPORT = 10044; -$endif \ No newline at end of file diff --git a/lib/std/os/win32/files.c3 b/lib/std/os/win32/files.c3 index d189ab0b5..cba7ecacb 100644 --- a/lib/std/os/win32/files.c3 +++ b/lib/std/os/win32/files.c3 @@ -1,4 +1,4 @@ -module std::os::win32::files; +module std::os::win32; $if (env::os_is_win32()) @@ -8,11 +8,6 @@ enum Win32_GET_FILEEX_INFO_LEVELS MAX, } -struct Win32_FILETIME -{ - Win32_DWORD dwLowDateTime; - Win32_DWORD dwHighDateTime; -} struct Win32_FILE_ATTRIBUTE_DATA { @@ -24,18 +19,47 @@ struct Win32_FILE_ATTRIBUTE_DATA Win32_DWORD nFileSizeLow; } + +const MAX_PATH = 260; + +struct Win32_WIN32_FIND_DATAW +{ + Win32_DWORD dwFileAttributes; + Win32_FILETIME ftCreationTime; + Win32_FILETIME ftLastAccessTime; + Win32_FILETIME ftLastWriteTime; + Win32_DWORD nFileSizeHigh; + Win32_DWORD nFileSizeLow; + Win32_DWORD dwReserved0; + Win32_DWORD dwReserved1; + Win32_WCHAR[260] cFileName; + Win32_WCHAR[14] cAlternateFileName; + Win32_DWORD dwFileType; // Obsolete. Do not use. + Win32_DWORD dwCreatorType; // Obsolete. Do not use + Win32_WORD wFinderFlags; // Obsolete. Do not use +} + +typedef Win32_LPWIN32_FIND_DATAW = Win32_WIN32_FIND_DATAW*; + extern fn Win32_BOOL win32_CloseHandle(Win32_HANDLE) @extern("CloseHandle"); extern fn Win32_BOOL win32_CreatePipe(Win32_PHANDLE hReadPipe, Win32_PHANDLE hWritePipe, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes, Win32_DWORD nSize) @extern("CreatePipe"); extern fn Win32_BOOL win32_GetFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @extern("GetFileAttributesExW"); extern fn Win32_BOOL win32_PathFileExistsW(Win32_LPCWSTR) @extern("PathFileExistsW"); extern fn Win32_DWORD win32_GetTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @extern("GetTempPathW"); extern fn Win32_BOOL win32_SetCurrentDirectoryW(Win32_LPCTSTR buffer) @extern("SetCurrentDirectoryW"); +extern fn Win32_BOOL win32_RemoveDirectoryW(Win32_LPCWSTR lpPathName) @extern("RemoveDirectoryW"); +extern fn Win32_BOOL win32_CreateDirectoryW(Win32_LPCWSTR lpPathName, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes) @extern("CreateDirectoryW"); +extern fn Win32_BOOL win32_DeleteFileW(Win32_LPCWSTR lpFileName) @extern("DeleteFileW"); +extern fn Win32_HANDLE win32_FindFirstFileW(Win32_LPCWSTR lpFileName, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindFirstFileW"); +extern fn Win32_BOOL win32_FindNextFileW(Win32_HANDLE hFindFile, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindNextFileW"); +extern fn Win32_BOOL win32_FindClose(Win32_HANDLE hFindFile) @extern("FindClose"); + +extern fn Char16* _wgetcwd(Char16* buffer, int maxlen); +extern fn usz wcslen(Char16* str); /* extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW"); extern bool _win32_CreateSymbolicLinkW(Char16* symlink_file, Char16* target_file, ulong flags) @extern("CreateSymbolicLinkW"); -extern bool _win32_CreateDirectoryW(Char16* path_name, void* security_attributes) @extern("CreateDirectoryW"); -extern bool _win32_DeleteFileW(Char16* file) @extern("DeleteFileW"); extern bool _win32_CopyFileW(Char16* from_file, Char16* to_file, bool no_overwrite) @extern("CopyFileW"); extern ulong _win32_GetFullPathNameW(Char16* file_name, ulong buffer_len, Char16* buffer, Char16** file_part) @extern("GetFullPathNameW"); */ diff --git a/lib/std/os/win32/general.c3 b/lib/std/os/win32/general.c3 new file mode 100644 index 000000000..a2ad96ed1 --- /dev/null +++ b/lib/std/os/win32/general.c3 @@ -0,0 +1,227 @@ +module std::os::win32; + +$if (env::os_is_win32()) + +extern fn Win32_DWORD win32_GetLastError() @extern("GetLastError"); + +const Win32_DWORD ERROR_INVALID_FUNCTION = 0x1; +const Win32_DWORD ERROR_FILE_NOT_FOUND = 0x2; +const Win32_DWORD ERROR_PATH_NOT_FOUND = 0x3; +const Win32_DWORD ERROR_TOO_MANY_OPEN_FILES = 0x4; +const Win32_DWORD ERROR_ACCESS_DENIED = 0x5; +const Win32_DWORD ERROR_INVALID_HANDLE = 0x6; +const Win32_DWORD ERROR_ARENA_TRASHED = 0x7; +const Win32_DWORD ERROR_NOT_ENOUGH_MEMORY = 0x8; +const Win32_DWORD ERROR_INVALID_BLOCK = 0x9; +const Win32_DWORD ERROR_BAD_ENVIRONMENT = 0xA; +const Win32_DWORD ERROR_BAD_FORMAT = 0xB; +const Win32_DWORD ERROR_INVALID_ACCESS = 0xC; +const Win32_DWORD ERROR_INVALID_DATA = 0xD; +const Win32_DWORD ERROR_OUTOFMEMORY = 0xE; +const Win32_DWORD ERROR_INVALID_DRIVE = 0xF; +const Win32_DWORD ERROR_CURRENT_DIRECTORY = 0x10; +const Win32_DWORD ERROR_NOT_SAME_DEVICE = 0x11; +const Win32_DWORD ERROR_NO_MORE_FILES = 0x12; +const Win32_DWORD ERROR_WRITE_PROTECT = 0x13; +const Win32_DWORD ERROR_BAD_UNIT = 0x14; +const Win32_DWORD ERROR_NOT_READY = 0x15; +const Win32_DWORD ERROR_BAD_COMMAND = 0x16; +const Win32_DWORD ERROR_CRC = 0x17; +const Win32_DWORD ERROR_BAD_LENGTH = 0x18; +const Win32_DWORD ERROR_SEEK = 0x19; +const Win32_DWORD ERROR_NOT_DOS_DISK = 0x1A; +const Win32_DWORD ERROR_SECTOR_NOT_FOUND = 0x1B; +const Win32_DWORD ERROR_OUT_OF_PAPER = 0x1C; +const Win32_DWORD ERROR_WRITE_FAULT = 0x1D; +const Win32_DWORD ERROR_READ_FAULT = 0x1E; +const Win32_DWORD ERROR_GEN_FAILURE = 0x1F; +const Win32_DWORD ERROR_SHARING_VIOLATION = 0x20; +const Win32_DWORD ERROR_LOCK_VIOLATION = 0x21; +const Win32_DWORD ERROR_WRONG_DISK = 0x22; +const Win32_DWORD ERROR_SHARING_BUFFER_EXCEEDED = 0x24; +const Win32_DWORD ERROR_HANDLE_EOF = 0x26; +const Win32_DWORD ERROR_HANDLE_DISK_FULL = 0x27; +const Win32_DWORD ERROR_NOT_SUPPORTED = 0x32; +const Win32_DWORD ERROR_REM_NOT_LIST = 0x33; +const Win32_DWORD ERROR_DUP_NAME = 0x34; +const Win32_DWORD ERROR_BAD_NETPATH = 0x35; +const Win32_DWORD ERROR_NETWORK_BUSY = 0x36; +const Win32_DWORD ERROR_DEV_NOT_EXIST = 0x37; +const Win32_DWORD ERROR_TOO_MANY_CMDS = 0x38; +const Win32_DWORD ERROR_ADAP_HDW_ERR = 0x39; +const Win32_DWORD ERROR_BAD_NET_RESP = 0x3A; +const Win32_DWORD ERROR_UNEXP_NET_ERR = 0x3B; +const Win32_DWORD ERROR_BAD_REM_ADAP = 0x3C; +const Win32_DWORD ERROR_PRINTQ_FULL = 0x3D; +const Win32_DWORD ERROR_NO_SPOOL_SPACE = 0x3E; +const Win32_DWORD ERROR_PRINT_CANCELLED = 0x3F; +const Win32_DWORD ERROR_NETNAME_DELETED = 0x40; +const Win32_DWORD ERROR_NETWORK_ACCESS_DENIED = 0x41; +const Win32_DWORD ERROR_BAD_DEV_TYPE = 0x42; +const Win32_DWORD ERROR_BAD_NET_NAME = 0x43; +const Win32_DWORD ERROR_TOO_MANY_NAMES = 0x44; +const Win32_DWORD ERROR_TOO_MANY_SESS = 0x45; +const Win32_DWORD ERROR_SHARING_PAUSED = 0x46; +const Win32_DWORD ERROR_REQ_NOT_ACCEP = 0x47; +const Win32_DWORD ERROR_REDIR_PAUSED = 0x48; +const Win32_DWORD ERROR_FILE_EXISTS = 0x50; +const Win32_DWORD ERROR_CANNOT_MAKE = 0x52; +const Win32_DWORD ERROR_FAIL_I24 = 0x53; +const Win32_DWORD ERROR_OUT_OF_STRUCTURES = 0x54; +const Win32_DWORD ERROR_ALREADY_ASSIGNED = 0x55; +const Win32_DWORD ERROR_INVALID_PASSWORD = 0x56; +const Win32_DWORD ERROR_INVALID_PARAMETER = 0x57; +const Win32_DWORD ERROR_NET_WRITE_FAULT = 0x58; +const Win32_DWORD ERROR_NO_PROC_SLOTS = 0x59; +const Win32_DWORD ERROR_TOO_MANY_SEMAPHORES = 0x64; +const Win32_DWORD ERROR_EXCL_SEM_ALREADY_OWNED = 0x65; +const Win32_DWORD ERROR_SEM_IS_SET = 0x66; +const Win32_DWORD ERROR_TOO_MANY_SEM_REQUESTS = 0x67; +const Win32_DWORD ERROR_INVALID_AT_INTERRUPT_TIME = 0x68; +const Win32_DWORD ERROR_SEM_OWNER_DIED = 0x69; +const Win32_DWORD ERROR_SEM_USER_LIMIT = 0x6A; +const Win32_DWORD ERROR_DISK_CHANGE = 0x6B; +const Win32_DWORD ERROR_DRIVE_LOCKED = 0x6C; +const Win32_DWORD ERROR_BROKEN_PIPE = 0x6D; +const Win32_DWORD ERROR_OPEN_FAILED = 0x6E; +const Win32_DWORD ERROR_BUFFER_OVERFLOW = 0x6F; +const Win32_DWORD ERROR_DISK_FULL = 0x70; +const Win32_DWORD ERROR_NO_MORE_SEARCH_HANDLES = 0x71; +const Win32_DWORD ERROR_INVALID_TARGET_HANDLE = 0x72; +const Win32_DWORD ERROR_INVALID_CATEGORY = 0x75; +const Win32_DWORD ERROR_INVALID_VERIFY_SWITCH = 0x76; +const Win32_DWORD ERROR_BAD_DRIVER_LEVEL = 0x77; +const Win32_DWORD ERROR_CALL_NOT_IMPLEMENTED = 0x78; +const Win32_DWORD ERROR_SEM_TIMEOUT = 0x79; +const Win32_DWORD ERROR_INSUFFICIENT_BUFFER = 0x7A; +const Win32_DWORD ERROR_INVALID_NAME = 0x7B; +const Win32_DWORD ERROR_INVALID_LEVEL = 0x7C; +const Win32_DWORD ERROR_NO_VOLUME_LABEL = 0x7D; +const Win32_DWORD ERROR_MOD_NOT_FOUND = 0x7E; +const Win32_DWORD ERROR_PROC_NOT_FOUND = 0x7F; +const Win32_DWORD ERROR_WAIT_NO_CHILDREN = 0x80; +const Win32_DWORD ERROR_CHILD_NOT_COMPLETE = 0x81; +const Win32_DWORD ERROR_DIRECT_ACCESS_HANDLE = 0x82; +const Win32_DWORD ERROR_NEGATIVE_SEEK = 0x83; +const Win32_DWORD ERROR_SEEK_ON_DEVICE = 0x84; +const Win32_DWORD ERROR_IS_JOIN_TARGET = 0x85; +const Win32_DWORD ERROR_IS_JOINED = 0x86; +const Win32_DWORD ERROR_IS_SUBSTED = 0x87; +const Win32_DWORD ERROR_NOT_JOINED = 0x88; +const Win32_DWORD ERROR_NOT_SUBSTED = 0x89; +const Win32_DWORD ERROR_JOIN_TO_JOIN = 0x8A; +const Win32_DWORD ERROR_SUBST_TO_SUBST = 0x8B; +const Win32_DWORD ERROR_JOIN_TO_SUBST = 0x8C; +const Win32_DWORD ERROR_SUBST_TO_JOIN = 0x8D; +const Win32_DWORD ERROR_BUSY_DRIVE = 0x8E; +const Win32_DWORD ERROR_SAME_DRIVE = 0x8F; +const Win32_DWORD ERROR_DIR_NOT_ROOT = 0x90; +const Win32_DWORD ERROR_DIR_NOT_EMPTY = 0x91; +const Win32_DWORD ERROR_IS_SUBST_PATH = 0x92; +const Win32_DWORD ERROR_IS_JOIN_PATH = 0x93; +const Win32_DWORD ERROR_PATH_BUSY = 0x94; +const Win32_DWORD ERROR_IS_SUBST_TARGET = 0x95; +const Win32_DWORD ERROR_SYSTEM_TRACE = 0x96; +const Win32_DWORD ERROR_INVALID_EVENT_COUNT = 0x97; +const Win32_DWORD ERROR_TOO_MANY_MUXWAITERS = 0x98; +const Win32_DWORD ERROR_INVALID_LIST_FORMAT = 0x99; +const Win32_DWORD ERROR_LABEL_TOO_LONG = 0x9A; +const Win32_DWORD ERROR_TOO_MANY_TCBS = 0x9B; +const Win32_DWORD ERROR_SIGNAL_REFUSED = 0x9C; +const Win32_DWORD ERROR_DISCARDED = 0x9D; +const Win32_DWORD ERROR_NOT_LOCKED = 0x9E; +const Win32_DWORD ERROR_BAD_THREADID_ADDR = 0x9F; +const Win32_DWORD ERROR_BAD_ARGUMENTS = 0xA0; +const Win32_DWORD ERROR_BAD_PATHNAME = 0xA1; +const Win32_DWORD ERROR_SIGNAL_PENDING = 0xA2; +const Win32_DWORD ERROR_MAX_THRDS_REACHED = 0xA4; +const Win32_DWORD ERROR_LOCK_FAILED = 0xA7; +const Win32_DWORD ERROR_BUSY = 0xAA; +const Win32_DWORD ERROR_DEVICE_SUPPORT_IN_PROGRESS = 0xAB; +const Win32_DWORD ERROR_CANCEL_VIOLATION = 0xAD; +const Win32_DWORD ERROR_ATOMIC_LOCKS_NOT_SUPPORTED = 0xAE; +const Win32_DWORD ERROR_INVALID_SEGMENT_NUMBER = 0xB4; +const Win32_DWORD ERROR_INVALID_ORDINAL = 0xB6; +const Win32_DWORD ERROR_ALREADY_EXISTS = 0xB7; +const Win32_DWORD ERROR_INVALID_FLAG_NUMBER = 0xBA; +const Win32_DWORD ERROR_SEM_NOT_FOUND = 0xBB; +const Win32_DWORD ERROR_INVALID_STARTING_CODESEG = 0xBC; +const Win32_DWORD ERROR_INVALID_STACKSEG = 0xBD; +const Win32_DWORD ERROR_INVALID_MODULETYPE = 0xBE; +const Win32_DWORD ERROR_INVALID_EXE_SIGNATURE = 0xBF; + +const Win32_DWORD ERROR_EXE_MARKED_INVALID = 0xC0; +const Win32_DWORD ERROR_BAD_EXE_FORMAT = 0xC1; +const Win32_DWORD ERROR_ITERATED_DATA_EXCEEDS_64K = 0xC2; +const Win32_DWORD ERROR_INVALID_MINALLOCSIZE = 0xC3; +const Win32_DWORD ERROR_DYNLINK_FROM_INVALID_RING = 0xC4; +const Win32_DWORD ERROR_IOPL_NOT_ENABLED = 0xC5; +const Win32_DWORD ERROR_INVALID_SEGDPL = 0xC6; +const Win32_DWORD ERROR_AUTODATASEG_EXCEEDS_64K = 0xC7; +const Win32_DWORD ERROR_RING2SEG_MUST_BE_MOVABLE = 0xC8; +const Win32_DWORD ERROR_RELOC_CHAIN_XEEDS_SEGLIM = 0xC9; +const Win32_DWORD ERROR_INFLOOP_IN_RELOC_CHAIN = 0xCA; +const Win32_DWORD ERROR_ENVVAR_NOT_FOUND = 0xCB; +const Win32_DWORD ERROR_NO_SIGNAL_SENT = 0xCD; +const Win32_DWORD ERROR_FILENAME_EXCED_RANGE = 0xCE; +const Win32_DWORD ERROR_RING2_STACK_IN_USE = 0xCF; +const Win32_DWORD ERROR_META_EXPANSION_TOO_LONG = 0xD0; +const Win32_DWORD ERROR_INVALID_SIGNAL_NUMBER = 0xD1; +const Win32_DWORD ERROR_THREAD_1_INACTIVE = 0xD2; +const Win32_DWORD ERROR_LOCKED = 0xD4; +const Win32_DWORD ERROR_TOO_MANY_MODULES = 0xD6; +const Win32_DWORD ERROR_NESTING_NOT_ALLOWED = 0xD7; +const Win32_DWORD ERROR_EXE_MACHINE_TYPE_MISMATCH = 0xD8; +const Win32_DWORD ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY = 0xD9; +const Win32_DWORD ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 0xDA; +const Win32_DWORD ERROR_FILE_CHECKED_OUT = 0xDC; +const Win32_DWORD ERROR_CHECKOUT_REQUIRED = 0xDD; +const Win32_DWORD ERROR_BAD_FILE_TYPE = 0xDE; +const Win32_DWORD ERROR_FILE_TOO_LARGE = 0xDF; +const Win32_DWORD ERROR_FORMS_AUTH_REQUIRED = 0xE0; +const Win32_DWORD ERROR_VIRUS_INFECTED = 0xE1; +const Win32_DWORD ERROR_VIRUS_DELETED = 0xE2; +const Win32_DWORD ERROR_PIPE_LOCAL = 0xE5; +const Win32_DWORD ERROR_BAD_PIPE = 0xE6; +const Win32_DWORD ERROR_PIPE_BUSY = 0xE7; +const Win32_DWORD ERROR_NO_DATA = 0xE8; +const Win32_DWORD ERROR_PIPE_NOT_CONNECTED = 0xE9; +const Win32_DWORD ERROR_MORE_DATA = 0xEA; +const Win32_DWORD ERROR_VC_DISCONNECTED = 0xF0; +const Win32_DWORD ERROR_INVALID_EA_NAME = 0xFE; +const Win32_DWORD ERROR_EA_LIST_INCONSISTENT = 0xFF; +const Win32_DWORD WAIT_TIMEOUT = 0x102; +const Win32_DWORD ERROR_NO_MORE_ITEMS = 0x103; +const Win32_DWORD ERROR_CANNOT_COPY = 0x10A; +const Win32_DWORD ERROR_DIRECTORY = 0x10B; + +const Win32_DWORD ERROR_EAS_DIDNT_FIT = 0x113; +const Win32_DWORD ERROR_EA_FILE_CORRUPT = 0x114; +const Win32_DWORD ERROR_EA_TABLE_FULL = 0x115; +const Win32_DWORD ERROR_INVALID_EA_HANDLE = 0x116; +const Win32_DWORD ERROR_EAS_NOT_SUPPORTED = 0x11A; +const Win32_DWORD ERROR_NOT_OWNER = 0x120; +const Win32_DWORD ERROR_TOO_MANY_POSTS = 0x12A; +const Win32_DWORD ERROR_PARTIAL_COPY = 0x12A; +const Win32_DWORD ERROR_OPLOCK_NOT_GRANTED = 0x12C; +const Win32_DWORD ERROR_INVALID_OPLOCK_PROTOCOL = 0x12D; +const Win32_DWORD ERROR_DISK_TOO_FRAGMENTED = 0x12E; +const Win32_DWORD ERROR_DELETE_PENDING = 0x12F; +const Win32_DWORD ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0x130; +const Win32_DWORD ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0x131; +const Win32_DWORD ERROR_SECURITY_STREAM_IS_INCONSISTENT = 0x132; +const Win32_DWORD ERROR_INVALID_LOCK_RANGE = 0x133; +const Win32_DWORD ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT = 0x134; +const Win32_DWORD ERROR_NOTIFICATION_GUID_ALREADY_DEFINED = 0x135; +const Win32_DWORD ERROR_INVALID_EXCEPTION_HANDLER = 0x136; +const Win32_DWORD ERROR_DUPLICATE_PRIVILEGES = 0x137; +const Win32_DWORD ERROR_NO_RANGES_PROCESSED = 0x138; +const Win32_DWORD ERROR_NOT_ALLOWED_ON_SYSTEM_FILE = 0x139; +const Win32_DWORD ERROR_DISK_RESOURCES_EXHAUSTED = 0x13A; +const Win32_DWORD ERROR_INVALID_TOKEN = 0x13B; +const Win32_DWORD ERROR_DEVICE_FEATURE_NOT_SUPPORTED = 0x13C; +const Win32_DWORD ERROR_MR_MID_NOT_FOUND = 0x13D; +const Win32_DWORD ERROR_SCOPE_NOT_FOUND = 0x13E; +const Win32_DWORD ERROR_UNDEFINED_SCOPE = 0x13F; + +$endif \ No newline at end of file diff --git a/lib/std/os/win32/process.c3 b/lib/std/os/win32/process.c3 index 86d6a2a0a..b6c10f70c 100644 --- a/lib/std/os/win32/process.c3 +++ b/lib/std/os/win32/process.c3 @@ -1,4 +1,4 @@ -module std::os::win32::process; +module std::os::win32; $if (env::os_is_win32()) @@ -13,6 +13,6 @@ extern fn bool win32_CreateProcessW( Win32_LPCWSTR lpCurrentDirectory, Win32_LPSTARTUPINFOW lpStartupInfo, Win32_LPPROCESS_INFORMATION lpProcessInformation -); +) @extern("CreateProcessW"); $endif \ No newline at end of file diff --git a/lib/std/os/win32/types.c3 b/lib/std/os/win32/types.c3 index 68f415fa3..c2f41b315 100644 --- a/lib/std/os/win32/types.c3 +++ b/lib/std/os/win32/types.c3 @@ -168,6 +168,8 @@ typedef Win32_WCHAR = Char16; typedef Win32_WORD = ushort; typedef Win32_WPARAM = Win32_UINT_PTR; +const INVALID_HANDLE_VALUE = (Win32_HANDLE)(uptr)-1; + struct Win32_UNICODE_STRING { Win32_USHORT length; @@ -230,6 +232,12 @@ struct Win32_STARTUPINFOEXW typedef Win32_LPPROC_THREAD_ATTRIBUTE_LIST = void*; typedef Win32_LPSTARTUPINFOEXW = Win32_STARTUPINFOEXW*; +struct Win32_FILETIME +{ + Win32_DWORD dwLowDateTime; + Win32_DWORD dwHighDateTime; +} + struct Win32_PROCESS_INFORMATION { Win32_HANDLE hProcess; diff --git a/lib/std/os/win32/wsa.c3 b/lib/std/os/win32/wsa.c3 new file mode 100644 index 000000000..cade24ad7 --- /dev/null +++ b/lib/std/os/win32/wsa.c3 @@ -0,0 +1,36 @@ +module std::os::win32; + +typedef WSAError = distinct int; + +$if (env::os_is_win32()) + +extern fn WSAError win32_WSAGetLastError() @extern("WSAGetLastError"); +extern fn void win32_WSASetLastError(WSAError error) @extern("WSASetLastError"); +$endif + +module std::os::win32::wsa; + +$if (env::os_is_win32()) +const WSAError INVALID_HANDLE = 6; +const WSAError NOT_ENOUGHT_MEMORY = 8; +const WSAError INVALID_PARAMETER = 87; +const WSAError OPERATION_ABORTED = 995; +const WSAError IO_INCOMPLETE = 996; +const WSAError IO_PENDING = 997; +const WSAError EINTR = 10004; +const WSAError EBADF = 10009; +const WSAError ACCESS = 10013; +const WSAError EFAULT = 10014; +const WSAError EINVAL = 10022; +const WSAError EMFILE = 10024; +const WSAError EWOULDBLOCK = 10035; +const WSAError EINPROGRESS = 10036; +const WSAError EALREADY = 10037; +const WSAError ENOTSOCK = 10038; +const WSAError EDESTADDRREQ = 10039; +const WSAError EMSGSIZE = 10040; +const WSAError EPROTOTYPE = 10041; +const WSAError ENOPROTOOPT = 10042; +const WSAError EPROTONOSUPPORT = 10043; +const WSAError ESOCKTNOSUPPORT = 10044; +$endif \ No newline at end of file diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index 78f89ae29..8dc2ea941 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -61,23 +61,23 @@ extern fn int sched_yield(); fn void! NativeMutex.init(NativeMutex* mutex, MutexType type) { PthreadMutexAttribute attr; - if (pthread_mutexattr_init(&attr)) return ThreadFault.INIT_FAILED!; + if (pthread_mutexattr_init(&attr)) return ThreadFault.INIT_FAILED?; defer pthread_mutexattr_destroy(&attr); if (type & thread::MUTEX_RECURSIVE) { - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return ThreadFault.INIT_FAILED!; + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return ThreadFault.INIT_FAILED?; } - if (pthread_mutex_init(mutex, &attr)) return ThreadFault.INIT_FAILED!; + if (pthread_mutex_init(mutex, &attr)) return ThreadFault.INIT_FAILED?; } fn void! NativeMutex.destroy(NativeMutex* mtx) { - if (pthread_mutex_destroy(mtx)) return ThreadFault.DESTROY_FAILED!; + if (pthread_mutex_destroy(mtx)) return ThreadFault.DESTROY_FAILED?; } fn void! NativeMutex.lock(NativeMutex* mtx) { - if (pthread_mutex_lock(mtx)) return ThreadFault.LOCK_FAILED!; + if (pthread_mutex_lock(mtx)) return ThreadFault.LOCK_FAILED?; } fn void! NativeMutex.lock_timeoutout(NativeMutex* mtx, ulong ms) @@ -88,7 +88,7 @@ fn void! NativeMutex.lock_timeoutout(NativeMutex* mtx, ulong ms) { if (!ms) break; ulong sleep = min(5, ms); - if (!libc::nanosleep(&& TimeSpec { .s = 0, .ns = sleep * 1000_000 }, null)) return ThreadFault.LOCK_FAILED!; + if (!libc::nanosleep(&& TimeSpec { .s = 0, .ns = (CLong)sleep * 1000_000 }, null)) return ThreadFault.LOCK_FAILED?; ms -= sleep; } switch (result) @@ -97,9 +97,9 @@ fn void! NativeMutex.lock_timeoutout(NativeMutex* mtx, ulong ms) return; case errno::EBUSY: case errno::ETIMEDOUT: - return ThreadFault.LOCK_TIMEOUT!; + return ThreadFault.LOCK_TIMEOUT?; default: - return ThreadFault.LOCK_FAILED!; + return ThreadFault.LOCK_FAILED?; } } @@ -110,48 +110,48 @@ fn bool NativeMutex.try_lock(NativeMutex* mtx) fn void! NativeMutex.unlock(NativeMutex* mtx) { - if (pthread_mutex_unlock(mtx)) return ThreadFault.UNLOCK_FAILED!; + if (pthread_mutex_unlock(mtx)) return ThreadFault.UNLOCK_FAILED?; } fn void! NativeConditionVariable.init(NativeConditionVariable* cond) { - if (pthread_cond_init(cond, null)) return ThreadFault.INIT_FAILED!; + if (pthread_cond_init(cond, null)) return ThreadFault.INIT_FAILED?; } fn void! NativeConditionVariable.destroy(NativeConditionVariable* cond) { - if (pthread_cond_destroy(cond)) return ThreadFault.DESTROY_FAILED!; + if (pthread_cond_destroy(cond)) return ThreadFault.DESTROY_FAILED?; } fn void! NativeConditionVariable.signal(NativeConditionVariable* cond) { - if (pthread_cond_signal(cond)) return ThreadFault.SIGNAL_FAILED!; + if (pthread_cond_signal(cond)) return ThreadFault.SIGNAL_FAILED?; } fn void! NativeConditionVariable.broadcast(NativeConditionVariable* cond) { - if (pthread_cond_broadcast(cond)) return ThreadFault.SIGNAL_FAILED!; + if (pthread_cond_broadcast(cond)) return ThreadFault.SIGNAL_FAILED?; } fn void! NativeConditionVariable.wait(NativeConditionVariable* cond, NativeMutex* mtx) { - if (pthread_cond_wait(cond, mtx)) return ThreadFault.WAIT_FAILED!; + if (pthread_cond_wait(cond, mtx)) return ThreadFault.WAIT_FAILED?; } fn void! NativeConditionVariable.wait_timeout(NativeConditionVariable* cond, NativeMutex* mtx, ulong ms) { TimeSpec now; - if (libc::timespec_get(&now, libc::TIME_UTC) != libc::TIME_UTC) return ThreadFault.WAIT_FAILED!; - now.s += ms / 1000; - now.ns += (ms % 1000) * 1000_000; + if (libc::timespec_get(&now, libc::TIME_UTC) != libc::TIME_UTC) return ThreadFault.WAIT_FAILED?; + now.s += (Time_t)(ms / 1000); + now.ns += (CLong)((ms % 1000) * 1000_000); switch (pthread_cond_timedwait(cond, mtx, &now)) { case errno::ETIMEDOUT: - return ThreadFault.WAIT_TIMEOUT!; + return ThreadFault.WAIT_TIMEOUT?; case errno::OK: return; default: - return ThreadFault.WAIT_FAILED!; + return ThreadFault.WAIT_FAILED?; } } @@ -170,13 +170,13 @@ fn void! NativeThread.create(NativeThread* thread, ThreadFn thread_fn, void* arg { *thread = null; free(thread_data); - return ThreadFault.INIT_FAILED!; + return ThreadFault.INIT_FAILED?; } } fn void! NativeThread.detach(NativeThread thread) { - if (!pthread_detach(thread)) return ThreadFault.DETACH_FAILED!; + if (!pthread_detach(thread)) return ThreadFault.DETACH_FAILED?; } fn void native_thread_exit(int result) @@ -197,7 +197,7 @@ fn bool NativeThread.equals(NativeThread this, NativeThread other) fn int! NativeThread.join(NativeThread thread) { void *pres; - if (pthread_join(thread, &pres)) return ThreadFault.JOIN_FAILED!; + if (pthread_join(thread, &pres)) return ThreadFault.JOIN_FAILED?; return (int)(iptr)pres; } @@ -219,21 +219,21 @@ struct PosixThreadData @private fn void! native_sleep_nano(ulong nano) { - TimeSpec to = { .s = 0, .ns = nano }; - if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED!; + TimeSpec to = { .s = 0, .ns = (CLong)nano }; + if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED?; } fn void! native_sleep_ms(ulong ms) { - TimeSpec to = { .s = ms / 1000, .ns = (ms % 1000) * 1000_000 }; - if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED!; + TimeSpec to = { .s = (Time_t)(ms / 1000), .ns = (CLong)((ms % 1000) * 1000_000) }; + if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED?; } fn void! native_sleep(double s) { - ulong si = (ulong)s; - TimeSpec to = { .s = si, .ns = (ulong)((s - si) * 1000_000_000) }; - if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED!; + Time_t si = (Time_t)s; + TimeSpec to = { .s = si, .ns = (CLong)((s - si) * 1000_000_000) }; + if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED?; } $endif \ 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 594a96d36..1bd27c680 100644 --- a/lib/std/threads/os/thread_win32.c3 +++ b/lib/std/threads/os/thread_win32.c3 @@ -76,7 +76,7 @@ fn void! NativeMutex.init(NativeMutex* mtx, MutexType type) win32_InitializeCriticalSection(&(mtx.critical_section)); return; } - if (!(mtx.handle = win32_CreateMutex(null, false, null))) return ThreadFault.INIT_FAILED!; + if (!(mtx.handle = win32_CreateMutex(null, false, null))) return ThreadFault.INIT_FAILED?; } fn void! NativeMutex.destroy(NativeMutex* mtx) @@ -86,7 +86,7 @@ fn void! NativeMutex.destroy(NativeMutex* mtx) win32_DeleteCriticalSection(&mtx.critical_section); return; } - if (!win32_CloseHandle(mtx.handle)) return ThreadFault.DESTROY_FAILED!; + if (!win32_CloseHandle(mtx.handle)) return ThreadFault.DESTROY_FAILED?; } fn void! NativeMutex.lock(NativeMutex* mtx) @@ -103,7 +103,7 @@ fn void! NativeMutex.lock(NativeMutex* mtx) break; case WAIT_ABANDONED: default: - return ThreadFault.LOCK_FAILED!; + return ThreadFault.LOCK_FAILED?; } } @@ -125,10 +125,10 @@ fn void! NativeMutex.lock_timeout(NativeMutex* mtx, uint ms) case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: - return ThreadFault.LOCK_TIMEOUT!; + return ThreadFault.LOCK_TIMEOUT?; case WAIT_ABANDONED: default: - return ThreadFault.LOCK_FAILED!; + return ThreadFault.LOCK_FAILED?; } if (!mtx.recursive) { @@ -165,7 +165,7 @@ fn void! NativeMutex.unlock(NativeMutex* mtx) win32_LeaveCriticalSection(&mtx.critical_section); return; } - if (!win32_ReleaseMutex(mtx.handle)) return ThreadFault.UNLOCK_FAILED!; + if (!win32_ReleaseMutex(mtx.handle)) return ThreadFault.UNLOCK_FAILED?; } const int CONDITION_EVENT_ONE = 0; @@ -179,14 +179,14 @@ fn void! NativeConditionVariable.init(NativeConditionVariable* cond) if (!cond.event_one) { cond.event_all = (Win32_HANDLE)0; - return ThreadFault.INIT_FAILED!; + return ThreadFault.INIT_FAILED?; } cond.event_all = win32_CreateEventA(null, true, false, null); if (!cond.event_all) { win32_CloseHandle(cond.event_one); cond.event_one = (Win32_HANDLE)0; - return ThreadFault.INIT_FAILED!; + return ThreadFault.INIT_FAILED?; } } @@ -202,7 +202,7 @@ fn void! NativeConditionVariable.signal(NativeConditionVariable* cond) win32_EnterCriticalSection(&cond.waiters_count_lock); bool have_waiters = cond.waiters_count > 0; win32_LeaveCriticalSection(&cond.waiters_count_lock); - if (have_waiters && !win32_SetEvent(cond.event_one)) return ThreadFault.SIGNAL_FAILED!; + if (have_waiters && !win32_SetEvent(cond.event_one)) return ThreadFault.SIGNAL_FAILED?; } fn void! NativeConditionVariable.broadcast(NativeConditionVariable* cond) @@ -210,7 +210,7 @@ fn void! NativeConditionVariable.broadcast(NativeConditionVariable* cond) win32_EnterCriticalSection(&cond.waiters_count_lock); bool have_waiters = cond.waiters_count > 0; win32_LeaveCriticalSection(&cond.waiters_count_lock); - if (have_waiters && !win32_SetEvent(cond.event_all)) return ThreadFault.SIGNAL_FAILED!; + if (have_waiters && !win32_SetEvent(cond.event_all)) return ThreadFault.SIGNAL_FAILED?; } fn void! timedwait(NativeConditionVariable* cond, NativeMutex* mtx, uint timeout) @private @@ -219,17 +219,17 @@ fn void! timedwait(NativeConditionVariable* cond, NativeMutex* mtx, uint timeout cond.waiters_count++; win32_LeaveCriticalSection(&cond.waiters_count_lock); - mtx.unlock()?; + mtx.unlock()!; uint result = win32_WaitForMultipleObjects(2, &cond.events, false, timeout); switch (result) { case WAIT_TIMEOUT: - mtx.lock()?; - return ThreadFault.WAIT_TIMEOUT!; + mtx.lock()!; + return ThreadFault.WAIT_TIMEOUT?; case WAIT_FAILED: - mtx.lock()?; - return ThreadFault.WAIT_FAILED!; + mtx.lock()!; + return ThreadFault.WAIT_FAILED?; default: break; } @@ -244,12 +244,12 @@ fn void! timedwait(NativeConditionVariable* cond, NativeMutex* mtx, uint timeout { if (!win32_ResetEvent(cond.event_all)) { - mtx.lock()?; - return ThreadFault.WAIT_FAILED!; + mtx.lock()!; + return ThreadFault.WAIT_FAILED?; } } - mtx.lock()?; + mtx.lock()!; } fn void! NativeConditionVariable.wait(NativeConditionVariable* cond, NativeMutex* mtx) @inline @@ -264,12 +264,12 @@ fn void! NativeConditionVariable.wait_timeout(NativeConditionVariable* cond, Nat fn void! NativeThread.create(NativeThread* thread, ThreadFn func, void* args) { - if (!(*thread = win32_CreateThread(null, 0, func, args, 0, null))) return ThreadFault.INIT_FAILED!; + if (!(*thread = win32_CreateThread(null, 0, func, args, 0, null))) return ThreadFault.INIT_FAILED?; } fn void! NativeThread.detach(NativeThread thread) @inline { - if (!win32_CloseHandle(thread)) return ThreadFault.DETACH_FAILED!; + if (!win32_CloseHandle(thread)) return ThreadFault.DETACH_FAILED?; } @@ -313,8 +313,8 @@ fn void NativeOnceFlag.call_once(NativeOnceFlag* flag, OnceFn func) fn void! NativeThread.join(NativeThread thread, int *res) { - if (win32_WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) return ThreadFault.JOIN_FAILED!; - if (!win32_GetExitCodeThread(thread, (uint*)res)) return ThreadFault.JOIN_FAILED!; + if (win32_WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) return ThreadFault.JOIN_FAILED?; + if (!win32_GetExitCodeThread(thread, (uint*)res)) return ThreadFault.JOIN_FAILED?; defer win32_CloseHandle(thread); } @@ -333,7 +333,7 @@ fn bool NativeThread.equals(NativeThread this, NativeThread other) **/ fn void! native_sleep_ms(ulong ms) { - if (win32_SleepEx((uint)ms, true) == WAIT_IO_COMPLETION) return ThreadFault.INTERRUPTED!; + if (win32_SleepEx((uint)ms, true) == WAIT_IO_COMPLETION) return ThreadFault.INTERRUPTED?; } fn void! native_sleep(double s) diff --git a/lib/std/time/clock.c3 b/lib/std/time/clock.c3 new file mode 100644 index 000000000..00901be8f --- /dev/null +++ b/lib/std/time/clock.c3 @@ -0,0 +1,23 @@ +module std::time::clock; + +fn Clock now() +{ +$if ($defined(native_clock)) + return os::native_clock(); +$else + return 0; +$endif +} + +fn NanoDuration Clock.mark(Clock* this) +{ + Clock mark = now(); + NanoDuration diff = (NanoDuration)(mark - *this); + *this = mark; + return diff; +} + +fn NanoDuration Clock.to_now(Clock this) +{ + return (NanoDuration)(now() - this); +} \ No newline at end of file diff --git a/lib/std/time/datetime.c3 b/lib/std/time/datetime.c3 new file mode 100644 index 000000000..0daa2f78b --- /dev/null +++ b/lib/std/time/datetime.c3 @@ -0,0 +1,175 @@ +module std::time::datetime; +import libc; + +fn DateTime now() +{ + return from_time(time::now()); +} + +/** + * @require day >= 1 && day < 32 + * @require hour >= 0 && hour < 24 + * @require min >= 0 && min < 60 + * @require sec >= 0 && sec < 60 + * @require us >= 0 && us < 999_999 + **/ +fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0) +{ + DateTime dt @noinit; + dt.set_date(year, month, day, hour, min, sec, us) @inline; + return dt; +} + +fn TzDateTime DateTime.to_local(DateTime* this) +{ + Tm tm @noinit; + Time_t time_t = (Time_t)this.time.to_seconds(); + libc::localtime_r(&time_t, &tm); + TzDateTime dt; + dt.usec = (int)((long)this.time % (long)time::MICROSECONDS_PER_SECOND); + dt.sec = (char)tm.tm_sec; + dt.min = (char)tm.tm_min; + dt.hour = (char)tm.tm_hour; + dt.day = (char)tm.tm_mday; + dt.month = (Month)tm.tm_mon; + dt.year = tm.tm_year + 1900; + dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday + 1; + dt.year_day = (ushort)tm.tm_yday; + dt.time = this.time; +$if ($defined(tm.tm_gmtoff)) + dt.gmt_offset = (int)tm.tm_gmtoff; +$else + $assert($defined(libc::_get_timezone)); + CLong timezone; + libc::_get_timezone(&timezone); + dt.gmt_offset = (int)-timezone; +$endif + return dt; +} + +/** + * @require day >= 1 && day < 32 + * @require hour >= 0 && hour < 24 + * @require min >= 0 && min <= 60 + * @require sec >= 0 && sec < 60 + * @require us >= 0 && us < 999_999 + **/ +fn void DateTime.set_date(DateTime *this, int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0) +{ + Tm tm; + tm.tm_sec = sec; + tm.tm_min = min; + tm.tm_hour = hour; + tm.tm_mon = month.ordinal; + tm.tm_mday = day; + tm.tm_year = year - 1900; + Time_t time = libc::timegm(&tm); + this.set_time((Time)(time * (long)time::MICROSECONDS_PER_SECOND + us)); +} + +fn void DateTime.set_time(DateTime* this, Time time) +{ + Tm tm @noinit; + Time_t time_t = (Time_t)time.to_seconds(); + libc::gmtime_r(&time_t, &tm); + this.usec = (int)((long)time % (long)time::MICROSECONDS_PER_SECOND); + this.sec = (char)tm.tm_sec; + this.min = (char)tm.tm_min; + this.hour = (char)tm.tm_hour; + this.day = (char)tm.tm_mday; + this.month = (Month)tm.tm_mon; + this.year = tm.tm_year + 1900; + this.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday + 1; + this.year_day = (ushort)tm.tm_yday; + this.time = time; +} + +fn DateTime DateTime.add_seconds(DateTime* date, int seconds) => from_time(date.time.add_seconds(seconds)); +fn DateTime DateTime.add_minutes(DateTime* date, int minutes) => from_time(date.time.add_minutes(minutes)); +fn DateTime DateTime.add_hours(DateTime* date, int hours) => from_time(date.time.add_hours(hours)); +fn DateTime DateTime.add_days(DateTime* date, int days) => from_time(date.time.add_days(days)); +fn DateTime DateTime.add_weeks(DateTime* date, int weeks) => from_time(date.time.add_weeks(weeks)); + +fn DateTime DateTime.add_years(DateTime* date, int years) +{ + if (!years) return *date; + return from_date(date.year + years, date.month, date.day, date.hour, date.min, date.sec, date.usec); +} + +fn DateTime DateTime.add_months(DateTime* date, int months) +{ + if (months == 0) return *date; + int year = date.year; + int month = date.month.ordinal; + switch + { + case months % 12 == 0: + year += months / 12; + case months < 0: + month += months % 12; + year += months / 12; + if (month < 0) + { + year--; + month += 12; + } + default: + month += months; + year += month / 12; + month %= 12; + } + return from_date(year, (Month)month, date.day, date.hour, date.min, date.sec, date.usec); +} + +fn DateTime from_time(Time time) +{ + DateTime dt @noinit; + dt.set_time(time) @inline; + return dt; +} + +fn Time DateTime.to_time(DateTime* this) @inline +{ + return this.time; +} + +fn bool DateTime.after(DateTime* this, DateTime compare) +{ + return this.time > compare.time; +} + +fn bool DateTime.before(DateTime* this, DateTime compare) +{ + return this.time < compare.time; +} + +fn int DateTime.compare_to(DateTime* this, DateTime compare) +{ + switch + { + case this.time > compare.time: return 1; + case this.time < compare.time: return -1; + default: return 0; + } +} + +fn int DateTime.diff_years(DateTime *to, DateTime from) +{ + int year_diff = to.year - from.year; + switch + { + case year_diff < 0: return -from.diff_years(*to); + case year_diff == 0: return 0; + } + if (to.year_day < from.year_day) year_diff--; + return year_diff; +} + +fn double DateTime.diff_sec(DateTime to, DateTime from) +{ + return (double)to.time.diff_us(from.time) / (double)time::MICROSECONDS_PER_SECOND; +} +fn TimeDuration DateTime.diff_us(DateTime to, DateTime from) +{ + return to.time.diff_us(from.time); +} \ No newline at end of file diff --git a/lib/std/time/os/time_darwin.c3 b/lib/std/time/os/time_darwin.c3 new file mode 100644 index 000000000..a9f5174d7 --- /dev/null +++ b/lib/std/time/os/time_darwin.c3 @@ -0,0 +1,28 @@ +module std::time::os; + +$if (env::os_is_darwin()) + +struct Darwin_mach_timebase_info +{ + uint numer; + uint denom; +} + +typedef Darwin_mach_timebase_info_t = Darwin_mach_timebase_info; +typedef Darwin_mach_timebase_info_data_t = Darwin_mach_timebase_info; + +extern fn void mach_timebase_info(Darwin_mach_timebase_info_data_t* timebase); +extern fn ulong mach_absolute_time(); + +fn Clock native_clock() +{ + static Darwin_mach_timebase_info_data_t timebase; + if (!timebase.denom) + { + mach_timebase_info(&timebase); + } + return (Clock)(mach_absolute_time() * timebase.numer / timebase.denom); +} + + +$endif diff --git a/lib/std/time/os/time_posix.c3 b/lib/std/time/os/time_posix.c3 new file mode 100644 index 000000000..407ec9c59 --- /dev/null +++ b/lib/std/time/os/time_posix.c3 @@ -0,0 +1,88 @@ +module std::time::os; +import libc; + +$if (env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE) + +$switch (env::OS_TYPE) +$case OPENBSD: +const CLOCK_REALTIME = 0; +const CLOCK_PROCESS_CPUTIME_ID = 2; +const CLOCK_MONOTONIC = 3; +const CLOCK_THREAD_CPUTIME_ID = 4; +const CLOCK_UPTIME = 5; +const CLOCK_BOOTTIME = 6; +$case FREEBSD: +const CLOCK_REALTIME = 0; +const CLOCK_VIRTUAL = 1; +const CLOCK_PROF = 2; +const CLOCK_MONOTONIC = 4; +const CLOCK_UPTIME = 5; +const CLOCK_UPTIME_PRECISE = 7; +const CLOCK_UPTIME_FAST = 8; +const CLOCK_REALTIME_PRECISE = 9; +const CLOCK_REALTIME_FAST = 10; +const CLOCK_MONOTONIC_PRECISE = 11; +const CLOCK_MONOTONIC_FAST = 12; +const CLOCK_SECOND = 13; +const CLOCK_THREAD_CPUTIME_ID = 14; +const CLOCK_PROCESS_CPUTIME_ID = 15; +const CLOCK_BOOTTIME = CLOCK_UPTIME; +const CLOCK_REALTIME_COARSE = CLOCK_REALTIME_FAST; +const CLOCK_MONOTONIC_COARSE = CLOCK_MONOTONIC_FAST; +$case NETBSD: +const CLOCK_REALTIME = 0; +const CLOCK_VIRTUAL = 1; +const CLOCK_PROF = 2; +const CLOCK_MONOTONIC = 3; +const CLOCK_THREAD_CPUTIME_ID = 0x20000000; +const CLOCK_PROCESS_CPUTIME_ID = 0x40000000; +$case WASI: +// Not implemented +const CLOCK_REALTIME = 0; +const CLOCK_MONOTONIC = 0; +$case MACOS: +$case TVOS: +$case IOS: +$case WATCHOS: +const CLOCK_REALTIME = 0; +const CLOCK_MONOTONIC = 6; +const CLOCK_MONOTONIC_RAW = 4; +const CLOCK_MONOTONIC_RAW_APPROX = 5; +const CLOCK_UPTIME_RAW = 8; +const CLOCK_UPTIME_RAW_APPROX = 9; +const CLOCK_PROCESS_CPUTIME_ID = 12; +const CLOCK_THREAD_CPUTIME_ID = 16; +$case LINUX: +$default: +const CLOCK_REALTIME = 0; +const CLOCK_MONOTONIC = 1; +const CLOCK_PROCESS_CPUTIME_ID = 2; +const CLOCK_THREAD_CPUTIME_ID = 3; +const CLOCK_MONOTONIC_RAW = 4; +const CLOCK_REALTIME_COARSE = 5; +const CLOCK_MONOTONIC_COARSE = 6; +const CLOCK_BOOTTIME = 7; +const CLOCK_REALTIME_ALARM = 8; +const CLOCK_BOOTTIME_ALARM = 9; +const CLOCK_TAI = 11; +$endswitch + +extern fn void clock_gettime(int type, TimeSpec *time); + +fn Time native_timestamp() +{ + TimeSpec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (Time)(ts.s * 1_000_000i64 + ts.ns / 1_000i64); +} + +$if (!env::os_is_darwin()) +fn Clock native_clock() +{ + TimeSpec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (Clock)((ulong)ts.s * 1_000_000_000u64 + (ulong)ts.ns); +} +$endif + +$endif diff --git a/lib/std/time/os/time_win32.c3 b/lib/std/time/os/time_win32.c3 new file mode 100644 index 000000000..5cb1a4776 --- /dev/null +++ b/lib/std/time/os/time_win32.c3 @@ -0,0 +1,33 @@ +module std::time::os; +import std::os::win32; + +$if (env::os_is_win32() && env::COMPILER_LIBC_AVAILABLE) + +extern fn void win32_GetSystemTimeAsFileTime(Win32_FILETIME* time) @extern("GetSystemTimeAsFileTime"); +extern fn Win32_BOOL win32_QueryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @extern("QueryPerformanceFrequency"); +extern fn Win32_BOOL win32_QueryPerformanceCounter(Win32_LARGE_INTEGER* lpPerformanceCount) @extern("QueryPerformanceCounter"); + +const ulong WINDOWS_TICK_US @local = 10; +const ulong WIN_TO_UNIX_EPOCH_US @local = 116444736000000000u64 / WINDOWS_TICK_US; + +fn Clock native_clock() +{ + static Win32_LARGE_INTEGER freq; + if (!freq.quadPart) + { + if (!win32_QueryPerformanceFrequency(&freq)) return 0; + } + Win32_LARGE_INTEGER counter @noinit; + if (!win32_QueryPerformanceCounter(&counter)) return 0; + return (Clock)counter.quadPart; +} + +fn Time native_timestamp() +{ + Win32_FILETIME ft @noinit; + win32_GetSystemTimeAsFileTime(&ft); + ulong result = (ulong)ft.dwHighDateTime << 32 | ft.dwLowDateTime; + return (Time)(result / WINDOWS_TICK_US - WIN_TO_UNIX_EPOCH_US); +} + +$endif \ No newline at end of file diff --git a/lib/std/time/time.c3 b/lib/std/time/time.c3 new file mode 100644 index 000000000..2f1144853 --- /dev/null +++ b/lib/std/time/time.c3 @@ -0,0 +1,87 @@ +module std::time; + +typedef Time @inline = distinct long; +typedef TimeDuration @inline = distinct long; +typedef Clock @inline = distinct ulong; +typedef NanoDuration @inline = distinct long; + +const TimeDuration MICROSECONDS_PER_SECOND = 1_000_000; +const TimeDuration MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * 60; +const TimeDuration MICROSECONDS_PER_HOUR = MICROSECONDS_PER_MINUTE * 60; +const TimeDuration MICROSECONDS_PER_DAY = MICROSECONDS_PER_HOUR * 24; +const TimeDuration MICROSECONDS_PER_WEEK = MICROSECONDS_PER_DAY * 7; + +struct DateTime +{ + int usec; + char sec; + char min; + char hour; + char day; + Month month; + Weekday weekday; + int year; + ushort year_day; + Time time; +} + +struct TzDateTime +{ + inline DateTime date_time; + int gmt_offset; +} + +enum Weekday : char +{ + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY, +} + +enum Month : char +{ + JANUARY, + FEBRUARY, + MARCH, + APRIL, + MAY, + JUNE, + JULY, + AUGUST, + SEPTEMBER, + OCTOBER, + NOVEMBER, + DECEMBER +} + + +fn Time now() +{ +$if ($defined(native_timestamp)) + return os::native_timestamp(); +$else + return 0; +$endif +} + +fn Time Time.add_seconds(Time time, long seconds) => time + (Time)(seconds * (long)MICROSECONDS_PER_SECOND); +fn Time Time.add_minutes(Time time, long minutes) => time + (Time)(minutes * (long)MICROSECONDS_PER_MINUTE); +fn Time Time.add_hours(Time time, long hours) => time + (Time)(hours * (long)MICROSECONDS_PER_HOUR); +fn Time Time.add_days(Time time, long days) => time + (Time)(days * (long)MICROSECONDS_PER_DAY); +fn Time Time.add_weeks(Time time, long weeks) => time + (Time)(weeks * (long)MICROSECONDS_PER_WEEK); +fn double Time.to_seconds(Time time) => (long)time / (double)MICROSECONDS_PER_SECOND; +fn TimeDuration Time.diff_us(Time time, Time other) => (TimeDuration)(time - other); +fn double Time.diff_sec(Time time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_SECOND; +fn double Time.diff_min(Time time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_MINUTE; +fn double Time.diff_hour(Time time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_HOUR; +fn double Time.diff_days(Time time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_DAY; +fn double Time.diff_weeks(Time time, Time other) => (long)time.diff_us(other) / (double)MICROSECONDS_PER_WEEK; + +fn double NanoDuration.to_sec(NanoDuration nd) => (double)nd / 1_000_000_000.0; +fn long NanoDuration.to_ms(NanoDuration nd) => (long)nd / 1_000_000; +fn TimeDuration NanoDuration.to_duration(NanoDuration nd) => (TimeDuration)nd / 1_000; +fn NanoDuration TimeDuration.to_nano(TimeDuration td) => (NanoDuration)td * 1_000; \ No newline at end of file diff --git a/releasenotes.md b/releasenotes.md index a8fbc2f1a..2e80aa9d0 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,4 +1,170 @@ -Release Notes +# C3C Release Notes + +## 0.5.0 Change List + +### Changes / improvements +- Dropped support for LLVM 13-14. +- Updated grammar and lexer definition. +- Removal of `$elif`. +- Empty fault definitions is now an error. +- Better errors on incorrect bitstruct syntax. +- Internal use wildcard type rather than optional wildcard. +- Experimental scaled vector type removed. +- Disallow parameterize attributes without parameters eg `define @Foo() = { @inline }`. +- Handle `@optreturn` contract, renamed `@return!`. +- Restrict interface style functions. +- Optional propagation and assignment '!' and '?' are flipped. +- Add `l` suffix (alias for i64). +- Allow getting the underlying type of anyfault. +- De-duplicate string constants. +- Change @extname => @extern. +- `define Type = int` is replaced by `typedef Type = int`. +- LLVM "wrapper" library compilation is exception free. +- `private` is replaced by attribute `@private`. +- Addition of `@local` for file local visibility. +- Addition of `@public` for overriding default visibility. +- Default visibility can be overridden per module compile unit. Eg `module foo @private`. +- Addition of unary `+`. +- Remove the `:` and `;` used in $if, $switch etc. +- Faults have an ordinal. +- Generic module contracts. +- Type inference on enum comparisons, e.g `foo_enum == ABC`. +- Allow {} to initialize basic types. +- String literals default to `String`. +- More const modification detection. +- C3L zip support. +- Support printing object files. +- Downloading of libraries using vendor "fetch". +- Structural casts removed. +- Added "native" option for vector capability. +- `$$shufflevector` replaced with `$$swizzle` and `$$swizzle2`. +- Builtin swizzle accessors. +- Lambdas, e.g `a = int(x, y) => x + y`. +- $$FILEPATH builtin constant. +- `variant` renamed `any`. +- `anyerr` renamed `anyfault`. +- Added `$$wasm_memory_size` and `$$wasm_memory_grow` builtins. +- Add "link-args" for project. +- Possible to suppress entry points using `--no-entry`. +- Added `memory-env` option. +- Use the .wasm extension on WASM binaries. +- Update precedence clarification rules for ^|&. +- Support for casting any expression to `void`. +- Win 32-bit processor target removed. +- Insert null-check for contracts declaring & params. +- Support user defined attributes in generic modules. +- `--strip-unused` directive for small binaries. +- `$$atomic_store` and `$$atomic_load` added. +- `usz`/`isz` replaces `usize` and `isize`. +- `@export` attribute to determine what is visible in precompiled libraries. +- Disallow obviously wrong code returning a pointer to a stack variable. +- Add &^| operations for bitstructs. +- `@noinit` replaces `= void` to opt-out of implicit zeroing. +- Multiple declarations are now allowed in most places, eg `int a, b;`. +- Allow simplified (boolean) bitstruct definitions. +- Allow `@test` to be placed on module declarations. +- Updated name mangling for non-exports. +- `defer catch` and `defer try` statements added. +- Better errors from `$assert`. +- `@deprecated` attribute added. +- Allow complex array length inference, eg `int[*][2][*] a = ...`. +- Cleanup of cast code. +- Removal of `generic` keyword. +- Remove implicit cast enum <-> int. +- Allow enums to use a distinct type as the backing type. +- Update addition and subtraction on enums. +- `@ensure` checks only non-optional results. + +### Stdlib changes +- Stdlib updates to string. +- Additions to `List` +- Added dstringwriter. +- Improved printf formatting. +- is_finite/is_nam/is_inf added. +- OnStack allocator to easily allocate a stack buffer. +- File enhancements: mkdir, rmdir, chdir. +- Path type for file path handling. +- Distinct `String` type. +- VarString replaced by DString. +- Removal of std::core::str. +- JSON parser and general Object type. +- Addition of `EnumMap`. +- RC4 crypto. +- Matrix identity macros. +- compare_exchange added. +- `printfln` and `println` renamed `printfn` and `printn`. +- Support of roundeven. +- Added easings. +- Updated complex/matrix, added quaternion maths. +- Improved support for freestanding. +- Improved windows main support, with @winmain annotations. +- `SimpleHeapAllocator` added. +- Added win32 standard types. +- Added `saturated` math. +- Added `@expect`, `@unlikely` and `@likely` macros. +- Temp allocator uses memory-env to determine starting size. +- Temp allocator is now accessed using `mem::temp()`, heap allocator using `mem::heap()`. +- Float parsing added. +- Additions to std::net, ipv4/ipv6 parsing. +- Stream api. +- Random api. +- Sha1 hash function. +- Extended enumset functionality. +- Updated malloc/calloc/realloc/free removing old helper functions. +- Added TrackingAllocator. +- Add checks to prevent incorrect alignment on malloc. +- Updated clamp. +- Added `Clock` and `DateTime`. + +### Fixes +- Fixes to the x64 ABI. +- Updates to how variadics are implemented. +- Fixes to shift checks. +- Fixes to string parsing. +- Disallow trailing ',' in function parameter list. +- Fixed errors on flexible array slices. +- Fix of `readdir` issues on macOS. +- Fix to slice assignment of distinct types. +- Fix of issue casting subarrays to distinct types. +- Fixes to `split`, `rindex_of`. +- List no longer uses the temp allocator by default. +- Remove test global when not in test mode. +- Fix sum/product on floats. +- Fix error on void! return of macros. +- Removed too permissive casts on subarrays. +- Using C files correctly places objects in the build folder. +- Fix of overaligned deref. +- Fix negating a float vector. +- Fix where $typeof(x) { ... } would not be a valid compound literal. +- Fix so that using `var` in `if (var x = ...)` works correctly. +- Fix int[] -> void* casts. +- Fix in utf8to16 conversions. +- Updated builtin checking. +- Reduce formatter register memory usage. +- Fixes to the "any" type. +- Fix bug in associated values. +- More RISC-V tests and fixes to the ABI. +- Fix issue with hex floats assumed being double despite `f` suffix. +- Fix of the `tan` function. +- Fixes to the aarch64 ABI when passing invalid vectors. +- Fix creating typed compile time variables. +- Fix bug in !floatval codegen. +- Fix of visibility issues for generic methods. +- Fixes to `$include`. +- Fix of LLVM codegen for optionals in certain cases. +- Fix of `$vasplat` when invoked repeatedly. +- Fix to `$$DATE`. +- Fix of attributes on nested bitstructs. +- Fix comparing const values > 64 bits. +- Defer now correctly invoked in expressions like `return a > 0 ? Foo.ABC! : 1`. +- Fix conversion in `if (int x = foo())`. +- Delay C ABI lowering until requested to prevent circular dependencies. +- Fix issue with decls accidentally invalidated during `$checked` eval. +- Fold optional when casting slice to pointer. +- Fixed issue when using named arguments after varargs. +- Fix bug initializing nested struct/unions. +- Fix of bool -> vector cast. +- Correctly widen C style varargs for distinct types and optionals. ## 0.4.0 Change List diff --git a/resources/examples/base64.c3 b/resources/examples/base64.c3 index 31002a6b4..9a935d886 100644 --- a/resources/examples/base64.c3 +++ b/resources/examples/base64.c3 @@ -89,7 +89,7 @@ fn int! decode(String in, char* out, int* invalid_char_index = null) if (c == ERR) { if (invalid_char_index) *invalid_char_index = i; - return DecodingError.INVALID_CHARACTER!; + return DecodingError.INVALID_CHARACTER?; } @@ -128,7 +128,7 @@ fn void! main() printf("Result: %s\n", &buffer); char *to_decode = "aGVsbG8gd29ybGRcMA=="; char[*] result = b64"aGVsbG8gd29ybGRcMA=="; - decode((String)to_decode[0..19], &buffer)?; + decode((String)to_decode[0..19], &buffer)!; printf("Result: %s\n", &buffer); printf("Result direct: %.*s\n", 13, &result); } \ No newline at end of file diff --git a/resources/examples/brainfk.c3 b/resources/examples/brainfk.c3 index e9ed4ec2a..516b3b977 100644 --- a/resources/examples/brainfk.c3 +++ b/resources/examples/brainfk.c3 @@ -12,7 +12,7 @@ fault InterpretError fn void! print_error(usz pos, String err) { io::printfn("Error at %s: %s", pos, err); - return InterpretError.INTEPRET_FAILED!; + return InterpretError.INTEPRET_FAILED?; } fn void! brainf(String program) @@ -81,5 +81,5 @@ fn void! main() >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<] <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<- ]`; - brainf(program)?; + brainf(program)!; } \ No newline at end of file diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 1e44d6f51..93adb794e 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -3,11 +3,11 @@ import libc; import std::io; struct Doc { Head *head; } -struct Head { VarString* title; } +struct Head { DString* title; } struct Summary { - VarString* title; + DString* title; bool ok; } @@ -44,7 +44,7 @@ fn bool contains(String haystack, String needle) macro @dupe(value) { - $typeof(&value) temp = malloc_checked($typeof(value))?; + $typeof(&value) temp = malloc_checked($typeof(value))!; *temp = value; return temp; } @@ -56,11 +56,11 @@ fault ReadError fn Doc! readDoc(String url) { - if (contains(url, "fail")) return ReadError.BAD_READ!; + if (contains(url, "fail")) return ReadError.BAD_READ?; if (contains(url, "head-missing")) return { .head = null }; if (contains(url, "title-missing")) return { @dupe(Head { .title = null }) }; - if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((VarString)null) }) }; - VarString str; + if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((DString)null) }) }; + DString str; str.printf("Title of %s", url); return { @dupe(Head { .title = @dupe(str) }) }; } @@ -96,9 +96,9 @@ fault TitleResult fn bool! isTitleNonEmpty(Doc doc) { - if (!doc.head) return TitleResult.TITLE_MISSING!; - VarString* head = doc.head.title; - if (!head) return TitleResult.TITLE_MISSING!; + if (!doc.head) return TitleResult.TITLE_MISSING?; + DString* head = doc.head.title; + if (!head) return TitleResult.TITLE_MISSING?; return head.len() > 0; } @@ -133,7 +133,7 @@ fn void main() bool! has_title = readWhetherTitleNonEmpty(url); // This looks a bit less than elegant, but as you see it's mostly due to having to // use printf here. - io::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? (catch? has_title).nameof, has_title ?? false); + io::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? (@catchof(has_title)).nameof, has_title ?? false); }; dynamic_arena.reset(); } diff --git a/resources/examples/contextfree/cleanup.c3 b/resources/examples/contextfree/cleanup.c3 new file mode 100644 index 000000000..bdb1c7ea6 --- /dev/null +++ b/resources/examples/contextfree/cleanup.c3 @@ -0,0 +1,52 @@ +import std::io; + + +struct Resource +{ + String name; +} + +fault Error +{ + WELCOME_TO_YOUR_DOOM +} + +fn Resource! resource_init(String name) +{ + io::printfn("open %s", name); + return { name }; +} + +fn void Resource.deinit(Resource this) => io::printfn("close %s", this.name); + +macro void! @open_with(String name; @body(Resource resource)) +{ + Resource resource = resource_init(name)!; + defer { + io::printn("Using open_with to close"); + resource.deinit(); + } + @body(resource); +} + +fn Resource! prep_out(String out_name, String[] prep_names) +{ + Resource writer = resource_init(out_name)!; // Rethrow the optional result + defer catch writer.deinit(); + foreach (name : prep_names) + { + @open_with(name; Resource reader) + { + io::printfn("use %s", reader.name); + // if (true) return Error.WELCOME_TO_YOUR_DOOM?; + }!; + } + return writer; +} + +fn void! main() +{ + Resource writer = prep_out("out", String[] { "a", "b"})!; + defer writer.deinit(); + io::printn("use out"); +} \ No newline at end of file diff --git a/resources/examples/contextfree/guess_number.c3 b/resources/examples/contextfree/guess_number.c3 index 6a1565a55..a1086e1af 100644 --- a/resources/examples/contextfree/guess_number.c3 +++ b/resources/examples/contextfree/guess_number.c3 @@ -23,10 +23,10 @@ int err_count = 0; fn int! askGuess(int high) { libc::printf("Guess a number between 1 and %d: ", high); - String text = readLine()?; + String text = readLine()!; char* end = null; int value = (int)libc::strtol(text.ptr, &end, 10); - if (end && end[0] >= ' ') return InputResult.NOT_AN_INT!; + if (end && end[0] >= ' ') return InputResult.NOT_AN_INT?; return value; } @@ -34,7 +34,7 @@ fn String! readLine() { char* chars = tmalloc(1024); isz loaded = getline(&chars, &&(usz)1023, libc::stdin()); - if (loaded < 0) return InputResult.FAILED_TO_READ!; + if (loaded < 0) return InputResult.FAILED_TO_READ?; chars[loaded] = 0; return (String)chars[0..(loaded - 1)]; } @@ -44,7 +44,7 @@ fn int! askGuessMulti(int high) while (true) { int! result = askGuess(high); - if (catch? result == InputResult.NOT_AN_INT) + if (@catchof(result) == InputResult.NOT_AN_INT) { libc::printf("I didn't understand that.\n"); err_count++; @@ -59,7 +59,7 @@ fn void! Game.play(Game *game) { while (!game.done) { - int guess = askGuessMulti(game.high)?; + int guess = askGuessMulti(game.high)!; game.report(guess); game.update(guess); } diff --git a/resources/examples/load_world.c3 b/resources/examples/load_world.c3 index ef269c188..9c87b23aa 100644 --- a/resources/examples/load_world.c3 +++ b/resources/examples/load_world.c3 @@ -2,7 +2,7 @@ module load_world; import std::io; fn void! main() { - File f = file::open("examples/hello_world.txt", "rb")?; + File f = file::open("examples/hello_world.txt", "rb")!; defer f.close()!!; while (!f.eof()) { diff --git a/resources/examples/map.c3 b/resources/examples/map.c3 index b4d552489..c5855150c 100644 --- a/resources/examples/map.c3 +++ b/resources/examples/map.c3 @@ -35,17 +35,17 @@ fn void Map.init(Map *map, uint capacity = 128) fn Type! Map.valueForKey(Map *map, Key key) { - if (!map.map) return MapResult.KEY_NOT_FOUND!; + if (!map.map) return MapResult.KEY_NOT_FOUND?; uint hash = key.hash(); usz pos = hash & map.mod; Entry* entry = &map.map[pos]; - if (!entry) return MapResult.KEY_NOT_FOUND!; + if (!entry) return MapResult.KEY_NOT_FOUND?; while (entry) { if (entry.hash == hash && entry.key == key) return entry.value; entry = entry.next; } - return MapResult.KEY_NOT_FOUND!; + return MapResult.KEY_NOT_FOUND?; } fn Type! Map.set(Map *map, Key key, Type value) @maydiscard @@ -67,7 +67,7 @@ fn Type! Map.set(Map *map, Key key, Type value) @maydiscard entry.value = value; entry.hash = hash; entry.key = key; - return MapResult.KEY_NOT_FOUND!; + return MapResult.KEY_NOT_FOUND?; } if (entry.hash == hash && entry.key == key) { @@ -87,7 +87,7 @@ fn Type! Map.set(Map *map, Key key, Type value) @maydiscard new.next = null; new.used = true; entry.next = new; - return MapResult.KEY_NOT_FOUND!; + return MapResult.KEY_NOT_FOUND?; } } diff --git a/resources/examples/nbodies.c3 b/resources/examples/nbodies.c3 index 919a25ca5..c15455b7d 100644 --- a/resources/examples/nbodies.c3 +++ b/resources/examples/nbodies.c3 @@ -144,7 +144,7 @@ fn void scale_bodies(Planet[] bodies, double scale) fn void main(String[] args) { - int n = args.len < 2 ? 50000000 : str::to_int(args[1])!!; + int n = args.len < 2 ? 50000000 : args[1].to_int()!!; Planet[] bodies = &planet_bodies; offset_momentum(bodies); diff --git a/resources/examples/plus_minus.c3 b/resources/examples/plus_minus.c3 index 0556cbd0c..2a75e23a3 100644 --- a/resources/examples/plus_minus.c3 +++ b/resources/examples/plus_minus.c3 @@ -13,9 +13,9 @@ fault TokenResult fn void main(String[] args) { // Grab a string from stdin - VarString s = io::stdin().getline(); + DString s = io::stdin().getline(); // Delete it at scope end [defer] - defer s.destroy(); + defer s.free(); // Grab the string as a slice. String numbers = s.str(); @@ -77,8 +77,8 @@ fn String! read_next(String* remaining) } // If it's a zero length token, return an optional result. - if (!len) return TokenResult.NO_MORE_TOKENS!; + if (!len) return TokenResult.NO_MORE_TOKENS?; // Otherwise create a slice from the pointer start and length. - return ptr_start[:len]; + return (String)ptr_start[:len]; } diff --git a/resources/examples/retry.c3 b/resources/examples/retry.c3 index e1332353c..ff921048b 100644 --- a/resources/examples/retry.c3 +++ b/resources/examples/retry.c3 @@ -9,14 +9,14 @@ fault TestErr fn int! eventually_succeed() { static int i = 0; - if (i++ < 3) return TestErr.NOPE!; + if (i++ < 3) return TestErr.NOPE?; return i * 3; } macro @retry(#function, int retries = 3) { var $Type = $typeof(#function); - anyerr e; + anyfault e; do { $Type! result = #function; diff --git a/resources/examples/spectralnorm.c3 b/resources/examples/spectralnorm.c3 index 6f8894b2a..782df4d65 100644 --- a/resources/examples/spectralnorm.c3 +++ b/resources/examples/spectralnorm.c3 @@ -43,7 +43,7 @@ fn void eval_AtA_times_u(double[] u, double[] atau, double[] x) fn void main(String[] args) { - int n = args.len == 2 ? str::to_int(args[1])!! : 2000; + int n = args.len == 2 ? args[1].to_int()!! : 2000; temparr = malloc(double, n); double[] u = malloc(double, n); double[] v = malloc(double, n); diff --git a/resources/examples/time.c3 b/resources/examples/time.c3 new file mode 100644 index 000000000..bf5d72ee8 --- /dev/null +++ b/resources/examples/time.c3 @@ -0,0 +1,17 @@ +import std::io; +import std::time; +import std::math; + +fn void main() +{ + Clock start = clock::now(); + DateTime d = datetime::now(); + io::printfn("Today is: %d-%02d-%02d %02d:%02d", d.year, d.month.ordinal + 1, d.day, d.hour, d.min); + io::printfn("Epoch timestamp: %d", d.time / 1_000); + TzDateTime td = d.to_local(); + int absolute_offset = math::abs(td.gmt_offset); + int offset_hour = absolute_offset / 3600; + int offset_min = (absolute_offset / 60) % 60; + io::printfn("Local time is: %d-%02d-%02d %02d:%02d:%02d %c%02d:%02d", td.year, td.month.ordinal + 1, td.day, td.hour, td.min, td.sec, td.gmt_offset < 0 ? '-' : '+', offset_hour, offset_min); + io::printfn("Executed the above in %d ns", start.to_now()); +} \ No newline at end of file diff --git a/resources/grammar/Makefile b/resources/grammar/Makefile new file mode 100644 index 000000000..97dd4e220 --- /dev/null +++ b/resources/grammar/Makefile @@ -0,0 +1,7 @@ +c3yacc: grammar.y c3.l + bison -d grammar.y; cc -c grammar.tab.c + flex c3.l; gcc -c lex.yy.c + cc -o c3yacc lex.yy.o grammar.tab.o + +clean: + rm -f c3yacc grammar.output *.o grammar.tab.* lex.yy.c \ No newline at end of file diff --git a/resources/grammar/c3.l b/resources/grammar/c3.l index 7876e9b28..efb5bbbf1 100644 --- a/resources/grammar/c3.l +++ b/resources/grammar/c3.l @@ -1,98 +1,196 @@ D [0-9] +DU [0-9_] UN [_] L [a-zA-Z_] AN [a-zA-Z_0-9] H [a-fA-F0-9] +HU [a-fA-F0-9_] UA [A-Z_0-9] +O [0-7] +B [0-1] DC [a-z] UC [A-Z] +CONST [_]*{UC}{UA}* +TYPE [_]*{UC}{UA}*{DC}{AN}* +IDENTIFIER [_]*{DC}{AN}* E [Ee][+-]?{D}+ +P [Pp][+-]?{D}+ +B64 [ \t\v\n\f]?[A-Za-z0-9+/][ \t\v\n\fA-Za-z0-9+/=]+ +HEX [ \t\v\n\f]?[A-Fa-f0-9][ \t\v\n\fA-Fa-f0-9]+ +INTTYPE [ui](8|16|32|64|128)? +REALTYPE [f](8|16|32|64|128)? +INT {D}(_*{D})* +HINT {H}(_*{H})* +OINT {O}(_*{O})* +BINT {B}(_*{B})* + +%x COMMENT RAW_STRING %{ #include -#include "y.tab.h" +#include "grammar.tab.h" void count(void); -void comment(void); +int comment_level = 0; %} %% -"/*" { comment(); } + +"$alignof" { count(); return(CT_ALIGNOF); } +"$assert" { count(); return(CT_ASSERT); } +"$case" { count(); return(CT_CASE); } +"$checks" { count(); return(CT_CHECKS); } +"$default" { count(); return(CT_DEFAULT); } +"$defined" { count(); return(CT_DEFINED); } +"$echo" { count(); return(CT_ECHO); } +"$else" { count(); return(CT_ELSE); } +"$endfor" { count(); return(CT_ENDFOR); } +"$endforeach" { count(); return(CT_ENDFOREACH); } +"$endif" { count(); return(CT_ENDIF); } +"$endswitch" { count(); return(CT_ENDSWITCH); } +"$eval" { count(); return(CT_EVAL); } +"$evaltype" { count(); return(CT_EVALTYPE); } +"$extnameof" { count(); return(CT_EXTNAMEOF); } +"$for" { count(); return(CT_FOR); } +"$foreach" { count(); return(CT_FOREACH); } +"$if" { count(); return(CT_IF); } +"$nameof" { count(); return(CT_NAMEOF); } +"$offsetof" { count(); return(CT_OFFSETOF); } +"$qnameof" { count(); return(CT_QNAMEOF); } +"$sizeof" { count(); return(CT_SIZEOF); } +"$stringify" { count(); return(CT_STRINGIFY); } +"$switch" { count(); return(CT_SWITCH); } +"$typefrom" { count(); return(CT_TYPEFROM); } +"$typeof" { count(); return(CT_TYPEOF); } +"$vaarg" { count(); return(CT_VAARG); } +"$vaconst" { count(); return(CT_VACONST); } +"$vacount" { count(); return(CT_VACOUNT); } +"$vaexpr" { count(); return(CT_VAEXPR); } +"$varef" { count(); return(CT_VAREF); } +"$vasplat" { count(); return(CT_VASPLAT); } +"$vatype" { count(); return(CT_VATYPE); } +"/*" { count(); BEGIN(COMMENT); } +{ + "/*" { count(); comment_level++; } + "*"+"/" { count(); if (comment_level) { comment_level--; } else { BEGIN(INITIAL); } } + "*"+ { count(); } + [^/*\n]+ { count(); } + [/] { count(); } + \n { count(); } +} +\/\/.* { count(); } +"any" { count(); return(ANY); } +"anyfault" { count(); return(ANYFAULT); } +"asm" { count(); return(ASM); } +"assert" { count(); return(ASSERT); } +"bitstruct" { count(); return(BITSTRUCT); } +"bool" { count(); return(BOOL); } "break" { count(); return(BREAK); } "case" { count(); return(CASE); } +"catch" { count(); return(CATCH); } "char" { count(); return(CHAR); } "const" { count(); return(CONST); } "continue" { count(); return(CONTINUE); } "default" { count(); return(DEFAULT); } +"defer" { count(); return(DEFER); } "define" { count(); return(DEFINE); } +"distinct" { count(); return(DISTINCT); } "do" { count(); return(DO); } "double" { count(); return(DOUBLE); } "else" { count(); return(ELSE); } "enum" { count(); return(ENUM); } +"extern" { count(); return(EXTERN); } +"false" { count(); return(FALSE); } +"fault" { count(); return(FAULT); } +"finalize" { count(); return(FINALIZE); } "float" { count(); return(FLOAT); } +"bfloat16" { count(); return(BFLOAT16); } +"float16" { count(); return(FLOAT16); } +"float128" { count(); return(FLOAT128); } +"fn" { count(); return(FN); } "for" { count(); return(FOR); } "foreach" { count(); return(FOREACH); } "foreach_r" { count(); return(FOREACH_R); } -"fn" { count(); return(FUNC); } +"ichar" { count(); return(ICHAR); } "if" { count(); return(IF); } +"import" { count(); return(IMPORT); } +"initialize" { count(); return(INITIALIZE); } +"inline" { count(); return(INLINE); } "int" { count(); return(INT); } -"uint" { count(); return(UINT); } +"int128" { count(); return(INT128); } +"iptr" { count(); return(IPTR); } +"isz" { count(); return(ISZ); } "long" { count(); return(LONG); } +"macro" { count(); return(MACRO); } +"module" { count(); return(MODULE); } "nextcase" { count(); return(NEXTCASE); } -"ulong" { count(); return(ULONG); } +"null" { count(); return(NUL); } "return" { count(); return(RETURN); } "short" { count(); return(SHORT); } -"ushort" { count(); return(USHORT); } -"fault" { count(); return(ERROR); } -"module" { count(); return(MODULE); } "struct" { count(); return(STRUCT); } +"static" { count(); return(STATIC); } "switch" { count(); return(SWITCH); } +"tlocal" { count(); return(TLOCAL); } +"true" { count(); return(TRUE); } +"try" { count(); return(TRY); } "typedef" { count(); return(TYPEDEF); } +"typeid" { count(); return(TYPEID); } +"uint" { count(); return(UINT); } +"uint128" { count(); return(UINT128); } +"ulong" { count(); return(ULONG); } "union" { count(); return(UNION); } +"uptr" { count(); return(UPTR); } +"ushort" { count(); return(USHORT); } +"usz" { count(); return(USZ); } +"var" { count(); return(VAR); } "void" { count(); return(VOID); } "while" { count(); return(WHILE); } -"null" { count(); return(NUL); } -"$for" { count(); return(CTFOR); } -"$foreach" { count(); return(CTFOREACH); } -"$case" { count(); return(CTCASE); } -"$switch" { count(); return(CTSWITCH); } -"$default" { count(); return(CTDEFAULT); } -"$if" { count(); return(CTIF); } -"$else" { count(); return(CTELSE); } -"$endif" { count(); return(CTENDIF); } -"$endswitch" { count(); return(CTENDIF); } -"$endforeach" { count(); return(CTENDFOREACH); } -"$endfor" { count(); return(CTENDFOR); } -@[_]*[A-Z]{UA}* { count(); return(AT_CONST_IDENT); } -#[_]*[A-Z]{UA}* { count(); return(HASH_CONST_IDENT); } -$[_]*[A-Z]{UA}* { count(); return(CT_CONST_IDENT); } -[_]*[A-Z]{UA}* { count(); return(CONST_IDENT); } -@[_]*[A-Z]{UA}*[a-z]{AN}* { count(); return(AT_TYPE_IDENT); } -#[_]*[A-Z]{UA}*[a-z]{AN}* { count(); return(HASH_TYPE_IDENT); } -$[_]*[A-Z]{UA}*[a-z]{AN}* { count(); return(CT_TYPE_IDENT); } -[_]*[A-Z]{UA}*[a-z]{AN}* { count(); return(TYPE_IDENT); } -@[_]*[a-z]{AN}* { count(); return(AT_IDENT); } -#[_]*[a-z]{AN}* { count(); return(HASH_IDENT); } -$[_]*[a-z]{AN}* { count(); return(CT_IDENT); } -[_]*[a-z]{AN}* { count(); return(IDENT); } -0[xX]{H}+ { count(); return(CONSTANT); } -0{D}+? { count(); return(CONSTANT); } -{D}+ { count(); return(CONSTANT); } -L?'(\\.|[^\\'])+' { count(); return(CONSTANT); } +@{CONST} { count(); return(AT_CONST_IDENT); } +#{CONST} { count(); return(HASH_CONST_IDENT); } +${CONST} { count(); return(CT_CONST_IDENT); } +{CONST} { count(); return(CONST_IDENT); } +@{TYPE} { count(); return(AT_TYPE_IDENT); } +#{TYPE} { count(); return(HASH_TYPE_IDENT); } +${TYPE} { count(); return(CT_TYPE_IDENT); } +{TYPE} { count(); return(TYPE_IDENT); } +@{IDENTIFIER} { count(); return(AT_IDENT); } +#{IDENTIFIER} { count(); return(HASH_IDENT); } +${IDENTIFIER} { count(); return(CT_IDENT); } +{IDENTIFIER} { count(); return(IDENT); } +0[xX]{HINT}{INTTYPE}? { count(); return(INTEGER); } +0[oO]{OINT}{INTTYPE}? { count(); return(INTEGER); } +0[bB]{BINT}{INTTYPE}? { count(); return(INTEGER); } +{INT}{INTTYPE}? { count(); return(INTEGER); } +x\'{HEX}+\' { count(); return(BYTES); } +x\"{HEX}+\" { count(); return(BYTES); } +x\`{HEX}+\` { count(); return(BYTES); } +b64\'{B64}+\' { count(); return(BYTES); } +b64\"{B64}+\" { count(); return(BYTES); } +b64\`{B64}+\` { count(); return(BYTES); } -{D}+{E} { count(); return(CONSTANT); } -{D}*"."{D}+({E})? { count(); return(CONSTANT); } -{D}+"."{D}*({E})? { count(); return(CONSTANT); } +{INT}{E}{REALTYPE}? { count(); return(REAL); } +0[xX]{HINT}{P}{REALTYPE}? { count(); return(REAL); } +{INT}"."{INT}{E}?{REALTYPE}? { count(); return(REAL); } +0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { count(); return(REAL); } -L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } +\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } +\'(\\.|[^\\'])*\' { count(); return(CHAR_LITERAL); } + +"`" { count(); BEGIN(RAW_STRING); } +{ + "``" { count(); } + "`" { count(); BEGIN(INITIAL); return(STRING_LITERAL); } + "*"+ { count(); } + <> { BEGIN(INITIAL); return(RAW_STRING); } +} "..." { count(); return(ELLIPSIS); } ".." { count(); return(DOTDOT); } -">>=" { count(); return(RIGHT_ASSIGN); } -"<<=" { count(); return(LEFT_ASSIGN); } +">>=" { count(); return(SHR_ASSIGN); } +"<<=" { count(); return(SHL_ASSIGN); } "+=" { count(); return(ADD_ASSIGN); } "-=" { count(); return(SUB_ASSIGN); } "*=" { count(); return(MUL_ASSIGN); } @@ -101,8 +199,8 @@ L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } "&=" { count(); return(AND_ASSIGN); } "^=" { count(); return(XOR_ASSIGN); } "|=" { count(); return(OR_ASSIGN); } -">>" { count(); return(RIGHT_OP); } -"<<" { count(); return(LEFT_OP); } +">>" { count(); return(SHR_OP); } +"<<" { count(); return(SHL_OP); } "++" { count(); return(INC_OP); } "--" { count(); return(DEC_OP); } "&&" { count(); return(AND_OP); } @@ -111,8 +209,13 @@ L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } ">=" { count(); return(GE_OP); } "==" { count(); return(EQ_OP); } "!=" { count(); return(NE_OP); } +"??" { count(); return(OPTELSE); } "::" { count(); return(SCOPE); } "?:" { count(); return(ELVIS); } +"=>" { count(); return(IMPLIES); } +"[<" { count(); return(LVEC); } +">]" { count(); return(RVEC); } +"$$" { count(); return(BUILTIN); } ";" { count(); return(';'); } ("{") { count(); return('{'); } ("}") { count(); return('}'); } @@ -120,7 +223,6 @@ L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } ":" { count(); return(':'); } "=" { count(); return('='); } "(" { count(); return('('); } -"@" { count(); return(AT); } ")" { count(); return(')'); } ("[") { count(); return('['); } ("]") { count(); return(']'); } @@ -138,8 +240,8 @@ L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } "^" { count(); return('^'); } "|" { count(); return('|'); } "?" { count(); return('?'); } -"{|" { count(); return(FN_BLOCK_BEGIN); } -"|}" { count(); return(FN_BLOCK_END); } +"{|" { count(); return(LBRAPIPE); } +"|}" { count(); return(RBRAPIPE); } [ \t\v\n\f] { count(); } . { /* ignore bad characters */ } @@ -150,26 +252,6 @@ int yywrap(void) return 1; } - -void comment(void) -{ - char c, c1; - -loop: - while ((c = input()) != '*' && c != 0) - putchar(c); - - if ((c1 = input()) != '/' && c != 0) - { - unput(c1); - goto loop; - } - - if (c != 0) - putchar(c1); -} - - int column = 0; void count(void) diff --git a/resources/grammar/grammar.y b/resources/grammar/grammar.y index 8356a7793..0176c602c 100644 --- a/resources/grammar/grammar.y +++ b/resources/grammar/grammar.y @@ -2,7 +2,7 @@ #include #define YYERROR_VERBOSE - +int yydebug = 1; extern char yytext[]; extern int column; int yylex(void); @@ -12,205 +12,327 @@ void yyerror(char *s); %token IDENT HASH_IDENT CT_IDENT CONST_IDENT %token TYPE_IDENT CT_TYPE_IDENT %token AT_TYPE_IDENT AT_IDENT -%token STRING_LITERAL CTSIZEOF -%token INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token STRING_LITERAL INTEGER +%token INC_OP DEC_OP SHL_OP SHR_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN -%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN -%token ADD_MOD SUB_MOD MULT_MOD ADD_MOD_ASSIGN SUB_MOD_ASSIGN -%token MULT_MOD_ASSIGN NEG_MOD -%token XOR_ASSIGN OR_ASSIGN VAR NIL ELVIS NEXTCASE -%token TYPEDEF MODULE IMPORT DEFINE -%token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOID -%token ICHAR USHORT UINT ULONG BOOL INT128 UINT128 FLOAT16 FLOAT128 -%token TYPEID BITSTRUCT STATIC -%token STRUCT UNION ENUM ELLIPSIS DOTDOT +%token SUB_ASSIGN SHL_ASSIGN SHR_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN VAR NUL ELVIS NEXTCASE ANYFAULT +%token TYPEDEF MODULE IMPORT DEFINE EXTERN +%token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOID USZ ISZ UPTR IPTR ANY +%token ICHAR USHORT UINT ULONG BOOL INT128 UINT128 FLOAT16 FLOAT128 BFLOAT16 +%token TYPEID BITSTRUCT STATIC BANGBANG AT_CONST_IDENT HASH_TYPE_IDENT +%token STRUCT UNION ENUM ELLIPSIS DOTDOT BYTES -%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN -%token FN FAULT MACRO GENERIC CT_IF CT_ENDIF CT_ELSE CT_SWITCH CT_CASE CT_DEFAULT CT_FOR CT_FOREACH CT_ENDFOREACH +%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR CONTINUE BREAK RETURN FOREACH_R FOREACH +%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 PUBLIC DEFER ATTRIBUTE TRY_Q CATCH_Q LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF TLOCAL -%token CT_VASPLAT - -%token FN_BLOCK_START FN_BLOCK_END +%token TRY CATCH SCOPE DEFER LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF TLOCAL +%token CT_VASPLAT INLINE DISTINCT CT_VACONST CT_NAMEOF CT_VAREF CT_VACOUNT CT_VAARG +%token CT_SIZEOF CT_STRINGIFY CT_QNAMEOF CT_OFFSETOF CT_VAEXPR +%token CT_EXTNAMEOF CT_EVAL CT_DEFINED CT_CHECKS CT_ALIGNOF ASSERT +%token ASM CHAR_LITERAL REAL TRUE FALSE CT_CONST_IDENT +%token LBRAPIPE RBRAPIPE HASH_CONST_IDENT %start translation_unit %% path - : IDENT SCOPE - | path IDENT SCOPE - ; + : IDENT SCOPE + | path IDENT SCOPE + ; -/* Checked for 0.5 */ -import_path - : IDENT - | import_path SCOPE IDENT - ; +path_const + : path CONST_IDENT + | CONST_IDENT + ; -ident_expression +path_ident + : path IDENT + | IDENT + ; + +ident_expr : CONST_IDENT | IDENT - | CT_IDENT - | HASH_IDENT | AT_IDENT ; -primary_expression +local_ident_expr + : CT_IDENT + | HASH_IDENT + ; + +ct_call + : CT_ALIGNOF + | CT_DEFINED + | CT_EXTNAMEOF + | CT_NAMEOF + | CT_OFFSETOF + | CT_QNAMEOF + ; + +ct_analyse + : CT_EVAL + | CT_SIZEOF + | CT_STRINGIFY + ; + +ct_arg + : CT_VACONST + | CT_VAARG + | CT_VAREF + | CT_VAEXPR + ; + +flat_path + : primary_expression param_path + | primary_expression + ; + +maybe_optional_type + : optional_type + | empty + ; + +string_expr : STRING_LITERAL - | NIL - | BUILTIN - | path ident_expression - | ident_expression - | base_type initializer_list + | string_expr STRING_LITERAL + ; + +bytes_expr + : BYTES + | bytes_expr BYTES + ; + +primary_expression + : string_expr + | INTEGER + | bytes_expr + | NUL + | BUILTIN CONST_IDENT + | BUILTIN IDENT + | CHAR_LITERAL + | REAL + | TRUE + | FALSE + | path ident_expr + | ident_expr + | local_ident_expr + | type initializer_list | type '.' IDENT + | type '.' CONST_IDENT | type '.' TYPEID | '(' type ')' '.' IDENT | '(' type ')' '.' TYPEID - | '(' expression ')' - | FN_BLOCK_START statement_list FN_BLOCK_END + | '(' expr ')' + | LBRAPIPE opt_stmt_list RBRAPIPE + | ct_call '(' flat_path ')' + | ct_arg '(' expr ')' + | ct_analyse '(' expr ')' + | CT_VACOUNT + | CT_CHECKS '(' expression_list ')' + | lambda_decl compound_statement ; -postfix_expression +range_loc + : expr + | '^' expr + ; + +range_expr + : range_loc DOTDOT range_loc + | range_loc DOTDOT + | DOTDOT range_loc + | range_loc ':' range_loc + | ':' range_loc + | range_loc ':' + | DOTDOT + ; + + +call_inline_attributes + : AT_IDENT + | call_inline_attributes AT_IDENT + ; + +call_invocation + : '(' call_arg_list ')' compound_statement + | '(' call_arg_list ')' call_inline_attributes compound_statement + | '(' call_arg_list ')' + | '(' call_arg_list ')' call_inline_attributes + ; + +call_expr : primary_expression - | postfix_expression '[' expression ']' - | postfix_expression '(' ')' - | postfix_expression '(' argument_expression_list ')' - | postfix_expression '.' IDENT - | postfix_expression INC_OP - | postfix_expression DEC_OP + | call_expr '[' range_loc ']' + | call_expr '[' range_expr ']' + | call_expr call_invocation + | call_expr '.' IDENT + | call_expr '.' AT_IDENT + | call_expr INC_OP + | call_expr DEC_OP + | call_expr '!' + | call_expr BANGBANG ; -argument_expression_list - : expression - | argument_expression_list ',' expression +unary_expr + : call_expr + | INC_OP unary_expr + | DEC_OP unary_expr + | unary_op unary_expr + | '(' type ')' unary_expr ; -unary_expression - : postfix_expression - | INC_OP unary_expression - | DEC_OP unary_expression - | unary_operator unary_expression - ; - -unary_operator +unary_op : '&' + | AND_OP | '*' | '+' | '-' - | NEG_MOD | '~' | '!' - | TRY_Q - | CATCH_Q ; -mult_operator - : '*' - | MULT_MOD - | '/' - | '%' - ; +mult_op + : '*' + | '/' + | '%' + ; -multiplicative_expression - : unary_expression - | multiplicative_expression mult_operator unary_expression +multiplicative_expr + : unary_expr + | multiplicative_expr mult_op unary_expr ; shift_op - : LEFT_OP - | RIGHT_OP - ; + : SHL_OP + | SHR_OP + ; -shift_expression - : multiplicative_expression - | shift_expression shift_op multiplicative_expression +shift_expr + : multiplicative_expr + | shift_expr shift_op multiplicative_expr ; bit_op - : '&' - | '^' - | '|' - ; + : '&' + | '^' + | '|' + ; -bit_expression - : shift_expression - | bit_expression bit_op shift_expression +bit_expr + : shift_expr + | bit_expr bit_op shift_expr ; additive_op - : '+' - | ADD_MOD - | SUB_MOD - | '-' - ; + : '+' + | '-' + ; -additive_expression - : bit_expression - | additive_expression additive_op bit_expression +additive_expr + : bit_expr + | additive_expr additive_op bit_expr + | additive_expr additive_op initializer_list ; -relational_expression - : additive_expression - | relational_expression '<' additive_expression - | relational_expression '>' additive_expression - | relational_expression LE_OP additive_expression - | relational_expression GE_OP additive_expression - | relational_expression EQ_OP additive_expression - | relational_expression NE_OP additive_expression +relational_op + : '<' + | '>' + | LE_OP + | GE_OP + | EQ_OP + | NE_OP ; -logical_expression - : relational_expression - | logical_expression AND_OP relational_expression - | logical_expression OR_OP relational_expression +relational_expr + : additive_expr + | relational_expr relational_op additive_expr + | relational_expr relational_op initializer_list ; -conditional_expression - : logical_expression - | logical_expression '?' expression ':' conditional_expression - | logical_expression ELVIS conditional_expression +rel_expr_or_list + : relational_expr + | lambda_decl IMPLIES relational_expr + | initializer_list ; -error_expression - : conditional_expression - | conditional_expression '!' - ; - -assignment_expression - : error_expression - | unary_expression assignment_operator assignment_expression - | unary_expression '=' initializer_list - ; - -expression - : assignment_expression - | assignment_expression OPTELSE assignment_expression +and_expr + : relational_expr + | and_expr AND_OP relational_expr ; +or_expr + : and_expr + | or_expr OR_OP and_expr + ; -assignment_operator +ternary_expr + : or_expr + | or_expr '?' expr ':' ternary_expr + | or_expr '?' expr ':' initializer_list + | or_expr ELVIS ternary_expr + | or_expr '?' + | or_expr '?' '!' + | or_expr OPTELSE ternary_expr + | or_expr OPTELSE initializer_list + | lambda_decl implies_body + ; + +assignment_op : '=' + | ADD_ASSIGN + | SUB_ASSIGN | MUL_ASSIGN | DIV_ASSIGN | MOD_ASSIGN - | ADD_ASSIGN - | SUB_ASSIGN - | LEFT_ASSIGN - | RIGHT_ASSIGN + | SHL_ASSIGN + | SHR_ASSIGN | AND_ASSIGN | XOR_ASSIGN | OR_ASSIGN - | MULT_MOD_ASSIGN - | ADD_MOD_ASSIGN - | SUB_MOD_ASSIGN + ; + +empty + : + ; + +assignment_expr + : ternary_expr + | CT_TYPE_IDENT '=' type + | unary_expr assignment_op assignment_expr + | unary_expr assignment_op initializer_list + ; + +implies_body + : IMPLIES expr_or_list + ; + +lambda_decl + : FN maybe_optional_type fn_parameter_list opt_attributes + ; + +expr + : assignment_expr + ; + +expr_or_list + : expr + | initializer_list ; constant_expr - : conditional_expression + : ternary_expr + | initializer_list + ; + +const_paren_expr + : '(' constant_expr ')' ; param_path_element - : '[' expression ']' + : '[' expr ']' + | '[' range_expr ']' | '.' IDENT ; @@ -219,10 +341,13 @@ param_path | param_path param_path_element ; -arg : param_path '=' expression - | expression +arg : param_path '=' expr_or_list + | type + | param_path '=' type + | expr_or_list | CT_VASPLAT '(' constant_expr ')' - | ELLIPSIS expression + | CT_VASPLAT '(' ')' + | ELLIPSIS expr ; arg_list @@ -230,19 +355,35 @@ arg_list | arg_list ',' arg ; -enumerators - : enumerator - | enumerators ',' enumerator +call_arg_list + : arg_list + | arg_list ';' + | arg_list ';' parameters + | ';' + | ';' parameters + | empty + ; + +opt_arg_list_trailing + : arg_list + | arg_list ',' + | empty + ; + +enum_constants + : enum_constant + | enum_constants ',' enum_constant ; enum_list - : enumerators - | enumerators ',' + : enum_constants + | enum_constants ',' ; -enumerator +enum_constant : CONST_IDENT | CONST_IDENT '(' arg_list ')' + | CONST_IDENT '(' arg_list ',' ')' ; identifier_list @@ -250,52 +391,12 @@ identifier_list | identifier_list ',' IDENT ; -macro_argument - : CT_IDENT - | IDENT - | type IDENT - | type CT_IDENT - ; - -macro_argument_list - : macro_argument - | macro_argument_list ',' macro_argument - ; - -declaration - : optional_type IDENT '=' initializer - | optional_type IDENT - ; - enum_param_decl : type | type IDENT - | type IDENT '=' expression + | type IDENT '=' expr_or_list ; -param_declaration - : type - | type IDENT - | type IDENT '=' initializer - ; - -parameter_type_list - : parameter_list - | parameter_list ',' ELLIPSIS - | parameter_list ',' type ELLIPSIS - ; - -opt_parameter_type_list - : '(' ')' - | '(' parameter_type_list ')' - ; - -parameter_list - : param_declaration - | parameter_list ',' param_declaration - ; - -/* Updated for 0.5 */ base_type : VOID | BOOL @@ -312,17 +413,24 @@ base_type | FLOAT | DOUBLE | FLOAT16 + | BFLOAT16 | FLOAT128 + | IPTR + | UPTR + | ISZ + | USZ + | ANYFAULT + | ANY + | TYPEID | TYPE_IDENT | path TYPE_IDENT | CT_TYPE_IDENT - | CT_TYPEOF '(' expression ')' + | CT_TYPEOF '(' expr ')' | CT_TYPEFROM '(' constant_expr ')' | CT_VATYPE '(' constant_expr ')' | CT_EVALTYPE '(' constant_expr ')' ; -/* Updated for 0.5 */ type : base_type | type '*' @@ -333,108 +441,316 @@ type | type LVEC '*' RVEC ; -/* Updated for 0.5 */ optional_type : type | type '!' ; -initializer - : expression - | initializer_list - ; - - -/* Updated for 0.5 */ local_decl_after_type : CT_IDENT | CT_IDENT '=' constant_expr | IDENT opt_attributes - | IDENT opt_attributes '=' expression + | IDENT opt_attributes '=' expr_or_list ; local_decl_storage : STATIC | TLOCAL - | ; -/* Updated for 0.5 */ -local_decl - : const_declaration - | local_decl_storage optional_type local_decl_after_type - ; - -/* Updated for 0.5 */ decl_or_expr : var_decl | optional_type local_decl_after_type - | expression + | expr ; -/* Updated for 0.5 */ var_decl - : VAR IDENT '=' expression - | VAR CT_IDENT '=' expression + : VAR IDENT '=' expr_or_list + | VAR CT_IDENT '=' expr_or_list | VAR CT_IDENT - | VAR CT_TYPE_IDENT '=' expression + | VAR CT_TYPE_IDENT '=' type | VAR CT_TYPE_IDENT ; -initializer_values - : initializer - | initializer_values ',' initializer - ; - initializer_list - : '{' initializer_values '}' - | '{' initializer_values ',' '}' + : '{' opt_arg_list_trailing '}' ; ct_case_statement - : CT_CASE constant_expr ':' opt_stmt_list - | CT_DEFAULT ':' opt_stmt_list - ; + : CT_CASE constant_expr ':' opt_stmt_list + | CT_CASE type ':' opt_stmt_list + | CT_DEFAULT ':' opt_stmt_list + ; ct_switch_body - : ct_case_statement - | ct_switch_body ct_case_statement - ; - + : ct_case_statement + | ct_switch_body ct_case_statement + ; ct_for_stmt - : CT_FOR '(' decl_expr_list ';' expression_list ';' expression_list ')' opt_stmt_list CT_ENDFOR + : CT_FOR '(' expression_list ';' expr ';' expression_list ')' opt_stmt_list CT_ENDFOR ; ct_foreach_stmt - : CT_FOREACH '(' CT_IDENT ':' constant_expr ')' opt_stmt_list CT_ENDFOREACH + : CT_FOREACH '(' CT_IDENT ':' expr_or_list ')' opt_stmt_list CT_ENDFOREACH -ct_statement - : ct_if opt_stmt_list CT_ENDIF - | ct_if opt_stmt_list CT_ELSE opt_stmt_list CT_ENDIF - | ct_switch ct_switch_body CT_ENDSWITCH - | ct_for_stmt - | ct_foreach_stmt - ; +ct_switch + : CT_SWITCH '(' constant_expr ')' + | CT_SWITCH '(' type ')' + | CT_SWITCH + ; - -statement - : compound_statement - | expression_statement - | selection_statement - | iteration_statement - | jump_statement - | declaration_statement - | defer_statement - | ct_statement +ct_switch_stmt + : ct_switch ct_switch_body CT_ENDSWITCH ; -defer_statement - : DEFER statement - | DEFER TRY statement - | DEFER CATCH statement - ; +var_stmt + : var_decl ';' +decl_stmt_after_type + : local_decl_after_type + | local_decl_after_type ',' identifier_list + ; + +declaration_stmt + : const_declaration ';' + | local_decl_storage optional_type decl_stmt_after_type ';' + | optional_type decl_stmt_after_type ';' + ; + +return_stmt + : RETURN expr_or_list ';' + | RETURN ';' + ; + +catch_unwrap_list + : rel_expr_or_list + | catch_unwrap_list ',' rel_expr_or_list + ; + +catch_unwrap + : CATCH catch_unwrap_list + | CATCH IDENT '=' catch_unwrap_list + | CATCH type IDENT '=' catch_unwrap_list + ; + +try_unwrap + : TRY rel_expr_or_list + | TRY IDENT '=' rel_expr_or_list + | TRY type IDENT '=' rel_expr_or_list + ; + +try_unwrap_chain + : try_unwrap + | try_unwrap_chain AND_OP try_unwrap + | try_unwrap_chain AND_OP rel_expr_or_list + ; + + +case_stmts + : statement_list + | empty + ; + +default_stmt + : DEFAULT ':' case_stmts + ; + +case_stmt + : CASE expr ':' case_stmts + | CASE expr DOTDOT expr ':' case_stmts + | CASE type ':' case_stmts + ; + +switch_body + : case_stmt + | default_stmt + | switch_body case_stmt + | switch_body default_stmt + ; + +cond_repeat + : decl_or_expr + | cond_repeat ',' decl_or_expr + ; + +cond + : try_unwrap_chain + | catch_unwrap + | cond_repeat + | cond_repeat ',' try_unwrap_chain + | cond_repeat ',' catch_unwrap + ; + +else_part + : ELSE if_stmt + | ELSE compound_statement + ; + +if_stmt + : IF optional_label '(' cond ')' '{' switch_body '}' + | IF optional_label '(' cond ')' '{' switch_body '}' else_part + | IF optional_label '(' cond ')' statement + | IF optional_label '(' cond ')' compound_statement else_part + ; + +expr_list_eos + : expression_list ';' + | ';' + ; + +cond_eos + : cond ';' + | ';' + ; + +for_stmt + : FOR optional_label '(' expr_list_eos cond_eos expression_list ')' statement + | FOR optional_label '(' expr_list_eos cond_eos ')' statement + ; + +while_stmt + : WHILE optional_label '(' cond ')' statement + ; + +do_stmt + : DO optional_label compound_statement WHILE '(' expr ')' ';' + | DO optional_label compound_statement ';' + ; + +optional_label_target + : CONST_IDENT + | empty + ; + +continue_stmt + : CONTINUE optional_label_target ';' + ; + +break_stmt + : BREAK optional_label_target ';' + ; + +nextcase_stmt + : NEXTCASE CONST_IDENT ':' expr ';' + | NEXTCASE expr ';' + | NEXTCASE ';' + ; + +foreach_var + : optional_type '&' IDENT + | optional_type IDENT + | '&' IDENT + | IDENT + ; + +foreach_vars + : foreach_var + | foreach_var ',' foreach_var + ; + +foreach_stmt + : FOREACH optional_label '(' foreach_vars ':' expr ')' statement + : FOREACH_R optional_label '(' foreach_vars ':' expr ')' statement + ; + +defer_stmt + : DEFER statement + | DEFER TRY statement + | DEFER CATCH statement + ; + +ct_if_stmt + : CT_IF const_paren_expr opt_stmt_list CT_ENDIF + | CT_IF const_paren_expr opt_stmt_list CT_ELSE opt_stmt_list CT_ENDIF + ; + +assert_expr + : try_unwrap_chain + | expr + ; + +assert_stmt + : ASSERT '(' assert_expr ')' ';' + | ASSERT '(' assert_expr ',' expr ')' ';' + ; + +asm_stmts + : asm_stmt + | asm_stmts asm_stmt + ; + +asm_instr + : INT + | IDENT + | INT '.' IDENT + | IDENT '.' IDENT + ; + +asm_addr + : asm_expr + | asm_expr additive_op asm_expr + | asm_expr additive_op asm_expr '*' INTEGER + | asm_expr additive_op asm_expr '*' INTEGER additive_op INTEGER + | asm_expr additive_op asm_expr shift_op INTEGER + | asm_expr additive_op asm_expr additive_op INTEGER + ; + +asm_expr + : CT_IDENT + | CT_CONST_IDENT + | IDENT + | '&' IDENT + | CONST_IDENT + | REAL + | INTEGER + | '(' expr ')' + | '[' asm_addr ']' + +asm_exprs + : asm_expr + | asm_exprs ',' asm_expr + ; + +asm_stmt + : asm_instr asm_exprs ';' + | asm_instr ';' + ; + +asm_block_stmt + : ASM '(' expr ')' + | ASM '{' asm_stmts '}' + | ASM '{' '}' + ; + + +/* Order here matches compiler */ +statement + : compound_statement + | var_stmt + | declaration_stmt + | return_stmt + | if_stmt + | while_stmt + | defer_stmt + | switch_stmt + | do_stmt + | for_stmt + | foreach_stmt + | continue_stmt + | break_stmt + | nextcase_stmt + | asm_block_stmt + | ct_echo_stmt + | ct_assert_stmt + | ct_if_stmt + | ct_switch_stmt + | ct_foreach_stmt + | ct_for_stmt + | expr ';' + | assert_stmt + | ';' + ; compound_statement : '{' opt_stmt_list '}' @@ -447,54 +763,25 @@ statement_list opt_stmt_list : statement_list - | + | empty ; -declaration_statement - : declaration ';' - ; - -expression_statement - : expression ';' - ; - - -if_expr - : type IDENT '=' initializer - | TRY type IDENT '=' expression - | TRY IDENT '=' expression - | TRY IDENT - | CATCH IDENT '=' expression - | expression - ; - -if_cond_expr - : if_expr - | if_cond_expr ',' if_expr - ; - -control_expression - : decl_expr_list - | decl_expr_list ';' decl_expr_list - ; - -selection_statement - : IF '(' if_cond_expr ')' statement - | IF '(' if_cond_expr ')' compound_statement ELSE statement - | SWITCH '(' control_expression ')' compound_statement +switch_stmt + : SWITCH optional_label '{' switch_body '}' + | SWITCH optional_label '{' '}' + | SWITCH optional_label '(' cond ')' '{' switch_body '}' + | SWITCH optional_label '(' cond ')' '{' '}' ; expression_list - : expression - | expression_list ',' expression - ; + : decl_or_expr + | expression_list ',' decl_or_expr + ; -decl_expr_list - : expression - | declaration - | decl_expr_list ',' expression - | decl_expr_list ',' declaration - ; +optional_label + : CONST_IDENT ':' + | empty + ; ct_assert_stmt : CT_ASSERT '(' constant_expr ',' constant_expr ')' ';' @@ -505,11 +792,12 @@ ct_echo_stmt : CT_ECHO '(' constant_expr ')' ';' bitstruct_declaration - : BITSTRUCT IDENT ':' type opt_attributes bitstruct_body + : BITSTRUCT TYPE_IDENT ':' type opt_attributes bitstruct_body bitstruct_body : '{' '}' | '{' bitstruct_defs '}' + | '{' bitstruct_simple_defs '}' ; bitstruct_defs @@ -517,9 +805,14 @@ bitstruct_defs | bitstruct_defs bitstruct_def ; +bitstruct_simple_defs + : base_type IDENT ';' + | bitstruct_simple_defs base_type IDENT ';' + ; + bitstruct_def - : type IDENT ':' constant_expr DOTDOT constant_expr ';' - | type IDENT ':' constant_expr ';' + : base_type IDENT ':' constant_expr DOTDOT constant_expr ';' + | base_type IDENT ':' constant_expr ';' ; static_declaration @@ -527,121 +820,110 @@ static_declaration | STATIC FINALIZE opt_attributes compound_statement ; -for_statement - : FOR '(' decl_expr_list ';' expression_statement ')' statement - | FOR '(' decl_expr_list ';' expression_statement expression_list ')' statement - ; - -iteration_statement - : WHILE '(' control_expression ')' statement - | DO statement WHILE '(' expression ')' ';' - | for_statement - ; - -jump_statement - : CONTINUE CONST_IDENT ';' - | CONTINUE ';' - | BREAK ';' - | BREAK CONST_IDENT ';' - | NEXTCASE CONST_IDENT ':' ';' - | NEXTCASE CONST_IDENT ':' expression ';' - | NEXTCASE ';' - | NEXTCASE expression ';' - | RETURN ';' - | RETURN expression ';' - ; - -/* Updated for 0.5 */ attribute_name : AT_IDENT | AT_TYPE_IDENT | path AT_TYPE_IDENT ; -/* Checked for 0.5 */ attribute_operator_expr : '&' '[' ']' | '[' ']' '=' | '[' ']' ; -/* Checked for 0.5 */ attr_param : attribute_operator_expr | constant_expr ; -/* Checked for 0.5 */ attribute_param_list : attr_param | attribute_param_list ',' attr_param ; -/* Checked for 0.5 */ attribute : attribute_name | attribute_name '(' attribute_param_list ')' ; -/* Checked for 0.5 */ attribute_list : attribute | attribute_list attribute ; -/* Checked for 0.5 */ opt_attributes : attribute_list - | + | empty ; +trailing_block_param + : AT_IDENT + | AT_IDENT '(' ')' + | AT_IDENT '(' parameters ')' + ; + +macro_params + : parameters + | parameters ';' trailing_block_param + | ';' trailing_block_param + | empty + ; + +macro_func_body + : implies_body ';' + | compound_statement + ; + macro_declaration - : MACRO type IDENT '(' macro_argument_list ')' compound_statement - : MACRO IDENT '(' macro_argument_list ')' compound_statement - ; + : MACRO macro_header '(' macro_params ')' opt_attributes macro_func_body + ; - -/* Checked for 0.5 */ struct_or_union : STRUCT | UNION ; -/* Checked for 0.5 */ struct_declaration : struct_or_union TYPE_IDENT opt_attributes struct_body ; struct_body - : '{' struct_declaration_list '}' + : '{' struct_declaration_list '}' ; struct_declaration_list - : struct_member_declaration - | struct_declaration_list struct_member_declaration - ; + : struct_member_decl + | struct_declaration_list struct_member_decl + ; -struct_member_declaration - : type identifier_list opt_attributes ';' - | struct_or_union IDENT opt_attributes struct_body - | struct_or_union opt_attributes struct_body - ; - -/* Checked for 0.5 */ enum_params : enum_param_decl | enum_params ',' enum_param_decl ; -/* Checked for 0.5 */ -enum_spec - : ':' type - | ':' type '(' ')' - | ':' type '(' enum_params ')' - | +enum_param_list + : '(' enum_params ')' + | '(' ')' + | empty + ; + +struct_member_decl + : type identifier_list opt_attributes ';' + | struct_or_union IDENT opt_attributes struct_body + | struct_or_union opt_attributes struct_body + | BITSTRUCT ':' type opt_attributes bitstruct_body + | BITSTRUCT IDENT ':' type opt_attributes bitstruct_body + | INLINE type IDENT opt_attributes ';' + | INLINE type opt_attributes ';' + ; + + +enum_spec + : ':' type enum_param_list + | empty ; -/* Checked for 0.5 */ enum_declaration : ENUM TYPE_IDENT enum_spec opt_attributes '{' enum_list '}' ; @@ -652,23 +934,20 @@ faults ; fault_declaration - : FAULT opt_attributes '{' faults '}' - | FAULT opt_attributes '{' faults ',' '}' - ; + : FAULT TYPE_IDENT opt_attributes '{' faults '}' + | FAULT TYPE_IDENT opt_attributes '{' faults ',' '}' + ; -/* Checked for 0.5 */ func_header : optional_type type '.' IDENT | optional_type IDENT ; -/* Checked for 0.5 */ macro_name : IDENT | AT_IDENT ; -/* Checked for 0.5 */ macro_header : optional_type type '.' macro_name | optional_type macro_name @@ -676,26 +955,22 @@ macro_header | macro_name ; -/* Checked for 0.5 */ fn_parameter_list : '(' parameters ')' | '(' ')' ; - -/* Checked for 0.5 */ parameters - : parameter '=' expression + : parameter '=' expr_or_list | parameter | parameters ',' parameter - | parameters ',' parameter '=' expression + | parameters ',' parameter '=' expr_or_list ; - -/* Checked for 0.5 */ parameter : type IDENT opt_attributes | ELLIPSIS + | IDENT | type ELLIPSIS IDENT opt_attributes | type ELLIPSIS CT_IDENT | IDENT ELLIPSIS @@ -711,24 +986,40 @@ parameter function_definition : FN func_header fn_parameter_list opt_attributes ';' - | FN func_header fn_parameter_list opt_attributes IMPLIES expression ';' - | FN func_header fn_parameter_list opt_attributes compound_statement + | FN func_header fn_parameter_list opt_attributes macro_func_body ; -/* Checked for 0.5 */ const_declaration - : CONST CONST_IDENT opt_attributes '=' expression - | CONST type CONST_IDENT opt_attributes '=' expression + : CONST CONST_IDENT opt_attributes '=' expr_or_list + | CONST type CONST_IDENT opt_attributes '=' expr_or_list ; func_typedef - : FN optional_type opt_parameter_type_list + : FN optional_type fn_parameter_list ; +opt_distinct_inline + : DISTINCT + | DISTINCT INLINE + | INLINE DISTINCT + | INLINE + | empty + ; + +generic_parameters + : bit_expr + | type + | generic_parameters ',' bit_expr + | generic_parameters ',' type + ; + +typedef_type + : func_typedef + | type opt_generic_parameters + ; + typedef_declaration - : TYPEDEF TYPE_IDENT '=' TYPE_IDENT ';' - | TYPEDEF TYPE_IDENT '=' TYPE_IDENT '<' '>' ';' - | TYPEDEF TYPE_IDENT '=' func_typedef ';' + : TYPEDEF TYPE_IDENT opt_attributes '=' opt_distinct_inline typedef_type ';' ; @@ -737,82 +1028,93 @@ multi_declaration | multi_declaration ',' IDENT ; -opt_multi_declaration - : multi_declaration - | - ; - global_storage : TLOCAL - | + | empty ; global_declaration - : global_storage optional_type IDENT opt_multi_declaration opt_attributes ';' - | global_storage optional_type IDENT '=' constant_expr ';' + : global_storage optional_type IDENT opt_attributes ';' + | global_storage optional_type IDENT multi_declaration opt_attributes ';' + | global_storage optional_type IDENT opt_attributes '=' expr_or_list ';' ; -ct_if - : CT_IF '(' expression ')' - ; - -ct_switch - : CT_SWITCH '(' expression ')' - | CT_SWITCH - ; - - opt_tl_stmts : top_level_statements - | + | empty ; - tl_ct_case - : CT_CASE expression ':' top_level_statements - | CT_DEFAULT ':' top_level_statements + : CT_CASE constant_expr ':' opt_tl_stmts + | CT_CASE type ':' opt_tl_stmts + | CT_DEFAULT ':' opt_tl_stmts ; tl_ct_switch_body - : tl_ct_case - | tl_ct_switch_body tl_ct_case - ; + : tl_ct_case + | tl_ct_switch_body tl_ct_case + ; -define_declaration - : DEFINE IDENT '=' IDENT ';' +define_attribute + : DEFINE AT_TYPE_IDENT '(' parameters ')' opt_attributes '=' '{' opt_attributes '}' ';' + | DEFINE AT_TYPE_IDENT opt_attributes '=' '{' opt_attributes '}' ';' ; -conditional_compilation - : ct_if opt_tl_stmts CT_ENDIF - | ct_if opt_tl_stmts CT_ELSE opt_tl_stmts CT_ENDIF - | ct_switch tl_ct_switch_body CT_ENDSWITCH - ; +opt_generic_parameters + : '<' generic_parameters '>' + | empty + ; + + + +define_ident + : DEFINE IDENT '=' path_ident opt_generic_parameters ';' + | DEFINE CONST_IDENT '=' path_const opt_generic_parameters ';' + | DEFINE AT_IDENT '=' path AT_IDENT opt_generic_parameters ';' + | DEFINE AT_IDENT '=' AT_IDENT opt_generic_parameters ';' + ; + +define_declaration + : define_ident + | define_attribute + ; + +tl_ct_if + : CT_IF const_paren_expr opt_tl_stmts CT_ENDIF + | CT_IF const_paren_expr opt_tl_stmts CT_ELSE opt_tl_stmts CT_ENDIF + ; + +tl_ct_switch + : ct_switch tl_ct_switch_body CT_ENDSWITCH + ; -/* Checked for 0.5 */ module_param - : CONST_IDENT - | TYPE_IDENT - ; + : CONST_IDENT + | TYPE_IDENT + ; -/* Checked for 0.5 */ module_params - : module_param - | module_params ',' module_param - ; + : module_param + | module_params ',' module_param + ; -/* Checked for 0.5 */ module - : MODULE import_path opt_attributes ';' - | MODULE import_path '<' module_params '>' opt_attributes ';' - ; + : MODULE path_ident opt_attributes ';' + | MODULE path_ident '<' module_params '>' opt_attributes ';' + ; + +import_paths + : path_ident + | path_ident ',' path_ident + ; import_decl - : IMPORT import_path ';' - ; + : IMPORT import_paths opt_attributes ';' + ; translation_unit : top_level_statements - | + | empty ; top_level_statements @@ -820,23 +1122,28 @@ top_level_statements | top_level_statements top_level ; +opt_extern + : EXTERN + | empty + ; top_level - : function_definition + : opt_extern function_definition | module | import_decl - | conditional_compilation + | ct_assert_stmt + | ct_echo_stmt + | tl_ct_if + | tl_ct_switch | struct_declaration - | enum_declaration | fault_declaration - | const_declaration ';' - | global_declaration + | enum_declaration + | opt_extern const_declaration ';' + | opt_extern global_declaration | macro_declaration | typedef_declaration | define_declaration | static_declaration - | ct_assert_stmt - | ct_echo_stmt | bitstruct_declaration ; @@ -851,6 +1158,6 @@ void yyerror(char *s) int main(int argc, char *argv[]) { - yyparse(); - return(0); + yyparse(); + return 0; } \ No newline at end of file diff --git a/resources/testfragments/bigint.c3 b/resources/testfragments/bigint.c3 index f9f220823..e1027ea22 100644 --- a/resources/testfragments/bigint.c3 +++ b/resources/testfragments/bigint.c3 @@ -1,19 +1,20 @@ module bigint; +import libc; -macro max(a, b) +macro @max(a, b) { return a > b ? a : b; } // Horribly bad implementation of BigInt with add/sub. -public struct BigInt +struct BigInt { - byte* number; + char* number; uint length; - char sign; + ichar sign; } -public fn void BigInt.init(BigInt* bigInt) +fn void BigInt.init(BigInt* bigInt) { bigInt.number = malloc(1); bigInt.number[0] = 0; @@ -21,9 +22,9 @@ public fn void BigInt.init(BigInt* bigInt) bigInt.sign = 1; } -public fn void BigInt.initFromString(BigInt* bigInt, char* str) +fn void BigInt.initFromString(BigInt* bigInt, char* str) { - uint size = strlen(str); + uint size = (uint)libc::strlen(str); bigInt.sign = 1; switch (str[0]) { @@ -46,7 +47,7 @@ public fn void BigInt.initFromString(BigInt* bigInt, char* str) bigInt.length = size; } -public fn void BigInt.copyTo(BigInt* source, BigInt* target) +fn void BigInt.copyTo(BigInt* source, BigInt* target) { target.number = realloc(target.number, source.length); target.sign = source.sign; @@ -54,7 +55,7 @@ public fn void BigInt.copyTo(BigInt* source, BigInt* target) for (uint i = 0; i < target.length; i++) target.number[i] = source.number[i]; } -public fn void BigInt.destroy(BigInt* bigInt) +fn void BigInt.destroy(BigInt* bigInt) { free(bigInt.number); } @@ -62,8 +63,8 @@ public fn void BigInt.destroy(BigInt* bigInt) fn void BigInt.addIgnoreSign(BigInt* a, BigInt* b, BigInt* result) { uint length = @max(a.length, b.length) + 1; - byte* res = malloc(length); - char carry = 0; + char* res = malloc(length); + ichar carry = 0; BigInt* x; BigInt* y; if (a.length > b.length) @@ -98,7 +99,7 @@ fn void BigInt.addIgnoreSign(BigInt* a, BigInt* b, BigInt* result) result.length = length; } -public fn void BigInt.getMaxVal(BigInt* bigInt, uint* pos, int* val) +fn void BigInt.getMaxVal(BigInt* bigInt, uint* pos, int* val) { for (uint i = bigInt.length; i > 0; i++) { @@ -113,14 +114,14 @@ public fn void BigInt.getMaxVal(BigInt* bigInt, uint* pos, int* val) *val = 0; } -public fn char BigInt.compare(BigInt* a, BigInt* b) +fn ichar BigInt.compare(BigInt* a, BigInt* b) { if (a.sign != b.sign) return a.sign; - byte aMax; + int aMax; uint aMaxPos; a.getMaxVal(&aMaxPos, &aMax); if (aMaxPos >= b.length) return a.sign; - byte bMax; + int bMax; uint bMaxPos; b.getMaxVal(&bMaxPos, &bMax); if (aMaxPos > bMaxPos) return a.sign; @@ -130,13 +131,13 @@ public fn char BigInt.compare(BigInt* a, BigInt* b) return 0; } -public fn char BigInt.compareNoSign(BigInt* a, BigInt* b) +fn ichar BigInt.compareNoSign(BigInt* a, BigInt* b) { - byte aMax; + int aMax; uint aMaxPos; a.getMaxVal(&aMaxPos, &aMax); if (aMaxPos >= b.length) return 1; - byte bMax; + int bMax; uint bMaxPos; b.getMaxVal(&bMaxPos, &bMax); if (aMaxPos > bMaxPos) return 1; @@ -149,7 +150,7 @@ public fn char BigInt.compareNoSign(BigInt* a, BigInt* b) fn void BigInt.subIgnoreSign(BigInt* a, BigInt* b, BigInt* result) { uint length = @max(a.length, b.length); - byte* res = malloc(length); + char* res = malloc(length); BigInt* x; BigInt* y; @@ -166,11 +167,11 @@ fn void BigInt.subIgnoreSign(BigInt* a, BigInt* b, BigInt* result) y = b; } - byte borrow = 0; + char borrow = 0; for (uint i = 0; i < length; i++) { - byte aValue = i >= x.length ? 0 : x.number[i]; - byte bValue = borrow + (i >= y.length ? 0 : y.number[i]); + char aValue = i >= x.length ? 0 : x.number[i]; + char bValue = borrow + (i >= y.length ? 0 : y.number[i]); if (bValue > aValue) { borrow = 1; @@ -187,7 +188,7 @@ fn void BigInt.subIgnoreSign(BigInt* a, BigInt* b, BigInt* result) result.length = length; } -public fn void BigInt.add(BigInt* a, BigInt* b, BigInt* result) +fn void BigInt.add(BigInt* a, BigInt* b, BigInt* result) { if (a.sign == b.sign) { @@ -205,12 +206,12 @@ public fn void BigInt.add(BigInt* a, BigInt* b, BigInt* result) } } -public fn char* BigInt.toCharArray(BigInt* bigInt) +fn char* BigInt.toCharArray(BigInt* bigInt) { - uint charLen = bigInt.length + 1 + (bigInt.sign < 0 ? 1 : 0); - byte* out = malloc(charLen); - out[charLen - 1] = '\0'; - byte* start = out; + uint icharLen = bigInt.length + 1 + (bigInt.sign < 0 ? 1 : 0); + char* out = malloc(icharLen); + out[icharLen - 1] = '\0'; + char* start = out; if (bigInt.sign < 0) { out[0] = '-'; @@ -219,7 +220,7 @@ public fn char* BigInt.toCharArray(BigInt* bigInt) bool nonZeroFound = false; for (uint i = bigInt.length; i > 0; i--) { - byte digit = bigInt.number[i - 1]; + char digit = bigInt.number[i - 1]; if (i > 1 && !nonZeroFound && digit == 0) continue; nonZeroFound = true; *(start++) = digit + '0'; @@ -227,24 +228,24 @@ public fn char* BigInt.toCharArray(BigInt* bigInt) return out; } -public fn void BigInt.print(BigInt* bigInt) +fn void BigInt.print(BigInt* bigInt) { char* chars = bigInt.toCharArray(); - puts(chars); + libc::puts(chars); free(chars); } /* -public fn void BigInt.fprint(BigInt* bigInt, FILE* file) +fn void BigInt.fprint(BigInt* bigInt, FILE* file) { - char* chars = bigInt.toCharArray(); - fputs(chars, file); + ichar* ichars = bigInt.toicharArray(); + fputs(ichars, file); putc('\n', file); - free(chars); + free(ichars); }*/ -public fn int main(int size, char** args) +fn int main(int size, char** args) { BigInt minus2; BigInt minus1; @@ -257,7 +258,7 @@ public fn int main(int size, char** args) for (int i = 1; i <= 500; i++) { minus1.add(&minus2, ¤t); - printf("%d : ", i); + libc::printf("%d : ", i); current.print(); minus1.copyTo(&minus2); current.copyTo(&minus1); diff --git a/resources/testfragments/casting.c3 b/resources/testfragments/casting.c3 index 28347f7c6..99dd21617 100644 --- a/resources/testfragments/casting.c3 +++ b/resources/testfragments/casting.c3 @@ -12,9 +12,9 @@ fn void readpgm(char* name, Pixmap* p) pnm_readpaminit(fp, &inpam); p.x = inpam.width; p.y = inpam.height; - if (!(p.p = malloc(@safe(p.x + p.y))) + if (!(p.p = malloc(@safe(p.x + p.y)))) { - @F1("Error at malloc"); + @f1("Error at malloc"); } for (int i = 0; i < inpam.height; i++) { @@ -24,7 +24,7 @@ fn void readpgm(char* name, Pixmap* p) { p.p[@nowrap(i * inpam.width + j)] = sample; } - } + }; } } diff --git a/resources/testfragments/comparisons.c3 b/resources/testfragments/comparisons.c3 index de4934cfd..a32042705 100644 --- a/resources/testfragments/comparisons.c3 +++ b/resources/testfragments/comparisons.c3 @@ -32,8 +32,8 @@ extern fn void printf(char *s); fn void test_signedunsigned() { - char a = 0 - 1; - byte b = (byte)(a); + ichar a = 0 - 1; + char b = (char)(a); printf("Signed-unsigned -1 0xFF \n"); if (a > b) printf("a > b\n"); diff --git a/resources/testfragments/compilertest2.c3 b/resources/testfragments/compilertest2.c3 deleted file mode 100644 index a22850e89..000000000 --- a/resources/testfragments/compilertest2.c3 +++ /dev/null @@ -1,272 +0,0 @@ -module bigint; - -macro @max(a, b) -{ - return a > b ? a : b; -} - -// Horribly bad implementation of BigInt with add/sub. -public struct BigInt -{ - byte& number; - uint length; - char sign; -} - -public fn void BigInt.init(BigInt& bigInt) -{ - bigInt.number = malloc(1); - bigInt.number[0] = 0; - bigInt.length = 1; - bigInt.sign = 1; -} - -public fn void BigInt.initFromString(BigInt& bigInt, char& str) -{ - uint size = strlen(str); - bigInt.sign = 1; - switch (str[0]) - { - case '-': - bigInt.sign = -1; - size--; - str++; - case '+': - size--; - str++; - default: - break; - } - char* res = malloc(size); - for (uint i = 0; i < size; i++) - { - res[i] = str[size - i - 1] - '0'; - } - bigInt.number = res; - bigInt.length = size; -} - -public fn BigInt& BigInt.newFromString(char& str) -{ - BigInt& bigInt = malloc(sizeof(BigInt)); - bigInt.initFromString(str); - return bigInt; -} - -public fn void BigInt.copyTo(BigInt& source, BigInt& target) -{ - target.number = realloc(target.number, source.length); - target.sign = source.sign; - target.length = source.length; - for (uint i = 0; i < target.length; i++) target.number[i] = source.number[i]; -} - -public fn void BigInt.destroy(BigInt& bigInt) -{ - free(bigInt.number); -} - -fn void BigInt.addIgnoreSign(BigInt& a, BigInt& b, BigInt& result) -{ - uint length = @max(a.length, b.length) + 1; - byte* res = malloc(length); - char carry = 0; - BigInt* x; - BigInt* y; - if (a.length > b.length) - { - x = a; - y = b; - } - else - { - x = b; - y = a; - } - for (uint i = 0; i < length; i++) - { - if (i >= y.length) - { - res[i] = carry + (i >= x.length ? 0 : x.number[i]); - } - else - { - res[i] = x.number[i] + y.number[i] + carry; - } - carry = 0; - if (res[i] > 9) - { - carry = 1; - res[i] -= 10; - } - } - result.destroy(); - result.number = res; - result.length = length; -} - -public fn void BigInt.getMaxVal(BigInt &bigInt, uint& pos, int& val) -{ - for (uint i = bigInt.length; i > 0; i++) - { - if (bigInt.number[i] != 0) - { - *pos = i; - *val = bigInt.number[i]; - return; - } - } - *pos = 0; - *val = 0; -} - -public fn char BigInt.compare(BigInt& a, BigInt& b) -{ - if (a.sign != b.sign) return a.sign; - byte aMax; - uint aMaxPos; - a.getMaxVal(&aMaxPos, &aMax); - if (aMaxPos >= b.length) return a.sign; - byte bMax; - uint bMaxPos; - b.getMaxVal(&bMaxPos, &bMax); - if (aMaxPos > bMaxPos) return a.sign; - if (aMaxPos < bMaxPos) return -a.sign; - if (aMax > bMax) return a.sign; - if (aMax < bMax) return -a.sign; - return 0; -} - -public fn char BigInt.compareNoSign(BigInt& a, BigInt& b) -{ - byte aMax; - uint aMaxPos; - a.getMaxVal(&aMaxPos, &aMax); - if (aMaxPos >= b.length) return 1; - byte bMax; - uint bMaxPos; - b.getMaxVal(&bMaxPos, &bMax); - if (aMaxPos > bMaxPos) return 1; - if (aMaxPos < bMaxPos) return -1; - if (aMax > bMax) return 1; - if (aMax < bMax) return -1; - return 0; -} - -fn void BigInt.subIgnoreSign(BigInt& a, BigInt& b, BigInt& result) -{ - uint length = @max(a.length, b.length); - byte& res = malloc(length); - - BigInt& x; - BigInt& y; - if (a.compareNoSign(b) < 0) - { - result.sign = -1; - x = b; - y = a; - } - else - { - result.sign = 1; - x = a; - y = b; - } - - byte borrow = 0; - for (uint i = 0; i < length; i++) - { - byte aValue = i >= x.length ? 0 : x.number[i]; - byte bValue = borrow + (i >= y.length ? 0 : y.number[i]); - if (bValue > aValue) - { - borrow = 1; - aValue += 10; - } - else - { - borrow = 0; - } - res[i] = aValue - bValue; - } - result.destroy(); - result.number = res; - result.length = length; -} - -public fn void BigInt.add(BigInt& a, BigInt& b, BigInt& result) -{ - if (a.sign == b.sign) - { - a.addIgnoreSign(b, result); - result.sign = a.sign; - return; - } - if (a.sign < 0) - { - b.subIgnoreSign(a, result); - } - else - { - a.subIgnoreSign(a, result); - } -} - -public fn char* BigInt.toCharArray(BigInt* bigInt) -{ - uint charLen = bigInt.length + 1 + (bigInt.sign < 0 ? 1 : 0); - byte* out = malloc(charLen); - out[charLen - 1] = '\0'; - byte* start = out; - if (bigInt.sign < 0) - { - out[0] = '-'; - start++; - } - bool nonZeroFound = false; - for (uint i = bigInt.length; i > 0; i--) - { - byte digit = bigInt.number[i - 1]; - if (i > 1 && !nonZeroFound && digit == 0) continue; - nonZeroFound = true; - *(start++) = digit + '0'; - } - return out; -} - -public fn void BigInt.print(BigInt& bigInt) -{ - char* chars = bigInt.toCharArray(); - puts(chars); - free(chars); -} - -/* -public fn void BigInt.fprint(BigInt* bigInt, FILE* file) -{ - char* chars = bigInt.toCharArray(); - fputs(chars, file); - putc('\n', file); - free(chars); -}*/ - - -public fn int main(int size, char*& args) -{ - BigInt minus2; - BigInt minus1; - BigInt current; - minus2.initFromString("0"); - minus1.initFromString("1"); - current.initFromString("0"); - - for (int i = 1; i <= 500; i++) - { - minus1.add(&minus2, ¤t); - printf("%d : ", i); - current.print(); - minus1.copyTo(&minus2); - current.copyTo(&minus1); - } - return 0; -} diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 deleted file mode 100644 index e76931a10..000000000 --- a/resources/testfragments/compiletest.c3 +++ /dev/null @@ -1,190 +0,0 @@ -module foo; - -int oefk = 1; -int bob = 'HELO'; - -typedef Foo* as Bob; - -fn void testdefer(int x) -{ - defer printf("A"); - defer - { - int x = 2; - printf("B"); - x = x + 1; - } - //defer catch printf("B") - //defer catch (error e) printf("%s", @name(e)); - //if (x = 1) return throw Error.FOO; - printf("!"); -} - -struct Foo -{ - int i; - Bar *x; -} - -struct Bar -{ - Foo foo; - Foo* fooPtr; - Bob helo; - struct bar - { - int a; - } -} - -union Xyz -{ - int x; - int y; -} - - -$if (1) -{ - struct Ogg - { - Zed *bob; - } - struct DOgg - { - Zed bob; - } - struct Zed - { - Foo b; - } - -} - - -struct Simple -{ - int i; - double j; -} -fn int boo() -{ - Zed zfe; - Simple s = { 1 }; - s = { 2 }; - //Simple x = { j = 1 }; - //Zed zfed = { 1 }; - int eok = 0; - { - eok = 2; - } - eok = eok * 2 + 1 * 2; - eok = eok / 2 + 32 / 2; - eok = eok % 2 - 32 % 45; - - int de = eok; - de++; - de = de << 1; - de = de >> 1; - de = de ^ (byte)(1); - de = de & 1; - de = de | 1; - if (de > 100 || de < 10 || de <= 1000 || de >= 1921 || de == 100 || de != 2) - { - return boo(); - } - switch (eok) - { - case 1 - eok++; - next; - case 3: - eok++; - next; - eok--; - case 2: - eok--; - default: - eok--; - break; - } - - - if (eok > 0) - { - eok++; - } - else - { - eok--; - } - int xfeef = -eok; - /* - bool xoek = !eok; - int oekfefo = ~eok; - int *booe = &eok; - int **de = &booe; - int &xfok = &eok; - int &&bo = &xfok; - int e12 = **bo; - int fe = *(&eok); - int x2 = *xfok;*/ - int x1 = 2; - FOO: - x1 = x1 + 1; - goto FOO; - bool z = 123 > 3.0; - { - int x = 0; - } - { - int x = 1; - } - int j = 10; - do - { - j = j + 10; - } while (j > 2); - return 1; -} - -fn int helo(int i) -{ - return i + 1; -} -fn void while_test() -{ - - int a = 10; - - while (int b = 37; a < 0) - { - a++; - int xy = 1; - } -} - -fn void test() -{ - int a = 10; - while (1) - { - int xy = 1; - } - int eokfe = boo(); - int i = -1; - bool dwf = !2.0; - ushort b = ~(byte)(0); - int j as k; - int l as m = 0; - int o = 0, p = 3; - short f = (char)((int)(-2)); - //int doek = ~2; - return; -} - -fn void main() -{ - helo(2); - printf("Helo\n"); -} \ No newline at end of file diff --git a/resources/testfragments/demo1.c3 b/resources/testfragments/demo1.c3 index d0f68f83a..6fef9e5d5 100644 --- a/resources/testfragments/demo1.c3 +++ b/resources/testfragments/demo1.c3 @@ -13,7 +13,7 @@ struct Foo fn Foo createFoo(int a, int b = 10) { // Compound initializer - return Foo({a, b}); + return Foo {a, b}; } struct Bar @@ -37,8 +37,7 @@ fn void testStruct() foo = createFoo(.b = 13, .a = 14); printf("Foo a:%d b:%d\n", foo.a, foo.b); - // Structural copy - Bar bar = (Bar)(foo); + Bar bar = bitcast(foo, Bar); printf("Bar x:%d y:%d\n", bar.x, bar.y); // Type functions diff --git a/resources/testfragments/file1.c3 b/resources/testfragments/file1.c3 deleted file mode 100644 index aee7ad3bd..000000000 --- a/resources/testfragments/file1.c3 +++ /dev/null @@ -1,18 +0,0 @@ -module baz; -import bar; - -struct Foo -{ - int x; - int y; -} - - - -//define bar::blub(Foo, 1) as fooblub; - -public fn void main() -{ - Foo f = { 3, 4 }; - //Foo g = fooblub(&f); -} \ No newline at end of file diff --git a/resources/testfragments/file2.c3 b/resources/testfragments/file2.c3 deleted file mode 100644 index 04f9711d0..000000000 --- a/resources/testfragments/file2.c3 +++ /dev/null @@ -1,7 +0,0 @@ -module bar(Type, i); - -public fn Type blub(Type type) -{ - type.x = i; - return type; -} \ No newline at end of file diff --git a/resources/testfragments/lexertest.c3 b/resources/testfragments/lexertest.c3 deleted file mode 100644 index 825bcf28e..000000000 --- a/resources/testfragments/lexertest.c3 +++ /dev/null @@ -1,24 +0,0 @@ -module foo; - -const int = 0; - -struct Boo -{ - int i; - union - { - int death; - }; -} - -fn void test() -{ - int i = 0; - i++; - if (i < 100) - { - int j = 0; - j += i; - return; - } -} \ No newline at end of file diff --git a/resources/testfragments/test_break.c3 b/resources/testfragments/test_break.c3 deleted file mode 100644 index 69a3d7cb8..000000000 --- a/resources/testfragments/test_break.c3 +++ /dev/null @@ -1,30 +0,0 @@ -module foo; - -extern fn void printf(char *hello, ...); - -error MyError; -error YourError; -fn void main() -{ - int! i = 1; - catch (i) - { - printf("Caught\n"); - return; - } - i = MyError!; - catch FOO: (i) - { - case YourError: - printf("YourError\n"); - case MyError: - printf("MyError\n"); - next FOO : YourError; - default: - printf("Any error\n"); - } - do - { - printf("Test\n"); - } -} \ No newline at end of file diff --git a/resources/testfragments/testdefer.c3 b/resources/testfragments/testdefer.c3 index ae332cd78..5391f5d52 100644 --- a/resources/testfragments/testdefer.c3 +++ b/resources/testfragments/testdefer.c3 @@ -1,19 +1,19 @@ extern fn void printf(char* message, ...); -public fn void defer1() {} -public fn void defer2() {} -public fn void defer3() {} -public fn void defer4() {} -public fn void defer5() {} -public fn void defer6() {} -public fn void defer7() {} -public fn void defer8() {} -public fn void defer9() {} -public fn void defer10() {} -public fn void defer11() {} +fn void defer1() {} +fn void defer2() {} +fn void defer3() {} +fn void defer4() {} +fn void defer5() {} +fn void defer6() {} +fn void defer7() {} +fn void defer8() {} +fn void defer9() {} +fn void defer10() {} +fn void defer11() {} -public fn int main(int argc) +fn int main(int argc) { int a = 0; { diff --git a/src/compiler/abi/c_abi_aarch64.c b/src/compiler/abi/c_abi_aarch64.c index e467c0d05..d890c7674 100644 --- a/src/compiler/abi/c_abi_aarch64.c +++ b/src/compiler/abi/c_abi_aarch64.c @@ -6,7 +6,11 @@ INLINE bool is_aarch64_illegal_vector(Type *type) { - if (type->type_kind != TYPE_VECTOR) return type->type_kind == TYPE_SCALED_VECTOR; + if (type->type_kind != TYPE_VECTOR) + { + // Return true if scaled vector + return false; + } ArraySize len = type->array.len; if (!is_power_of_two(len)) return true; switch (type_size(type)) @@ -22,7 +26,7 @@ INLINE bool is_aarch64_illegal_vector(Type *type) ABIArgInfo *aarch64_coerce_illegal_vector(Type *type) { - if (type->type_kind == TYPE_SCALED_VECTOR) + if (false /*type->type_kind == TYPE_SCALED_VECTOR*/) { /* Type *base_type = type->array.base; @@ -61,7 +65,7 @@ ABIArgInfo *aarch64_coerce_illegal_vector(Type *type) { return abi_arg_new_direct_coerce_type(type_ushort); } - // 32 bits or less? Put in int. + // 32 bits or fewer? Put in int. if (size <= 4) return abi_arg_new_direct_coerce_type(type_uint); // 64 bits or less? Put in uint[<2>] @@ -212,7 +216,7 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic) void c_abi_func_create_aarch64(FunctionPrototype *prototype) { - prototype->ret_abi_info = aarch64_classify_return_type(prototype->abi_ret_type, prototype->variadic == VARIADIC_RAW); + prototype->ret_abi_info = aarch64_classify_return_type(prototype->abi_ret_type, prototype->raw_variadic); if (prototype->ret_by_ref) { prototype->ret_by_ref_abi_info = aarch64_classify_argument_type(type_get_ptr(type_flatten(prototype->ret_by_ref_type))); diff --git a/src/compiler/abi/c_abi_x64.c b/src/compiler/abi/c_abi_x64.c index 80bdfff2b..6813f425c 100644 --- a/src/compiler/abi/c_abi_x64.c +++ b/src/compiler/abi/c_abi_x64.c @@ -336,7 +336,7 @@ void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X6 // 1 x double passed in memory (by gcc) if (element->type_kind == TYPE_F64) return; - // 1 x long long is passed different on older clang and + // 1 x "long long" is passed different on older clang and // gcc, we pick SSE which is the GCC and later Clang standard. *current = CLASS_SSE; // Split if crossing boundary. @@ -385,11 +385,10 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_TYPEID: case TYPE_FUNC: case TYPE_DISTINCT: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: case TYPE_BITSTRUCT: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case CT_TYPES: UNREACHABLE case TYPE_VOID: @@ -413,6 +412,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_I64: *current = CLASS_INTEGER; break; + case TYPE_BF16: case TYPE_F16: case TYPE_F32: case TYPE_F64: @@ -436,9 +436,6 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_VECTOR: x64_classify_vector(type, offset_base, current, lo_class, hi_class, named); break; - case TYPE_SCALED_VECTOR: - *current = CLASS_MEMORY; - break; } } @@ -502,22 +499,65 @@ bool x64_contains_float_at_offset(Type *type, unsigned offset) return false; } -static AbiType x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source_type, unsigned source_offset) +static Type *x64_get_fp_type_at_offset(Type *type, unsigned ir_offset) { - // The only three choices we have are either double, <2 x float>, or float. We - // pass as float if the last 4 bytes is just padding. This happens for - // structs that contain 3 floats. - if (x64_bits_contain_no_user_data(source_type, source_offset + 4, source_offset + 8)) return abi_type_get(type_float); - - // We want to pass as <2 x float> if the LLVM IR type contains a float at - // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the - // case. - if (x64_contains_float_at_offset(type, ir_offset) && - x64_contains_float_at_offset(type, ir_offset + 4)) + if (!ir_offset && type_is_float(type)) return type; + if (type->type_kind == TYPE_STRUCT) { - return abi_type_get(type_get_vector(type_float, 2)); + Decl *element = x64_get_member_at_offset(type->decl, ir_offset); + return x64_get_fp_type_at_offset(element->type, ir_offset - element->offset); } - return abi_type_get(type_double); + if (type->type_kind == TYPE_ARRAY) + { + Type *element_type = type_lowering(type->array.base); + ByteSize size = type_size(element_type); + return x64_get_fp_type_at_offset(element_type, ir_offset - size * (ir_offset / size)); + } + return NULL; +} + +static Type *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source_type, unsigned source_offset) +{ + Type *float_type = x64_get_fp_type_at_offset(type, ir_offset); + if (!float_type || float_type == type_double) return type_double; + + ByteSize size = type_size(float_type); + ByteSize source_size = type_size(source_type) - source_offset; + + Type *float_type2 = NULL; + if (source_size > size) + { + float_type2 = x64_get_fp_type_at_offset(type, ir_offset + size); + } + + if (!float_type2) + { + // Check if type is half / bf16 + float, float will be at offset + 4 due + // to alignment. + if (type_is_16bit_float(float_type) && source_size > 4) + { + float_type2 = x64_get_fp_type_at_offset(type, ir_offset + 4); + } + // If we can't get a second FP type, return a simple half or float. + if (!float_type2) return float_type; + } + + if (float_type == type_float && float_type == float_type2) + { + return type_get_vector(float_type, 2); + } + + if (type_is_16bit_float(float_type) && type_is_16bit_float(float_type2)) + { + bool has_following_float = source_size > 4 + && x64_get_fp_type_at_offset(type, ir_offset + 4) != NULL; + return type_get_vector(float_type, has_following_float ? 4 : 2); + } + if (type_is_16bit_float(float_type) || type_is_16bit_float(float_type2)) + { + return type_get_vector(type_float16, 4); + } + return type_double; } /** @@ -580,24 +620,18 @@ AbiType x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_typ case TYPE_FUNC: case TYPE_TYPEDEF: case TYPE_DISTINCT: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: case TYPE_BITSTRUCT: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case CT_TYPES: UNREACHABLE case TYPE_I128: case TYPE_U128: - case TYPE_F16: - case TYPE_F32: - case TYPE_F64: - case TYPE_F128: + case ALL_FLOATS: case TYPE_UNION: case TYPE_VECTOR: break; - case TYPE_SCALED_VECTOR: - return (AbiType) { .type = type }; } ByteSize size = type_size(source_type); assert(size != source_offset); @@ -687,8 +721,10 @@ ABIArgInfo *x64_classify_return(Type *return_type) } break; case CLASS_SSE: - result_type = x64_get_sse_type_at_offset(return_type, 0, return_type, 0); + result_type = abi_type_get(x64_get_sse_type_at_offset(return_type, 0, return_type, 0)); break; + default: + UNREACHABLE } AbiType high_part = ABI_TYPE_EMPTY; @@ -704,7 +740,7 @@ ABIArgInfo *x64_classify_return(Type *return_type) break; case CLASS_SSE: assert(lo_class != CLASS_NO_CLASS); - high_part = x64_get_sse_type_at_offset(return_type, 8, return_type, 8); + high_part = abi_type_get(x64_get_sse_type_at_offset(return_type, 8, return_type, 8)); break; case CLASS_SSEUP: // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte @@ -755,7 +791,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs assert(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY); assert(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE); - AbiType result_type = ABI_TYPE_EMPTY; + AbiType result_type; *needed_registers = (Registers) { 0, 0 }; // Start by checking the lower class. @@ -779,7 +815,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs } break; case CLASS_SSE: - result_type = x64_get_sse_type_at_offset(type, 0, type, 0); + result_type = abi_type_get(x64_get_sse_type_at_offset(type, 0, type, 0)); needed_registers->sse_registers++; break; } @@ -800,7 +836,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs break; case CLASS_SSE: needed_registers->sse_registers++; - high_part = x64_get_sse_type_at_offset(type, 8, type, 8); + high_part = abi_type_get(x64_get_sse_type_at_offset(type, 8, type, 8)); assert(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff"); break; case CLASS_SSEUP: diff --git a/src/compiler/abi/c_abi_x86.c b/src/compiler/abi/c_abi_x86.c index dd938e4ff..54fd844bf 100644 --- a/src/compiler/abi/c_abi_x86.c +++ b/src/compiler/abi/c_abi_x86.c @@ -25,7 +25,7 @@ static bool type_is_union_struct_with_simd_vector(Type *type) { Type *member_type = members[i]->type; if (type_is_simd_vector(member_type)) return true; - if (type_is_union_struct_with_simd_vector(type)) return true; + if (type_is_union_struct_with_simd_vector(member_type)) return true; } return false; } @@ -115,15 +115,12 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_ENUM: case TYPE_FAULTTYPE: case TYPE_TYPEID: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_BITSTRUCT: case CT_TYPES: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_FLEXIBLE_ARRAY: UNREACHABLE - case TYPE_SCALED_VECTOR: - return false; case ALL_INTS: case ALL_FLOATS: case TYPE_BOOL: @@ -461,14 +458,13 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) case TYPE_TYPEDEF: case TYPE_VOID: case TYPE_ENUM: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEID: case TYPE_BITSTRUCT: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case CT_TYPES: case TYPE_FLEXIBLE_ARRAY: UNREACHABLE @@ -485,8 +481,6 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) case TYPE_ANY: case TYPE_ARRAY: return x86_classify_aggregate(call, regs, type); - case TYPE_SCALED_VECTOR: - // No scaled vectors in x86 UNREACHABLE } UNREACHABLE diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 158adf7f5..b837f7e23 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -118,7 +118,7 @@ const char *decl_to_a_name(Decl *decl) switch (decl->decl_kind) { case DECL_BODYPARAM: - return "a bodyparam"; + return "a body parameter"; case DECL_DECLARRAY: return "a declarray"; case DECL_BITSTRUCT: diff --git a/src/compiler/bigint.c b/src/compiler/bigint.c index 2e39fb21d..f538a6e14 100644 --- a/src/compiler/bigint.c +++ b/src/compiler/bigint.c @@ -336,7 +336,7 @@ Int128 i128_ashr(Int128 op1, Int128 op2) return i128_ashr64(op1, op2.low); } -Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped) +UNUSED Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped) { Int128 res = i128_add64(op1, (uint64_t) op2); bool is_less = i128_scomp(res, op1) == CMP_LT; @@ -344,7 +344,7 @@ Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped) return res; } -Int128 i128_add_uwrap64(Int128 op1, uint64_t op2, bool *wrapped) +UNUSED Int128 i128_add_uwrap64(Int128 op1, uint64_t op2, bool *wrapped) { Int128 res = i128_add64(op1, op2); *wrapped = i128_ucomp(res, op1) == CMP_LT; @@ -466,12 +466,12 @@ uint32_t i128_clz(const Int128 *op) return op->high ? clz64(op->high) : clz64(op->low) + 64; } -int i128_lsb(const Int128 *op) +UNUSED int i128_lsb(const Int128 *op) { return (int)(127 - i128_ctz(op)); } -int i128_msb(const Int128 *op) +UNUSED int i128_msb(const Int128 *op) { return (int)(127 - i128_clz(op)); } @@ -548,7 +548,7 @@ Int128 i128_from_signed(int64_t i) return (Int128){ i < 0 ? UINT64_MAX : 0, (uint64_t)i }; } -Int128 i128_from_unsigned(uint64_t i) +UNUSED Int128 i128_from_unsigned(uint64_t i) { return (Int128){ 0, i }; } @@ -567,7 +567,7 @@ Int128 i128_sdiv(Int128 op1, Int128 op2) return res; } -static CmpRes int_icompare(Int op1, int64_t op2) +static CmpRes int_signed_compare(Int op1, int64_t op2) { if (type_kind_is_signed(op1.type)) { @@ -600,7 +600,7 @@ bool binary_op_matches_res(BinaryOp op, CmpRes res) } -static CmpRes int_ucompare(Int op1, uint64_t op2) +static CmpRes int_unsigned_compare(Int op1, uint64_t op2) { if (type_kind_is_signed(op1.type) && i128_is_neg(op1.i)) return CMP_LT; if (op1.i.high || op1.i.low > op2) return CMP_GT; @@ -627,12 +627,12 @@ bool int_comp(Int op1, Int op2, BinaryOp op) bool int_icomp(Int op1, int64_t op2, BinaryOp op) { - return binary_op_matches_res(op, int_icompare(op1, op2)); + return binary_op_matches_res(op, int_signed_compare(op1, op2)); } bool int_ucomp(Int op1, uint64_t op2, BinaryOp op) { - return binary_op_matches_res(op, int_ucompare(op1, op2)); + return binary_op_matches_res(op, int_unsigned_compare(op1, op2)); } bool int_fits(Int op1, TypeKind kind) @@ -890,21 +890,21 @@ bool int_is_neg(Int op) } -bool i128_can_convert_from_double(double x) +UNUSED bool i128_can_convert_from_double(double x) { return isfinite(x) && x > -1 && x < ldexp(1, 128); } -bool i128_can_convert_from_double_signed(double x) +UNUSED bool i128_can_convert_from_double_signed(double x) { return isfinite(x) && x >= -ldexp(1, 127) && x < ldexp(1, 127); } -Int128 i128_from_double(double x) +UNUSED Int128 i128_from_double(double x) { if (x >= ldexp(1, 64)) { @@ -915,7 +915,7 @@ Int128 i128_from_double(double x) return i128_from_int((uint64_t)x); } -Int128 i128_from_double_signed(double x) +UNUSED Int128 i128_from_double_signed(double x) { return x < 0 ? i128_neg(i128_from_signed((int64_t)-x)) : i128_from_int((uint64_t)x); } diff --git a/src/compiler/c_abi_internal.h b/src/compiler/c_abi_internal.h index 7205c50bb..6172d47a1 100644 --- a/src/compiler/c_abi_internal.h +++ b/src/compiler/c_abi_internal.h @@ -24,7 +24,6 @@ ABIArgInfo *abi_arg_new_direct_coerce_int_ext(Type *int_to_extend); ABIArgInfo *abi_arg_new_direct_coerce_int(void); ABIArgInfo *abi_arg_new_direct_coerce_type(Type *type); ABIArgInfo *abi_arg_new_direct_struct_expand_i32(uint8_t elements); -ABIArgInfo *abi_arg_new_expand_coerce(AbiType target_type, unsigned offset); ABIArgInfo *abi_arg_new_expand_coerce_pair(Type *first_element, Type *second_element, unsigned hi_offset, bool packed); ABIArgInfo *abi_arg_new_indirect_realigned(AlignSize alignment, Type *by_val_type); ABIArgInfo *abi_arg_new_indirect_by_val(Type *by_val_type); diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index d18a170d0..40d3b430f 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -2,7 +2,6 @@ const char *test_fns_var_name = "__$C3_TEST_FN_LIST"; -const char *test_count_var_name = "__$C3_TEST_COUNT"; const char *test_names_var_name = "__$C3_TEST_NAMES_LIST"; /** * Based on isSingleElementStruct in Clang @@ -184,13 +183,12 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) case TYPE_FUNC: case TYPE_SUBARRAY: case CT_TYPES: - case TYPE_OPTIONAL_ANY: return false; case TYPE_ANY: *base = type_iptr->canonical; *elements = 2; return true; - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: type = type_iptr; goto RETRY; @@ -238,7 +236,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) } goto TYPECHECK; case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: + // Same with scaled vectors return false; case TYPE_ARRAY: // Empty arrays? Not homogenous. diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index 4d3f7fd26..50328fa9f 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -34,13 +34,15 @@ static inline Type *type_lowering(Type *type) case TYPE_ENUM: type = type->decl->enums.type_info->type; continue; - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_FAULTTYPE: return type_iptr->canonical; case TYPE_BITSTRUCT: type = type->decl->bitstruct.base_type->type; continue; + case TYPE_WILDCARD: + type = type_void; default: return type; } @@ -85,5 +87,4 @@ static inline bool expr_is_vector_index(Expr *expr) const char *codegen_create_asm(Ast *ast); extern const char *test_fns_var_name; -extern const char *test_count_var_name; extern const char *test_names_var_name; \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index d1c496cdd..a91840594 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -4,9 +4,6 @@ #include "compiler_internal.h" #include -#ifndef _MSC_VER -#include -#endif #define MAX_OUTPUT_FILES 1000000 #define MAX_MODULES 100000 @@ -289,7 +286,7 @@ void compiler_compile(void) return; } - void **gen_contexts = VECNEW(void*, module_count); + void **gen_contexts; void (*task)(void *); if (active_target.asm_file_dir || active_target.ir_file_dir || active_target.emit_object_files) @@ -407,9 +404,16 @@ void compiler_compile(void) #if USE_PTHREAD INFO_LOG("Will use %d thread(s).", active_target.build_threads); #endif - - TaskQueueRef queue = taskqueue_create(active_target.build_threads, tasks); - taskqueue_wait_for_completion(queue); + unsigned task_count = vec_size(tasks); + if (task_count == 1) + { + tasks[0]->task(tasks[0]->arg); + } + else if (task_count > 1) + { + TaskQueueRef queue = taskqueue_create(active_target.build_threads > task_count ? task_count : active_target.build_threads, tasks); + taskqueue_wait_for_completion(queue); + } if (active_target.print_output) { @@ -685,8 +689,8 @@ void print_syntax(BuildOptions *options) puts("precedence | operators"); puts("---------------+----------"); puts(" 1. Macro | @ "); - puts(" 2. Call | . () [] postfix ++/-- postfix !"); - puts(" 3. Unary | ! - + ~ * & prefix ++/-- try catch (cast)"); + puts(" 2. Call | . () [] !! postfix ++/-- postfix !"); + puts(" 3. Unary | ! - + ~ * & prefix ++/-- (cast)"); puts(" 4. Mult | * / %"); puts(" 5. Shift | << >>"); puts(" 6. Bitwise | ^ | &"); @@ -738,7 +742,7 @@ static int jump_buffer_size() // Based on Godbolt return 24; case MACOS_AARCH64: - // Based on MacOS headers + // Based on macOS headers return 25; case LINUX_X86: case MCU_X86: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 0ff3fa222..2900fcd08 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -560,6 +560,7 @@ typedef struct bool attr_naked : 1; bool attr_test : 1; bool attr_winmain : 1; + bool has_faults : 1; Decl** generated_lambda; }; struct @@ -831,7 +832,7 @@ typedef struct { ExprId ptr; ExprId type_id; -} ExprVariant; +} ExprAny; typedef struct { @@ -845,6 +846,7 @@ typedef enum ACCESS_LEN, ACCESS_PTR, ACCESS_TYPEOFANY, + ACCESS_TYPEOFANYFAULT, ACCESS_ENUMNAME, ACCESS_FAULTNAME, ACCESS_FAULTORDINAL, @@ -870,7 +872,7 @@ typedef struct DesignatorElement_ DesignatorType kind : 4; union { - const char *field; + Expr *field_expr; struct { Expr *index_expr; @@ -910,11 +912,7 @@ typedef struct Decl *decl; } ExprIdentifierRaw; -typedef struct -{ - bool array : 1; - Expr *inner; -} ExprFlatElement; + typedef struct { @@ -924,7 +922,7 @@ typedef struct struct { Expr *main_var; - ExprFlatElement *flat_path; + DesignatorElement **flat_path; }; struct { @@ -1103,11 +1101,11 @@ typedef struct { const char *new_ident; SourceSpan span; - Expr *variant_expr; + Expr *any_expr; }; Decl *variable; }; -} ExprVariantSwitch; +} ExprAnySwitch; typedef struct { @@ -1121,11 +1119,6 @@ typedef struct const char *swizzle; } ExprSwizzle; -typedef struct -{ - Decl *argc; - Decl *argv; -} ExprArgv; struct Expr_ @@ -1137,15 +1130,14 @@ struct Expr_ union { Range vasplat_expr; ExprTypeidInfo typeid_info_expr; - ExprVariantSwitch variant_switch; // 32 + ExprAnySwitch any_switch; // 32 ExprCast cast_expr; // 12 - ExprVariant variant_expr; + ExprAny any_expr; ExprPointerOffset pointer_offset_expr; ExprAsmArg expr_asm_arg; OperatorOverload overload_expr; TypeInfo *type_expr; // 8 ExprConst const_expr; // 32 - ExprArgv argv_expr; // 16 ExprGuard rethrow_expr; // 16 Decl *decl_expr; // 8 Decl *lambda_expr; @@ -1404,17 +1396,17 @@ typedef struct typedef struct { + bool resolved; union { struct { - SourceSpan span; TypeInfo *type; const char *ident; }; Decl *decl; }; -} DocOptReturn; +} AstDocFault; typedef struct AstDocDirective_ { @@ -1429,7 +1421,7 @@ typedef struct AstDocDirective_ InOutModifier modifier : 4; bool by_ref : 1; } param; - DocOptReturn *optreturns; + Ast **faults; struct { Expr *decl_exprs; @@ -1474,6 +1466,7 @@ typedef struct Ast_ AstCtForeachStmt ct_foreach_stmt; // 40 AstAssertStmt assert_stmt; // 16 AstContractStmt contract; + AstDocFault contract_fault; }; } Ast; @@ -1588,6 +1581,7 @@ struct CompilationUnit_ Decl **faulttypes; Visibility default_visibility; bool export_by_default; + bool is_interface_file; bool test_by_default; Decl **generic_defines; Decl **ct_ifs; @@ -1635,6 +1629,7 @@ typedef struct CallEnvKind kind : 8; bool ensures : 1; bool pure : 1; + Decl **opt_returns; union { Decl *attr_declaration; @@ -1708,6 +1703,7 @@ typedef struct Path std_module_path; Type *string_type; Decl *panic_var; + Decl *panicf; Decl *main; Decl *test_func; Decl *decl_stack[MAX_GLOBAL_DECL_STACK]; @@ -1782,7 +1778,7 @@ typedef struct ABIArgInfo_ typedef struct FunctionPrototype_ { CallABI call_abi : 4; - Variadic variadic : 3; + bool raw_variadic : 1; bool use_win64 : 1; bool is_optional : 1; bool ret_by_ref : 1; @@ -1845,13 +1841,14 @@ extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isz; extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usz; extern Type *type_iptr, *type_uptr; extern Type *type_u128, *type_i128; -extern Type *type_typeid, *type_anyerr, *type_typeinfo, *type_member; +extern Type *type_typeid, *type_anyfault, *type_typeinfo, *type_member; extern Type *type_any; extern Type *type_untypedlist; -extern Type *type_anyfail; +extern Type *type_wildcard; extern Type *type_cint; extern Type *type_cuint; extern Type *type_chars; +extern Type *type_wildcard_optional; extern Type *type_string; @@ -1869,12 +1866,10 @@ extern const char *kw_argv; extern const char *kw_at_checked; extern const char *kw_at_deprecated; extern const char *kw_at_ensure; -extern const char *kw_at_optreturn; extern const char *kw_at_param; extern const char *kw_at_pure; extern const char *kw_at_require; extern const char *kw_at_return; -extern const char *kw_catch_question; extern const char *kw_check_assign; extern const char *kw_deprecated; extern const char *kw_distinct; @@ -1898,7 +1893,6 @@ extern const char *kw_ptr; extern const char *kw_pure; extern const char *kw_return; extern const char *kw_std; -extern const char *kw_try_question; extern const char *kw_type; extern const char *kw_winmain; extern const char *kw_wmain; @@ -2343,7 +2337,7 @@ Type *type_get_subarray(Type *arr_type); Type *type_get_inferred_array(Type *arr_type); Type *type_get_inferred_vector(Type *arr_type); Type *type_get_flexible_array(Type *arr_type); -Type *type_get_scaled_vector(Type *arr_type); + Type *type_get_optional(Type *optional_type); Type *type_get_vector(Type *vector_type, unsigned len); Type *type_get_vector_bool(Type *original_type); @@ -2387,8 +2381,7 @@ INLINE const char *type_invalid_storage_type_name(Type *type); INLINE bool type_is_float(Type *type); INLINE bool type_is_floatlike(Type *type); INLINE bool type_is_optional(Type *type); -INLINE bool type_is_optional_type(Type *type); -INLINE bool type_is_optional_any(Type *type); +INLINE bool type_is_wildcard(Type *type); INLINE bool type_is_void(Type *type); INLINE bool type_is_integer(Type *type); INLINE bool type_is_integer_unsigned(Type *type); @@ -2445,7 +2438,6 @@ INLINE Type *type_no_optional(Type *type) { if (!type) return NULL; if (type->type_kind == TYPE_OPTIONAL) return type->optional; - if (type->type_kind == TYPE_OPTIONAL_ANY) return type_void; return type; } @@ -2466,7 +2458,7 @@ INLINE bool type_is_pointer_sized(Type *type) INLINE Type *type_add_optional(Type *type, bool make_optional) { - if (!make_optional || type->type_kind == TYPE_OPTIONAL || type->type_kind == TYPE_OPTIONAL_ANY) return type; + if (!make_optional || type->type_kind == TYPE_OPTIONAL) return type; return type_get_optional(type); } @@ -2510,7 +2502,6 @@ INLINE bool type_len_is_inferred(Type *type) case TYPE_SUBARRAY: case TYPE_FLEXIBLE_ARRAY: case TYPE_VECTOR: - case TYPE_SCALED_VECTOR: type = type->array.base; continue; case TYPE_INFERRED_ARRAY: @@ -2526,22 +2517,17 @@ INLINE bool type_len_is_inferred(Type *type) } } -INLINE bool type_is_optional(Type *type) +INLINE bool type_is_wildcard(Type *type) { - DECL_TYPE_KIND_REAL(kind, type); - return kind == TYPE_OPTIONAL || kind == TYPE_OPTIONAL_ANY; + return type == type_wildcard || type == type_wildcard_optional; } -INLINE bool type_is_optional_type(Type *type) +INLINE bool type_is_optional(Type *type) { DECL_TYPE_KIND_REAL(kind, type); return kind == TYPE_OPTIONAL; } -INLINE bool type_is_optional_any(Type *type) -{ - return type->canonical == type_anyfail; -} INLINE bool type_is_void(Type *type) { return type->canonical == type_void; @@ -2581,15 +2567,13 @@ INLINE bool type_info_poison(TypeInfo *type) INLINE bool type_is_arraylike(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind == TYPE_ARRAY || kind == TYPE_VECTOR || kind == TYPE_FLEXIBLE_ARRAY || kind == TYPE_SCALED_VECTOR; + return kind == TYPE_ARRAY || kind == TYPE_VECTOR || kind == TYPE_FLEXIBLE_ARRAY; } INLINE bool type_is_any_arraylike(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind == TYPE_ARRAY || kind == TYPE_VECTOR - || kind == TYPE_FLEXIBLE_ARRAY || kind == TYPE_SCALED_VECTOR - || kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY; + return kind >= TYPE_FIRST_ARRAYLIKE && kind <= TYPE_LAST_ARRAYLIKE; } INLINE CanonicalType *type_pointer_type(Type *type) @@ -2648,6 +2632,12 @@ INLINE bool type_is_float(Type *type) return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST; } +INLINE bool type_is_16bit_float(Type *type) +{ + DECL_TYPE_KIND_REAL(kind, type); + return kind == TYPE_BF16 || kind == TYPE_F16; +} + INLINE bool type_is_floatlike(Type *type) { type = type->canonical; @@ -2674,13 +2664,16 @@ INLINE const char *type_invalid_storage_type_name(Type *type) INLINE bool type_is_invalid_storage_type(Type *type) { if (!type) return false; + if (type == type_wildcard_optional) return true; switch (type->type_kind) { case TYPE_MEMBER: case TYPE_UNTYPED_LIST: case TYPE_TYPEINFO: + case TYPE_WILDCARD: return true; default: + return false; } } @@ -2764,8 +2757,6 @@ static inline Type *type_base(Type *type) case TYPE_OPTIONAL: type = type->optional; break; - case TYPE_OPTIONAL_ANY: - return type_void; case TYPE_TYPEDEF: UNREACHABLE default: @@ -2787,8 +2778,6 @@ static inline Type *type_flatten(Type *type) case TYPE_OPTIONAL: type = type->optional; break; - case TYPE_OPTIONAL_ANY: - return type_void; case TYPE_TYPEDEF: UNREACHABLE default: @@ -2879,7 +2868,7 @@ INLINE bool type_flat_is_vector_bitstruct(Type *type) INLINE bool type_kind_is_any_vector(TypeKind kind) { - return kind == TYPE_VECTOR || kind == TYPE_INFERRED_VECTOR || kind == TYPE_SCALED_VECTOR; + return kind == TYPE_VECTOR || kind == TYPE_INFERRED_VECTOR; } INLINE bool type_flat_is_bool_vector(Type *type) diff --git a/src/compiler/context.c b/src/compiler/context.c index a5fc2e9ac..468c90eff 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -9,6 +9,7 @@ CompilationUnit *unit_create(File *file) { CompilationUnit *unit = CALLOCS(CompilationUnit); unit->file = file; + unit->is_interface_file = str_has_suffix(file->name, ".c3i"); htable_init(&unit->local_symbols, 64 * 1024); return unit; } diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 8ad8a9da3..8e561c455 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -26,7 +26,7 @@ static inline void copy_reg_ref(CopyStruct *c, void *original, void *result) c->current_fixup++; if (c->current_fixup == &c->fixups[MAX_FIXUPS]) { - error_exit("Too many fixups for macros."); + error_exit("Too many fix-ups for macros."); } } @@ -139,6 +139,7 @@ static DesignatorElement **macro_copy_designator_list(CopyStruct *c, DesignatorE switch (to_copy->kind) { case DESIGNATOR_FIELD: + MACRO_COPY_EXPR(element->field_expr); // Nothing needed break; case DESIGNATOR_RANGE: @@ -293,7 +294,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) Expr *expr = expr_copy(source_expr); switch (source_expr->expr_kind) { - case EXPR_VARIANTSWITCH: + case EXPR_ANYSWITCH: UNREACHABLE case EXPR_MACRO_BODY_EXPANSION: MACRO_COPY_EXPR_LIST(expr->body_expansion_expr.values); @@ -309,7 +310,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_SWIZZLE: MACRO_COPY_EXPRID(expr->swizzle_expr.parent); return expr; - case EXPR_FLATPATH: case EXPR_NOP: case EXPR_BUILTIN: case EXPR_RETVAL: @@ -331,9 +331,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); return expr; - case EXPR_VARIANT: - MACRO_COPY_EXPRID(expr->variant_expr.ptr); - MACRO_COPY_EXPRID(expr->variant_expr.type_id); + case EXPR_ANY: + MACRO_COPY_EXPRID(expr->any_expr.ptr); + MACRO_COPY_EXPRID(expr->any_expr.type_id); return expr; case EXPR_CT_CALL: MACRO_COPY_EXPR(expr->ct_call_expr.main_var); @@ -413,8 +413,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) } UNREACHABLE case EXPR_FORCE_UNWRAP: - case EXPR_TRY: - case EXPR_CATCH: case EXPR_OPTIONAL: case EXPR_GROUP: case EXPR_STRINGIFY: @@ -526,8 +524,10 @@ void doc_ast_copy(CopyStruct *c, AstContractStmt *doc) case CONTRACT_CHECKED: MACRO_COPY_EXPR(doc->contract.decl_exprs); break; + case CONTRACT_OPTIONALS: + MACRO_COPY_AST_LIST(doc->faults); + break; case CONTRACT_PARAM: - case CONTRACT_ERRORS: case CONTRACT_PURE: case CONTRACT_UNKNOWN: break; @@ -553,6 +553,16 @@ RETRY: case AST_DECLS_STMT: MACRO_COPY_DECL_LIST(ast->decls_stmt); break; + case AST_CONTRACT_FAULT: + if (ast->contract_fault.resolved) + { + MACRO_COPY_DECL(ast->contract_fault.decl); + } + else + { + MACRO_COPY_TYPE(ast->contract_fault.type); + } + break; case AST_CONTRACT: doc_ast_copy(c, &source->contract); break; @@ -653,7 +663,7 @@ RETRY: MACRO_COPY_ASTID(ast->if_stmt.else_body); MACRO_COPY_ASTID(ast->if_stmt.then_body); break; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: MACRO_COPY_EXPR(ast->nextcase_stmt.expr); break; case AST_NOP_STMT: @@ -802,7 +812,6 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source) case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_SUBARRAY: case TYPE_INFO_INFERRED_VECTOR: - case TYPE_INFO_SCALED_VECTOR: assert(source->resolve_status == RESOLVE_NOT_DONE); copy->array.base = copy_type_info(c, source->array.base); return copy; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index d621d7eb3..167d82f92 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -72,8 +72,9 @@ typedef enum AST_RETURN_STMT, AST_BLOCK_EXIT_STMT, AST_SWITCH_STMT, - AST_NEXT_STMT, + AST_NEXTCASE_STMT, AST_CONTRACT, + AST_CONTRACT_FAULT, } AstKind; @@ -116,6 +117,7 @@ typedef enum CAST_VOID, CAST_INTERR, CAST_INTPTR, + CAST_VOIDFERR } CastKind; @@ -162,8 +164,8 @@ typedef enum #define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \ case EXPR_CT_CHECKS: \ case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \ - case EXPR_COMPILER_CONST: case EXPR_CT_CALL: case EXPR_FLATPATH: \ - case EXPR_VARIANTSWITCH: case EXPR_STRINGIFY: case EXPR_CT_EVAL + case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \ + case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_CT_EVAL typedef enum { @@ -172,7 +174,7 @@ typedef enum CONTRACT_REQUIRE, CONTRACT_CHECKED, CONTRACT_PARAM, - CONTRACT_ERRORS, + CONTRACT_OPTIONALS, CONTRACT_ENSURE, } ContractKind; @@ -184,8 +186,8 @@ typedef enum INTROSPECT_TYPE_UNSIGNED_INT = 3, INTROSPECT_TYPE_FLOAT = 4, INTROSPECT_TYPE_TYPEID = 5, - INTROSPECT_TYPE_ANYERR = 6, - INTROSPECT_TYPE_VARIANT = 7, + INTROSPECT_TYPE_ANYFAULT = 6, + INTROSPECT_TYPE_ANY = 7, INTROSPECT_TYPE_ENUM = 8, INTROSPECT_TYPE_FAULT = 9, INTROSPECT_TYPE_STRUCT = 10, @@ -212,7 +214,6 @@ typedef enum EXPR_BUILTIN_ACCESS, EXPR_CALL, EXPR_CAST, - EXPR_CATCH, EXPR_CATCH_UNWRAP, EXPR_COMPILER_CONST, EXPR_COMPOUND_LITERAL, @@ -229,7 +230,6 @@ typedef enum EXPR_EXPRESSION_LIST, EXPR_EXPR_BLOCK, EXPR_OPTIONAL, - EXPR_FLATPATH, EXPR_FORCE_UNWRAP, EXPR_GROUP, EXPR_HASH_IDENT, @@ -254,15 +254,14 @@ typedef enum EXPR_SUBSCRIPT_ASSIGN, EXPR_TERNARY, EXPR_TEST_HOOK, - EXPR_TRY, EXPR_TRY_UNWRAP, EXPR_TRY_UNWRAP_CHAIN, EXPR_TYPEID, EXPR_TYPEID_INFO, EXPR_TYPEINFO, EXPR_UNARY, - EXPR_VARIANT, - EXPR_VARIANTSWITCH, + EXPR_ANY, + EXPR_ANYSWITCH, EXPR_VASPLAT, } ExprKind; @@ -337,7 +336,7 @@ typedef enum { PREC_NONE, PREC_ASSIGNMENT, // =, *=, /=, %=, +=, etc - PREC_TERNARY, // ?: ?? + PREC_TERNARY, // ?: ? ?? PREC_OR, // || PREC_AND, // && PREC_RELATIONAL, // < > <= >= == != @@ -345,10 +344,10 @@ typedef enum PREC_BIT, // ^ | & PREC_SHIFT, // << >> PREC_MULTIPLICATIVE, // * / % - PREC_UNARY, // ! - + ~ * & prefix ++/-- try? catch? (type) - PREC_CALL, // . () [] postfix ++/-- - PREC_MACRO, - PREC_FIRST = PREC_MACRO + PREC_UNARY, // ! - + ~ * & prefix ++/-- (type) + PREC_CALL, // . () [] postfix ++ -- !! ! + PREC_PRIMARY, + PREC_FIRST = PREC_PRIMARY } Precedence; typedef enum @@ -379,7 +378,6 @@ typedef enum TYPE_INFO_VECTOR, TYPE_INFO_INFERRED_ARRAY, TYPE_INFO_INFERRED_VECTOR, - TYPE_INFO_SCALED_VECTOR, TYPE_INFO_SUBARRAY, TYPE_INFO_POINTER, } TypeInfoKind; @@ -460,8 +458,8 @@ typedef enum TOKEN_CONST_IDENT, // Any purely uppercase ident, TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar - // We want to parse $foo separately. - // Otherwise we allow things like "# foo" which would be pretty bad. + // We want to parse $foo separately, + // otherwise we allow things like "$ foo" which would be pretty bad. TOKEN_CT_IDENT, // $foobar TOKEN_CT_CONST_IDENT, // $FOOBAR TOKEN_CT_TYPE_IDENT, // $Foobar @@ -505,20 +503,18 @@ typedef enum TOKEN_USHORT, TOKEN_USZ, TOKEN_FLOAT128, - TOKEN_VARIANT, - TOKEN_ANYERR, + TOKEN_ANY, + TOKEN_ANYFAULT, TOKEN_TYPEID, // Keywords TOKEN_ALIAS, // Reserved - TOKEN_AS, TOKEN_ASSERT, TOKEN_ASM, TOKEN_BITSTRUCT, TOKEN_BREAK, TOKEN_CASE, TOKEN_CATCH, - TOKEN_CATCH_QUESTION, TOKEN_CONST, TOKEN_CONTINUE, TOKEN_DEFINE, @@ -541,14 +537,12 @@ typedef enum TOKEN_MODULE, TOKEN_NEXTCASE, TOKEN_NULL, - TOKEN_PRIVATE, TOKEN_RETURN, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_TRUE, TOKEN_TRY, - TOKEN_TRY_QUESTION, TOKEN_TYPEDEF, TOKEN_UNION, TOKEN_VAR, @@ -561,7 +555,6 @@ typedef enum TOKEN_CT_DEFAULT, // $default TOKEN_CT_DEFINED, // $defined TOKEN_CT_ECHO, // $echo - TOKEN_CT_ELIF, // $elif TOKEN_CT_ELSE, // $else TOKEN_CT_ENDFOR, // $endfor TOKEN_CT_ENDFOREACH, // $endforeach @@ -605,7 +598,7 @@ typedef enum case TOKEN_IPTR: case TOKEN_LONG: \ case TOKEN_SHORT: case TOKEN_UINT128: case TOKEN_UINT: case TOKEN_ULONG: \ case TOKEN_UPTR: case TOKEN_USHORT: case TOKEN_USZ: \ - case TOKEN_ISZ: case TOKEN_FLOAT128: case TOKEN_TYPEID: case TOKEN_ANYERR: case TOKEN_VARIANT + case TOKEN_ISZ: case TOKEN_FLOAT128: case TOKEN_TYPEID: case TOKEN_ANYFAULT: case TOKEN_ANY #define TYPE_TOKENS NON_VOID_TYPE_TOKENS: case TOKEN_VOID #define CT_TYPE_TOKENS TOKEN_CT_TYPE_IDENT: case TOKEN_CT_TYPEOF: case TOKEN_CT_EVALTYPE: \ case TOKEN_CT_VATYPE: case TOKEN_CT_TYPEFROM @@ -639,13 +632,14 @@ typedef enum TYPE_INTEGER_LAST = TYPE_U128, TYPE_F16, TYPE_FLOAT_FIRST = TYPE_F16, + TYPE_BF16, TYPE_F32, TYPE_F64, TYPE_F128, TYPE_FLOAT_LAST = TYPE_F128, TYPE_NUM_LAST = TYPE_FLOAT_LAST, TYPE_ANY, - TYPE_ANYERR, + TYPE_ANYFAULT, TYPE_TYPEID, TYPE_POINTER, TYPE_ENUM, @@ -657,27 +651,28 @@ typedef enum TYPE_TYPEDEF, TYPE_DISTINCT, TYPE_ARRAY, + TYPE_FIRST_ARRAYLIKE = TYPE_ARRAY, TYPE_SUBARRAY, - TYPE_INFERRED_ARRAY, TYPE_FLEXIBLE_ARRAY, + TYPE_INFERRED_ARRAY, + TYPE_VECTOR, + TYPE_INFERRED_VECTOR, + TYPE_LAST_ARRAYLIKE = TYPE_INFERRED_VECTOR, TYPE_UNTYPED_LIST, TYPE_OPTIONAL, - TYPE_OPTIONAL_ANY, + TYPE_WILDCARD, TYPE_TYPEINFO, TYPE_MEMBER, - TYPE_INFERRED_VECTOR, - TYPE_SCALED_VECTOR, - TYPE_VECTOR, TYPE_LAST = TYPE_ANY } TypeKind; #define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: case TYPE_UNTYPED_LIST: \ -case TYPE_POISONED: case TYPE_MEMBER +case TYPE_POISONED: case TYPE_MEMBER: case TYPE_WILDCARD #define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \ case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128 #define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128 #define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128 -#define ALL_FLOATS TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128 +#define ALL_FLOATS TYPE_BF16: case TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128 #define TYPE_KINDS (TYPE_LAST + 1) @@ -936,6 +931,7 @@ typedef enum typedef enum { TYPE_PROPERTY_ALIGNOF, + TYPE_PROPERTY_ASSOCIATED, TYPE_PROPERTY_ELEMENTS, TYPE_PROPERTY_EXTNAMEOF, TYPE_PROPERTY_INF, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index aa82de60f..334e06384 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -89,7 +89,6 @@ bool expr_may_addr(Expr *expr) case EXPR_BUILTIN_ACCESS: case EXPR_CALL: case EXPR_CAST: - case EXPR_CATCH: case EXPR_CATCH_UNWRAP: case EXPR_COMPILER_CONST: case EXPR_COMPOUND_LITERAL: @@ -106,7 +105,6 @@ bool expr_may_addr(Expr *expr) case EXPR_EXPRESSION_LIST: case EXPR_EXPR_BLOCK: case EXPR_OPTIONAL: - case EXPR_FLATPATH: case EXPR_FORCE_UNWRAP: case EXPR_HASH_IDENT: case EXPR_INITIALIZER_LIST: @@ -125,14 +123,13 @@ bool expr_may_addr(Expr *expr) case EXPR_SUBSCRIPT_ADDR: case EXPR_SUBSCRIPT_ASSIGN: case EXPR_TERNARY: - case EXPR_TRY: case EXPR_TRY_UNWRAP: case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TYPEID: case EXPR_TYPEID_INFO: case EXPR_TYPEINFO: - case EXPR_VARIANT: - case EXPR_VARIANTSWITCH: + case EXPR_ANY: + case EXPR_ANYSWITCH: case EXPR_VASPLAT: case EXPR_SWIZZLE: case EXPR_LAMBDA: @@ -174,7 +171,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_ACCESS: expr = expr->access_expr.parent; goto RETRY; - case EXPR_VARIANTSWITCH: + case EXPR_ANYSWITCH: return false; case EXPR_BITASSIGN: return false; @@ -187,18 +184,20 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case ACCESS_PTR: case ACCESS_FAULTORDINAL: break; + case ACCESS_TYPEOFANYFAULT: case ACCESS_TYPEOFANY: if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false; break; } return exprid_is_constant_eval(expr->builtin_access_expr.inner, eval_kind); - case EXPR_VARIANT: - return exprid_is_constant_eval(expr->variant_expr.type_id, eval_kind) && exprid_is_constant_eval(expr->variant_expr.ptr, eval_kind); + case EXPR_ANY: + return exprid_is_constant_eval(expr->any_expr.type_id, eval_kind) && exprid_is_constant_eval(expr->any_expr.ptr, eval_kind); case EXPR_BINARY: return expr_binary_is_constant_eval(expr, eval_kind); case EXPR_CAST: return expr_cast_is_constant_eval(expr, eval_kind); case EXPR_CONST: + return true; case EXPR_OPERATOR_CHARS: case EXPR_STRINGIFY: case EXPR_CT_CHECKS: @@ -289,10 +288,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) assert(!exprid_is_constant_eval(expr->ternary_expr.cond, eval_kind)); return false; case EXPR_FORCE_UNWRAP: - case EXPR_TRY: - case EXPR_CATCH: - expr = expr->inner_expr; - goto RETRY; case EXPR_TYPEID: return eval_kind != CONSTANT_EVAL_CONSTANT_VALUE; case EXPR_UNARY: @@ -325,7 +320,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_TYPEINFO: case EXPR_HASH_IDENT: case EXPR_CT_IDENT: - case EXPR_FLATPATH: case EXPR_COMPOUND_LITERAL: case EXPR_POISONED: case EXPR_CT_ARG: @@ -344,6 +338,8 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ { case CAST_ERROR: UNREACHABLE + case CAST_VOIDFERR: + return false; case CAST_BSINT: case CAST_BSARRY: return true; @@ -554,6 +550,7 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) case TYPE_POISONED: case TYPE_VOID: case TYPE_INFERRED_VECTOR: + case TYPE_WILDCARD: UNREACHABLE case ALL_INTS: expr_rewrite_const_int(expr, type, 0); @@ -567,7 +564,7 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) case TYPE_POINTER: case TYPE_FAULTTYPE: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: expr_rewrite_const_null(expr, type); return; @@ -577,7 +574,6 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) break; case TYPE_FUNC: case TYPE_TYPEDEF: - case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: case TYPE_TYPEINFO: case TYPE_MEMBER: @@ -590,7 +586,6 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) case TYPE_INFERRED_ARRAY: case TYPE_FLEXIBLE_ARRAY: case TYPE_UNTYPED_LIST: - case TYPE_SCALED_VECTOR: case TYPE_VECTOR: { ConstInitializer *init = CALLOCS(ConstInitializer); @@ -642,8 +637,8 @@ bool expr_is_pure(Expr *expr) return exprid_is_pure(expr->swizzle_expr.parent); case EXPR_BUILTIN_ACCESS: return exprid_is_pure(expr->builtin_access_expr.inner); - case EXPR_VARIANT: - return exprid_is_pure(expr->variant_expr.type_id) && exprid_is_pure(expr->variant_expr.ptr); + case EXPR_ANY: + return exprid_is_pure(expr->any_expr.type_id) && exprid_is_pure(expr->any_expr.ptr); case EXPR_POINTER_OFFSET: return exprid_is_pure(expr->pointer_offset_expr.ptr) && exprid_is_pure(expr->pointer_offset_expr.offset); case EXPR_COMPILER_CONST: @@ -666,7 +661,7 @@ bool expr_is_pure(Expr *expr) return true; case EXPR_BITASSIGN: return false; - case EXPR_VARIANTSWITCH: + case EXPR_ANYSWITCH: return false; case EXPR_BINARY: // Anything with assignment is impure, otherwise true if sub expr are pure. @@ -708,7 +703,6 @@ bool expr_is_pure(Expr *expr) case EXPR_RETHROW: case EXPR_HASH_IDENT: case EXPR_MACRO_BLOCK: - case EXPR_FLATPATH: case EXPR_INITIALIZER_LIST: case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_POST_UNARY: @@ -743,9 +737,7 @@ bool expr_is_pure(Expr *expr) && exprid_is_pure(expr->ternary_expr.then_expr); case EXPR_ASM: return false; - case EXPR_TRY: case EXPR_GROUP: - case EXPR_CATCH: return expr_is_pure(expr->inner_expr); } UNREACHABLE diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 8d046b465..29863103f 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -47,7 +47,6 @@ static void header_print_type(FILE *file, Type *type) { case CT_TYPES: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: UNREACHABLE case TYPE_VOID: OUTPUT("void"); @@ -85,6 +84,9 @@ static void header_print_type(FILE *file, Type *type) case TYPE_U128: OUTPUT("unsigned __int128"); return; + case TYPE_BF16: + OUTPUT("__bf16"); + return; case TYPE_F16: OUTPUT("__fp16"); return; @@ -104,8 +106,6 @@ static void header_print_type(FILE *file, Type *type) header_print_type(file, type->pointer); OUTPUT("*"); return; - case TYPE_SCALED_VECTOR: - error_exit("Scaled vectors are not supported yet."); case TYPE_FUNC: OUTPUT("%s", decl_get_extname(type->decl)); return; @@ -117,7 +117,7 @@ static void header_print_type(FILE *file, Type *type) case TYPE_BITSTRUCT: header_print_type(file, type->decl->bitstruct.base_type->type); return; - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: OUTPUT("c3fault_t"); return; @@ -134,7 +134,8 @@ static void header_print_type(FILE *file, Type *type) OUTPUT(" arr[%d]; }", type->array.len); return; case TYPE_ANY: - TODO + OUTPUT("c3any_t"); + return; case TYPE_SUBARRAY: OUTPUT("c3slice_t"); return; @@ -168,7 +169,7 @@ static void header_gen_function_ptr(FILE *file, HTable *table, Type *type) { extra_ret = rtype->optional; header_gen_maybe_generate_type(file, table, extra_ret); - rtype = type_anyerr; + rtype = type_anyfault; } header_gen_maybe_generate_type(file, table, rtype); FOREACH_BEGIN_IDX(i, Decl *param, sig->params) @@ -207,7 +208,7 @@ static void header_gen_function(FILE *file, FILE *file_types, HTable *table, Dec { extra_ret = rtype->optional; header_gen_maybe_generate_type(file_types, table, extra_ret); - rtype = type_anyerr; + rtype = type_anyfault; } header_gen_maybe_generate_type(file_types, table, rtype); header_print_type(file, rtype); @@ -367,14 +368,14 @@ RETRY: case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_INFERRED_VECTOR: + case TYPE_WILDCARD: UNREACHABLE - case TYPE_OPTIONAL_ANY: case TYPE_VOID: case TYPE_BOOL: case ALL_FLOATS: case ALL_INTS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_BITSTRUCT: case TYPE_FAULTTYPE: @@ -447,8 +448,6 @@ RETRY: type = type->optional; goto RETRY; break; - case TYPE_SCALED_VECTOR: - error_exit("Scaled vectors are not supported yet."); case TYPE_VECTOR: if (htable_get(table, type)) return; OUTPUT("typedef "); @@ -548,9 +547,9 @@ void header_gen(Module **modules, unsigned module_count) OUT(file_types, "#ifndef __c3__\n"); OUT(file_types, "#define __c3__\n\n"); OUT(file_types, "typedef void* c3typeid_t;\n"); - OUT(file_types, "typedef void* c3typeid_t;\n"); OUT(file_types, "typedef void* c3fault_t;\n"); OUT(file_types, "typedef struct { void* ptr; size_t len; } c3slice_t;\n"); + OUT(file_types, "typedef struct { void* ptr; c3typeid_t type; } c3any_t;\n"); OUT(file_types, "\n#endif\n\n"); OUTPUT("#include \"foo_types.h\"\n"); diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 51bfb083d..150f6684a 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -4,19 +4,6 @@ #include "compiler_internal.h" -#define LOWER_CASE \ - 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': \ - case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': \ - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z' -#define UPPER_CASE \ - 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': \ - case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': \ - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z' -#define NUM_CASE \ - '0': case '1': case '2': case '3': case '4': \ - case '5': case '6': case '7': case '8': case '9' - - static inline uint16_t check_col(intptr_t col, uint32_t row) { if (col > 255) return 0; @@ -71,9 +58,6 @@ static inline void backtrack(Lexer *lexer) } } - - - // Skip the x next characters. static inline void skip(Lexer *lexer, int steps) { @@ -85,7 +69,6 @@ static inline void skip(Lexer *lexer, int steps) } // Match a single character – if successful, more one step forward. - static inline bool match(Lexer *lexer, char expected) { if (lexer->current[0] != expected) return false; @@ -119,7 +102,9 @@ static inline void set_generic_token(Lexer *lexer, TokenType type) } else { + // For multiline, we grab the diff from the starting line. col = check_col(lexer->lexing_start - lexer->start_row_start + 1, line); + // But always set a single token length. length = 1; } lexer->tok_span.length = length; @@ -138,6 +123,7 @@ static bool add_error_token(Lexer *lexer, const char *message, ...) return false; } +// Error at the start of the lexing, with a single length. static bool add_error_token_at_start(Lexer *lexer, const char *message, ...) { va_list list; @@ -154,6 +140,8 @@ static bool add_error_token_at_start(Lexer *lexer, const char *message, ...) return false; } +// Create an error token at a particular place in the file. +// used for pointing out errors in strings etc. static bool add_error_token_at(Lexer *lexer, const char *loc, uint32_t len, const char *message, ...) { va_list list; @@ -172,6 +160,7 @@ static bool add_error_token_at(Lexer *lexer, const char *loc, uint32_t len, cons return false; } +// Print an error at the current location. static bool add_error_token_at_current(Lexer *lexer, const char *message, ...) { va_list list; @@ -202,27 +191,20 @@ static inline bool return_token(Lexer *lexer, TokenType type, const char *string // --- Comment parsing /** - * Parsing of the "//" line comment, - * also handling "///" doc comments that we probably don't need, - * but let's keep it for now. + * Parsing of the "//" line comment - skipping past the end. */ -static inline bool parse_line_comment(Lexer *lexer) +static inline void parse_line_comment(Lexer *lexer) { while (!reached_end(lexer) && peek(lexer) != '\n') { next(lexer); } // If we found EOL, then walk past '\n' - if (!reached_end(lexer)) - { - next(lexer); - } - return true; + if (peek(lexer) == '\n') next(lexer); } - /** - * Parse the common / * * / style multiline comments + * Parse the common / * * / style multiline comments, allowing nesting. **/ static inline void parse_multiline_comment(Lexer *lexer) { @@ -248,9 +230,8 @@ static inline void parse_multiline_comment(Lexer *lexer) continue; } break; - case '\n': - break; case '\0': + // Reached eof - end. return; default: break; @@ -271,12 +252,14 @@ static void skip_whitespace(Lexer *lexer) { case '/': if (lexer->mode == LEX_DOCS) return; + // The '//' case if (peek_next(lexer) == '/') { skip(lexer, 2); parse_line_comment(lexer); continue; } + // '/*' but not '/**' if (peek_next(lexer) == '*' && lexer->current[2] != '*') { skip(lexer, 2); @@ -285,6 +268,7 @@ static void skip_whitespace(Lexer *lexer) } return; case '\n': + // Doc lexing sees '\n' as a token. if (lexer->mode == LEX_DOCS) return; FALLTHROUGH; case ' ': @@ -293,6 +277,7 @@ static void skip_whitespace(Lexer *lexer) next(lexer); break; case '\r': + // Already filtered out. UNREACHABLE default: return; @@ -300,11 +285,8 @@ static void skip_whitespace(Lexer *lexer) } } - - // --- Identifier scanning - // Parses identifiers. Note that this is a bit complicated here since // we split identifiers into 2 types + find keywords. static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_token, TokenType type_token, char prefix) @@ -326,7 +308,7 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to c = peek(lexer); switch (c) { - case LOWER_CASE: + case LOWER_CHAR_CASE: if (!type) { type = normal; @@ -336,10 +318,10 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to type = type_token; } break; - case UPPER_CASE: + case UPPER_CHAR_CASE: if (!type) type = const_token; break; - case NUM_CASE: + case NUMBER_CHAR_CASE: if (!type) return add_error_token(lexer, "A letter must precede any digit"); case '_': break; @@ -372,19 +354,6 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to case TOKEN_RETURN: if (lexer->mode == LEX_DOCS) type = TOKEN_IDENT; break; - case TOKEN_TRY: - if (peek(lexer) == '?') - { - next(lexer); - return return_token(lexer, TOKEN_TRY_QUESTION, kw_try_question); - } - break; - case TOKEN_CATCH: - if (peek(lexer) == '?') - { - next(lexer); - return return_token(lexer, TOKEN_CATCH_QUESTION, kw_catch_question); - } default: break; } @@ -403,11 +372,28 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float) { char c = peek(lexer); if (!char_is_alphanum_(c)) return true; - switch (c) + switch (c | 32) { + case 'l': + c = next(lexer); + if (*is_float) + { + return add_error_token_at_current(lexer, "Integer suffix '%c' is not valid for a floating point literal.", c); + } + break; case 'u': - case 'U': - case 'I': + if (*is_float) + { + return add_error_token_at_current(lexer, "Integer suffix '%c' is not valid for a floating point literal.", c); + } + c = next(lexer); + if ((c | 32) == 'l') + { + c = next(lexer); + break; + } + while (char_is_digit(c = peek(lexer))) next(lexer); + break; case 'i': if (*is_float) { @@ -510,7 +496,7 @@ static inline bool scan_exponent(Lexer *lexer) if (c < 31 || c > 127) add_error_token(lexer, "An unexpected character was found while parsing the exponent."); return add_error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c); } - // Walk through all of the digits. + // Step through all the digits. while (char_is_digit(peek(lexer))) next(lexer); return true; } @@ -814,7 +800,7 @@ static inline bool scan_char(Lexer *lexer) "Character literals with '\\%c' can only contain one character, please remove this one.", escape); } - // Assign the value and go to DONE. + // Assign the value and go to "DONE". b.low = (uint64_t) hex; width = bytes; goto DONE; @@ -832,10 +818,6 @@ static inline bool scan_char(Lexer *lexer) b = i128_add64(b, (unsigned char)c); } assert(width > 0 && width <= 16); - if (width > 8 && !platform_target.int128) - { - return add_error_token(lexer, "Character literal exceeded 8 characters."); - } DONE: set_generic_token(lexer, TOKEN_CHAR_LITERAL); lexer->data.char_value = b; @@ -1087,6 +1069,7 @@ static inline bool scan_hex_array(Lexer *lexer) return true; } +// Scan b64"abc=" and b64'abc=' static inline bool scan_base64(Lexer *lexer) { next(lexer); // Step past 6 @@ -1288,10 +1271,7 @@ static bool lexer_scan_token_inner(Lexer *lexer) // Point start to the first non-whitespace character. begin_new_token(lexer); - if (reached_end(lexer)) - { - return return_token(lexer, TOKEN_EOF, "\n") && false; - } + if (reached_end(lexer)) return return_token(lexer, TOKEN_EOF, "\n") && false; char c = peek(lexer); next(lexer); @@ -1447,22 +1427,17 @@ static bool lexer_scan_token_inner(Lexer *lexer) } } - -void lexer_init(Lexer *lexer) +INLINE void check_bidirectional_markers(Lexer *lexer) { - lexer->file_begin = lexer->file->contents; - lexer->current = lexer->file_begin; - lexer->line_start = lexer->current; - lexer->current_row = 1; - lexer->tok_span.file_id = lexer->file->file_id; - lexer->mode = LEX_NORMAL; - begin_new_token(lexer); + // First we check for bidirectional markers. const unsigned char *check = (const unsigned char *)lexer->current; unsigned c; int balance = 0; + // Loop until end. while ((c = *(check++)) != '\0') { if (c != 0xE2) continue; + // Possible marker. unsigned char next = check[0]; if (next == 0) break; unsigned char type = check[1]; @@ -1479,22 +1454,23 @@ void lexer_init(Lexer *lexer) balance++; } break; - case 0x81: - if (type >= 0xA6 && type <= 0xA8) - { - balance++; - } - else if (type == 0xA9) - { - balance--; - if (balance < 0) goto DONE; - } - break; - default: - break; + case 0x81: + if (type >= 0xA6 && type <= 0xA8) + { + balance++; + } + else if (type == 0xA9) + { + balance--; + if (balance < 0) goto DONE; + } + break; + default: + break; } } DONE: + // Check for unbalanced result if (balance != 0) { add_error_token_at_start(lexer, "Invalid encoding - Unbalanced bidirectional markers."); @@ -1502,20 +1478,46 @@ void lexer_init(Lexer *lexer) } } +// Initialize a file +void lexer_init(Lexer *lexer) +{ + // Set the current file. + lexer->file_begin = lexer->file->contents; + // Set current to beginning. + lexer->current = lexer->file_begin; + // Line start is current. + lexer->line_start = lexer->current; + // Row number starts at 1 + lexer->current_row = 1; + // File id is the current file. + lexer->tok_span.file_id = lexer->file->file_id; + // Mode is NORMAL + lexer->mode = LEX_NORMAL; + // Set up lexing for a new token. + begin_new_token(lexer); + // Check for bidirectional markers. + check_bidirectional_markers(lexer); +} + bool lexer_next_token(Lexer *lexer) { + // Scan for a token. if (lexer_scan_token_inner(lexer)) return true; + // Failed, so check if we're at end: if (reached_end(lexer)) return true; + // Scan through the rest of the text for other invalid tokens: bool token_is_ok = false; do { if (!token_is_ok) { + // Scan to the end of the line if we have an error. while (!reached_end(lexer) && peek(lexer) != '\n') next(lexer); } token_is_ok = lexer_scan_token_inner(lexer); } while (!reached_end(lexer)); + // Done. return false; } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 1c6931729..816c7b8ef 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -8,7 +8,7 @@ #include #include #include -#include + typedef struct LLVMOpaquePassBuilderOptions *LLVMPassBuilderOptionsRef; LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes, LLVMTargetMachineRef TM, @@ -88,9 +88,9 @@ static void gencontext_destroy(GenContext *context) LLVMValueRef llvm_emit_is_no_opt(GenContext *c, LLVMValueRef error_value) { - LLVMValueRef compare = LLVMBuildICmp(c->builder, LLVMIntEQ, error_value, llvm_get_zero(c, type_anyerr), "not_err"); - LLVMValueRef vals[2] = { compare, LLVMConstInt(c->bool_type, 1, false) }; - return llvm_emit_call_intrinsic(c, intrinsic_id.expect, &c->bool_type, 1, vals, 2); + LLVMValueRef compare = LLVMBuildICmp(c->builder, LLVMIntEQ, error_value, llvm_get_zero(c, type_anyfault), "not_err"); + LLVMValueRef values[2] = { compare, LLVMConstInt(c->bool_type, 1, false) }; + return llvm_emit_call_intrinsic(c, intrinsic_id.expect, &c->bool_type, 1, values, 2); } LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ptr, uint64_t size, AlignSize align) @@ -438,7 +438,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) LLVMValueRef optional_ref = decl->var.optional_ref; if (optional_ref) { - llvm_set_alignment(optional_ref, type_alloca_alignment(type_anyerr)); + llvm_set_alignment(optional_ref, type_alloca_alignment(type_anyfault)); LLVMSetUnnamedAddress(optional_ref, LLVMGlobalUnnamedAddr); } if (init_expr && IS_OPTIONAL(init_expr) && init_expr->expr_kind == EXPR_OPTIONAL) @@ -450,7 +450,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) LLVMSetInitializer(decl->backend_ref, init_value); if (optional_ref) { - LLVMSetInitializer(optional_ref, llvm_get_zero(c, type_anyerr)); + LLVMSetInitializer(optional_ref, llvm_get_zero(c, type_anyfault)); } } @@ -592,28 +592,6 @@ void llvm_emit_local_var_alloca(GenContext *c, Decl *decl) } } -/** - * Values here taken from LLVM. - * @return return the inlining threshold given the build options. - */ -static int get_inlining_threshold() -{ - if (active_target.optimization_level == OPTIMIZATION_AGGRESSIVE) - { - return 250; - } - switch (active_target.size_optimization_level) - { - case SIZE_OPTIMIZATION_TINY: - return 5; - case SIZE_OPTIMIZATION_SMALL: - return 50; - default: - return 250; - } -} - - static inline unsigned lookup_intrinsic(const char *name) { return LLVMLookupIntrinsicID(name, strlen(name)); @@ -636,7 +614,6 @@ static void llvm_codegen_setup() intrinsic_id.assume = lookup_intrinsic("llvm.assume"); intrinsic_id.bitreverse = lookup_intrinsic("llvm.bitreverse"); intrinsic_id.bswap = lookup_intrinsic("llvm.bswap"); - intrinsic_id.bswap = lookup_intrinsic("llvm.bswap"); intrinsic_id.ceil = lookup_intrinsic("llvm.ceil"); intrinsic_id.convert_from_fp16 = lookup_intrinsic("llvm.convert.from.fp16"); intrinsic_id.convert_to_fp16 = lookup_intrinsic("llvm.convert.to.fp16"); @@ -914,7 +891,7 @@ void llvm_add_global_decl(GenContext *c, Decl *decl) assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST); bool same_module = decl->unit->module == c->code_module; - const char *name = same_module ? "tempglobal" : decl_get_extname(decl); + const char *name = same_module ? "temp_global" : decl_get_extname(decl); decl->backend_ref = llvm_add_global(c, name, decl->type, decl->alignment); llvm_set_alignment(decl->backend_ref, decl->alignment); if (!same_module) @@ -930,7 +907,7 @@ void llvm_add_global_decl(GenContext *c, Decl *decl) scratch_buffer_clear(); scratch_buffer_append(decl_get_extname(decl)); scratch_buffer_append(".f"); - decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyerr, 0); + decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyfault, 0); } llvm_set_global_tls(decl); } @@ -1148,7 +1125,7 @@ INLINE GenContext *llvm_gen_tests(Module** modules, unsigned module_count, LLVMC LLVMValueRef *names = NULL; LLVMValueRef *decls = NULL; - LLVMTypeRef opt_test = LLVMFunctionType(llvm_get_type(c, type_anyerr), NULL, 0, false); + LLVMTypeRef opt_test = LLVMFunctionType(llvm_get_type(c, type_anyfault), NULL, 0, false); for (unsigned i = 0; i < module_count; i++) { Module *module = modules[i]; diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index cc569578e..2759423e0 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -534,7 +534,6 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case CT_TYPES: UNREACHABLE case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: // If this is reachable then we're not doing the proper lowering. UNREACHABLE case TYPE_BOOL: @@ -554,6 +553,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case TYPE_U128: return llvm_debug_simple_type(c, type, DW_ATE_unsigned); case TYPE_F16: + case TYPE_BF16: case TYPE_F32: case TYPE_F64: case TYPE_F128: @@ -583,12 +583,10 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * return type->backend_debug_type = llvm_debug_array_type(c, type); case TYPE_SUBARRAY: return type->backend_debug_type = llvm_debug_subarray_type(c, type); - case TYPE_ANYERR: + case TYPE_ANYFAULT: return type->backend_debug_type = llvm_debug_errunion_type(c, type); case TYPE_ANY: return type->backend_debug_type = llvm_debug_any_type(c, type); - case TYPE_SCALED_VECTOR: - UNSUPPORTED; } UNREACHABLE } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 000e20f61..fd824f394 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -33,8 +33,7 @@ static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *ex static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit); static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceSpan loc); static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *expr); -static inline void llvm_emit_vararg_parameter(GenContext *c, BEValue *value, Type *vararg_type, ABIArgInfo *abi_info, Expr **varargs, Expr *vararg_splat); -static inline void llvm_emit_variant(GenContext *c, BEValue *value, Expr *expr); +static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr); static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr); static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_value, Decl *member, Decl *parent_decl); static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLVMValueRef val, Type *vector_type, @@ -153,12 +152,13 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue { llvm_emit_expr(c, &value, expr); } + if (value.type != type_void) llvm_store(c, ref, &value); } if (optional) { - llvm_store_to_ptr_raw(c, optional, llvm_get_zero(c, type_anyerr), type_anyerr); + llvm_store_to_ptr_raw(c, optional, llvm_get_zero(c, type_anyfault), type_anyfault); } POP_OPT(); @@ -168,8 +168,8 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue if (rejump_block) { llvm_emit_block(c, rejump_block); - LLVMValueRef error = llvm_load_abi_alignment(c, type_anyerr, optional, "reload_err"); - llvm_store_to_ptr_raw(c, c->opt_var, error, type_anyerr); + LLVMValueRef error = llvm_load_abi_alignment(c, type_anyfault, optional, "reload_err"); + llvm_store_to_ptr_raw(c, c->opt_var, error, type_anyfault); llvm_emit_br(c, c->catch_block); } llvm_emit_block(c, assign_block); @@ -278,7 +278,7 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu } LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0); LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1); - llvm_emit_panic_on_true(c, ok, "Addition overflow", loc); + llvm_emit_panic_on_true(c, ok, "Addition overflow", loc, NULL, NULL, NULL); return result; } @@ -500,7 +500,7 @@ static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValu } LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0); LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1); - llvm_emit_panic_on_true(c, ok, "Subtraction overflow", loc); + llvm_emit_panic_on_true(c, ok, "Subtraction overflow", loc, NULL, NULL, NULL); return result; } @@ -518,13 +518,15 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu { llvm_emit_int_comp_raw(c, &result, index->type, index->type, index->value, llvm_get_zero(c, index->type), BINARYOP_LT); - llvm_emit_panic_if_true(c, &result, "Negative array indexing", loc); + llvm_emit_panic_if_true(c, &result, "Negative array indexing", loc, "Negative array indexing (index was %d)", index, NULL); } llvm_emit_int_comp_raw(c, &result, index->type, index->type, index->value, array_max_index, BINARYOP_GE); - llvm_emit_panic_if_true(c, &result, "Array index out of bounds", loc); + BEValue max; + llvm_value_set(&max, array_max_index, index->type); + llvm_emit_panic_if_true(c, &result, "Array index out of bounds", loc, "Array index out of bounds (array had size %d, index was %d)", &max, index); } static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceSpan loc) @@ -1163,6 +1165,50 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type llvm_value_set(value, vector, to_type); } +void llvm_emit_voidfail_err(GenContext *c, BEValue *value, Expr *expr) +{ + Expr *inner = exprptr(expr->cast_expr.expr); + + if (inner->expr_kind == EXPR_IDENTIFIER) + { + Decl *decl = inner->identifier_expr.decl; + assert(IS_OPTIONAL(decl)); + llvm_value_set_address_abi_aligned(value, decl_optional_ref(decl), expr->type); + return; + } + + if (inner->expr_kind == EXPR_OPTIONAL) + { + llvm_emit_expr(c, value, inner->inner_expr); + value->type = type_lowering(expr->type); + return; + } + + LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block"); + + // Store catch/error var + PUSH_OPT(); + + LLVMValueRef error_var = llvm_emit_alloca_aligned(c, expr->type, "error_var"); + llvm_value_set_address_abi_aligned(value, error_var, expr->type); + llvm_store_raw(c, value, llvm_get_zero(c, expr->type)); + c->opt_var = error_var; + c->catch_block = end_block; + + BEValue expr_value; + llvm_emit_expr(c, &expr_value, inner); + llvm_value_fold_optional(c, &expr_value); + + // Restore. + POP_OPT(); + + // Emit success and jump to end block. + llvm_emit_br(c, end_block); + + llvm_emit_block(c, end_block); + +} + void llvm_emit_num_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) { llvm_value_rvalue(c, value); @@ -1176,7 +1222,7 @@ void llvm_emit_num_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Typ llvm_value_set(value, res, to_type); } -void llvm_emit_bool_to_intvec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) +static void llvm_emit_bool_to_intvec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) { llvm_value_rvalue(c, value); LLVMTypeRef type = llvm_get_type(c, to_type); @@ -1184,30 +1230,95 @@ void llvm_emit_bool_to_intvec_cast(GenContext *c, BEValue *value, Type *to_type, llvm_value_set(value, res, to_type); } -void llvm_emit_void_cast(GenContext *c, Expr *expr, BEValue *value) +// Prune the common occurrence where the optional is not used. +static void llvm_prune_optional(GenContext *c, LLVMBasicBlockRef discard_fail) { - // Simple path - if (!IS_OPTIONAL(expr)) + // Replace discard with the current block, + // this removes the jump in the case: + // br i1 %not_err, label %after_check, label %voiderr + //after_check: + // br label %voiderr + //voiderr: + // + LLVMValueRef block_value = LLVMBasicBlockAsValue(c->current_block); + LLVMReplaceAllUsesWith(LLVMBasicBlockAsValue(discard_fail), block_value); + + // We now have: + // br i1 %not_err, label %after_check, label %after_check + //after_check: + // + + // Find the use of this block. + LLVMUseRef use = LLVMGetFirstUse(block_value); + if (!use) return; + + LLVMValueRef maybe_br = LLVMGetUser(use); + // Expect a br instruction. + if (!LLVMIsAInstruction(maybe_br) || LLVMGetInstructionOpcode(maybe_br) != LLVMBr) return; + if (LLVMGetNumOperands(maybe_br) != 3) return; + // We expect a single user. + LLVMUseRef other_use = LLVMGetNextUse(use); + while (other_use) { - llvm_emit_expr_to_rvalue(c, expr); - llvm_value_set(value, NULL, type_void); + if (LLVMGetUser(other_use) != maybe_br) return; + other_use = LLVMGetNextUse(other_use); + } + // Both operands same block value + if (LLVMGetOperand(maybe_br, 1) != block_value || LLVMGetOperand(maybe_br, 2) != block_value) return; + + // Grab the compared value + LLVMValueRef compared = LLVMGetOperand(maybe_br, 0); + + // Remove the block and the br + LLVMBasicBlockRef prev_block = LLVMGetInstructionParent(maybe_br); + LLVMRemoveBasicBlockFromParent(c->current_block); + LLVMInstructionEraseFromParent(maybe_br); + + // Optionally remove the comparison + if (!LLVMGetFirstUse(compared)) + { + LLVMValueRef operand = NULL; + if (LLVMGetInstructionOpcode(compared) == LLVMCall) + { + operand = LLVMGetOperand(compared, 0); + } + LLVMInstructionEraseFromParent(compared); + if (operand) LLVMInstructionEraseFromParent(operand); + } + // Update the context + c->current_block = prev_block; + c->current_block_is_target = LLVMGetFirstBasicBlock(c->function) == prev_block; + LLVMPositionBuilderAtEnd(c->builder, prev_block); +} + +void llvm_emit_ignored_expr(GenContext *c, Expr *expr) +{ + BEValue value; + // For a standalone catch, we can ignore storing the value. + if (IS_OPTIONAL(expr)) + { + PUSH_OPT(); + LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr"); + c->catch_block = discard_fail; + c->opt_var = NULL; + llvm_emit_expr(c, &value, expr); + llvm_value_fold_optional(c, &value); + EMIT_LOC(c, expr); + // We only optimize if there is no instruction the current block + if (!LLVMGetFirstInstruction(c->current_block)) + { + llvm_prune_optional(c, discard_fail); + } + else + { + llvm_emit_br(c, discard_fail); + llvm_emit_block(c, discard_fail); + } + POP_OPT(); return; } + llvm_emit_expr(c, &value, expr); - PUSH_OPT(); - LLVMBasicBlockRef after_void = llvm_basic_block_new(c, "end_block"); - c->opt_var = NULL; - c->catch_block = after_void; - llvm_emit_expr_to_rvalue(c, expr); - llvm_emit_br(c, after_void); - // Ensure we are on a branch that is non-empty. - if (llvm_emit_check_block_branch(c)) - { - c->current_block = NULL; - c->current_block_is_target = false; - } - POP_OPT(); - llvm_emit_block(c, after_void); } void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *value, Type *to_type, Type *from_type) @@ -1218,6 +1329,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu switch (cast_kind) { + case CAST_VOIDFERR: + UNREACHABLE case CAST_NUMVEC: llvm_emit_num_to_vec_cast(c, value, to_type, from_type); return; @@ -1309,7 +1422,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_EUBOOL: { BEValue zero; - llvm_value_set_int(c, &zero, type_anyerr, 0); + llvm_value_set_int(c, &zero, type_anyfault, 0); llvm_emit_int_comp(c, value, value, &zero, BINARYOP_NE); break; } @@ -1387,15 +1500,16 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu if (type_is_signed(value->type)) { scratch_buffer_clear(); - scratch_buffer_printf("Conversion to enum '%s' failed - tried to convert a negative value.", decl->name); + scratch_buffer_printf("Attempt to convert a negative value (%%d) to enum '%s' failed.", decl->name); llvm_emit_int_comp_zero(c, &check, value, BINARYOP_LT); - llvm_emit_panic_on_true(c, check.value, scratch_buffer_to_string(), expr->span); + BEValue val; + llvm_emit_panic_on_true(c, check.value, "Attempt to convert negative value to enum failed.", expr->span, scratch_buffer_to_string(), value, NULL); } scratch_buffer_clear(); - scratch_buffer_printf("Conversion to enum '%s' failed - the value was greater than %u.", decl->name, max - 1); + scratch_buffer_printf("Attempting to convert %%d to enum '%s' failed as the value exceeds the max ordinal (%u).", decl->name, max - 1); LLVMValueRef val = llvm_const_int(c, value->type, max); llvm_emit_int_comp_raw(c, &check, value->type, value->type, value->value, val, BINARYOP_GE); - llvm_emit_panic_on_true(c, check.value,scratch_buffer_to_string(), expr->span); + llvm_emit_panic_on_true(c, check.value, "Failed integer to enum conversion", expr->span, scratch_buffer_to_string(), value, NULL); } // We might need to extend or truncate. if (type_size(to_type) != type_size(from_type)) @@ -1432,7 +1546,13 @@ static inline void llvm_emit_cast_expr(GenContext *context, BEValue *be_value, E { if (expr->cast_expr.kind == CAST_VOID) { - llvm_emit_void_cast(context, exprptr(expr->cast_expr.expr), be_value); + llvm_value_set(be_value, NULL, type_void); + llvm_emit_ignored_expr(context, exprptr(expr->cast_expr.expr)); + return; + } + if (expr->cast_expr.kind == CAST_VOIDFERR) + { + llvm_emit_voidfail_err(context, be_value, expr); return; } llvm_emit_exprid(context, be_value, expr->cast_expr.expr); @@ -1506,7 +1626,6 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, assert(expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER); LLVMValueRef value = llvm_emit_const_initializer(c, expr->const_expr.initializer); - LLVMTypeRef expected_type = llvm_get_type(c, canonical); // Create a global const. AlignSize alignment = type_alloca_alignment(expr->type); LLVMTypeRef type = LLVMTypeOf(value); @@ -2291,7 +2410,11 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T if (active_target.feature.safe_mode) { LLVMValueRef check = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, inner->type), "checknull"); - llvm_emit_panic_on_true(c, check, "Dereference of null pointer", inner->span); + scratch_buffer_clear(); + scratch_buffer_append("Dereference of null pointer, '"); + span_to_scratch(inner->span); + scratch_buffer_append("' was null."); + llvm_emit_panic_on_true(c, check, scratch_buffer_to_string(), inner->span, NULL, NULL, NULL); } // Load the pointer value. llvm_value_rvalue(c, value); @@ -2424,7 +2547,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) &type_to_use, 1, args, 2); value->value = llvm_emit_extract_value(c, call_res, 0); LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1); - llvm_emit_panic_on_true(c, ok, "Signed negation overflow", expr->span); + llvm_emit_panic_on_true(c, ok, "Signed negation overflow", expr->span, NULL, NULL, NULL); return; } value->value = LLVMBuildNeg(c->builder, value->value, "neg"); @@ -2483,14 +2606,15 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l } } -static void llvm_emit_trap_negative(GenContext *c, Expr *expr, LLVMValueRef value, const char *error) +static void llvm_emit_trap_negative(GenContext *c, Expr *expr, LLVMValueRef value, const char *error, + BEValue *index_val) { if (!active_target.feature.safe_mode) return; if (type_is_integer_unsigned(expr->type->canonical)) return; LLVMValueRef zero = llvm_const_int(c, expr->type, 0); LLVMValueRef ok = LLVMBuildICmp(c->builder, LLVMIntSLT, value, zero, "underflow"); - llvm_emit_panic_on_true(c, ok, error, expr->span); + llvm_emit_panic_on_true(c, ok, "Negative value", expr->span, error, index_val, NULL); } static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, const char *error, SourceSpan loc) @@ -2518,14 +2642,16 @@ static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, c LLVMValueRef zero = llvm_get_zero(c, type); LLVMValueRef ok = type_is_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero"); - llvm_emit_panic_on_true(c, ok, error, loc); + llvm_emit_panic_on_true(c, ok, error, loc, NULL, NULL, NULL); } static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type *type, const char *error, SourceSpan loc) { if (!active_target.feature.safe_mode) return; + BEValue val; type = type_flatten(type); + llvm_value_set(&val, value, type); if (type_flat_is_vector(type)) { Type *vec_base = type->array.base; @@ -2536,16 +2662,16 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type { LLVMValueRef flat_max = llvm_emit_call_intrinsic(c, intrinsic_id.vector_reduce_umax, &llvm_type, 1, &value, 1); LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntUGE, flat_max, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error, loc); + llvm_emit_panic_on_true(c, equal_or_greater, "Invalid shift", loc, error, &val, NULL); return; } LLVMValueRef flat_min = llvm_emit_call_intrinsic(c, intrinsic_id.vector_reduce_smin, &llvm_type, 1, &value, 1); LLVMValueRef zero = llvm_const_int(c, vec_base, 0); LLVMValueRef negative = LLVMBuildICmp(c->builder, LLVMIntSLT, flat_min, zero, "shift_underflow"); - llvm_emit_panic_on_true(c, negative, error, loc); + llvm_emit_panic_on_true(c, negative, "Invalid shift", loc, error, &val, NULL); LLVMValueRef flat_max = llvm_emit_call_intrinsic(c, intrinsic_id.vector_reduce_smax, &llvm_type, 1, &value, 1); LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntSGE, flat_max, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error, loc); + llvm_emit_panic_on_true(c, equal_or_greater, "Invalid shift", loc, error, &val, NULL); return; } @@ -2556,14 +2682,14 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type if (type_is_unsigned(type)) { LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntUGE, value, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error, loc); + llvm_emit_panic_on_true(c, equal_or_greater, "Invalid shift", loc, error, &val, NULL); return; } LLVMValueRef zero = llvm_const_int(c, type, 0); LLVMValueRef negative = LLVMBuildICmp(c->builder, LLVMIntSLT, value, zero, "shift_underflow"); - llvm_emit_panic_on_true(c, negative, error, loc); + llvm_emit_panic_on_true(c, negative, "Invalid shift", loc, error, &val, NULL); LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntSGE, value, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error, loc); + llvm_emit_panic_on_true(c, equal_or_greater, "Invalid shift", loc, error, &val, NULL); } } @@ -2646,13 +2772,13 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r assert(len.value); BEValue exceeds_size; llvm_emit_int_comp(c, &exceeds_size, &start_index, &len, BINARYOP_GT); - llvm_emit_panic_if_true(c, &exceeds_size, "Index exceeds array length.", slice->span); + llvm_emit_panic_if_true(c, &exceeds_size, "Index exceeds array len", slice->span, "Index exceeds array length (array had size %d, index was %d).", &len, &start_index); } // Insert trap for negative start offset for non pointers. if (parent_type->type_kind != TYPE_POINTER) { - llvm_emit_trap_negative(c, start, start_index.value, "Negative index"); + llvm_emit_trap_negative(c, start, start_index.value, "Negative indexing (%d)", &start_index); } Type *end_type; @@ -2681,12 +2807,12 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r { BEValue excess; llvm_emit_int_comp(c, &excess, &start_index, &end_index, BINARYOP_GT); - llvm_emit_panic_if_true(c, &excess, "Negative size", slice->span); + llvm_emit_panic_if_true(c, &excess, "Negative size", slice->span, "Negative size (start %d is less than end %d)", &start_index, &end_index); if (len.value) { llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LT); - llvm_emit_panic_if_true(c, &excess, "Size exceeds index", slice->span); + llvm_emit_panic_if_true(c, &excess, "Size exceeds index", slice->span, "Size exceeds index (end index was %d, size was %d)", &end_index, &len); } } } @@ -2779,7 +2905,7 @@ static void llvm_emit_slice_copy(GenContext *c, BEValue *be_value, Expr *expr) llvm_emit_subarray_len(c, &assigned_to, &to_len); BEValue comp; llvm_emit_int_comp(c, &comp, &to_len, &from_len, BINARYOP_NE); - llvm_emit_panic_if_true(c, &comp, "Subarray copy length mismatch.", expr->span); + llvm_emit_panic_if_true(c, &comp, "Length mismatch", expr->span, "Subarray copy length mismatch (%d != %d).", &to_len, &from_len); } Type *pointer_type = to_pointer.type->pointer; @@ -3212,7 +3338,7 @@ static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMVal 2); LLVMValueRef val = llvm_emit_extract_value(c, call_res, 0); LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1); - llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc); + llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc, NULL, NULL, NULL); return val; } return LLVMBuildMul(c->builder, left, right, "mul"); @@ -3433,7 +3559,6 @@ void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, assert(binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ); switch (lhs->type->type_kind) { - case TYPE_POISONED: case TYPE_VOID: UNREACHABLE; case TYPE_BOOL: @@ -3452,26 +3577,20 @@ void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, llvm_emit_array_comp(c, result, lhs, rhs, binary_op); return; case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_ENUM: case TYPE_FAULTTYPE: case TYPE_TYPEDEF: case TYPE_DISTINCT: - case TYPE_INFERRED_ARRAY: - case TYPE_UNTYPED_LIST: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: - case TYPE_TYPEINFO: - case TYPE_MEMBER: - case TYPE_INFERRED_VECTOR: + case CT_TYPES: UNREACHABLE case TYPE_FUNC: break; case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: - case TYPE_SCALED_VECTOR: case TYPE_FLEXIBLE_ARRAY: UNREACHABLE case TYPE_SUBARRAY: @@ -3517,7 +3636,7 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr) LLVMBasicBlockRef success_end_block = llvm_get_current_block_if_in_use(c); // Only jump to phi if we didn't have an immediate jump. That would - // for example happen on "{| defer foo(); return Foo.ERR! |} ?? 123" + // for example happen on "{| defer foo(); return Foo.ERR?; |} ?? 123" if (success_end_block) llvm_emit_br(c, phi_block); // Emit else @@ -3811,7 +3930,7 @@ void llvm_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs break; case BINARYOP_SHR: rhs_value = llvm_zext_trunc(c, rhs_value, LLVMTypeOf(lhs_value)); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", expr->span); + llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range (was %s).", expr->span); val = type_is_unsigned(lhs_type) ? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr") : LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr"); @@ -3819,7 +3938,7 @@ void llvm_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs break; case BINARYOP_SHL: rhs_value = llvm_zext_trunc(c, rhs_value, LLVMTypeOf(lhs_value)); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", expr->span); + llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range (was %s).", expr->span); val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl"); val = LLVMBuildFreeze(c->builder, val, ""); break; @@ -3950,92 +4069,6 @@ void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_valu } -static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *expr) -{ - Expr *inner = expr->inner_expr; - - if (inner->expr_kind == EXPR_IDENTIFIER) - { - Decl *decl = inner->identifier_expr.decl; - assert(IS_OPTIONAL(decl)); - llvm_value_set_address_abi_aligned(value, decl_optional_ref(decl), type_anyerr); - return; - } - - if (inner->expr_kind == EXPR_OPTIONAL) - { - llvm_emit_expr(c, value, inner->inner_expr); - return; - } - - LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block"); - - // Store catch/error var - PUSH_OPT(); - - LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyerr, "error_var"); - llvm_value_set_address_abi_aligned(value, error_var, type_anyerr); - llvm_store_raw(c, value, llvm_get_zero(c, type_anyerr)); - c->opt_var = error_var; - c->catch_block = end_block; - - BEValue expr_value; - llvm_emit_expr(c, &expr_value, inner); - llvm_value_fold_optional(c, &expr_value); - - // Restore. - POP_OPT(); - - // Emit success and jump to end block. - llvm_emit_br(c, end_block); - - llvm_emit_block(c, end_block); - -} -void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr) -{ - - LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block"); - LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block"); - LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block"); - - // Store catch/error var - PUSH_OPT(); - - // Set the catch/error var - c->opt_var = NULL; - c->catch_block = error_block; - - llvm_emit_expr(c, value, expr->inner_expr); - llvm_value_fold_optional(c, value); - - // Restore. - POP_OPT(); - - // Emit success and jump to phi. - llvm_emit_br(c, no_err_block); - llvm_emit_block(c, no_err_block); - llvm_emit_br(c, phi_block); - - // Emit error and jump to phi - llvm_emit_block(c, error_block); - llvm_emit_br(c, phi_block); - - llvm_emit_block(c, phi_block); - - LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val"); - LLVMValueRef lhs = llvm_const_int(c, type_bool, 1); - LLVMValueRef rhs = llvm_const_int(c, type_bool, 0); - - LLVMValueRef logic_values[2] = { lhs, rhs }; - LLVMBasicBlockRef blocks[2] = { no_err_block, error_block }; - LLVMAddIncoming(phi, logic_values, blocks, 2); - - llvm_value_set(value, phi, expr->type); -} - - - /** * This is the foo? instruction. */ @@ -4048,7 +4081,7 @@ static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr PUSH_OPT(); // Set the catch/error var - LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyerr, "error_var"); + LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyfault, "error_var"); c->opt_var = error_var; c->catch_block = guard_block; @@ -4071,7 +4104,7 @@ static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr { llvm_emit_statement_chain(c, expr->rethrow_expr.cleanup); BEValue value; - llvm_value_set_address_abi_aligned(&value, error_var, type_anyerr); + llvm_value_set_address_abi_aligned(&value, error_var, type_anyfault); llvm_emit_return_abi(c, NULL, &value); c->current_block = NULL; c->current_block_is_target = false; @@ -4094,7 +4127,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value, PUSH_OPT(); // Set the catch/error var - LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyerr, "error_var"); + LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyfault, "error_var"); c->opt_var = error_var; c->catch_block = panic_block; @@ -4118,12 +4151,16 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value, { // TODO, we should add info about the error. SourceSpan loc = expr->span; - llvm_emit_panic(c, "Runtime error force unwrap!", loc); + BEValue *varargs = NULL; + BEValue fault_arg; + llvm_value_set_address(&fault_arg, error_var, type_anyfault, type_abi_alignment(type_anyfault)); + llvm_emit_any_from_value(c, &fault_arg, type_anyfault); + vec_add(varargs, fault_arg); + llvm_emit_panic(c, "Force unwrap failed!", loc, "Unexpected fault '%s' was unwrapped!", varargs); LLVMBuildUnreachable(c->builder); c->current_block = NULL; c->current_block_is_target = false; } - llvm_emit_block(c, no_err_block); } @@ -4548,13 +4585,13 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) LLVMValueRef value; if (decl) { - value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyerr), ""); + value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyfault), ""); } else { - value = llvm_get_zero(c, type_anyerr); + value = llvm_get_zero(c, type_anyfault); } - llvm_value_set(be_value, value, type_anyerr); + llvm_value_set(be_value, value, type_anyfault); return; } case CONST_ENUM: @@ -4609,13 +4646,11 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_DISTINCT: case TYPE_ENUM: case TYPE_FAULTTYPE: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_BITSTRUCT: case TYPE_OPTIONAL: case CT_TYPES: - case TYPE_OPTIONAL_ANY: case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: UNREACHABLE break; case TYPE_BOOL: @@ -4975,7 +5010,7 @@ void llvm_add_abi_call_attributes(GenContext *c, LLVMValueRef call_value, int co } -static inline void llvm_emit_vararg_parameter(GenContext *c, BEValue *value, Type *vararg_type, ABIArgInfo *abi_info, Expr **varargs, Expr *vararg_splat) +void llvm_emit_vararg_parameter(GenContext *c, BEValue *value, Type *vararg_type, ABIArgInfo *abi_info, Expr **varargs, Expr *vararg_splat) { REMINDER("All varargs should be called with non-alias!"); @@ -5175,7 +5210,7 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype BEValue error_holder = *result_value; if (error_var) { - llvm_value_set_address_abi_aligned(&error_holder, c->opt_var, type_anyerr); + llvm_value_set_address_abi_aligned(&error_holder, c->opt_var, type_anyfault); } LLVMValueRef stored_error; @@ -5280,19 +5315,16 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr Expr **args = expr->call_expr.arguments; Expr **varargs = NULL; Expr *vararg_splat = NULL; - if (prototype->variadic != VARIADIC_NONE) + if (expr->call_expr.splat_vararg) { - if (expr->call_expr.splat_vararg) - { - vararg_splat = expr->call_expr.splat; - } - else - { - varargs = expr->call_expr.varargs; - } + vararg_splat = expr->call_expr.splat; + } + else + { + varargs = expr->call_expr.varargs; } FunctionPrototype copy; - if (prototype->variadic == VARIADIC_RAW) + if (prototype->raw_variadic) { if (varargs || vararg_splat) { @@ -5394,7 +5426,6 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr } else { - assert(prototype->variadic == VARIADIC_TYPED || prototype->variadic == VARIADIC_ANY); llvm_emit_vararg_parameter(c, &temp_value, param, info, varargs, vararg_splat); } @@ -5404,7 +5435,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr // 9. Typed varargs - if (prototype->variadic == VARIADIC_RAW) + if (prototype->raw_variadic) { if (prototype->abi_varargs) { @@ -5481,8 +5512,22 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type return; } - LLVMValueRef old_ret_out = c->return_out; + Ast *value = ast_next(¤t); + // Just a return statement, in this case we can just do the expression. + if (value->ast_kind == AST_BLOCK_EXIT_STMT && !value->return_stmt.cleanup && !value->return_stmt.cleanup_fail) + { + Expr *expr = value->return_stmt.expr; + if (!expr) + { + llvm_value_set(be_value, NULL, type_void); + return; + } + llvm_emit_expr(c, be_value, expr); + return; + } + + LLVMValueRef old_ret_out = c->return_out; LLVMValueRef error_out = c->opt_var; LLVMBasicBlockRef error_block = c->catch_block; LLVMValueRef return_out = NULL; @@ -5505,7 +5550,6 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type c->catch_block = NULL; // Process all but the last statement. - Ast *value = ast_next(¤t); while (value->next) { llvm_emit_stmt(c, value); @@ -5535,14 +5579,16 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type goto DONE; } - // Optional? Then we use the normal path - if (IS_OPTIONAL(ret_expr)) break; - - // Optimization, emit directly to value - llvm_emit_expr(c, be_value, ret_expr); - // And remove the alloca LLVMInstructionEraseFromParent(exit.block_return_out); - goto DONE; + + // Restore + c->return_out = old_ret_out; + c->catch_block = error_block; + c->opt_var = error_out; + + // Output directly to a value + llvm_emit_expr(c, be_value, ret_expr); + return; } while (0); @@ -5660,8 +5706,8 @@ static inline void llvm_emit_optional(GenContext *c, BEValue *be_value, Expr *ex // Finally we need to replace the result with something undefined here. // It will be optimized away. - Type *type = type_no_optional(expr->type); - if (type->canonical == type_void) + Type *type = type_lowering(expr->type); + if (type == type_void) { llvm_value_set(be_value, NULL, type_void); return; @@ -5772,8 +5818,8 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp if (!expr->try_unwrap_expr.optional) { LLVMValueRef fail_ref = decl_optional_ref(expr->try_unwrap_expr.decl); - LLVMValueRef errv = llvm_load(c, llvm_get_type(c, type_anyerr), fail_ref, type_abi_alignment(type_anyerr), "load.err"); - LLVMValueRef result = LLVMBuildICmp(c->builder, LLVMIntEQ, errv, llvm_get_zero(c, type_anyerr), "result"); + LLVMValueRef errv = llvm_load(c, llvm_get_type(c, type_anyfault), fail_ref, type_abi_alignment(type_anyfault), "load.err"); + LLVMValueRef result = LLVMBuildICmp(c->builder, LLVMIntEQ, errv, llvm_get_zero(c, type_anyfault), "result"); llvm_value_set(value, result, type_bool); return; } @@ -5805,8 +5851,8 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr) } else { - LLVMValueRef temp_err = llvm_emit_alloca_aligned(c, type_anyerr, "temp_err"); - llvm_value_set_address_abi_aligned(&addr, temp_err, type_anyerr); + LLVMValueRef temp_err = llvm_emit_alloca_aligned(c, type_anyfault, "temp_err"); + llvm_value_set_address_abi_aligned(&addr, temp_err, type_anyfault); } PUSH_OPT(); @@ -5828,11 +5874,11 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr) POP_OPT(); - llvm_store_raw(c, &addr, llvm_get_zero(c, type_anyerr)); + llvm_store_raw(c, &addr, llvm_get_zero(c, type_anyfault)); llvm_emit_br(c, catch_block); llvm_emit_block(c, catch_block); llvm_value_rvalue(c, &addr); - llvm_value_set(value, addr.value, type_anyerr); + llvm_value_set(value, addr.value, type_anyfault); } @@ -5877,7 +5923,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex llvm_emit_cond_br(c, &check, exit, next); llvm_emit_block(c, next); } - llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", expr->span); + llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", expr->span, NULL, NULL); c->current_block = NULL; c->current_block_is_target = false; LLVMBuildUnreachable(c->builder); @@ -5908,7 +5954,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex llvm_emit_cond_br(c, &check, exit, next); llvm_emit_block(c, next); } - llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", expr->span); + llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", expr->span, NULL, NULL); c->current_block = NULL; c->current_block_is_target = false; LLVMBuildUnreachable(c->builder); @@ -5943,7 +5989,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex llvm_emit_cond_br(c, &check, exit, next); llvm_emit_block(c, next); } - llvm_emit_panic(c, "Attempted to access 'len' on non array type", expr->span); + llvm_emit_panic(c, "Attempted to access 'len' on non array type", expr->span, NULL, NULL); c->current_block = NULL; c->current_block_is_target = false; LLVMBuildUnreachable(c->builder); @@ -6016,13 +6062,30 @@ void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr) } -static inline void llvm_emit_variant(GenContext *c, BEValue *value, Expr *expr) +void llvm_emit_any_from_value(GenContext *c, BEValue *value, Type *type) { + llvm_value_addr(c, value); + BEValue typeid; + llvm_emit_typeid(c, &typeid, type); + llvm_value_rvalue(c, &typeid); + LLVMValueRef var = llvm_get_undef(c, type_any); + var = llvm_emit_insert_value(c, var, value->value, 0); + var = llvm_emit_insert_value(c, var, typeid.value, 1); + llvm_value_set(value, var, type_any); +} + +static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr) +{ + if (!expr->any_expr.ptr && !expr->any_expr.type_id) + { + llvm_value_set(value, llvm_get_zero(c, type_any), type_any); + return; + } BEValue ptr; - llvm_emit_exprid(c, &ptr, expr->variant_expr.ptr); + llvm_emit_exprid(c, &ptr, expr->any_expr.ptr); llvm_value_rvalue(c, &ptr); BEValue typeid; - llvm_emit_exprid(c, &typeid, expr->variant_expr.type_id); + llvm_emit_exprid(c, &typeid, expr->any_expr.type_id); llvm_value_rvalue(c, &typeid); LLVMValueRef var = llvm_get_undef(c, type_any); var = llvm_emit_insert_value(c, var, ptr.value, 0); @@ -6084,7 +6147,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex case ACCESS_FAULTNAME: { Type *inner_type = type_no_optional(inner->type)->canonical; - assert(inner_type->type_kind == TYPE_FAULTTYPE || inner_type->type_kind == TYPE_ANYERR); + assert(inner_type->type_kind == TYPE_FAULTTYPE || inner_type->type_kind == TYPE_ANYFAULT); llvm_value_rvalue(c, be_value); LLVMValueRef val = llvm_emit_alloca_aligned(c, type_chars, "faultname_zero"); BEValue zero; @@ -6126,6 +6189,13 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex type_chars, llvm_abi_alignment(c, subarray)); return; } + case ACCESS_TYPEOFANYFAULT: + { + llvm_value_addr(c, be_value); + LLVMValueRef value = llvm_load(c, c->ptr_type, be_value->value, be_value->alignment, ""); + llvm_value_set_address(be_value, value, type_typeid, type_alloca_alignment(type_typeid)); + return; + } case ACCESS_TYPEOFANY: if (llvm_value_is_addr(be_value)) { @@ -6226,8 +6296,8 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_RETVAL: *value = c->retval; return; - case EXPR_VARIANT: - llvm_emit_variant(c, value, expr); + case EXPR_ANY: + llvm_emit_any(c, value, expr); return; case EXPR_TRY_UNWRAP_CHAIN: llvm_emit_try_unwrap_chain(c, value, expr); @@ -6261,12 +6331,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_OPTIONAL: llvm_emit_optional(c, value, expr); return; - case EXPR_TRY: - llvm_emit_try_expr(c, value, expr); - return; - case EXPR_CATCH: - llvm_emit_catch_expr(c, value, expr); - return; case EXPR_NOP: llvm_value_set(value, NULL, type_void); return; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index a3ba1a771..da74a43a3 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -173,7 +173,21 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, ABIAr if (decl->var.not_null && active_target.feature.safe_mode) { LLVMValueRef is_null = LLVMBuildIsNull(c->builder, param_value, ""); - llvm_emit_panic_on_true(c, is_null, "Unexpected null pointer passed as '&' parameter.", decl->span); + scratch_buffer_clear(); + if (decl->name) + { + scratch_buffer_printf("Reference parameter '%s' was passed a null pointer argument.", decl->name); + } + else + { + // This is currently not possible, but let's handle it anyway. + scratch_buffer_append("A null pointer argument was passed to a '&' parameter."); + } + llvm_emit_panic_on_true(c, + is_null, + scratch_buffer_to_string(), + decl->span, + NULL, NULL, NULL); } if (!decl->var.is_written && !decl->var.is_addr) { @@ -299,7 +313,7 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *optiona return_out = c->optional_out; if (!optional) { - llvm_value_set(&no_fail, llvm_get_zero(c, type_anyerr), type_anyerr); + llvm_value_set(&no_fail, llvm_get_zero(c, type_anyfault), type_anyfault); optional = &no_fail; } return_value = optional; @@ -383,7 +397,7 @@ void llvm_emit_return_implicit(GenContext *c) return; } BEValue value; - llvm_value_set(&value, llvm_get_zero(c, type_anyerr), type_anyerr); + llvm_value_set(&value, llvm_get_zero(c, type_anyfault), type_anyfault); llvm_emit_return_abi(c, NULL, &value); } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 192fff415..61961b5ca 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -69,6 +69,12 @@ typedef struct +typedef struct ReusableConstant_ +{ + const char *string; + const char *name; + LLVMValueRef value; +} ReusableConstant; typedef struct GenContext_ { bool shared_context; @@ -84,6 +90,7 @@ typedef struct GenContext_ LLVMBasicBlockRef catch_block; LLVMValueRef *constructors; LLVMValueRef *destructors; + ReusableConstant *reusable_constants; const char *ir_filename; const char *object_filename; const char *asm_filename; @@ -99,6 +106,7 @@ typedef struct GenContext_ LLVMTypeRef ptr_type; LLVMTypeRef chars_type; Decl *panic_var; + Decl *panicf; struct { const char *name; @@ -443,13 +451,19 @@ INLINE bool call_supports_variadic(CallABI abi); static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi); void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param); 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); // -- C3 Lowering -- void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); +void llvm_emit_ignored_expr(GenContext *c, Expr *expr); void llvm_emit_stmt(GenContext *c, Ast *ast); -void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc); -void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc); -void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc); +void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc, + const char *fmt, BEValue *value_1, BEValue *value_2); +void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc, const char *fmt, BEValue *value_1, + BEValue *value_2); +void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *args); + +void llvm_emit_any_from_value(GenContext *c, BEValue *value, Type *type); void llvm_emit_subarray_len(GenContext *context, BEValue *subarray, BEValue *len); void llvm_emit_subarray_pointer(GenContext *context, BEValue *subarray, BEValue *pointer); void llvm_emit_compound_stmt(GenContext *c, Ast *ast); diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index c599c1883..4f15353bc 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -41,6 +41,7 @@ void gencontext_begin_module(GenContext *c) codegen_setup_object_names(c->code_module, &c->ir_filename, &c->asm_filename, &c->object_filename); c->panic_var = global_context.panic_var; + c->panicf = global_context.panicf; c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context); c->machine = llvm_target_machine_create(); c->target_data = LLVMCreateTargetDataLayout(c->machine); @@ -116,6 +117,7 @@ void gencontext_begin_module(GenContext *c) c->introspect_type = create_introspection_type(c); c->fault_type = create_fault_type(c); if (c->panic_var) c->panic_var->backend_ref = NULL; + if (c->panicf) c->panicf->backend_ref = NULL; if (active_target.debug_info != DEBUG_INFO_NONE) { diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 1552b38c4..f9dc329fe 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -51,7 +51,7 @@ void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value) scratch_buffer_clear(); scratch_buffer_append(decl->extname); scratch_buffer_append("$f"); - decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyerr, 0); + decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyfault, 0); } llvm_emit_global_variable_init(c, decl); c->builder = builder; @@ -67,7 +67,7 @@ void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value) scratch_buffer_clear(); scratch_buffer_append(decl->name); scratch_buffer_append(".f"); - decl->var.optional_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string()); + decl->var.optional_ref = llvm_emit_alloca_aligned(c, type_anyfault, scratch_buffer_to_string()); // Only clear out the result if the assignment isn't an optional. } @@ -83,14 +83,14 @@ void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value) llvm_value_set(value, LLVMGetUndef(alloc_type), decl->type); if (decl->var.optional_ref) { - llvm_store_to_ptr_raw(c, decl->var.optional_ref, llvm_get_undef(c, type_anyerr), type_anyerr); + llvm_store_to_ptr_raw(c, decl->var.optional_ref, llvm_get_undef(c, type_anyfault), type_anyfault); } } else { if (decl->var.optional_ref) { - llvm_store_to_ptr_zero(c, decl->var.optional_ref, type_anyerr); + llvm_store_to_ptr_zero(c, decl->var.optional_ref, type_anyfault); } Type *type = type_lowering(decl->type); @@ -184,7 +184,7 @@ static inline void llvm_emit_return(GenContext *c, Ast *ast) if (c->cur_func.prototype && type_is_optional(c->cur_func.prototype->rtype)) { error_return_block = llvm_basic_block_new(c, "err_retblock"); - error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr"); + error_out = llvm_emit_alloca_aligned(c, type_anyfault, "reterr"); c->opt_var = error_out; c->catch_block = error_return_block; } @@ -217,7 +217,7 @@ static inline void llvm_emit_return(GenContext *c, Ast *ast) llvm_emit_block(c, error_return_block); llvm_emit_statement_chain(c, ast->return_stmt.cleanup_fail); BEValue value; - llvm_value_set_address_abi_aligned(&value, error_out, type_anyerr); + llvm_value_set_address_abi_aligned(&value, error_out, type_anyfault); llvm_emit_return_abi(c, NULL, &value); c->current_block = NULL; } @@ -469,7 +469,7 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) { SourceSpan loc = ast->span; - llvm_emit_panic(c, "Infinite loop found", loc); + llvm_emit_panic(c, "Infinite loop found", loc, NULL, NULL); LLVMBuildUnreachable(c->builder); LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block"); c->current_block = NULL; @@ -749,7 +749,7 @@ static void llvm_emit_switch_jump_table(GenContext *c, static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast) { bool is_if_chain = switch_ast->switch_stmt.flow.if_chain; - Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyerr) : exprptr(switch_ast->switch_stmt.cond)->type; + Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyfault) : switch_value->type; Ast **cases = switch_ast->switch_stmt.cases; ArraySize case_count = vec_size(cases); @@ -865,11 +865,21 @@ static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *swi llvm_emit_block(c, exit_block); } -void gencontext_emit_switch(GenContext *context, Ast *ast) +void llvm_emit_switch(GenContext *c, Ast *ast) { BEValue switch_value; - llvm_emit_decl_expr_list(context, &switch_value, exprptrzero(ast->switch_stmt.cond), false); - llvm_emit_switch_body(context, &switch_value, ast); + Expr *expr = exprptrzero(ast->switch_stmt.cond); + if (expr) + { + // Regular switch + llvm_emit_decl_expr_list(c, &switch_value, expr, false); + } + else + { + // Match switch, so set the value to true + llvm_value_set(&switch_value, llvm_const_int(c, type_bool, 1), type_bool); + } + llvm_emit_switch_body(c, &switch_value, ast); } @@ -1002,7 +1012,7 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) { error = "Assert violation"; } - llvm_emit_panic(c, error, loc); + llvm_emit_panic(c, error, loc, NULL, NULL); llvm_emit_br(c, on_ok); llvm_emit_block(c, on_ok); } @@ -1215,99 +1225,10 @@ static inline void llvm_emit_asm_block_stmt(GenContext *c, Ast *ast) } } -// Prune the common occurrence where the optional is not used. -static void llvm_prune_optional(GenContext *c, LLVMBasicBlockRef discard_fail) -{ - // Replace discard with the current block, - // this removes the jump in the case: - // br i1 %not_err, label %after_check, label %voiderr - //after_check: - // br label %voiderr - //voiderr: - // - LLVMValueRef block_value = LLVMBasicBlockAsValue(c->current_block); - LLVMReplaceAllUsesWith(LLVMBasicBlockAsValue(discard_fail), block_value); - - // We now have: - // br i1 %not_err, label %after_check, label %after_check - //after_check: - // - - // Find the use of this block. - LLVMUseRef use = LLVMGetFirstUse(block_value); - if (!use) return; - - LLVMValueRef maybe_br = LLVMGetUser(use); - // Expect a br instruction. - if (!LLVMIsAInstruction(maybe_br) || LLVMGetInstructionOpcode(maybe_br) != LLVMBr) return; - if (LLVMGetNumOperands(maybe_br) != 3) return; - // We expect a single user. - LLVMUseRef other_use = LLVMGetNextUse(use); - while (other_use) - { - if (LLVMGetUser(other_use) != maybe_br) return; - other_use = LLVMGetNextUse(other_use); - } - // Both operands same block value - if (LLVMGetOperand(maybe_br, 1) != block_value || LLVMGetOperand(maybe_br, 2) != block_value) return; - - // Grab the compared value - LLVMValueRef compared = LLVMGetOperand(maybe_br, 0); - - // Remove the block and the br - LLVMBasicBlockRef prev_block = LLVMGetInstructionParent(maybe_br); - LLVMRemoveBasicBlockFromParent(c->current_block); - LLVMInstructionEraseFromParent(maybe_br); - - // Optionally remove the comparison - if (!LLVMGetFirstUse(compared)) - { - LLVMValueRef operand = NULL; - if (LLVMGetInstructionOpcode(compared) == LLVMCall) - { - operand = LLVMGetOperand(compared, 0); - } - LLVMInstructionEraseFromParent(compared); - if (operand) LLVMInstructionEraseFromParent(operand); - } - // Update the context - c->current_block = prev_block; - c->current_block_is_target = LLVMGetFirstBasicBlock(c->function) == prev_block; - LLVMPositionBuilderAtEnd(c->builder, prev_block); -} static void llvm_emit_expr_stmt(GenContext *c, Ast *ast) { - BEValue value; - Expr *e = ast->expr_stmt; - // For a standalone catch, we can ignore storing the value. - if (e->expr_kind == EXPR_CATCH) - { - e = e->inner_expr; - } - if (IS_OPTIONAL(e)) - { - PUSH_OPT(); - LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr"); - c->catch_block = discard_fail; - c->opt_var = NULL; - llvm_emit_expr(c, &value, e); - llvm_value_fold_optional(c, &value); - EMIT_LOC(c, ast); - // We only optimize if there is no instruction the current block - if (!LLVMGetFirstInstruction(c->current_block)) - { - llvm_prune_optional(c, discard_fail); - } - else - { - llvm_emit_br(c, discard_fail); - llvm_emit_block(c, discard_fail); - } - POP_OPT(); - return; - } - llvm_emit_expr(c, &value, e); + llvm_emit_ignored_expr(c, ast->expr_stmt); } LLVMValueRef llvm_emit_string_const(GenContext *c, const char *str, const char *extname) @@ -1332,6 +1253,14 @@ LLVMValueRef llvm_emit_zstring(GenContext *c, const char *str) LLVMValueRef llvm_emit_zstring_named(GenContext *c, const char *str, const char *extname) { + VECEACH(c->reusable_constants, i) + { + if (strcmp(str, c->reusable_constants[i].string) == 0 && strcmp(extname, c->reusable_constants[i].name) == 0) + { + return c->reusable_constants[i].value; + } + } + unsigned len = (unsigned)strlen(str); LLVMTypeRef char_array_type = LLVMArrayType(c->byte_type, len + 1); LLVMValueRef global_string = llvm_add_global_raw(c, extname, char_array_type, 0); @@ -1340,14 +1269,14 @@ LLVMValueRef llvm_emit_zstring_named(GenContext *c, const char *str, const char LLVMSetInitializer(global_string, llvm_get_zstring(c, str, len)); AlignSize alignment; LLVMValueRef string = llvm_emit_array_gep_raw(c, global_string, char_array_type, 0, 1, &alignment); + ReusableConstant reuse = { .string = str_copy(str, len), .name = str_copy(extname, strlen(extname)), .value = string }; + vec_add(c->reusable_constants, reuse); return string; } -void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc) +void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *varargs) { - File *file = source_file_by_id(loc.file_id); - if (c->debug.builder) llvm_emit_debug_location(c, loc); if (c->debug.stack_slot_row) { @@ -1364,13 +1293,19 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc) return; } - LLVMValueRef args[4] = { - llvm_emit_string_const(c, message, ".panic_msg"), + File *file = source_file_by_id(loc.file_id); + + Decl *panicf = fmt ? c->panicf : NULL; + + LLVMValueRef panic_args[5] = { + llvm_emit_string_const(c, panicf ? fmt : message, ".panic_msg"), llvm_emit_string_const(c, file->name, ".file"), llvm_emit_string_const(c, c->cur_func.name, ".func"), llvm_const_int(c, type_uint, loc.row) }; - FunctionPrototype *prototype = type_get_resolved_prototype(panic_var->type->canonical->pointer); + FunctionPrototype *prototype = panicf + ? type_get_resolved_prototype(panicf->type) + : type_get_resolved_prototype(panic_var->type->canonical->pointer); LLVMValueRef actual_args[16]; unsigned count = 0; ABIArgInfo **abi_args = prototype->abi_args; @@ -1378,10 +1313,41 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc) for (unsigned i = 0; i < 4; i++) { Type *type = type_lowering(types[i]); - BEValue value = { .value = args[i], .type = type }; + BEValue value = { .value = panic_args[i], .type = type }; llvm_emit_parameter(c, actual_args, &count, abi_args[i], &value, type); } + if (panicf) + { + unsigned elements = vec_size(varargs); + Type *any_subarray = type_get_subarray(type_any); + Type *any_array = type_get_array(type_any, elements); + LLVMTypeRef llvm_array_type = llvm_get_type(c, any_array); + AlignSize alignment = type_alloca_alignment(any_array); + LLVMValueRef array_ref = llvm_emit_alloca(c, llvm_array_type, alignment, "varargslots"); + VECEACH(varargs, i) + { + AlignSize store_alignment; + LLVMValueRef slot = llvm_emit_array_gep_raw(c, + array_ref, + llvm_array_type, + i, + alignment, + &store_alignment); + llvm_store_to_ptr_aligned(c, slot, &varargs[i], store_alignment); + } + BEValue value; + llvm_value_aggregate_two(c, &value, any_subarray, array_ref, llvm_const_int(c, type_usz, elements)); + + llvm_emit_parameter(c, actual_args, &count, abi_args[4], &value, any_subarray); + + BEValue res; + if (c->debug.builder) llvm_emit_debug_location(c, loc); + llvm_emit_raw_call(c, &res, prototype, llvm_func_type(c, prototype), llvm_get_ref(c, panicf), actual_args, + count, 0, NULL, false, NULL); + return; + } + BEValue val; llvm_value_set_decl(c, &val, panic_var); llvm_value_rvalue(c, &val); @@ -1392,7 +1358,8 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc) count, 0, NULL, false, NULL); } -void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc) +void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc, const char *fmt, BEValue *value_1, + BEValue *value_2) { if (llvm_is_const(value->value)) { @@ -1404,22 +1371,30 @@ void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_na assert(llvm_value_is_bool(value)); llvm_emit_cond_br(c, value, panic_block, ok_block); llvm_emit_block(c, panic_block); - llvm_emit_panic(c, panic_name, loc); + BEValue *values = NULL; + if (value_1) + { + BEValue var = *value_1; + llvm_emit_any_from_value(c, &var, var.type); + vec_add(values, var); + if (value_2) + { + var = *value_2; + llvm_emit_any_from_value(c, &var, var.type); + vec_add(values, var); + } + } + llvm_emit_panic(c, panic_name, loc, fmt, values); llvm_emit_br(c, ok_block); llvm_emit_block(c, ok_block); } -void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc) +void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc, + const char *fmt, BEValue *value_1, BEValue *value_2) { - LLVMBasicBlockRef panic_block = llvm_basic_block_new(c, "panic"); - LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "checkok"); BEValue be_value; llvm_value_set(&be_value, value, type_bool); - llvm_emit_cond_br(c, &be_value, panic_block, ok_block); - llvm_emit_block(c, panic_block); - llvm_emit_panic(c, panic_name, loc); - llvm_emit_br(c, ok_block); - llvm_emit_block(c, ok_block); + llvm_emit_panic_if_true(c, &be_value, panic_name, loc, fmt, value_1, value_2); } @@ -1433,6 +1408,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_FOREACH_STMT: case AST_CONTRACT: case AST_ASM_STMT: + case AST_CONTRACT_FAULT: UNREACHABLE case AST_EXPR_STMT: llvm_emit_expr_stmt(c, ast); @@ -1472,7 +1448,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_FOR_STMT: llvm_emit_for_stmt(c, ast); break; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: gencontext_emit_next_stmt(c, ast); break; case AST_DEFER_STMT: @@ -1495,7 +1471,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_CT_FOREACH_STMT: UNREACHABLE case AST_SWITCH_STMT: - gencontext_emit_switch(c, ast); + llvm_emit_switch(c, ast); break; } } diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index c86034a69..55104b2f9 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -121,7 +121,7 @@ static void param_expand(GenContext *context, LLVMTypeRef** params_ref, Type *ty return; } case TYPE_ENUM: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: param_expand(context, params_ref, type_lowering(type)); return; @@ -274,7 +274,7 @@ LLVMTypeRef llvm_func_type(GenContext *context, FunctionPrototype *prototype) { LLVMTypeRef *params = NULL; LLVMTypeRef ret = llvm_update_prototype_abi(context, prototype, ¶ms); - return LLVMFunctionType(ret, params, vec_size(params), prototype->variadic == VARIADIC_RAW); + return LLVMFunctionType(ret, params, vec_size(params), prototype->raw_variadic); } @@ -317,14 +317,13 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case CT_TYPES: UNREACHABLE case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_TYPEDEF: case TYPE_DISTINCT: case TYPE_ENUM: // If this is reachable, then we're not doing the proper lowering. UNREACHABLE case TYPE_TYPEID: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: return any_type->backend_type = llvm_get_type(c, type_iptr->canonical); case TYPE_STRUCT: @@ -339,6 +338,8 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) return any_type->backend_type = LLVMDoubleTypeInContext(c->context); case TYPE_F16: return any_type->backend_type = LLVMHalfTypeInContext(c->context); + case TYPE_BF16: + return any_type->backend_type = LLVMBFloatTypeInContext(c->context); case TYPE_F32: return any_type->backend_type = LLVMFloatTypeInContext(c->context); case TYPE_F128: @@ -368,8 +369,6 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) LLVMStructSetBody(virtual_type, types, 2, false); return any_type->backend_type = virtual_type; } - case TYPE_SCALED_VECTOR: - return any_type->backend_type = LLVMScalableVectorType(llvm_get_type(c, any_type->array.base), any_type->array.len); case TYPE_VECTOR: return any_type->backend_type = LLVMVectorType(llvm_get_type(c, any_type->array.base), any_type->array.len); } @@ -660,12 +659,7 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) } case TYPE_TYPEDEF: return llvm_get_typeid(c, type->canonical); - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_UNTYPED_LIST: - case TYPE_OPTIONAL_ANY: - case TYPE_TYPEINFO: - case TYPE_MEMBER: + case CT_TYPES: UNREACHABLE case TYPE_VOID: return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_VOID, 0); @@ -684,16 +678,12 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) type, INTROSPECT_TYPE_FLOAT, type_kind_bitsize(type->type_kind)); - case TYPE_ANYERR: - return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANYERR, 0); + case TYPE_ANYFAULT: + return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANYFAULT, 0); case TYPE_ANY: - return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_VARIANT, 0); + return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANY, 0); case TYPE_TYPEID: return llvm_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_TYPEID, 0); - case TYPE_POISONED: - UNREACHABLE - case TYPE_SCALED_VECTOR: - UNSUPPORTED; } UNREACHABLE } \ No newline at end of file diff --git a/src/compiler/llvm_codegen_value.c b/src/compiler/llvm_codegen_value.c index 42ad07454..d95efd806 100644 --- a/src/compiler/llvm_codegen_value.c +++ b/src/compiler/llvm_codegen_value.c @@ -135,7 +135,7 @@ void llvm_emit_jump_to_optional_exit(GenContext *c, LLVMValueRef opt_value) llvm_emit_block(c, error_block); } - llvm_store_to_ptr_raw(c, c->opt_var, opt_value, type_anyerr); + llvm_store_to_ptr_raw(c, c->opt_var, opt_value, type_anyfault); llvm_emit_br(c, c->catch_block); llvm_emit_block(c, after_block); } @@ -144,7 +144,7 @@ void llvm_value_fold_optional(GenContext *c, BEValue *value) { if (value->kind == BE_ADDRESS_OPTIONAL) { - llvm_emit_jump_to_optional_exit(c, llvm_load_abi_alignment(c, type_anyerr, value->optional, "optval")); + llvm_emit_jump_to_optional_exit(c, llvm_load_abi_alignment(c, type_anyfault, value->optional, "optval")); value->kind = BE_ADDRESS; } } diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 6ac8ce4af..8a17c5aae 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -5,8 +5,6 @@ #include "compiler_internal.h" #include "parser_internal.h" - -#define IF_TRY_CATCH_PREC (PREC_AND + 1) typedef Expr *(*ParseFn)(ParseContext *context, Expr *); typedef struct @@ -19,6 +17,11 @@ typedef struct extern ParseRule rules[TOKEN_EOF + 1]; +bool parse_current_is_expr(ParseContext *c) +{ + return rules[c->tok].prefix != NULL; +} + /** * maybe_range ::= range | ('^'? INTEGER) * range ::= dot_range | colon_range @@ -50,19 +53,34 @@ bool parse_range(ParseContext *c, Range *range) } range->is_range = true; - // ] ) are the possible ways to end a range. - if (tok_is(c, TOKEN_RBRACKET) || tok_is(c, TOKEN_RPAREN)) + // Is there an expression next? + range->end_from_end = try_consume(c, TOKEN_BIT_XOR); + if (range->end_from_end || parse_current_is_expr(c)) { - // So here we have [1..] or [3:] - range->end_from_end = false; - range->end = 0; + ASSIGN_EXPRID_OR_RET(range->end, parse_expr(c), false); return true; } - range->end_from_end = try_consume(c, TOKEN_BIT_XOR); - ASSIGN_EXPRID_OR_RET(range->end, parse_expr(c), false); + + // Otherwise we have [1..] or [3:] + range->end_from_end = false; + range->end = 0; return true; } +/** + * rethrow_expr ::= call_expr '!' + */ +static Expr *parse_rethrow_expr(ParseContext *c, Expr *left_side) +{ + assert(expr_ok(left_side)); + advance_and_verify(c, TOKEN_BANG); + Expr *expr_ternary = expr_new_expr(EXPR_RETHROW, left_side); + expr_ternary->rethrow_expr.inner = left_side; + RANGE_EXTEND_PREV(expr_ternary); + + return expr_ternary; +} + /** * Parse lhs [op] [rhs] * This will return lhs if no candidate is found. @@ -72,6 +90,7 @@ inline Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, P while (1) { TokenType tok = c->tok; + Precedence token_precedence = rules[tok].precedence; // See if the operator precedence is greater than the last, if so exit. // Note that if the token is not an operator then token_precedence = 0 @@ -92,7 +111,6 @@ inline Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, P return left_side; } - /** * Parse an expression in any position. */ @@ -124,72 +142,96 @@ Expr *parse_generic_parameter(ParseContext *c) return parse_precedence(c, PREC_ADDITIVE); } -static inline Expr *parse_for_try_expr(ParseContext *c) +/* + * Parse anything with higher precedence than &&, that means <= >= etc are ok. + */ +static inline Expr *parse_relational_expr(ParseContext *c) { - return parse_precedence(c, PREC_AND + 1); + return parse_precedence(c, PREC_RELATIONAL); } + + /** - * catch_unwrap ::= CATCH IDENT | (type? IDENT '=' (expr | '(' expr (',' expr) ')')) + * catch_unwrap ::= CATCH (IDENT | type? IDENT '=' catch_chain) | catch_chain + * catch_chain ::= try_rhs_expr (',' try_rhs_expr)* */ static inline Expr *parse_catch_unwrap(ParseContext *c) { Expr *expr = expr_new(EXPR_CATCH_UNWRAP, c->span); advance_and_verify(c, TOKEN_CATCH); - TypeInfo *type = NULL; - ASSIGN_EXPR_OR_RET(Expr * lhs, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr); - if (lhs->expr_kind == EXPR_TYPEINFO) + Expr **exprs = NULL; + + // First, try parsing as single expression + ASSIGN_EXPR_OR_RET(Expr *sub_expr, parse_relational_expr(c), poisoned_expr); + + // Check if we have a chain. + if (try_consume(c, TOKEN_COMMA)) { - expr->catch_unwrap_expr.type = lhs->type_expr; - ASSIGN_EXPR_OR_RET(expr->catch_unwrap_expr.variable, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr); + // Create the chain. + vec_add(exprs, sub_expr); + do + { + ASSIGN_EXPR_OR_RET(sub_expr, parse_relational_expr(c), poisoned_expr); + vec_add(exprs, sub_expr); + } while (try_consume(c, TOKEN_COMMA)); + // We're done. + expr->catch_unwrap_expr.exprs = exprs; + return expr; + } + + // We don't have a chain, so it's either "anyfault f" or "f" or an expression. + if (sub_expr->expr_kind == EXPR_TYPEINFO) + { + // Assign the type + expr->catch_unwrap_expr.type = sub_expr->type_expr; + // Assign the variable + ASSIGN_EXPR_OR_RET(expr->catch_unwrap_expr.variable, parse_relational_expr(c), poisoned_expr); } else { + // Here we assume it's either "f" or an expression. expr->catch_unwrap_expr.type = NULL; - expr->catch_unwrap_expr.variable = lhs; + expr->catch_unwrap_expr.variable = sub_expr; } + // If we don't have an '=', we check whether if (!try_consume(c, TOKEN_EQ)) { + // If we had "anyfault f", then we MUST have '=' if (expr->catch_unwrap_expr.type) { SEMA_ERROR_HERE("Expected a '=' here."); return poisoned_expr; } + // We just have `catch foo`, so we add the "variable" as an expression vec_add(expr->catch_unwrap_expr.exprs, expr->catch_unwrap_expr.variable); expr->catch_unwrap_expr.variable = NULL; RANGE_EXTEND_PREV(expr); return expr; } - if (try_consume(c, TOKEN_LPAREN)) + // After '=' we have a chain of expressions. + do { - do - { - ASSIGN_EXPR_OR_RET(Expr * init_expr, parse_expr(c), poisoned_expr); - vec_add(expr->catch_unwrap_expr.exprs, init_expr); - } while (try_consume(c, TOKEN_COMMA)); - CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); - } - else - { - ASSIGN_EXPR_OR_RET(Expr * init_expr, parse_expr(c), poisoned_expr); - vec_add(expr->catch_unwrap_expr.exprs, init_expr); - } + ASSIGN_EXPR_OR_RET(sub_expr, parse_relational_expr(c), poisoned_expr); + vec_add(exprs, sub_expr); + } while (try_consume(c, TOKEN_COMMA)); + expr->catch_unwrap_expr.exprs = exprs; RANGE_EXTEND_PREV(expr); return expr; } /** - * try_unwrap ::= TRY (IDENT | type? IDENT '=' non_and_expr) + * try_unwrap ::= TRY ((type? IDENT '=' try_rhs_expr) | try_rhs_expr) */ static inline Expr *parse_try_unwrap(ParseContext *c) { Expr *expr = EXPR_NEW_TOKEN(EXPR_TRY_UNWRAP); advance_and_verify(c, TOKEN_TRY); - ASSIGN_EXPR_OR_RET(Expr *lhs, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr); + ASSIGN_EXPR_OR_RET(Expr *lhs, parse_relational_expr(c), poisoned_expr); if (lhs->expr_kind == EXPR_TYPEINFO) { expr->try_unwrap_expr.type = lhs->type_expr; - ASSIGN_EXPR_OR_RET(expr->try_unwrap_expr.variable, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr); + ASSIGN_EXPR_OR_RET(expr->try_unwrap_expr.variable, parse_relational_expr(c), poisoned_expr); } else { @@ -202,15 +244,14 @@ static inline Expr *parse_try_unwrap(ParseContext *c) } if (try_consume(c, TOKEN_EQ)) { - ASSIGN_EXPR_OR_RET(expr->try_unwrap_expr.init, parse_precedence(c, PREC_AND + 1), poisoned_expr); + ASSIGN_EXPR_OR_RET(expr->try_unwrap_expr.init, parse_relational_expr(c), poisoned_expr); } RANGE_EXTEND_PREV(expr); return expr; } /** - * try_unwrap_chain ::= try_unwrap ('&&' (try_unwrap | non_and_expr))* - * try_unwrap ::= TRY (IDENT | type? IDENT '=' non_and_expr) + * try_unwrap_chain ::= try_unwrap ('&&' (try_unwrap | try_rhs_expr))* */ static inline Expr *parse_try_unwrap_chain(ParseContext *c) { @@ -225,7 +266,7 @@ static inline Expr *parse_try_unwrap_chain(ParseContext *c) vec_add(unwraps, expr); continue; } - ASSIGN_EXPR_OR_RET(Expr * next_unwrap, parse_for_try_expr(c), poisoned_expr); + ASSIGN_EXPR_OR_RET(Expr * next_unwrap, parse_relational_expr(c), poisoned_expr); vec_add(unwraps, next_unwrap); } Expr *try_unwrap_chain = expr_new_expr(EXPR_TRY_UNWRAP_CHAIN, first_unwrap); @@ -234,6 +275,9 @@ static inline Expr *parse_try_unwrap_chain(ParseContext *c) return try_unwrap_chain; } +/** + * assert_expr ::= try_unwrap_chain | expr + */ Expr *parse_assert_expr(ParseContext *c) { if (tok_is(c, TOKEN_TRY)) @@ -301,11 +345,11 @@ Expr* parse_expr(ParseContext *c) Expr* parse_constant_expr(ParseContext *c) { - return parse_precedence(c, PREC_TERNARY); + return parse_precedence(c, PREC_ASSIGNMENT + 1); } /** - * param_path : ('[' expression ']' | '.' IDENT)* + * param_path ::= ('[' expr ']' | '.' IDENT)* * * @param c * @param path reference to the path to return @@ -340,9 +384,7 @@ static bool parse_param_path(ParseContext *c, DesignatorElement ***path) advance(c); DesignatorElement *element = CALLOCS(DesignatorElement); element->kind = DESIGNATOR_FIELD; - element->field = symstr(c); - EXPECT_OR_RET(TOKEN_IDENT, false); - advance(c); + ASSIGN_EXPR_OR_RET(element->field_expr, parse_precedence(c, PREC_PRIMARY), false); vec_add(*path, element); continue; } @@ -394,6 +436,10 @@ static Expr *parse_lambda(ParseContext *c, Expr *left) expr->lambda_expr = func; return expr; } + +/** + * vasplat ::= CT_VASPLAT '(' range_expr ')' + */ Expr *parse_vasplat(ParseContext *c) { Expr *expr = EXPR_NEW_TOKEN(EXPR_VASPLAT); @@ -408,11 +454,12 @@ Expr *parse_vasplat(ParseContext *c) return expr; } /** - * param_list ::= ('...' parameter | parameter (',' parameter)*)? + * param_list ::= ('...' arg | arg (',' arg)*)? * * parameter ::= (param_path '=')? expr */ -bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat) +bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat, + bool allow_trailing_comma) { *result = NULL; if (splat) *splat = false; @@ -453,7 +500,15 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool * { return true; } - if (tok_is(c, param_end)) return true; + if (tok_is(c, param_end)) + { + if (!allow_trailing_comma) + { + sema_error_at(c->prev_span, "Trailing commas are not allowed."); + return false; + } + return true; + } if (splat && *splat) { SEMA_ERROR_HERE("'...' is only allowed on the last argument in a call."); @@ -462,14 +517,8 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool * } } - - /** - * expression_list - * : expression - * | expression_list ',' expression - * ; - * @return Ast * + * expression_list ::= decl_or_expr+ */ Expr *parse_expression_list(ParseContext *c, bool allow_decl) { @@ -531,6 +580,9 @@ static Expr *parse_type_identifier(ParseContext *context, Expr *left) return parse_type_expression_with_path(context, NULL); } +/** + * type_expr ::= type initializer_list? + */ static Expr *parse_type_expr(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -577,7 +629,9 @@ static Expr *parse_ct_stringify(ParseContext *c, Expr *left) return expr; } - +/** + * unary_expr ::= unary_op unary_prec_expr + */ static Expr *parse_unary_expr(ParseContext *c, Expr *left) { assert(!left && "Did not expect a left hand side!"); @@ -594,6 +648,9 @@ static Expr *parse_unary_expr(ParseContext *c, Expr *left) return unary; } +/** + * post_unary_expr ::= unary_op + */ static Expr *parse_post_unary(ParseContext *c, Expr *left) { assert(expr_ok(left)); @@ -605,46 +662,65 @@ static Expr *parse_post_unary(ParseContext *c, Expr *left) return unary; } - - - -static Expr *parse_ternary_expr(ParseContext *c, Expr *left_side) +/** + * elvis_expr := ?: ternary_prec_expr + */ +static Expr *parse_elvis_expr(ParseContext *c, Expr *left_side) { assert(expr_ok(left_side)); Expr *expr_ternary = expr_new_expr(EXPR_TERNARY, left_side); expr_ternary->ternary_expr.cond = exprid(left_side); - - - // Check for elvis - if (try_consume(c, TOKEN_ELVIS)) - { - expr_ternary->ternary_expr.then_expr = 0; - } - else - { - advance_and_verify(c, TOKEN_QUESTION); - if (!rules[c->tok].prefix) - { - expr_ternary->expr_kind = EXPR_RETHROW; - expr_ternary->rethrow_expr.inner = left_side; - RANGE_EXTEND_PREV(expr_ternary); - return expr_ternary; - } - ASSIGN_EXPR_OR_RET(Expr * true_expr, parse_expr(c), poisoned_expr); - expr_ternary->ternary_expr.then_expr = exprid(true_expr); - CONSUME_OR_RET(TOKEN_COLON, poisoned_expr); - } - + advance_and_verify(c, TOKEN_ELVIS); + expr_ternary->ternary_expr.then_expr = 0; ASSIGN_EXPRID_OR_RET(expr_ternary->ternary_expr.else_expr, parse_precedence(c, PREC_TERNARY), poisoned_expr); RANGE_EXTEND_PREV(expr_ternary); return expr_ternary; } /** - * grouping_expr - * : '(' expression ')' ('(' expression ')')? - * ; + * ternary_optional_expr ::= optional_expr | ternary_expr + * optional_expr ::= '?' '!'? + * ternary_expr ::= '?' expr ':' ternary_prec_expr + */ +static Expr *parse_ternary_expr(ParseContext *c, Expr *left_side) +{ + assert(expr_ok(left_side)); + + Expr *expr = expr_new_expr(EXPR_TERNARY, left_side); + advance_and_verify(c, TOKEN_QUESTION); + + // If we have no expression following *or* it is a '!' followed by no expression + // in this case it's an optional expression. + if (!rules[c->tok].prefix || (c->tok == TOKEN_BANG && !rules[peek(c)].prefix)) + { + expr->expr_kind = EXPR_OPTIONAL; + expr->inner_expr = left_side; + RANGE_EXTEND_PREV(expr); + return expr; + } + + // Otherwise we have a ternary + expr->ternary_expr.cond = exprid(left_side); + // LHS is a plain expression + ASSIGN_EXPR_OR_RET(Expr *true_expr, parse_expr(c), poisoned_expr); + expr->ternary_expr.then_expr = exprid(true_expr); + CONSUME_OR_RET(TOKEN_COLON, poisoned_expr); + + // RHS is ternary prec, to get right -> left associativity + ASSIGN_EXPRID_OR_RET(expr->ternary_expr.else_expr, parse_precedence(c, PREC_TERNARY), poisoned_expr); + RANGE_EXTEND_PREV(expr); + return expr; +} + +/** + * grouping_expr ::= cast_expr | group_expr + * + * cast_expr ::= '(' type ')' expr + * group_expr ::= '(' expr ')' + * + * When parsing we retain EXPR_GROUP in order to require explicit parentheses later + * as needed. */ static Expr *parse_grouping_expr(ParseContext *c, Expr *left) { @@ -662,6 +738,7 @@ static Expr *parse_grouping_expr(ParseContext *c, Expr *left) SEMA_ERROR_HERE("Unexpected start of a block '{' here. If you intended a compound literal, remove the () around the type."); return poisoned_expr; } + // Create a cast expr if (rules[c->tok].prefix) { ASSIGN_EXPRID_OR_RET(expr->cast_expr.expr, parse_precedence(c, PREC_CALL), poisoned_expr); @@ -696,7 +773,7 @@ Expr *parse_initializer_list(ParseContext *c, Expr *left) if (!try_consume(c, TOKEN_RBRACE)) { Expr **exprs = NULL; - if (!parse_arg_list(c, &exprs, TOKEN_RBRACE, NULL, true)) return poisoned_expr; + if (!parse_arg_list(c, &exprs, TOKEN_RBRACE, NULL, true, true)) return poisoned_expr; int designated = -1; VECEACH(exprs, i) { @@ -734,17 +811,25 @@ Expr *parse_initializer_list(ParseContext *c, Expr *left) return initializer_list; } -static Expr *parse_optional(ParseContext *c, Expr *left_side) +static Expr *parse_orelse(ParseContext *c, Expr *left_side) { - Expr *optional = expr_new(EXPR_OPTIONAL, left_side->span); - advance_and_verify(c, TOKEN_BANG); - optional->inner_expr = left_side; - RANGE_EXTEND_PREV(optional); - return optional; + assert(left_side && expr_ok(left_side)); + + advance_and_verify(c, TOKEN_QUESTQUEST); + + Expr *right_side; + // Assignment operators have precedence right -> left. + ASSIGN_EXPR_OR_RET(right_side, parse_precedence(c, PREC_TERNARY), poisoned_expr); + + Expr *expr = expr_new_expr(EXPR_BINARY, left_side); + expr->binary_expr.operator = BINARYOP_ELSE; + expr->binary_expr.left = exprid(left_side); + expr->binary_expr.right = exprid(right_side); + + RANGE_EXTEND_PREV(expr); + return expr; } - - static Expr *parse_binary(ParseContext *c, Expr *left_side) { assert(left_side && expr_ok(left_side)); @@ -786,7 +871,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) { // Pick a modest guess. params = VECNEW(Expr*, 4); - if (!parse_arg_list(c, ¶ms, TOKEN_RPAREN, &splat, true)) return poisoned_expr; + if (!parse_arg_list(c, ¶ms, TOKEN_RPAREN, &splat, true, false)) return poisoned_expr; } if (try_consume(c, TOKEN_EOS)) { @@ -865,8 +950,9 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) return call; } - - +/** + * subscript ::= '[' range_expr ']' + */ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) { assert(left && expr_ok(left)); @@ -884,20 +970,20 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) return subs_expr; } - +/** + * access_expr ::= '.' primary_expr + */ static Expr *parse_access_expr(ParseContext *c, Expr *left) { assert(left && expr_ok(left)); advance_and_verify(c, TOKEN_DOT); Expr *access_expr = expr_new_expr(EXPR_ACCESS, left); access_expr->access_expr.parent = left; - ASSIGN_EXPR_OR_RET(access_expr->access_expr.child, parse_precedence(c, PREC_CALL + 1), poisoned_expr); + ASSIGN_EXPR_OR_RET(access_expr->access_expr.child, parse_precedence(c, PREC_PRIMARY), poisoned_expr); RANGE_EXTEND_PREV(access_expr); return access_expr; } - - static Expr *parse_ct_ident(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -908,20 +994,23 @@ static Expr *parse_ct_ident(ParseContext *c, Expr *left) } Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_IDENT); expr->ct_ident_expr.identifier = symstr(c); - advance(c); + advance_and_verify(c, TOKEN_CT_IDENT); return expr; } + static Expr *parse_hash_ident(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); Expr *expr = EXPR_NEW_TOKEN(EXPR_HASH_IDENT); expr->ct_ident_expr.identifier = symstr(c); - - advance(c); + advance_and_verify(c, TOKEN_HASH_IDENT); return expr; } +/** + * ct_eval ::= CT_EVAL '(' expr ')' + */ static Expr *parse_ct_eval(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -934,6 +1023,11 @@ static Expr *parse_ct_eval(ParseContext *c, Expr *left) return expr; } +/** + * ct_sizeof ::= CT_SIZEOF '(' expr ')' + * + * Note that this is tranformed to $typeof(expr).sizeof. + */ static Expr *parse_ct_sizeof(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -955,6 +1049,9 @@ static Expr *parse_ct_sizeof(ParseContext *c, Expr *left) return access; } +/** + * ct_checks ::= CT_CHECKS '(' expression_list ')' + */ static Expr *parse_ct_checks(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -967,6 +1064,10 @@ static Expr *parse_ct_checks(ParseContext *c, Expr *left) return checks; } +/** + * ct_call ::= (ALIGNOF | DEFINED | EXTNAMEOF | OFFSETOF | NAMEOF | QNAMEOF) '(' flat_path ')' + * flat_path ::= expr ('.' primary) | '[' expr ']')* + */ static Expr *parse_ct_call(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -975,42 +1076,18 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left) advance(c); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr); ASSIGN_EXPR_OR_RET(Expr* internal, parse_precedence(c, PREC_FIRST + 1), poisoned_expr); - ExprFlatElement *flat_path = NULL; - TokenType tok = c->tok; - if (tok == TOKEN_DOT || tok == TOKEN_LBRACKET) - { - while (1) - { - ExprFlatElement flat_element; - if (try_consume(c, TOKEN_LBRACKET)) - { - ASSIGN_EXPR_OR_RET(flat_element.inner, parse_expr(c), poisoned_expr); - TRY_CONSUME_OR_RET(TOKEN_RBRACKET, "Expected a ']' after the index.", poisoned_expr); - flat_element.array = true; - } - else if (try_consume(c, TOKEN_DOT)) - { - ASSIGN_EXPR_OR_RET(flat_element.inner, parse_precedence(c, PREC_FIRST), poisoned_expr); - flat_element.array = false; - } - else - { - SEMA_ERROR_HERE("Expected '.' or '[' here."); - return poisoned_expr; - } - vec_add(flat_path, flat_element); - if (tok_is(c, TOKEN_RPAREN)) break; - } - RANGE_EXTEND_PREV(internal); - } + DesignatorElement **elements = NULL; + if (!parse_param_path(c, &elements)) return poisoned_expr; expr->ct_call_expr.main_var = internal; - expr->ct_call_expr.flat_path = flat_path; + expr->ct_call_expr.flat_path = elements; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); RANGE_EXTEND_PREV(expr); return expr; } - +/** + * ct_arg ::= VACOUNT | (VAARG | VAREF | VAEXPR | VACONST) '(' expr ')' + */ static Expr *parse_ct_arg(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -1028,6 +1105,10 @@ static Expr *parse_ct_arg(ParseContext *c, Expr *left) return expr; } +/** + * identifier ::= CONST_IDENT | IDENT + * Note: if the identifier is "return" (only possible in doc lexing "mode"), create an EXPR_RETVAL instead. + */ static Expr *parse_identifier(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); @@ -1070,19 +1151,9 @@ static Expr *parse_identifier_starting_expression(ParseContext *c, Expr *left) } - -static Expr *parse_try_expr(ParseContext *c, Expr *left) -{ - assert(!left && "Unexpected left hand side"); - bool is_try = tok_is(c, TOKEN_TRY_QUESTION); - Expr *try_expr = EXPR_NEW_TOKEN(is_try ? EXPR_TRY : EXPR_CATCH); - advance(c); - ASSIGN_EXPR_OR_RET(try_expr->inner_expr, parse_precedence(c, PREC_UNARY), poisoned_expr); - RANGE_EXTEND_PREV(try_expr); - return try_expr; -} - - +/** + * force_unwrap ::= expr '!!' + */ static Expr *parse_force_unwrap_expr(ParseContext *c, Expr *left) { Expr *force_unwrap_expr = expr_new_expr(EXPR_FORCE_UNWRAP, left); @@ -1093,26 +1164,30 @@ static Expr *parse_force_unwrap_expr(ParseContext *c, Expr *left) } +/** + * builtin ::= '$$' IDENT + * compiler_const ::= '$$' CONST_IDENT + * + * Note this code accepts any ident as builtin, and relies on the lexer to prevent space between tokens. + */ static Expr *parse_builtin(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); Expr *expr = EXPR_NEW_TOKEN(EXPR_BUILTIN); - advance_and_verify(c, TOKEN_BUILTIN); - if (!token_is_some_ident(c->tok)) + if (!token_is_some_ident(peek(c))) { - SEMA_ERROR_HERE("Expected a name here."); + SEMA_ERROR_HERE("Unexpected '$$', did you mean to write a builtin?"); return poisoned_expr; } + advance_and_verify(c, TOKEN_BUILTIN); expr->builtin_expr.ident = symstr(c); + expr->span = extend_span_with_token(expr->span, c->span); if (try_consume(c, TOKEN_CONST_IDENT)) { expr->expr_kind = EXPR_COMPILER_CONST; + return expr; } - else - { - CONSUME_OR_RET(TOKEN_IDENT, poisoned_expr); - } - RANGE_EXTEND_PREV(expr); + advance(c); return expr; } @@ -1130,6 +1205,23 @@ static int read_num_type(const char *string, size_t loc, size_t len) return i; } +int read_int_suffix(const char *string, int loc, int len, char c) +{ + switch (c | 32) + { + case 'i': + return read_num_type(string, loc, len); + case 'l': + if (loc != len - 1) return -1; + return 64; + case 'u': + if (loc == len - 2 && (string[loc + 1] | 32) == 'l') return 64; + return read_num_type(string, loc, len); + default: + return -1; + } +} + Expr *parse_integer(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); @@ -1144,7 +1236,7 @@ Expr *parse_integer(ParseContext *c, Expr *left) int binary_characters = 0; bool wrapped = false; uint64_t max; - switch (len > 2 ? string[1] : '0') + switch (len > 2 ? (string[1] | 32) : '0') { case 'x': is_unsigned = true; @@ -1152,18 +1244,22 @@ Expr *parse_integer(ParseContext *c, Expr *left) for (size_t loc = 2; loc < len; loc++) { char ch = string[loc]; - if (ch == 'u' || ch == 'U') + switch (ch | 32) { - type_bits = read_num_type(string, loc, len); - break; + case 'u': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = true; + goto EXIT; + case 'l': + case 'i': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = false; + goto EXIT; + case '_' | 32: + continue; + default: + break; } - if (ch == 'i' || ch == 'I') - { - is_unsigned = false; - type_bits = read_num_type(string, loc, len); - break; - } - if (ch == '_') continue; if (i.high > max) wrapped = true; i = i128_shl64(i, 4); i = i128_add64(i, (uint64_t) char_hex_to_nibble(ch)); @@ -1176,18 +1272,22 @@ Expr *parse_integer(ParseContext *c, Expr *left) for (size_t loc = 2; loc < len; loc++) { char ch = string[loc]; - if (ch == 'i' || ch == 'I') + switch (ch | 32) { - is_unsigned = false; - type_bits = read_num_type(string, loc, len); - break; + case 'u': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = true; + goto EXIT; + case 'l': + case 'i': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = false; + goto EXIT; + case '_' | 32: + continue; + default: + break; } - if (ch == 'u' || ch == 'U') - { - type_bits = read_num_type(string, loc, len); - break; - } - if (ch == '_') continue; if (i.high > max) wrapped = true; i = i128_shl64(i, 3); i = i128_add64(i, (uint64_t)(ch - '0')); @@ -1200,7 +1300,22 @@ Expr *parse_integer(ParseContext *c, Expr *left) for (size_t loc = 2; loc < len; loc++) { char ch = string[loc]; - if (ch == '_') continue; + switch (ch | 32) + { + case 'u': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = true; + goto EXIT; + case 'l': + case 'i': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = false; + goto EXIT; + case '_' | 32: + continue; + default: + break; + } binary_characters++; if (i.high > max) wrapped = true; i = i128_shl64(i, 1); @@ -1211,35 +1326,30 @@ Expr *parse_integer(ParseContext *c, Expr *left) for (size_t loc = 0; loc < len; loc++) { char ch = string[loc]; - switch (ch) + switch (ch | 32) { - case 'i': - case 'I': - is_unsigned = false; - type_bits = read_num_type(string, loc, len); - goto EXIT; case 'u': - case 'U': + type_bits = read_int_suffix(string, loc, len, ch); is_unsigned = true; - type_bits = read_num_type(string, loc, len); goto EXIT; - case '_': + case 'l': + case 'i': + type_bits = read_int_suffix(string, loc, len, ch); + is_unsigned = false; + goto EXIT; + case '_' | 32: continue; - case NUMBER_CHAR_CASE: - { - uint64_t old_top = i.high; - i = i128_mult64(i, 10); - i = i128_add64(i, (uint64_t)(ch - '0')); - if (!wrapped && old_top > i.high) wrapped = true; - break; - } default: - UNREACHABLE + break; } + uint64_t old_top = i.high; + i = i128_mult64(i, 10); + i = i128_add64(i, (uint64_t)(ch - '0')); + if (!wrapped && old_top > i.high) wrapped = true; } - EXIT: break; } +EXIT: if (wrapped) { SEMA_ERROR_HERE("Integer size exceeded 128 bits, max 128 bits are supported."); @@ -1348,14 +1458,11 @@ static void parse_hex(char *result_pointer, const char *data, const char *end) assert(data_current); while (data < end) { - int val; - int val2; - while ((val = char_hex_to_nibble(*(data++))) < 0) if (data == end) goto DONE; + int val, val2; + while ((val = char_hex_to_nibble(*(data++))) < 0) if (data == end) return; while ((val2 = char_hex_to_nibble(*(data++))) < 0); - *(data_current++) = (char)((val << 4) | val2); } - DONE:; } /** @@ -1383,10 +1490,7 @@ static void parse_base64(char *result_pointer, char *result_pointer_end, const c assert(data_current); while (data < end) { - int val; - int val2; - int val3; - int val4; + int val, val2, val3, val4; while ((val = base64_to_sextet(*(data++))) < 0) if (data == end) goto DONE; while ((val2 = base64_to_sextet(*(data++))) < 0); while ((val3 = base64_to_sextet(*(data++))) < 0); @@ -1443,6 +1547,9 @@ static Expr *parse_bytes_expr(ParseContext *c, Expr *left) return expr_bytes; } +/** + * Char literals may be 1, 2, 4, 8 or 16 bytes. They are always unsigned. + */ static Expr *parse_char_lit(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); @@ -1481,7 +1588,9 @@ static Expr *parse_char_lit(ParseContext *c, Expr *left) return expr_int; } - +/** + * Parse a double from the underlying string into a constant. + */ static Expr *parse_double(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); @@ -1489,6 +1598,8 @@ static Expr *parse_double(ParseContext *c, Expr *left) Expr *number = EXPR_NEW_TOKEN(EXPR_CONST); const char *original = symstr(c); bool is_hex = original[0] == '0' && original[1] == 'x'; + // This is set to try to print in a similar manner as the input. + number->const_expr.is_hex = is_hex; Float f = is_hex ? float_from_hex(original, &err) : float_from_string(original, &err); if (f.type == TYPE_POISONED) { @@ -1510,87 +1621,20 @@ static Expr *parse_double(ParseContext *c, Expr *left) case TYPE_F16: number->type = type_float16; break; + case TYPE_BF16: + TODO default: UNREACHABLE } number->const_expr.const_kind = CONST_FLOAT; + number->resolve_status = RESOLVE_DONE; advance(c); return number; } -static int append_esc_string_token(char *restrict dest, const char *restrict src, size_t *pos) -{ - int scanned; - uint64_t unicode_char; - signed char scanned_char = char_is_valid_escape(src[0]); - if (scanned_char < 0) return -1; - switch (scanned_char) - { - case 'x': - { - int h = char_hex_to_nibble(src[1]); - int l = char_hex_to_nibble(src[2]); - if (h < 0 || l < 0) return -1; - unicode_char = ((unsigned) h << 4U) + (unsigned)l; - scanned = 3; - break; - } - case 'u': - { - int x1 = char_hex_to_nibble(src[1]); - int x2 = char_hex_to_nibble(src[2]); - int x3 = char_hex_to_nibble(src[3]); - int x4 = char_hex_to_nibble(src[4]); - if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0) return -1; - unicode_char = ((unsigned) x1 << 12U) + ((unsigned) x2 << 8U) + ((unsigned) x3 << 4U) + (unsigned)x4; - scanned = 5; - break; - } - case 'U': - { - int x1 = char_hex_to_nibble(src[1]); - int x2 = char_hex_to_nibble(src[2]); - int x3 = char_hex_to_nibble(src[3]); - int x4 = char_hex_to_nibble(src[4]); - int x5 = char_hex_to_nibble(src[5]); - int x6 = char_hex_to_nibble(src[6]); - int x7 = char_hex_to_nibble(src[7]); - int x8 = char_hex_to_nibble(src[8]); - if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0 || x6 < 0 || x7 < 0 || x8 < 0) return -1; - unicode_char = ((unsigned) x1 << 28U) + ((unsigned) x2 << 24U) + ((unsigned) x3 << 20U) + ((unsigned) x4 << 16U) + - ((unsigned) x5 << 12U) + ((unsigned) x6 << 8U) + ((unsigned) x7 << 4U) + (unsigned)x8; - scanned = 9; - break; - } - default: - dest[(*pos)++] = scanned_char; - return 1; - } - if (unicode_char < 0x80U) - { - dest[(*pos)++] = (char)unicode_char; - } - else if (unicode_char < 0x800U) - { - dest[(*pos)++] = (char)(0xC0U | (unicode_char >> 6U)); - dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); - } - else if (unicode_char < 0x10000U) - { - dest[(*pos)++] = (char)(0xE0U | (unicode_char >> 12U)); - dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 6U) & 0x3FU)); - dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); - } - else - { - dest[(*pos)++] = (char)(0xF0U | (unicode_char >> 18U)); - dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 12U) & 0x3FU)); - dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 6U) & 0x3FU)); - dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); - } - return scanned; -} - +/** + * string_literal ::= STRING+ + */ static Expr *parse_string_literal(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); @@ -1604,8 +1648,15 @@ static Expr *parse_string_literal(ParseContext *c, Expr *left) // and can be optimized. while (tok_is(c, TOKEN_STRING)) { + // Grab the token. size_t next_len = c->data.strlen; - if (!next_len) continue; + if (!next_len) + { + // Zero length so just continue. + advance_and_verify(c, TOKEN_STRING); + continue; + } + // Create new string and copy. char *buffer = malloc_string(len + next_len + 1); memcpy(buffer, str, len); memcpy(buffer + len, symstr(c), next_len); @@ -1614,7 +1665,6 @@ static Expr *parse_string_literal(ParseContext *c, Expr *left) str = buffer; advance_and_verify(c, TOKEN_STRING); } - if (len > UINT32_MAX) { SEMA_ERROR_HERE("String exceeded max size."); @@ -1625,19 +1675,27 @@ static Expr *parse_string_literal(ParseContext *c, Expr *left) expr_string->const_expr.string.len = (uint32_t)len; expr_string->type = type_string; expr_string->const_expr.const_kind = CONST_STRING; + expr_string->resolve_status = RESOLVE_DONE; return expr_string; } +/* + * bool ::= 'true' | 'false' + */ static Expr *parse_bool(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST); number->const_expr = (ExprConst) { .b = tok_is(c, TOKEN_TRUE), .const_kind = CONST_BOOL }; number->type = type_bool; + number->resolve_status = RESOLVE_DONE; advance(c); return number; } +/** + * Parse 'null', creating a const void* with zero address. + */ static Expr *parse_null(ParseContext *c, Expr *left) { assert(!left && "Had left hand side"); @@ -1645,10 +1703,14 @@ static Expr *parse_null(ParseContext *c, Expr *left) number->const_expr.const_kind = CONST_POINTER; number->const_expr.ptr = 0; number->type = type_voidptr; + number->resolve_status = RESOLVE_DONE; advance(c); return number; } +/** + * Expects an initializer list, then appends the type making it a compound expr rather than initializer list. + */ Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info) { Expr *expr = expr_new(EXPR_COMPOUND_LITERAL, type_info->span); @@ -1659,22 +1721,8 @@ Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *typ return expr; } - -Expr *parse_any_expression(ParseContext *c, TypeInfo *type) -{ - Expr *expr = expr_new(EXPR_VARIANT, type->span); - advance_and_verify(c, TOKEN_LBRACE); - ASSIGN_EXPRID_OR_RET(expr->variant_expr.ptr, parse_expr(c), poisoned_expr); - TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected a ','", poisoned_expr); - ASSIGN_EXPRID_OR_RET(expr->variant_expr.type_id, parse_expr(c), poisoned_expr); - TRY_CONSUME_OR_RET(TOKEN_RBRACE, "Missing end '}'", poisoned_expr); - return expr; -} /** - * type_identifier ::= TYPE_IDENT initializer_list? - * - * @param left must be null. - * @return Expr* + * type_expression_with_path ::= TYPE_IDENT initializer_list? */ Expr *parse_type_expression_with_path(ParseContext *c, Path *path) { @@ -1695,10 +1743,6 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path) } if (tok_is(c, TOKEN_LBRACE)) { - if (type->resolve_status == RESOLVE_DONE && type->type == type_any) - { - return parse_any_expression(c, type); - } return parse_type_compound_literal_expr_after_type(c, type); } Expr *expr = expr_new(EXPR_TYPEINFO, type->span); @@ -1714,8 +1758,7 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path) /** - * function_block - * : '{|' stmt_list '|}' + * expr_block ::= '{|' opt_stmt_list '|}' */ static Expr* parse_expr_block(ParseContext *c, Expr *left) { @@ -1755,18 +1798,16 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_FLOAT128] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_VOID] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_TYPEID] = { parse_type_identifier, NULL, PREC_NONE }, - [TOKEN_ANYERR] = { parse_type_identifier, NULL, PREC_NONE }, - [TOKEN_VARIANT] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_ANYFAULT] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_ANY] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_QUESTION] = { NULL, parse_ternary_expr, PREC_TERNARY }, - [TOKEN_QUESTQUEST] = { NULL, parse_binary, PREC_TERNARY}, - [TOKEN_ELVIS] = { NULL, parse_ternary_expr, PREC_TERNARY }, + [TOKEN_QUESTQUEST] = { NULL, parse_orelse, PREC_TERNARY }, + [TOKEN_ELVIS] = { NULL, parse_elvis_expr, PREC_TERNARY }, [TOKEN_PLUSPLUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, [TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, [TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL }, [TOKEN_LBRAPIPE] = { parse_expr_block, NULL, PREC_NONE }, - [TOKEN_TRY_QUESTION] = { parse_try_expr, NULL, PREC_NONE }, - [TOKEN_CATCH_QUESTION] = { parse_try_expr, NULL, PREC_NONE }, [TOKEN_BANGBANG] = { NULL, parse_force_unwrap_expr, PREC_CALL }, [TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL }, [TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, @@ -1775,7 +1816,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_STAR] = { parse_unary_expr, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_DOT] = { NULL, parse_access_expr, PREC_CALL }, - [TOKEN_BANG] = { parse_unary_expr, parse_optional, PREC_CALL }, + [TOKEN_BANG] = { parse_unary_expr, parse_rethrow_expr, PREC_CALL }, [TOKEN_BYTES] = { parse_bytes_expr, NULL, PREC_NONE }, [TOKEN_BIT_NOT] = { parse_unary_expr, NULL, PREC_UNARY }, [TOKEN_BIT_XOR] = { NULL, parse_binary, PREC_BIT }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 6565ad0fb..c570b5926 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -6,9 +6,9 @@ #include "parser_internal.h" static bool context_next_is_path_prefix_start(ParseContext *c); -static Decl *parse_const_declaration(ParseContext *c, bool is_global); static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool is_interface); static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl); +static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref); static inline Decl *parse_static_top_level(ParseContext *c); static Decl *parse_include(ParseContext *c); static bool parse_attributes_for_global(ParseContext *c, Decl *decl); @@ -42,7 +42,6 @@ void recover_top_level(ParseContext *c) { switch (c->tok) { - case TOKEN_PRIVATE: case TOKEN_IMPORT: case TOKEN_EXTERN: case TOKEN_ENUM: @@ -90,8 +89,6 @@ INLINE bool parse_decl_initializer(ParseContext *c, Decl *decl) */ static inline bool parse_top_level_block(ParseContext *c, Decl ***decls, TokenType end1, TokenType end2, TokenType end3) { - consume_deprecated_symbol(c, TOKEN_COLON); // TODO remove - // Check whether we reached a terminating token or EOF while (!tok_is(c, end1) && !tok_is(c, end2) && !tok_is(c, end3) && !tok_is(c, TOKEN_EOF)) { @@ -117,23 +114,9 @@ static inline Decl *parse_ct_if_top_level(ParseContext *c) advance_and_verify(c, TOKEN_CT_IF); ASSIGN_EXPR_OR_RET(ct->ct_if_decl.expr, parse_const_paren_expr(c), poisoned_decl); - if (!parse_top_level_block(c, &ct->ct_if_decl.then, TOKEN_CT_ENDIF, TOKEN_CT_ELIF, TOKEN_CT_ELSE)) return poisoned_decl; - + if (!parse_top_level_block(c, &ct->ct_if_decl.then, TOKEN_CT_ENDIF, TOKEN_CT_ENDIF, TOKEN_CT_ELSE)) return poisoned_decl; CtIfDecl *ct_if_decl = &ct->ct_if_decl; - // Chain elif TODO remove - while (tok_is(c, TOKEN_CT_ELIF)) - { - sema_warning_at(c->span, "$elif is deprecated, use $switch instead."); - Decl *ct_elif = decl_new_ct(DECL_CT_IF, c->span); - advance_and_verify(c, TOKEN_CT_ELIF); - ASSIGN_EXPR_OR_RET(ct_elif->ct_elif_decl.expr, parse_const_paren_expr(c), poisoned_decl); - if (!parse_top_level_block(c, &ct_elif->ct_elif_decl.then, TOKEN_CT_ENDIF, TOKEN_CT_ELIF, TOKEN_CT_ELSE)) return poisoned_decl; - ct_if_decl->elif = ct_elif; - ct_if_decl = &ct_elif->ct_elif_decl; - } - // <- end - // final else if (tok_is(c, TOKEN_CT_ELSE)) { @@ -143,7 +126,6 @@ static inline Decl *parse_ct_if_top_level(ParseContext *c) if (!parse_top_level_block(c, &ct_else->ct_else_decl, TOKEN_CT_ENDIF, TOKEN_CT_ENDIF, TOKEN_CT_ENDIF)) return poisoned_decl; } CONSUME_OR_RET(TOKEN_CT_ENDIF, poisoned_decl); - consume_deprecated_symbol(c, TOKEN_EOS); // TODO remove return ct; } @@ -192,14 +174,12 @@ static inline Decl *parse_ct_switch_top_level(ParseContext *c) if (!tok_is(c, TOKEN_CT_CASE) && !tok_is(c, TOKEN_CT_DEFAULT) && !tok_is(c, TOKEN_CT_ENDSWITCH)) { ASSIGN_EXPR_OR_RET(ct->ct_switch_decl.expr, parse_const_paren_expr(c), poisoned_decl); - consume_deprecated_symbol(c, TOKEN_COLON); // TODO remove } while (!try_consume(c, TOKEN_CT_ENDSWITCH)) { ASSIGN_DECL_OR_RET(Decl *result, parse_ct_case(c), poisoned_decl); vec_add(ct->ct_switch_decl.cases, result); } - consume_deprecated_symbol(c, TOKEN_EOS); // TODO remove return ct; } @@ -366,7 +346,7 @@ bool parse_module(ParseContext *c, AstId contracts) case CONTRACT_UNKNOWN: case CONTRACT_PURE: case CONTRACT_PARAM: - case CONTRACT_ERRORS: + case CONTRACT_OPTIONALS: case CONTRACT_ENSURE: break; case CONTRACT_REQUIRE: @@ -672,11 +652,7 @@ static inline TypeInfo *parse_vector_type_index(ParseContext *c, TypeInfo *type) advance_and_verify(c, TOKEN_LVEC); TypeInfo *vector = type_info_new(TYPE_INFO_VECTOR, type->span); vector->array.base = type; - if (try_consume(c, TOKEN_RVEC)) - { - vector->kind = TYPE_INFO_SCALED_VECTOR; - } - else if (try_consume(c, TOKEN_STAR)) + if (try_consume(c, TOKEN_STAR)) { CONSUME_OR_RET(TOKEN_RVEC, poisoned_type_info); vector->kind = TYPE_INFO_INFERRED_VECTOR; @@ -827,37 +803,6 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type) return decl; } -/** - * declaration ::= ('static' | 'const')? type variable ('=' expr)? - * - * @return Decl* (poisoned on error) - */ -Decl *parse_local_decl(ParseContext *c) -{ - if (tok_is(c, TOKEN_CONST)) - { - ASSIGN_DECL_OR_RET(Decl *decl, parse_const_declaration(c, false), poisoned_decl); - decl->visibility = VISIBLE_LOCAL; - return decl; - } - - bool is_threadlocal = try_consume(c, TOKEN_TLOCAL); - bool is_static = !is_threadlocal && try_consume(c, TOKEN_STATIC); - - ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl); - - ASSIGN_DECL_OR_RET(Decl * decl, parse_local_decl_after_type(c, type), poisoned_decl); - if (type->optional && decl->var.unwrap) - { - SEMA_ERROR(decl, "You cannot use unwrap with an optional variable."); - return poisoned_decl; - } - decl->var.is_static = is_static || is_threadlocal; - decl->var.is_threadlocal = is_threadlocal; - decl->visibility = VISIBLE_LOCAL; - return decl; -} - /** * decl_or_expr ::= var_decl | type local_decl_after_type | expression */ @@ -883,7 +828,7 @@ Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref) /** * const_decl ::= 'const' type? CONST_IDENT attributes? '=' const_expr */ -static Decl *parse_const_declaration(ParseContext *c, bool is_global) +Decl *parse_const_declaration(ParseContext *c, bool is_global) { advance_and_verify(c, TOKEN_CONST); @@ -1358,7 +1303,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, sema_error_at(extend_span_with_token(span, c->span), "Variadic parameters are not allowed."); return false; } - // Did we get Foo foo..., then that's an error. + // Did we get Foo foo...? If so then that's an error. if (type) { SEMA_ERROR_HERE("For typed varargs '...', needs to appear after the type."); @@ -1391,7 +1336,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, SEMA_ERROR_HERE("A regular variable name, e.g. 'foo' was expected after the '&'."); return false; } - // This will catch Type... &foo and &foo..., neighter is allowed. + // This will catch Type... &foo and &foo..., neither is allowed. if (ellipsis || try_consume(c, TOKEN_ELLIPSIS)) { SEMA_ERROR_HERE("Reference parameters may not be varargs, use untyped macro varargs '...' instead."); @@ -1497,20 +1442,16 @@ static inline bool parse_fn_parameter_list(ParseContext *c, Signature *signature /** * Expect pointer to after '{' * - * struct_body - * : '{' struct_declaration_list '}' - * ; + * struct_body ::= '{' struct_declaration_list '}' * - * struct_declaration_list - * : struct_member_declaration - * | struct_declaration_list struct_member_declaration - * ; + * struct_declaration_list ::= struct_member_decl+ * - * struct_member_declaration - * : type_expression identifier_list opt_attributes ';' + * struct_member_decl ::= + * (type_expression identifier_list opt_attributes ';') * | struct_or_union IDENT opt_attributes struct_body * | struct_or_union opt_attributes struct_body - * ; + * | BITSTRUCT IDENT ':' type opt_attributes struct_body + * | BITSTRUCT ':' type opt_attributes struct_body * * @param parent the parent of the struct */ @@ -1554,8 +1495,7 @@ bool parse_struct_body(ParseContext *c, Decl *parent) index++; if (index > MAX_MEMBERS) { - SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS); - return false; + RETURN_SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS); } continue; } @@ -1564,13 +1504,11 @@ bool parse_struct_body(ParseContext *c, Decl *parent) { if (parent->decl_kind != DECL_STRUCT) { - SEMA_ERROR_HERE("Only structs may have 'inline' elements, did you make a mistake?"); - return false; + RETURN_SEMA_ERROR_HERE("Only structs may have 'inline' elements, did you make a mistake?"); } if (index > 0) { - SEMA_ERROR_LAST("Only the first element may be 'inline', did you order your fields wrong?"); - return false; + RETURN_SEMA_ERROR_LAST("Only the first element may be 'inline', did you order your fields wrong?"); } parent->is_substruct = true; was_inline = true; @@ -1580,26 +1518,21 @@ bool parse_struct_body(ParseContext *c, Decl *parent) while (1) { - if (!tok_is(c, TOKEN_IDENT)) - { - SEMA_ERROR_HERE("A valid member name was expected here."); - return false; - } + if (!tok_is(c, TOKEN_IDENT)) RETURN_SEMA_ERROR_HERE("A valid member name was expected here."); + Decl *member = decl_new_var_current(c, type, VARDECL_MEMBER); vec_add(parent->strukt.members, member); index++; if (index > MAX_MEMBERS) { - SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS); - return false; + RETURN_SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS); } advance(c); if (!parse_attributes(c, &member->attributes, NULL)) return false; if (!try_consume(c, TOKEN_COMMA)) break; if (was_inline) { - SEMA_ERROR(member, "'Inline' can only be applied to a single member, so please define it on its own line."); - return false; + RETURN_SEMA_ERROR(member, "'inline' can only be applied to a single member, so please define it on its own line."); } } CONSUME_EOS_OR_RET(false); @@ -1611,11 +1544,7 @@ bool parse_struct_body(ParseContext *c, Decl *parent) /** - * struct_declaration - * : struct_or_union TYPE_IDENT opt_attributes struct_body - * ; - * - * @param visibility + * struct_declaration ::= struct_or_union TYPE_IDENT opt_attributes struct_body */ static inline Decl *parse_struct_declaration(ParseContext *c) { @@ -1627,22 +1556,18 @@ 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_attributes_for_global(c, decl)) return poisoned_decl; + if (!parse_struct_body(c, decl)) return poisoned_decl; - if (!parse_struct_body(c, decl)) - { - return poisoned_decl; - } DEBUG_LOG("Parsed %s %s completely.", type_name, decl->name); return decl; } /** - * body ::= '{' (TYPE IDENT ':' expr '..' expr EOS)* '}' - * @param c - * @param decl - * @return + * bitstruct_body ::= '{' bitstruct_def* | bitstruct_simple_def* '}' + * + * bitstruct_def ::= base_type IDENT ':' constant_expr (DOTDOT constant_expr)? ';' + * bitstruct_simple_def ::= base_type IDENT ';' */ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl) { @@ -1651,7 +1576,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl) bool is_consecutive = false; while (!try_consume(c, TOKEN_RBRACE)) { - ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_type(c), false); + ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_base_type(c), false); Decl *member_decl = decl_new_var_current(c, type, VARDECL_BITMEMBER); if (!try_consume(c, TOKEN_IDENT)) @@ -1664,13 +1589,13 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl) SEMA_ERROR_HERE("Expected a field name at this position."); return false; } - if (is_consecutive || tok_is(c, TOKEN_EOS)) + if (tok_is(c, TOKEN_EOS)) { if (!is_consecutive) { if (decl->bitstruct.members) { - SEMA_ERROR_HERE("Expected a ':'."); + SEMA_ERROR(member_decl, "Bitstructs either have bit ranges for all members, or no members have ranges – mixing is not permitted. Either add a range to this member or remove ranges from the other member(s)."); return false; } is_consecutive = true; @@ -1693,13 +1618,18 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl) member_decl->var.end = NULL; } CONSUME_EOS_OR_RET(false); + if (is_consecutive) + { + SEMA_ERROR(member_decl->var.start, "Bitstructs either have bit ranges for all members, or no members have ranges – mixing is not permitted. Either remove this range, or add ranges to all other members."); + return false; + } vec_add(decl->bitstruct.members, member_decl); } decl->bitstruct.consecutive = is_consecutive; return true; } /** - * bitstruct_declaration = 'bitstruct' IDENT ':' type bitstruct_body + * bitstruct_declaration ::= 'bitstruct' TYPE_IDENT ':' type bitstruct_body */ static inline Decl *parse_bitstruct_declaration(ParseContext *c) { @@ -1730,11 +1660,11 @@ static inline Decl *parse_top_level_const_declaration(ParseContext *c) /** - * macro_arguments ::= '(' parameters (EOS trailing_block_parameter )? ')' + * macro_params ::= parameters? (EOS trailing_block_param)? * - * trailing_block_parameter ::= '@' IDENT ( '(' parameters ')' )? + * trailing_block_param ::= AT_IDENT ( '(' parameters? ')' )? */ -static bool parse_macro_arguments(ParseContext *c, Decl *macro) +static bool parse_macro_params(ParseContext *c, Decl *macro) { CONSUME_OR_RET(TOKEN_LPAREN, false); @@ -1797,16 +1727,17 @@ static inline void decl_add_type(Decl *decl, TypeKind kind) decl->type = type; } /** - * define_type_body ::= TYPE_IDENT '=' 'distinct'? (func_typedef | type generic_params?) ';' + * typedef_declaration ::= TYPEDEF TYPE_IDENT '=' 'distinct'? typedef_type ';' * + * typedef_type ::= func_typedef | type generic_params? * func_typedef ::= 'fn' optional_type parameter_type_list */ -static inline Decl *parse_define_type(ParseContext *c) +static inline Decl *parse_typedef_declaration(ParseContext *c) { - advance(c); + advance_and_verify(c, TOKEN_TYPEDEF); Decl *decl = decl_new(DECL_POISONED, symstr(c), c->span); - DEBUG_LOG("Parse define %s", decl->name); + DEBUG_LOG("Parse typedef %s", decl->name); if (!try_consume(c, TOKEN_TYPE_IDENT)) { if (token_is_any_type(c->tok)) @@ -1908,9 +1839,9 @@ static inline Decl *parse_define_type(ParseContext *c) } /** - * define_ident ::= 'define' (IDENT | CONST_IDENT) '=' identifier_alias generic_params? + * define_ident ::= 'define' (IDENT | CONST_IDENT | AT_IDENT) '=' identifier_alias generic_params? * - * identifier_alias ::= path? (IDENT | CONST_IDENT) + * identifier_alias ::= path? (IDENT | CONST_IDENT | AT_IDENT) */ static inline Decl *parse_define_ident(ParseContext *c) { @@ -1922,14 +1853,13 @@ static inline Decl *parse_define_ident(ParseContext *c) TokenType alias_type = c->tok; if (alias_type != TOKEN_IDENT && alias_type != TOKEN_CONST_IDENT && alias_type != TOKEN_AT_IDENT) { - if (token_is_any_type(alias_type)) + if (alias_type == TOKEN_TYPE_IDENT) { - SEMA_ERROR_HERE("'%s' is the name of a built-in type and can't be used as an alias.", - token_type_to_string(alias_type)); + SEMA_ERROR_HERE("A variable, constant or attribute name was expected here. If you want to define a new type, use 'typedef' instead."); } else { - SEMA_ERROR_HERE("An identifier was expected here."); + SEMA_ERROR_HERE("A variable, constant or attribute name was expected here."); } return poisoned_decl; } @@ -1996,25 +1926,13 @@ static inline Decl *parse_define_ident(ParseContext *c) if (!params) return poisoned_decl; decl->define_decl.generic_params = params; } - else if (!tok_is(c, TOKEN_EOS) && decl->define_decl.ident == kw_distinct) - { - if (token_is_any_type(c->tok)) - { - SEMA_ERROR(decl, "A type name alias must start with an uppercase letter."); - } - else - { - sema_error_at(decl->define_decl.span, "'distinct' can only be used with types."); - } - return poisoned_decl; - } RANGE_EXTEND_PREV(decl); CONSUME_EOS_OR_RET(poisoned_decl); return decl; } /** - * define_attribute ::= 'define' AT_TYPE_IDENT '(' parameter_list ')' ('=' attribute_list)? + * define_attribute ::= 'define' AT_TYPE_IDENT '(' parameter_list ')' opt_attributes '=' '{' attributes? '}' ';' */ static inline Decl *parse_define_attribute(ParseContext *c) { @@ -2027,6 +1945,11 @@ static inline Decl *parse_define_attribute(ParseContext *c) if (try_consume(c, TOKEN_LPAREN)) { + if (tok_is(c, TOKEN_RPAREN)) + { + sema_error_at(c->prev_span, "At least one parameter was expected after '(' - try removing the '()'."); + return poisoned_decl; + } if (!parse_parameters(c, &decl->attr_decl.params, NULL, NULL, NULL, PARAM_PARSE_ATTR)) return poisoned_decl; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl); } @@ -2054,9 +1977,6 @@ static inline Decl *parse_define(ParseContext *c) case TOKEN_AT_TYPE_IDENT: // define @Foo = @inline, @noreturn return parse_define_attribute(c); - case TOKEN_TYPE_IDENT: - sema_warning_at(c->span, "Defining types with 'define' is deprecated. Use 'typedef'."); - return parse_define_type(c); default: return parse_define_ident(c); } @@ -2138,7 +2058,8 @@ static inline bool parse_func_macro_header(ParseContext *c, Decl *decl) /** - * macro ::= macro_header '(' macro_params ')' compound_statement + * macro ::= MACRO macro_header '(' macro_params ')' opt_attributes macro_body + * macro_body ::= IMPLIES expression ';' | compound_statement */ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs) { @@ -2149,7 +2070,7 @@ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs) decl->func_decl.docs = docs; if (!parse_func_macro_header(c, decl)) return poisoned_decl; const char *block_parameter = NULL; - if (!parse_macro_arguments(c, decl)) return poisoned_decl; + if (!parse_macro_params(c, decl)) return poisoned_decl; if (!parse_attributes_for_global(c, decl)) return poisoned_decl; if (tok_is(c, TOKEN_IMPLIES)) @@ -2158,26 +2079,22 @@ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs) parse_short_body(c, decl->func_decl.signature.rtype, true), poisoned_decl); return decl; } - ASSIGN_ASTID_OR_RET(decl->func_decl.body, parse_stmt(c), poisoned_decl); + ASSIGN_ASTID_OR_RET(decl->func_decl.body, parse_compound_stmt(c), poisoned_decl); return decl; } /** - * error_declaration - * : FAULT TYPE_IDENT ';' - * | FAULT TYPE_IDENT '{' error_data '}' - * ; + * fault_declaration ::= FAULT TYPE_IDENT opt_attributes '{' faults ','? '}' */ static inline Decl *parse_fault_declaration(ParseContext *c) { - advance(c); - // advance_and_verify(context, TOKEN_ERRTYPE); + advance_and_verify(c, TOKEN_FAULT); Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_FAULT); if (!consume_type_name(c, "fault")) return poisoned_decl; - TypeInfo *type = NULL; + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl); @@ -2201,8 +2118,7 @@ static inline Decl *parse_fault_declaration(ParseContext *c) { SEMA_ERROR(fault_const, "This fault value was declared twice."); SEMA_NOTE(other_constant, "The previous declaration was here."); - decl_poison(fault_const); - break; + return poisoned_decl; } } vec_add(decl->enums.values, fault_const); @@ -2212,20 +2128,19 @@ static inline Decl *parse_fault_declaration(ParseContext *c) EXPECT_OR_RET(TOKEN_RBRACE, poisoned_decl); } } + if (ordinal == 0) + { + sema_error_at(c->prev_span, "Declaration of '%s' contains no values, at least one value is required.", decl->name); + return poisoned_decl; + } return decl; } /** - * enum_spec ::= type ('(' enum_params ')')? + * enum_param_list ::= '(' enum_param* ')' */ -static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl*** parameters_ref) +static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref) { - ASSIGN_TYPE_OR_RET(*type_ref, parse_optional_type(c), false); - if ((*type_ref)->optional) - { - SEMA_ERROR(*type_ref, "An enum can't have an optional type."); - return false; - } // If no left parenthesis we're done. if (!try_consume(c, TOKEN_LPAREN)) return true; @@ -2248,7 +2163,7 @@ static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl*** /** * Parse an enum declaration (after "enum") * - * enum ::= ENUM TYPE_IDENT enum_spec? opt_attributes '{' enum_body '}' + * enum ::= ENUM TYPE_IDENT (':' type enum_param_list)? opt_attributes '{' enum_body '}' * enum_body ::= enum_def (',' enum_def)* ','? * enum_def ::= CONST_IDENT ('(' arg_list ')')? */ @@ -2263,7 +2178,13 @@ static inline Decl *parse_enum_declaration(ParseContext *c) // Parse the spec if (try_consume(c, TOKEN_COLON)) { - if (!parse_enum_spec(c, &type, &decl->enums.parameters)) return poisoned_decl; + ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false); + if (type->optional) + { + SEMA_ERROR(type, "An enum can't have an optional type."); + return false; + } + if (!parse_enum_param_list(c, &decl->enums.parameters)) return poisoned_decl; } if (!parse_attributes_for_global(c, decl)) return poisoned_decl; @@ -2295,7 +2216,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c) if (try_consume(c, TOKEN_LPAREN)) { Expr **result = NULL; - if (!parse_arg_list(c, &result, TOKEN_RPAREN, NULL, false)) return poisoned_decl; + if (!parse_arg_list(c, &result, TOKEN_RPAREN, NULL, false, true)) return poisoned_decl; enum_const->enum_constant.args = result; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl); } @@ -2347,21 +2268,30 @@ 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; - // TODO remove - is_interface = tok_is(c, TOKEN_EOS); - if (is_interface) { - if (tok_is(c, TOKEN_LBRACE)) + if (tok_is(c, TOKEN_LBRACE) || tok_is(c, TOKEN_IMPLIES)) { - advance(c); - SEMA_ERROR_HERE("A function body is not allowed here."); + if (c->unit->is_interface_file) + { + SEMA_ERROR_HERE("An interface file may not contain function bodies."); + } + else + { + SEMA_ERROR_HERE("An 'extern' function may not have a body."); + } return poisoned_decl; } - TRY_CONSUME_OR_RET(TOKEN_EOS, "Expected ';' after function declaration.", poisoned_decl); + TRY_CONSUME_OR_RET(TOKEN_EOS, "Expected ';' after the function declaration.", poisoned_decl); return func; } + if (tok_is(c, TOKEN_EOS)) + { + SEMA_ERROR_HERE("Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file."); + return poisoned_decl; + } + if (tok_is(c, TOKEN_IMPLIES)) { ASSIGN_ASTID_OR_RET(func->func_decl.body, @@ -2412,21 +2342,10 @@ static inline Decl *parse_static_top_level(ParseContext *c) return init; } -static inline bool check_no_visibility_before(ParseContext *c, bool is_private) -{ - if (is_private) - { - SEMA_ERROR_HERE("Unexpected 'private' before '%s'", symstr(c)); - return false; - } - return true; -} - - /** * - * import ::= IMPORT import_path (',' import_path)* EOS + * import ::= IMPORT import_path (',' import_path)* opt_attributes EOS * * @return true if import succeeded */ @@ -2491,10 +2410,10 @@ static inline bool parse_doc_contract(ParseContext *c, AstId **docs_ref, Contrac const char *start = c->lexer.data.lex_start; advance(c); ASSIGN_EXPR_OR_RET(ast->contract.contract.decl_exprs, parse_expression_list(c, kind == CONTRACT_CHECKED), false); - const char *end = start; - while (*++end != '\n' && *end != '\0') end++; + const char *end = start + 1; + while (end[0] != '\n' && end[0] != '\0') end++; if (end > c->data.lex_start) end = c->data.lex_start; - while (end[-1] == ' ') end--; + while (is_space(end[-1])) end--; scratch_buffer_clear(); switch (kind) { @@ -2607,32 +2526,35 @@ static inline bool parse_contract_param(ParseContext *c, AstId **docs_ref) return true; } -static inline bool parse_doc_errors(ParseContext *c, AstId **docs_ref) +static inline bool parse_doc_optreturn(ParseContext *c, AstId **docs_ref) { - DocOptReturn *returns = NULL; + Ast **returns = NULL; Ast *ast = ast_new_curr(c, AST_CONTRACT); - ast->contract.kind = CONTRACT_ERRORS; - advance(c); + ast->span = c->prev_span; + advance_and_verify(c, TOKEN_BANG); + ast->contract.kind = CONTRACT_OPTIONALS; while (1) { - DocOptReturn ret = { .span = c->span }; - ASSIGN_TYPE_OR_RET(ret.type, parse_base_type(c), false); - if (ret.type->kind != TYPE_INFO_IDENTIFIER) + Ast *ret = ast_new_curr(c, AST_CONTRACT_FAULT); + ASSIGN_TYPE_OR_RET(ret->contract_fault.type, parse_base_type(c), false); + if (ret->contract_fault.type->kind != TYPE_INFO_IDENTIFIER) { - SEMA_ERROR(ret.type, "Expected a fault type."); + SEMA_ERROR(ret->contract_fault.type, "Expected a fault type."); return false; } if (try_consume(c, TOKEN_DOT)) { - ret.ident = c->data.string; + ret->contract_fault.ident = c->data.string; TRY_CONSUME_OR_RET(TOKEN_CONST_IDENT, "Expected a fault value.", false); } - ret.span = extend_span_with_token(ret.span, c->prev_span); + RANGE_EXTEND_PREV(ret); vec_add(returns, ret); if (!try_consume(c, TOKEN_COMMA)) break; } RANGE_EXTEND_PREV(ast); - ast->contract.optreturns = returns; + // Just ignore our potential string: + (void)try_consume(c, TOKEN_STRING); + ast->contract.faults = returns; **docs_ref = astid(ast); *docs_ref = &ast->next; return true; @@ -2663,6 +2585,11 @@ static bool parse_contracts(ParseContext *c, AstId *contracts_ref) else if (name == kw_at_return) { advance(c); + if (tok_is(c, TOKEN_BANG)) + { + if (!parse_doc_optreturn(c, &contracts_ref)) return false; + break; + } if (!consume(c, TOKEN_STRING, "Expected a string description.")) return false; break; } @@ -2688,11 +2615,6 @@ static bool parse_contracts(ParseContext *c, AstId *contracts_ref) if (!parse_doc_contract(c, &contracts_ref, CONTRACT_ENSURE)) return false; break; } - else if (name == kw_at_optreturn) - { - if (!parse_doc_errors(c, &contracts_ref)) return false; - break; - } else if (name == kw_at_pure) { Ast *ast = ast_new_curr(c, AST_CONTRACT); @@ -2800,11 +2722,6 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) AstId contracts = 0; if (!parse_contracts(c, &contracts)) return poisoned_decl; Decl *decl; - bool is_private = try_consume(c, TOKEN_PRIVATE); // TODO remove - if (is_private) - { - sema_warning_at(c->prev_span, "The use of 'private' is deprecated. Use '@private' instead."); - } TokenType tok = c->tok; if (tok != TOKEN_MODULE && !c->unit->module) @@ -2822,7 +2739,7 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) switch (tok) { case TOKEN_FN: - decl = parse_func_definition(c, contracts, false); + decl = parse_func_definition(c, contracts, true); break; case TOKEN_CONST: if (contracts) goto CONTRACT_NOT_ALLOWED; @@ -2863,14 +2780,14 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) return poisoned_decl; case TOKEN_TYPEDEF: if (contracts) goto CONTRACT_NOT_ALLOWED; - decl = parse_define_type(c); + decl = parse_typedef_declaration(c); break; case TOKEN_DEFINE: if (contracts) goto CONTRACT_NOT_ALLOWED; decl = parse_define(c); break; case TOKEN_FN: - decl = parse_func_definition(c, contracts, false); + decl = parse_func_definition(c, contracts, c->unit->is_interface_file); break; case TOKEN_STATIC: if (contracts) goto CONTRACT_NOT_ALLOWED; @@ -2967,7 +2884,6 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) return poisoned_decl; } if (!decl_ok(decl)) return decl; - if (is_private) decl->visibility = VISIBLE_PRIVATE; // TODO remove assert(decl); return decl; CONTRACT_NOT_ALLOWED: @@ -2975,11 +2891,3 @@ CONTRACT_NOT_ALLOWED: return poisoned_decl; } -void consume_deprecated_symbol(ParseContext *c, TokenType type) -{ - if (try_consume(c, type)) - { - sema_warning_at(c->prev_span, "'%s' is deprecated here.", token_type_to_string(type)); - } -} - diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 09d59db4d..3edb75aa9 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -5,12 +5,11 @@ #include "compiler_internal.h" #include "parser_internal.h" - // --- Internal functions static inline Expr *parse_asm_expr(ParseContext *c); -static Ast *parse_declaration_statment_after_type(ParseContext *c, TypeInfo *type) +static Ast *parse_decl_stmt_after_type(ParseContext *c, TypeInfo *type) { Ast *ast = ast_calloc(); ast->span = type->span; @@ -75,6 +74,7 @@ static Ast *parse_declaration_statment_after_type(ParseContext *c, TypeInfo *typ } + /** * declaration_stmt * : declaration ';' @@ -85,7 +85,8 @@ static inline Ast *parse_declaration_stmt(ParseContext *c) { // Consts don't have multiple declarations. Ast *decl_stmt = new_ast(AST_DECLARE_STMT, c->span); - ASSIGN_DECL_OR_RET(decl_stmt->declare_stmt, parse_local_decl(c), poisoned_ast); + ASSIGN_DECL_OR_RET(decl_stmt->declare_stmt, parse_const_declaration(c, false), poisoned_ast); + decl_stmt->declare_stmt->visibility = VISIBLE_LOCAL; RANGE_EXTEND_PREV(decl_stmt); CONSUME_EOS_OR_RET(poisoned_ast); return decl_stmt; @@ -95,7 +96,7 @@ static inline Ast *parse_declaration_stmt(ParseContext *c) bool is_static = !is_threadlocal && try_consume(c, TOKEN_STATIC); is_static = is_threadlocal || is_static; ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_ast); - ASSIGN_AST_OR_RET(Ast *result, parse_declaration_statment_after_type(c, type), poisoned_ast); + ASSIGN_AST_OR_RET(Ast *result, parse_decl_stmt_after_type(c, type), poisoned_ast); CONSUME_EOS_OR_RET(poisoned_ast); if (result->ast_kind == AST_DECLARE_STMT) { @@ -377,7 +378,7 @@ static inline Ast *parse_asm_stmt(ParseContext *c) } /** - * asm ::= 'asm' '(' string ')' + * asm ::= 'asm' '{' asm_stmt* '}' | 'asm' '(' string ')' * @param c * @return */ @@ -411,8 +412,11 @@ static inline Ast* parse_asm_block_stmt(ParseContext *c) /** - * do_stmt - * : DO statement WHILE '(' expression ')' ';' + * do_stmt ::= DO optional_label compound_stmt (WHILE '(' expression ')')? ';' + * + * Note that we transform do to a for loop (with a special flag) + * – and in parsing we allow a regular statement, but disambiguate that + * during semantic analysis. */ static inline Ast* parse_do_stmt(ParseContext *c) { @@ -460,8 +464,7 @@ static inline Ast *parse_case_stmts(ParseContext *c, TokenType case_type, TokenT /** - * defer_stmt - * : DEFER statement + * defer_stmt ::= DEFER (TRY | CATCH)? statement */ static inline Ast* parse_defer_stmt(ParseContext *c) { @@ -480,8 +483,9 @@ static inline Ast* parse_defer_stmt(ParseContext *c) } /** - * while_stmt - * : WHILE '(' control_expression ')' statement + * while_stmt ::= WHILE optional_label '(' cond ')' statement + * + * Note that during parsing we rewrite this as a for loop. */ static inline Ast* parse_while_stmt(ParseContext *c) { @@ -489,7 +493,6 @@ static inline Ast* parse_while_stmt(ParseContext *c) advance_and_verify(c, TOKEN_WHILE); ASSIGN_DECL_OR_RET(while_ast->for_stmt.flow.label, parse_optional_label(c, while_ast), poisoned_ast); - CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); ASSIGN_EXPRID_OR_RET(while_ast->for_stmt.cond, parse_cond(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); @@ -507,21 +510,9 @@ static inline Ast* parse_while_stmt(ParseContext *c) /** - * if_expr - * : optional_type IDENT '=' initializer - * | optional_type IDENT NOFAIL_ASSIGN expression - * | expression - * ; - * - * if_cond_expr - * : if_expr - * | if_cond_expr ',' if_expr - * ; - * - * if_stmt - * : IF '(' control_expression ')' statement - * | IF '(' control_expression ')' compound_statement ELSE compound_statement - * ; + * if_stmt ::= IF optional_label '(' cond ')' switch_body (ELSE compound_stmt)? + * | IF optional_label '(' cond ')' compound_stmt (ELSE compound_stmt)? + * | IF optional_label '(' cond ')' statement */ static inline Ast* parse_if_stmt(ParseContext *c) { @@ -532,6 +523,7 @@ static inline Ast* parse_if_stmt(ParseContext *c) ASSIGN_EXPRID_OR_RET(if_ast->if_stmt.cond, parse_cond(c), poisoned_ast); unsigned row = c->span.row; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); + // Special case, we might have if ( ) { case ... } if (tok_is(c, TOKEN_LBRACE) && (peek(c) == TOKEN_CASE || peek(c) == TOKEN_DEFAULT)) { @@ -551,11 +543,10 @@ static inline Ast* parse_if_stmt(ParseContext *c) ast_poison(astptr(if_ast->if_stmt.then_body)); } } - if (!try_consume(c, TOKEN_ELSE)) + if (try_consume(c, TOKEN_ELSE)) { - return if_ast; + ASSIGN_ASTID_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast); } - ASSIGN_ASTID_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast); return if_ast; } @@ -563,9 +554,9 @@ static inline Ast* parse_if_stmt(ParseContext *c) /** * * case_stmt - * : CASE constant_expression ':' case_stmts - * | CASE constant_expression ELLIPSIS constant_expression ':' cast_stmts - * | CAST type ':' cast_stmts + * : CASE expression ':' case_stmts + * | CASE expression DOTDOT expression ':' case_stmts + * | CAST type ':' case_stmts * ; */ static inline Ast *parse_case_stmt(ParseContext *c, TokenType case_type, TokenType default_type) @@ -642,8 +633,7 @@ bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, Token /** - * switch - * : SWITCH '(' decl_expr_list ')' '{' switch_body '}' + * switch ::= SWITCH optional_label ('(' cond ')')? switch_body */ static inline Ast* parse_switch_stmt(ParseContext *c) { @@ -652,9 +642,7 @@ static inline Ast* parse_switch_stmt(ParseContext *c) ASSIGN_DECL_OR_RET(switch_ast->switch_stmt.flow.label, parse_optional_label(c, switch_ast), poisoned_ast); if (!try_consume(c, TOKEN_LPAREN)) { - Expr *cond = expr_new(EXPR_COND, switch_ast->span); - vec_add(cond->cond_expr, expr_new_const_bool(switch_ast->span, type_bool, true)); - switch_ast->switch_stmt.cond = exprid(cond); + switch_ast->switch_stmt.cond = 0; } else { @@ -668,52 +656,58 @@ static inline Ast* parse_switch_stmt(ParseContext *c) /** - * for_statement - * : FOR '(' decl_expr_list ';' expression ';' ')' statement - * | FOR '(' decl_expr_list ';' ';' expression_list ')' statement - * | FOR '(' decl_expr_list ';' expression ';' expression_list ')' statement - * | FOR '(' ';' expression ';' ')' statement - * | FOR '(' ';' ';' expression_list ')' statement - * | FOR '(' ';' expression ';' expression_list ')' statement - * ; + * for_stmt ::= IF optional_label '(' expression_list? ';' cond? ';' expression_list? ')' statement */ static inline Ast* parse_for_stmt(ParseContext *c) { Ast *ast = new_ast(AST_FOR_STMT, c->span); advance_and_verify(c, TOKEN_FOR); - ASSIGN_DECL_OR_RET(ast->for_stmt.flow.label, parse_optional_label(c, ast), poisoned_ast); - CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - if (!tok_is(c, TOKEN_EOS)) - { - ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast); - } - else + // Label + ASSIGN_DECL_OR_RET(ast->for_stmt.flow.label, parse_optional_label(c, ast), poisoned_ast); + + CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); + if (try_consume(c, TOKEN_EOS)) { ast->for_stmt.init = 0; } - CONSUME_EOS_OR_RET(poisoned_ast); + else + { + ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast); + CONSUME_EOS_OR_RET(poisoned_ast); + } - if (!tok_is(c, TOKEN_EOS)) + if (try_consume(c, TOKEN_EOS)) + { + ast->for_stmt.cond = 0; + } + else { ASSIGN_EXPRID_OR_RET(ast->for_stmt.cond, parse_cond(c), poisoned_ast); + CONSUME_EOS_OR_RET(poisoned_ast); } - CONSUME_EOS_OR_RET(poisoned_ast); - - if (!tok_is(c, TOKEN_RPAREN)) + if (try_consume(c, TOKEN_RPAREN)) + { + ast->for_stmt.incr = 0; + } + else { ASSIGN_EXPRID_OR_RET(ast->for_stmt.incr, parse_expression_list(c, false), poisoned_ast); + CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); } - CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); - + // Ast range does not include the body RANGE_EXTEND_PREV(ast); + ASSIGN_AST_OR_RET(Ast *body, parse_stmt(c), poisoned_ast); ast->for_stmt.body = astid(body); return ast; } +/** + * foreach_var ::= optional_type? '&'? IDENT + */ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach) { TypeInfo *type = NULL; @@ -733,21 +727,15 @@ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach) Decl *var = decl_new_var(symstr(c), c->span, type, VARDECL_LOCAL); if (!try_consume(c, TOKEN_IDENT)) { - if (type) - { - SEMA_ERROR_HERE("Expected an identifier after the type."); - return false; - } - SEMA_ERROR_HERE("Expected an identifier or type."); - return false; + if (type) RETURN_SEMA_ERROR_HERE("Expected an identifier after the type."); + RETURN_SEMA_ERROR_HERE("Expected an identifier or type."); } foreach->foreach_stmt.variable = declid(var); return true; } /** - * foreach_statement - * : FOREACH (CONST_IDENT ':')? '(' type? '*'? IDENT (',' type? '*'? IDENT) ':' expression ')' statement - * ; + * foreach_stmt ::= (FOREACH | FOREACH_R) optional_label '(' foreach_vars ':' expression ')' statement + * foreach_vars ::= foreach_var (',' foreach_var)? */ static inline Ast* parse_foreach_stmt(ParseContext *c) { @@ -788,48 +776,52 @@ static inline Ast* parse_foreach_stmt(ParseContext *c) } /** - * continue_stmt - * : CONTINUE + * continue_stmt ::= CONTINUE optional_label_target ';' */ -static inline Ast* parse_continue(ParseContext *c) +static inline Ast* parse_continue_stmt(ParseContext *c) { Ast *ast = new_ast(AST_CONTINUE_STMT, c->span); advance_and_verify(c, TOKEN_CONTINUE); parse_optional_label_target(c, &ast->contbreak_stmt.label); if (ast->contbreak_stmt.label.name) ast->contbreak_stmt.is_label = true; + RANGE_EXTEND_PREV(ast); + CONSUME_EOS_OR_RET(poisoned_ast); return ast; } /** - * next ::= NEXTCASE ((CONST ':')? expression)? + * next ::= NEXTCASE ((CONST_IDENT ':')? expression)? ';' */ -static inline Ast* parse_next(ParseContext *c) +static inline Ast* parse_nextcase_stmt(ParseContext *c) { - Ast *ast = new_ast(AST_NEXT_STMT, c->span); + Ast *ast = new_ast(AST_NEXTCASE_STMT, c->span); advance_and_verify(c, TOKEN_NEXTCASE); - if (!tok_is(c, TOKEN_EOS)) + if (try_consume(c, TOKEN_EOS)) { - if (tok_is(c, TOKEN_CONST_IDENT) && peek(c) == TOKEN_COLON) - { - parse_optional_label_target(c, &ast->nextcase_stmt.label); - advance_and_verify(c, TOKEN_COLON); - } - ASSIGN_EXPR_OR_RET(ast->nextcase_stmt.expr, parse_expr(c), poisoned_ast); + return ast; } + if (tok_is(c, TOKEN_CONST_IDENT) && peek(c) == TOKEN_COLON) + { + parse_optional_label_target(c, &ast->nextcase_stmt.label); + advance_and_verify(c, TOKEN_COLON); + } + ASSIGN_EXPR_OR_RET(ast->nextcase_stmt.expr, parse_expr(c), poisoned_ast); + CONSUME_EOS_OR_RET(poisoned_ast); return ast; } /** - * break - * : BREAK + * break_stmt ::= BREAK optional_label_target ';' */ -static inline Ast* parse_break(ParseContext *c) +static inline Ast* parse_break_stmt(ParseContext *c) { Ast *ast = new_ast(AST_BREAK_STMT, c->span); advance_and_verify(c, TOKEN_BREAK); parse_optional_label_target(c, &ast->contbreak_stmt.label); if (ast->contbreak_stmt.label.name) ast->contbreak_stmt.is_label = true; + RANGE_EXTEND_PREV(ast); + CONSUME_EOS_OR_RET(poisoned_ast); return ast; } @@ -851,7 +843,7 @@ static inline Ast *parse_expr_stmt(ParseContext *c) static inline Ast *parse_decl_or_expr_stmt(ParseContext *c) { - ASSIGN_EXPR_OR_RET(Expr * expr, parse_expr(c), poisoned_ast); + ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_ast); // We might be parsing "int!" // If so we need to unwrap this. if (expr->expr_kind == EXPR_OPTIONAL && expr->inner_expr->expr_kind == EXPR_TYPEINFO) @@ -860,7 +852,7 @@ static inline Ast *parse_decl_or_expr_stmt(ParseContext *c) } if (expr->expr_kind == EXPR_TYPEINFO) { - ASSIGN_AST_OR_RET(Ast *ast, parse_declaration_statment_after_type(c, expr->type_expr), poisoned_ast); + ASSIGN_AST_OR_RET(Ast *ast, parse_decl_stmt_after_type(c, expr->type_expr), poisoned_ast); CONSUME_EOS_OR_RET(poisoned_ast); return ast; } @@ -898,55 +890,36 @@ static inline bool parse_ct_compound_stmt(ParseContext *c, AstId *start) while (1) { TokenType tok = c->tok; - if (tok == TOKEN_CT_ELSE || tok == TOKEN_CT_ELIF || tok == TOKEN_CT_ENDIF) break; + if (tok == TOKEN_CT_ELSE || tok == TOKEN_CT_ENDIF) break; ASSIGN_AST_OR_RET(Ast *stmt, parse_stmt(c), false); ast_append(&next, stmt); } return true; } -/** - * ct_else_stmt - * : CT_ELSE ':' ct_compound_stmt - */ -static inline Ast* parse_ct_else_stmt(ParseContext *c) -{ - Ast *ast = new_ast(AST_CT_ELSE_STMT, c->span); - advance_and_verify(c, TOKEN_CT_ELSE); - consume_deprecated_symbol(c, TOKEN_COLON); - if (!parse_ct_compound_stmt(c, &ast->ct_else_stmt)) return poisoned_ast; - return ast; -} - - /** * ct_if_stmt - * : CT_IF '(' expression ')' ':' ct_compound_stmt (ct_elif_stmt | ct_else_stmt) CT_ENDIF EOS + * : CT_IF '(' expression ')' ct_compound_stmt (ct_elif_stmt | ct_else_stmt) CT_ENDIF EOS * ; */ -static inline Ast* parse_ct_if_stmt(ParseContext *c, bool is_elif) +static inline Ast *parse_ct_if_stmt(ParseContext *c) { Ast *ast = ast_new_curr(c, AST_CT_IF_STMT); - if (is_elif) sema_warning_at(c->span, "$elif is deprecated, use $switch instead."); - advance_and_verify(c, is_elif ? TOKEN_CT_ELIF : TOKEN_CT_IF); + advance_and_verify(c, TOKEN_CT_IF); ASSIGN_EXPR_OR_RET(ast->ct_if_stmt.expr, parse_const_paren_expr(c), poisoned_ast); - consume_deprecated_symbol(c, TOKEN_COLON); if (!parse_ct_compound_stmt(c, &ast->ct_if_stmt.then)) return poisoned_ast; - if (tok_is(c, TOKEN_CT_ELIF)) + if (tok_is(c, TOKEN_CT_ELSE)) { - ASSIGN_ASTID_OR_RET(ast->ct_if_stmt.elif, parse_ct_if_stmt(c, true), poisoned_ast); + Ast *else_ast = new_ast(AST_CT_ELSE_STMT, c->span); + advance_and_verify(c, TOKEN_CT_ELSE); + if (!parse_ct_compound_stmt(c, &else_ast->ct_else_stmt)) return poisoned_ast; + ast->ct_if_stmt.elif = astid(else_ast); } - else if (tok_is(c, TOKEN_CT_ELSE)) - { - ASSIGN_ASTID_OR_RET(ast->ct_if_stmt.elif, parse_ct_else_stmt(c), poisoned_ast); - } - if (is_elif) return ast; advance_and_verify(c, TOKEN_CT_ENDIF); RANGE_EXTEND_PREV(ast); - consume_deprecated_symbol(c, TOKEN_EOS); return ast; } @@ -958,7 +931,7 @@ static inline Ast* parse_ct_if_stmt(ParseContext *c, bool is_elif) * | RETURN * ; */ -static inline Ast *parse_return(ParseContext *c) +static inline Ast *parse_return_stmt(ParseContext *c) { advance_and_verify(c, TOKEN_RETURN); Ast *ast = ast_new_curr(c, AST_RETURN_STMT); @@ -966,6 +939,7 @@ static inline Ast *parse_return(ParseContext *c) { ASSIGN_EXPR_OR_RET(ast->return_stmt.expr, parse_expr(c), poisoned_ast); } + CONSUME_EOS_OR_RET(poisoned_ast); return ast; } @@ -976,11 +950,7 @@ static inline Ast *parse_return(ParseContext *c) /** - * ct_foreach_stmt - * | CT_FOREACH '(' CT_IDENT (',' CT_IDENT)? ':' expr ')' ':' statement* CT_ENDFOREACH EOS - * ; - * - * @return + * ct_foreach_stmt ::= CT_FOREACH '(' CT_IDENT (',' CT_IDENT)? ':' expr ')' statement* CT_ENDFOREACH */ static inline Ast* parse_ct_foreach_stmt(ParseContext *c) { @@ -1000,7 +970,6 @@ static inline Ast* parse_ct_foreach_stmt(ParseContext *c) TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected ':'.", poisoned_ast); ASSIGN_EXPRID_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); - consume_deprecated_symbol(c, TOKEN_COLON); Ast *body = new_ast(AST_COMPOUND_STMT, ast->span); ast->ct_foreach_stmt.body = astid(body); AstId *current = &body->compound_stmt.first_stmt; @@ -1010,7 +979,6 @@ static inline Ast* parse_ct_foreach_stmt(ParseContext *c) *current = astid(stmt); current = &stmt->next; } - consume_deprecated_symbol(c, TOKEN_EOS); return ast; } @@ -1042,8 +1010,6 @@ static inline Ast* parse_ct_for_stmt(ParseContext *c) CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); - consume_deprecated_symbol(c, TOKEN_COLON); - Ast *body = new_ast(AST_COMPOUND_STMT, ast->span); ast->for_stmt.body = astid(body); AstId *current = &body->compound_stmt.first_stmt; @@ -1053,33 +1019,23 @@ static inline Ast* parse_ct_for_stmt(ParseContext *c) *current = astid(stmt); current = &stmt->next; } - consume_deprecated_symbol(c, TOKEN_EOS); return ast; } /** - * CTSWITCH '(' expression ')' ':' '{' ct_switch_body '}' + * ct_switch_stmt ::= CT_SWITCH const_paren_expr? ct_case_statement* CT_ENDSWITCH * - * ct_switch_body - * : ct_case_statement - * | ct_switch_body ct_case_statement - * ; - * - * ct_case_statement - * : CTCASE type_list ':' statement - * | CTDEFAULT ':' statement - * ; - * - * @return + * ct_case_statement ::= (CT_CASE constant_expr | CT_DEFAULT) ':' opt_stmt_list */ static inline Ast* parse_ct_switch_stmt(ParseContext *c) { Ast *ast = ast_new_curr(c, AST_CT_SWITCH_STMT); advance_and_verify(c, TOKEN_CT_SWITCH); - if (!tok_is(c, TOKEN_CT_CASE) && !tok_is(c, TOKEN_CT_DEFAULT) && !tok_is(c, TOKEN_CT_ENDSWITCH)) + + // Is it a paren expr? + if (tok_is(c, TOKEN_LPAREN)) { ASSIGN_EXPRID_OR_RET(ast->ct_switch_stmt.cond, parse_const_paren_expr(c), poisoned_ast); - consume_deprecated_symbol(c, TOKEN_COLON); } Ast **cases = NULL; @@ -1102,11 +1058,13 @@ static inline Ast* parse_ct_switch_stmt(ParseContext *c) } vec_add(cases, result); } - consume_deprecated_symbol(c, TOKEN_EOS); ast->ct_switch_stmt.body = cases; return ast; } +/** + * assert_stmt ::= ASSERT '(' assert_expr (',' expr)? ')' ';' + */ static inline Ast *parse_assert_stmt(ParseContext *c) { Ast *ast = ast_new_curr(c, AST_ASSERT_STMT); @@ -1204,16 +1162,8 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_STATIC: // Static means declaration! case TOKEN_CONST: // Const means declaration! return parse_declaration_stmt(c); - case TOKEN_AT_TYPE_IDENT: - case TOKEN_AT_CONST_IDENT: - case TOKEN_AT: - case TOKEN_AT_IDENT: - return parse_expr_stmt(c); case TOKEN_RETURN: - { - ASSIGN_AST_OR_RET(Ast *ast, parse_return(c), poisoned_ast); - RETURN_AFTER_EOS(ast); - } + return parse_return_stmt(c); case TOKEN_IF: return parse_if_stmt(c); case TOKEN_WHILE: @@ -1230,24 +1180,15 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_FOREACH_R: return parse_foreach_stmt(c); case TOKEN_CONTINUE: - { - ASSIGN_AST_OR_RET(Ast *ast, parse_continue(c), poisoned_ast); - RETURN_AFTER_EOS(ast); - } + return parse_continue_stmt(c); case TOKEN_CASE: SEMA_ERROR_HERE("'case' was found outside of 'switch', did you mismatch a '{ }' pair?"); advance(c); return poisoned_ast; case TOKEN_BREAK: - { - ASSIGN_AST_OR_RET(Ast *ast, parse_break(c), poisoned_ast); - RETURN_AFTER_EOS(ast); - } + return parse_break_stmt(c); case TOKEN_NEXTCASE: - { - ASSIGN_AST_OR_RET(Ast *ast, parse_next(c), poisoned_ast); - RETURN_AFTER_EOS(ast); - } + return parse_nextcase_stmt(c); case TOKEN_ASM: return parse_asm_block_stmt(c); case TOKEN_DEFAULT: @@ -1259,7 +1200,7 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_CT_ASSERT: return parse_ct_assert_stmt(c); case TOKEN_CT_IF: - return parse_ct_if_stmt(c, false); + return parse_ct_if_stmt(c); case TOKEN_CT_SWITCH: return parse_ct_switch_stmt(c); case TOKEN_CT_FOREACH: @@ -1298,8 +1239,6 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_CT_CHECKS: case TOKEN_CT_STRINGIFY: case TOKEN_CT_EVAL: - case TOKEN_TRY_QUESTION: - case TOKEN_CATCH_QUESTION: case TOKEN_BYTES: case TOKEN_BUILTIN: case TOKEN_CT_VACOUNT: @@ -1307,6 +1246,10 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_CT_VAEXPR: case TOKEN_CT_VACONST: case TOKEN_CT_VAREF: + case TOKEN_AT_TYPE_IDENT: + case TOKEN_AT_CONST_IDENT: + case TOKEN_AT: + case TOKEN_AT_IDENT: return parse_expr_stmt(c); case TOKEN_ASSERT: return parse_assert_stmt(c); @@ -1348,7 +1291,6 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_SHR_ASSIGN: case TOKEN_SHL_ASSIGN: case TOKEN_ALIAS: - case TOKEN_AS: case TOKEN_ELSE: case TOKEN_QUESTQUEST: case TOKEN_ENUM: @@ -1366,7 +1308,6 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_DOCS_END: case TOKEN_DOC_COMMENT: case TOKEN_CT_CASE: - case TOKEN_CT_ELIF: case TOKEN_CT_ELSE: case TOKEN_CT_DEFAULT: case TOKEN_CT_ENDIF: @@ -1374,7 +1315,6 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_RBRAPIPE: case TOKEN_BANGBANG: case TOKEN_UNDERSCORE: - case TOKEN_PRIVATE: case TOKEN_BITSTRUCT: case TOKEN_LVEC: case TOKEN_RVEC: @@ -1411,23 +1351,6 @@ Ast *parse_stmt(ParseContext *c) UNREACHABLE } -Ast *parse_jump_stmt_no_eos(ParseContext *c) -{ - switch (c->tok) - { - case TOKEN_NEXTCASE: - return parse_next(c); - case TOKEN_RETURN: - return parse_return(c); - case TOKEN_BREAK: - return parse_break(c); - case TOKEN_CONTINUE: - return parse_continue(c); - default: - UNREACHABLE - } -} - /** * compound_stmt diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 766d037ab..677107e02 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -37,7 +37,8 @@ TypeInfo *parse_type(ParseContext *c); TypeInfo *parse_optional_type(ParseContext *c); TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info); Expr* parse_constant_expr(ParseContext *c); -Decl *parse_local_decl(ParseContext *c); + +Decl *parse_const_declaration(ParseContext *c, bool is_global); Expr *parse_integer(ParseContext *c, Expr *left); Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref); void recover_top_level(ParseContext *c); @@ -45,7 +46,6 @@ Expr *parse_cond(ParseContext *c); Expr *parse_assert_expr(ParseContext *c); Ast* parse_compound_stmt(ParseContext *c); Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos); -Ast *parse_jump_stmt_no_eos(ParseContext *c); bool parse_attribute(ParseContext *c, Attr **attribute_ref); bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref); @@ -54,11 +54,13 @@ Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl); Expr *parse_expression_list(ParseContext *c, bool allow_decls); Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type); Decl *parse_var_decl(ParseContext *c); +bool parse_current_is_expr(ParseContext *c); bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, Variadic *variadic, int *vararg_index_ref, ParameterParseKind parse_kind); -bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat); +bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat, + bool allow_trailing_comma); Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info); INLINE void add_decl_to_list(Decl ***list, Decl *decl) @@ -79,7 +81,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); -void consume_deprecated_symbol(ParseContext *c, TokenType type); INLINE const char *symstr(ParseContext *c) { diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 3606acd5f..7286581ce 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. +// Copyright (c) 2022-2023 Christoffer Lerno. All rights reserved. // Use of this source code is governed by a LGPLv3.0 // a copy of which can be found in the LICENSE file. #include "sema_internal.h" @@ -24,11 +24,19 @@ typedef enum static bool sema_check_builtin_args_match(Expr **args, size_t arg_len); static bool sema_check_builtin_args_const(Expr **args, size_t arg_len); static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t arg_len); +static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr); +static bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, bool swizzle_two); static inline int builtin_expected_args(BuiltinFunction func); +static inline bool is_valid_atomicity(Expr* expr); +/** + * Used for when we have a builtin that has a constraint between argument types that + * they should be the same. + */ static bool sema_check_builtin_args_match(Expr **args, size_t arg_len) { + assert(arg_len > 1); Type *first = type_no_optional(args[0]->type->canonical); for (size_t i = 1; i < arg_len; i++) { @@ -41,15 +49,14 @@ static bool sema_check_builtin_args_match(Expr **args, size_t arg_len) return true; } +/** + * Check the constraint that the arguments are constant. + */ static bool sema_check_builtin_args_const(Expr **args, size_t arg_len) { for (size_t i = 0; i < arg_len; i++) { - if (!expr_is_const(args[i])) - { - SEMA_ERROR(args[i], "Expected a compile time constant value for this argument."); - return false; - } + if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "Expected a compile time constant value for this argument."); } return true; } @@ -58,144 +65,82 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar { for (size_t i = 0; i < arg_len; i++) { - Type *type = type_flatten(args[i]->type->canonical); + Expr *arg = args[i]; + Type *type = type_flatten(arg->type->canonical); switch (arg_type[i]) { case BA_POINTER: - if (!type_is_pointer(type)) - { - SEMA_ERROR(args[i], "Expected a pointer."); - return false; - } - break; + if (type_is_pointer(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected a pointer."); case BA_CHAR: - if (type != type_char && type != type_ichar) - { - SEMA_ERROR(args[i], "Expected a char or ichar."); - return false; - } - break; + if (type == type_char || type == type_ichar) continue; + RETURN_SEMA_ERROR(arg, "Expected a char or ichar."); case BA_SIZE: - if (!type_is_integer(type) || type_size(type) != type_size(type_usz)) - { - SEMA_ERROR(args[i], "Expected an usz or isz value."); - return false; - } - break; + if (type_is_integer(type) && type_size(type) == type_size(type_usz)) continue; + RETURN_SEMA_ERROR(arg, "Expected an usz or isz value."); case BA_BOOL: - if (type != type_bool) - { - SEMA_ERROR(args[i], "Expected a bool."); - return false; - } - break; + if (type == type_bool) continue; + RETURN_SEMA_ERROR(arg, "Expected a bool."); case BA_NUMLIKE: - if (!type_flat_is_numlike(type)) - { - SEMA_ERROR(args[i], "Expected a number or vector."); - return false; - } - break; + if (type_flat_is_numlike(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected a number or vector."); case BA_FLOATLIKE: - if (!type_flat_is_floatlike(type)) - { - SEMA_ERROR(args[i], "Expected a floating point or floating point vector, but was %s.", + if (type_flat_is_floatlike(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected a floating point or floating point vector, but was %s.", type_quoted_error_string(type)); - return false; - } - break; case BA_VEC: - if (type->type_kind != TYPE_VECTOR) - { - SEMA_ERROR(args[i], "Expected a vector."); - return false; - } - break; + if (type->type_kind == TYPE_VECTOR) continue; + RETURN_SEMA_ERROR(arg, "Expected a vector."); case BA_INTVEC: - - if (type->type_kind != TYPE_VECTOR || !type_flat_is_intlike(type->array.base)) - { - SEMA_ERROR(args[i], "Expected an integer vector."); - return false; - } - break; + if (type->type_kind == TYPE_VECTOR && type_flat_is_intlike(type->array.base)) continue; + RETURN_SEMA_ERROR(arg, "Expected an integer vector."); case BA_BOOLINT: - if (!type_is_integer_or_bool_kind(type)) - { - SEMA_ERROR(args[i], "Expected a boolean or integer value."); - return false; - } - break; + if (type_is_integer_or_bool_kind(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected a boolean or integer value."); case BA_BOOLINTVEC: - - if (type->type_kind != TYPE_VECTOR || !type_flat_is_boolintlike(type->array.base)) - { - SEMA_ERROR(args[i], "Expected a boolean or integer vector."); - return false; - } - break; + if (type->type_kind == TYPE_VECTOR && type_flat_is_boolintlike(type->array.base)) continue; + RETURN_SEMA_ERROR(arg, "Expected a boolean or integer vector."); case BA_FLOATVEC: - if (type->type_kind != TYPE_VECTOR || !type_flat_is_floatlike(type->array.base)) - { - SEMA_ERROR(args[i], "Expected an float vector."); - return false; - } - break; + if (type->type_kind == TYPE_VECTOR && type_flat_is_floatlike(type->array.base)) continue; + RETURN_SEMA_ERROR(arg, "Expected an float vector."); case BA_INTLIKE: - if (!type_flat_is_intlike(type)) - { - SEMA_ERROR(args[i], "Expected an integer or integer vector."); - return false; - } - break; + if (type_flat_is_intlike(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected an integer or integer vector."); case BA_INTEGER: - if (!type_is_integer(type)) - { - SEMA_ERROR(args[i], "Expected an integer."); - return false; - } - break; + if (type_is_integer(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected an integer."); case BA_FLOAT: - if (!type_is_float(type)) - { - SEMA_ERROR(args[i], "Expected a float or double."); - return false; - } - break; + if (type_is_float(type)) continue; + RETURN_SEMA_ERROR(arg, "Expected a float or double."); } + UNREACHABLE } return true; } +/** + * Analyse both $$swizzle and $$swizzle2 + */ static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, bool swizzle_two) { Expr **args = expr->call_expr.arguments; unsigned arg_count = vec_size(args); bool optional = false; int first_mask_value = swizzle_two ? 2 : 1; - Type *first = NULL; for (unsigned i = 0; i < first_mask_value; i++) { Expr *arg = args[i]; + // Analyse the expressions if (!sema_analyse_expr(context, arg)) return false; - if (!type_flat_is_vector(arg->type)) - { - SEMA_ERROR(arg, "A vector was expected here."); - return false; - } + // Expect vector + if (!type_flat_is_vector(arg->type)) RETURN_SEMA_ERROR(arg, "A vector was expected here."); + // Optional-ness updated optional = optional || type_is_optional(args[i]->type); - if (i == 0) - { - first = type_no_optional(arg->type)->canonical; - continue; - } - else if (type_no_optional(arg->type->canonical) != first) - { - SEMA_ERROR(arg, "Vector type does not match the first vector."); - return false; - } } - unsigned components = type_flatten(first)->array.len; + // Ensure matching types + if (swizzle_two && !sema_check_builtin_args_match(args, 2)) return false; + + unsigned components = type_flatten(args[0]->type)->array.len; if (swizzle_two) components *= 2; for (unsigned i = first_mask_value; i < arg_count; i++) { @@ -203,48 +148,38 @@ static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, b if (!sema_analyse_expr_rhs(context, type_int, mask_val, false)) return false; if (!expr_is_const_int(mask_val)) { - SEMA_ERROR(mask_val, "The swizzle positions must be compile time constants."); - return false; + RETURN_SEMA_ERROR(mask_val, "The swizzle positions must be compile time constants."); } if (mask_val->const_expr.ixx.i.low >= components) { - if (components == 1) - { - SEMA_ERROR(mask_val, "The only possible swizzle position is 0."); - return false; - } - SEMA_ERROR(mask_val, "The swizzle position must be in the range 0-%d.", components - 1); - return false; + if (components == 1) RETURN_SEMA_ERROR(mask_val, "The only possible swizzle position is 0."); + RETURN_SEMA_ERROR(mask_val, "The swizzle position must be in the range 0-%d.", components - 1); } } expr->type = type_add_optional(type_get_vector(type_get_indexed_type(args[0]->type), arg_count - first_mask_value), optional); return true; } -bool is_valid_atomicity(Expr* expr) +static inline bool is_valid_atomicity(Expr* expr) { if (!expr_is_const_int(expr) || !int_fits(expr->const_expr.ixx, TYPE_U8) || expr->const_expr.ixx.i.low > 6) { - SEMA_ERROR(expr, "Expected a constant integer value < 8."); - return false; + RETURN_SEMA_ERROR(expr, "Expected a constant integer value < 8."); } return true; } -bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr) +static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr) { Expr **args = expr->call_expr.arguments; Expr *pointer = args[0]; if (!sema_analyse_expr(context, pointer)) return false; - bool optional = IS_OPTIONAL(args[0]); - Type *comp_type = type_flatten(args[0]->type); - if (!type_is_pointer(comp_type)) - { - SEMA_ERROR(args[0], "Expected a pointer here."); - return false; - } + bool optional = IS_OPTIONAL(pointer); + Type *comp_type = type_flatten(pointer->type); + if (!type_is_pointer(comp_type)) RETURN_SEMA_ERROR(pointer, "Expected a pointer here."); + Type *pointee = comp_type->pointer; for (int i = 1; i < 3; i++) { @@ -271,19 +206,19 @@ bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr) || !int_fits(align->const_expr.ixx, TYPE_U64) || (!is_power_of_two(align->const_expr.ixx.i.low) && align->const_expr.ixx.i.low)) { - SEMA_ERROR(args[7], "Expected a constant power-of-two alignment or zero."); - return false; + RETURN_SEMA_ERROR(args[7], "Expected a constant power-of-two alignment or zero."); } expr->type = type_add_optional(args[1]->type, optional); return true; } -bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr) + +static bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr) { Expr **args = expr->call_expr.arguments; unsigned arg_count = vec_size(args); if (arg_count > 7) { - SEMA_ERROR(args[7], "Only 7 arguments supported for $$syscall."); + RETURN_SEMA_ERROR(args[7], "Only 7 arguments supported for $$syscall."); } bool optional = false; for (unsigned i = 0; i < arg_count; i++) @@ -300,8 +235,7 @@ bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr) case ARCH_TYPE_X86_64: break; default: - SEMA_ERROR(expr, "Target does not support $$syscall."); - return false; + RETURN_SEMA_ERROR(expr, "Target does not support $$syscall."); } expr->type = type_add_optional(type_uptr, optional); return true; @@ -328,16 +262,10 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { if (arg_count == 0) { - SEMA_ERROR(expr, "Expected %s%d arguments to builtin.", expect_vararg ? "at least " : "", expected_args); - return false; + RETURN_SEMA_ERROR(expr, "Expected %s%d arguments to builtin.", expect_vararg ? "at least " : "", expected_args); } - if (arg_count < expected_args) - { - SEMA_ERROR(args[arg_count - 1], "Expected more arguments after this one."); - return false; - } - SEMA_ERROR(args[expected_args], "Too many arguments."); - return false; + if (arg_count < expected_args) RETURN_SEMA_ERROR(args[arg_count - 1], "Expected more arguments after this one."); + RETURN_SEMA_ERROR(args[expected_args], "Too many arguments."); } switch (func) @@ -381,9 +309,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) switch (func) { case BUILTIN_SET_ROUNDING_MODE: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTEGER }, - arg_count)) return false; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTEGER }, 1)) return false; if (!sema_check_builtin_args_match(args, 1)) return false; rtype = type_void; break; @@ -394,58 +321,57 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_VECCOMPGT: case BUILTIN_VECCOMPLT: case BUILTIN_VECCOMPNE: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_VEC, BA_VEC }, - arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC, BA_VEC }, 2)) return false; if (!sema_check_builtin_args_match(args, 2)) return false; rtype = type_get_vector(type_bool, type_flatten(args[0]->type)->array.len); break; case BUILTIN_OVERFLOW_ADD: case BUILTIN_OVERFLOW_MUL: case BUILTIN_OVERFLOW_SUB: - { + assert(arg_count == 3); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTEGER, BA_INTEGER, BA_POINTER }, - arg_count)) return false; + 3)) return false; if (!sema_check_builtin_args_match(args, 2)) return false; if (type_no_optional(args[0]->type->canonical) != type_no_optional(args[2]->type->canonical->pointer)) { - SEMA_ERROR(args[2], "Expected %s, not %s.", type_to_error_string(type_get_ptr(args[0]->type)), - type_to_error_string(args[2]->type)); - return false; + RETURN_SEMA_ERROR(args[2], "Expected %s, not %s.", + type_to_error_string(type_get_ptr(args[0]->type)), + type_to_error_string(args[2]->type)); } rtype = type_bool; break; - } case BUILTIN_EXACT_ADD: case BUILTIN_EXACT_DIV: case BUILTIN_EXACT_MUL: case BUILTIN_EXACT_SUB: case BUILTIN_EXACT_MOD: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTEGER, BA_INTEGER }, - arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTEGER, BA_INTEGER }, 2)) return false; + if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type->canonical; break; case BUILTIN_EXACT_NEG: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE }, arg_count)) return false; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE }, 1)) return false; rtype = args[0]->type->canonical; break; case BUILTIN_MEMCOPY: case BUILTIN_MEMCOPY_INLINE: case BUILTIN_MEMMOVE: + assert(arg_count == 6); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER, BA_POINTER, BA_SIZE, BA_BOOL, BA_SIZE, BA_SIZE }, - arg_count)) return false; + 6)) return false; if (!sema_check_builtin_args_const(&args[3], 3)) return false; rtype = type_void; break; case BUILTIN_MEMSET: case BUILTIN_MEMSET_INLINE: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_POINTER, BA_CHAR, BA_SIZE, BA_BOOL, BA_SIZE }, - arg_count)) return false; + assert(arg_count == 5); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER, BA_CHAR, BA_SIZE, BA_BOOL, BA_SIZE }, + 5)) return false; if (!sema_check_builtin_args_const(&args[3], 2)) return false; rtype = type_void; break; @@ -454,49 +380,44 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_CTLZ: case BUILTIN_POPCOUNT: case BUILTIN_CTTZ: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTLIKE }, - arg_count)) return false; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE }, 1)) return false; rtype = args[0]->type; break; case BUILTIN_SAT_SHL: case BUILTIN_SAT_SUB: case BUILTIN_SAT_ADD: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE }, - arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE }, 2)) return false; if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type; break; case BUILTIN_REVERSE: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC }, arg_count)) return false; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC }, 1)) return false; rtype = args[0]->type; break; case BUILTIN_EXPECT: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINT, BA_BOOLINT }, arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINT, BA_BOOLINT }, 2)) return false; + if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type; break; case BUILTIN_EXPECT_WITH_PROBABILITY: + assert(arg_count == 3); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINT, BA_BOOLINT }, 2)) return false; if (!cast_implicit(context, args[2], type_double)) { - SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type)); - return false; + RETURN_SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type)); } if (!expr_is_const(args[2])) { - SEMA_ERROR(args[2], "This value must be a constant."); - return false; + RETURN_SEMA_ERROR(args[2], "This value must be a constant."); } else { Real r = args[2]->const_expr.fxx.f; - if (r < 0 || r > 1) - { - SEMA_ERROR(args[2], "The probability must be between 0 and 1."); - return false; - } + if (r < 0 || r > 1) RETURN_SEMA_ERROR(args[2], "The probability must be between 0 and 1."); } if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type; @@ -521,29 +442,28 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_SIN: case BUILTIN_SQRT: case BUILTIN_TRUNC: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE, BA_FLOATLIKE }, + assert(arg_count); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE, BA_FLOATLIKE }, arg_count)) return false; rtype = args[0]->type; break; case BUILTIN_WASM_MEMORY_SIZE: + assert(arg_count == 1); if (!cast_implicit(context, args[0], type_uint)) return false; rtype = type_uptr; break; case BUILTIN_WASM_MEMORY_GROW: + assert(arg_count == 2); if (!cast_implicit(context, args[0], type_uint)) return false; if (!cast_implicit(context, args[1], type_uptr)) return false; rtype = type_iptr; break; case BUILTIN_PREFETCH: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER, BA_INTEGER, BA_INTEGER }, arg_count)) return false; + assert(arg_count == 3); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER, BA_INTEGER, BA_INTEGER }, 3)) return false; for (unsigned i = 1; i < 3; i++) { - if (!expr_is_const(args[i])) - { - SEMA_ERROR(args[i], "A constant value is required."); - return false; - } + if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "A constant value is required."); if (!cast_implicit(context, args[i], type_int)) return false; } if (!expr_in_int_range(args[1], 0, 1)) @@ -560,24 +480,21 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) rtype = type_void; break; case BUILTIN_POW: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE }, - arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE }, 2)) return false; + if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type; break; case BUILTIN_POW_INT: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOATLIKE, BA_INTLIKE }, - arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATLIKE, BA_INTLIKE }, 2)) return false; if (!cast_implicit(context, args[1], type_cint)) return false; rtype = args[0]->type; break; case BUILTIN_REDUCE_FMUL: case BUILTIN_REDUCE_FADD: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOATVEC, BA_FLOAT }, - arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATVEC, BA_FLOAT }, 2)) return false; if (!cast_implicit(context, args[1], args[0]->type->canonical->array.base)) return false; { Expr *arg = args[0]; @@ -588,98 +505,84 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) break; case BUILTIN_REDUCE_MAX: case BUILTIN_REDUCE_MIN: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_VEC }, - arg_count)) return false; - rtype = args[0]->type->canonical->array.base; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC }, 1)) return false; + rtype = type_get_indexed_type(args[0]->type); break; case BUILTIN_REDUCE_ADD: case BUILTIN_REDUCE_AND: case BUILTIN_REDUCE_OR: case BUILTIN_REDUCE_XOR: case BUILTIN_REDUCE_MUL: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_BOOLINTVEC }, - arg_count)) return false; - rtype = args[0]->type->canonical->array.base; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINTVEC }, 1)) return false; + rtype = type_get_indexed_type(args[0]->type); break; case BUILTIN_ABS: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_NUMLIKE }, arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 1); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_NUMLIKE }, 1)) return false; rtype = args[0]->type; break; case BUILTIN_MAX: case BUILTIN_MIN: - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_NUMLIKE, BA_NUMLIKE }, arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 2); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_NUMLIKE, BA_NUMLIKE }, 2)) return false; + if (!sema_check_builtin_args_match(args, 2)) return false; rtype = args[0]->type; break; case BUILTIN_FMA: + assert(arg_count == 3); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE, BA_FLOATLIKE }, - arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + 3)) return false; + if (!sema_check_builtin_args_match(args, 3)) return false; rtype = args[0]->type; break; case BUILTIN_FSHL: case BUILTIN_FSHR: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE, BA_INTLIKE }, - arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 3); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE, BA_INTLIKE }, + 3)) return false; + if (!sema_check_builtin_args_match(args, 3)) return false; rtype = args[0]->type; break; case BUILTIN_FMULADD: - if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_FLOAT, BA_FLOAT, BA_FLOAT }, - arg_count)) return false; - if (!sema_check_builtin_args_match(args, arg_count)) return false; + assert(arg_count == 3); + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOAT, BA_FLOAT, BA_FLOAT }, + 3)) return false; + if (!sema_check_builtin_args_match(args, 3)) return false; rtype = args[0]->type; break; case BUILTIN_ATOMIC_LOAD: { + assert(arg_count == 3); if (!sema_check_builtin_args(args, (BuiltinArg[]){ BA_POINTER, BA_BOOL, BA_INTEGER }, 3)) return false; Type *original = type_flatten(args[0]->type); - if (original == type_voidptr) - { - SEMA_ERROR(args[0], "Expected a typed pointer."); - return false; - } - if (!expr_is_const(args[1])) - { - SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant."); - return false; - } - if (!expr_is_const(args[2])) - { - SEMA_ERROR(args[2], "Ordering must be a compile time constant."); - return false; - } + if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer."); + if (!expr_is_const(args[1])) RETURN_SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant."); + if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "Ordering must be a compile time constant."); if (!is_valid_atomicity(args[2])) return false; switch (expr->const_expr.ixx.i.low) { case ATOMIC_ACQUIRE_RELEASE: case ATOMIC_RELEASE: - SEMA_ERROR(args[2], "'release' and 'acquire release' are not valid for atomic loads."); - return false; + RETURN_SEMA_ERROR(args[2], "'release' and 'acquire release' are not valid for atomic loads."); } rtype = original->pointer; break; } case BUILTIN_VOLATILE_LOAD: { + assert(arg_count == 1); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER }, 1)) return false; Type *original = type_flatten(args[0]->type); - if (original == type_voidptr) - { - SEMA_ERROR(args[0], "Expected a typed pointer."); - return false; - } + if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer."); rtype = original->pointer; break; } case BUILTIN_VOLATILE_STORE: { + assert(arg_count == 2); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER }, 1)) return false; Type *original = type_flatten(args[0]->type); if (original != type_voidptr) @@ -691,6 +594,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) } case BUILTIN_ATOMIC_STORE: { + assert(arg_count == 4); if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER }, 1)) return false; if (!sema_check_builtin_args(&args[2], (BuiltinArg[]) { BA_BOOL, BA_INTEGER }, 2)) return false; Type *original = type_flatten(args[0]->type); @@ -698,23 +602,14 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { if (!cast_implicit(context, args[1], original->pointer)) return false; } - if (!expr_is_const(args[2])) - { - SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - return false; - } - if (!expr_is_const(args[3])) - { - SEMA_ERROR(args[3], "Ordering must be a compile time constant."); - return false; - } + if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(args[3])) return false; switch (expr->const_expr.ixx.i.low) { case ATOMIC_ACQUIRE_RELEASE: case ATOMIC_ACQUIRE: - SEMA_ERROR(args[2], "'acquire' and 'acquire release' are not valid for atomic stores."); - return false; + RETURN_SEMA_ERROR(args[2], "'acquire' and 'acquire release' are not valid for atomic stores."); } rtype = args[1]->type; break; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index e4a32a0d3..4903282a8 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -145,7 +145,7 @@ Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type) */ INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) { - if (expr->expr_kind == EXPR_CONST) return false; + if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind != CONST_TYPEID) return false; return insert_cast(expr, kind, type); } @@ -228,16 +228,12 @@ static bool bool_to_float(Expr *expr, Type *canonical, Type *type) } /** - * Insert a cast from `void!` to some fault type by inserting a `catch`, - * so "anyerr a = returns_voidfail()" => "anyerr a = catch? returns_voidfail()" + * Insert a cast from `void!` to some fault type */ static bool voidfail_to_error(Expr *expr, Type *type) { - assert(type->canonical->type_kind == TYPE_FAULTTYPE || type == type_anyerr); - Expr *inner = expr_copy(expr); - expr->expr_kind = EXPR_CATCH; - expr->inner_expr = inner; - expr->type = type; + assert(type->canonical->type_kind == TYPE_FAULTTYPE || type == type_anyfault); + insert_cast(expr, CAST_VOIDFERR, type); return true; } @@ -311,6 +307,7 @@ static bool integer_to_enum(Expr *expr, Type *canonical, Type *type) assert(canonical->type_kind == TYPE_ENUM); Decl *enum_decl = canonical->decl; + assert(type_flatten(type)->type_kind == TYPE_ENUM); if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return true; // Check that the type is within limits. @@ -446,6 +443,11 @@ static void enum_to_int_lowering(Expr* expr) expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); } + if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_INTENUM) + { + *expr = *exprptr(expr->cast_expr.expr); + return; + } expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); } @@ -667,9 +669,10 @@ CastKind cast_to_bool_kind(Type *type) { switch (type_flatten(type)->type_kind) { + case TYPE_WILDCARD: case TYPE_BOOL: return CAST_BOOLBOOL; - case TYPE_ANYERR: + case TYPE_ANYFAULT: return CAST_EUBOOL; case TYPE_SUBARRAY: return CAST_SABOOL; @@ -684,7 +687,6 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_TYPEDEF: case TYPE_DISTINCT: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_ENUM: // These are not possible due to flattening. UNREACHABLE @@ -705,7 +707,6 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_UNTYPED_LIST: case TYPE_ANY: case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: case TYPE_MEMBER: // Everything else is an error return CAST_ERROR; @@ -784,6 +785,7 @@ RETRY: if (type_size(type) < type_size(type_cint)) return expr; return NULL; case ACCESS_PTR: + case ACCESS_TYPEOFANYFAULT: case ACCESS_TYPEOFANY: case ACCESS_ENUMNAME: case ACCESS_FAULTNAME: @@ -931,7 +933,7 @@ static bool cast_from_subarray(SemaContext *context, Expr *expr, Type *from, Typ /** * Try casting to a pointer. - * 1. Any pointer -> variant, any pointer -> void*, void* -> any pointer - always works. + * 1. Any pointer -> any, any pointer -> void*, void* -> any pointer - always works. * 2. Pointer -> integer must be explicit and type size >= uptr * 3. Pointer -> subarray if the pointer points to a vector or array, allow void*[2]* -> int*[2]* (pointer equivalence). * 4. Pointer -> bool must be explicit (conditionals are treated as a special case. @@ -1005,7 +1007,6 @@ static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type return cast_with_optional(expr, to_type, add_optional); } return sema_error_cannot_convert(expr, to_type, true, silent); - case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: UNREACHABLE default: @@ -1017,7 +1018,7 @@ static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type) { assert(expr->expr_kind == EXPR_CONST); - if (expr->const_expr.is_character) + if (expr->const_expr.is_character && expr->type->type_kind != TYPE_U128) { SEMA_ERROR(problem, "The unicode character U+%04x cannot fit in a %s.", (uint32_t)expr->const_expr.ixx.i.low, type_quoted_error_string(to_type)); return; @@ -1515,12 +1516,14 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo // Step one, cast from optional. // This handles: // 1. *! -> any type - // 2. void! -> anyerr + // 2. void! -> anyfault // 3. void! -> SomeFault (explicit) if (type_is_optional(from_type)) { + Type *opt = from_type->optional; + // *! -> int => ok, gives int! - if (from_type == type_anyfail) + if (opt == type_wildcard) { if (may_not_be_optional) { @@ -1533,14 +1536,11 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo return true; } - // Here we have something like int! - assert(from_type->type_kind == TYPE_OPTIONAL); - // If it is void!, then there are special rules: - if (from_type->optional == type_void) + if (opt == type_void) { - // void! x; anyerr y = x; - if (!type_is_optional(to_type) && to == type_anyerr) + // void! x; anyfault y = x; + if (!type_is_optional(to_type) && to == type_anyfault) { cast(expr, to_type); return true; @@ -1585,7 +1585,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo } // We may already be done. - if (from == to) + if (from == to || from == type_wildcard) { expr->type = type_add_optional(to_type, add_optional); return true; @@ -1611,10 +1611,10 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo return true; case TYPE_FAULTTYPE: // Allow MyError.A -> error, to an integer or to bool - if (to == type_anyerr) return cast(expr, to_type); + if (to == type_anyfault) return cast(expr, to_type); if (type_is_integer(to) || to == type_bool) goto CAST_IF_EXPLICIT; goto CAST_FAILED; - case TYPE_ANYERR: + case TYPE_ANYFAULT: if (to_type == type_bool || to->type_kind == TYPE_FAULTTYPE || type_is_integer(to)) { goto CAST_IF_EXPLICIT; @@ -1629,7 +1629,6 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo if (type_is_integer(to) || type_is_float(to)) goto CAST_IF_EXPLICIT; goto CAST_FAILED; case TYPE_VECTOR: - case TYPE_SCALED_VECTOR: return cast_from_vector(context, expr, from, to, to_type, add_optional, is_explicit, silent); case TYPE_ARRAY: return cast_from_array(context, expr, from, to, to_type, add_optional, is_explicit, silent); @@ -1641,6 +1640,8 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo return cast_from_float(context, expr, from, to, to_type, add_optional, is_explicit, silent); case TYPE_POISONED: return false; + case TYPE_WILDCARD: + UNREACHABLE case TYPE_VOID: case TYPE_INFERRED_ARRAY: case TYPE_TYPEINFO: @@ -1651,9 +1652,8 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo goto CAST_FAILED; case TYPE_TYPEID: if (!type_is_pointer_sized_or_more(to_type)) goto CAST_FAILED; - goto CAST_IF_EXPLICIT; + goto CAST_IF_EXPLICIT; case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_TYPEDEF: UNREACHABLE; case TYPE_ANY: @@ -1771,7 +1771,7 @@ static void vector_const_initializer_convert_to_type(ConstInitializer *initializ } -static bool err_to_anyerr(Expr *expr, Type *to_type) +static bool err_to_anyfault(Expr *expr, Type *to_type) { expr->type = to_type; return true; @@ -1817,7 +1817,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) { switch (from_type->type_kind) { - case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: case TYPE_VOID: UNREACHABLE @@ -1833,11 +1832,11 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (type_is_integer(to)) return bool_to_int(expr, to, to_type); if (type_is_float(to)) return bool_to_float(expr, to, to_type); break; - case TYPE_ANYERR: + case TYPE_ANYFAULT: if (to->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type); if (to->type_kind == TYPE_FAULTTYPE) { - REMINDER("Improve anyerr -> fault conversion."); + REMINDER("Improve anyfault -> fault conversion."); return insert_cast(expr, CAST_EUER, to_type); } if (type_is_integer(to)) return insert_cast(expr, CAST_EUINT, to_type); @@ -1884,12 +1883,11 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type); break; case TYPE_FAULTTYPE: - if (to->type_kind == TYPE_ANYERR) return err_to_anyerr(expr, to_type); + if (to->type_kind == TYPE_ANYFAULT) return err_to_anyfault(expr, to_type); if (to == type_bool) return err_to_bool(expr, to_type); if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type); break; case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: return false; case TYPE_ARRAY: if (to->type_kind == TYPE_VECTOR) return array_to_vector(expr, to_type); @@ -1930,22 +1928,23 @@ bool cast(Expr *expr, Type *to_type) Type *to = type_flatten(to_type); // Special case *! => error - if (to == type_anyerr || to->type_kind == TYPE_FAULTTYPE) + if (to == type_anyfault || to->type_kind == TYPE_FAULTTYPE) { if (type_is_optional(from_type)) return voidfail_to_error(expr, to_type); } - if (type_is_optional_any(from_type)) - { - expr->type = type_get_optional(to_type); - return true; - } - - if (type_is_optional_type(from_type)) + if (type_is_optional(from_type)) { from_type = from_type->optional; from_is_optional = true; } + + if (from_type == type_wildcard) + { + expr->type = type_add_optional(to_type, from_is_optional); + return true; + } + from_type = type_flatten(from_type); if (type_len_is_inferred(to_type)) { diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 9903342f8..bb2322ea5 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -204,11 +204,6 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl ** SEMA_ERROR(member, "Flexible array members not allowed in unions."); return false; } - if (member->type->type_kind == TYPE_SCALED_VECTOR) - { - SEMA_ERROR(member, "Scaled vector members not allowed in unions / structs."); - return false; - } AlignSize member_alignment; if (!sema_set_abi_alignment(context, member->type, &member_alignment)) return false; ByteSize member_size = type_size(member->type); @@ -240,7 +235,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl ** // 1. If packed, then the alignment is zero, unless previously given if (decl->is_packed && !decl->alignment) decl->alignment = 1; - // 2. Otherwise pick the highest of the natural alignment and the given alignment. + // 2. otherwise pick the highest of the natural alignment and the given alignment. if (!decl->is_packed && decl->alignment < max_alignment) decl->alignment = max_alignment; // We're only packed if the max alignment is > 1 @@ -313,11 +308,6 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * } decl->has_variable_array = true; } - if (member_type->type_kind == TYPE_SCALED_VECTOR) - { - SEMA_ERROR(member, "Scaled vectors may not be used in structs and unions."); - return false; - } if (member_type->type_kind == TYPE_INFERRED_ARRAY) { if (i != member_count - 1) @@ -393,7 +383,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * // 1. If packed, use the alignment given, otherwise set to 1. if (decl->is_packed && !decl->alignment) decl->alignment = 1; - // 2. Otherwise pick the highest of the natural alignment and the given alignment. + // 2. otherwise pick the highest of the natural alignment and the given alignment. if (!decl->is_packed && decl->alignment < natural_alignment) decl->alignment = natural_alignment; // We must now possibly add the end padding. @@ -529,7 +519,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec SEMA_ERROR(member, "This element would overflow the bitstruct size (%d bits).", bits); return false; } - goto AFTER_BITCHECK; + goto AFTER_BIT_CHECK; } Expr *start = member->var.start; @@ -606,7 +596,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec member->var.start_bit = start_bit; member->var.end_bit = end_bit; -AFTER_BITCHECK: +AFTER_BIT_CHECK: // Check for duplicate members. for (unsigned i = 0; i < index; i++) { @@ -891,7 +881,7 @@ static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl) } if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false; Type *type = decl->typedef_decl.type_info->type->canonical; - if (type == type_anyerr || type == type_any) + if (type == type_anyfault || type == type_any) { SEMA_ERROR(decl->typedef_decl.type_info, "%s may not be aliased.", type_quoted_error_string(type)); return false; @@ -928,13 +918,12 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl) case TYPE_FLEXIBLE_ARRAY: UNREACHABLE return false; - case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: UNREACHABLE case TYPE_FAULTTYPE: SEMA_ERROR(decl, "You cannot create a distinct type from a fault type."); return false; - case TYPE_ANYERR: + case TYPE_ANYFAULT: SEMA_ERROR(decl, "You cannot create a distinct type from an error union."); return false; case TYPE_ANY: @@ -952,7 +941,6 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl) case TYPE_ARRAY: case TYPE_SUBARRAY: case TYPE_VECTOR: - case TYPE_SCALED_VECTOR: break; } // Do we need anything else? @@ -1396,7 +1384,7 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type vec_add(parent->methods, method_like); break; case VISIBLE_PRIVATE: - if (parent->unit->module == unit->module && parent->visibility >= VISIBLE_PRIVATE) + if (parent->unit && parent->unit->module == unit->module && parent->visibility >= VISIBLE_PRIVATE) { vec_add(parent->methods, method_like); break; @@ -1705,7 +1693,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, decl->section = expr->const_expr.string.chars; break; case ATTRIBUTE_EXTNAME: - sema_warning_at(attr->span, "'@extname' is deprecated, plase use '@extern' instead."); + sema_warning_at(attr->span, "'@extname' is deprecated, please use '@extern' instead."); FALLTHROUGH; case ATTRIBUTE_EXTERN: decl->has_extname = true; @@ -2205,7 +2193,6 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) Type *rtype = rtype_info->type; bool is_int_return = true; bool is_err_return = false; - if (rtype->type_kind == TYPE_OPTIONAL_ANY) is_err_return = true; if (!is_err_return && type_is_optional(rtype)) { if (rtype->optional->type_kind != TYPE_VOID) @@ -2547,10 +2534,10 @@ bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span) break; } if (!type_is_optional(type)) return true; - if (type_is_optional_any(type) || type->optional == type_void) + if (type == type_wildcard_optional || type->optional == type_void) { sema_error_at(span, "The use of 'void!' as a variable type is not permitted, use %s instead.", - type_quoted_error_string(type_anyerr)); + type_quoted_error_string(type_anyfault)); return false; } return true; @@ -2687,6 +2674,11 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) decl->type = init_expr->type; if (type_is_invalid_storage_type(init_expr->type)) { + if (init_expr->type == type_wildcard_optional || init_expr->type == type_wildcard) + { + SEMA_ERROR(init_expr, "No type can be inferred from the optional result."); + return false; + } if (init_expr->type == type_untypedlist) { SEMA_ERROR(init_expr, "The type of an untyped list cannot be inferred, you can try adding an explicit type to solve this."); @@ -3157,7 +3149,9 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) DEBUG_LOG(">>> Analysing %s.", decl->name ? decl->name : ".anon"); if (decl->resolve_status == RESOLVE_RUNNING) { - SEMA_ERROR(decl, "Recursive definition of '%s'.", decl->name ? decl->name : ".anon"); + SEMA_ERROR(decl, decl->name + ? "Recursive definition of '%s'." + : "Recursive definition of anonymous declaration.", decl->name); goto FAILED; } decl->resolve_status = RESOLVE_RUNNING; @@ -3238,6 +3232,7 @@ FAILED: void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan span) { if (!decl->is_deprecated) return; + // Prevent multiple reports decl->is_deprecated = false; FOREACH_BEGIN(Attr *attr, decl->attributes) if (attr->attr_kind == ATTRIBUTE_DEPRECATED) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 313382e35..8caa06dbc 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -44,8 +44,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_unary(SemaContext *context, Expr *expr); -static inline bool sema_expr_analyse_try(SemaContext *context, Expr *expr); -static inline bool sema_expr_analyse_catch(SemaContext *context, Expr *expr); + static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_force_unwrap(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_typeid(SemaContext *context, Expr *expr); @@ -57,7 +56,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_call(SemaContext *context, Expr *expr); -static inline bool sema_expr_analyse_variant(SemaContext *context, Expr *expr); + static inline bool sema_expr_analyse_retval(SemaContext *c, Expr *expr); static inline bool sema_expr_analyse_expr_list(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_ct_checks(SemaContext *context, Expr *expr); @@ -136,7 +135,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, bool *optional, Expr ***varargs_ref, Expr **vararg_splat_ref); -static inline int sema_call_find_index_of_named_parameter(Decl **func_params, Expr *expr); +static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr); static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr); static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *call); @@ -150,11 +149,9 @@ static inline IndexDiff range_const_len(Range *range); static inline bool sema_expr_begin_analyse(Expr *expr); static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr); -static Decl *sema_expr_analyse_var_path(SemaContext *context, Expr *expr, ExprFlatElement **elements); -static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlatElement *element, Type *type, Decl **member_ref, ArraySize *index_ref, Type **return_type, unsigned i, SourceSpan loc, +static Decl *sema_expr_analyse_var_path(SemaContext *context, Expr *expr); +static inline bool sema_expr_analyse_decl_element(SemaContext *context, DesignatorElement *element, Type *type, Decl **member_ref, ArraySize *index_ref, Type **return_type, unsigned i, SourceSpan loc, bool *is_missing); -static Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing); - static Type *sema_expr_check_type_exists(SemaContext *context, TypeInfo *type_info); static inline Expr *sema_ct_checks_exprlist_compiles(SemaContext *context, Expr *exprlist); static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr); @@ -186,7 +183,7 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr); static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr); -static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, TypeInfo *parent, bool was_group, Expr *identifier); +static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier); static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier); static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member); @@ -473,7 +470,6 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_BUILTIN_ACCESS: case EXPR_CALL: case EXPR_CAST: - case EXPR_CATCH: case EXPR_CATCH_UNWRAP: case EXPR_COMPILER_CONST: case EXPR_COMPOUND_LITERAL: @@ -488,7 +484,6 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_DESIGNATOR: case EXPR_EXPR_BLOCK: case EXPR_OPTIONAL: - case EXPR_FLATPATH: case EXPR_FORCE_UNWRAP: case EXPR_INITIALIZER_LIST: case EXPR_MACRO_BLOCK: @@ -503,14 +498,13 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_SLICE_COPY: case EXPR_STRINGIFY: case EXPR_TERNARY: - case EXPR_TRY: case EXPR_TRY_UNWRAP: case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TYPEID: case EXPR_TYPEID_INFO: case EXPR_TYPEINFO: - case EXPR_VARIANT: - case EXPR_VARIANTSWITCH: + case EXPR_ANY: + case EXPR_ANYSWITCH: case EXPR_VASPLAT: case EXPR_TEST_HOOK: goto ERR; @@ -698,18 +692,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) if (left_canonical != right_canonical) { Type *max; - if (left_canonical->type_kind == TYPE_OPTIONAL_ANY) - { - max = right_canonical; - } - else if (right_canonical->type_kind == TYPE_OPTIONAL_ANY) - { - max = left_canonical; - } - else - { - max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical)); - } + max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical)); if (!max) { SEMA_ERROR(expr, "Cannot find a common parent type of '%s' and '%s'", @@ -993,7 +976,7 @@ static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context, } -static inline int sema_call_find_index_of_named_parameter(Decl **func_params, Expr *expr) +static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr) { if (vec_size(expr->designator_expr.path) != 1) { @@ -1006,7 +989,15 @@ static inline int sema_call_find_index_of_named_parameter(Decl **func_params, Ex SEMA_ERROR(expr, "Expected the name of a function parameter here, this looks like an array path field."); return -1; } - const char *name = element->field; + Expr *field = sema_expr_resolve_access_child(context, element->field_expr, NULL); + if (!field) return false; + + if (field->expr_kind != EXPR_IDENTIFIER) + { + SEMA_ERROR(expr, "A name was expected here."); + return -1; + } + const char *name = field->identifier_expr.ident; VECEACH(func_params, i) { if (func_params[i] && func_params[i]->name == name) return (int)i; @@ -1093,7 +1084,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, if (arg->expr_kind == EXPR_DESIGNATOR) { // Find the location of the parameter. - int index = sema_call_find_index_of_named_parameter(params, arg); + int index = sema_call_find_index_of_named_parameter(context, params, arg); // If it's not found then this is an error. if (index < 0) return false; @@ -1465,8 +1456,8 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call if (IS_OPTIONAL(arg)) *optional = true; if (type_is_invalid_storage_type(arg->type)) { - SEMA_ERROR(arg, "A value of type %s can only be passed as a compile time parameter.", type_quoted_error_string(arg->type)); - return false; + assert(!type_is_wildcard(arg->type)); + RETURN_SEMA_ERROR(arg, "A value of type %s can only be passed as a compile time parameter.", type_quoted_error_string(arg->type)); } if (!param->alignment) { @@ -1581,29 +1572,28 @@ static inline Type *context_unify_returns(SemaContext *context) bool all_returns_need_casts = false; Type *common_type = NULL; - bool optional = false; - bool no_return = true; // 1. Loop through the returns. - VECEACH(context->returns, i) + bool optional = false; + unsigned returns = vec_size(context->returns); + if (!returns) return type_void; + for (unsigned i = 0; i < returns; i++) { Ast *return_stmt = context->returns[i]; + Type *rtype; if (!return_stmt) { optional = true; - continue; + rtype = type_wildcard; } - no_return = false; - Expr *ret_expr = return_stmt->return_stmt.expr; - Type *rtype = ret_expr ? ret_expr->type : type_void; - if (type_is_optional_any(rtype)) + else { - optional = true; - continue; - } - if (type_is_optional(rtype)) - { - optional = true; - rtype = type_no_optional(rtype); + Expr *ret_expr = return_stmt->return_stmt.expr; + rtype = ret_expr ? ret_expr->type : type_void; + if (type_is_optional(rtype)) + { + optional = true; + rtype = type_no_optional(rtype); + } } // 2. If we have no common type, set to the return type. if (!common_type) @@ -1634,24 +1624,12 @@ static inline Type *context_unify_returns(SemaContext *context) all_returns_need_casts = true; } - // If we have no return (or only anyfail) - if (!common_type) - { - assert(!all_returns_need_casts && "We should never need casts here."); - // An optional? - if (optional) - { - // If there are only implicit returns, then we assume void!, otherwise it's an "anyfail" - return no_return ? type_get_optional(type_void) : type_anyfail; - } - // No optional => void. - return type_void; - } + assert(common_type); // 7. Insert casts. if (all_returns_need_casts) { - assert(!type_is_optional_type(common_type)); + assert(common_type != type_wildcard); VECEACH(context->returns, i) { Ast *return_stmt = context->returns[i]; @@ -2377,6 +2355,11 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, int64_t index_value = -1; bool start_from_end = expr->subscript_expr.range.start_from_end; + if (start_from_end && (underlying_type->type_kind == TYPE_POINTER || underlying_type->type_kind == TYPE_FLEXIBLE_ARRAY)) + { + SEMA_ERROR(index, "Indexing from the end is not allowed for pointers and flexible array members."); + return false; + } int64_t size; if (expr_is_const_int(index) && (size = expr_get_index_max(subscripted)) >= 0) { @@ -2710,7 +2693,7 @@ static inline bool sema_expr_analyse_group(SemaContext *context, Expr *expr) * 5. .@#bar -> It is an identifier to resolve as a macro * 6. .$eval(...) -> resolve the eval and retry. */ -static Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing) + Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing) { RETRY: assert(child->resolve_status != RESOLVE_DONE); @@ -2796,25 +2779,25 @@ static inline void sema_expr_replace_with_enum_name_array(Expr *enum_array_expr, enum_array_expr->resolve_status = RESOLVE_NOT_DONE; } -static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, TypeInfo *parent, bool was_group, Expr *identifier) +static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier) { assert(identifier->expr_kind == EXPR_IDENTIFIER); - Type *canonical = parent->type->canonical; + Type *canonical = parent_type->canonical; const char *name = identifier->identifier_expr.ident; bool is_const = identifier->identifier_expr.is_const; if (!is_const) { AlignSize align; - if (!sema_set_abi_alignment(context, parent->type, &align)) return false; + if (!sema_set_abi_alignment(context, parent_type, &align)) return false; if (sema_expr_rewrite_to_type_property(context, expr, canonical, type_property_by_name(name), align, 0)) return true; } if (!type_may_have_sub_elements(canonical)) { - SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent->type), name); + SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent_type), name); return false; } Decl *decl = canonical->decl; @@ -2957,6 +2940,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e case TYPE_PROPERTY_INNER: case TYPE_PROPERTY_NAMES: case TYPE_PROPERTY_VALUES: + case TYPE_PROPERTY_ASSOCIATED: break; } @@ -3035,7 +3019,6 @@ static inline bool sema_create_const_len(SemaContext *context, Expr *expr, Type case TYPE_FAULTTYPE: len = vec_size(type->decl->enums.values); break; - case TYPE_SCALED_VECTOR: case TYPE_INFERRED_ARRAY: case TYPE_FLEXIBLE_ARRAY: case TYPE_SUBARRAY: @@ -3071,7 +3054,6 @@ static inline bool sema_create_const_inner(SemaContext *context, Expr *expr, Typ case TYPE_SUBARRAY: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: - case TYPE_SCALED_VECTOR: case TYPE_VECTOR: inner = type->array.base; break; @@ -3146,8 +3128,7 @@ static inline bool sema_create_const_min(SemaContext *context, Expr *expr, Type static inline bool sema_create_const_params(SemaContext *context, Expr *expr, Type *type) { - if (type->type_kind != TYPE_POINTER || type->pointer->type_kind != TYPE_FUNC) return false; - type = type->pointer; + if (type->type_kind != TYPE_FUNC) return false; Signature *sig = type->function.signature; unsigned params = vec_size(sig->params); Expr **param_exprs = params ? VECNEW(Expr*, params) : NULL; @@ -3161,6 +3142,22 @@ static inline bool sema_create_const_params(SemaContext *context, Expr *expr, Ty return true; } +static inline bool sema_create_const_associated(SemaContext *context, Expr *expr, Type *type) +{ + if (type->type_kind != TYPE_ENUM) return false; + Decl **associated = type->decl->enums.parameters; + unsigned count = vec_size(associated); + Expr **associated_exprs = count ? VECNEW(Expr*, count) : NULL; + for (unsigned i = 0; i < count; i++) + { + Decl *decl = associated[i]; + Expr *expr_element = expr_new_const_typeid(expr->span, decl->type->canonical); + vec_add(associated_exprs, expr_element); + } + expr_rewrite_const_untyped_list(expr, associated_exprs); + return true; +} + static inline void sema_create_const_membersof(SemaContext *context, Expr *expr, Type *type, AlignSize alignment, AlignSize offset) { @@ -3316,6 +3313,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp case TYPE_PROPERTY_EXTNAMEOF: case TYPE_PROPERTY_NAMEOF: case TYPE_PROPERTY_QNAMEOF: + case TYPE_PROPERTY_ASSOCIATED: // Not supported by dynamic typeid case TYPE_PROPERTY_NONE: return false; @@ -3411,6 +3409,8 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, if (!type_kind_is_enumlike(flat->type_kind)) return false; sema_expr_replace_with_enum_name_array(expr, flat->decl); return sema_analyse_expr(context, expr); + case TYPE_PROPERTY_ASSOCIATED: + return sema_create_const_associated(context, expr, flat); case TYPE_PROPERTY_ELEMENTS: if (!type_kind_is_enumlike(flat->type_kind)) return false; expr_rewrite_const_int(expr, type_isz, vec_size(flat->decl->enums.values)); @@ -3431,10 +3431,11 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, sema_create_const_membersof(context, expr, flat, alignment, offset); return true; case TYPE_PROPERTY_PARAMS: + if (flat->type_kind == TYPE_POINTER && flat->pointer->type_kind == TYPE_FUNC) flat = flat->pointer; return sema_create_const_params(context, expr, flat); case TYPE_PROPERTY_RETURNS: - if (flat->type_kind != TYPE_POINTER || flat->pointer->type_kind != TYPE_FUNC) return false; - flat = flat->pointer; + if (flat->type_kind == TYPE_POINTER && flat->pointer->type_kind == TYPE_FUNC) flat = flat->pointer; + if (flat->type_kind != TYPE_FUNC) return false; expr_rewrite_const_typeid(expr, type_infoptr(flat->function.signature->rtype)->type); return true; case TYPE_PROPERTY_SIZEOF: @@ -3519,7 +3520,15 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr) SEMA_ERROR(child, "A type can't appear here."); return false; } - + if (parent->expr_kind == EXPR_IDENTIFIER && parent->type->type_kind == TYPE_FUNC) + { + expr->type = type_typeid; + expr->expr_kind = EXPR_CONST; + expr->const_expr.const_kind = CONST_TYPEID; + expr->const_expr.typeid = parent->type; + expr->resolve_status = RESOLVE_DONE; + return true; + } if (parent->expr_kind == EXPR_TYPEINFO) { expr->type = type_typeid; @@ -3550,7 +3559,11 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr) // 2. If our left-hand side is a type, e.g. MyInt.abc, handle this here. if (parent->expr_kind == EXPR_TYPEINFO) { - return sema_expr_analyse_type_access(context, expr, parent->type_expr, was_group, identifier); + return sema_expr_analyse_type_access(context, expr, parent->type_expr->type, was_group, identifier); + } + if (parent->expr_kind == EXPR_IDENTIFIER && parent->type->type_kind == TYPE_FUNC) + { + return sema_expr_analyse_type_access(context, expr, parent->type, was_group, identifier); } if (expr_is_const_member(parent)) { @@ -3579,10 +3592,18 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr) Type *flat_type = type_flatten(type); const char *kw = identifier->identifier_expr.ident; - if (kw_type == kw && flat_type->type_kind == TYPE_ANY) + if (kw_type == kw) { - expr_rewrite_to_builtin_access(expr, parent, ACCESS_TYPEOFANY, type_typeid); - return true; + if (flat_type->type_kind == TYPE_ANY) + { + expr_rewrite_to_builtin_access(expr, parent, ACCESS_TYPEOFANY, type_typeid); + return true; + } + if (flat_type->type_kind == TYPE_ANYFAULT) + { + expr_rewrite_to_builtin_access(expr, parent, ACCESS_TYPEOFANYFAULT, type_typeid); + return true; + } } CHECK_DEEPER: @@ -3616,7 +3637,6 @@ CHECK_DEEPER: { if (sema_expr_rewrite_to_typeid_property(context, expr, parent, kw)) return true; } - if (flat_type->type_kind == TYPE_VECTOR) { unsigned len = strlen(kw); @@ -3631,7 +3651,7 @@ CHECK_DEEPER: NOT_SWIZZLE:; } } - // Hard coded ptr on subarrays and variant + // Hard coded ptr on subarrays and any if (kw == kw_ptr) { if (flat_type->type_kind == TYPE_SUBARRAY) @@ -3645,7 +3665,6 @@ CHECK_DEEPER: return true; } } - if (kw == kw_ordinal) { if (flat_type->type_kind == TYPE_ENUM) @@ -3686,7 +3705,7 @@ CHECK_DEEPER: return true; } } - if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYERR) + if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYFAULT) { if (current_parent->expr_kind == EXPR_CONST) { @@ -5036,9 +5055,9 @@ static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left // the left hand side. We ignore this check for lhs being a constant. Type *left_type_no_fail = type_no_optional(left->type)->canonical; assert(type_kind_is_any_integer(left_type_no_fail->type_kind)); - if (int_ucomp(right->const_expr.ixx, left_type_no_fail->builtin.bitsize, BINARYOP_GT)) + if (int_ucomp(right->const_expr.ixx, left_type_no_fail->builtin.bitsize, BINARYOP_GE)) { - SEMA_ERROR(right, "The shift exceeds bitsize of %s.", type_quoted_error_string(type_no_optional(left->type))); + SEMA_ERROR(right, "The shift is not less than the bitsize of %s.", type_quoted_error_string(type_no_optional(left->type))); return false; } @@ -5636,9 +5655,6 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) case TYPE_VECTOR: expr->type = type_get_vector(type_bool, canonical->array.len); return true; - case TYPE_SCALED_VECTOR: - expr->type = type_get_scaled_vector(type_bool); - return true; case TYPE_INFERRED_VECTOR: UNREACHABLE; default: @@ -5840,23 +5856,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr) // Here we might need to insert casts. Type *else_type = rhs->type; - if (type_is_optional_any(type)) - { - // One possibility is that both sides have the "optional any" type - // if so then we're done. - if (else_type == type) - { - expr->type = type; - return true; - } - // Otherwise assign the type of "else": - type = else_type; - } - else if (type_is_optional_any(else_type)) - { - expr->type = type; - return true; - } + // Remove any possible optional of the else type. bool add_optional = type_is_optional(else_type); type = type_no_optional(type); @@ -5978,32 +5978,6 @@ static inline bool sema_expr_analyse_unary(SemaContext *context, Expr *expr) } -static inline bool sema_expr_analyse_try(SemaContext *context, Expr *expr) -{ - Expr *inner = expr->inner_expr; - if (!sema_analyse_expr(context, inner)) return false; - if (!IS_OPTIONAL(inner)) - { - SEMA_ERROR(inner, "Expected an optional expression to 'try'."); - return false; - } - expr->type = type_bool; - return true; -} - -static inline bool sema_expr_analyse_catch(SemaContext *context, Expr *expr) -{ - Expr *inner = expr->inner_expr; - if (!sema_analyse_expr(context, inner)) return false; - if (!IS_OPTIONAL(inner)) - { - SEMA_ERROR(inner, "Expected an optional expression to 'catch'."); - return false; - } - expr->type = type_anyerr; - return true; -} - static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) { if (context->call_env.kind != CALL_ENV_FUNCTION && context->call_env.kind != CALL_ENV_CHECKS) @@ -6020,20 +5994,15 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) return false; } expr->rethrow_expr.cleanup = context_get_defers(context, context->active_scope.defer_last, 0, false); - if (inner->type == type_anyfail) - { - SEMA_ERROR(expr, "This expression will always throw, which isn't allowed."); - return false; - } + expr->type = type_no_optional(inner->type); if (!IS_OPTIONAL(inner)) { - SEMA_ERROR(expr, "No optional to rethrow before '?' in the expression, please remove '?'."); + SEMA_ERROR(expr, "No optional to rethrow before '!' in the expression, please remove '!'."); return false; } - if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO)) { vec_add(context->returns, NULL); @@ -6042,7 +6011,7 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) { if (context->rtype && context->rtype->type_kind != TYPE_OPTIONAL) { - SEMA_ERROR(expr, "This expression implicitly returns with an optional result, but the function does not allow optional results. Did you mean to use 'else' instead?"); + SEMA_ERROR(expr, "This expression implicitly returns with an optional result, but the function does not allow optional results. Did you mean to use '!!' instead?"); return false; } } @@ -6055,11 +6024,6 @@ static inline bool sema_expr_analyse_force_unwrap(SemaContext *context, Expr *ex { Expr *inner = expr->inner_expr; if (!sema_analyse_expr(context, inner)) return false; - if (inner->type == type_anyfail) - { - SEMA_ERROR(expr, "This expression will always throw, which isn't allowed."); - return false; - } expr->type = type_no_optional(inner->type); if (!IS_OPTIONAL(inner)) { @@ -6123,7 +6087,8 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe success = false; goto EXIT; } - if (type_no_optional(sum_returns) != type_void && !context->active_scope.jump_end) + Type *return_no_optional = type_no_optional(sum_returns); + if (return_no_optional != type_wildcard && return_no_optional != type_void && !context->active_scope.jump_end) { Ast *ast = ast_last(astptr(expr->expr_block.first_stmt)); SEMA_ERROR(ast, "Expected a return statement following this statement."); @@ -6165,12 +6130,12 @@ static inline bool sema_expr_analyse_optional(SemaContext *context, Expr *expr) } Type *type = inner->type->canonical; - if (type->type_kind != TYPE_FAULTTYPE && type->type_kind != TYPE_ANYERR) + if (type->type_kind != TYPE_FAULTTYPE && type->type_kind != TYPE_ANYFAULT) { SEMA_ERROR(inner, "You cannot use the '!' operator on expressions of type %s", type_quoted_error_string(type)); return false; } - expr->type = type_anyfail; + expr->type = type_wildcard_optional; return true; } @@ -6321,7 +6286,7 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * -static Decl *sema_expr_analyse_var_path(SemaContext *context, Expr *expr, ExprFlatElement **elements) +static Decl *sema_expr_analyse_var_path(SemaContext *context, Expr *expr) { if (!sema_analyse_expr_lvalue_fold_const(context, expr)) return NULL; Expr *current = expr; @@ -6343,13 +6308,19 @@ RETRY: return decl; } -static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlatElement *element, Type *type, Decl **member_ref, ArraySize *index_ref, Type **return_type, unsigned i, SourceSpan loc, - bool *is_missing) +static inline bool sema_expr_analyse_decl_element(SemaContext *context, DesignatorElement *element, Type *type, Decl **member_ref, ArraySize *index_ref, Type **return_type, unsigned i, SourceSpan loc, + bool *is_missing) { - Expr *inner = element->inner; - Type *actual_type = type_flatten(type); - if (element->array) + DesignatorType kind = element->kind; + if (kind == DESIGNATOR_RANGE) { + SEMA_ERROR(element->index_expr, "Ranges are not allowed."); + return false; + } + Type *actual_type = type_flatten(type); + if (kind == DESIGNATOR_ARRAY) + { + Expr *inner = element->index_expr; if (!type_is_arraylike(actual_type) && actual_type->type_kind != TYPE_POINTER) { if (is_missing) @@ -6393,7 +6364,7 @@ static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlat *index_ref = 0; return false; } - SEMA_ERROR(element->inner, "Index exceeds array bounds."); + SEMA_ERROR(inner, "Index exceeds array bounds."); return false; } *return_type = type; @@ -6401,14 +6372,14 @@ static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlat *member_ref = NULL; return true; } - inner = sema_expr_resolve_access_child(context, inner, is_missing); - if (!inner) return false; - if (inner->expr_kind != EXPR_IDENTIFIER) + Expr *field = sema_expr_resolve_access_child(context, element->field_expr, is_missing); + if (!field) return false; + if (field->expr_kind != EXPR_IDENTIFIER) { - SEMA_ERROR(inner, "Expected an identifier here."); + SEMA_ERROR(field, "Expected an identifier here."); return false; } - const char *kw = inner->identifier_expr.ident; + const char *kw = field->identifier_expr.ident; if (kw == kw_ptr) { switch (actual_type->type_kind) @@ -6455,7 +6426,7 @@ static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlat } return false; } - Decl *member = sema_decl_stack_find_decl_member(actual_type->decl, element->inner->identifier_expr.ident); + Decl *member = sema_decl_stack_find_decl_member(actual_type->decl, kw); if (!member) { Decl *ambiguous = NULL; @@ -6483,8 +6454,8 @@ static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlat static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr) { Expr *main_var = expr->ct_call_expr.main_var; - ExprFlatElement *path = expr->ct_call_expr.flat_path; - Decl *decl = sema_expr_analyse_var_path(context, main_var, &path); + DesignatorElement **path = expr->ct_call_expr.flat_path; + Decl *decl = sema_expr_analyse_var_path(context, main_var); if (!decl) return false; Type *type = decl->type; if (type_is_invalid_storage_type(type)) @@ -6501,13 +6472,19 @@ static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr { if (!sema_set_abi_alignment(context, type, &align)) return false; } - VECEACH(path, i) - { - ExprFlatElement *element = &path[i]; + FOREACH_BEGIN_IDX(i, DesignatorElement *element, path) Decl *member; ArraySize index = 0; Type *result_type; - if (!sema_expr_analyse_flat_element(context, element, type, &member, &index, &result_type, i, i == 0 ? main_var->span : expr->span, NULL)) return false; + if (!sema_expr_analyse_decl_element(context, + element, + type, + &member, + &index, + &result_type, + i, + i == 0 ? main_var->span : expr->span, + NULL)) return false; if (member) { align = type_min_alignment(member->offset, align); @@ -6518,8 +6495,7 @@ static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr align = type_min_alignment(size * index, align); } type = result_type; - } - + FOREACH_END(); expr_rewrite_const_int(expr, type_isz, align); return true; } @@ -6552,14 +6528,13 @@ static inline void sema_expr_rewrite_to_type_nameof(Expr *expr, Type *type, Toke static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr) { Expr *main_var = expr->ct_call_expr.main_var; - ExprFlatElement *path = expr->ct_call_expr.flat_path; - Decl *decl = sema_expr_analyse_var_path(context, main_var, &path); + Decl *decl = sema_expr_analyse_var_path(context, main_var); if (!decl) return false; Type *type = decl->type; TokenType name_type = expr->ct_call_expr.token_type; - if (vec_size(path)) + if (vec_size(expr->ct_call_expr.flat_path)) { SEMA_ERROR(main_var, "You can only take the name of types and variables, not their sub elements."); return false; @@ -6677,13 +6652,6 @@ RETRY: if (!type_ok(type)) return type; return type_get_inferred_vector(type); } - case TYPE_INFO_SCALED_VECTOR: - { - Type *type = sema_expr_check_type_exists(context, type_info->array.base); - if (!type) return NULL; - if (!type_ok(type)) return type; - return type_get_scaled_vector(type); - } case TYPE_INFO_POINTER: { // If it's an array, make sure we can resolve the length @@ -6884,7 +6852,6 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr Expr *main_var = expr->ct_call_expr.main_var; Type *type = NULL; Decl *decl = NULL; - ExprFlatElement *flat_path = expr->ct_call_expr.flat_path; RETRY: switch (main_var->expr_kind) { @@ -6919,20 +6886,26 @@ RETRY: return false; } - VECEACH(flat_path, i) - { - ExprFlatElement *element = &flat_path[i]; + FOREACH_BEGIN_IDX(i, DesignatorElement *element, expr->ct_call_expr.flat_path) Decl *member = NULL; ArraySize index; Type *ret_type; bool missing = false; - if (!sema_expr_analyse_flat_element(context, element, type, &member, &index, &ret_type, i, i == 0 ? main_var->span : expr->span, &missing)) + if (!sema_expr_analyse_decl_element(context, + element, + type, + &member, + &index, + &ret_type, + i, + i == 0 ? main_var->span : expr->span, + &missing)) { if (missing) goto NOT_DEFINED; return false; } type = ret_type; - } + FOREACH_END(); expr_rewrite_const_bool(expr, type_bool, true); return true; @@ -6942,26 +6915,6 @@ NOT_DEFINED: return true; } -static inline bool sema_expr_analyse_variant(SemaContext *context, Expr *expr) -{ - Expr *ptr = exprptr(expr->variant_expr.ptr); - Expr *typeid = exprptr(expr->variant_expr.type_id); - if (!sema_analyse_expr(context, ptr)) return false; - if (!sema_analyse_expr(context, typeid)) return false; - if (!type_is_pointer(ptr->type)) - { - SEMA_ERROR(ptr, "This must be a pointer, but is %s.", type_quoted_error_string(ptr->type)); - return false; - } - if (typeid->type != type_typeid) - { - SEMA_ERROR(ptr, "This must of type 'typeid', but was %s.", type_quoted_error_string(ptr->type)); - return false; - } - expr->type = type_any; - return true; -} - static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Expr *expr) { assert(expr->resolve_status == RESOLVE_RUNNING); @@ -7099,9 +7052,9 @@ static inline bool sema_expr_analyse_ct_eval(SemaContext *context, Expr *expr) static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *expr) { Expr *main_var = expr->ct_call_expr.main_var; - ExprFlatElement *path = expr->ct_call_expr.flat_path; - Decl *decl = sema_expr_analyse_var_path(context, main_var, &path); + Decl *decl = sema_expr_analyse_var_path(context, main_var); if (!decl) return false; + DesignatorElement **path = expr->ct_call_expr.flat_path; if (!vec_size(path)) { SEMA_ERROR(expr, "Expected a path to get the offset of."); @@ -7110,13 +7063,19 @@ static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *exp ByteSize offset = 0; Type *type = decl->type; - VECEACH(path, i) - { - ExprFlatElement *element = &path[i]; + FOREACH_BEGIN_IDX(i, DesignatorElement *element, path) Decl *member; ArraySize index = 0; Type *result_type; - if (!sema_expr_analyse_flat_element(context, element, type, &member, &index, &result_type, i, i == 0 ? main_var->span : expr->span, NULL)) return false; + if (!sema_expr_analyse_decl_element(context, + element, + type, + &member, + &index, + &result_type, + i, + i == 0 ? main_var->span : expr->span, + NULL)) return false; if (member) { offset += member->offset; @@ -7126,7 +7085,7 @@ static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *exp offset += type_size(result_type) * index; } type = result_type; - } + FOREACH_END(); expr_rewrite_const_int(expr, type_isz, offset); @@ -7228,12 +7187,11 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) case EXPR_COND: case EXPR_DESIGNATOR: case EXPR_MACRO_BODY_EXPANSION: - case EXPR_FLATPATH: case EXPR_NOP: case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TRY_UNWRAP: case EXPR_CATCH_UNWRAP: - case EXPR_VARIANTSWITCH: + case EXPR_ANYSWITCH: case EXPR_TYPEID_INFO: case EXPR_ASM: case EXPR_OPERATOR_CHARS: @@ -7249,8 +7207,9 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) return sema_expr_analyse_ct_checks(context, expr); case EXPR_CT_ARG: return sema_expr_analyse_ct_arg(context, expr); - case EXPR_VARIANT: - return sema_expr_analyse_variant(context, expr); + case EXPR_ANY: + // Created from compound statement. + UNREACHABLE; case EXPR_STRINGIFY: if (!sema_expr_analyse_ct_stringify(context, expr)) return false; return true; @@ -7291,10 +7250,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) return sema_expr_analyse_slice(context, expr); case EXPR_FORCE_UNWRAP: return sema_expr_analyse_force_unwrap(context, expr); - case EXPR_TRY: - return sema_expr_analyse_try(context, expr); - case EXPR_CATCH: - return sema_expr_analyse_catch(context, expr); case EXPR_COMPOUND_LITERAL: return sema_expr_analyse_compound_literal(context, expr); case EXPR_EXPR_BLOCK: @@ -7351,8 +7306,8 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr) if (!sema_analyse_expr(context, expr)) return false; if (IS_OPTIONAL(expr)) { - SEMA_ERROR(expr, "An optional %s cannot be implicitly converted to a regular boolean value, use 'try? ' " - "and 'catch? ' to conditionally execute on success or failure.", + SEMA_ERROR(expr, "An optional %s cannot be implicitly converted to a regular boolean value, use '@ok()' " + "and '@catchof()' to conditionally execute on success or failure.", type_quoted_error_string(expr->type)); return false; } @@ -7362,7 +7317,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr) bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional) { - if (to && type_is_optional_type(to)) + if (to && type_is_optional(to)) { to = to->optional; assert(allow_optional); @@ -7371,7 +7326,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo if (to && allow_optional && to->canonical != expr->type->canonical && expr->type->canonical->type_kind == TYPE_FAULTTYPE) { Type *flat = type_flatten(to); - if (flat != type_anyerr && flat->type_kind != TYPE_FAULTTYPE && expr->expr_kind == EXPR_CONST) + if (flat != type_anyfault && flat->type_kind != TYPE_FAULTTYPE && expr->expr_kind == EXPR_CONST) { sema_error_at_after(expr->span, "You need to add a trailing '!' here to make this an optional."); return false; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 7007d8e16..657bb1afd 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -14,10 +14,10 @@ static inline void sema_not_enough_elements_error(Expr *initializer, int element static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr); static void sema_create_const_initializer_value(ConstInitializer *const_init, Expr *value); static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer); -static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **elements, unsigned *index); +static Decl *sema_resolve_element_for_name(SemaContext *context, Decl **decls, DesignatorElement ***elements_ref, unsigned *index); static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, Expr *expr, MemberIndex *max_index, Decl **member_ptr); INLINE bool sema_initializer_list_is_empty(Expr *value); -static Type *sema_find_type_of_element(SemaContext *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, MemberIndex *max_index, Decl **member_ptr); +static Type *sema_find_type_of_element(SemaContext *context, Type *type, DesignatorElement ***elements_ref, unsigned *curr_index, bool *is_constant, bool *did_report_error, MemberIndex *max_index, Decl **member_ptr); MemberIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size); static MemberIndex sema_analyse_designator_index(SemaContext *context, Expr *index); static void sema_update_const_initializer_with_designator(ConstInitializer *const_init, @@ -523,6 +523,42 @@ static void sema_create_const_initializer_from_designated_init(ConstInitializer } } +static bool sema_analyse_variant_init(SemaContext *context, Expr *expr) +{ + unsigned elements = expr->expr_kind == EXPR_INITIALIZER_LIST ? vec_size(expr->initializer_list) : (unsigned)-1; + if (elements != 2 && elements != 0) + { + SEMA_ERROR(expr, "Expected an initializer with arguments '{ ptr, typeid }'."); + return false; + } + if (elements == 0) + { + expr->expr_kind = EXPR_ANY; + expr->any_expr = (ExprAny) { 0, 0 }; + expr->type = type_any; + return true; + } + Expr *ptr = expr->initializer_list[0]; + Expr *typeid = expr->initializer_list[1]; + if (!sema_analyse_expr(context, ptr)) return false; + if (!sema_analyse_expr(context, typeid)) return false; + if (!type_is_pointer(ptr->type)) + { + SEMA_ERROR(ptr, "Expected a pointer, but was %s.", type_quoted_error_string(ptr->type)); + return false; + } + if (typeid->type != type_typeid) + { + SEMA_ERROR(ptr, "Expected a 'typeid', but was %s.", type_quoted_error_string(ptr->type)); + return false; + } + expr->expr_kind = EXPR_ANY; + expr->any_expr.ptr = exprid(ptr); + expr->any_expr.type_id = exprid(typeid); + expr->type = type_any; + return true; +} + bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr) { if (!to) to = type_untypedlist; @@ -558,9 +594,6 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex if (!sema_analyse_expr(context, expr)) return false; return cast(expr, to); } - case TYPE_SCALED_VECTOR: - SEMA_ERROR(expr, "Scaled vectors cannot be initialized using an initializer list, since the length is not known at compile time."); - return false; case TYPE_POINTER: if (is_zero_init) { @@ -573,11 +606,12 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex case TYPE_POISONED: case TYPE_FUNC: case TYPE_TYPEDEF: - case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: case TYPE_TYPEINFO: case TYPE_MEMBER: break; + case TYPE_ANY: + return sema_analyse_variant_init(context, expr); default: if (is_zero_init) { @@ -860,7 +894,7 @@ static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, E for (unsigned i = 0; i < vec_size(path); i++) { Decl *member_found; - Type *new_current = sema_find_type_of_element(context, current, path, &i, &is_constant, &did_report_error, i == 0 ? max_index : NULL, &member_found); + Type *new_current = sema_find_type_of_element(context, current, &path, &i, &is_constant, &did_report_error, i == 0 ? max_index : NULL, &member_found); if (!new_current) { if (!did_report_error) SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(current)); @@ -878,10 +912,10 @@ INLINE bool sema_initializer_list_is_empty(Expr *value) && value->const_expr.initializer->kind == CONST_INIT_ZERO; } -static Type *sema_find_type_of_element(SemaContext *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, MemberIndex *max_index, Decl **member_ptr) +static Type *sema_find_type_of_element(SemaContext *context, Type *type, DesignatorElement ***elements_ref, unsigned *curr_index, bool *is_constant, bool *did_report_error, MemberIndex *max_index, Decl **member_ptr) { Type *type_flattened = type_flatten(type); - DesignatorElement *element = elements[*curr_index]; + DesignatorElement *element = (*elements_ref)[*curr_index]; if (element->kind == DESIGNATOR_ARRAY || element->kind == DESIGNATOR_RANGE) { *member_ptr = NULL; @@ -947,7 +981,10 @@ static Type *sema_find_type_of_element(SemaContext *context, Type *type, Designa { return NULL; } - Decl *member = sema_resolve_element_for_name(type_flattened->decl->strukt.members, elements, curr_index); + Decl *member = sema_resolve_element_for_name(context, + type_flattened->decl->strukt.members, + elements_ref, + curr_index); *member_ptr = member; if (!member) return NULL; return member->type; @@ -1078,10 +1115,20 @@ static MemberIndex sema_analyse_designator_index(SemaContext *context, Expr *ind return (MemberIndex)index_val; } -static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **elements, unsigned *index) + +static Decl *sema_resolve_element_for_name(SemaContext *context, Decl **decls, DesignatorElement ***elements_ref, unsigned *index) { - DesignatorElement *element = elements[*index]; - const char *name = element->field; + DesignatorElement *element = (*elements_ref)[*index]; + + Expr *field = sema_expr_resolve_access_child(context, element->field_expr, NULL); + if (!field) return poisoned_decl; + + if (field->expr_kind != EXPR_IDENTIFIER) + { + SEMA_ERROR(field, "An identifier was expected."); + return poisoned_decl; + } + const char *name = field->identifier_expr.ident; unsigned old_index = *index; VECEACH(decls, i) { @@ -1096,24 +1143,15 @@ static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **ele { assert(type_is_union_or_strukt(decl->type) || decl->decl_kind == DECL_BITSTRUCT); // Anonymous struct - Decl *found = sema_resolve_element_for_name(decl->strukt.members, elements, index); + Decl *found = sema_resolve_element_for_name(context, decl->strukt.members, elements_ref, index); // No match, continue... if (!found) continue; - // Special handling, we now need to patch the elements - unsigned current_size = vec_size(elements); - // Add an element at the end. - vec_add(elements, NULL); - // Shift all elements - for (unsigned j = current_size; j > old_index; j--) - { - elements[j] = elements[j - 1]; - } // Create our anon field. DesignatorElement *anon_element = CALLOCS(DesignatorElement); anon_element->kind = DESIGNATOR_FIELD; anon_element->index = (MemberIndex)i; - elements[old_index] = anon_element; + vec_insert_at(*elements_ref, old_index, anon_element); // Advance (*index)++; return found; diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index cca84cf3d..17abe2622 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -64,6 +64,7 @@ void sema_analysis_pass_lambda(Module *module); void sema_analyze_stage(Module *module, AnalysisStage stage); void sema_trace_liveness(void); +Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing); bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr); bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr); Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl); diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 83387a5ec..ed757d488 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -37,7 +37,7 @@ static void sema_trace_stmt_chain_liveness(AstId astid) case AST_RETURN_STMT: case AST_BREAK_STMT: case AST_CONTINUE_STMT: - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: return; default: break; @@ -84,6 +84,7 @@ static void sema_trace_stmt_liveness(Ast *ast) case AST_CT_SWITCH_STMT: case AST_CONTRACT: case AST_FOREACH_STMT: + case AST_CONTRACT_FAULT: UNREACHABLE case AST_ASM_STMT: sema_trace_expr_list_liveness(ast->asm_stmt.args); @@ -163,7 +164,7 @@ static void sema_trace_stmt_liveness(Ast *ast) case AST_DEFAULT_STMT: sema_trace_stmt_liveness(ast->case_stmt.body); return; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: sema_trace_stmt_chain_liveness(ast->nextcase_stmt.defer_id); sema_trace_expr_liveness(ast->nextcase_stmt.switch_expr); return; @@ -243,12 +244,11 @@ RETRY: case EXPR_CT_CHECKS: case EXPR_CT_EVAL: case EXPR_CT_IDENT: - case EXPR_VARIANTSWITCH: + case EXPR_ANYSWITCH: UNREACHABLE case EXPR_DESIGNATOR: sema_trace_expr_liveness(expr->designator_expr.value); return; - case EXPR_FLATPATH: case EXPR_HASH_IDENT: case EXPR_STRINGIFY: case EXPR_TYPEINFO: @@ -304,11 +304,9 @@ RETRY: case EXPR_CAST: expr = exprptr(expr->cast_expr.expr); goto RETRY; - case EXPR_CATCH: case EXPR_FORCE_UNWRAP: case EXPR_RETHROW: case EXPR_OPTIONAL: - case EXPR_TRY: expr = expr->inner_expr; goto RETRY; case EXPR_BUILTIN_ACCESS: @@ -440,9 +438,9 @@ RETRY: return; case EXPR_TYPEID: return; - case EXPR_VARIANT: - sema_trace_exprid_liveness(expr->variant_expr.ptr); - sema_trace_exprid_liveness(expr->variant_expr.type_id); + case EXPR_ANY: + sema_trace_exprid_liveness(expr->any_expr.ptr); + sema_trace_exprid_liveness(expr->any_expr.type_id); return; } UNREACHABLE diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 9ee26d02d..555437b74 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -626,22 +626,20 @@ bool sema_resolve_type_decl(SemaContext *context, Type *type) { switch (type->type_kind) { - case TYPE_OPTIONAL_ANY: - return true; case TYPE_POISONED: return false; + case TYPE_WILDCARD: case TYPE_VOID: case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_POINTER: case TYPE_UNTYPED_LIST: case TYPE_MEMBER: case TYPE_INFERRED_VECTOR: - case TYPE_SCALED_VECTOR: case TYPE_VECTOR: case TYPE_SUBARRAY: return true; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 508496158..fbd93a864 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -23,6 +23,7 @@ static inline bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *stateme static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement); static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement); +static inline bool sema_return_optional_check_is_valid_in_scope(SemaContext *context, Expr *ret_expr); static inline bool sema_defer_by_result(AstId defer_top, AstId defer_bottom); static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *statement); static inline bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body); @@ -43,12 +44,12 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr); static inline bool sema_analyse_compound_statement_no_scope(SemaContext *context, Ast *compound_statement); static inline bool sema_check_type_case(SemaContext *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index); static inline bool sema_check_value_case(SemaContext *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index, bool *if_chained, bool *max_ranged); -static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprVariantSwitch *variant, Decl *var_holder); +static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprAnySwitch *any_switch, Decl *var_holder); static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *statement); static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **asserts); static bool sema_analyse_ensure(SemaContext *context, Ast *directive); -static bool sema_analyse_errors(SemaContext *context, Ast *directive); +static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive); static inline bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt) { @@ -341,6 +342,25 @@ static inline void sema_inline_return_defers(SemaContext *context, Ast *stmt, As } } +static inline bool sema_return_optional_check_is_valid_in_scope(SemaContext *context, Expr *ret_expr) +{ + if (!IS_OPTIONAL(ret_expr) || !context->call_env.opt_returns) return true; + if (ret_expr->expr_kind != EXPR_OPTIONAL) return true; + Expr *inner = ret_expr->inner_expr; + if (!expr_is_const(inner)) return true; + assert(ret_expr->inner_expr->const_expr.const_kind == CONST_ERR); + Decl *fault = ret_expr->inner_expr->const_expr.enum_err_val; + FOREACH_BEGIN(Decl *opt, context->call_env.opt_returns) + if (opt->decl_kind == DECL_FAULT) + { + if (fault->type->decl == opt) return true; + continue; + } + if (opt == fault) return true; + FOREACH_END(); + SEMA_ERROR(ret_expr, "This value does not match declared optional returns, it needs to be declared with the other optional returns."); + return false; +} /** * Handle exit in a macro or in an expression block. * @param context @@ -353,16 +373,20 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state statement->ast_kind = AST_BLOCK_EXIT_STMT; context->active_scope.jump_end = true; Type *block_type = context->expected_block_type; - if (statement->return_stmt.expr) + Expr *ret_expr = statement->return_stmt.expr; + if (ret_expr) { if (block_type) { - if (!sema_analyse_expr_rhs(context, block_type, statement->return_stmt.expr, type_is_optional(block_type))) return false; + if (!sema_analyse_expr_rhs(context, block_type, ret_expr, type_is_optional(block_type))) return false; } else { - if (!sema_analyse_expr(context, statement->return_stmt.expr)) return false; + if (!sema_analyse_expr(context, ret_expr)) return false; } + if ((context->active_scope.flags & SCOPE_MACRO) + && !sema_return_optional_check_is_valid_in_scope(context, ret_expr)) return false; + } else { @@ -455,6 +479,7 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement { if (!sema_analyse_expr_rhs(context, expected_rtype, return_expr, type_is_optional(expected_rtype))) return false; if (!sema_check_not_stack_variable_escape(context, return_expr)) return false; + if (!sema_return_optional_check_is_valid_in_scope(context, return_expr)) return false; } else { @@ -706,9 +731,9 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr) if (!sema_expr_check_assign(context, ident)) return false; - if (ident->type->canonical != type_anyerr) + if (ident->type->canonical != type_anyfault) { - SEMA_ERROR(ident, "Expected the variable to have the type %s, not %s.", type_quoted_error_string(type_anyerr), + SEMA_ERROR(ident, "Expected the variable to have the type %s, not %s.", type_quoted_error_string(type_anyfault), type_quoted_error_string(ident->type)); return false; } @@ -718,13 +743,13 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr) } else { - type = type ? type : type_info_new_base(type_anyerr, expr->span); + type = type ? type : type_info_new_base(type_anyfault, expr->span); if (!sema_resolve_type_info(context, type)) return false; - if (type->type->canonical != type_anyerr) + if (type->type->canonical != type_anyfault) { - SEMA_ERROR(type, "Expected the type to be %s, not %s.", type_quoted_error_string(type_anyerr), + SEMA_ERROR(type, "Expected the type to be %s, not %s.", type_quoted_error_string(type_anyfault), type_quoted_error_string(type->type)); return false; } @@ -769,7 +794,7 @@ RESOLVE_EXPRS:; return false; } } - expr->type = type_anyerr; + expr->type = type_anyfault; expr->resolve_status = RESOLVE_DONE; return true; } @@ -810,7 +835,7 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond case EXPR_CATCH_UNWRAP: if (cond_type != COND_TYPE_UNWRAP_BOOL && cond_type != COND_TYPE_UNWRAP) { - SEMA_ERROR(expr, "Catch unwrapping is only allowed inside of a 'while' or 'if' conditional, maybe catch? will do what you need?"); + SEMA_ERROR(expr, "Catch unwrapping is only allowed inside of a 'while' or 'if' conditional, maybe '@catchof()' will do what you need?"); return false; } return sema_analyse_catch_unwrap(context, expr); @@ -824,12 +849,12 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond // Case 1: switch (var = variant_expr) if (expr->expr_kind == EXPR_BINARY && expr->binary_expr.operator == BINARYOP_ASSIGN) { - // No variable on the lhs? Then it can't be a variant unwrap. + // No variable on the lhs? Then it can't be an any unwrap. Expr *left = exprptr(expr->binary_expr.left); if (left->resolve_status == RESOLVE_DONE || left->expr_kind != EXPR_IDENTIFIER || left->identifier_expr.path) goto NORMAL_EXPR; // Does the identifier exist in the parent scope? - // then again it can't be a variant unwrap. + // then again it can't be an any unwrap. if (sema_symbol_is_defined_in_scope(context, left->identifier_expr.ident)) goto NORMAL_EXPR; Expr *right = exprptr(expr->binary_expr.right); @@ -844,12 +869,12 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond } if (right->type != type_any) goto NORMAL_EXPR; // Found an expansion here - expr->expr_kind = EXPR_VARIANTSWITCH; - expr->variant_switch.new_ident = left->identifier_expr.ident; - expr->variant_switch.span = left->span; - expr->variant_switch.variant_expr = right; - expr->variant_switch.is_deref = is_deref; - expr->variant_switch.is_assign = true; + expr->expr_kind = EXPR_ANYSWITCH; + expr->any_switch.new_ident = left->identifier_expr.ident; + expr->any_switch.span = left->span; + expr->any_switch.any_expr = right; + expr->any_switch.is_deref = is_deref; + expr->any_switch.is_assign = true; expr->resolve_status = RESOLVE_DONE; expr->type = type_typeid; return true; @@ -859,10 +884,10 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond if (expr->expr_kind == EXPR_IDENTIFIER) { Decl *decl = expr->identifier_expr.decl; - expr->expr_kind = EXPR_VARIANTSWITCH; - expr->variant_switch.is_deref = false; - expr->variant_switch.is_assign = false; - expr->variant_switch.variable = decl; + expr->expr_kind = EXPR_ANYSWITCH; + expr->any_switch.is_deref = false; + expr->any_switch.is_assign = false; + expr->any_switch.variable = decl; expr->type = type_typeid; expr->resolve_status = RESOLVE_DONE; return true; @@ -971,17 +996,8 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType { if (type_no_optional(last->type) == type_void && cast_to_bool) { - Expr *catch = expr_new_expr(EXPR_CATCH, last); - catch->expr_kind = EXPR_CATCH; - catch->inner_expr = expr_copy(last); - catch->type = type_anyerr; - catch->resolve_status = RESOLVE_DONE; - catch->inner_expr->resolve_status = RESOLVE_DONE; - last->expr_kind = EXPR_UNARY; - last->unary_expr.operator = UNARYOP_NOT; - last->unary_expr.expr = catch; - last->type = type_bool; - return true; + SEMA_ERROR(last, "Use '@ok()' or '@catchof()' to explicitly convert a 'void!' to a boolean."); + return false; } SEMA_ERROR(last, "The expression may not be an optional, but was %s.", type_quoted_error_string(last->type)); return false; @@ -1205,6 +1221,12 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement) return success; } +/** + * foreach_stmt ::= foreach + * @param context + * @param statement + * @return + */ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statement) { // Pull out the relevant data. @@ -1678,7 +1700,7 @@ static bool sema_analyse_asm_string_stmt(SemaContext *context, Ast *stmt) */ static inline Decl *sema_analyse_label(SemaContext *context, Ast *stmt) { - Label *label = stmt->ast_kind == AST_NEXT_STMT ? &stmt->nextcase_stmt.label : &stmt->contbreak_stmt.label; + Label *label = stmt->ast_kind == AST_NEXTCASE_STMT ? &stmt->nextcase_stmt.label : &stmt->contbreak_stmt.label; const char *name = label->name; Decl *target = sema_find_label_symbol(context, name); if (!target) @@ -1696,7 +1718,7 @@ static inline Decl *sema_analyse_label(SemaContext *context, Ast *stmt) case AST_CONTINUE_STMT: SEMA_ERROR(stmt, "You cannot use continue out of an expression block."); return poisoned_decl; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: SEMA_ERROR(stmt, "You cannot use nextcase to exit an expression block."); return poisoned_decl; default: @@ -1713,7 +1735,7 @@ static inline Decl *sema_analyse_label(SemaContext *context, Ast *stmt) case AST_CONTINUE_STMT: SEMA_ERROR(stmt, "You cannot use continue out of a defer."); return poisoned_decl; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: SEMA_ERROR(stmt, "You cannot use nextcase out of a defer."); return poisoned_decl; default: @@ -1743,7 +1765,7 @@ static inline Decl *sema_analyse_label(SemaContext *context, Ast *stmt) case AST_CONTINUE_STMT: SEMA_ERROR(stmt, "You cannot use continue out of a defer."); return poisoned_decl; - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: SEMA_ERROR(stmt, "You cannot use nextcase out of a defer."); return poisoned_decl; default: @@ -1853,7 +1875,7 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) Expr *target = statement->nextcase_stmt.expr; - Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? cond->type : type_anyerr; + Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? cond->type : type_anyfault; if (!sema_analyse_expr_rhs(context, expected_type, target, false)) return false; @@ -2071,7 +2093,7 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type return true; } -static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprVariantSwitch *variant, Decl *var_holder) +static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprAnySwitch *any_switch, Decl *var_holder) { bool use_type_id = false; if (!type_is_comparable(switch_type)) @@ -2144,16 +2166,16 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc Ast *body = stmt->case_stmt.body; if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && stmt->case_stmt.expr->expr_kind == EXPR_CONST) { - if (variant->is_assign) + if (any_switch->is_assign) { Type *real_type = type_get_ptr(stmt->case_stmt.expr->const_expr.typeid); - Decl *new_var = decl_new_var(variant->new_ident, variant->span, - type_info_new_base(variant->is_deref - ? real_type->pointer : real_type, variant->span), + Decl *new_var = decl_new_var(any_switch->new_ident, any_switch->span, + type_info_new_base(any_switch->is_deref + ? real_type->pointer : real_type, any_switch->span), VARDECL_LOCAL); Expr *var_result = expr_variable(var_holder); if (!cast(var_result, real_type)) return false; - if (variant->is_deref) + if (any_switch->is_deref) { expr_rewrite_insert_deref(var_result); } @@ -2441,35 +2463,33 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label); - Expr *cond = exprptr(statement->switch_stmt.cond); + Expr *cond = exprptrzero(statement->switch_stmt.cond); Type *switch_type; - ExprVariantSwitch var_switch; - Decl *variant_decl = NULL; + ExprAnySwitch var_switch; + Decl *any_decl = NULL; if (statement->ast_kind == AST_SWITCH_STMT) { - if (!sema_analyse_cond(context, cond, COND_TYPE_EVALTYPE_VALUE)) return false; - Expr *last = VECLAST(cond->cond_expr); - switch_type = last->type->canonical; - if (last->expr_kind == EXPR_VARIANTSWITCH) + if (cond && !sema_analyse_cond(context, cond, COND_TYPE_EVALTYPE_VALUE)) return false; + Expr *last = cond ? VECLAST(cond->cond_expr) : NULL; + switch_type = last ? last->type->canonical : type_bool; + if (last && last->expr_kind == EXPR_ANYSWITCH) { - var_switch = last->variant_switch; - - + var_switch = last->any_switch; Expr *inner; if (var_switch.is_assign) { inner = expr_new(EXPR_DECL, last->span); - variant_decl = decl_new_generated_var(type_any, VARDECL_LOCAL, last->span); - variant_decl->var.init_expr = var_switch.variant_expr; - inner->decl_expr = variant_decl; + any_decl = decl_new_generated_var(type_any, VARDECL_LOCAL, last->span); + any_decl->var.init_expr = var_switch.any_expr; + inner->decl_expr = any_decl; if (!sema_analyse_expr(context, inner)) return false; } else { inner = expr_new(EXPR_IDENTIFIER, last->span); - variant_decl = var_switch.variable; - inner->identifier_expr.decl = variant_decl; + any_decl = var_switch.variable; + inner->identifier_expr.decl = any_decl; inner->type = type_any; inner->resolve_status = RESOLVE_DONE; } @@ -2481,13 +2501,13 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement } else { - switch_type = type_anyerr; + switch_type = type_anyfault; } statement->switch_stmt.defer = context->active_scope.defer_last; if (!sema_analyse_switch_body(context, statement, cond ? cond->span : statement->span, switch_type->canonical, - statement->switch_stmt.cases, variant_decl ? &var_switch : NULL, variant_decl)) + statement->switch_stmt.cases, any_decl ? &var_switch : NULL, any_decl)) { return SCOPE_POP_ERROR(); } @@ -2696,6 +2716,7 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state case AST_IF_CATCH_SWITCH_STMT: case AST_CONTRACT: case AST_ASM_STMT: + case AST_CONTRACT_FAULT: UNREACHABLE case AST_DECLS_STMT: return sema_analyse_decls_stmt(context, statement); @@ -2741,7 +2762,7 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state return sema_analyse_return_stmt(context, statement); case AST_SWITCH_STMT: return sema_analyse_switch_stmt(context, statement); - case AST_NEXT_STMT: + case AST_NEXTCASE_STMT: return sema_analyse_nextcase_stmt(context, statement); case AST_CT_SWITCH_STMT: return sema_analyse_ct_switch_stmt(context, statement); @@ -2786,28 +2807,22 @@ static bool sema_analyse_ensure(SemaContext *context, Ast *directive) return true; } -static bool sema_analyse_errors(SemaContext *context, Ast *directive) +static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive) { - DocOptReturn *returns = directive->contract.optreturns; - VECEACH(returns, i) - { - TypeInfo *type_info = returns[i].type; - const char *ident = returns[i].ident; - if (type_info->kind != TYPE_INFO_IDENTIFIER) - { - SEMA_ERROR(type_info, "Expected a fault name here."); - return false; - } + Ast **returns = NULL; + context->call_env.opt_returns = NULL; + FOREACH_BEGIN(Ast *ret, directive->contract.faults) + if (ret->contract_fault.resolved) continue; + TypeInfo *type_info = ret->contract_fault.type; + const char *ident = ret->contract_fault.ident; + if (type_info->kind != TYPE_INFO_IDENTIFIER) RETURN_SEMA_ERROR(type_info, "Expected a fault name here."); if (!sema_resolve_type_info(context, type_info)) return false; Type *type = type_info->type; - if (type->type_kind != TYPE_FAULTTYPE) - { - SEMA_ERROR(type_info, "A fault type is required."); - return false; - } + if (type->type_kind != TYPE_FAULTTYPE) RETURN_SEMA_ERROR(type_info, "A fault type is required."); if (!ident) { - returns[i].decl = type->decl; + ret->contract_fault.decl = type->decl; + ret->contract_fault.resolved = true; goto NEXT; } Decl *decl = type->decl; @@ -2817,14 +2832,15 @@ static bool sema_analyse_errors(SemaContext *context, Ast *directive) Decl *opt_value = enums[j]; if (opt_value->name == ident) { - returns[i].decl = opt_value; + ret->contract_fault.decl = opt_value; + ret->contract_fault.resolved = true; goto NEXT; } } - sema_error_at(returns[i].span, "No fault value '%s' found.", ident); - return false; + RETURN_SEMA_ERROR(ret, "No fault value '%s' found.", ident); NEXT:; - } + vec_add(context->call_env.opt_returns, ret->contract_fault.decl); + FOREACH_END(); return true; } @@ -2882,8 +2898,8 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, So break; case CONTRACT_PARAM: break; - case CONTRACT_ERRORS: - if (!sema_analyse_errors(context, directive)) return false; + case CONTRACT_OPTIONALS: + if (!sema_analyse_optional_returns(context, directive)) return false; break; case CONTRACT_ENSURE: if (!sema_analyse_ensure(context, directive)) return false; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 141f57821..f785dfe22 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -140,9 +140,6 @@ static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, case TYPE_INFO_INFERRED_VECTOR: type->type = type_get_inferred_vector(type->array.base->type); break; - case TYPE_INFO_SCALED_VECTOR: - type->type = type_get_scaled_vector(type->array.base->type); - break; case TYPE_INFO_VECTOR: { ArraySize width; @@ -273,14 +270,18 @@ INLINE bool sema_resolve_evaltype(SemaContext *context, TypeInfo *type_info, boo INLINE bool sema_resolve_typeof(SemaContext *context, TypeInfo *type_info) { Expr *expr = type_info->unresolved_type_expr; - if (!sema_analyse_expr(context, expr)) - { - return false; - } + if (!sema_analyse_expr(context, expr)) return false; if (type_is_invalid_storage_type(expr->type)) { - SEMA_ERROR(expr, "Expected a regular runtime expression here."); - return false; + if (expr->type == type_wildcard) + { + RETURN_SEMA_ERROR(expr, "This expression has no concrete type."); + } + if (expr->type == type_wildcard_optional) + { + RETURN_SEMA_ERROR(expr, "This optional expression is untyped."); + } + RETURN_SEMA_ERROR(expr, "Expected a regular runtime expression here."); } type_info->type = expr->type; return true; @@ -292,8 +293,7 @@ INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info) if (!sema_analyse_expr(context, expr)) return false; if (!expr_is_const(expr) || expr->const_expr.const_kind != CONST_TYPEID) { - SEMA_ERROR(expr, "Expected a constant typeid value."); - return false; + RETURN_SEMA_ERROR(expr, "Expected a constant typeid value."); } type_info->type = expr->const_expr.typeid; return true; @@ -304,16 +304,12 @@ INLINE bool sema_resolve_vatype(SemaContext *context, TypeInfo *type_info) { if (!context->current_macro) { - SEMA_ERROR(type_info, "'%s' can only be used inside of a macro.", token_type_to_string(TOKEN_CT_VATYPE)); - return false; + RETURN_SEMA_ERROR(type_info, "'%s' can only be used inside of a macro.", token_type_to_string(TOKEN_CT_VATYPE)); } ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, type_info->unresolved_type_expr), false); - if (arg_expr->expr_kind != EXPR_TYPEINFO) - { - SEMA_ERROR(arg_expr, "The argument was not a type."); - return false; - } + if (arg_expr->expr_kind != EXPR_TYPEINFO) RETURN_SEMA_ERROR(arg_expr, "The argument was not a type."); + assert(arg_expr->resolve_status == RESOLVE_DONE); type_info->type = arg_expr->type_expr->type; return true; @@ -372,7 +368,6 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info, return type_info_poison(type_info); } FALLTHROUGH; - case TYPE_INFO_SCALED_VECTOR: case TYPE_INFO_SUBARRAY: case TYPE_INFO_ARRAY: case TYPE_INFO_VECTOR: diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 33cf03543..cddbdcd5b 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -230,6 +230,64 @@ static void sema_analyze_to_stage(AnalysisStage stage) halt_on_error(); } +static void assign_panicfn(void) +{ + if (!active_target.panicfn && active_target.no_stdlib) + { + global_context.panic_var = NULL; + global_context.panicf = NULL; + } + + const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::core::builtin::panic"; + Path *path; + const char *ident; + TokenType type; + if (sema_splitpathref(panicfn, strlen(panicfn), &path, &ident) != TOKEN_IDENT || path == NULL || !ident) + { + error_exit("'%s' is not a valid panic function.", panicfn); + } + Decl *decl = sema_find_decl_in_modules(global_context.module_list, path, ident); + if (!decl) + { + error_exit("Panic function pointer '%s::%s' could not be found.", path->module, ident); + } + Type *panic_fn_type = decl->type->canonical; + if (decl->decl_kind != DECL_VAR || !type_is_func_ptr(panic_fn_type)) + { + error_exit("'%s::%s' is not a function pointer.", path->module, ident); + } + if (!type_func_match(panic_fn_type, type_void, 4, type_string, type_string, type_string, type_uint)) + { + error_exit("Expected panic function to have the signature fn void(String, String, String, uint)."); + } + global_context.panic_var = decl; + if (active_target.no_stdlib) return; + + const char *panicf = "std::core::builtin::panicf"; + if (sema_splitpathref(panicf, strlen(panicf), &path, &ident) != TOKEN_IDENT || path == NULL || !ident) + { + error_exit("'%s' is not a valid panicf function.", panicf); + } + Decl *panicf_decl = sema_find_decl_in_modules(global_context.module_list, path, ident); + if (!panicf_decl) + { + global_context.panicf = NULL; + return; + } + + Type *panicf_fn_type = panicf_decl->type->canonical; + if (panicf_decl->decl_kind != DECL_FUNC) + { + error_exit("'%s' is not a function function.", panicf); + } + if (!type_func_match(type_get_ptr(panicf_fn_type), type_void, 5, type_string, type_string, type_string, type_uint, + type_get_subarray(type_any))) + { + error_exit("Expected panic function to have the signature fn void(String, String, String, uint, ...)."); + } + global_context.panicf = panicf_decl; +} + /** * Perform the entire semantic analysis. */ @@ -316,36 +374,8 @@ RESOLVE_LAMBDA:; sema_trace_liveness(); } - if (active_target.panicfn || !active_target.no_stdlib) - { - const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::core::builtin::panic"; - Path *path; - const char *ident; - TokenType type; - if (sema_splitpathref(panicfn, strlen(panicfn), &path, &ident) != TOKEN_IDENT || path == NULL || !ident) - { - error_exit("'%s' is not a valid panic function.", panicfn); - } - Decl *decl = sema_find_decl_in_modules(global_context.module_list, path, ident); - if (!decl) - { - error_exit("Panic function pointer '%s::%s' could not be found.", path->module, ident); - } - Type *panic_fn_type = decl->type->canonical; - if (decl->decl_kind != DECL_VAR || !type_is_func_ptr(panic_fn_type)) - { - error_exit("'%s::%s' is not a function pointer.", path->module, ident); - } - if (!type_func_match(panic_fn_type, type_void, 4, type_string, type_string, type_string, type_uint)) - { - error_exit("Expected panic function to have the signature fn void(String, String, String, uint)."); - } - global_context.panic_var = decl; - } - else - { - global_context.panic_var = NULL; - } + assign_panicfn(); + compiler_sema_time = bench_mark(); } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index e3eafc47b..e1871b9d1 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -45,12 +45,10 @@ const char *kw_argv; const char *kw_at_checked; const char *kw_at_deprecated; const char *kw_at_ensure; -const char *kw_at_optreturn; const char *kw_at_param; const char *kw_at_pure; const char *kw_at_require; const char *kw_at_return; -const char *kw_catch_question; const char *kw_check_assign; const char *kw_deprecated; const char *kw_distinct; @@ -77,7 +75,6 @@ const char *kw_std; const char *kw_std__core; const char *kw_std__core__types; const char *kw___run_default_test_runner; -const char *kw_try_question; const char *kw_type; const char *kw_typekind; const char *kw_winmain; @@ -114,12 +111,6 @@ void symtab_init(uint32_t capacity) case TOKEN_RETURN: kw_return = interned; break; - case TOKEN_TRY_QUESTION: - kw_try_question = interned; - break; - case TOKEN_CATCH_QUESTION: - kw_catch_question = interned; - break; default: break; } @@ -167,6 +158,7 @@ void symtab_init(uint32_t capacity) kw_out = KW_DEF("out"); kw_ptr = KW_DEF("ptr"); kw_pure = KW_DEF("pure"); + KW_DEF("returns"); kw_std = KW_DEF("std"); kw_std__core = KW_DEF("std::core"); kw_std__core__types = KW_DEF("std::core::types"); @@ -181,6 +173,7 @@ void symtab_init(uint32_t capacity) type_property_list[TYPE_PROPERTY_LEN] = kw_len = KW_DEF("len"); type_property_list[TYPE_PROPERTY_ALIGNOF] = KW_DEF("alignof"); + type_property_list[TYPE_PROPERTY_ASSOCIATED] = KW_DEF("associated"); type_property_list[TYPE_PROPERTY_ELEMENTS] = KW_DEF("elements"); type_property_list[TYPE_PROPERTY_EXTNAMEOF] = KW_DEF("extnameof"); type_property_list[TYPE_PROPERTY_INF] = KW_DEF("inf"); @@ -297,7 +290,6 @@ void symtab_init(uint32_t capacity) kw_at_checked = KW_DEF("@checked"); kw_at_ensure = KW_DEF("@ensure"); - kw_at_optreturn = KW_DEF("@optreturn"); kw_at_deprecated = KW_DEF("@deprecated"); kw_at_param = KW_DEF("@param"); kw_at_pure = KW_DEF("@pure"); diff --git a/src/compiler/tilde_codegen.c b/src/compiler/tilde_codegen.c index 72cc27bd3..d768969ad 100644 --- a/src/compiler/tilde_codegen.c +++ b/src/compiler/tilde_codegen.c @@ -568,7 +568,7 @@ static void param_expand(TB_DataType **params_ref, Type *type) return; } case TYPE_ENUM: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: param_expand(params_ref, type_lowering(type)); return; diff --git a/src/compiler/tilde_codegen_expr.c b/src/compiler/tilde_codegen_expr.c index 0cae8661e..e0f4d54fa 100644 --- a/src/compiler/tilde_codegen_expr.c +++ b/src/compiler/tilde_codegen_expr.c @@ -148,13 +148,13 @@ static void tilde_emit_const_expr(TildeContext *c, TBEValue *value, Expr *expr) LLVMValueRef value; if (decl) { - value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyerr), ""); + value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyfault), ""); } else { - value = llvm_get_zero(c, type_anyerr); + value = llvm_get_zero(c, type_anyfault); } - llvm_value_set(be_value, value, type_anyerr);*/ + llvm_value_set(be_value, value, type_anyfault);*/ return; } case CONST_ENUM: @@ -536,7 +536,7 @@ void tilde_emit_raw_call(TildeContext *c, TBEValue *result_value, FunctionProtot TBEValue error_holder = *result_value; if (error_var) { - value_set_address_abi_aligned(&error_holder, c->opt_var, type_anyerr); + value_set_address_abi_aligned(&error_holder, c->opt_var, type_anyfault); } TB_Reg stored_error; @@ -910,7 +910,7 @@ TBEValue tilde_emit_assign_expr(TildeContext *c, TBEValue *ref, Expr *expr, TB_R if (optional) { - tilde_store_to_ptr_raw(c, optional, tilde_get_zero(c, type_anyerr), type_anyerr); + tilde_store_to_ptr_raw(c, optional, tilde_get_zero(c, type_anyfault), type_anyfault); } POP_OPT(); @@ -920,8 +920,8 @@ TBEValue tilde_emit_assign_expr(TildeContext *c, TBEValue *ref, Expr *expr, TB_R if (rejump_block) { tilde_emit_block(c, rejump_block); - TB_Reg error = tilde_load_abi_alignment(c, type_anyerr, optional); - tilde_store_to_ptr_raw(c, c->opt_var, error, type_anyerr); + TB_Reg error = tilde_load_abi_alignment(c, type_anyfault, optional); + tilde_store_to_ptr_raw(c, c->opt_var, error, type_anyfault); tb_inst_goto(c->f, c->catch_block); } tilde_emit_block(c, assign_block); @@ -1567,7 +1567,7 @@ void tilde_emit_cast(TildeContext *c, CastKind cast_kind, Expr *expr, TBEValue * case CAST_EUBOOL: { BEValue zero; - llvm_value_set_int(c, &zero, type_anyerr, 0); + llvm_value_set_int(c, &zero, type_anyfault, 0); llvm_emit_int_comp(c, value, value, &zero, BINARYOP_NE); break; } diff --git a/src/compiler/tilde_codegen_instr.c b/src/compiler/tilde_codegen_instr.c index a28d94e9c..9da7751b0 100644 --- a/src/compiler/tilde_codegen_instr.c +++ b/src/compiler/tilde_codegen_instr.c @@ -41,6 +41,6 @@ TB_Reg tilde_emit_alloca(TildeContext *c, Type *type, AlignSize alignment) TB_Reg tilde_emit_is_no_opt(TildeContext *c, TB_Reg error_value) { - return tb_inst_cmp_eq(c->f, error_value, tilde_get_zero(c, type_anyerr)); + return tb_inst_cmp_eq(c->f, error_value, tilde_get_zero(c, type_anyfault)); } diff --git a/src/compiler/tilde_codegen_stmt.c b/src/compiler/tilde_codegen_stmt.c index b8194ed5b..7023213b1 100644 --- a/src/compiler/tilde_codegen_stmt.c +++ b/src/compiler/tilde_codegen_stmt.c @@ -58,7 +58,7 @@ static void tilde_emit_return_abi(TildeContext *c, TBEValue *return_value, TBEVa return_out = c->optional_out; if (!optional) { - value_set(&no_fail, tilde_get_zero(c, type_anyerr), type_anyerr); + value_set(&no_fail, tilde_get_zero(c, type_anyfault), type_anyfault); optional = &no_fail; } return_value = optional; @@ -172,7 +172,7 @@ void tilde_emit_return_implicit(TildeContext *c) return; } TBEValue value; - value_set(&value, tb_inst_ptr(c->f, 0), type_anyerr); + value_set(&value, tb_inst_ptr(c->f, 0), type_anyfault); tilde_emit_return_abi(c, NULL, &value); } @@ -231,7 +231,7 @@ INLINE void tilde_emit_return_stmt(TildeContext *c, Ast *ast) if (c->cur_func.prototype && type_is_optional(c->cur_func.prototype->rtype)) { error_return_block = tb_basic_block_create(c->f); - error_out = tilde_emit_alloca(c, type_anyerr, 0); + error_out = tilde_emit_alloca(c, type_anyfault, 0); c->opt_var = error_out; c->catch_block = error_return_block; } @@ -262,7 +262,7 @@ INLINE void tilde_emit_return_stmt(TildeContext *c, Ast *ast) { tilde_emit_block(c, error_return_block); TBEValue value; - value_set_address_abi_aligned(&value, error_out, type_anyerr); + value_set_address_abi_aligned(&value, error_out, type_anyfault); tilde_emit_return_abi(c, NULL, &value); } } @@ -292,7 +292,7 @@ void tilde_emit_local_decl(TildeContext *c, Decl *decl, TBEValue *value) scratch_buffer_clear(); scratch_buffer_append(decl->extname); scratch_buffer_append("$f"); - decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyerr, 0); + decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyfault, 0); } llvm_emit_global_variable_init(c, decl); c->builder = builder; @@ -308,7 +308,7 @@ void tilde_emit_local_decl(TildeContext *c, Decl *decl, TBEValue *value) scratch_buffer_clear(); scratch_buffer_append(decl->name); scratch_buffer_append(".f"); - decl->var.tb_optional_reg = tb_inst_local(c->f, type_size(type_anyerr), type_alloca_alignment(type_anyerr)); + decl->var.tb_optional_reg = tb_inst_local(c->f, type_size(type_anyfault), type_alloca_alignment(type_anyfault)); // Only clear out the result if the assignment isn't an optional. } @@ -324,21 +324,21 @@ void tilde_emit_local_decl(TildeContext *c, Decl *decl, TBEValue *value) value_set(value, tb_inst_poison(c->f), decl->type); if (decl->var.tb_optional_reg) { - tilde_store_to_ptr_raw(c, decl->var.tb_optional_reg, tb_inst_poison(c->f), type_anyerr); + tilde_store_to_ptr_raw(c, decl->var.tb_optional_reg, tb_inst_poison(c->f), type_anyfault); } } else { if (decl->var.tb_optional_reg) { - tilde_store_zero(c, type_anyerr, decl->var.tb_optional_reg, 0); + tilde_store_zero(c, type_anyfault, decl->var.tb_optional_reg, 0); } Type *type = type_lowering(decl->type); // Normal case, zero init. if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER) { - tilde_store_zero(c, type_anyerr, decl->tb_register, decl->alignment); + tilde_store_zero(c, type_anyfault, decl->tb_register, decl->alignment); } else { @@ -516,7 +516,7 @@ void tilde_emit_jump_to_optional_exit(TildeContext *c, TB_Reg opt_value) tilde_emit_block(c, error_block); } - tilde_store_to_ptr_raw(c, c->opt_var, opt_value, type_anyerr); + tilde_store_to_ptr_raw(c, c->opt_var, opt_value, type_anyfault); tb_inst_goto(c->f, c->catch_block); tilde_emit_block(c, after_block); diff --git a/src/compiler/tilde_codegen_type.c b/src/compiler/tilde_codegen_type.c index 0dd0c4d9f..8a952b6d8 100644 --- a/src/compiler/tilde_codegen_type.c +++ b/src/compiler/tilde_codegen_type.c @@ -112,7 +112,7 @@ static void param_expand(TildeContext *context, TB_DataType** params_ref, Type * return; } case TYPE_ENUM: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: param_expand(context, params_ref, type_lowering(type)); return; @@ -448,7 +448,7 @@ TB_DataType tildetype(Type *type) switch (type->type_kind) { case TYPE_TYPEID: - case TYPE_ANYERR: + case TYPE_ANYFAULT: UNREACHABLE; case TYPE_FUNC: TODO diff --git a/src/compiler/tilde_codegen_value.c b/src/compiler/tilde_codegen_value.c index 5fb387ef5..0ac46591c 100644 --- a/src/compiler/tilde_codegen_value.c +++ b/src/compiler/tilde_codegen_value.c @@ -158,7 +158,7 @@ void value_fold_optional(TildeContext *c, TBEValue *value) if (value->kind == TBE_ADDRESS_OPTIONAL) { TODO - //tilde_emit_jump_to_optional_exit(c, tilde_load_natural_alignment(c, type_anyerr, value->optional, "optval")); + //tilde_emit_jump_to_optional_exit(c, tilde_load_natural_alignment(c, type_anyfault, value->optional, "optval")); value->kind = TBE_ADDRESS; } } diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 1ac648d37..4a929d010 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -185,10 +185,8 @@ const char *token_type_to_string(TokenType type) // Keywords case TOKEN_ALIAS: return "alias"; - case TOKEN_ANYERR: - return "anyerr"; - case TOKEN_AS: - return "as"; + case TOKEN_ANYFAULT: + return "anyfault"; case TOKEN_ASM: return "asm"; case TOKEN_ASSERT: @@ -201,8 +199,6 @@ const char *token_type_to_string(TokenType type) return "case"; case TOKEN_CATCH: return "catch"; - case TOKEN_CATCH_QUESTION: - return "catch?"; case TOKEN_CONST: return "const"; case TOKEN_CONTINUE: @@ -245,8 +241,6 @@ const char *token_type_to_string(TokenType type) return "nextcase"; case TOKEN_NULL: return "null"; - case TOKEN_PRIVATE: - return "private"; case TOKEN_RETURN: return "return"; case TOKEN_STATIC: @@ -261,8 +255,6 @@ const char *token_type_to_string(TokenType type) return "true"; case TOKEN_TRY: return "try"; - case TOKEN_TRY_QUESTION: - return "try?"; case TOKEN_TYPEDEF: return "typedef"; case TOKEN_TYPEID: @@ -277,8 +269,8 @@ const char *token_type_to_string(TokenType type) // Named types case TOKEN_VOID: return "void"; - case TOKEN_VARIANT: - return "variant"; + case TOKEN_ANY: + return "any"; case TOKEN_BOOL: return "bool"; case TOKEN_FLOAT128: @@ -346,8 +338,6 @@ const char *token_type_to_string(TokenType type) return "$foreach"; case TOKEN_CT_ELSE: return "$else"; - case TOKEN_CT_ELIF: - return "$elif"; case TOKEN_CT_ENDIF: return "$endif"; case TOKEN_CT_ENDSWITCH: diff --git a/src/compiler/types.c b/src/compiler/types.c index 176d6b7eb..2974afebf 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -13,8 +13,8 @@ static struct Type f16, f32, f64, f128; Type usz, isz, uptr, iptr; Type string; - Type voidstar, typeid, anyerr, member, typeinfo, untyped_list; - Type any, anyfail; + Type voidstar, typeid, anyfault, member, typeinfo, untyped_list; + Type any, wildcard; } t; Type *type_bool = &t.u1; @@ -41,11 +41,12 @@ Type *type_ulong = &t.u64; Type *type_u128 = &t.u128; Type *type_uptr = &t.uptr; Type *type_usz = &t.usz; -Type *type_anyerr = &t.anyerr; +Type *type_anyfault = &t.anyfault; Type *type_untypedlist = &t.untyped_list; -Type *type_anyfail = &t.anyfail; +Type *type_wildcard = &t.wildcard; Type *type_member = &t.member; Type *type_chars = NULL; +Type *type_wildcard_optional = NULL; Type *type_string = &t.string; static unsigned size_subarray; @@ -56,10 +57,9 @@ static AlignSize max_alignment_vector; #define INFERRED_ARRAY_OFFSET 1 #define FLEXIBLE_ARRAY_OFFSET 2 #define SUB_ARRAY_OFFSET 3 -#define SCALED_VECTOR_OFFSET 4 -#define INFERRED_VECTOR_OFFSET 5 -#define OPTIONAL_OFFSET 6 -#define ARRAY_OFFSET 7 +#define INFERRED_VECTOR_OFFSET 4 +#define OPTIONAL_OFFSET 5 +#define ARRAY_OFFSET 6 Type *type_cint; Type *type_cuint; @@ -126,9 +126,6 @@ static void type_append_name_to_scratch(Type *type) type_append_name_to_scratch(type->pointer); scratch_buffer_append_char('*'); break; - case TYPE_OPTIONAL_ANY: - scratch_buffer_append("void!"); - break; case TYPE_OPTIONAL: if (type->optional) { @@ -148,16 +145,12 @@ static void type_append_name_to_scratch(Type *type) type_append_name_to_scratch(type->array.base); scratch_buffer_append("[*]"); break; - case TYPE_SCALED_VECTOR: - type_append_name_to_scratch(type->array.base); - scratch_buffer_append("[<>]"); - break; case TYPE_VOID: case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: case TYPE_TYPEID: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_ANY: case TYPE_VECTOR: scratch_buffer_append(type->name); @@ -167,6 +160,7 @@ static void type_append_name_to_scratch(Type *type) case TYPE_INFERRED_VECTOR: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_WILDCARD: UNREACHABLE break; case TYPE_FUNC: @@ -194,14 +188,10 @@ static void type_append_func_to_scratch(FunctionPrototype *prototype) } type_append_name_to_scratch(prototype->param_types[i]); } - if (prototype->variadic == VARIADIC_RAW && elements > 0) + if (prototype->raw_variadic && elements > 0) { scratch_buffer_append_char(','); } - if (prototype->variadic != VARIADIC_NONE) - { - scratch_buffer_append("..."); - } scratch_buffer_append_char(')'); } @@ -222,10 +212,11 @@ const char *type_to_error_string(Type *type) case TYPE_UNION: case TYPE_DISTINCT: case TYPE_BITSTRUCT: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_UNTYPED_LIST: case TYPE_ANY: case TYPE_MEMBER: + case TYPE_WILDCARD: return type->name; case TYPE_FUNC: scratch_buffer_clear(); @@ -233,16 +224,12 @@ const char *type_to_error_string(Type *type) return str_printf("fn %s", scratch_buffer_to_string()); case TYPE_INFERRED_VECTOR: return str_printf("%s[<*>]", type_to_error_string(type->array.base)); - case TYPE_SCALED_VECTOR: - return str_printf("%s[<>]", type_to_error_string(type->array.base)); case TYPE_VECTOR: return str_printf("%s[<%llu>]", type_to_error_string(type->array.base), (unsigned long long)type->array.len); case TYPE_TYPEINFO: return "typeinfo"; case TYPE_TYPEID: return "typeid"; - case TYPE_OPTIONAL_ANY: - return "void!"; case TYPE_POINTER: if (type->pointer->type_kind == TYPE_FUNC) { @@ -289,7 +276,6 @@ RETRY: } case CT_TYPES: UNREACHABLE; - case TYPE_SCALED_VECTOR: case TYPE_FLEXIBLE_ARRAY: return 0; case TYPE_OPTIONAL: @@ -310,13 +296,12 @@ RETRY: assert(type->decl->resolve_status == RESOLVE_DONE); return type->decl->strukt.size; case TYPE_VOID: - case TYPE_OPTIONAL_ANY: return 1; case TYPE_BOOL: case TYPE_TYPEID: case ALL_INTS: case ALL_FLOATS: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_ANY: return type->builtin.bytesize; case TYPE_FUNC: @@ -385,8 +370,6 @@ bool type_is_abi_aggregate(Type *type) RETRY: switch (type->type_kind) { - case TYPE_POISONED: - return false; case TYPE_OPTIONAL: type = type->optional; goto RETRY; @@ -399,7 +382,6 @@ bool type_is_abi_aggregate(Type *type) case TYPE_BITSTRUCT: case ALL_FLOATS: case TYPE_VOID: - case TYPE_OPTIONAL_ANY: case ALL_INTS: case TYPE_BOOL: case TYPE_TYPEID: @@ -407,7 +389,7 @@ bool type_is_abi_aggregate(Type *type) case TYPE_ENUM: case TYPE_FUNC: case TYPE_VECTOR: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_FAULTTYPE: return false; case TYPE_STRUCT: @@ -416,13 +398,8 @@ bool type_is_abi_aggregate(Type *type) case TYPE_ARRAY: case TYPE_ANY: return true; - case TYPE_TYPEINFO: - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_UNTYPED_LIST: + case CT_TYPES: case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: - case TYPE_MEMBER: UNREACHABLE } UNREACHABLE @@ -485,7 +462,6 @@ bool type_is_comparable(Type *type) case TYPE_BITSTRUCT: case TYPE_FLEXIBLE_ARRAY: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_MEMBER: return false; case TYPE_TYPEDEF: @@ -503,7 +479,7 @@ bool type_is_comparable(Type *type) case ALL_INTS: case ALL_FLOATS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_POINTER: case TYPE_ENUM: @@ -511,8 +487,8 @@ bool type_is_comparable(Type *type) case TYPE_FAULTTYPE: case TYPE_UNTYPED_LIST: case TYPE_TYPEINFO: - case TYPE_SCALED_VECTOR: case TYPE_VECTOR: + case TYPE_WILDCARD: return true; } UNREACHABLE @@ -522,20 +498,14 @@ void type_mangle_introspect_name_to_buffer(Type *type) { switch (type->type_kind) { - case TYPE_POISONED: - case TYPE_TYPEINFO: - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_UNTYPED_LIST: - case TYPE_OPTIONAL_ANY: - case TYPE_MEMBER: + case CT_TYPES: UNREACHABLE case TYPE_VOID: case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: scratch_buffer_append(type->name); return; @@ -561,10 +531,6 @@ void type_mangle_introspect_name_to_buffer(Type *type) scratch_buffer_append_char('$'); type_mangle_introspect_name_to_buffer(type->array.base); return; - case TYPE_SCALED_VECTOR: - scratch_buffer_append("vn$"); - type_mangle_introspect_name_to_buffer(type->array.base); - return; case TYPE_ARRAY: scratch_buffer_append_char('a'); scratch_buffer_append_unsigned_int(type->array.len); @@ -646,6 +612,7 @@ AlignSize type_abi_alignment(Type *type) case TYPE_TYPEINFO: case TYPE_UNTYPED_LIST: case TYPE_MEMBER: + case TYPE_WILDCARD: UNREACHABLE; case TYPE_BITSTRUCT: type = type->decl->bitstruct.base_type->type; @@ -665,7 +632,6 @@ AlignSize type_abi_alignment(Type *type) return alignment; } case TYPE_VOID: - case TYPE_OPTIONAL_ANY: return 1; case TYPE_OPTIONAL: type = type->optional; @@ -689,7 +655,7 @@ AlignSize type_abi_alignment(Type *type) case ALL_INTS: case ALL_FLOATS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: return type->builtin.abi_alignment; case TYPE_FUNC: case TYPE_POINTER: @@ -702,8 +668,6 @@ AlignSize type_abi_alignment(Type *type) goto RETRY; case TYPE_SUBARRAY: return alignment_subarray; - case TYPE_SCALED_VECTOR: - UNSUPPORTED; } UNREACHABLE } @@ -872,37 +836,10 @@ static Type *type_generate_flexible_array(Type *arr_type, bool canonical) return arr; } -static Type *type_generate_scaled_vector(Type *arr_type, bool canonical) -{ - if (canonical) arr_type = arr_type->canonical; - if (!arr_type->type_cache) - { - create_type_cache(arr_type); - } - - Type *arr = arr_type->type_cache[SCALED_VECTOR_OFFSET]; - if (arr == NULL) - { - arr = type_new(TYPE_SCALED_VECTOR, str_printf("%s[<>]", arr_type->name)); - arr->array.base = arr_type; - arr->array.len = 0; - arr_type->type_cache[SCALED_VECTOR_OFFSET] = arr; - if (arr_type == arr_type->canonical) - { - arr->canonical = arr; - } - else - { - arr->canonical = type_generate_scaled_vector(arr_type->canonical, true); - } - } - return arr; -} Type *type_get_ptr_recurse(Type *ptr_type) { - assert(ptr_type->type_kind != TYPE_OPTIONAL_ANY); if (ptr_type->type_kind == TYPE_OPTIONAL) { ptr_type = ptr_type->optional; @@ -943,11 +880,6 @@ Type *type_get_flexible_array(Type *arr_type) return type_generate_flexible_array(arr_type, false); } -Type *type_get_scaled_vector(Type *arr_type) -{ - return type_generate_scaled_vector(arr_type, false); -} - static inline bool array_structurally_equivalent_to_struct(Type *array, Type *type) { assert(array->type_kind == TYPE_ARRAY); @@ -1067,7 +999,6 @@ Type *type_get_indexed_type(Type *type) case TYPE_SUBARRAY: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: - case TYPE_SCALED_VECTOR: case TYPE_FLEXIBLE_ARRAY: case TYPE_VECTOR: return type->array.base; @@ -1241,7 +1172,7 @@ void type_func_prototype_init(uint32_t capacity) static uint32_t hash_function(Signature *sig) { - uintptr_t hash = (unsigned)sig->variadic; + uintptr_t hash = sig->variadic == VARIADIC_RAW ? 0 : 1; hash = hash * 31 + (uintptr_t)flatten_raw_function_type(type_infoptr(sig->rtype)->type); Decl **params = sig->params; VECEACH(params, i) @@ -1280,7 +1211,8 @@ static bool compare_func_param(Type *one, Type *other) static int compare_function(Signature *sig, FunctionPrototype *proto) { - if (sig->variadic != proto->variadic) return -1; + bool is_raw_variadic = sig->variadic == VARIADIC_RAW; + if (is_raw_variadic != proto->raw_variadic) return -1; Decl **params = sig->params; Type **other_params = proto->param_types; unsigned param_count = vec_size(params); @@ -1337,7 +1269,7 @@ static inline Type *func_create_new_func_proto(Signature *sig, CallABI abi, uint { unsigned param_count = vec_size(sig->params); FunctionPrototype *proto = CALLOCS(FunctionPrototype); - proto->variadic = sig->variadic; + proto->raw_variadic = sig->variadic == VARIADIC_RAW; proto->vararg_index = sig->vararg_index; Type *rtype = type_infoptr(sig->rtype)->type; proto->rtype = rtype; @@ -1347,7 +1279,7 @@ static inline Type *func_create_new_func_proto(Signature *sig, CallABI abi, uint Type *real_return_type = rtype->optional; proto->ret_by_ref_type = rtype->optional; proto->ret_by_ref = real_return_type->type_kind != TYPE_VOID; - proto->abi_ret_type = type_anyerr; + proto->abi_ret_type = type_anyfault; } else { @@ -1490,13 +1422,13 @@ void type_setup(PlatformTarget *target) type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1); type_create("member_ref", &t.member, TYPE_MEMBER, 1, 1, 1); type_create("untyped_list", &t.untyped_list, TYPE_UNTYPED_LIST, 1, 1, 1); - type_create("void!", &t.anyfail, TYPE_OPTIONAL_ANY, 1, 1, 1); + type_create("void", &t.wildcard, TYPE_WILDCARD, 1, 1, 1); type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer); type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer); create_type_cache(type_void); type_void->type_cache[0] = &t.voidstar; t.voidstar.pointer = type_void; - type_init("variant", &t.any, TYPE_ANY, target->width_pointer * 2, target->align_pointer); + type_init("any", &t.any, TYPE_ANY, target->width_pointer * 2, target->align_pointer); type_create_alias("usz", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer)); type_create_alias("isz", &t.isz, type_int_signed_by_bitsize(target->width_pointer)); @@ -1505,8 +1437,9 @@ void type_setup(PlatformTarget *target) alignment_subarray = MAX(type_abi_alignment(&t.voidstar), type_abi_alignment(t.usz.canonical)); size_subarray = (unsigned)(alignment_subarray * 2); - type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer); + type_init("anyfault", &t.anyfault, TYPE_ANYFAULT, target->width_pointer, target->align_pointer); type_chars = type_get_subarray(type_char); + type_wildcard_optional = type_get_optional(type_wildcard); 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; @@ -1558,10 +1491,8 @@ bool type_is_scalar(Type *type) case TYPE_ARRAY: case TYPE_SUBARRAY: case TYPE_VECTOR: - case TYPE_OPTIONAL_ANY: case TYPE_ANY: case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: return false; case TYPE_BOOL: case ALL_INTS: @@ -1570,7 +1501,7 @@ bool type_is_scalar(Type *type) case TYPE_POINTER: case TYPE_ENUM: case TYPE_FAULTTYPE: - case TYPE_ANYERR: + case TYPE_ANYFAULT: return true; case TYPE_BITSTRUCT: type = type->decl->bitstruct.base_type->type; @@ -1619,10 +1550,10 @@ Type *type_from_token(TokenType type) { switch (type) { - case TOKEN_VARIANT: + case TOKEN_ANY: return type_any; - case TOKEN_ANYERR: - return type_anyerr; + case TOKEN_ANYFAULT: + return type_anyfault; case TOKEN_VOID: return type_void; case TOKEN_BOOL: @@ -1790,7 +1721,7 @@ bool type_may_have_method(Type *type) case ALL_FLOATS: case ALL_INTS: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_ARRAY: case TYPE_SUBARRAY: @@ -1799,7 +1730,6 @@ bool type_may_have_method(Type *type) case TYPE_FLEXIBLE_ARRAY: case TYPE_VECTOR: case TYPE_BOOL: - case TYPE_SCALED_VECTOR: return true; case TYPE_TYPEDEF: UNREACHABLE @@ -1809,9 +1739,9 @@ bool type_may_have_method(Type *type) case TYPE_FUNC: case TYPE_UNTYPED_LIST: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_WILDCARD: return false; } UNREACHABLE @@ -1962,6 +1892,9 @@ Type *type_find_max_type(Type *type, Type *other) if (type == other) return type; + if (type == type_wildcard) return 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; @@ -1983,7 +1916,7 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_INFERRED_VECTOR: case TYPE_POISONED: case TYPE_OPTIONAL: - case TYPE_OPTIONAL_ANY: + case TYPE_WILDCARD: UNREACHABLE case TYPE_VOID: case TYPE_BOOL: @@ -1991,7 +1924,6 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_ANY: case TYPE_BITSTRUCT: case TYPE_FLEXIBLE_ARRAY: - case TYPE_SCALED_VECTOR: return NULL; case ALL_INTS: if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other; @@ -2039,10 +1971,10 @@ Type *type_find_max_type(Type *type, Type *other) // some way? return NULL; case TYPE_FAULTTYPE: - if (other->type_kind == TYPE_FAULTTYPE) return type_anyerr; + if (other->type_kind == TYPE_FAULTTYPE) return type_anyfault; return NULL; - case TYPE_ANYERR: - return type_anyerr; + case TYPE_ANYFAULT: + return type_anyfault; case TYPE_FUNC: if (other->type_kind != TYPE_FUNC) return NULL; other = other->function.prototype->raw_type; @@ -2148,14 +2080,15 @@ unsigned type_get_introspection_kind(TypeKind kind) case TYPE_U128: return INTROSPECT_TYPE_UNSIGNED_INT; case TYPE_F16: + case TYPE_BF16: case TYPE_F32: case TYPE_F64: case TYPE_F128: return INTROSPECT_TYPE_FLOAT; case TYPE_ANY: - return INTROSPECT_TYPE_VARIANT; - case TYPE_ANYERR: - return INTROSPECT_TYPE_ANYERR; + return INTROSPECT_TYPE_ANY; + case TYPE_ANYFAULT: + return INTROSPECT_TYPE_ANYFAULT; case TYPE_TYPEID: return INTROSPECT_TYPE_TYPEID; case TYPE_POINTER: @@ -2183,14 +2116,13 @@ unsigned type_get_introspection_kind(TypeKind kind) case TYPE_SUBARRAY: return INTROSPECT_TYPE_SUBARRAY; case TYPE_VECTOR: - case TYPE_SCALED_VECTOR: case TYPE_INFERRED_VECTOR: return INTROSPECT_TYPE_VECTOR; case TYPE_UNTYPED_LIST: - case TYPE_OPTIONAL_ANY: case TYPE_TYPEINFO: case TYPE_OPTIONAL: case TYPE_MEMBER: + case TYPE_WILDCARD: UNREACHABLE return 0; } @@ -2208,8 +2140,9 @@ Module *type_base_module(Type *type) case ALL_FLOATS: case TYPE_BOOL: case TYPE_ANY: - case TYPE_ANYERR: + case TYPE_ANYFAULT: case TYPE_TYPEID: + case TYPE_WILDCARD: return NULL; case TYPE_POINTER: type = type->pointer; @@ -2222,7 +2155,7 @@ Module *type_base_module(Type *type) case TYPE_BITSTRUCT: case TYPE_FAULTTYPE: case TYPE_DISTINCT: - return type->decl->unit->module; + return type->decl->unit ? type->decl->unit->module : NULL; case TYPE_TYPEDEF: type = type->canonical; goto RETRY; @@ -2231,7 +2164,6 @@ Module *type_base_module(Type *type) case TYPE_INFERRED_ARRAY: case TYPE_FLEXIBLE_ARRAY: case TYPE_VECTOR: - case TYPE_SCALED_VECTOR: case TYPE_INFERRED_VECTOR: type = type->array.base; goto RETRY; @@ -2239,7 +2171,6 @@ Module *type_base_module(Type *type) type = type->optional; goto RETRY; case TYPE_UNTYPED_LIST: - case TYPE_OPTIONAL_ANY: case TYPE_TYPEINFO: case TYPE_MEMBER: UNREACHABLE diff --git a/src/utils/lib.h b/src/utils/lib.h index a9fb320a4..9e438bb2c 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -159,7 +159,7 @@ static inline bool char_is_whitespace(char c); static inline signed char char_is_valid_escape(char c); // Hex to nibble, -1 if invalid static inline int char_hex_to_nibble(char c); -static inline char char_nibble_to_hex(int c); +INLINE char char_nibble_to_hex(int c); static inline uint32_t fnv1a(const char *key, uint32_t len); @@ -520,12 +520,17 @@ static inline bool char_is_hex(char c) return hex_conv[(unsigned char)c] != 0; } -static inline char char_nibble_to_hex(int c) +INLINE char char_nibble_to_hex(int c) { static const char *conv = "0123456789ABCDEF"; return conv[c]; } +INLINE bool is_space(char c) +{ + return c == ' ' || c == '\t'; +} + static inline bool char_is_whitespace(char c) { switch (c) diff --git a/src/version.h b/src/version.h index 2669c2ee1..20885b636 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.117" \ No newline at end of file +#define COMPILER_VERSION "0.4.500" \ No newline at end of file diff --git a/test/test_suite/abi/avx512fp16-abi.c3t b/test/test_suite/abi/avx512fp16-abi.c3t new file mode 100644 index 000000000..74feffe87 --- /dev/null +++ b/test/test_suite/abi/avx512fp16-abi.c3t @@ -0,0 +1,166 @@ +// #target: macos-x64 +// #opt: --x86vec=avx512 +module abi; + +struct Half1 { + float16 a; +} + +fn Half1 h1(float16 a) { + Half1 x; + x.a = a; + return x; +} + +struct Half2 { + float16 a; + float16 b; +} + +fn Half2 h2(float16 a, float16 b) { + Half2 x; + x.a = a; + x.b = b; + return x; +} + +struct Half3 { + float16 a; + float16 b; + float16 c; +} + +fn Half3 h3(float16 a, float16 b, float16 c) { + // CHECK: define{{.*}}<4 x half> @ + Half3 x; + x.a = a; + x.b = b; + x.c = c; + return x; +} + +struct Half4 { + float16 a; + float16 b; + float16 c; + float16 d; +} + +fn Half4 h4(float16 a, float16 b, float16 c, float16 d) { + Half4 x; + x.a = a; + x.b = b; + x.c = c; + x.d = d; + return x; +} + +struct Floathalf { + float a; + float16 b; +} + +fn Floathalf fh(float a, float16 b) { + Floathalf x; + x.a = a; + x.b = b; + return x; +} + +struct Floathalf2 { + float a; + float16 b; + float16 c; +} + +fn Floathalf2 fh2(float a, float16 b, float16 c) { + Floathalf2 x; + x.a = a; + x.b = b; + x.c = c; + return x; +} + +struct Halffloat { + float16 a; + float b; +} + +fn Halffloat hf(float16 a, float b) { + Halffloat x; + x.a = a; + x.b = b; + return x; +} + +struct Half2float { + float16 a; + float16 b; + float c; +} + +fn Half2float h2f(float16 a, float16 b, float c) { + Half2float x; + x.a = a; + x.b = b; + x.c = c; + return x; +} + +struct Floathalf3 { + float a; + float16 b; + float16 c; + float16 d; +} + +fn Floathalf3 fh3(float a, float16 b, float16 c, float16 d) { + Floathalf3 x; + x.a = a; + x.b = b; + x.c = c; + x.d = d; + return x; +} + +struct Half5 { + float16 a; + float16 b; + float16 c; + float16 d; + float16 e; +} + +fn Half5 h5(float16 a, float16 b, float16 c, float16 d, float16 e) { + Half5 x; + x.a = a; + x.b = b; + x.c = c; + x.d = d; + x.e = e; + return x; +} + +/* #expect: abi.ll + +%Half1 = type { half } +%Half2 = type { half, half } +%Half3 = type { half, half, half } +%Half4 = type { half, half, half, half } +%Floathalf = type { float, half } +%Floathalf2 = type { float, half, half } +%Halffloat = type { half, float } +%Half2float = type { half, half, float } +%Floathalf3 = type { float, half, half, half } +%Half5 = type { half, half, half, half, half } + +define half @abi.h1(half %0) +define <2 x half> @abi.h2(half %0, half %1) +define <4 x half> @abi.h3(half %0, half %1, half %2) +define <4 x half> @abi.h4(half %0, half %1, half %2, half %3) +define <4 x half> @abi.fh(float %0, half %1) +define <4 x half> @abi.fh2(float %0, half %1, half %2) +define <4 x half> @abi.hf(half %0, float %1) +define <4 x half> @abi.h2f(half %0, half %1, float %2) #0 { +define { <4 x half>, half } @abi.fh3(float %0, half %1, half %2, half %3) #0 { +define { <4 x half>, half } @abi.h5(half %0, half %1, half %2, half %3, half %4) #0 { diff --git a/test/test_suite/abi/darwin64_avx.c3t b/test/test_suite/abi/darwin64_avx.c3t index 69405366f..e35f1e1d7 100644 --- a/test/test_suite/abi/darwin64_avx.c3t +++ b/test/test_suite/abi/darwin64_avx.c3t @@ -52,7 +52,7 @@ struct Vec47 { uint a; } extern fn void f47(int,int,int,int,int,int,Vec47); fn void test47(int a, Vec47 b) { f47(a, a, a, a, a, a, b); } -fn void test49_helper(double, ...); +extern fn void test49_helper(double, ...); fn void test49(double d, double e) { test49_helper(d, e); } struct Complex { double i; double c; } @@ -117,13 +117,13 @@ define void @test.func41(ptr byval(%Two128) align 16 %0) declare void @func42(ptr byval(%Sa) align 16) define void @test.func43(ptr byval(%Sa) align 16 %0) -declare void @f46(double, double, double, double, double, double, double, double, ptr byval(<2 x float>) align 8, ptr byval(<2 x float>) align 8) #0 +declare void @f46(double, double, double, double, double, double, double, double, ptr byval(<2 x float>) align 8, ptr byval(<2 x float>) align 8) declare void @f47(i32, i32, i32, i32, i32, i32, i32) -declare void @test.test49_helper(double, ...) +declare void @test49_helper(double, ...) define void @test.test49(double %0, double %1) entry: - call void (double, ...) @test.test49_helper(double %0, double %1) + call void (double, ...) @test49_helper(double %0, double %1) ret void call void (i32, ...) @test52_helper(i32 0, <8 x float> %0, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi) @@ -138,4 +138,4 @@ define void @test.f59(ptr byval(%Two256) align 32 %0) declare void @f60(ptr byval(%SAtwo256) align 32) -define void @test.f61(ptr byval(%SAtwo256) align 32 %0) #0 { +define void @test.f61(ptr byval(%SAtwo256) align 32 %0) diff --git a/test/test_suite/abi/darwin64_avx512.c3t b/test/test_suite/abi/darwin64_avx512.c3t index 1f3ed9881..d02ce5374 100644 --- a/test/test_suite/abi/darwin64_avx512.c3t +++ b/test/test_suite/abi/darwin64_avx512.c3t @@ -42,13 +42,13 @@ fn void f61(SAtwo256 s) { struct Complex { double i; double c; } // AVX512: @f62_helper(i32 0, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}}) -fn void f62_helper(int, ...); +extern fn void f62_helper(int, ...); Mm512 x62; fn void f62() { f62_helper(0, x62, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 1.0, 1.0 }); } -fn void f64_helper(Mm512, ...); +extern fn void f64_helper(Mm512, ...); Mm512 x64; fn void f64() { f64_helper(x64, x64, 1.0, 1.0, 1.0, 1.0, 1.0, Complex { 1.0, 1.0 }); @@ -58,17 +58,18 @@ fn void f64() { /* #expect: test.ll -declare void @f55(<16 x float>) #0 -declare void @f56(<16 x float>) #0 +declare void @f55(<16 x float>) +declare void @f56(<16 x float>) -declare void @f58(ptr byval(%Two256) align 32) #0 -define void @test.f59(ptr byval(%Two256) align 32 %0) #0 { +declare void @f58(ptr byval(%Two256) align 32) +define void @test.f59(ptr byval(%Two256) align 32 %0) -declare void @f60(ptr byval(%SAtwo256) align 32) #0 -define void @test.f61(ptr byval(%SAtwo256) align 32 %0) #0 { +declare void @f60(ptr byval(%SAtwo256) align 32) +define void @test.f61(ptr byval(%SAtwo256) align 32 %0) -define void @test.f62() #0 { - call void (i32, ...) @test.f62_helper(i32 0, <16 x float> %0, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi) -define void @test.f64() #0 { - call void (<16 x float>, ...) @test.f64_helper(<16 x float> %0, <16 x float> %1, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi) - call void (<16 x float>, ...) @test.f64_helper(<16 x float> %6, <16 x float> %7, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, ptr byval(%Complex) align 8 %literal1) +define void @test.f62() + call void (i32, ...) @f62_helper(i32 0, <16 x float> %0, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi) + +define void @test.f64() + call void (<16 x float>, ...) @f64_helper(<16 x float> %0, <16 x float> %1, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double %lo, double %hi) + call void (<16 x float>, ...) @f64_helper(<16 x float> %6, <16 x float> %7, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, ptr byval(%Complex) align 8 %literal1) diff --git a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-1.c3t b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-1.c3t index af916aa60..9409e756d 100644 --- a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-1.c3t +++ b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-1.c3t @@ -141,7 +141,7 @@ fn Large f_scalar_stack_3(uint a, int128 b, float128 c, char[<32>] d, // passed in registers but not on the stack. Ensure this takes into account // the use of "aligned" register pairs for varargs with 2*xlen alignment. -fn int f_va_callee(int, ...); +extern fn int f_va_callee(int, ...); fn void f_va_caller() { float128 fq; @@ -177,7 +177,7 @@ define void @test.f_vec_tiny_v4i16(i64 %0) define i64 @test.f_vec_tiny_v4i16_ret() define void @test.f_vec_tiny_v1i64(i64 %0) define i64 @test.f_vec_tiny_v1i64_ret() -define void @test.f_agg_small([2 x i64] +define void @test.f_agg_small([2 x i64] %0) define [2 x i64] @test.f_agg_small_ret() define void @test.f_vec_small_v8i16(i128 %0) define i128 @test.f_vec_small_v8i16_ret() @@ -190,18 +190,17 @@ define void @test.f_agg_large_ret(ptr noalias sret(%Large) align 8 %0, i32 signe define void @test.f_vec_large_v32i8(ptr align 32 %0) define void @test.f_vec_large_v32i8_ret(ptr noalias sret(<32 x i8>) align 32 %0) define signext i32 @test.f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr align 8 %3, i8 zeroext %4, i8 signext %5, i8 %6, i8 %7) -define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) #0 { +define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) define void @test.f_scalar_stack_3(ptr noalias sret(%Large) align 8 %0, i32 signext %1, i128 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) -declare signext i32 @test.f_va_callee(i32 signext, ...) #0 -call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %literal3, i32 32, i1 false) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) -d \ No newline at end of file +declare signext i32 @f_va_callee(i32 signext, ...) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %literal3, i32 32, i1 false) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) \ No newline at end of file diff --git a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-2.c3t b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-2.c3t index 29763fd55..f67bcda4a 100644 --- a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-2.c3t +++ b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-2.c3t @@ -142,7 +142,7 @@ fn Large f_scalar_stack_3(uint a, int128 b, float128 c, char[<32>] d, // passed in registers but not on the stack. Ensure this takes into account // the use of "aligned" register pairs for varargs with 2*xlen alignment. -fn int f_va_callee(int, ...); +extern fn int f_va_callee(int, ...); fn void f_va_caller() { float128 fq; @@ -178,7 +178,7 @@ define void @test.f_vec_tiny_v4i16(i64 %0) define i64 @test.f_vec_tiny_v4i16_ret() define void @test.f_vec_tiny_v1i64(i64 %0) define i64 @test.f_vec_tiny_v1i64_ret() -define void @test.f_agg_small([2 x i64] +define void @test.f_agg_small([2 x i64] %0) define [2 x i64] @test.f_agg_small_ret() define void @test.f_vec_small_v8i16(i128 %0) define i128 @test.f_vec_small_v8i16_ret() @@ -191,17 +191,17 @@ define void @test.f_agg_large_ret(ptr noalias sret(%Large) align 8 %0, i32 signe define void @test.f_vec_large_v32i8(ptr align 32 %0) define void @test.f_vec_large_v32i8_ret(ptr noalias sret(<32 x i8>) align 32 %0) define signext i32 @test.f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr align 8 %3, i8 zeroext %4, i8 signext %5, i8 %6, i8 %7) -define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) #0 { +define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) define void @test.f_scalar_stack_3(ptr noalias sret(%Large) align 8 %0, i32 signext %1, i128 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) -declare signext i32 @test.f_va_callee(i32 signext, ...) #0 +declare signext i32 @f_va_callee(i32 signext, ...) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %literal3, i32 32, i1 false) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) \ No newline at end of file diff --git a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-3.c3t b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-3.c3t index 9a83ccd76..05d371b3b 100644 --- a/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-3.c3t +++ b/test/test_suite/abi/riscv64-lp64-lp64f-lp64d-abi-3.c3t @@ -142,7 +142,7 @@ fn Large f_scalar_stack_3(uint a, int128 b, float128 c, char[<32>] d, // passed in registers but not on the stack. Ensure this takes into account // the use of "aligned" register pairs for varargs with 2*xlen alignment. -fn int f_va_callee(int, ...); +extern fn int f_va_callee(int, ...); fn void f_va_caller() { float128 fq; @@ -178,7 +178,7 @@ define void @test.f_vec_tiny_v4i16(i64 %0) define i64 @test.f_vec_tiny_v4i16_ret() define void @test.f_vec_tiny_v1i64(i64 %0) define i64 @test.f_vec_tiny_v1i64_ret() -define void @test.f_agg_small([2 x i64] +define void @test.f_agg_small([2 x i64] %0) define [2 x i64] @test.f_agg_small_ret() define void @test.f_vec_small_v8i16(i128 %0) define i128 @test.f_vec_small_v8i16_ret() @@ -191,17 +191,17 @@ define void @test.f_agg_large_ret(ptr noalias sret(%Large) align 8 %0, i32 signe define void @test.f_vec_large_v32i8(ptr align 32 %0) define void @test.f_vec_large_v32i8_ret(ptr noalias sret(<32 x i8>) align 32 %0) define signext i32 @test.f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr align 8 %3, i8 zeroext %4, i8 signext %5, i8 %6, i8 %7) -define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) #0 { +define signext i32 @test.f_scalar_stack_2(i32 signext %0, i128 %1, i64 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) define void @test.f_scalar_stack_3(ptr noalias sret(%Large) align 8 %0, i32 signext %1, i128 %2, fp128 %3, ptr align 32 %4, i8 zeroext %5, i8 %6, i8 %7) -declare signext i32 @test.f_va_callee(i32 signext, ...) #0 +declare signext i32 @f_va_callee(i32 signext, ...) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg, ptr align 8 %literal3, i32 32, i1 false) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) -call i32 (i32, ...) @test.f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double 4.000000e+00, double 5.000000e+00, i64 %4, [2 x i64] %7, i128 %9, ptr align 8 %indirectarg) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, fp128 %15, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 %18, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, [2 x i64] %22, i32 signext 6, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, fp128 %24, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i128 %27, i32 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, [2 x i64] %31, i32 signext 7, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, fp128 %33, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i128 %36, i32 8, i32 9) +call i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, [2 x i64] %40, i32 8, i32 9) diff --git a/test/test_suite/arrays/global_init.c3t b/test/test_suite/arrays/global_init.c3t index cab5a2640..7bfe9f313 100644 --- a/test/test_suite/arrays/global_init.c3t +++ b/test/test_suite/arrays/global_init.c3t @@ -14,8 +14,8 @@ int *bf3 = &abc[2] + 2; fn void main() { int *bf34 = (&abc[2] + 2) + 3; - static variant[3] x = { &&42, &&'c', &&"for" }; - variant[3] y = { &&42, &&'c', &&"for" }; + static any[3] x = { &&42, &&'c', &&"for" }; + any[3] y = { &&42, &&'c', &&"for" }; } /* #expect: test.ll @@ -33,30 +33,30 @@ fn void main() { @.taddr.9 = private global i32 42, align 4 @.taddr.10 = private global i8 99, align 1 @.taddr.11 = private global %"char[]" { ptr @.str, i64 3 }, align 8 -@"main$x" = internal unnamed_addr global [3 x %variant] [%variant { ptr @.taddr.9, i64 ptrtoint (ptr @"$ct.int" to i64) }, %variant { ptr @.taddr.10, i64 ptrtoint (ptr @"$ct.char" to i64) }, %variant { ptr @.taddr.11, i64 ptrtoint (ptr @"$ct.String" to i64) }], align 16 +@"main$x" = internal unnamed_addr global [3 x %any] [%any { ptr @.taddr.9, i64 ptrtoint (ptr @"$ct.int" to i64) }, %any { ptr @.taddr.10, i64 ptrtoint (ptr @"$ct.char" to i64) }, %any { ptr @.taddr.11, i64 ptrtoint (ptr @"$ct.String" to i64) }], align 16 define void @test.main() #0 { entry: %bf34 = alloca ptr, align 8 - %y = alloca [3 x %variant], align 16 + %y = alloca [3 x %any], align 16 %taddr = alloca i32, align 4 %taddr1 = alloca i8, align 1 %taddr2 = alloca %"char[]", align 8 store ptr getelementptr ([3 x i32], ptr @test.abc, i64 2, i64 1), ptr %bf34, align 8 - %0 = getelementptr inbounds [3 x %variant], ptr %y, i64 0, i64 0 + %0 = getelementptr inbounds [3 x %any], ptr %y, i64 0, i64 0 store i32 42, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %2, ptr %0, align 16 - %3 = getelementptr inbounds [3 x %variant], ptr %y, i64 0, i64 1 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %2, ptr %0, align 16 + %3 = getelementptr inbounds [3 x %any], ptr %y, i64 0, i64 1 store i8 99, ptr %taddr1, align 1 - %4 = insertvalue %variant undef, ptr %taddr1, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - store %variant %5, ptr %3, align 16 - %6 = getelementptr inbounds [3 x %variant], ptr %y, i64 0, i64 2 + %4 = insertvalue %any undef, ptr %taddr1, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + store %any %5, ptr %3, align 16 + %6 = getelementptr inbounds [3 x %any], ptr %y, i64 0, i64 2 store %"char[]" { ptr @.str.12, i64 3 }, ptr %taddr2, align 8 - %7 = insertvalue %variant undef, ptr %taddr2, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - store %variant %8, ptr %6, align 16 + %7 = insertvalue %any undef, ptr %taddr2, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + store %any %8, ptr %6, align 16 ret void } diff --git a/test/test_suite/assert/local_static_assert_not_constant.c3 b/test/test_suite/assert/local_static_assert_not_constant.c3 index cc02a64ca..c75ffc30a 100644 --- a/test/test_suite/assert/local_static_assert_not_constant.c3 +++ b/test/test_suite/assert/local_static_assert_not_constant.c3 @@ -12,7 +12,7 @@ fn void test2() $assert(i == 0); // #error: Compile time evaluation requires a compile time constant value. } -fn int foo(); +extern fn int foo(); fn void test3() { int i = 0; diff --git a/test/test_suite/assert/unreachable.c3t b/test/test_suite/assert/unreachable.c3t index 5d289ac2b..1d3d66b60 100644 --- a/test/test_suite/assert/unreachable.c3t +++ b/test/test_suite/assert/unreachable.c3t @@ -18,23 +18,27 @@ fn void test() define void @unreachable.test() #0 { entry: %x = alloca i32, align 4 + %string = alloca %"char[]", align 8 + %indirectarg = alloca %"any[]", align 8 %0 = call i32 @unreachable.foo() store i32 %0, ptr %x, align 4 %1 = load i32, ptr %x, align 4 %gt = icmp sgt i32 %1, 0 br i1 %gt, label %if.then, label %if.exit - if.then: ; preds = %entry ret void - if.exit: ; preds = %entry - %2 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %2(ptr @.str, i64 30, ptr @.str.1, i64 14, ptr @.str.2, i64 4, i32 10) + store %"char[]" { ptr @.str, i64 30 }, ptr %string, align 8 + %2 = getelementptr inbounds %"char[]", ptr %string, i32 0, i32 0 + %lo = load ptr, ptr %2, align 8 + %3 = getelementptr inbounds %"char[]", ptr %string, i32 0, i32 1 + %hi = load i64, ptr %3, align 8 + store %"any[]" zeroinitializer, ptr %indirectarg, align 8 + call void @std.core.builtin.panicf(ptr %lo, i64 %hi, ptr @.str.1, i64 14, ptr @.str.2, i64 4, i32 10, ptr byval(%"any[]") align 8 %indirectarg) unreachable - after.unreachable: ; No predecessors! - %3 = load i32, ptr %x, align 4 - %add = add i32 %3, 1 + %4 = load i32, ptr %x, align 4 + %add = add i32 %4, 1 store i32 %add, ptr %x, align 4 ret void } diff --git a/test/test_suite/attributes/attribute_params.c3 b/test/test_suite/attributes/attribute_params.c3 new file mode 100644 index 000000000..714a915d3 --- /dev/null +++ b/test/test_suite/attributes/attribute_params.c3 @@ -0,0 +1,7 @@ +define @Foo() = { @inline }; // #error: At least one parameter was expected +define @Bar = { @inline }; + +fn void test1() @Foo { } +fn void test2() @Foo() { } // #error: An expression was +fn void test3() @Bar { } +fn void test4() @Bar() { } // #error: An expression was \ No newline at end of file diff --git a/test/test_suite/bitstruct/bitstruct_be.c3t b/test/test_suite/bitstruct/bitstruct_be.c3t index 7c7739927..a18f7705a 100644 --- a/test/test_suite/bitstruct/bitstruct_be.c3t +++ b/test/test_suite/bitstruct/bitstruct_be.c3t @@ -46,17 +46,17 @@ fn void main() %0 = load i32, ptr %x, align 4 %1 = call i32 @llvm.bswap.i32(i32 %0) store i32 2063597568, ptr %x, align 4 - %2 = insertvalue %variant undef, ptr %x, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %4 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %3, ptr %4, align 16 + %2 = insertvalue %any undef, ptr %x, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %4 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %3, ptr %4, align 16 %5 = load i32, ptr %x, align 4 %6 = call i32 @llvm.bswap.i32(i32 %5) store i32 %6, ptr %taddr, align 4 - %7 = insertvalue %variant undef, ptr %taddr, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %9 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %8, ptr %9, align 16 + %7 = insertvalue %any undef, ptr %taddr, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %9 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %8, ptr %9, align 16 %10 = call i64 @std.io.printf(ptr %retparam, ptr @.str, i64 18, ptr %varargslots, i64 2) store i32 873625686, ptr %abc, align 4 store [4 x i8] c"\124Vx", ptr %abc2, align 1 @@ -78,10 +78,10 @@ loop.body: ; preds = %loop.cond %15 = getelementptr inbounds [4 x i8], ptr %13, i64 0, i64 %14 %16 = load i8, ptr %15, align 1 store i8 %16, ptr %d, align 1 - %17 = insertvalue %variant undef, ptr %d, 0 - %18 = insertvalue %variant %17, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %19 = getelementptr inbounds [1 x %variant], ptr %varargslots3, i64 0, i64 0 - store %variant %18, ptr %19, align 16 + %17 = insertvalue %any undef, ptr %d, 0 + %18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %19 = getelementptr inbounds [1 x %any], ptr %varargslots3, i64 0, i64 0 + store %any %18, ptr %19, align 16 %20 = call i64 @std.io.printf(ptr %retparam2, ptr @.str.1, i64 3, ptr %varargslots3, i64 1) %21 = load i64, ptr %.anon1, align 8 %add = add i64 %21, 1 @@ -114,10 +114,10 @@ loop.body10: ; preds = %loop.cond8 %31 = getelementptr inbounds [4 x i8], ptr %29, i64 0, i64 %30 %32 = load i8, ptr %31, align 1 store i8 %32, ptr %d11, align 1 - %33 = insertvalue %variant undef, ptr %d11, 0 - %34 = insertvalue %variant %33, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %35 = getelementptr inbounds [1 x %variant], ptr %varargslots13, i64 0, i64 0 - store %variant %34, ptr %35, align 16 + %33 = insertvalue %any undef, ptr %d11, 0 + %34 = insertvalue %any %33, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %35 = getelementptr inbounds [1 x %any], ptr %varargslots13, i64 0, i64 0 + store %any %34, ptr %35, align 16 %36 = call i64 @std.io.printf(ptr %retparam12, ptr @.str.2, i64 3, ptr %varargslots13, i64 1) %37 = load i64, ptr %.anon7, align 8 %add14 = add i64 %37, 1 @@ -139,10 +139,10 @@ loop.exit15: ; preds = %loop.cond8 %45 = and i32 65535, %44 %trunc = trunc i32 %45 to i16 store i16 %trunc, ptr %taddr23, align 2 - %46 = insertvalue %variant undef, ptr %taddr23, 0 - %47 = insertvalue %variant %46, i64 ptrtoint (ptr @"$ct.ushort" to i64), 1 - %48 = getelementptr inbounds [1 x %variant], ptr %varargslots22, i64 0, i64 0 - store %variant %47, ptr %48, align 16 + %46 = insertvalue %any undef, ptr %taddr23, 0 + %47 = insertvalue %any %46, i64 ptrtoint (ptr @"$ct.ushort" to i64), 1 + %48 = getelementptr inbounds [1 x %any], ptr %varargslots22, i64 0, i64 0 + store %any %47, ptr %48, align 16 %49 = call i64 @std.io.printfn(ptr %retparam21, ptr @.str.3, i64 10, ptr %varargslots22, i64 1) %50 = load i32, ptr %abc, align 4 %51 = call i32 @llvm.bswap.i32(i32 %50) @@ -161,10 +161,10 @@ loop.exit15: ; preds = %loop.cond8 %62 = and i32 65535, %61 %trunc26 = trunc i32 %62 to i16 store i16 %trunc26, ptr %taddr27, align 2 - %63 = insertvalue %variant undef, ptr %taddr27, 0 - %64 = insertvalue %variant %63, i64 ptrtoint (ptr @"$ct.ushort" to i64), 1 - %65 = getelementptr inbounds [1 x %variant], ptr %varargslots25, i64 0, i64 0 - store %variant %64, ptr %65, align 16 + %63 = insertvalue %any undef, ptr %taddr27, 0 + %64 = insertvalue %any %63, i64 ptrtoint (ptr @"$ct.ushort" to i64), 1 + %65 = getelementptr inbounds [1 x %any], ptr %varargslots25, i64 0, i64 0 + store %any %64, ptr %65, align 16 %66 = call i64 @std.io.printfn(ptr %retparam24, ptr @.str.4, i64 12, ptr %varargslots25, i64 1) %67 = load ptr, ptr %z, align 8 store ptr %67, ptr %.anon28, align 8 @@ -182,10 +182,10 @@ loop.body32: ; preds = %loop.cond30 %71 = getelementptr inbounds [4 x i8], ptr %69, i64 0, i64 %70 %72 = load i8, ptr %71, align 1 store i8 %72, ptr %d33, align 1 - %73 = insertvalue %variant undef, ptr %d33, 0 - %74 = insertvalue %variant %73, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %75 = getelementptr inbounds [1 x %variant], ptr %varargslots35, i64 0, i64 0 - store %variant %74, ptr %75, align 16 + %73 = insertvalue %any undef, ptr %d33, 0 + %74 = insertvalue %any %73, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %75 = getelementptr inbounds [1 x %any], ptr %varargslots35, i64 0, i64 0 + store %any %74, ptr %75, align 16 %76 = call i64 @std.io.printf(ptr %retparam34, ptr @.str.5, i64 3, ptr %varargslots35, i64 1) %77 = load i64, ptr %.anon29, align 8 %add36 = add i64 %77, 1 @@ -205,16 +205,16 @@ loop.exit37: ; preds = %loop.cond30 store i32 0, ptr %y, align 4 %83 = load i32, ptr %y, align 4 store i32 123, ptr %y, align 4 - %84 = insertvalue %variant undef, ptr %y, 0 - %85 = insertvalue %variant %84, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %86 = getelementptr inbounds [2 x %variant], ptr %varargslots44, i64 0, i64 0 - store %variant %85, ptr %86, align 16 + %84 = insertvalue %any undef, ptr %y, 0 + %85 = insertvalue %any %84, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %86 = getelementptr inbounds [2 x %any], ptr %varargslots44, i64 0, i64 0 + store %any %85, ptr %86, align 16 %87 = load i32, ptr %y, align 4 store i32 %87, ptr %taddr45, align 4 - %88 = insertvalue %variant undef, ptr %taddr45, 0 - %89 = insertvalue %variant %88, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %90 = getelementptr inbounds [2 x %variant], ptr %varargslots44, i64 0, i64 1 - store %variant %89, ptr %90, align 16 + %88 = insertvalue %any undef, ptr %taddr45, 0 + %89 = insertvalue %any %88, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %90 = getelementptr inbounds [2 x %any], ptr %varargslots44, i64 0, i64 1 + store %any %89, ptr %90, align 16 %91 = call i64 @std.io.printf(ptr %retparam43, ptr @.str.6, i64 18, ptr %varargslots44, i64 2) ret void } \ No newline at end of file diff --git a/test/test_suite/bitstruct/bitstruct_initializer.c3t b/test/test_suite/bitstruct/bitstruct_initializer.c3t index be906da49..6e01a7ae1 100644 --- a/test/test_suite/bitstruct/bitstruct_initializer.c3t +++ b/test/test_suite/bitstruct/bitstruct_initializer.c3t @@ -55,32 +55,32 @@ entry: %d = alloca %Abc, align 8 %b = alloca [8 x i8], align 1 %retparam = alloca i64, align 8 - %varargslots = alloca [3 x %variant], align 16 + %varargslots = alloca [3 x %any], align 16 %taddr = alloca i32, align 4 %taddr13 = alloca i32, align 4 %taddr16 = alloca i8, align 1 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [3 x %variant], align 16 + %varargslots18 = alloca [3 x %any], align 16 %taddr20 = alloca i32, align 4 %taddr23 = alloca i32, align 4 %taddr26 = alloca i8, align 1 %retparam27 = alloca i64, align 8 - %varargslots28 = alloca [3 x %variant], align 16 + %varargslots28 = alloca [3 x %any], align 16 %taddr36 = alloca i32, align 4 %taddr44 = alloca i32, align 4 %taddr46 = alloca i8, align 1 %retparam61 = alloca i64, align 8 - %varargslots62 = alloca [3 x %variant], align 16 + %varargslots62 = alloca [3 x %any], align 16 %taddr64 = alloca i32, align 4 %taddr67 = alloca i32, align 4 %taddr70 = alloca i8, align 1 %retparam71 = alloca i64, align 8 - %varargslots72 = alloca [3 x %variant], align 16 + %varargslots72 = alloca [3 x %any], align 16 %taddr74 = alloca i32, align 4 %taddr77 = alloca i32, align 4 %taddr80 = alloca i8, align 1 %retparam81 = alloca i64, align 8 - %varargslots82 = alloca [3 x %variant], align 16 + %varargslots82 = alloca [3 x %any], align 16 %taddr90 = alloca i32, align 4 %taddr98 = alloca i32, align 4 %taddr100 = alloca i8, align 1 @@ -157,58 +157,58 @@ entry: %32 = and i64 4294967295, %31 %trunc10 = trunc i64 %32 to i32 store i32 %trunc10, ptr %taddr, align 4 - %33 = insertvalue %variant undef, ptr %taddr, 0 - %34 = insertvalue %variant %33, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %35 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %34, ptr %35, align 16 + %33 = insertvalue %any undef, ptr %taddr, 0 + %34 = insertvalue %any %33, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %35 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 0 + store %any %34, ptr %35, align 16 %36 = load i64, ptr %x, align 8 %lshrl11 = lshr i64 %36, 32 %37 = and i64 2147483647, %lshrl11 %trunc12 = trunc i64 %37 to i32 store i32 %trunc12, ptr %taddr13, align 4 - %38 = insertvalue %variant undef, ptr %taddr13, 0 - %39 = insertvalue %variant %38, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %40 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %39, ptr %40, align 16 + %38 = insertvalue %any undef, ptr %taddr13, 0 + %39 = insertvalue %any %38, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %40 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 1 + store %any %39, ptr %40, align 16 %41 = load i64, ptr %x, align 8 %lshrl14 = lshr i64 %41, 63 %42 = and i64 1, %lshrl14 %trunc15 = trunc i64 %42 to i8 store i8 %trunc15, ptr %taddr16, align 1 - %43 = insertvalue %variant undef, ptr %taddr16, 0 - %44 = insertvalue %variant %43, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %45 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 2 - store %variant %44, ptr %45, align 16 + %43 = insertvalue %any undef, ptr %taddr16, 0 + %44 = insertvalue %any %43, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %45 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 2 + store %any %44, ptr %45, align 16 %46 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 3) %47 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %48 = load i64, ptr %47, align 8 %49 = and i64 4294967295, %48 %trunc19 = trunc i64 %49 to i32 store i32 %trunc19, ptr %taddr20, align 4 - %50 = insertvalue %variant undef, ptr %taddr20, 0 - %51 = insertvalue %variant %50, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %52 = getelementptr inbounds [3 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %51, ptr %52, align 16 + %50 = insertvalue %any undef, ptr %taddr20, 0 + %51 = insertvalue %any %50, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %52 = getelementptr inbounds [3 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %51, ptr %52, align 16 %53 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %54 = load i64, ptr %53, align 8 %lshrl21 = lshr i64 %54, 32 %55 = and i64 2147483647, %lshrl21 %trunc22 = trunc i64 %55 to i32 store i32 %trunc22, ptr %taddr23, align 4 - %56 = insertvalue %variant undef, ptr %taddr23, 0 - %57 = insertvalue %variant %56, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %58 = getelementptr inbounds [3 x %variant], ptr %varargslots18, i64 0, i64 1 - store %variant %57, ptr %58, align 16 + %56 = insertvalue %any undef, ptr %taddr23, 0 + %57 = insertvalue %any %56, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %58 = getelementptr inbounds [3 x %any], ptr %varargslots18, i64 0, i64 1 + store %any %57, ptr %58, align 16 %59 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %60 = load i64, ptr %59, align 8 %lshrl24 = lshr i64 %60, 63 %61 = and i64 1, %lshrl24 %trunc25 = trunc i64 %61 to i8 store i8 %trunc25, ptr %taddr26, align 1 - %62 = insertvalue %variant undef, ptr %taddr26, 0 - %63 = insertvalue %variant %62, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %64 = getelementptr inbounds [3 x %variant], ptr %varargslots18, i64 0, i64 2 - store %variant %63, ptr %64, align 16 + %62 = insertvalue %any undef, ptr %taddr26, 0 + %63 = insertvalue %any %62, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %64 = getelementptr inbounds [3 x %any], ptr %varargslots18, i64 0, i64 2 + store %any %63, ptr %64, align 16 %65 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.2, i64 8, ptr %varargslots18, i64 3) %66 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 0 %67 = load i8, ptr %66, align 1 @@ -229,10 +229,10 @@ entry: %shl35 = shl i32 %zext34, 24 %76 = or i32 %shl35, %73 store i32 %76, ptr %taddr36, align 4 - %77 = insertvalue %variant undef, ptr %taddr36, 0 - %78 = insertvalue %variant %77, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %79 = getelementptr inbounds [3 x %variant], ptr %varargslots28, i64 0, i64 0 - store %variant %78, ptr %79, align 16 + %77 = insertvalue %any undef, ptr %taddr36, 0 + %78 = insertvalue %any %77, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %79 = getelementptr inbounds [3 x %any], ptr %varargslots28, i64 0, i64 0 + store %any %78, ptr %79, align 16 %80 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 4 %81 = load i8, ptr %80, align 1 %zext37 = zext i8 %81 to i32 @@ -253,20 +253,20 @@ entry: %90 = or i32 %shl43, %87 %91 = and i32 2147483647, %90 store i32 %91, ptr %taddr44, align 4 - %92 = insertvalue %variant undef, ptr %taddr44, 0 - %93 = insertvalue %variant %92, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %94 = getelementptr inbounds [3 x %variant], ptr %varargslots28, i64 0, i64 1 - store %variant %93, ptr %94, align 16 + %92 = insertvalue %any undef, ptr %taddr44, 0 + %93 = insertvalue %any %92, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %94 = getelementptr inbounds [3 x %any], ptr %varargslots28, i64 0, i64 1 + store %any %93, ptr %94, align 16 %95 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 7 %96 = load i8, ptr %95, align 1 %lshrl45 = lshr i8 %96, 7 %97 = trunc i8 %lshrl45 to i1 %98 = zext i1 %97 to i8 store i8 %98, ptr %taddr46, align 1 - %99 = insertvalue %variant undef, ptr %taddr46, 0 - %100 = insertvalue %variant %99, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %101 = getelementptr inbounds [3 x %variant], ptr %varargslots28, i64 0, i64 2 - store %variant %100, ptr %101, align 16 + %99 = insertvalue %any undef, ptr %taddr46, 0 + %100 = insertvalue %any %99, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %101 = getelementptr inbounds [3 x %any], ptr %varargslots28, i64 0, i64 2 + store %any %100, ptr %101, align 16 %102 = call i64 @std.io.printfn(ptr %retparam27, ptr @.str.3, i64 8, ptr %varargslots28, i64 3) %add = add i32 %0, 1 %zext47 = zext i32 %add to i64 @@ -338,58 +338,58 @@ entry: %135 = and i64 4294967295, %134 %trunc63 = trunc i64 %135 to i32 store i32 %trunc63, ptr %taddr64, align 4 - %136 = insertvalue %variant undef, ptr %taddr64, 0 - %137 = insertvalue %variant %136, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %138 = getelementptr inbounds [3 x %variant], ptr %varargslots62, i64 0, i64 0 - store %variant %137, ptr %138, align 16 + %136 = insertvalue %any undef, ptr %taddr64, 0 + %137 = insertvalue %any %136, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %138 = getelementptr inbounds [3 x %any], ptr %varargslots62, i64 0, i64 0 + store %any %137, ptr %138, align 16 %139 = load i64, ptr %x, align 8 %lshrl65 = lshr i64 %139, 32 %140 = and i64 2147483647, %lshrl65 %trunc66 = trunc i64 %140 to i32 store i32 %trunc66, ptr %taddr67, align 4 - %141 = insertvalue %variant undef, ptr %taddr67, 0 - %142 = insertvalue %variant %141, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %143 = getelementptr inbounds [3 x %variant], ptr %varargslots62, i64 0, i64 1 - store %variant %142, ptr %143, align 16 + %141 = insertvalue %any undef, ptr %taddr67, 0 + %142 = insertvalue %any %141, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %143 = getelementptr inbounds [3 x %any], ptr %varargslots62, i64 0, i64 1 + store %any %142, ptr %143, align 16 %144 = load i64, ptr %x, align 8 %lshrl68 = lshr i64 %144, 63 %145 = and i64 1, %lshrl68 %trunc69 = trunc i64 %145 to i8 store i8 %trunc69, ptr %taddr70, align 1 - %146 = insertvalue %variant undef, ptr %taddr70, 0 - %147 = insertvalue %variant %146, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %148 = getelementptr inbounds [3 x %variant], ptr %varargslots62, i64 0, i64 2 - store %variant %147, ptr %148, align 16 + %146 = insertvalue %any undef, ptr %taddr70, 0 + %147 = insertvalue %any %146, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %148 = getelementptr inbounds [3 x %any], ptr %varargslots62, i64 0, i64 2 + store %any %147, ptr %148, align 16 %149 = call i64 @std.io.printfn(ptr %retparam61, ptr @.str.4, i64 8, ptr %varargslots62, i64 3) %150 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %151 = load i64, ptr %150, align 8 %152 = and i64 4294967295, %151 %trunc73 = trunc i64 %152 to i32 store i32 %trunc73, ptr %taddr74, align 4 - %153 = insertvalue %variant undef, ptr %taddr74, 0 - %154 = insertvalue %variant %153, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %155 = getelementptr inbounds [3 x %variant], ptr %varargslots72, i64 0, i64 0 - store %variant %154, ptr %155, align 16 + %153 = insertvalue %any undef, ptr %taddr74, 0 + %154 = insertvalue %any %153, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %155 = getelementptr inbounds [3 x %any], ptr %varargslots72, i64 0, i64 0 + store %any %154, ptr %155, align 16 %156 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %157 = load i64, ptr %156, align 8 %lshrl75 = lshr i64 %157, 32 %158 = and i64 2147483647, %lshrl75 %trunc76 = trunc i64 %158 to i32 store i32 %trunc76, ptr %taddr77, align 4 - %159 = insertvalue %variant undef, ptr %taddr77, 0 - %160 = insertvalue %variant %159, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %161 = getelementptr inbounds [3 x %variant], ptr %varargslots72, i64 0, i64 1 - store %variant %160, ptr %161, align 16 + %159 = insertvalue %any undef, ptr %taddr77, 0 + %160 = insertvalue %any %159, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %161 = getelementptr inbounds [3 x %any], ptr %varargslots72, i64 0, i64 1 + store %any %160, ptr %161, align 16 %162 = getelementptr inbounds %Abc, ptr %y, i32 0, i32 1 %163 = load i64, ptr %162, align 8 %lshrl78 = lshr i64 %163, 63 %164 = and i64 1, %lshrl78 %trunc79 = trunc i64 %164 to i8 store i8 %trunc79, ptr %taddr80, align 1 - %165 = insertvalue %variant undef, ptr %taddr80, 0 - %166 = insertvalue %variant %165, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %167 = getelementptr inbounds [3 x %variant], ptr %varargslots72, i64 0, i64 2 - store %variant %166, ptr %167, align 16 + %165 = insertvalue %any undef, ptr %taddr80, 0 + %166 = insertvalue %any %165, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %167 = getelementptr inbounds [3 x %any], ptr %varargslots72, i64 0, i64 2 + store %any %166, ptr %167, align 16 %168 = call i64 @std.io.printfn(ptr %retparam71, ptr @.str.5, i64 8, ptr %varargslots72, i64 3) %169 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 0 %170 = load i8, ptr %169, align 1 @@ -410,10 +410,10 @@ entry: %shl89 = shl i32 %zext88, 24 %179 = or i32 %shl89, %176 store i32 %179, ptr %taddr90, align 4 - %180 = insertvalue %variant undef, ptr %taddr90, 0 - %181 = insertvalue %variant %180, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %182 = getelementptr inbounds [3 x %variant], ptr %varargslots82, i64 0, i64 0 - store %variant %181, ptr %182, align 16 + %180 = insertvalue %any undef, ptr %taddr90, 0 + %181 = insertvalue %any %180, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %182 = getelementptr inbounds [3 x %any], ptr %varargslots82, i64 0, i64 0 + store %any %181, ptr %182, align 16 %183 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 4 %184 = load i8, ptr %183, align 1 %zext91 = zext i8 %184 to i32 @@ -434,20 +434,20 @@ entry: %193 = or i32 %shl97, %190 %194 = and i32 2147483647, %193 store i32 %194, ptr %taddr98, align 4 - %195 = insertvalue %variant undef, ptr %taddr98, 0 - %196 = insertvalue %variant %195, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %197 = getelementptr inbounds [3 x %variant], ptr %varargslots82, i64 0, i64 1 - store %variant %196, ptr %197, align 16 + %195 = insertvalue %any undef, ptr %taddr98, 0 + %196 = insertvalue %any %195, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %197 = getelementptr inbounds [3 x %any], ptr %varargslots82, i64 0, i64 1 + store %any %196, ptr %197, align 16 %198 = getelementptr inbounds [8 x i8], ptr %b, i64 0, i64 7 %199 = load i8, ptr %198, align 1 %lshrl99 = lshr i8 %199, 7 %200 = trunc i8 %lshrl99 to i1 %201 = zext i1 %200 to i8 store i8 %201, ptr %taddr100, align 1 - %202 = insertvalue %variant undef, ptr %taddr100, 0 - %203 = insertvalue %variant %202, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %204 = getelementptr inbounds [3 x %variant], ptr %varargslots82, i64 0, i64 2 - store %variant %203, ptr %204, align 16 + %202 = insertvalue %any undef, ptr %taddr100, 0 + %203 = insertvalue %any %202, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %204 = getelementptr inbounds [3 x %any], ptr %varargslots82, i64 0, i64 2 + store %any %203, ptr %204, align 16 %205 = call i64 @std.io.printfn(ptr %retparam81, ptr @.str.6, i64 8, ptr %varargslots82, i64 3) ret void } diff --git a/test/test_suite/bitstruct/bitstruct_ops.c3t b/test/test_suite/bitstruct/bitstruct_ops.c3t index 691d6b8a9..e822e272f 100644 --- a/test/test_suite/bitstruct/bitstruct_ops.c3t +++ b/test/test_suite/bitstruct/bitstruct_ops.c3t @@ -48,21 +48,21 @@ entry: %f2 = alloca i32, align 4 %f3 = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %taddr = alloca i8, align 1 %taddr2 = alloca i8, align 1 %f4 = alloca i32, align 4 %retparam3 = alloca i64, align 8 - %varargslots4 = alloca [2 x %variant], align 16 + %varargslots4 = alloca [2 x %any], align 16 %taddr6 = alloca i8, align 1 %taddr9 = alloca i8, align 1 %f5 = alloca i32, align 4 %retparam10 = alloca i64, align 8 - %varargslots11 = alloca [2 x %variant], align 16 + %varargslots11 = alloca [2 x %any], align 16 %taddr13 = alloca i8, align 1 %taddr16 = alloca i8, align 1 %retparam18 = alloca i64, align 8 - %varargslots19 = alloca [2 x %variant], align 16 + %varargslots19 = alloca [2 x %any], align 16 %taddr21 = alloca i8, align 1 %taddr24 = alloca i8, align 1 %b1 = alloca [13 x i8], align 1 @@ -70,20 +70,20 @@ entry: %b3 = alloca [13 x i8], align 1 %0 = alloca i104, align 1 %retparam26 = alloca i64, align 8 - %varargslots27 = alloca [3 x %variant], align 16 + %varargslots27 = alloca [3 x %any], align 16 %taddr28 = alloca i8, align 1 %taddr30 = alloca i8, align 1 %taddr32 = alloca i8, align 1 %1 = alloca i104, align 1 %retparam34 = alloca i64, align 8 - %varargslots35 = alloca [3 x %variant], align 16 + %varargslots35 = alloca [3 x %any], align 16 %taddr36 = alloca i8, align 1 %taddr38 = alloca i8, align 1 %taddr40 = alloca i8, align 1 %taddr41 = alloca [13 x i8], align 1 %2 = alloca i104, align 1 %retparam43 = alloca i64, align 8 - %varargslots44 = alloca [3 x %variant], align 16 + %varargslots44 = alloca [3 x %any], align 16 %taddr45 = alloca i8, align 1 %taddr47 = alloca i8, align 1 %taddr49 = alloca i8, align 1 @@ -97,19 +97,19 @@ entry: %6 = and i32 1, %5 %trunc = trunc i32 %6 to i8 store i8 %trunc, ptr %taddr, align 1 - %7 = insertvalue %variant undef, ptr %taddr, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %9 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %8, ptr %9, align 16 + %7 = insertvalue %any undef, ptr %taddr, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %9 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %8, ptr %9, align 16 %10 = load i32, ptr %f3, align 4 %lshrl = lshr i32 %10, 1 %11 = and i32 1, %lshrl %trunc1 = trunc i32 %11 to i8 store i8 %trunc1, ptr %taddr2, align 1 - %12 = insertvalue %variant undef, ptr %taddr2, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %14 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %13, ptr %14, align 16 + %12 = insertvalue %any undef, ptr %taddr2, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %14 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %13, ptr %14, align 16 %15 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 5, ptr %varargslots, i64 2) %16 = load i32, ptr %f1, align 4 %17 = load i32, ptr %f2, align 4 @@ -122,38 +122,38 @@ entry: %20 = and i32 1, %19 %trunc5 = trunc i32 %20 to i8 store i8 %trunc5, ptr %taddr6, align 1 - %21 = insertvalue %variant undef, ptr %taddr6, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %23 = getelementptr inbounds [2 x %variant], ptr %varargslots4, i64 0, i64 0 - store %variant %22, ptr %23, align 16 + %21 = insertvalue %any undef, ptr %taddr6, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %23 = getelementptr inbounds [2 x %any], ptr %varargslots4, i64 0, i64 0 + store %any %22, ptr %23, align 16 %24 = load i32, ptr %f4, align 4 %lshrl7 = lshr i32 %24, 1 %25 = and i32 1, %lshrl7 %trunc8 = trunc i32 %25 to i8 store i8 %trunc8, ptr %taddr9, align 1 - %26 = insertvalue %variant undef, ptr %taddr9, 0 - %27 = insertvalue %variant %26, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %28 = getelementptr inbounds [2 x %variant], ptr %varargslots4, i64 0, i64 1 - store %variant %27, ptr %28, align 16 + %26 = insertvalue %any undef, ptr %taddr9, 0 + %27 = insertvalue %any %26, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %28 = getelementptr inbounds [2 x %any], ptr %varargslots4, i64 0, i64 1 + store %any %27, ptr %28, align 16 %29 = call i64 @std.io.printfn(ptr %retparam3, ptr @.str.1, i64 5, ptr %varargslots4, i64 2) store i32 3, ptr %f5, align 4 %30 = load i32, ptr %f5, align 4 %31 = and i32 1, %30 %trunc12 = trunc i32 %31 to i8 store i8 %trunc12, ptr %taddr13, align 1 - %32 = insertvalue %variant undef, ptr %taddr13, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %34 = getelementptr inbounds [2 x %variant], ptr %varargslots11, i64 0, i64 0 - store %variant %33, ptr %34, align 16 + %32 = insertvalue %any undef, ptr %taddr13, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %34 = getelementptr inbounds [2 x %any], ptr %varargslots11, i64 0, i64 0 + store %any %33, ptr %34, align 16 %35 = load i32, ptr %f5, align 4 %lshrl14 = lshr i32 %35, 1 %36 = and i32 1, %lshrl14 %trunc15 = trunc i32 %36 to i8 store i8 %trunc15, ptr %taddr16, align 1 - %37 = insertvalue %variant undef, ptr %taddr16, 0 - %38 = insertvalue %variant %37, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %39 = getelementptr inbounds [2 x %variant], ptr %varargslots11, i64 0, i64 1 - store %variant %38, ptr %39, align 16 + %37 = insertvalue %any undef, ptr %taddr16, 0 + %38 = insertvalue %any %37, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %39 = getelementptr inbounds [2 x %any], ptr %varargslots11, i64 0, i64 1 + store %any %38, ptr %39, align 16 %40 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.2, i64 5, ptr %varargslots11, i64 2) %41 = load i32, ptr %f5, align 4 %42 = load i32, ptr %f2, align 4 @@ -163,19 +163,19 @@ entry: %44 = and i32 1, %43 %trunc20 = trunc i32 %44 to i8 store i8 %trunc20, ptr %taddr21, align 1 - %45 = insertvalue %variant undef, ptr %taddr21, 0 - %46 = insertvalue %variant %45, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %47 = getelementptr inbounds [2 x %variant], ptr %varargslots19, i64 0, i64 0 - store %variant %46, ptr %47, align 16 + %45 = insertvalue %any undef, ptr %taddr21, 0 + %46 = insertvalue %any %45, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %47 = getelementptr inbounds [2 x %any], ptr %varargslots19, i64 0, i64 0 + store %any %46, ptr %47, align 16 %48 = load i32, ptr %f5, align 4 %lshrl22 = lshr i32 %48, 1 %49 = and i32 1, %lshrl22 %trunc23 = trunc i32 %49 to i8 store i8 %trunc23, ptr %taddr24, align 1 - %50 = insertvalue %variant undef, ptr %taddr24, 0 - %51 = insertvalue %variant %50, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %52 = getelementptr inbounds [2 x %variant], ptr %varargslots19, i64 0, i64 1 - store %variant %51, ptr %52, align 16 + %50 = insertvalue %any undef, ptr %taddr24, 0 + %51 = insertvalue %any %50, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %52 = getelementptr inbounds [2 x %any], ptr %varargslots19, i64 0, i64 1 + store %any %51, ptr %52, align 16 %53 = call i64 @std.io.printfn(ptr %retparam18, ptr @.str.3, i64 5, ptr %varargslots19, i64 2) store [13 x i8] c"\03\00\00\02\00\00\00\00\00\00\00\00\00", ptr %b1, align 1 store [13 x i8] c"\01\00\00\00\00\00\00\00\00\00\00\00\00", ptr %b2, align 1 @@ -189,30 +189,30 @@ entry: %58 = trunc i8 %57 to i1 %59 = zext i1 %58 to i8 store i8 %59, ptr %taddr28, align 1 - %60 = insertvalue %variant undef, ptr %taddr28, 0 - %61 = insertvalue %variant %60, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %62 = getelementptr inbounds [3 x %variant], ptr %varargslots27, i64 0, i64 0 - store %variant %61, ptr %62, align 16 + %60 = insertvalue %any undef, ptr %taddr28, 0 + %61 = insertvalue %any %60, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %62 = getelementptr inbounds [3 x %any], ptr %varargslots27, i64 0, i64 0 + store %any %61, ptr %62, align 16 %63 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 0 %64 = load i8, ptr %63, align 1 %lshrl29 = lshr i8 %64, 1 %65 = trunc i8 %lshrl29 to i1 %66 = zext i1 %65 to i8 store i8 %66, ptr %taddr30, align 1 - %67 = insertvalue %variant undef, ptr %taddr30, 0 - %68 = insertvalue %variant %67, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %69 = getelementptr inbounds [3 x %variant], ptr %varargslots27, i64 0, i64 1 - store %variant %68, ptr %69, align 16 + %67 = insertvalue %any undef, ptr %taddr30, 0 + %68 = insertvalue %any %67, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %69 = getelementptr inbounds [3 x %any], ptr %varargslots27, i64 0, i64 1 + store %any %68, ptr %69, align 16 %70 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 3 %71 = load i8, ptr %70, align 1 %lshrl31 = lshr i8 %71, 1 %72 = trunc i8 %lshrl31 to i1 %73 = zext i1 %72 to i8 store i8 %73, ptr %taddr32, align 1 - %74 = insertvalue %variant undef, ptr %taddr32, 0 - %75 = insertvalue %variant %74, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %76 = getelementptr inbounds [3 x %variant], ptr %varargslots27, i64 0, i64 2 - store %variant %75, ptr %76, align 16 + %74 = insertvalue %any undef, ptr %taddr32, 0 + %75 = insertvalue %any %74, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %76 = getelementptr inbounds [3 x %any], ptr %varargslots27, i64 0, i64 2 + store %any %75, ptr %76, align 16 %77 = call i64 @std.io.printfn(ptr %retparam26, ptr @.str.4, i64 8, ptr %varargslots27, i64 3) %78 = load i104, ptr %b3, align 1 %bnot33 = xor i104 %78, -1 @@ -223,30 +223,30 @@ entry: %81 = trunc i8 %80 to i1 %82 = zext i1 %81 to i8 store i8 %82, ptr %taddr36, align 1 - %83 = insertvalue %variant undef, ptr %taddr36, 0 - %84 = insertvalue %variant %83, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %85 = getelementptr inbounds [3 x %variant], ptr %varargslots35, i64 0, i64 0 - store %variant %84, ptr %85, align 16 + %83 = insertvalue %any undef, ptr %taddr36, 0 + %84 = insertvalue %any %83, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %85 = getelementptr inbounds [3 x %any], ptr %varargslots35, i64 0, i64 0 + store %any %84, ptr %85, align 16 %86 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 0 %87 = load i8, ptr %86, align 1 %lshrl37 = lshr i8 %87, 1 %88 = trunc i8 %lshrl37 to i1 %89 = zext i1 %88 to i8 store i8 %89, ptr %taddr38, align 1 - %90 = insertvalue %variant undef, ptr %taddr38, 0 - %91 = insertvalue %variant %90, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %92 = getelementptr inbounds [3 x %variant], ptr %varargslots35, i64 0, i64 1 - store %variant %91, ptr %92, align 16 + %90 = insertvalue %any undef, ptr %taddr38, 0 + %91 = insertvalue %any %90, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %92 = getelementptr inbounds [3 x %any], ptr %varargslots35, i64 0, i64 1 + store %any %91, ptr %92, align 16 %93 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 3 %94 = load i8, ptr %93, align 1 %lshrl39 = lshr i8 %94, 1 %95 = trunc i8 %lshrl39 to i1 %96 = zext i1 %95 to i8 store i8 %96, ptr %taddr40, align 1 - %97 = insertvalue %variant undef, ptr %taddr40, 0 - %98 = insertvalue %variant %97, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %99 = getelementptr inbounds [3 x %variant], ptr %varargslots35, i64 0, i64 2 - store %variant %98, ptr %99, align 16 + %97 = insertvalue %any undef, ptr %taddr40, 0 + %98 = insertvalue %any %97, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %99 = getelementptr inbounds [3 x %any], ptr %varargslots35, i64 0, i64 2 + store %any %98, ptr %99, align 16 %100 = call i64 @std.io.printfn(ptr %retparam34, ptr @.str.5, i64 8, ptr %varargslots35, i64 3) store [13 x i8] c"\03\00\00\00\00\00\00\00\00\00\00\00\00", ptr %taddr41, align 1 %101 = load i104, ptr %b3, align 1 @@ -259,30 +259,30 @@ entry: %105 = trunc i8 %104 to i1 %106 = zext i1 %105 to i8 store i8 %106, ptr %taddr45, align 1 - %107 = insertvalue %variant undef, ptr %taddr45, 0 - %108 = insertvalue %variant %107, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %109 = getelementptr inbounds [3 x %variant], ptr %varargslots44, i64 0, i64 0 - store %variant %108, ptr %109, align 16 + %107 = insertvalue %any undef, ptr %taddr45, 0 + %108 = insertvalue %any %107, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %109 = getelementptr inbounds [3 x %any], ptr %varargslots44, i64 0, i64 0 + store %any %108, ptr %109, align 16 %110 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 0 %111 = load i8, ptr %110, align 1 %lshrl46 = lshr i8 %111, 1 %112 = trunc i8 %lshrl46 to i1 %113 = zext i1 %112 to i8 store i8 %113, ptr %taddr47, align 1 - %114 = insertvalue %variant undef, ptr %taddr47, 0 - %115 = insertvalue %variant %114, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %116 = getelementptr inbounds [3 x %variant], ptr %varargslots44, i64 0, i64 1 - store %variant %115, ptr %116, align 16 + %114 = insertvalue %any undef, ptr %taddr47, 0 + %115 = insertvalue %any %114, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %116 = getelementptr inbounds [3 x %any], ptr %varargslots44, i64 0, i64 1 + store %any %115, ptr %116, align 16 %117 = getelementptr inbounds [13 x i8], ptr %b3, i64 0, i64 3 %118 = load i8, ptr %117, align 1 %lshrl48 = lshr i8 %118, 1 %119 = trunc i8 %lshrl48 to i1 %120 = zext i1 %119 to i8 store i8 %120, ptr %taddr49, align 1 - %121 = insertvalue %variant undef, ptr %taddr49, 0 - %122 = insertvalue %variant %121, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %123 = getelementptr inbounds [3 x %variant], ptr %varargslots44, i64 0, i64 2 - store %variant %122, ptr %123, align 16 + %121 = insertvalue %any undef, ptr %taddr49, 0 + %122 = insertvalue %any %121, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %123 = getelementptr inbounds [3 x %any], ptr %varargslots44, i64 0, i64 2 + store %any %122, ptr %123, align 16 %124 = call i64 @std.io.printfn(ptr %retparam43, ptr @.str.6, i64 8, ptr %varargslots44, i64 3) ret void } diff --git a/test/test_suite/bitstruct/bitstruct_simple_err_decl.c3 b/test/test_suite/bitstruct/bitstruct_simple_err_decl.c3 index e809380b1..f4909c0ac 100644 --- a/test/test_suite/bitstruct/bitstruct_simple_err_decl.c3 +++ b/test/test_suite/bitstruct/bitstruct_simple_err_decl.c3 @@ -1,11 +1,11 @@ bitstruct Foo : char { bool a : 1; - bool b; // #error: Expected a ':' + bool b; // #error: remove ranges from the other member } bitstruct Foo2 : char { bool a; - bool b : 1; // #error: Expected ';' + bool b : 1; // #error: ranges to all other members } \ No newline at end of file diff --git a/test/test_suite/cast/cast_to_failable.c3 b/test/test_suite/cast/cast_to_failable.c3 index 663cb3114..ae83f6c33 100644 --- a/test/test_suite/cast/cast_to_failable.c3 +++ b/test/test_suite/cast/cast_to_failable.c3 @@ -6,7 +6,9 @@ fault MyErr fn void test() { int! x; - int! d = ($typeof(MyErr.FOO!))(x); // #error: Casting to an optional type is not allowed + double! y; + int! d = ($typeof(MyErr.FOO?))(x); // #error: This optional expression is untyped + int! df = ($typeof(y))(x); // #error: Casting to an optional type is not allowed } diff --git a/test/test_suite/clang/2002-01_02.c3t b/test/test_suite/clang/2002-01_02.c3t index c8006e7ed..527c059fa 100644 --- a/test/test_suite/clang/2002-01_02.c3t +++ b/test/test_suite/clang/2002-01_02.c3t @@ -6,7 +6,7 @@ Foo[10] array; fn void foo() {} -fn void *dlclose(void*); +extern fn void *dlclose(void*); fn void ap_os_dso_unload(void *handle) { @@ -80,7 +80,7 @@ fn int test(int x) { return x; } -fn void abc(int *x); +extern fn void abc(int *x); fn int def(int y, int z) { abc(&z); return y; @@ -154,11 +154,11 @@ entry: ret void } -declare ptr @test.dlclose(ptr) #0 +declare ptr @dlclose(ptr) #0 define void @test.ap_os_dso_unload(ptr %0) #0 { entry: - %1 = call ptr @test.dlclose(ptr %0) + %1 = call ptr @dlclose(ptr %0) ret void } @@ -201,6 +201,7 @@ entry: ret void } +; Function Attrs: nounwind define i32 @test.do_merge(ptr %0, ptr %1) #0 { entry: %lvalid = alloca i32, align 4 @@ -231,13 +232,13 @@ entry: ret i32 %0 } -declare void @test.abc(ptr) #0 +declare void @abc(ptr) #0 define i32 @test.def(i32 %0, i32 %1) #0 { entry: %z = alloca i32, align 4 store i32 %1, ptr %z, align 4 - call void @test.abc(ptr %z) + call void @abc(ptr %z) ret i32 %0 } diff --git a/test/test_suite/clang/2002-03.c3t b/test/test_suite/clang/2002-03.c3t index 3bb280f67..93b782698 100644 --- a/test/test_suite/clang/2002-03.c3t +++ b/test/test_suite/clang/2002-03.c3t @@ -1,6 +1,6 @@ // #target: macos-x64 module test; -fn int strcmp(char *s1, char *s2); +extern fn int strcmp(char *s1, char *s2); fn int test(char *x) { /* LLVM-GCC used to emit: @@ -63,11 +63,11 @@ fn char* foo() { @.str = private unnamed_addr constant [4 x i8] c"\1F\C2\8B\00", align 1 @.str.7 = private unnamed_addr constant [32 x i8] c"*** Word \22%s\22 on line %d is not\00", align 1 -declare i32 @test.strcmp(ptr, ptr) #0 +declare i32 @strcmp(ptr, ptr) #0 define i32 @test.test(ptr %0) #0 { entry: - %1 = call i32 @test.strcmp(ptr %0, ptr @.str) + %1 = call i32 @strcmp(ptr %0, ptr @.str) ret i32 %1 } diff --git a/test/test_suite/clang/2002-07.c3t b/test/test_suite/clang/2002-07.c3t index b8bc7035b..85536403b 100644 --- a/test/test_suite/clang/2002-07.c3t +++ b/test/test_suite/clang/2002-07.c3t @@ -242,7 +242,7 @@ fn int arrayToSum() { } -fn int externFunc(long, uint*, short, char); +extern fn int externFunc(long, uint*, short, char); fn int main(int argc, char **argv) { uint i @noinit; @@ -800,7 +800,7 @@ entry: %i = alloca i32, align 4 %2 = call i32 @puts(ptr @.str.10) %trunc = trunc i32 %0 to i16 - %3 = call i32 @foo.externFunc(i64 -1, ptr null, i16 signext %trunc, i8 zeroext 2) + %3 = call i32 @externFunc(i64 -1, ptr null, i16 signext %trunc, i8 zeroext 2) store i32 0, ptr %i, align 4 br label %loop.cond loop.cond: ; preds = %loop.body, %entry 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 72f5b1133..21789e452 100644 --- a/test/test_suite/compile_time/compile_time_access_subscript.c3t +++ b/test/test_suite/compile_time/compile_time_access_subscript.c3t @@ -27,10 +27,10 @@ fn void main() { var $i = int[4] { 1, 2, 3, 4 }; var $b = Abc[2] { Abc {}, Abc { 11, 22, 33, 44 }}; - var $c = variant[4] {}; + var $c = any[4] {}; check_type(int); check_type(Abc); - check_type(anyerr); + check_type(anyfault); check_type(Blurb); check_type(int*); check_type(bool); @@ -56,7 +56,7 @@ fn void main() %z9 = alloca [2 x i32], align 4 %z10 = alloca %"int[]", align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %literal = alloca %Abc, align 4 store i32 0, ptr %z, align 4 %0 = getelementptr inbounds %Abc, ptr %z1, i32 0, i32 0 @@ -94,10 +94,10 @@ fn void main() store float 0.000000e+00, ptr %12, align 4 %13 = getelementptr inbounds %Abc, ptr %literal, i32 0, i32 3 store float 0.000000e+00, ptr %13, align 4 - %14 = insertvalue %variant undef, ptr %literal, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.test.Abc" to i64), 1 - %16 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %15, ptr %16, align 16 + %14 = insertvalue %any undef, ptr %literal, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.test.Abc" to i64), 1 + %16 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %15, ptr %16, align 16 %17 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) ret void } diff --git a/test/test_suite/compile_time/ct_builtin_time_date.c3t b/test/test_suite/compile_time/ct_builtin_time_date.c3t index 24f81660d..9bd5d7c19 100644 --- a/test/test_suite/compile_time/ct_builtin_time_date.c3t +++ b/test/test_suite/compile_time/ct_builtin_time_date.c3t @@ -29,7 +29,7 @@ fn void main() define void @test.test(i32 %0) #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 %x = alloca %"char[]", align 8 %retparam1 = alloca i64, align 8 @@ -38,10 +38,10 @@ entry: %retparam3 = alloca i64, align 8 %result4 = alloca %File, align 8 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %taddr9 = alloca i64, align 8 %retparam10 = alloca i64, align 8 - %varargslots11 = alloca [1 x %variant], align 16 + %varargslots11 = alloca [1 x %any], align 16 %taddr12 = alloca i64, align 8 %x13 = alloca %"char[]", align 8 %retparam14 = alloca i64, align 8 @@ -50,10 +50,10 @@ entry: %retparam19 = alloca i64, align 8 %result20 = alloca %File, align 8 store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) %gt = icmp sgt i32 %0, 0 br i1 %gt, label %if.then, label %if.exit @@ -81,16 +81,16 @@ if.exit: ; preds = %if.then, %entry %hi6 = load i64, ptr %13, align 8 %14 = call i64 @std.io.File.printn(ptr %retparam3, ptr %11, ptr %lo5, i64 %hi6) store i64 14, ptr %taddr9, align 8 - %15 = insertvalue %variant undef, ptr %taddr9, 0 - %16 = insertvalue %variant %15, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %17 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %16, ptr %17, align 16 + %15 = insertvalue %any undef, ptr %taddr9, 0 + %16 = insertvalue %any %15, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %17 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %16, ptr %17, align 16 %18 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.3, i64 2, ptr %varargslots8, i64 1) store i64 6, ptr %taddr12, align 8 - %19 = insertvalue %variant undef, ptr %taddr12, 0 - %20 = insertvalue %variant %19, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %21 = getelementptr inbounds [1 x %variant], ptr %varargslots11, i64 0, i64 0 - store %variant %20, ptr %21, align 16 + %19 = insertvalue %any undef, ptr %taddr12, 0 + %20 = insertvalue %any %19, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %21 = getelementptr inbounds [1 x %any], ptr %varargslots11, i64 0, i64 0 + store %any %20, ptr %21, align 16 %22 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.4, i64 2, ptr %varargslots11, i64 1) store %"char[]" { ptr @.str.5, i64 23 }, ptr %x13, align 8 %23 = call ptr @std.io.stdout() diff --git a/test/test_suite/compile_time/ct_funcptr.c3t b/test/test_suite/compile_time/ct_funcptr.c3t index 28897e2eb..fe71b50b2 100644 --- a/test/test_suite/compile_time/ct_funcptr.c3t +++ b/test/test_suite/compile_time/ct_funcptr.c3t @@ -20,14 +20,14 @@ define void @test.test(i32 %0) #0 { entry: %ptr = alloca ptr, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 store ptr @test.test, ptr %ptr, align 8 store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) %gt = icmp sgt i32 %0, 0 br i1 %gt, label %if.then, label %if.exit diff --git a/test/test_suite/compile_time/ct_memberof.c3t b/test/test_suite/compile_time/ct_memberof.c3t index 21b355de8..3d252bcbf 100644 --- a/test/test_suite/compile_time/ct_memberof.c3t +++ b/test/test_suite/compile_time/ct_memberof.c3t @@ -104,7 +104,7 @@ fn void main() define void @test.hello(i32 %0, double %1, i64 %2, i64 %3, ptr %4, i64 %5) #0 { entry: %d = alloca [4 x i32], align 8 - %args = alloca %"variant[]", align 8 + %args = alloca %"any[]", align 8 store i64 %2, ptr %d, align 8 %ptroffset = getelementptr inbounds i64, ptr %d, i64 1 store i64 %3, ptr %ptroffset, align 8 @@ -139,52 +139,52 @@ entry: %retparam27 = alloca i64, align 8 %result28 = alloca %File, align 8 %retparam31 = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca %"char[]", align 8 %retparam32 = alloca i64, align 8 - %varargslots33 = alloca [2 x %variant], align 16 + %varargslots33 = alloca [2 x %any], align 16 %taddr34 = alloca %"char[]", align 8 %taddr35 = alloca %"char[]", align 8 %retparam36 = alloca i64, align 8 - %varargslots37 = alloca [2 x %variant], align 16 + %varargslots37 = alloca [2 x %any], align 16 %taddr38 = alloca %"char[]", align 8 %taddr39 = alloca %"char[]", align 8 %retparam40 = alloca i64, align 8 - %varargslots41 = alloca [2 x %variant], align 16 + %varargslots41 = alloca [2 x %any], align 16 %taddr42 = alloca %"char[]", align 8 %taddr43 = alloca %"char[]", align 8 %retparam44 = alloca i64, align 8 - %varargslots45 = alloca [2 x %variant], align 16 + %varargslots45 = alloca [2 x %any], align 16 %taddr46 = alloca %"char[]", align 8 %taddr47 = alloca %"char[]", align 8 %retparam48 = alloca i64, align 8 - %varargslots49 = alloca [1 x %variant], align 16 + %varargslots49 = alloca [1 x %any], align 16 %taddr50 = alloca %"char[]", align 8 %retparam51 = alloca i64, align 8 - %varargslots52 = alloca [2 x %variant], align 16 + %varargslots52 = alloca [2 x %any], align 16 %taddr53 = alloca %"char[]", align 8 %taddr54 = alloca %"char[]", align 8 %retparam55 = alloca i64, align 8 - %varargslots56 = alloca [2 x %variant], align 16 + %varargslots56 = alloca [2 x %any], align 16 %taddr57 = alloca %"char[]", align 8 %taddr58 = alloca %"char[]", align 8 %retparam59 = alloca i64, align 8 - %varargslots60 = alloca [2 x %variant], align 16 + %varargslots60 = alloca [2 x %any], align 16 %taddr61 = alloca %"char[]", align 8 %taddr62 = alloca %"char[]", align 8 %retparam63 = alloca i64, align 8 - %varargslots64 = alloca [2 x %variant], align 16 + %varargslots64 = alloca [2 x %any], align 16 %taddr65 = alloca %"char[]", align 8 %taddr66 = alloca %"char[]", align 8 %retparam67 = alloca i64, align 8 - %varargslots68 = alloca [1 x %variant], align 16 + %varargslots68 = alloca [1 x %any], align 16 %taddr69 = alloca %"char[]", align 8 %retparam70 = alloca i64, align 8 - %varargslots71 = alloca [2 x %variant], align 16 + %varargslots71 = alloca [2 x %any], align 16 %taddr72 = alloca %"char[]", align 8 %taddr73 = alloca %"char[]", align 8 %retparam74 = alloca i64, align 8 - %varargslots75 = alloca [2 x %variant], align 16 + %varargslots75 = alloca [2 x %any], align 16 %taddr76 = alloca %"char[]", align 8 %taddr77 = alloca %"char[]", align 8 store %"char[]" { ptr @.str, i64 3 }, ptr %x, align 8 @@ -223,7 +223,7 @@ entry: %19 = getelementptr inbounds %"char[]", ptr %x11, i32 0, i32 1 %hi15 = load i64, ptr %19, align 8 %20 = call i64 @std.io.File.printn(ptr %retparam12, ptr %17, ptr %lo14, i64 %hi15) - store %"char[]" { ptr @.str.13, i64 9 }, ptr %x16, align 8 + store %"char[]" { ptr @.str.13, i64 5 }, ptr %x16, align 8 %21 = call ptr @std.io.stdout() store ptr %21, ptr %result18, align 8 %22 = load ptr, ptr %result18, align 8 @@ -251,132 +251,132 @@ entry: %hi30 = load i64, ptr %34, align 8 %35 = call i64 @std.io.File.printn(ptr %retparam27, ptr %32, ptr %lo29, i64 %hi30) store %"char[]" { ptr @.str.17, i64 3 }, ptr %taddr, align 8 - %36 = insertvalue %variant undef, ptr %taddr, 0 - %37 = insertvalue %variant %36, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %38 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %37, ptr %38, align 16 + %36 = insertvalue %any undef, ptr %taddr, 0 + %37 = insertvalue %any %36, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %38 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %37, ptr %38, align 16 %39 = call i64 @std.io.printfn(ptr %retparam31, ptr @.str.16, i64 8, ptr %varargslots, i64 1) store %"char[]" { ptr @.str.19, i64 1 }, ptr %taddr34, align 8 - %40 = insertvalue %variant undef, ptr %taddr34, 0 - %41 = insertvalue %variant %40, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %42 = getelementptr inbounds [2 x %variant], ptr %varargslots33, i64 0, i64 0 - store %variant %41, ptr %42, align 16 + %40 = insertvalue %any undef, ptr %taddr34, 0 + %41 = insertvalue %any %40, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %42 = getelementptr inbounds [2 x %any], ptr %varargslots33, i64 0, i64 0 + store %any %41, ptr %42, align 16 store %"char[]" { ptr @.str.20, i64 3 }, ptr %taddr35, align 8 - %43 = insertvalue %variant undef, ptr %taddr35, 0 - %44 = insertvalue %variant %43, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %45 = getelementptr inbounds [2 x %variant], ptr %varargslots33, i64 0, i64 1 - store %variant %44, ptr %45, align 16 + %43 = insertvalue %any undef, ptr %taddr35, 0 + %44 = insertvalue %any %43, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %45 = getelementptr inbounds [2 x %any], ptr %varargslots33, i64 0, i64 1 + store %any %44, ptr %45, align 16 %46 = call i64 @std.io.printfn(ptr %retparam32, ptr @.str.18, i64 6, ptr %varargslots33, i64 2) store %"char[]" { ptr @.str.22, i64 4 }, ptr %taddr38, align 8 - %47 = insertvalue %variant undef, ptr %taddr38, 0 - %48 = insertvalue %variant %47, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %49 = getelementptr inbounds [2 x %variant], ptr %varargslots37, i64 0, i64 0 - store %variant %48, ptr %49, align 16 + %47 = insertvalue %any undef, ptr %taddr38, 0 + %48 = insertvalue %any %47, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %49 = getelementptr inbounds [2 x %any], ptr %varargslots37, i64 0, i64 0 + store %any %48, ptr %49, align 16 store %"char[]" { ptr @.str.23, i64 4 }, ptr %taddr39, align 8 - %50 = insertvalue %variant undef, ptr %taddr39, 0 - %51 = insertvalue %variant %50, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %52 = getelementptr inbounds [2 x %variant], ptr %varargslots37, i64 0, i64 1 - store %variant %51, ptr %52, align 16 + %50 = insertvalue %any undef, ptr %taddr39, 0 + %51 = insertvalue %any %50, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %52 = getelementptr inbounds [2 x %any], ptr %varargslots37, i64 0, i64 1 + store %any %51, ptr %52, align 16 %53 = call i64 @std.io.printfn(ptr %retparam36, ptr @.str.21, i64 6, ptr %varargslots37, i64 2) store %"char[]" zeroinitializer, ptr %taddr42, align 8 - %54 = insertvalue %variant undef, ptr %taddr42, 0 - %55 = insertvalue %variant %54, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %56 = getelementptr inbounds [2 x %variant], ptr %varargslots41, i64 0, i64 0 - store %variant %55, ptr %56, align 16 + %54 = insertvalue %any undef, ptr %taddr42, 0 + %55 = insertvalue %any %54, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %56 = getelementptr inbounds [2 x %any], ptr %varargslots41, i64 0, i64 0 + store %any %55, ptr %56, align 16 store %"char[]" { ptr @.str.25, i64 5 }, ptr %taddr43, align 8 - %57 = insertvalue %variant undef, ptr %taddr43, 0 - %58 = insertvalue %variant %57, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %59 = getelementptr inbounds [2 x %variant], ptr %varargslots41, i64 0, i64 1 - store %variant %58, ptr %59, align 16 + %57 = insertvalue %any undef, ptr %taddr43, 0 + %58 = insertvalue %any %57, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %59 = getelementptr inbounds [2 x %any], ptr %varargslots41, i64 0, i64 1 + store %any %58, ptr %59, align 16 %60 = call i64 @std.io.printfn(ptr %retparam40, ptr @.str.24, i64 6, ptr %varargslots41, i64 2) store %"char[]" { ptr @.str.27, i64 1 }, ptr %taddr46, align 8 - %61 = insertvalue %variant undef, ptr %taddr46, 0 - %62 = insertvalue %variant %61, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %63 = getelementptr inbounds [2 x %variant], ptr %varargslots45, i64 0, i64 0 - store %variant %62, ptr %63, align 16 + %61 = insertvalue %any undef, ptr %taddr46, 0 + %62 = insertvalue %any %61, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %63 = getelementptr inbounds [2 x %any], ptr %varargslots45, i64 0, i64 0 + store %any %62, ptr %63, align 16 store %"char[]" { ptr @.str.28, i64 6 }, ptr %taddr47, align 8 - %64 = insertvalue %variant undef, ptr %taddr47, 0 - %65 = insertvalue %variant %64, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %66 = getelementptr inbounds [2 x %variant], ptr %varargslots45, i64 0, i64 1 - store %variant %65, ptr %66, align 16 + %64 = insertvalue %any undef, ptr %taddr47, 0 + %65 = insertvalue %any %64, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %66 = getelementptr inbounds [2 x %any], ptr %varargslots45, i64 0, i64 1 + store %any %65, ptr %66, align 16 %67 = call i64 @std.io.printfn(ptr %retparam44, ptr @.str.26, i64 6, ptr %varargslots45, i64 2) store %"char[]" { ptr @.str.30, i64 3 }, ptr %taddr50, align 8 - %68 = insertvalue %variant undef, ptr %taddr50, 0 - %69 = insertvalue %variant %68, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %70 = getelementptr inbounds [1 x %variant], ptr %varargslots49, i64 0, i64 0 - store %variant %69, ptr %70, align 16 + %68 = insertvalue %any undef, ptr %taddr50, 0 + %69 = insertvalue %any %68, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %70 = getelementptr inbounds [1 x %any], ptr %varargslots49, i64 0, i64 0 + store %any %69, ptr %70, align 16 %71 = call i64 @std.io.printfn(ptr %retparam48, ptr @.str.29, i64 8, ptr %varargslots49, i64 1) store %"char[]" { ptr @.str.32, i64 1 }, ptr %taddr53, align 8 - %72 = insertvalue %variant undef, ptr %taddr53, 0 - %73 = insertvalue %variant %72, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %74 = getelementptr inbounds [2 x %variant], ptr %varargslots52, i64 0, i64 0 - store %variant %73, ptr %74, align 16 + %72 = insertvalue %any undef, ptr %taddr53, 0 + %73 = insertvalue %any %72, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %74 = getelementptr inbounds [2 x %any], ptr %varargslots52, i64 0, i64 0 + store %any %73, ptr %74, align 16 store %"char[]" { ptr @.str.33, i64 4 }, ptr %taddr54, align 8 - %75 = insertvalue %variant undef, ptr %taddr54, 0 - %76 = insertvalue %variant %75, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %77 = getelementptr inbounds [2 x %variant], ptr %varargslots52, i64 0, i64 1 - store %variant %76, ptr %77, align 16 + %75 = insertvalue %any undef, ptr %taddr54, 0 + %76 = insertvalue %any %75, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %77 = getelementptr inbounds [2 x %any], ptr %varargslots52, i64 0, i64 1 + store %any %76, ptr %77, align 16 %78 = call i64 @std.io.printfn(ptr %retparam51, ptr @.str.31, i64 6, ptr %varargslots52, i64 2) store %"char[]" { ptr @.str.35, i64 1 }, ptr %taddr57, align 8 - %79 = insertvalue %variant undef, ptr %taddr57, 0 - %80 = insertvalue %variant %79, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %81 = getelementptr inbounds [2 x %variant], ptr %varargslots56, i64 0, i64 0 - store %variant %80, ptr %81, align 16 + %79 = insertvalue %any undef, ptr %taddr57, 0 + %80 = insertvalue %any %79, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %81 = getelementptr inbounds [2 x %any], ptr %varargslots56, i64 0, i64 0 + store %any %80, ptr %81, align 16 store %"char[]" { ptr @.str.36, i64 5 }, ptr %taddr58, align 8 - %82 = insertvalue %variant undef, ptr %taddr58, 0 - %83 = insertvalue %variant %82, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %84 = getelementptr inbounds [2 x %variant], ptr %varargslots56, i64 0, i64 1 - store %variant %83, ptr %84, align 16 + %82 = insertvalue %any undef, ptr %taddr58, 0 + %83 = insertvalue %any %82, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %84 = getelementptr inbounds [2 x %any], ptr %varargslots56, i64 0, i64 1 + store %any %83, ptr %84, align 16 %85 = call i64 @std.io.printfn(ptr %retparam55, ptr @.str.34, i64 6, ptr %varargslots56, i64 2) store %"char[]" zeroinitializer, ptr %taddr61, align 8 - %86 = insertvalue %variant undef, ptr %taddr61, 0 - %87 = insertvalue %variant %86, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %88 = getelementptr inbounds [2 x %variant], ptr %varargslots60, i64 0, i64 0 - store %variant %87, ptr %88, align 16 + %86 = insertvalue %any undef, ptr %taddr61, 0 + %87 = insertvalue %any %86, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %88 = getelementptr inbounds [2 x %any], ptr %varargslots60, i64 0, i64 0 + store %any %87, ptr %88, align 16 store %"char[]" { ptr @.str.38, i64 5 }, ptr %taddr62, align 8 - %89 = insertvalue %variant undef, ptr %taddr62, 0 - %90 = insertvalue %variant %89, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %91 = getelementptr inbounds [2 x %variant], ptr %varargslots60, i64 0, i64 1 - store %variant %90, ptr %91, align 16 + %89 = insertvalue %any undef, ptr %taddr62, 0 + %90 = insertvalue %any %89, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %91 = getelementptr inbounds [2 x %any], ptr %varargslots60, i64 0, i64 1 + store %any %90, ptr %91, align 16 %92 = call i64 @std.io.printfn(ptr %retparam59, ptr @.str.37, i64 6, ptr %varargslots60, i64 2) store %"char[]" { ptr @.str.40, i64 3 }, ptr %taddr65, align 8 - %93 = insertvalue %variant undef, ptr %taddr65, 0 - %94 = insertvalue %variant %93, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %95 = getelementptr inbounds [2 x %variant], ptr %varargslots64, i64 0, i64 0 - store %variant %94, ptr %95, align 16 + %93 = insertvalue %any undef, ptr %taddr65, 0 + %94 = insertvalue %any %93, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %95 = getelementptr inbounds [2 x %any], ptr %varargslots64, i64 0, i64 0 + store %any %94, ptr %95, align 16 store %"char[]" { ptr @.str.41, i64 3 }, ptr %taddr66, align 8 - %96 = insertvalue %variant undef, ptr %taddr66, 0 - %97 = insertvalue %variant %96, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %98 = getelementptr inbounds [2 x %variant], ptr %varargslots64, i64 0, i64 1 - store %variant %97, ptr %98, align 16 + %96 = insertvalue %any undef, ptr %taddr66, 0 + %97 = insertvalue %any %96, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %98 = getelementptr inbounds [2 x %any], ptr %varargslots64, i64 0, i64 1 + store %any %97, ptr %98, align 16 %99 = call i64 @std.io.printfn(ptr %retparam63, ptr @.str.39, i64 6, ptr %varargslots64, i64 2) store %"char[]" { ptr @.str.43, i64 4 }, ptr %taddr69, align 8 - %100 = insertvalue %variant undef, ptr %taddr69, 0 - %101 = insertvalue %variant %100, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %102 = getelementptr inbounds [1 x %variant], ptr %varargslots68, i64 0, i64 0 - store %variant %101, ptr %102, align 16 + %100 = insertvalue %any undef, ptr %taddr69, 0 + %101 = insertvalue %any %100, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %102 = getelementptr inbounds [1 x %any], ptr %varargslots68, i64 0, i64 0 + store %any %101, ptr %102, align 16 %103 = call i64 @std.io.printfn(ptr %retparam67, ptr @.str.42, i64 8, ptr %varargslots68, i64 1) store %"char[]" { ptr @.str.45, i64 1 }, ptr %taddr72, align 8 - %104 = insertvalue %variant undef, ptr %taddr72, 0 - %105 = insertvalue %variant %104, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %106 = getelementptr inbounds [2 x %variant], ptr %varargslots71, i64 0, i64 0 - store %variant %105, ptr %106, align 16 + %104 = insertvalue %any undef, ptr %taddr72, 0 + %105 = insertvalue %any %104, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %106 = getelementptr inbounds [2 x %any], ptr %varargslots71, i64 0, i64 0 + store %any %105, ptr %106, align 16 store %"char[]" { ptr @.str.46, i64 3 }, ptr %taddr73, align 8 - %107 = insertvalue %variant undef, ptr %taddr73, 0 - %108 = insertvalue %variant %107, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %109 = getelementptr inbounds [2 x %variant], ptr %varargslots71, i64 0, i64 1 - store %variant %108, ptr %109, align 16 + %107 = insertvalue %any undef, ptr %taddr73, 0 + %108 = insertvalue %any %107, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %109 = getelementptr inbounds [2 x %any], ptr %varargslots71, i64 0, i64 1 + store %any %108, ptr %109, align 16 %110 = call i64 @std.io.printfn(ptr %retparam70, ptr @.str.44, i64 6, ptr %varargslots71, i64 2) store %"char[]" { ptr @.str.48, i64 1 }, ptr %taddr76, align 8 - %111 = insertvalue %variant undef, ptr %taddr76, 0 - %112 = insertvalue %variant %111, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %113 = getelementptr inbounds [2 x %variant], ptr %varargslots75, i64 0, i64 0 - store %variant %112, ptr %113, align 16 + %111 = insertvalue %any undef, ptr %taddr76, 0 + %112 = insertvalue %any %111, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %113 = getelementptr inbounds [2 x %any], ptr %varargslots75, i64 0, i64 0 + store %any %112, ptr %113, align 16 store %"char[]" { ptr @.str.49, i64 5 }, ptr %taddr77, align 8 - %114 = insertvalue %variant undef, ptr %taddr77, 0 - %115 = insertvalue %variant %114, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %116 = getelementptr inbounds [2 x %variant], ptr %varargslots75, i64 0, i64 1 - store %variant %115, ptr %116, align 16 + %114 = insertvalue %any undef, ptr %taddr77, 0 + %115 = insertvalue %any %114, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %116 = getelementptr inbounds [2 x %any], ptr %varargslots75, i64 0, i64 1 + store %any %115, ptr %116, align 16 %117 = call i64 @std.io.printfn(ptr %retparam74, ptr @.str.47, i64 6, ptr %varargslots75, i64 2) ret void } @@ -384,151 +384,151 @@ entry: define void @test.main() #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i64, align 8 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [1 x %variant], align 16 + %varargslots2 = alloca [1 x %any], align 16 %taddr3 = alloca i64, align 8 %retparam4 = alloca i64, align 8 - %varargslots5 = alloca [2 x %variant], align 16 + %varargslots5 = alloca [2 x %any], align 16 %taddr6 = alloca i64, align 8 %taddr7 = alloca i64, align 8 %retparam8 = alloca i64, align 8 - %varargslots9 = alloca [2 x %variant], align 16 + %varargslots9 = alloca [2 x %any], align 16 %taddr10 = alloca i64, align 8 %taddr11 = alloca i64, align 8 %retparam12 = alloca i64, align 8 - %varargslots13 = alloca [2 x %variant], align 16 + %varargslots13 = alloca [2 x %any], align 16 %taddr14 = alloca i64, align 8 %taddr15 = alloca i64, align 8 %retparam16 = alloca i64, align 8 - %varargslots17 = alloca [2 x %variant], align 16 + %varargslots17 = alloca [2 x %any], align 16 %taddr18 = alloca i64, align 8 %taddr19 = alloca i64, align 8 %retparam20 = alloca i64, align 8 - %varargslots21 = alloca [2 x %variant], align 16 + %varargslots21 = alloca [2 x %any], align 16 %taddr22 = alloca i64, align 8 %taddr23 = alloca i64, align 8 %retparam24 = alloca i64, align 8 - %varargslots25 = alloca [2 x %variant], align 16 + %varargslots25 = alloca [2 x %any], align 16 %taddr26 = alloca i64, align 8 %taddr27 = alloca i64, align 8 %retparam28 = alloca i64, align 8 - %varargslots29 = alloca [2 x %variant], align 16 + %varargslots29 = alloca [2 x %any], align 16 %taddr30 = alloca i64, align 8 %taddr31 = alloca i64, align 8 %retparam32 = alloca i64, align 8 - %varargslots33 = alloca [1 x %variant], align 16 + %varargslots33 = alloca [1 x %any], align 16 %taddr34 = alloca i64, align 8 %retparam35 = alloca i64, align 8 - %varargslots36 = alloca [2 x %variant], align 16 + %varargslots36 = alloca [2 x %any], align 16 %taddr37 = alloca i64, align 8 %taddr38 = alloca i64, align 8 store i64 4, ptr %taddr, align 8 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %2 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %1, ptr %2, align 16 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %2 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %1, ptr %2, align 16 %3 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.50, i64 7, ptr %varargslots, i64 1) store i64 1, ptr %taddr3, align 8 - %4 = insertvalue %variant undef, ptr %taddr3, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %6 = getelementptr inbounds [1 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %taddr3, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.51, i64 7, ptr %varargslots2, i64 1) store i64 0, ptr %taddr6, align 8 - %8 = insertvalue %variant undef, ptr %taddr6, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %10 = getelementptr inbounds [2 x %variant], ptr %varargslots5, i64 0, i64 0 - store %variant %9, ptr %10, align 16 + %8 = insertvalue %any undef, ptr %taddr6, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %10 = getelementptr inbounds [2 x %any], ptr %varargslots5, i64 0, i64 0 + store %any %9, ptr %10, align 16 store i64 4, ptr %taddr7, align 8 - %11 = insertvalue %variant undef, ptr %taddr7, 0 - %12 = insertvalue %variant %11, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %13 = getelementptr inbounds [2 x %variant], ptr %varargslots5, i64 0, i64 1 - store %variant %12, ptr %13, align 16 + %11 = insertvalue %any undef, ptr %taddr7, 0 + %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %13 = getelementptr inbounds [2 x %any], ptr %varargslots5, i64 0, i64 1 + store %any %12, ptr %13, align 16 %14 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.52, i64 8, ptr %varargslots5, i64 2) store i64 2, ptr %taddr10, align 8 - %15 = insertvalue %variant undef, ptr %taddr10, 0 - %16 = insertvalue %variant %15, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %17 = getelementptr inbounds [2 x %variant], ptr %varargslots9, i64 0, i64 0 - store %variant %16, ptr %17, align 16 + %15 = insertvalue %any undef, ptr %taddr10, 0 + %16 = insertvalue %any %15, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %17 = getelementptr inbounds [2 x %any], ptr %varargslots9, i64 0, i64 0 + store %any %16, ptr %17, align 16 store i64 2, ptr %taddr11, align 8 - %18 = insertvalue %variant undef, ptr %taddr11, 0 - %19 = insertvalue %variant %18, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %20 = getelementptr inbounds [2 x %variant], ptr %varargslots9, i64 0, i64 1 - store %variant %19, ptr %20, align 16 + %18 = insertvalue %any undef, ptr %taddr11, 0 + %19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %20 = getelementptr inbounds [2 x %any], ptr %varargslots9, i64 0, i64 1 + store %any %19, ptr %20, align 16 %21 = call i64 @std.io.printfn(ptr %retparam8, ptr @.str.53, i64 8, ptr %varargslots9, i64 2) store i64 4, ptr %taddr14, align 8 - %22 = insertvalue %variant undef, ptr %taddr14, 0 - %23 = insertvalue %variant %22, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %24 = getelementptr inbounds [2 x %variant], ptr %varargslots13, i64 0, i64 0 - store %variant %23, ptr %24, align 16 + %22 = insertvalue %any undef, ptr %taddr14, 0 + %23 = insertvalue %any %22, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %24 = getelementptr inbounds [2 x %any], ptr %varargslots13, i64 0, i64 0 + store %any %23, ptr %24, align 16 store i64 4, ptr %taddr15, align 8 - %25 = insertvalue %variant undef, ptr %taddr15, 0 - %26 = insertvalue %variant %25, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %27 = getelementptr inbounds [2 x %variant], ptr %varargslots13, i64 0, i64 1 - store %variant %26, ptr %27, align 16 + %25 = insertvalue %any undef, ptr %taddr15, 0 + %26 = insertvalue %any %25, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %27 = getelementptr inbounds [2 x %any], ptr %varargslots13, i64 0, i64 1 + store %any %26, ptr %27, align 16 %28 = call i64 @std.io.printfn(ptr %retparam12, ptr @.str.54, i64 8, ptr %varargslots13, i64 2) store i64 4, ptr %taddr18, align 8 - %29 = insertvalue %variant undef, ptr %taddr18, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %31 = getelementptr inbounds [2 x %variant], ptr %varargslots17, i64 0, i64 0 - store %variant %30, ptr %31, align 16 + %29 = insertvalue %any undef, ptr %taddr18, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %31 = getelementptr inbounds [2 x %any], ptr %varargslots17, i64 0, i64 0 + store %any %30, ptr %31, align 16 store i64 4, ptr %taddr19, align 8 - %32 = insertvalue %variant undef, ptr %taddr19, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %34 = getelementptr inbounds [2 x %variant], ptr %varargslots17, i64 0, i64 1 - store %variant %33, ptr %34, align 16 + %32 = insertvalue %any undef, ptr %taddr19, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %34 = getelementptr inbounds [2 x %any], ptr %varargslots17, i64 0, i64 1 + store %any %33, ptr %34, align 16 %35 = call i64 @std.io.printfn(ptr %retparam16, ptr @.str.55, i64 8, ptr %varargslots17, i64 2) store i64 4, ptr %taddr22, align 8 - %36 = insertvalue %variant undef, ptr %taddr22, 0 - %37 = insertvalue %variant %36, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %38 = getelementptr inbounds [2 x %variant], ptr %varargslots21, i64 0, i64 0 - store %variant %37, ptr %38, align 16 + %36 = insertvalue %any undef, ptr %taddr22, 0 + %37 = insertvalue %any %36, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %38 = getelementptr inbounds [2 x %any], ptr %varargslots21, i64 0, i64 0 + store %any %37, ptr %38, align 16 store i64 4, ptr %taddr23, align 8 - %39 = insertvalue %variant undef, ptr %taddr23, 0 - %40 = insertvalue %variant %39, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %41 = getelementptr inbounds [2 x %variant], ptr %varargslots21, i64 0, i64 1 - store %variant %40, ptr %41, align 16 + %39 = insertvalue %any undef, ptr %taddr23, 0 + %40 = insertvalue %any %39, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %41 = getelementptr inbounds [2 x %any], ptr %varargslots21, i64 0, i64 1 + store %any %40, ptr %41, align 16 %42 = call i64 @std.io.printfn(ptr %retparam20, ptr @.str.56, i64 9, ptr %varargslots21, i64 2) store i64 5, ptr %taddr26, align 8 - %43 = insertvalue %variant undef, ptr %taddr26, 0 - %44 = insertvalue %variant %43, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %45 = getelementptr inbounds [2 x %variant], ptr %varargslots25, i64 0, i64 0 - store %variant %44, ptr %45, align 16 + %43 = insertvalue %any undef, ptr %taddr26, 0 + %44 = insertvalue %any %43, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %45 = getelementptr inbounds [2 x %any], ptr %varargslots25, i64 0, i64 0 + store %any %44, ptr %45, align 16 store i64 1, ptr %taddr27, align 8 - %46 = insertvalue %variant undef, ptr %taddr27, 0 - %47 = insertvalue %variant %46, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %48 = getelementptr inbounds [2 x %variant], ptr %varargslots25, i64 0, i64 1 - store %variant %47, ptr %48, align 16 + %46 = insertvalue %any undef, ptr %taddr27, 0 + %47 = insertvalue %any %46, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %48 = getelementptr inbounds [2 x %any], ptr %varargslots25, i64 0, i64 1 + store %any %47, ptr %48, align 16 %49 = call i64 @std.io.printfn(ptr %retparam24, ptr @.str.57, i64 9, ptr %varargslots25, i64 2) store i64 8, ptr %taddr30, align 8 - %50 = insertvalue %variant undef, ptr %taddr30, 0 - %51 = insertvalue %variant %50, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %52 = getelementptr inbounds [2 x %variant], ptr %varargslots29, i64 0, i64 0 - store %variant %51, ptr %52, align 16 + %50 = insertvalue %any undef, ptr %taddr30, 0 + %51 = insertvalue %any %50, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %52 = getelementptr inbounds [2 x %any], ptr %varargslots29, i64 0, i64 0 + store %any %51, ptr %52, align 16 store i64 4, ptr %taddr31, align 8 - %53 = insertvalue %variant undef, ptr %taddr31, 0 - %54 = insertvalue %variant %53, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %55 = getelementptr inbounds [2 x %variant], ptr %varargslots29, i64 0, i64 1 - store %variant %54, ptr %55, align 16 + %53 = insertvalue %any undef, ptr %taddr31, 0 + %54 = insertvalue %any %53, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %55 = getelementptr inbounds [2 x %any], ptr %varargslots29, i64 0, i64 1 + store %any %54, ptr %55, align 16 %56 = call i64 @std.io.printfn(ptr %retparam28, ptr @.str.58, i64 10, ptr %varargslots29, i64 2) store i64 4, ptr %taddr34, align 8 - %57 = insertvalue %variant undef, ptr %taddr34, 0 - %58 = insertvalue %variant %57, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %59 = getelementptr inbounds [1 x %variant], ptr %varargslots33, i64 0, i64 0 - store %variant %58, ptr %59, align 16 + %57 = insertvalue %any undef, ptr %taddr34, 0 + %58 = insertvalue %any %57, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %59 = getelementptr inbounds [1 x %any], ptr %varargslots33, i64 0, i64 0 + store %any %58, ptr %59, align 16 %60 = call i64 @std.io.printfn(ptr %retparam32, ptr @.str.59, i64 7, ptr %varargslots33, i64 1) store i64 8, ptr %taddr37, align 8 - %61 = insertvalue %variant undef, ptr %taddr37, 0 - %62 = insertvalue %variant %61, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %63 = getelementptr inbounds [2 x %variant], ptr %varargslots36, i64 0, i64 0 - store %variant %62, ptr %63, align 16 + %61 = insertvalue %any undef, ptr %taddr37, 0 + %62 = insertvalue %any %61, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %63 = getelementptr inbounds [2 x %any], ptr %varargslots36, i64 0, i64 0 + store %any %62, ptr %63, align 16 store i64 4, ptr %taddr38, align 8 - %64 = insertvalue %variant undef, ptr %taddr38, 0 - %65 = insertvalue %variant %64, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %66 = getelementptr inbounds [2 x %variant], ptr %varargslots36, i64 0, i64 1 - store %variant %65, ptr %66, align 16 + %64 = insertvalue %any undef, ptr %taddr38, 0 + %65 = insertvalue %any %64, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %66 = getelementptr inbounds [2 x %any], ptr %varargslots36, i64 0, i64 1 + store %any %65, ptr %66, align 16 %67 = call i64 @std.io.printfn(ptr %retparam35, ptr @.str.60, i64 10, ptr %varargslots36, i64 2) call void @test.test(i32 10) ret void diff --git a/test/test_suite/compile_time/ct_switch_more_checks.c3 b/test/test_suite/compile_time/ct_switch_more_checks.c3 index c3e18e0ee..a6b96c103 100644 --- a/test/test_suite/compile_time/ct_switch_more_checks.c3 +++ b/test/test_suite/compile_time/ct_switch_more_checks.c3 @@ -26,7 +26,7 @@ fn void foo2() fn void foo3() { int a; - $switch ({ 1, 3 }): // #error: Only types, strings, enums, integers, floats and booleans + $switch ({ 1, 3 }) // #error: Only types, strings, enums, integers, floats and booleans $case 1: io::printn("Hello"); $default: diff --git a/test/test_suite/compile_time/untyped_conversions.c3t b/test/test_suite/compile_time/untyped_conversions.c3t index 0c73ef12f..c5770bc8c 100644 --- a/test/test_suite/compile_time/untyped_conversions.c3t +++ b/test/test_suite/compile_time/untyped_conversions.c3t @@ -27,7 +27,7 @@ fn void main() %.introspect = type { i8, i64, i64, i64, [0 x i64] } %Foo = type { i32, i32 } %"int[]" = type { ptr, i64 } -%variant = type { ptr, i64 } +%any = type { ptr, i64 } @"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [9 x i8] c"%s %s %s\00", align 1 @@ -52,24 +52,24 @@ entry: %b = alloca %"int[]", align 8 %c = alloca <2 x i32>, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [3 x %variant], align 16 + %varargslots = alloca [3 x %any], align 16 store i64 %0, ptr %a, align 4 store ptr %1, ptr %b, align 8 %ptroffset = getelementptr inbounds i64, ptr %b, i64 1 store i64 %2, ptr %ptroffset, align 8 store double %3, ptr %c, align 8 - %4 = insertvalue %variant undef, ptr %a, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.a2$int" to i64), 1 - %6 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 - %7 = insertvalue %variant undef, ptr %b, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 - %9 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %8, ptr %9, align 16 - %10 = insertvalue %variant undef, ptr %c, 0 - %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"$ct.v2$int" to i64), 1 - %12 = getelementptr inbounds [3 x %variant], ptr %varargslots, i64 0, i64 2 - store %variant %11, ptr %12, align 16 + %4 = insertvalue %any undef, ptr %a, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.a2$int" to i64), 1 + %6 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 + %7 = insertvalue %any undef, ptr %b, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 + %9 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 1 + store %any %8, ptr %9, align 16 + %10 = insertvalue %any undef, ptr %c, 0 + %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.v2$int" to i64), 1 + %12 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 2 + store %any %11, ptr %12, align 16 %13 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 3) ret void } @@ -82,7 +82,7 @@ entry: %y = alloca [1 x [2 x i32]], align 4 %y2 = alloca [1 x [2 x double]], align 16 %retparam = alloca i64, align 8 - %varargslots = alloca [4 x %variant], align 16 + %varargslots = alloca [4 x %any], align 16 %literal = alloca [2 x i32], align 4 %literal1 = alloca [2 x i32], align 4 %taddr = alloca <2 x i32>, align 8 @@ -93,24 +93,24 @@ entry: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %def, ptr align 4 @.__const.1, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 4 %y, ptr align 4 @.__const.2, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 16 %y2, ptr align 16 @.__const.3, i32 16, i1 false) - %0 = insertvalue %variant undef, ptr %y, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.a1$a2$int" to i64), 1 - %2 = getelementptr inbounds [4 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %1, ptr %2, align 16 - %3 = insertvalue %variant undef, ptr %y2, 0 - %4 = insertvalue %variant %3, i64 ptrtoint (ptr @"$ct.a1$a2$double" to i64), 1 - %5 = getelementptr inbounds [4 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %4, ptr %5, align 16 + %0 = insertvalue %any undef, ptr %y, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.a1$a2$int" to i64), 1 + %2 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 0 + store %any %1, ptr %2, align 16 + %3 = insertvalue %any undef, ptr %y2, 0 + %4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.a1$a2$double" to i64), 1 + %5 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 1 + store %any %4, ptr %5, align 16 %6 = getelementptr inbounds %Foo, ptr %def, i32 0, i32 0 - %7 = insertvalue %variant undef, ptr %6, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %9 = getelementptr inbounds [4 x %variant], ptr %varargslots, i64 0, i64 2 - store %variant %8, ptr %9, align 16 + %7 = insertvalue %any undef, ptr %6, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %9 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 2 + store %any %8, ptr %9, align 16 %10 = getelementptr inbounds %Foo, ptr %def, i32 0, i32 1 - %11 = insertvalue %variant undef, ptr %10, 0 - %12 = insertvalue %variant %11, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %13 = getelementptr inbounds [4 x %variant], ptr %varargslots, i64 0, i64 3 - store %variant %12, ptr %13, align 16 + %11 = insertvalue %any undef, ptr %10, 0 + %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %13 = getelementptr inbounds [4 x %any], ptr %varargslots, i64 0, i64 3 + store %any %12, ptr %13, align 16 %14 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.4, i64 14, ptr %varargslots, i64 4) %15 = getelementptr inbounds [2 x i32], ptr %literal, i64 0, i64 0 store i32 1, ptr %15, align 4 diff --git a/test/test_suite/defer/defer_catch_try.c3t b/test/test_suite/defer/defer_catch_try.c3t index da7f94bdf..ff4c3e1ab 100644 --- a/test/test_suite/defer/defer_catch_try.c3t +++ b/test/test_suite/defer/defer_catch_try.c3t @@ -12,7 +12,7 @@ fn int! abc(int x) defer catch printf("Abc catch %d\n", x); defer try printf("Abc try %d\n", x); defer printf("Abc normal %d\n", x); - return x > 0 ? Abc.FOO! : 0; + return x > 0 ? Abc.FOO? : 0; } fn int! bcd(int x) { @@ -25,7 +25,7 @@ fn int! bcd(int x) defer printf("Bcd %d normal %d\n", i, x); if (i == 1) continue; printf("bcd check\n"); - if (i == 2) return x > 0 ? Abc.FOO! : 0; + if (i == 2) return x > 0 ? Abc.FOO? : 0; } return 0; } diff --git a/test/test_suite/defer/defer_with_rethrow.c3 b/test/test_suite/defer/defer_with_rethrow.c3 index 265f2fa0e..4ecc41982 100644 --- a/test/test_suite/defer/defer_with_rethrow.c3 +++ b/test/test_suite/defer/defer_with_rethrow.c3 @@ -6,9 +6,9 @@ fn int! bar() { defer { {| - foo()?; + foo()!; |}; } - defer foo()?; // #error: Returns are not allowed inside of defers. + defer foo()!; // #error: Returns are not allowed inside of defers. return 1; } \ No newline at end of file diff --git a/test/test_suite/define/common.c3 b/test/test_suite/define/common.c3 index 74bee54b7..f4eaea3f4 100644 --- a/test/test_suite/define/common.c3 +++ b/test/test_suite/define/common.c3 @@ -7,7 +7,7 @@ typedef FooInt = Foo; define A_CONST_INT = A_CONST; define standard_foo = ofke; // #error: Expected '=' -define fn foo = fef; // #error: An identifier was expected here. +define fn foo = fef; // #error: A variable, constant or attribute name was expected here. define feokfe = fn void(int); // #error: Expected a function or variable name here define AOFKE = ofek; // #error: Expected a constant name here define okfoe = OFKEOK; // #error: Expected a function or variable name here diff --git a/test/test_suite/define/forbidden_defines.c3 b/test/test_suite/define/forbidden_defines.c3 index 206dfd45d..924c51beb 100644 --- a/test/test_suite/define/forbidden_defines.c3 +++ b/test/test_suite/define/forbidden_defines.c3 @@ -1,3 +1,3 @@ typedef Abc = int[*]; // #error: Inferred array types can only -typedef Bcd = anyerr; // #error: 'anyerr' may not be aliased. -typedef Efd = variant; // #error: 'variant' may not be aliased. +typedef Bcd = anyfault; // #error: 'anyfault' may not be aliased. +typedef Efd = any; // #error: 'any' may not be aliased. diff --git a/test/test_suite/distinct/distinct_invalid.c3 b/test/test_suite/distinct/distinct_invalid.c3 index 89cb300ba..9540a4e8c 100644 --- a/test/test_suite/distinct/distinct_invalid.c3 +++ b/test/test_suite/distinct/distinct_invalid.c3 @@ -1,5 +1,7 @@ fault Error -{} +{ + ABC +} typedef Foo1 = distinct Error; // #error: You cannot create a distinct type diff --git a/test/test_suite/distinct/distinct_parse_errors.c3 b/test/test_suite/distinct/distinct_parse_errors.c3 deleted file mode 100644 index 7f28662fc..000000000 --- a/test/test_suite/distinct/distinct_parse_errors.c3 +++ /dev/null @@ -1,4 +0,0 @@ -import std::io; - -define foo = distinct x; // #error: can only be used with types -define bar = distinct int; // #error: type name alias must start with an uppercase diff --git a/test/test_suite/enumerations/enum_associated_values_other.c3t b/test/test_suite/enumerations/enum_associated_values_other.c3t index 935624da0..9f5bd2e5f 100644 --- a/test/test_suite/enumerations/enum_associated_values_other.c3t +++ b/test/test_suite/enumerations/enum_associated_values_other.c3t @@ -58,7 +58,7 @@ entry: %a = alloca i32, align 4 %z = alloca %"char[]", align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 store ptr %0, ptr %args, align 8 %ptroffset = getelementptr inbounds i64, ptr %args, i64 1 store i64 %1, ptr %ptroffset, align 8 @@ -68,10 +68,10 @@ entry: %2 = load i32, ptr %a, align 4 %3 = getelementptr inbounds [2 x %"char[]"], ptr @"abc.Foo$val", i32 0, i32 %2 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %z, ptr align 8 %3, i32 16, i1 false) - %4 = insertvalue %variant undef, ptr %z, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %z, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.2, i64 2, ptr %varargslots, i64 1) ret void } \ No newline at end of file diff --git a/test/test_suite/enumerations/enum_conversions.c3t b/test/test_suite/enumerations/enum_conversions.c3t index 2c6521c9c..35cffb020 100644 --- a/test/test_suite/enumerations/enum_conversions.c3t +++ b/test/test_suite/enumerations/enum_conversions.c3t @@ -27,89 +27,129 @@ entry: %0 = load i32, ptr %a, align 4 %lt = icmp slt i32 %0, 0 br i1 %lt, label %panic, label %checkok - panic: ; preds = %entry - %1 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %1(ptr @.panic_msg, i64 68, ptr @.file, i64 19, ptr @.func, i64 4, i32 7) + store i32 %0, ptr %taddr, align 4 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 + %4 = insertvalue %"any[]" undef, ptr %varargslots, 0 + %5 = insertvalue %"any[]" %4, i64 1, 1 + store %"any[]" %5, ptr %indirectarg, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 7, ptr @.file, i64 19, ptr @.func, i64 4, i32 7, ptr byval(%"any[]") align 8 %indirectarg) br label %checkok - checkok: ; preds = %panic, %entry %ge = icmp sge i32 %0, 1 - br i1 %ge, label %panic1, label %checkok2 - + br i1 %ge, label %panic1, label %checkok5 panic1: ; preds = %checkok - %2 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %2(ptr @.panic_msg.1, i64 63, ptr @.file.2, i64 19, ptr @.func.3, i64 4, i32 7) - br label %checkok2 - -checkok2: ; preds = %panic1, %checkok + store i32 %0, ptr %taddr2, align 4 + %6 = insertvalue %any undef, ptr %taddr2, 0 + %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %8 = getelementptr inbounds [1 x %any], ptr %varargslots3, i64 0, i64 0 + store %any %7, ptr %8, align 16 + %9 = insertvalue %"any[]" undef, ptr %varargslots3, 0 + %10 = insertvalue %"any[]" %9, i64 1, 1 + store %"any[]" %10, ptr %indirectarg4, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 87, ptr @.file, i64 19, ptr @.func, i64 4, i32 7, ptr byval(%"any[]") align 8 %indirectarg4) + br label %checkok5 +checkok5: ; preds = %panic1, %checkok %trunc = trunc i32 %0 to i8 store i8 %trunc, ptr %x, align 1 store i64 0, ptr %z, align 8 - %3 = load i64, ptr %z, align 8 - %lt3 = icmp slt i64 %3, 0 - br i1 %lt3, label %panic4, label %checkok5 - -panic4: ; preds = %checkok2 - %4 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %4(ptr @.panic_msg.4, i64 68, ptr @.file.5, i64 19, ptr @.func.6, i64 4, i32 9) - br label %checkok5 - -checkok5: ; preds = %panic4, %checkok2 - %ge6 = icmp sge i64 %3, 1 - br i1 %ge6, label %panic7, label %checkok8 - + %11 = load i64, ptr %z, align 8 + %lt6 = icmp slt i64 %11, 0 + br i1 %lt6, label %panic7, label %checkok11 panic7: ; preds = %checkok5 - %5 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %5(ptr @.panic_msg.7, i64 63, ptr @.file.8, i64 19, ptr @.func.9, i64 4, i32 9) - br label %checkok8 - -checkok8: ; preds = %panic7, %checkok5 - %trunc9 = trunc i64 %3 to i8 - store i8 %trunc9, ptr %y, align 1 + store i64 %11, ptr %taddr8, align 8 + %12 = insertvalue %any undef, ptr %taddr8, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %14 = getelementptr inbounds [1 x %any], ptr %varargslots9, i64 0, i64 0 + store %any %13, ptr %14, align 16 + %15 = insertvalue %"any[]" undef, ptr %varargslots9, 0 + %16 = insertvalue %"any[]" %15, i64 1, 1 + store %"any[]" %16, ptr %indirectarg10, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.2, i64 8, ptr @.file, i64 19, ptr @.func, i64 4, i32 9, ptr byval(%"any[]") align 8 %indirectarg10) + br label %checkok11 +checkok11: ; preds = %panic7, %checkok5 + %ge12 = icmp sge i64 %11, 1 + br i1 %ge12, label %panic13, label %checkok17 +panic13: ; preds = %checkok11 + store i64 %11, ptr %taddr14, align 8 + %17 = insertvalue %any undef, ptr %taddr14, 0 + %18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %19 = getelementptr inbounds [1 x %any], ptr %varargslots15, i64 0, i64 0 + store %any %18, ptr %19, align 16 + %20 = insertvalue %"any[]" undef, ptr %varargslots15, 0 + %21 = insertvalue %"any[]" %20, i64 1, 1 + store %"any[]" %21, ptr %indirectarg16, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 87, ptr @.file, i64 19, ptr @.func, i64 4, i32 9, ptr byval(%"any[]") align 8 %indirectarg16) + br label %checkok17 +checkok17: ; preds = %panic13, %checkok11 + %trunc18 = trunc i64 %11 to i8 + store i8 %trunc18, ptr %y, align 1 store i32 256, ptr %a, align 4 - %6 = load i32, ptr %a, align 4 - %lt10 = icmp slt i32 %6, 0 - br i1 %lt10, label %panic11, label %checkok12 - -panic11: ; preds = %checkok8 - %7 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %7(ptr @.panic_msg.10, i64 68, ptr @.file.11, i64 19, ptr @.func.12, i64 4, i32 11) - br label %checkok12 - -checkok12: ; preds = %panic11, %checkok8 - %ge13 = icmp sge i32 %6, 1 - br i1 %ge13, label %panic14, label %checkok15 - -panic14: ; preds = %checkok12 - %8 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %8(ptr @.panic_msg.13, i64 63, ptr @.file.14, i64 19, ptr @.func.15, i64 4, i32 11) - br label %checkok15 - -checkok15: ; preds = %panic14, %checkok12 - %trunc16 = trunc i32 %6 to i8 - store i8 %trunc16, ptr %y, align 1 + %22 = load i32, ptr %a, align 4 + %lt19 = icmp slt i32 %22, 0 + br i1 %lt19, label %panic20, label %checkok24 +panic20: ; preds = %checkok17 + store i32 %22, ptr %taddr21, align 4 + %23 = insertvalue %any undef, ptr %taddr21, 0 + %24 = insertvalue %any %23, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %25 = getelementptr inbounds [1 x %any], ptr %varargslots22, i64 0, i64 0 + store %any %24, ptr %25, align 16 + %26 = insertvalue %"any[]" undef, ptr %varargslots22, 0 + %27 = insertvalue %"any[]" %26, i64 1, 1 + store %"any[]" %27, ptr %indirectarg23, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.3, i64 62, ptr @.file, i64 19, ptr @.func, i64 4, i32 11, ptr byval(%"any[]") align 8 %indirectarg23) + br label %checkok24 +checkok24: ; preds = %panic20, %checkok17 + %ge25 = icmp sge i32 %22, 1 + br i1 %ge25, label %panic26, label %checkok30 +panic26: ; preds = %checkok24 + store i32 %22, ptr %taddr27, align 4 + %28 = insertvalue %any undef, ptr %taddr27, 0 + %29 = insertvalue %any %28, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %30 = getelementptr inbounds [1 x %any], ptr %varargslots28, i64 0, i64 0 + store %any %29, ptr %30, align 16 + %31 = insertvalue %"any[]" undef, ptr %varargslots28, 0 + %32 = insertvalue %"any[]" %31, i64 1, 1 + store %"any[]" %32, ptr %indirectarg29, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 87, ptr @.file, i64 19, ptr @.func, i64 4, i32 11, ptr byval(%"any[]") align 8 %indirectarg29) + br label %checkok30 +checkok30: ; preds = %panic26, %checkok24 + %trunc31 = trunc i32 %22 to i8 + store i8 %trunc31, ptr %y, align 1 store i32 -1, ptr %a, align 4 - %9 = load i32, ptr %a, align 4 - %lt17 = icmp slt i32 %9, 0 - br i1 %lt17, label %panic18, label %checkok19 - -panic18: ; preds = %checkok15 - %10 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %10(ptr @.panic_msg.16, i64 68, ptr @.file.17, i64 19, ptr @.func.18, i64 4, i32 13) - br label %checkok19 - -checkok19: ; preds = %panic18, %checkok15 - %ge20 = icmp sge i32 %9, 1 - br i1 %ge20, label %panic21, label %checkok22 - -panic21: ; preds = %checkok19 - %11 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %11(ptr @.panic_msg.19, i64 63, ptr @.file.20, i64 19, ptr @.func.21, i64 4, i32 13) - br label %checkok22 - -checkok22: ; preds = %panic21, %checkok19 - %trunc23 = trunc i32 %9 to i8 - store i8 %trunc23, ptr %y, align 1 + %33 = load i32, ptr %a, align 4 + %lt32 = icmp slt i32 %33, 0 + br i1 %lt32, label %panic33, label %checkok37 +panic33: ; preds = %checkok30 + store i32 %33, ptr %taddr34, align 4 + %34 = insertvalue %any undef, ptr %taddr34, 0 + %35 = insertvalue %any %34, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %36 = getelementptr inbounds [1 x %any], ptr %varargslots35, i64 0, i64 0 + store %any %35, ptr %36, align 16 + %37 = insertvalue %"any[]" undef, ptr %varargslots35, 0 + %38 = insertvalue %"any[]" %37, i64 1, 1 + store %"any[]" %38, ptr %indirectarg36, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.3, i64 62, ptr @.file, i64 19, ptr @.func, i64 4, i32 13, ptr byval(%"any[]") align 8 %indirectarg36) + br label %checkok37 +checkok37: ; preds = %panic33, %checkok30 + %ge38 = icmp sge i32 %33, 1 + br i1 %ge38, label %panic39, label %checkok43 +panic39: ; preds = %checkok37 + store i32 %33, ptr %taddr40, align 4 + %39 = insertvalue %any undef, ptr %taddr40, 0 + %40 = insertvalue %any %39, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %41 = getelementptr inbounds [1 x %any], ptr %varargslots41, i64 0, i64 0 + store %any %40, ptr %41, align 16 + %42 = insertvalue %"any[]" undef, ptr %varargslots41, 0 + %43 = insertvalue %"any[]" %42, i64 1, 1 + store %"any[]" %43, ptr %indirectarg42, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 87, ptr @.file, i64 19, ptr @.func, i64 4, i32 13, ptr byval(%"any[]") align 8 %indirectarg42) + br label %checkok43 +checkok43: ; preds = %panic39, %checkok37 + %trunc44 = trunc i32 %33 to i8 + store i8 %trunc44, ptr %y, align 1 ret void } diff --git a/test/test_suite/enumerations/enum_reflect_associated.c3t b/test/test_suite/enumerations/enum_reflect_associated.c3t new file mode 100644 index 000000000..eab4167bb --- /dev/null +++ b/test/test_suite/enumerations/enum_reflect_associated.c3t @@ -0,0 +1,53 @@ +// #target: macos-x64 +module test; +import std::io; + +enum Abc : int (int x, double y, String z) +{ + OFEKFE(1, 2.0, "foek"), +} + +fn int main() +{ + $foreach ($type : Abc.associated) + io::printfn("%s", $type.qnameof); + $endforeach + return 0; +} +/* #expect: test.ll + +@.str.2 = private unnamed_addr constant [4 x i8] c"int\00", align 1 +@.str.4 = private unnamed_addr constant [7 x i8] c"double\00", align 1 +@.str.6 = private unnamed_addr constant [7 x i8] c"String\00", align 1 + +define i32 @main() #0 { +entry: + %retparam = alloca i64, align 8 + %varargslots = alloca [1 x %any], align 16 + %taddr = alloca %"char[]", align 8 + %retparam1 = alloca i64, align 8 + %varargslots2 = alloca [1 x %any], align 16 + %taddr3 = alloca %"char[]", align 8 + %retparam4 = alloca i64, align 8 + %varargslots5 = alloca [1 x %any], align 16 + %taddr6 = alloca %"char[]", align 8 + store %"char[]" { ptr @.str.2, i64 3 }, ptr %taddr, align 8 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %2 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %1, ptr %2, align 16 + %3 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.1, i64 2, ptr %varargslots, i64 1) + store %"char[]" { ptr @.str.4, i64 6 }, ptr %taddr3, align 8 + %4 = insertvalue %any undef, ptr %taddr3, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %5, ptr %6, align 16 + %7 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.3, i64 2, ptr %varargslots2, i64 1) + store %"char[]" { ptr @.str.6, i64 6 }, ptr %taddr6, align 8 + %8 = insertvalue %any undef, ptr %taddr6, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %10 = getelementptr inbounds [1 x %any], ptr %varargslots5, i64 0, i64 0 + store %any %9, ptr %10, align 16 + %11 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.5, i64 2, ptr %varargslots5, i64 1) + ret i32 0 +} diff --git a/test/test_suite/errors/anyerr_void.c3t b/test/test_suite/errors/anyfault_void.c3t similarity index 82% rename from test/test_suite/errors/anyerr_void.c3t rename to test/test_suite/errors/anyfault_void.c3t index 00d77638b..bb38e7ee1 100644 --- a/test/test_suite/errors/anyerr_void.c3t +++ b/test/test_suite/errors/anyfault_void.c3t @@ -5,7 +5,7 @@ fault MyError } fn void! errorThing() { - return MyError.BAR!; + return MyError.BAR?; } fn void! errorThing2() @@ -16,7 +16,7 @@ fn void! errorThing2() extern fn void printf(char*, ...); fn void main() { - anyerr z = errorThing(); + anyfault z = errorThing(); printf("Z; %llx\n", (iptr)(z)); printf("BAR: %llx\n", (iptr)(MyError.BAR)); printf("FOO: %llx\n", (iptr)(MyError.FOO)); @@ -24,15 +24,15 @@ fn void main() printf("Z2: %llx\n", (iptr)(z)); } -/* #expect: anyerr_void.ll +/* #expect: anyfault_void.ll -define i64 @anyerr_void.errorThing() #0 { +define i64 @anyfault_void.errorThing() #0 { entry: - ret i64 ptrtoint (ptr @"anyerr_void.MyError$BAR" to i64) + ret i64 ptrtoint (ptr @"anyfault_void.MyError$BAR" to i64) } ; Function Attrs: nounwind -define i64 @anyerr_void.errorThing2() #0 { +define i64 @anyfault_void.errorThing2() #0 { entry: %reterr = alloca i64, align 8 ret i64 0 @@ -42,13 +42,13 @@ entry: declare void @printf(ptr, ...) #0 ; Function Attrs: nounwind -define void @anyerr_void.main() #0 { +define void @anyfault_void.main() #0 { entry: %z = alloca i64, align 8 %error_var = alloca i64, align 8 %error_var1 = alloca i64, align 8 store i64 0, ptr %error_var, align 8 - %0 = call i64 @anyerr_void.errorThing() + %0 = call i64 @anyfault_void.errorThing() %not_err = icmp eq i64 %0, 0 %1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) br i1 %1, label %after_check, label %assign_optional @@ -65,10 +65,10 @@ noerr_block: ; preds = %after_check, %assig store i64 %2, ptr %z, align 8 %3 = load i64, ptr %z, align 8 call void (ptr, ...) @printf(ptr @.str, i64 %3) - call void (ptr, ...) @printf(ptr @.str.2, i64 ptrtoint (ptr @"anyerr_void.MyError$BAR" to i64)) - call void (ptr, ...) @printf(ptr @.str.3, i64 ptrtoint (ptr @"anyerr_void.MyError$FOO" to i64)) + call void (ptr, ...) @printf(ptr @.str.2, i64 ptrtoint (ptr @"anyfault_void.MyError$BAR" to i64)) + call void (ptr, ...) @printf(ptr @.str.3, i64 ptrtoint (ptr @"anyfault_void.MyError$FOO" to i64)) store i64 0, ptr %error_var1, align 8 - %4 = call i64 @anyerr_void.errorThing2() + %4 = call i64 @anyfault_void.errorThing2() %not_err2 = icmp eq i64 %4, 0 %5 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true) br i1 %5, label %after_check4, label %assign_optional3 diff --git a/test/test_suite/errors/bitshift_failable.c3 b/test/test_suite/errors/bitshift_failable.c3 index f649501f3..61ab084c9 100644 --- a/test/test_suite/errors/bitshift_failable.c3 +++ b/test/test_suite/errors/bitshift_failable.c3 @@ -1,5 +1,5 @@ fn void test() { int! x = 0; - int! z = x << 100; // #error: shift exceeds bitsize of 'int' + int! z = x << 100; // #error: the bitsize of 'int' } \ No newline at end of file diff --git a/test/test_suite/errors/empty_fault.c3 b/test/test_suite/errors/empty_fault.c3 new file mode 100644 index 000000000..855ecfbb5 --- /dev/null +++ b/test/test_suite/errors/empty_fault.c3 @@ -0,0 +1,4 @@ +module test; +fault Foo +{ +} // #error: no values \ No newline at end of file diff --git a/test/test_suite/errors/error_else.c3t b/test/test_suite/errors/error_else.c3t index cf6ce3134..c818323fd 100644 --- a/test/test_suite/errors/error_else.c3t +++ b/test/test_suite/errors/error_else.c3t @@ -10,7 +10,7 @@ import foo; fn int! abc() { - return Baz.TEST!; + return Baz.TEST?; } module baz; @@ -18,5 +18,5 @@ import foo; fn int! abc() { - return Baz.TEST!; + return Baz.TEST?; } diff --git a/test/test_suite/errors/error_introspect.c3t b/test/test_suite/errors/error_introspect.c3t index 8610381f3..4084093dd 100644 --- a/test/test_suite/errors/error_introspect.c3t +++ b/test/test_suite/errors/error_introspect.c3t @@ -39,12 +39,12 @@ entry: %x = alloca %"String[]", align 8 %literal = alloca [2 x %"char[]"], align 16 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [1 x %variant], align 16 + %varargslots2 = alloca [1 x %any], align 16 %literal3 = alloca [2 x i64], align 16 %retparam4 = alloca i64, align 8 - %varargslots5 = alloca [1 x %variant], align 16 + %varargslots5 = alloca [1 x %any], align 16 %taddr = alloca i64, align 8 %0 = getelementptr inbounds [2 x %"char[]"], ptr %literal, i64 0, i64 0 store %"char[]" { ptr @.str, i64 3 }, ptr %0, align 8 @@ -53,25 +53,25 @@ entry: %2 = insertvalue %"String[]" undef, ptr %literal, 0 %3 = insertvalue %"String[]" %2, i64 2, 1 store %"String[]" %3, ptr %x, align 8 - %4 = insertvalue %variant undef, ptr %x, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.sa$String" to i64), 1 - %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %x, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.sa$String" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.3, i64 13, ptr %varargslots, i64 1) %8 = getelementptr inbounds [2 x i64], ptr %literal3, i64 0, i64 0 store i64 ptrtoint (ptr @"foo.Foo$BAR" to i64), ptr %8, align 8 %9 = getelementptr inbounds [2 x i64], ptr %literal3, i64 0, i64 1 store i64 ptrtoint (ptr @"foo.Foo$BAZ" to i64), ptr %9, align 8 - %10 = insertvalue %variant undef, ptr %literal3, 0 - %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"$ct.a2$foo.Foo" to i64), 1 - %12 = getelementptr inbounds [1 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %11, ptr %12, align 16 + %10 = insertvalue %any undef, ptr %literal3, 0 + %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.a2$foo.Foo" to i64), 1 + %12 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %11, ptr %12, align 16 %13 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.4, i64 14, ptr %varargslots2, i64 1) store i64 2, ptr %taddr, align 8 - %14 = insertvalue %variant undef, ptr %taddr, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %16 = getelementptr inbounds [1 x %variant], ptr %varargslots5, i64 0, i64 0 - store %variant %15, ptr %16, align 16 + %14 = insertvalue %any undef, ptr %taddr, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %16 = getelementptr inbounds [1 x %any], ptr %varargslots5, i64 0, i64 0 + store %any %15, ptr %16, align 16 %17 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.5, i64 16, ptr %varargslots5, i64 1) ret void } diff --git a/test/test_suite/errors/error_regression_2.c3t b/test/test_suite/errors/error_regression_2.c3t index 285ab6cbc..a942beb91 100644 --- a/test/test_suite/errors/error_regression_2.c3t +++ b/test/test_suite/errors/error_regression_2.c3t @@ -40,7 +40,7 @@ fn bool contains(char[] haystack, char[] needle) macro dupe(value) { $typeof(&value) temp = malloc($sizeof(value)); - if (!temp) return ReadError.OUT_OF_MEMORY!; + if (!temp) return ReadError.OUT_OF_MEMORY?; *temp = value; return temp; } @@ -53,16 +53,16 @@ fault ReadError fn Doc! readDoc(char[] url) { - if (contains(url, "fail")) return ReadError.BAD_READ!; + if (contains(url, "fail")) return ReadError.BAD_READ?; if (contains(url, "head-missing")) return { .head = null }; - if (contains(url, "title-missing")) return { dupe(Head { .title = null })? }; - if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")? })? }; + if (contains(url, "title-missing")) return { dupe(Head { .title = null })! }; + if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")! })! }; // Not particularly elegant due to missing string functions. int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr); char* str = malloc(len + 1); - if (!str) return ReadError.OUT_OF_MEMORY!; + if (!str) return ReadError.OUT_OF_MEMORY?; libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr); - return { dupe(Head { .title = dupe(str[..len - 1])? })? }; + return { dupe(Head { .title = dupe(str[..len - 1])! })! }; } fn Summary buildSummary(Doc doc) @@ -96,9 +96,9 @@ fault TitleResult fn bool! isTitleNonEmpty(Doc doc) { - if (!doc.head) return TitleResult.TITLE_MISSING!; + if (!doc.head) return TitleResult.TITLE_MISSING?; char[]* head = doc.head.title; - if (!head) return TitleResult.TITLE_MISSING!; + if (!head) return TitleResult.TITLE_MISSING?; return (*head).len > 0; } @@ -112,7 +112,7 @@ fn char* bool_to_string(bool b) { return b ? "true" : "false"; } -fn char* nameFromError(anyerr e) +fn char* nameFromError(anyfault e) { switch (e) { @@ -144,7 +144,7 @@ fn void main() bool! has_title = readWhetherTitleNonEmpty(url); // This looks a bit less than elegant, but as you see it's mostly due to having to // use printf here. - libc::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? nameFromError(catch? has_title), (has_title ?? false) ? (char*)"true" : (char*)"false"); + libc::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? nameFromError(@catchof(has_title)), (has_title ?? false) ? (char*)"true" : (char*)"false"); } } @@ -168,7 +168,7 @@ cond.rhs: ; preds = %entry br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs - %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.41, i64 7 }, %cond.rhs ] + %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.26, i64 7 }, %cond.rhs ] store %"char[]" %val, ptr %title, align 8 %7 = getelementptr inbounds %"char[]", ptr %title, i32 0, i32 1 %8 = load i64, ptr %7, align 8 @@ -178,8 +178,8 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %11 = getelementptr inbounds %Summary, ptr %0, i32 0, i32 1 %12 = load i8, ptr %11, align 8 %13 = trunc i8 %12 to i1 - %ternary = select i1 %13, ptr @.str.43, ptr @.str.44 - %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.42, i32 %trunc, ptr %10, ptr %ternary) + %ternary = select i1 %13, ptr @.str.28, ptr @.str.29 + %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.27, i32 %trunc, ptr %10, ptr %ternary) ret void } @@ -273,72 +273,78 @@ entry: %temp = alloca ptr, align 8 %using = alloca ptr, align 8 %end_padding = alloca i64, align 8 - %error_var13 = alloca i64, align 8 - %using14 = alloca ptr, align 8 - %end_padding15 = alloca i64, align 8 + %error_var11 = alloca i64, align 8 + %using12 = alloca ptr, align 8 + %end_padding13 = alloca i64, align 8 %.anon = alloca i64, align 8 - %blockret16 = alloca ptr, align 8 %retparam = alloca ptr, align 8 - %reterr24 = alloca i64, align 8 - %literal25 = alloca %Doc, align 8 + %varargslots = alloca [1 x %any], align 16 + %indirectarg = alloca %"any[]", align 8 + %reterr21 = alloca i64, align 8 + %literal22 = alloca %Doc, align 8 + %error_var23 = alloca i64, align 8 + %value24 = alloca %Head, align 8 + %literal25 = alloca %Head, align 8 %error_var26 = alloca i64, align 8 - %value27 = alloca %Head, align 8 - %literal28 = alloca %Head, align 8 - %error_var29 = alloca i64, align 8 - %value30 = alloca %"char[]", align 8 - %temp31 = alloca ptr, align 8 + %value27 = alloca %"char[]", align 8 + %temp28 = alloca ptr, align 8 + %using29 = alloca ptr, align 8 + %end_padding30 = alloca i64, align 8 + %error_var31 = alloca i64, align 8 %using32 = alloca ptr, align 8 - %end_padding34 = alloca i64, align 8 - %error_var36 = alloca i64, align 8 - %using37 = alloca ptr, align 8 - %end_padding38 = alloca i64, align 8 - %.anon39 = alloca i64, align 8 - %blockret40 = alloca ptr, align 8 - %retparam41 = alloca ptr, align 8 - %temp54 = alloca ptr, align 8 - %using55 = alloca ptr, align 8 - %end_padding57 = alloca i64, align 8 - %error_var59 = alloca i64, align 8 - %using60 = alloca ptr, align 8 - %end_padding61 = alloca i64, align 8 - %.anon62 = alloca i64, align 8 - %blockret63 = alloca ptr, align 8 - %retparam64 = alloca ptr, align 8 + %end_padding33 = alloca i64, align 8 + %.anon34 = alloca i64, align 8 + %retparam35 = alloca ptr, align 8 + %varargslots41 = alloca [1 x %any], align 16 + %indirectarg42 = alloca %"any[]", align 8 + %temp49 = alloca ptr, align 8 + %using50 = alloca ptr, align 8 + %end_padding51 = alloca i64, align 8 + %error_var52 = alloca i64, align 8 + %using53 = alloca ptr, align 8 + %end_padding54 = alloca i64, align 8 + %.anon55 = alloca i64, align 8 + %retparam56 = alloca ptr, align 8 + %varargslots62 = alloca [1 x %any], align 16 + %indirectarg63 = alloca %"any[]", align 8 %len = alloca i32, align 4 %str = alloca ptr, align 8 - %using78 = alloca ptr, align 8 - %end_padding79 = alloca i64, align 8 - %error_var80 = alloca i64, align 8 - %using81 = alloca ptr, align 8 - %end_padding82 = alloca i64, align 8 - %.anon83 = alloca i32, align 4 - %blockret85 = alloca ptr, align 8 - %retparam86 = alloca ptr, align 8 - %reterr100 = alloca i64, align 8 - %literal101 = alloca %Doc, align 8 - %error_var102 = alloca i64, align 8 - %value103 = alloca %Head, align 8 - %literal104 = alloca %Head, align 8 + %using71 = alloca ptr, align 8 + %end_padding72 = alloca i64, align 8 + %error_var73 = alloca i64, align 8 + %using74 = alloca ptr, align 8 + %end_padding75 = alloca i64, align 8 + %.anon76 = alloca i32, align 4 + %retparam78 = alloca ptr, align 8 + %varargslots84 = alloca [1 x %any], align 16 + %indirectarg85 = alloca %"any[]", align 8 + %reterr93 = alloca i64, align 8 + %literal94 = alloca %Doc, align 8 + %error_var95 = alloca i64, align 8 + %value96 = alloca %Head, align 8 + %literal97 = alloca %Head, align 8 + %error_var98 = alloca i64, align 8 + %value99 = alloca %"char[]", align 8 + %temp102 = alloca ptr, align 8 + %using103 = alloca ptr, align 8 + %end_padding104 = alloca i64, align 8 %error_var105 = alloca i64, align 8 - %value106 = alloca %"char[]", align 8 - %temp109 = alloca ptr, align 8 - %using110 = alloca ptr, align 8 - %end_padding112 = alloca i64, align 8 - %error_var114 = alloca i64, align 8 - %using115 = alloca ptr, align 8 - %end_padding116 = alloca i64, align 8 - %.anon117 = alloca i64, align 8 - %blockret118 = alloca ptr, align 8 - %retparam119 = alloca ptr, align 8 - %temp132 = alloca ptr, align 8 - %using133 = alloca ptr, align 8 - %end_padding135 = alloca i64, align 8 - %error_var137 = alloca i64, align 8 - %using138 = alloca ptr, align 8 - %end_padding139 = alloca i64, align 8 - %.anon140 = alloca i64, align 8 - %blockret141 = alloca ptr, align 8 - %retparam142 = alloca ptr, align 8 + %using106 = alloca ptr, align 8 + %end_padding107 = alloca i64, align 8 + %.anon108 = alloca i64, align 8 + %retparam109 = alloca ptr, align 8 + %varargslots115 = alloca [1 x %any], align 16 + %indirectarg116 = alloca %"any[]", align 8 + %temp123 = alloca ptr, align 8 + %using124 = alloca ptr, align 8 + %end_padding125 = alloca i64, align 8 + %error_var126 = alloca i64, align 8 + %using127 = alloca ptr, align 8 + %end_padding128 = alloca i64, align 8 + %.anon129 = alloca i64, align 8 + %retparam130 = alloca ptr, align 8 + %varargslots136 = alloca [1 x %any], align 16 + %indirectarg137 = alloca %"any[]", align 8 store ptr %1, ptr %url, align 8 %ptroffset = getelementptr inbounds i64, ptr %url, i64 1 store i64 %2, ptr %ptroffset, align 8 @@ -375,7 +381,7 @@ if.exit4: ; preds = %if.exit %hi6 = load i64, ptr %13, align 8 %14 = call i8 @test.contains(ptr %lo5, i64 %hi6, ptr @.str.4, i64 13) %15 = trunc i8 %14 to i1 - br i1 %15, label %if.then7, label %if.exit20 + br i1 %15, label %if.then7, label %if.exit17 if.then7: ; preds = %if.exit4 %16 = getelementptr inbounds %Doc, ptr %literal9, i32 0, i32 0 @@ -386,13 +392,13 @@ if.then7: ; preds = %if.exit4 store ptr %18, ptr %using, align 8 store i64 0, ptr %end_padding, align 8 %19 = load ptr, ptr %using, align 8 - store ptr %19, ptr %using14, align 8 + store ptr %19, ptr %using12, align 8 %20 = load i64, ptr %end_padding, align 8 - store i64 %20, ptr %end_padding15, align 8 + store i64 %20, ptr %end_padding13, align 8 store i64 8, ptr %.anon, align 8 - %21 = load ptr, ptr %using14, align 8 + %21 = load ptr, ptr %using12, align 8 %22 = load i64, ptr %.anon, align 8 - %23 = load i64, ptr %end_padding15, align 8 + %23 = load i64, ptr %end_padding13, align 8 %add = add i64 %22, %23 %24 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam, ptr %21, i64 %add) #3 %not_err = icmp eq i64 %24, 0 @@ -400,375 +406,381 @@ if.then7: ; preds = %if.exit4 br i1 %25, label %after_check, label %assign_optional assign_optional: ; preds = %if.then7 - store i64 %24, ptr %error_var13, align 8 + store i64 %24, ptr %error_var11, align 8 br label %panic_block after_check: ; preds = %if.then7 %26 = load ptr, ptr %retparam, align 8 - store ptr %26, ptr %blockret16, align 8 - br label %expr_block.exit - -expr_block.exit: ; preds = %after_check - %27 = load ptr, ptr %blockret16, align 8 br label %noerr_block panic_block: ; preds = %assign_optional - %28 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %28(ptr @.panic_msg, i64 27, ptr @.file, i64 6, ptr @.func + %27 = insertvalue %any undef, ptr %error_var11, 0 + %28 = insertvalue %any %27, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %29 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %28, ptr %29, align 16 + %30 = insertvalue %"any[]" undef, ptr %varargslots, 0 + %31 = insertvalue %"any[]" %30, i64 1, 1 + store %"any[]" %31, ptr %indirectarg, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg) unreachable -noerr_block: ; preds = %expr_block.exit - store ptr %27, ptr %temp, align 8 - %29 = load ptr, ptr %temp, align 8 - %not = icmp eq ptr %29, null - br i1 %not, label %if.then17, label %if.exit18 +noerr_block: ; preds = %after_check + store ptr %26, ptr %temp, align 8 + %32 = load ptr, ptr %temp, align 8 + %not = icmp eq ptr %32, null + br i1 %not, label %if.then14, label %if.exit15 -if.then17: ; preds = %noerr_block +if.then14: ; preds = %noerr_block store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var, align 8 br label %guard_block -if.exit18: ; preds = %noerr_block - %30 = load ptr, ptr %temp, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %30, ptr align 8 %value, i32 8, i1 false) - br label %noerr_block19 +if.exit15: ; preds = %noerr_block + %33 = load ptr, ptr %temp, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %33, ptr align 8 %value, i32 8, i1 false) + br label %noerr_block16 -guard_block: ; preds = %if.then17 - %31 = load i64, ptr %error_var, align 8 - ret i64 %31 +guard_block: ; preds = %if.then14 + %34 = load i64, ptr %error_var, align 8 + ret i64 %34 -noerr_block19: ; preds = %if.exit18 - %32 = load ptr, ptr %temp, align 8 - store ptr %32, ptr %16, align 8 +noerr_block16: ; preds = %if.exit15 + %35 = load ptr, ptr %temp, align 8 + store ptr %35, ptr %16, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal9, i32 8, i1 false) ret i64 0 -if.exit20: ; preds = %if.exit4 - %33 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %lo21 = load ptr, ptr %33, align 8 - %34 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %hi22 = load i64, ptr %34, align 8 - %35 = call i8 @test.contains(ptr %lo21, i64 %hi22, ptr @.str.5, i64 11) - %36 = trunc i8 %35 to i1 - br i1 %36, label %if.then23, label %if.exit77 +if.exit17: ; preds = %if.exit4 + %36 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %lo18 = load ptr, ptr %36, align 8 + %37 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %hi19 = load i64, ptr %37, align 8 + %38 = call i8 @test.contains(ptr %lo18, i64 %hi19, ptr @.str.5, i64 11) + %39 = trunc i8 %38 to i1 + br i1 %39, label %if.then20, label %if.exit70 -if.then23: ; preds = %if.exit20 - %37 = getelementptr inbounds %Doc, ptr %literal25, i32 0, i32 0 - store ptr null, ptr %literal28, align 8 - %38 = getelementptr inbounds %Head, ptr %literal28, i32 0, i32 0 - store %"char[]" zeroinitializer, ptr %value30, align 8 - %39 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %39, ptr %using32, align 8 - store i64 0, ptr %end_padding34, align 8 - %40 = load ptr, ptr %using32, align 8 - store ptr %40, ptr %using37, align 8 - %41 = load i64, ptr %end_padding34, align 8 - store i64 %41, ptr %end_padding38, align 8 - store i64 16, ptr %.anon39, align 8 - %42 = load ptr, ptr %using37, align 8 - %43 = load i64, ptr %.anon39, align 8 - %44 = load i64, ptr %end_padding38, align 8 - %add42 = add i64 %43, %44 - %45 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam41, ptr %42, i64 %add42) #3 - %not_err43 = icmp eq i64 %45, 0 - %46 = call i1 @llvm.expect.i1(i1 %not_err43, i1 true) - br i1 %46, label %after_check45, label %assign_optional44 +if.then20: ; preds = %if.exit17 + %40 = getelementptr inbounds %Doc, ptr %literal22, i32 0, i32 0 + store ptr null, ptr %literal25, align 8 + %41 = getelementptr inbounds %Head, ptr %literal25, i32 0, i32 0 + store %"char[]" zeroinitializer, ptr %value27, align 8 + %42 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %42, ptr %using29, align 8 + store i64 0, ptr %end_padding30, align 8 + %43 = load ptr, ptr %using29, align 8 + store ptr %43, ptr %using32, align 8 + %44 = load i64, ptr %end_padding30, align 8 + store i64 %44, ptr %end_padding33, align 8 + store i64 16, ptr %.anon34, align 8 + %45 = load ptr, ptr %using32, align 8 + %46 = load i64, ptr %.anon34, align 8 + %47 = load i64, ptr %end_padding33, align 8 + %add36 = add i64 %46, %47 + %48 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam35, ptr %45, i64 %add36) #3 + %not_err37 = icmp eq i64 %48, 0 + %49 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true) + br i1 %49, label %after_check39, label %assign_optional38 -assign_optional44: ; preds = %if.then23 - store i64 %45, ptr %error_var36, align 8 - br label %panic_block47 +assign_optional38: ; preds = %if.then20 + store i64 %48, ptr %error_var31, align 8 + br label %panic_block40 -after_check45: ; preds = %if.then23 - %47 = load ptr, ptr %retparam41, align 8 - store ptr %47, ptr %blockret40, align 8 - br label %expr_block.exit46 +after_check39: ; preds = %if.then20 + %50 = load ptr, ptr %retparam35, align 8 + br label %noerr_block43 -expr_block.exit46: ; preds = %after_check45 - %48 = load ptr, ptr %blockret40, align 8 +panic_block40: ; preds = %assign_optional38 + %51 = insertvalue %any undef, ptr %error_var31, 0 + %52 = insertvalue %any %51, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %53 = getelementptr inbounds [1 x %any], ptr %varargslots41, i64 0, i64 0 + store %any %52, ptr %53, align 16 + %54 = insertvalue %"any[]" undef, ptr %varargslots41, 0 + %55 = insertvalue %"any[]" %54, i64 1, 1 + store %"any[]" %55, ptr %indirectarg42, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg42) + unreachable + +noerr_block43: ; preds = %after_check39 + store ptr %50, ptr %temp28, align 8 + %56 = load ptr, ptr %temp28, align 8 + %not44 = icmp eq ptr %56, null + br i1 %not44, label %if.then45, label %if.exit46 + +if.then45: ; preds = %noerr_block43 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var26, align 8 + br label %guard_block47 + +if.exit46: ; preds = %noerr_block43 + %57 = load ptr, ptr %temp28, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %57, ptr align 8 %value27, i32 16, i1 false) br label %noerr_block48 -panic_block47: ; preds = %assign_optional44 - %49 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %49(ptr @.panic_msg.6, i64 27, ptr @.file.7, i64 6, ptr @.func.8, i64 7 +guard_block47: ; preds = %if.then45 + %58 = load i64, ptr %error_var26, align 8 + ret i64 %58 + +noerr_block48: ; preds = %if.exit46 + %59 = load ptr, ptr %temp28, align 8 + store ptr %59, ptr %41, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value24, ptr align 8 %literal25, i32 8, i1 false) + %60 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %60, ptr %using50, align 8 + store i64 0, ptr %end_padding51, align 8 + %61 = load ptr, ptr %using50, align 8 + store ptr %61, ptr %using53, align 8 + %62 = load i64, ptr %end_padding51, align 8 + store i64 %62, ptr %end_padding54, align 8 + store i64 8, ptr %.anon55, align 8 + %63 = load ptr, ptr %using53, align 8 + %64 = load i64, ptr %.anon55, align 8 + %65 = load i64, ptr %end_padding54, align 8 + %add57 = add i64 %64, %65 + %66 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam56, ptr %63, i64 %add57) #3 + %not_err58 = icmp eq i64 %66, 0 + %67 = call i1 @llvm.expect.i1(i1 %not_err58, i1 true) + br i1 %67, label %after_check60, label %assign_optional59 + +assign_optional59: ; preds = %noerr_block48 + store i64 %66, ptr %error_var52, align 8 + br label %panic_block61 + +after_check60: ; preds = %noerr_block48 + %68 = load ptr, ptr %retparam56, align 8 + br label %noerr_block64 + +panic_block61: ; preds = %assign_optional59 + %69 = insertvalue %any undef, ptr %error_var52, 0 + %70 = insertvalue %any %69, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %71 = getelementptr inbounds [1 x %any], ptr %varargslots62, i64 0, i64 0 + store %any %70, ptr %71, align 16 + %72 = insertvalue %"any[]" undef, ptr %varargslots62, 0 + %73 = insertvalue %"any[]" %72, i64 1, 1 + store %"any[]" %73, ptr %indirectarg63, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg63) unreachable -noerr_block48: ; preds = %expr_block.exit46 - store ptr %48, ptr %temp31, align 8 - %50 = load ptr, ptr %temp31, align 8 - %not49 = icmp eq ptr %50, null - br i1 %not49, label %if.then50, label %if.exit51 +noerr_block64: ; preds = %after_check60 + store ptr %68, ptr %temp49, align 8 + %74 = load ptr, ptr %temp49, align 8 + %not65 = icmp eq ptr %74, null + br i1 %not65, label %if.then66, label %if.exit67 -if.then50: ; preds = %noerr_block48 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var29, align 8 - br label %guard_block52 +if.then66: ; preds = %noerr_block64 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var23, align 8 + br label %guard_block68 -if.exit51: ; preds = %noerr_block48 - %51 = load ptr, ptr %temp31, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %51, ptr align 8 %value30, i32 16, i1 false) - br label %noerr_block53 +if.exit67: ; preds = %noerr_block64 + %75 = load ptr, ptr %temp49, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %75, ptr align 8 %value24, i32 8, i1 false) + br label %noerr_block69 -guard_block52: ; preds = %if.then50 - %52 = load i64, ptr %error_var29, align 8 - ret i64 %52 +guard_block68: ; preds = %if.then66 + %76 = load i64, ptr %error_var23, align 8 + ret i64 %76 -noerr_block53: ; preds = %if.exit51 - %53 = load ptr, ptr %temp31, align 8 - store ptr %53, ptr %38, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value27, ptr align 8 %literal28, i32 8, i1 false) - %54 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %54, ptr %using55, align 8 - store i64 0, ptr %end_padding57, align 8 - %55 = load ptr, ptr %using55, align 8 - store ptr %55, ptr %using60, align 8 - %56 = load i64, ptr %end_padding57, align 8 - store i64 %56, ptr %end_padding61, align 8 - store i64 8, ptr %.anon62, align 8 - %57 = load ptr, ptr %using60, align 8 - %58 = load i64, ptr %.anon62, align 8 - %59 = load i64, ptr %end_padding61, align 8 - %add65 = add i64 %58, %59 - %60 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam64, ptr %57, i64 %add65) #3 - %not_err66 = icmp eq i64 %60, 0 - %61 = call i1 @llvm.expect.i1(i1 %not_err66, i1 true) - br i1 %61, label %after_check68, label %assign_optional67 - -assign_optional67: ; preds = %noerr_block53 - store i64 %60, ptr %error_var59, align 8 - br label %panic_block70 - -after_check68: ; preds = %noerr_block53 - %62 = load ptr, ptr %retparam64, align 8 - store ptr %62, ptr %blockret63, align 8 - br label %expr_block.exit69 - -expr_block.exit69: ; preds = %after_check68 - %63 = load ptr, ptr %blockret63, align 8 - br label %noerr_block71 - -panic_block70: ; preds = %assign_optional67 - %64 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %64(ptr @.panic_msg.9, i64 27, ptr @.file.10, i64 6, ptr @.func.11, i64 7 - unreachable - -noerr_block71: ; preds = %expr_block.exit69 - store ptr %63, ptr %temp54, align 8 - %65 = load ptr, ptr %temp54, align 8 - %not72 = icmp eq ptr %65, null - br i1 %not72, label %if.then73, label %if.exit74 - -if.then73: ; preds = %noerr_block71 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var26, align 8 - br label %guard_block75 - -if.exit74: ; preds = %noerr_block71 - %66 = load ptr, ptr %temp54, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %66, ptr align 8 %value27, i32 8, i1 false) - br label %noerr_block76 - -guard_block75: ; preds = %if.then73 - %67 = load i64, ptr %error_var26, align 8 - ret i64 %67 - -noerr_block76: ; preds = %if.exit74 - %68 = load ptr, ptr %temp54, align 8 - store ptr %68, ptr %37, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal25, i32 8, i1 false) +noerr_block69: ; preds = %if.exit67 + %77 = load ptr, ptr %temp49, align 8 + store ptr %77, ptr %40, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal22, i32 8, i1 false) ret i64 0 -if.exit77: ; preds = %if.exit20 - %69 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %70 = load i64, ptr %69, align 8 - %trunc = trunc i64 %70 to i32 - %71 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %72 = load ptr, ptr %71, align 8 - %73 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.12, i32 %trunc, ptr %72) - store i32 %73, ptr %len, align 4 - %74 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %74, ptr %using78, align 8 - store i64 0, ptr %end_padding79, align 8 - %75 = load ptr, ptr %using78, align 8 - store ptr %75, ptr %using81, align 8 - %76 = load i64, ptr %end_padding79, align 8 - store i64 %76, ptr %end_padding82, align 8 - %77 = load i32, ptr %len, align 4 - %add84 = add i32 %77, 1 - store i32 %add84, ptr %.anon83, align 4 - %78 = load ptr, ptr %using81, align 8 - %79 = load i32, ptr %.anon83, align 4 - %sext = sext i32 %79 to i64 - %80 = load i64, ptr %end_padding82, align 8 - %add87 = add i64 %sext, %80 - %81 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam86, ptr %78, i64 %add87) #3 - %not_err88 = icmp eq i64 %81, 0 - %82 = call i1 @llvm.expect.i1(i1 %not_err88, i1 true) - br i1 %82, label %after_check90, label %assign_optional89 +if.exit70: ; preds = %if.exit17 + %78 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %79 = load i64, ptr %78, align 8 + %trunc = trunc i64 %79 to i32 + %80 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %81 = load ptr, ptr %80, align 8 + %82 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.6, i32 %trunc, ptr %81) + store i32 %82, ptr %len, align 4 + %83 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %83, ptr %using71, align 8 + store i64 0, ptr %end_padding72, align 8 + %84 = load ptr, ptr %using71, align 8 + store ptr %84, ptr %using74, align 8 + %85 = load i64, ptr %end_padding72, align 8 + store i64 %85, ptr %end_padding75, align 8 + %86 = load i32, ptr %len, align 4 + %add77 = add i32 %86, 1 + store i32 %add77, ptr %.anon76, align 4 + %87 = load ptr, ptr %using74, align 8 + %88 = load i32, ptr %.anon76, align 4 + %sext = sext i32 %88 to i64 + %89 = load i64, ptr %end_padding75, align 8 + %add79 = add i64 %sext, %89 + %90 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam78, ptr %87, i64 %add79) #3 + %not_err80 = icmp eq i64 %90, 0 + %91 = call i1 @llvm.expect.i1(i1 %not_err80, i1 true) + br i1 %91, label %after_check82, label %assign_optional81 -assign_optional89: ; preds = %if.exit77 - store i64 %81, ptr %error_var80, align 8 - br label %panic_block92 +assign_optional81: ; preds = %if.exit70 + store i64 %90, ptr %error_var73, align 8 + br label %panic_block83 -after_check90: ; preds = %if.exit77 - %83 = load ptr, ptr %retparam86, align 8 - store ptr %83, ptr %blockret85, align 8 - br label %expr_block.exit91 +after_check82: ; preds = %if.exit70 + %92 = load ptr, ptr %retparam78, align 8 + br label %noerr_block86 -expr_block.exit91: ; preds = %after_check90 - %84 = load ptr, ptr %blockret85, align 8 - br label %noerr_block93 - -panic_block92: ; preds = %assign_optional89 - %85 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %85(ptr @.panic_msg.13, i64 27, ptr @.file.14, i64 6, ptr @.func.15 +panic_block83: ; preds = %assign_optional81 + %93 = insertvalue %any undef, ptr %error_var73, 0 + %94 = insertvalue %any %93, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %95 = getelementptr inbounds [1 x %any], ptr %varargslots84, i64 0, i64 0 + store %any %94, ptr %95, align 16 + %96 = insertvalue %"any[]" undef, ptr %varargslots84, 0 + %97 = insertvalue %"any[]" %96, i64 1, 1 + store %"any[]" %97, ptr %indirectarg85, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg85) unreachable -noerr_block93: ; preds = %expr_block.exit91 - store ptr %84, ptr %str, align 8 - %86 = load ptr, ptr %str, align 8 - %not94 = icmp eq ptr %86, null - br i1 %not94, label %if.then95, label %if.exit96 +noerr_block86: ; preds = %after_check82 + store ptr %92, ptr %str, align 8 + %98 = load ptr, ptr %str, align 8 + %not87 = icmp eq ptr %98, null + br i1 %not87, label %if.then88, label %if.exit89 -if.then95: ; preds = %noerr_block93 +if.then88: ; preds = %noerr_block86 ret i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64) -if.exit96: ; preds = %noerr_block93 - %87 = load ptr, ptr %str, align 8 - %88 = load i32, ptr %len, align 4 - %sext97 = sext i32 %88 to i64 - %add98 = add i64 %sext97, 1 - %89 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %90 = load i64, ptr %89, align 8 - %trunc99 = trunc i64 %90 to i32 - %91 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %92 = load ptr, ptr %91, align 8 - %93 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %87, i64 %add98, ptr @.str.16, i32 %trunc99, ptr %92) - %94 = getelementptr inbounds %Doc, ptr %literal101, i32 0, i32 0 - store ptr null, ptr %literal104, align 8 - %95 = getelementptr inbounds %Head, ptr %literal104, i32 0, i32 0 - %96 = load ptr, ptr %str, align 8 - %97 = load i32, ptr %len, align 4 - %sub = sub i32 %97, 1 - %sext107 = sext i32 %sub to i64 - %98 = add i64 %sext107, 1 - %size = sub i64 %98, 0 - %ptroffset108 = getelementptr inbounds i8, ptr %96, i64 0 - %99 = insertvalue %"char[]" undef, ptr %ptroffset108, 0 - %100 = insertvalue %"char[]" %99, i64 %size, 1 - store %"char[]" %100, ptr %value106, align 8 - %101 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %101, ptr %using110, align 8 - store i64 0, ptr %end_padding112, align 8 - %102 = load ptr, ptr %using110, align 8 - store ptr %102, ptr %using115, align 8 - %103 = load i64, ptr %end_padding112, align 8 - store i64 %103, ptr %end_padding116, align 8 - store i64 16, ptr %.anon117, align 8 - %104 = load ptr, ptr %using115, align 8 - %105 = load i64, ptr %.anon117, align 8 - %106 = load i64, ptr %end_padding116, align 8 - %add120 = add i64 %105, %106 - %107 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam119, ptr %104, i64 %add120) #3 - %not_err121 = icmp eq i64 %107, 0 - %108 = call i1 @llvm.expect.i1(i1 %not_err121, i1 true) - br i1 %108, label %after_check123, label %assign_optional122 +if.exit89: ; preds = %noerr_block86 + %99 = load ptr, ptr %str, align 8 + %100 = load i32, ptr %len, align 4 + %sext90 = sext i32 %100 to i64 + %add91 = add i64 %sext90, 1 + %101 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %102 = load i64, ptr %101, align 8 + %trunc92 = trunc i64 %102 to i32 + %103 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %104 = load ptr, ptr %103, align 8 + %105 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %99, i64 %add91, ptr @.str.7, i32 %trunc92, ptr %104) + %106 = getelementptr inbounds %Doc, ptr %literal94, i32 0, i32 0 + store ptr null, ptr %literal97, align 8 + %107 = getelementptr inbounds %Head, ptr %literal97, i32 0, i32 0 + %108 = load ptr, ptr %str, align 8 + %109 = load i32, ptr %len, align 4 + %sub = sub i32 %109, 1 + %sext100 = sext i32 %sub to i64 + %110 = add i64 %sext100, 1 + %size = sub i64 %110, 0 + %ptroffset101 = getelementptr inbounds i8, ptr %108, i64 0 + %111 = insertvalue %"char[]" undef, ptr %ptroffset101, 0 + %112 = insertvalue %"char[]" %111, i64 %size, 1 + store %"char[]" %112, ptr %value99, align 8 + %113 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %113, ptr %using103, align 8 + store i64 0, ptr %end_padding104, align 8 + %114 = load ptr, ptr %using103, align 8 + store ptr %114, ptr %using106, align 8 + %115 = load i64, ptr %end_padding104, align 8 + store i64 %115, ptr %end_padding107, align 8 + store i64 16, ptr %.anon108, align 8 + %116 = load ptr, ptr %using106, align 8 + %117 = load i64, ptr %.anon108, align 8 + %118 = load i64, ptr %end_padding107, align 8 + %add110 = add i64 %117, %118 + %119 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam109, ptr %116, i64 %add110) #3 + %not_err111 = icmp eq i64 %119, 0 + %120 = call i1 @llvm.expect.i1(i1 %not_err111, i1 true) + br i1 %120, label %after_check113, label %assign_optional112 -assign_optional122: ; preds = %if.exit96 - store i64 %107, ptr %error_var114, align 8 - br label %panic_block125 +assign_optional112: ; preds = %if.exit89 + store i64 %119, ptr %error_var105, align 8 + br label %panic_block114 -after_check123: ; preds = %if.exit96 - %109 = load ptr, ptr %retparam119, align 8 - store ptr %109, ptr %blockret118, align 8 - br label %expr_block.exit124 +after_check113: ; preds = %if.exit89 + %121 = load ptr, ptr %retparam109, align 8 + br label %noerr_block117 -expr_block.exit124: ; preds = %after_check123 - %110 = load ptr, ptr %blockret118, align 8 - br label %noerr_block126 - -panic_block125: ; preds = %assign_optional122 - %111 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %111(ptr @.panic_msg.17, i64 27, ptr @.file.18, i64 6, ptr @.func.19 +panic_block114: ; preds = %assign_optional112 + %122 = insertvalue %any undef, ptr %error_var105, 0 + %123 = insertvalue %any %122, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %124 = getelementptr inbounds [1 x %any], ptr %varargslots115, i64 0, i64 0 + store %any %123, ptr %124, align 16 + %125 = insertvalue %"any[]" undef, ptr %varargslots115, 0 + %126 = insertvalue %"any[]" %125, i64 1, 1 + store %"any[]" %126, ptr %indirectarg116, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg116) unreachable -noerr_block126: ; preds = %expr_block.exit124 - store ptr %110, ptr %temp109, align 8 - %112 = load ptr, ptr %temp109, align 8 - %not127 = icmp eq ptr %112, null - br i1 %not127, label %if.then128, label %if.exit129 +noerr_block117: ; preds = %after_check113 + store ptr %121, ptr %temp102, align 8 + %127 = load ptr, ptr %temp102, align 8 + %not118 = icmp eq ptr %127, null + br i1 %not118, label %if.then119, label %if.exit120 -if.then128: ; preds = %noerr_block126 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var105, align 8 - br label %guard_block130 +if.then119: ; preds = %noerr_block117 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var98, align 8 + br label %guard_block121 -if.exit129: ; preds = %noerr_block126 - %113 = load ptr, ptr %temp109, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %113, ptr align 8 %value106, i32 16, i1 false) - br label %noerr_block131 +if.exit120: ; preds = %noerr_block117 + %128 = load ptr, ptr %temp102, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %128, ptr align 8 %value99, i32 16, i1 false) + br label %noerr_block122 -guard_block130: ; preds = %if.then128 - %114 = load i64, ptr %error_var105, align 8 - ret i64 %114 - -noerr_block131: ; preds = %if.exit129 - %115 = load ptr, ptr %temp109, align 8 - store ptr %115, ptr %95, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value103, ptr align 8 %literal104, i32 8, i1 false) - %116 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %116, ptr %using133, align 8 - store i64 0, ptr %end_padding135, align 8 - %117 = load ptr, ptr %using133, align 8 - store ptr %117, ptr %using138, align 8 - %118 = load i64, ptr %end_padding135, align 8 - store i64 %118, ptr %end_padding139, align 8 - store i64 8, ptr %.anon140, align 8 - %119 = load ptr, ptr %using138, align 8 - %120 = load i64, ptr %.anon140, align 8 - %121 = load i64, ptr %end_padding139, align 8 - %add143 = add i64 %120, %121 - %122 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam142, ptr %119, i64 %add143) #3 - %not_err144 = icmp eq i64 %122, 0 - %123 = call i1 @llvm.expect.i1(i1 %not_err144, i1 true) - br i1 %123, label %after_check146, label %assign_optional145 - -assign_optional145: ; preds = %noerr_block131 - store i64 %122, ptr %error_var137, align 8 - br label %panic_block148 - -after_check146: ; preds = %noerr_block131 - %124 = load ptr, ptr %retparam142, align 8 - store ptr %124, ptr %blockret141, align 8 - br label %expr_block.exit147 - -expr_block.exit147: ; preds = %after_check146 - %125 = load ptr, ptr %blockret141, align 8 - br label %noerr_block149 - -panic_block148: ; preds = %assign_optional145 - %126 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %126(ptr @.panic_msg.20, i64 27, ptr @.file.21, i64 6, ptr @.func.22 - unreachable - -noerr_block149: ; preds = %expr_block.exit147 - store ptr %125, ptr %temp132, align 8 - %127 = load ptr, ptr %temp132, align 8 - %not150 = icmp eq ptr %127, null - br i1 %not150, label %if.then151, label %if.exit152 - -if.then151: ; preds = %noerr_block149 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var102, align 8 - br label %guard_block153 - -if.exit152: ; preds = %noerr_block149 - %128 = load ptr, ptr %temp132, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %128, ptr align 8 %value103, i32 8, i1 false) - br label %noerr_block154 - -guard_block153: ; preds = %if.then151 - %129 = load i64, ptr %error_var102, align 8 +guard_block121: ; preds = %if.then119 + %129 = load i64, ptr %error_var98, align 8 ret i64 %129 -noerr_block154: ; preds = %if.exit152 - %130 = load ptr, ptr %temp132, align 8 - store ptr %130, ptr %94, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal101, i32 8, i1 false) +noerr_block122: ; preds = %if.exit120 + %130 = load ptr, ptr %temp102, align 8 + store ptr %130, ptr %107, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value96, ptr align 8 %literal97, i32 8, i1 false) + %131 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + store ptr %131, ptr %using124, align 8 + store i64 0, ptr %end_padding125, align 8 + %132 = load ptr, ptr %using124, align 8 + store ptr %132, ptr %using127, align 8 + %133 = load i64, ptr %end_padding125, align 8 + store i64 %133, ptr %end_padding128, align 8 + store i64 8, ptr %.anon129, align 8 + %134 = load ptr, ptr %using127, align 8 + %135 = load i64, ptr %.anon129, align 8 + %136 = load i64, ptr %end_padding128, align 8 + %add131 = add i64 %135, %136 + %137 = call i64 @std.core.mem.allocator.Allocator.alloc(ptr %retparam130, ptr %134, i64 %add131) #3 + %not_err132 = icmp eq i64 %137, 0 + %138 = call i1 @llvm.expect.i1(i1 %not_err132, i1 true) + br i1 %138, label %after_check134, label %assign_optional133 + +assign_optional133: ; preds = %noerr_block122 + store i64 %137, ptr %error_var126, align 8 + br label %panic_block135 + +after_check134: ; preds = %noerr_block122 + %139 = load ptr, ptr %retparam130, align 8 + br label %noerr_block138 + +panic_block135: ; preds = %assign_optional133 + %140 = insertvalue %any undef, ptr %error_var126, 0 + %141 = insertvalue %any %140, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %142 = getelementptr inbounds [1 x %any], ptr %varargslots136, i64 0, i64 0 + store %any %141, ptr %142, align 16 + %143 = insertvalue %"any[]" undef, ptr %varargslots136, 0 + %144 = insertvalue %"any[]" %143, i64 1, 1 + store %"any[]" %144, ptr %indirectarg137, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 200, ptr byval(%"any[]") align 8 %indirectarg137) + unreachable + +noerr_block138: ; preds = %after_check134 + store ptr %139, ptr %temp123, align 8 + %145 = load ptr, ptr %temp123, align 8 + %not139 = icmp eq ptr %145, null + br i1 %not139, label %if.then140, label %if.exit141 + +if.then140: ; preds = %noerr_block138 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var95, align 8 + br label %guard_block142 + +if.exit141: ; preds = %noerr_block138 + %146 = load ptr, ptr %temp123, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %146, ptr align 8 %value96, i32 8, i1 false) + br label %noerr_block143 + +guard_block142: ; preds = %if.then140 + %147 = load i64, ptr %error_var95, align 8 + ret i64 %147 + +noerr_block143: ; preds = %if.exit141 + %148 = load ptr, ptr %temp123, align 8 + store ptr %148, ptr %106, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal94, i32 8, i1 false) ret i64 0 } @@ -935,7 +947,7 @@ err_retblock: ; preds = %assign_optional3, % define ptr @test.bool_to_string(i8 zeroext %0) #0 { entry: %1 = trunc i8 %0 to i1 - %ternary = select i1 %1, %"char[]" { ptr @.str.23, i64 4 }, %"char[]" { ptr @.str.24, i64 5 } + %ternary = select i1 %1, %"char[]" { ptr @.str.8, i64 4 }, %"char[]" { ptr @.str.9, i64 5 } %2 = extractvalue %"char[]" %ternary, 0 ret ptr %2 } @@ -953,27 +965,27 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - ret ptr @.str.25 + ret ptr @.str.10 next_if: ; preds = %switch.entry %eq1 = icmp eq i64 ptrtoint (ptr @"test.ReadError$BAD_READ" to i64), %1 br i1 %eq1, label %switch.case2, label %next_if3 switch.case2: ; preds = %next_if - ret ptr @.str.26 + ret ptr @.str.11 next_if3: ; preds = %next_if %eq4 = icmp eq i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), %1 br i1 %eq4, label %switch.case5, label %next_if6 switch.case5: ; preds = %next_if3 - ret ptr @.str.27 + ret ptr @.str.12 next_if6: ; preds = %next_if3 br label %switch.default switch.default: ; preds = %next_if6 - ret ptr @.str.28 + ret ptr @.str.13 } ; Function Attrs: nounwind @@ -990,16 +1002,18 @@ entry: %has_title = alloca i8, align 1 %has_title.f = alloca i64, align 8 %retparam = alloca i8, align 1 + %blockret = alloca i64, align 8 + %f = alloca i64, align 8 %0 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 0 - store %"char[]" { ptr @.str.29, i64 4 }, ptr %0, align 8 + store %"char[]" { ptr @.str.14, i64 4 }, ptr %0, align 8 %1 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 1 - store %"char[]" { ptr @.str.30, i64 11 }, ptr %1, align 8 + store %"char[]" { ptr @.str.15, i64 11 }, ptr %1, align 8 %2 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 2 - store %"char[]" { ptr @.str.31, i64 13 }, ptr %2, align 8 + store %"char[]" { ptr @.str.16, i64 13 }, ptr %2, align 8 %3 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 3 - store %"char[]" { ptr @.str.32, i64 12 }, ptr %3, align 8 + store %"char[]" { ptr @.str.17, i64 12 }, ptr %3, align 8 %4 = getelementptr inbounds [5 x %"char[]"], ptr %literal, i64 0, i64 4 - store %"char[]" { ptr @.str.33, i64 4 }, ptr %4, align 8 + store %"char[]" { ptr @.str.18, i64 4 }, ptr %4, align 8 %5 = insertvalue %"char[][]" undef, ptr %literal, 0 %6 = insertvalue %"char[][]" %5, i64 5, 1 store %"char[][]" %6, ptr %URLS, align 8 @@ -1009,7 +1023,7 @@ entry: store i64 0, ptr %.anon1, align 8 br label %loop.cond -loop.cond: ; preds = %phi_block12, %entry +loop.cond: ; preds = %phi_block16, %entry %9 = load i64, ptr %.anon1, align 8 %10 = load i64, ptr %.anon, align 8 %lt = icmp ult i64 %9, %10 @@ -1026,7 +1040,7 @@ loop.body: ; preds = %loop.cond %trunc = trunc i64 %15 to i32 %16 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %17 = load ptr, ptr %16, align 8 - %18 = call i32 (ptr, ...) @printf(ptr @.str.34, i32 %trunc, ptr %17) + %18 = call i32 (ptr, ...) @printf(ptr @.str.19, i32 %trunc, ptr %17) %19 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo = load ptr, ptr %19, align 8 %20 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -1034,10 +1048,10 @@ loop.body: ; preds = %loop.cond %21 = call { ptr, i8 } @test.readAndBuildSummary(ptr %lo, i64 %hi) store { ptr, i8 } %21, ptr %result, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %summary, ptr align 8 %result, i32 16, i1 false) - %22 = call i32 (ptr, ...) @printf(ptr @.str.35) + %22 = call i32 (ptr, ...) @printf(ptr @.str.20) %23 = load ptr, ptr @__stdoutp, align 8 call void @test.Summary.print(ptr %summary, ptr %23) - %24 = call i32 (ptr, ...) @printf(ptr @.str.36) + %24 = call i32 (ptr, ...) @printf(ptr @.str.21) %25 = getelementptr inbounds %Summary, ptr %summary, i32 0, i32 0 %26 = load ptr, ptr %25, align 8 %ptrbool = icmp ne ptr %26, null @@ -1060,7 +1074,7 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %trunc2 = trunc i64 %31 to i32 %32 = getelementptr inbounds %"char[]", ptr %title_sure, i32 0, i32 0 %33 = load ptr, ptr %32, align 8 - %34 = call i32 (ptr, ...) @printf(ptr @.str.37, i32 %trunc2, ptr %33) + %34 = call i32 (ptr, ...) @printf(ptr @.str.22, i32 %trunc2, ptr %33) %35 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo3 = load ptr, ptr %35, align 8 %36 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -1092,31 +1106,62 @@ after_check6: ; preds = %after_assign br label %phi_block else_block: ; preds = %after_assign - %43 = load i64, ptr %has_title.f, align 8 - %44 = call ptr @test.nameFromError(i64 %43) + br label %testblock + +testblock: ; preds = %else_block + %optval7 = load i64, ptr %has_title.f, align 8 + %not_err8 = icmp eq i64 %optval7, 0 + %43 = call i1 @llvm.expect.i1(i1 %not_err8, i1 true) + br i1 %43, label %after_check10, label %assign_optional9 + +assign_optional9: ; preds = %testblock + store i64 %optval7, ptr %f, align 8 + br label %end_block + +after_check10: ; preds = %testblock + store i64 0, ptr %f, align 8 + br label %end_block + +end_block: ; preds = %after_check10, %assign_optional9 + %44 = load i64, ptr %f, align 8 + %neq = icmp ne i64 %44, 0 + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + %45 = load i64, ptr %f, align 8 + store i64 %45, ptr %blockret, align 8 + br label %expr_block.exit + +if.exit: ; preds = %end_block + store i64 0, ptr %blockret, align 8 + br label %expr_block.exit + +expr_block.exit: ; preds = %if.exit, %if.then + %46 = load i64, ptr %blockret, align 8 + %47 = call ptr @test.nameFromError(i64 %46) br label %phi_block -phi_block: ; preds = %else_block, %after_check6 - %val7 = phi ptr [ %42, %after_check6 ], [ %44, %else_block ] - %optval8 = load i64, ptr %has_title.f, align 8 - %not_err9 = icmp eq i64 %optval8, 0 - %45 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) - br i1 %45, label %after_check10, label %else_block11 +phi_block: ; preds = %expr_block.exit, %after_check6 + %val11 = phi ptr [ %42, %after_check6 ], [ %47, %expr_block.exit ] + %optval12 = load i64, ptr %has_title.f, align 8 + %not_err13 = icmp eq i64 %optval12, 0 + %48 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true) + br i1 %48, label %after_check14, label %else_block15 -after_check10: ; preds = %phi_block - %46 = load i8, ptr %has_title, align 1 - %47 = trunc i8 %46 to i1 - br label %phi_block12 +after_check14: ; preds = %phi_block + %49 = load i8, ptr %has_title, align 1 + %50 = trunc i8 %49 to i1 + br label %phi_block16 -else_block11: ; preds = %phi_block - br label %phi_block12 +else_block15: ; preds = %phi_block + br label %phi_block16 -phi_block12: ; preds = %else_block11, %after_check10 - %val13 = phi i1 [ %47, %after_check10 ], [ false, %else_block11 ] - %ternary = select i1 %val13, ptr @.str.39, ptr @.str.40 - %48 = call i32 (ptr, ...) @printf(ptr @.str.38, ptr %val7, ptr %ternary) - %49 = load i64, ptr %.anon1, align 8 - %add = add i64 %49, 1 +phi_block16: ; preds = %else_block15, %after_check14 + %val17 = phi i1 [ %50, %after_check14 ], [ false, %else_block15 ] + %ternary = select i1 %val17, ptr @.str.24, ptr @.str.25 + %51 = call i32 (ptr, ...) @printf(ptr @.str.23, ptr %val11, ptr %ternary) + %52 = load i64, ptr %.anon1, align 8 + %add = add i64 %52, 1 store i64 %add, ptr %.anon1, align 8 br label %loop.cond diff --git a/test/test_suite/errors/error_throw.c3 b/test/test_suite/errors/error_throw.c3 index dacd9276b..e540cb29f 100644 --- a/test/test_suite/errors/error_throw.c3 +++ b/test/test_suite/errors/error_throw.c3 @@ -7,6 +7,6 @@ fault Blurg fn void main() { - int! i = Blurg.Z!; - int! j = Blurg.Z!; + int! i = Blurg.Z?; + int! j = Blurg.Z?; } \ No newline at end of file diff --git a/test/test_suite/errors/error_union.c3 b/test/test_suite/errors/error_union.c3 index b76a694c9..9996b2c2a 100644 --- a/test/test_suite/errors/error_union.c3 +++ b/test/test_suite/errors/error_union.c3 @@ -7,5 +7,5 @@ fault Blurg fn void main() { - anyerr foo; + anyfault foo; } \ No newline at end of file diff --git a/test/test_suite/errors/failable_catch.c3t b/test/test_suite/errors/failable_catch.c3t index b884d797c..99cac82ac 100644 --- a/test/test_suite/errors/failable_catch.c3t +++ b/test/test_suite/errors/failable_catch.c3t @@ -8,7 +8,7 @@ fault MyErr macro foo(int x) { if (x) return x; - return MyErr.TEST!; + return MyErr.TEST?; } extern fn void printf(char*, ...); @@ -22,7 +22,7 @@ fn int main() printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); - if (catch? c) printf("c had error\n"); + if (@catchof(c)) printf("c had error\n"); c = 3; printf("c = %d\n", c); return 0; @@ -44,6 +44,8 @@ entry: %c.f = alloca i64, align 8 %x8 = alloca i32, align 4 %blockret9 = alloca i32, align 4 + %blockret26 = alloca i64, align 8 + %f = alloca i64, align 8 store i32 1, ptr %x, align 4 %0 = load i32, ptr %x, align 4 %intbool = icmp ne i32 %0, 0 @@ -155,27 +157,58 @@ after_check24: ; preds = %voiderr21 br label %voiderr25 voiderr25: ; preds = %after_check24, %voiderr21 - %17 = load i64, ptr %c.f, align 8 - %neq = icmp ne i64 %17, 0 - br i1 %neq, label %if.then26, label %if.exit27 + br label %testblock -if.then26: ; preds = %voiderr25 +testblock: ; preds = %voiderr25 + %optval27 = load i64, ptr %c.f, align 8 + %not_err28 = icmp eq i64 %optval27, 0 + %17 = call i1 @llvm.expect.i1(i1 %not_err28, i1 true) + br i1 %17, label %after_check29, label %assign_optional + +assign_optional: ; preds = %testblock + store i64 %optval27, ptr %f, align 8 + br label %end_block + +after_check29: ; preds = %testblock + store i64 0, ptr %f, align 8 + br label %end_block + +end_block: ; preds = %after_check29, %assign_optional + %18 = load i64, ptr %f, align 8 + %neq = icmp ne i64 %18, 0 + br i1 %neq, label %if.then30, label %if.exit31 + +if.then30: ; preds = %end_block + %19 = load i64, ptr %f, align 8 + store i64 %19, ptr %blockret26, align 8 + br label %expr_block.exit32 + +if.exit31: ; preds = %end_block + store i64 0, ptr %blockret26, align 8 + br label %expr_block.exit32 + +expr_block.exit32: ; preds = %if.exit31, %if.then30 + %20 = load i64, ptr %blockret26, align 8 + %neq33 = icmp ne i64 %20, 0 + br i1 %neq33, label %if.then34, label %if.exit35 + +if.then34: ; preds = %expr_block.exit32 call void (ptr, ...) @printf(ptr @.str.3) - br label %if.exit27 + br label %if.exit35 -if.exit27: ; preds = %if.then26, %voiderr25 +if.exit35: ; preds = %if.then34, %expr_block.exit32 store i32 3, ptr %c, align 4 store i64 0, ptr %c.f, align 8 - %optval28 = load i64, ptr %c.f, align 8 - %not_err29 = icmp eq i64 %optval28, 0 - %18 = call i1 @llvm.expect.i1(i1 %not_err29, i1 true) - br i1 %18, label %after_check30, label %voiderr31 + %optval36 = load i64, ptr %c.f, align 8 + %not_err37 = icmp eq i64 %optval36, 0 + %21 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true) + br i1 %21, label %after_check38, label %voiderr39 -after_check30: ; preds = %if.exit27 - %19 = load i32, ptr %c, align 4 - call void (ptr, ...) @printf(ptr @.str.4, i32 %19) - br label %voiderr31 +after_check38: ; preds = %if.exit35 + %22 = load i32, ptr %c, align 4 + call void (ptr, ...) @printf(ptr @.str.4, i32 %22) + br label %voiderr39 -voiderr31: ; preds = %after_check30, %if.exit27 +voiderr39: ; preds = %after_check38, %if.exit35 ret i32 0 } diff --git a/test/test_suite/errors/general_error_regression.c3t b/test/test_suite/errors/general_error_regression.c3t index 082f33a30..ccf9f3924 100644 --- a/test/test_suite/errors/general_error_regression.c3t +++ b/test/test_suite/errors/general_error_regression.c3t @@ -45,7 +45,7 @@ fn void main() { Foo f = Foo.X; Foo ef = Foo.Y; - anyerr x = f; + anyfault x = f; ulong z = (ulong)(x); libc::printf("1: %p\n", z); x = ef; diff --git a/test/test_suite/errors/macro_err.c3t b/test/test_suite/errors/macro_err.c3t index d019063aa..36afd49b8 100644 --- a/test/test_suite/errors/macro_err.c3t +++ b/test/test_suite/errors/macro_err.c3t @@ -7,7 +7,7 @@ fn int! abc() } macro test() { - return abc()?; + return abc()!; } fn void main() diff --git a/test/test_suite/errors/macro_err2.c3t b/test/test_suite/errors/macro_err2.c3t index 67ea309fe..3ea96be61 100644 --- a/test/test_suite/errors/macro_err2.c3t +++ b/test/test_suite/errors/macro_err2.c3t @@ -5,7 +5,7 @@ fault Tester { FOO } fn int! abc() { - return Tester.FOO!; + return Tester.FOO?; } macro test() { diff --git a/test/test_suite/errors/macro_err3.c3t b/test/test_suite/errors/macro_err3.c3t index 6b6b045ea..3cff92b0e 100644 --- a/test/test_suite/errors/macro_err3.c3t +++ b/test/test_suite/errors/macro_err3.c3t @@ -7,7 +7,7 @@ fault Tester { FOO } macro test() { defer libc::printf("Test2\n"); - return Tester.FOO!; + return Tester.FOO?; } fn void main() diff --git a/test/test_suite/errors/more_optional_tests.c3 b/test/test_suite/errors/more_optional_tests.c3 index 141fbfc65..226c57303 100644 --- a/test/test_suite/errors/more_optional_tests.c3 +++ b/test/test_suite/errors/more_optional_tests.c3 @@ -4,10 +4,10 @@ fault Foo { ABC } fn void test() { - int x = Foo.ABC! ?? 123; + int x = Foo.ABC? ?? 123; } fn void test2() { - int! y = Foo.ABC! ?? Foo.ABC!; + int! y = Foo.ABC? ?? Foo.ABC?; } \ No newline at end of file diff --git a/test/test_suite/errors/multiple_catch.c3t b/test/test_suite/errors/multiple_catch.c3t new file mode 100644 index 000000000..eb3b9c761 --- /dev/null +++ b/test/test_suite/errors/multiple_catch.c3t @@ -0,0 +1,241 @@ +// #target: macos-x64 + +module demo1; +import std::io; + +fault CheckError +{ + ABC, + DEF +} + +fn int! hello(int a) +{ + io::printn("hello"); + return a < 0 ? CheckError.ABC? : a; +} + +fn void! bye() +{ + io::printn("bye"); + return CheckError.DEF?; +} +fn void main() +{ + if (catch err = hello(-1), bye()) + { + io::printfn("1 Got %s", err); + } + if (catch err = hello(0), bye()) + { + io::printfn("2 Got %s", err); + } + if (catch hello(0), bye()) + { + io::printn("3 Ok"); + } + if (catch anyfault err = hello(0), bye()) + { + io::printfn("4 Got %s", err); + } +} + +/* #expect: demo1.ll + +define void @demo1.main() #0 { +entry: + %err = alloca i64, align 8 + %retparam = alloca i32, align 4 + %retparam5 = alloca i64, align 8 + %varargslots = alloca [1 x %any], align 16 + %err8 = alloca i64, align 8 + %retparam10 = alloca i32, align 4 + %retparam21 = alloca i64, align 8 + %varargslots22 = alloca [1 x %any], align 16 + %temp_err = alloca i64, align 8 + %retparam27 = alloca i32, align 4 + %x = alloca %"char[]", align 8 + %retparam38 = alloca i64, align 8 + %result = alloca %File, align 8 + %err42 = alloca i64, align 8 + %retparam44 = alloca i32, align 4 + %retparam55 = alloca i64, align 8 + %varargslots56 = alloca [1 x %any], align 16 + br label %testblock + +testblock: ; preds = %entry + %0 = call i64 @demo1.hello(ptr %retparam, i32 -1) + %not_err = icmp eq i64 %0, 0 + %1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %1, label %after_check, label %assign_optional + +assign_optional: ; preds = %testblock + store i64 %0, ptr %err, align 8 + br label %end_block + +after_check: ; preds = %testblock + br label %testblock1 + +testblock1: ; preds = %after_check + %2 = call i64 @demo1.bye() + %not_err2 = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true) + br i1 %3, label %after_check4, label %assign_optional3 + +assign_optional3: ; preds = %testblock1 + store i64 %2, ptr %err, align 8 + br label %end_block + +after_check4: ; preds = %testblock1 + store i64 0, ptr %err, align 8 + br label %end_block + +end_block: ; preds = %after_check4, %assign_optional3, %assign_optional + %4 = load i64, ptr %err, align 8 + %neq = icmp ne i64 %4, 0 + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + %5 = insertvalue %any undef, ptr %err, 0 + %6 = insertvalue %any %5, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %7 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %6, ptr %7, align 16 + %8 = call i64 @std.io.printfn(ptr %retparam5, ptr @.str.3, i64 8, ptr %varargslots, i64 1) + br label %if.exit + +if.exit: ; preds = %if.then, %end_block + br label %testblock9 + +testblock9: ; preds = %if.exit + %9 = call i64 @demo1.hello(ptr %retparam10, i32 0) + %not_err11 = icmp eq i64 %9, 0 + %10 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true) + br i1 %10, label %after_check13, label %assign_optional12 + +assign_optional12: ; preds = %testblock9 + store i64 %9, ptr %err8, align 8 + br label %end_block18 + +after_check13: ; preds = %testblock9 + br label %testblock14 + +testblock14: ; preds = %after_check13 + %11 = call i64 @demo1.bye() + %not_err15 = icmp eq i64 %11, 0 + %12 = call i1 @llvm.expect.i1(i1 %not_err15, i1 true) + br i1 %12, label %after_check17, label %assign_optional16 + +assign_optional16: ; preds = %testblock14 + store i64 %11, ptr %err8, align 8 + br label %end_block18 + +after_check17: ; preds = %testblock14 + store i64 0, ptr %err8, align 8 + br label %end_block18 + +end_block18: ; preds = %after_check17, %assign_optional16, %assign_optional12 + %13 = load i64, ptr %err8, align 8 + %neq19 = icmp ne i64 %13, 0 + br i1 %neq19, label %if.then20, label %if.exit25 + +if.then20: ; preds = %end_block18 + %14 = insertvalue %any undef, ptr %err8, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %16 = getelementptr inbounds [1 x %any], ptr %varargslots22, i64 0, i64 0 + store %any %15, ptr %16, align 16 + %17 = call i64 @std.io.printfn(ptr %retparam21, ptr @.str.4, i64 8, ptr %varargslots22, i64 1) + br label %if.exit25 + +if.exit25: ; preds = %if.then20, %end_block18 + br label %testblock26 + +testblock26: ; preds = %if.exit25 + %18 = call i64 @demo1.hello(ptr %retparam27, i32 0) + %not_err28 = icmp eq i64 %18, 0 + %19 = call i1 @llvm.expect.i1(i1 %not_err28, i1 true) + br i1 %19, label %after_check30, label %assign_optional29 + +assign_optional29: ; preds = %testblock26 + store i64 %18, ptr %temp_err, align 8 + br label %end_block35 + +after_check30: ; preds = %testblock26 + br label %testblock31 + +testblock31: ; preds = %after_check30 + %20 = call i64 @demo1.bye() + %not_err32 = icmp eq i64 %20, 0 + %21 = call i1 @llvm.expect.i1(i1 %not_err32, i1 true) + br i1 %21, label %after_check34, label %assign_optional33 + +assign_optional33: ; preds = %testblock31 + store i64 %20, ptr %temp_err, align 8 + br label %end_block35 + +after_check34: ; preds = %testblock31 + store i64 0, ptr %temp_err, align 8 + br label %end_block35 + +end_block35: ; preds = %after_check34, %assign_optional33, %assign_optional29 + %22 = load i64, ptr %temp_err, align 8 + %neq36 = icmp ne i64 %22, 0 + br i1 %neq36, label %if.then37, label %if.exit41 + +if.then37: ; preds = %end_block35 + store %"char[]" { ptr @.str.5, i64 4 }, ptr %x, align 8 + %23 = call ptr @std.io.stdout() + store ptr %23, ptr %result, align 8 + %24 = load ptr, ptr %result, align 8 + %25 = getelementptr inbounds %"char[]", ptr %x, i32 0, i32 0 + %lo = load ptr, ptr %25, align 8 + %26 = getelementptr inbounds %"char[]", ptr %x, i32 0, i32 1 + %hi = load i64, ptr %26, align 8 + %27 = call i64 @std.io.File.printn(ptr %retparam38, ptr %24, ptr %lo, i64 %hi) + br label %if.exit41 + +if.exit41: ; preds = %if.then37, %end_block35 + br label %testblock43 + +testblock43: ; preds = %if.exit41 + %28 = call i64 @demo1.hello(ptr %retparam44, i32 0) + %not_err45 = icmp eq i64 %28, 0 + %29 = call i1 @llvm.expect.i1(i1 %not_err45, i1 true) + br i1 %29, label %after_check47, label %assign_optional46 + +assign_optional46: ; preds = %testblock43 + store i64 %28, ptr %err42, align 8 + br label %end_block52 + +after_check47: ; preds = %testblock43 + br label %testblock48 + +testblock48: ; preds = %after_check47 + %30 = call i64 @demo1.bye() + %not_err49 = icmp eq i64 %30, 0 + %31 = call i1 @llvm.expect.i1(i1 %not_err49, i1 true) + br i1 %31, label %after_check51, label %assign_optional50 + +assign_optional50: ; preds = %testblock48 + store i64 %30, ptr %err42, align 8 + br label %end_block52 + +after_check51: ; preds = %testblock48 + store i64 0, ptr %err42, align 8 + br label %end_block52 + +end_block52: ; preds = %after_check51, %assign_optional50, %assign_optional46 + %32 = load i64, ptr %err42, align 8 + %neq53 = icmp ne i64 %32, 0 + br i1 %neq53, label %if.then54, label %if.exit59 + +if.then54: ; preds = %end_block52 + %33 = insertvalue %any undef, ptr %err42, 0 + %34 = insertvalue %any %33, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %35 = getelementptr inbounds [1 x %any], ptr %varargslots56, i64 0, i64 0 + store %any %34, ptr %35, align 16 + %36 = call i64 @std.io.printfn(ptr %retparam55, ptr @.str.6, i64 8, ptr %varargslots56, i64 1) + br label %if.exit59 + +if.exit59: ; preds = %if.then54, %end_block52 + ret void +} \ No newline at end of file diff --git a/test/test_suite/errors/no_common.c3 b/test/test_suite/errors/no_common.c3 index 563fdafaa..2a86d72bb 100644 --- a/test/test_suite/errors/no_common.c3 +++ b/test/test_suite/errors/no_common.c3 @@ -4,10 +4,10 @@ fn int! abc() } macro test() { - abc()?; + abc()!; } fn void main() { - test() ?? 2; // #error: Cannot find a common type for 'void' and 'int' + test() ?? 2; // No longer an error! } \ No newline at end of file diff --git a/test/test_suite/errors/optional_chained_init.c3t b/test/test_suite/errors/optional_chained_init.c3t index 7dddb3698..d280f6208 100644 --- a/test/test_suite/errors/optional_chained_init.c3t +++ b/test/test_suite/errors/optional_chained_init.c3t @@ -7,7 +7,7 @@ fault Test { FOO } fn void test1() { int! a = 1; - int! b = a = Test.FOO!; + int! b = a = Test.FOO?; if (catch err = a) io::printfn("A err was: %s", err); if (catch err = b) io::printfn("B err was: %s", err); io::printfn("A was: %s", a); @@ -16,7 +16,7 @@ fn void test1() fn void test2() { - int! x = Test.FOO!; + int! x = Test.FOO?; int! a = 1; int! b = a = x; if (catch err = a) io::printfn("A err was: %s", err); @@ -54,14 +54,14 @@ entry: %b.f = alloca i64, align 8 %err = alloca i64, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %err3 = alloca i64, align 8 %retparam12 = alloca i64, align 8 - %varargslots13 = alloca [1 x %variant], align 16 + %varargslots13 = alloca [1 x %any], align 16 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [1 x %variant], align 16 + %varargslots18 = alloca [1 x %any], align 16 %retparam24 = alloca i64, align 8 - %varargslots25 = alloca [1 x %variant], align 16 + %varargslots25 = alloca [1 x %any], align 16 store i32 1, ptr %a, align 4 store i64 0, ptr %a.f, align 8 store i64 ptrtoint (ptr @"test.Test$FOO" to i64), ptr %a.f, align 8 @@ -91,10 +91,10 @@ end_block: ; preds = %after_check, %assig br i1 %neq, label %if.then, label %if.exit if.then: ; preds = %end_block - %2 = insertvalue %variant undef, ptr %err, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %4 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %3, ptr %4, align 16 + %2 = insertvalue %any undef, ptr %err, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %4 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %3, ptr %4, align 16 %5 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 13, ptr %varargslots, i64 1) br label %if.exit @@ -121,10 +121,10 @@ end_block9: ; preds = %after_check8, %assi br i1 %neq10, label %if.then11, label %if.exit16 if.then11: ; preds = %end_block9 - %8 = insertvalue %variant undef, ptr %err3, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %10 = getelementptr inbounds [1 x %variant], ptr %varargslots13, i64 0, i64 0 - store %variant %9, ptr %10, align 16 + %8 = insertvalue %any undef, ptr %err3, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %10 = getelementptr inbounds [1 x %any], ptr %varargslots13, i64 0, i64 0 + store %any %9, ptr %10, align 16 %11 = call i64 @std.io.printfn(ptr %retparam12, ptr @.str.1, i64 13, ptr %varargslots13, i64 1) br label %if.exit16 @@ -135,10 +135,10 @@ if.exit16: ; preds = %if.then11, %end_blo br i1 %12, label %after_check21, label %after_check23 after_check21: ; preds = %if.exit16 - %13 = insertvalue %variant undef, ptr %a, 0 - %14 = insertvalue %variant %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %15 = getelementptr inbounds [1 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %14, ptr %15, align 16 + %13 = insertvalue %any undef, ptr %a, 0 + %14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %15 = getelementptr inbounds [1 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %14, ptr %15, align 16 %16 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.2, i64 9, ptr %varargslots18, i64 1) %not_err22 = icmp eq i64 %16, 0 %17 = call i1 @llvm.expect.i1(i1 %not_err22, i1 true) @@ -151,10 +151,10 @@ after_check23: ; preds = %if.exit16, %after_c br i1 %18, label %after_check28, label %after_check30 after_check28: ; preds = %after_check23 - %19 = insertvalue %variant undef, ptr %b, 0 - %20 = insertvalue %variant %19, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %21 = getelementptr inbounds [1 x %variant], ptr %varargslots25, i64 0, i64 0 - store %variant %20, ptr %21, align 16 + %19 = insertvalue %any undef, ptr %b, 0 + %20 = insertvalue %any %19, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %21 = getelementptr inbounds [1 x %any], ptr %varargslots25, i64 0, i64 0 + store %any %20, ptr %21, align 16 %22 = call i64 @std.io.printfn(ptr %retparam24, ptr @.str.3, i64 9, ptr %varargslots25, i64 1) %not_err29 = icmp eq i64 %22, 0 %23 = call i1 @llvm.expect.i1(i1 %not_err29, i1 true) @@ -175,14 +175,14 @@ entry: %b.f = alloca i64, align 8 %err = alloca i64, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %err8 = alloca i64, align 8 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [1 x %variant], align 16 + %varargslots18 = alloca [1 x %any], align 16 %retparam22 = alloca i64, align 8 - %varargslots23 = alloca [1 x %variant], align 16 + %varargslots23 = alloca [1 x %any], align 16 %retparam29 = alloca i64, align 8 - %varargslots30 = alloca [1 x %variant], align 16 + %varargslots30 = alloca [1 x %any], align 16 store i64 ptrtoint (ptr @"test.Test$FOO" to i64), ptr %x.f, align 8 store i32 1, ptr %a, align 4 store i64 0, ptr %a.f, align 8 @@ -234,10 +234,10 @@ end_block: ; preds = %after_check5, %assi br i1 %neq, label %if.then, label %if.exit if.then: ; preds = %end_block - %4 = insertvalue %variant undef, ptr %err, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %err, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.4, i64 13, ptr %varargslots, i64 1) br label %if.exit @@ -264,10 +264,10 @@ end_block14: ; preds = %after_check13, %ass br i1 %neq15, label %if.then16, label %if.exit21 if.then16: ; preds = %end_block14 - %10 = insertvalue %variant undef, ptr %err8, 0 - %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %12 = getelementptr inbounds [1 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %11, ptr %12, align 16 + %10 = insertvalue %any undef, ptr %err8, 0 + %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %12 = getelementptr inbounds [1 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %11, ptr %12, align 16 %13 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.5, i64 13, ptr %varargslots18, i64 1) br label %if.exit21 @@ -278,10 +278,10 @@ if.exit21: ; preds = %if.then16, %end_blo br i1 %14, label %after_check26, label %after_check28 after_check26: ; preds = %if.exit21 - %15 = insertvalue %variant undef, ptr %a, 0 - %16 = insertvalue %variant %15, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %17 = getelementptr inbounds [1 x %variant], ptr %varargslots23, i64 0, i64 0 - store %variant %16, ptr %17, align 16 + %15 = insertvalue %any undef, ptr %a, 0 + %16 = insertvalue %any %15, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %17 = getelementptr inbounds [1 x %any], ptr %varargslots23, i64 0, i64 0 + store %any %16, ptr %17, align 16 %18 = call i64 @std.io.printfn(ptr %retparam22, ptr @.str.6, i64 9, ptr %varargslots23, i64 1) %not_err27 = icmp eq i64 %18, 0 %19 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true) @@ -294,10 +294,10 @@ after_check28: ; preds = %if.exit21, %after_c br i1 %20, label %after_check33, label %after_check35 after_check33: ; preds = %after_check28 - %21 = insertvalue %variant undef, ptr %b, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %23 = getelementptr inbounds [1 x %variant], ptr %varargslots30, i64 0, i64 0 - store %variant %22, ptr %23, align 16 + %21 = insertvalue %any undef, ptr %b, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %23 = getelementptr inbounds [1 x %any], ptr %varargslots30, i64 0, i64 0 + store %any %22, ptr %23, align 16 %24 = call i64 @std.io.printfn(ptr %retparam29, ptr @.str.7, i64 9, ptr %varargslots30, i64 1) %not_err34 = icmp eq i64 %24, 0 %25 = call i1 @llvm.expect.i1(i1 %not_err34, i1 true) @@ -318,14 +318,14 @@ entry: %b.f = alloca i64, align 8 %err = alloca i64, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %err8 = alloca i64, align 8 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [1 x %variant], align 16 + %varargslots18 = alloca [1 x %any], align 16 %retparam22 = alloca i64, align 8 - %varargslots23 = alloca [1 x %variant], align 16 + %varargslots23 = alloca [1 x %any], align 16 %retparam29 = alloca i64, align 8 - %varargslots30 = alloca [1 x %variant], align 16 + %varargslots30 = alloca [1 x %any], align 16 store i32 23, ptr %x, align 4 store i64 0, ptr %x.f, align 8 store i32 1, ptr %a, align 4 @@ -378,10 +378,10 @@ end_block: ; preds = %after_check5, %assi br i1 %neq, label %if.then, label %if.exit if.then: ; preds = %end_block - %4 = insertvalue %variant undef, ptr %err, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %err, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %6 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.8, i64 13, ptr %varargslots, i64 1) br label %if.exit @@ -408,10 +408,10 @@ end_block14: ; preds = %after_check13, %ass br i1 %neq15, label %if.then16, label %if.exit21 if.then16: ; preds = %end_block14 - %10 = insertvalue %variant undef, ptr %err8, 0 - %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %12 = getelementptr inbounds [1 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %11, ptr %12, align 16 + %10 = insertvalue %any undef, ptr %err8, 0 + %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %12 = getelementptr inbounds [1 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %11, ptr %12, align 16 %13 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.9, i64 13, ptr %varargslots18, i64 1) br label %if.exit21 @@ -422,10 +422,10 @@ if.exit21: ; preds = %if.then16, %end_blo br i1 %14, label %after_check26, label %after_check28 after_check26: ; preds = %if.exit21 - %15 = insertvalue %variant undef, ptr %a, 0 - %16 = insertvalue %variant %15, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %17 = getelementptr inbounds [1 x %variant], ptr %varargslots23, i64 0, i64 0 - store %variant %16, ptr %17, align 16 + %15 = insertvalue %any undef, ptr %a, 0 + %16 = insertvalue %any %15, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %17 = getelementptr inbounds [1 x %any], ptr %varargslots23, i64 0, i64 0 + store %any %16, ptr %17, align 16 %18 = call i64 @std.io.printfn(ptr %retparam22, ptr @.str.10, i64 9, ptr %varargslots23, i64 1) %not_err27 = icmp eq i64 %18, 0 %19 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true) @@ -438,10 +438,10 @@ after_check28: ; preds = %if.exit21, %after_c br i1 %20, label %after_check33, label %after_check35 after_check33: ; preds = %after_check28 - %21 = insertvalue %variant undef, ptr %b, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %23 = getelementptr inbounds [1 x %variant], ptr %varargslots30, i64 0, i64 0 - store %variant %22, ptr %23, align 16 + %21 = insertvalue %any undef, ptr %b, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %23 = getelementptr inbounds [1 x %any], ptr %varargslots30, i64 0, i64 0 + store %any %22, ptr %23, align 16 %24 = call i64 @std.io.printfn(ptr %retparam29, ptr @.str.11, i64 9, ptr %varargslots30, i64 1) %not_err34 = icmp eq i64 %24, 0 %25 = call i1 @llvm.expect.i1(i1 %not_err34, i1 true) diff --git a/test/test_suite/errors/optional_contracts.c3 b/test/test_suite/errors/optional_contracts.c3 new file mode 100644 index 000000000..9ba764050 --- /dev/null +++ b/test/test_suite/errors/optional_contracts.c3 @@ -0,0 +1,39 @@ +fault Abc +{ + ABC, + DEF, + ZED +} + + +fault Foo +{ + XYZ +} +/** + * + * @return! Abc.DEF "if x is blurb" + * @return! Foo, Abc.ABC, Abc + * @return! Foo, Abc.ABC + * hello world + **/ +fn void! abc(int a, int b, int z) +{ + return Abc.ZED?; // #error: This value does not match declared optional returns +} + +/** + * @return! Abc.DEF "if x is blurb" + * @return! Foo, Abc.ABC, Abc + * @return! Foo, Abc.ABC + * hello world + **/ +macro void! @abc(int a, int b, int z) +{ + return Abc.ZED?; // #error: This value does not match declared optional returns +} + +fn void main() +{ + @abc(2,3,3)!!; +} \ No newline at end of file diff --git a/test/test_suite/errors/optional_inits.c3t b/test/test_suite/errors/optional_inits.c3t index 50b1afbd3..680366232 100644 --- a/test/test_suite/errors/optional_inits.c3t +++ b/test/test_suite/errors/optional_inits.c3t @@ -15,14 +15,14 @@ struct Bar fn void! test1() @maydiscard { - Bar! x = Foo.MY_VAL1!; - Bar y = x?; + Bar! x = Foo.MY_VAL1?; + Bar y = x!; } fn void! test2() @maydiscard { Bar! x = {}; - Bar y = x?; + Bar y = x!; } fn void main() diff --git a/test/test_suite/errors/optional_sizeof.c3 b/test/test_suite/errors/optional_sizeof.c3 new file mode 100644 index 000000000..cac917ca9 --- /dev/null +++ b/test/test_suite/errors/optional_sizeof.c3 @@ -0,0 +1,38 @@ +fn int! abc() +{ + return 1; +} +macro test() +{ + abc()!; +} + +fn void a() +{ + String s = $typeof(test()).qnameof; // #error: This optional expression is untyped. +} + +fn void b() +{ + $sizeof(test()); // #error: This optional expression is untyped. +} + +fn void c() +{ + $sizeof(test() ?? 1); +} + +fn void! d() +{ + $typeof(test()!) g; // #error: This expression has no concrete type +} + +macro e() +{ + var g = test()!; // #error: No type can be inferred from the optional result +} + +fn void! h() +{ + e(); +} \ No newline at end of file diff --git a/test/test_suite/errors/optional_taddr_and_access.c3t b/test/test_suite/errors/optional_taddr_and_access.c3t index 5661426ef..3aab3f0df 100644 --- a/test/test_suite/errors/optional_taddr_and_access.c3t +++ b/test/test_suite/errors/optional_taddr_and_access.c3t @@ -18,7 +18,7 @@ fn void main() int! z = 2; Foo*! w = &&Foo{ z, 0 }; printf("%d\n", w.x); - z = MyErr.FOO!; + z = MyErr.FOO?; w = &&Foo{ z, 0 }; printf("Not visible: %d\n", w.x); } diff --git a/test/test_suite/errors/optional_with_optional.c3t b/test/test_suite/errors/optional_with_optional.c3t index 719885ced..00f6dc469 100644 --- a/test/test_suite/errors/optional_with_optional.c3t +++ b/test/test_suite/errors/optional_with_optional.c3t @@ -9,24 +9,24 @@ fn void main() io::printfn("1:%d", get_a(1) ?? get_b(4) ?? -1); io::printfn("2:%d", get_a(2) ?? get_b(4) ?? -1); io::printfn("3:%d", get_a(1) ?? get_b(5) ?? -1); - io::printfn("4:%s", catch? (Foo.ABC! ?? Foo.DEF!)); - io::printfn("5:%s", Foo.ABC! ?? 3); - io::printfn("6:%s", catch? ((3 > 2 ? Foo.ABC! : 4) ?? Foo.DEF!)); - io::printfn("7:%s", catch? ((3 < 2 ? Foo.ABC! : 4) ?? Foo.DEF!)); - long x = Foo.DEF! ?? 3; + io::printfn("4:%s", @catchof(Foo.ABC? ?? Foo.DEF?)); + io::printfn("5:%s", Foo.ABC? ?? 3); + io::printfn("6:%s", @catchof((3 > 2 ? Foo.ABC? : 4) ?? Foo.DEF?)); + io::printfn("7:%s", @catchof((3 < 2 ? Foo.ABC? : 4) ?? Foo.DEF?)); + long x = Foo.DEF? ?? 3; io::printfn("8:%s", x); - int! xy = Foo.ABC! ?? Foo.DEF!; + int! xy = Foo.ABC? ?? Foo.DEF?; } fn int! get_a(int x) { - if (x % 2) return Foo.ABC!; + if (x % 2) return Foo.ABC?; return x * 2; } fn int! get_b(int x) { - if (x % 2 == 0) return Foo.ABC!; + if (x % 2 == 0) return Foo.ABC?; return x * 2; } @@ -35,35 +35,38 @@ fn int! get_b(int x) define void @test.main() #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %retparam1 = alloca i32, align 4 %retparam2 = alloca i32, align 4 %taddr = alloca i32, align 4 %retparam10 = alloca i64, align 8 - %varargslots11 = alloca [1 x %variant], align 16 + %varargslots11 = alloca [1 x %any], align 16 %retparam12 = alloca i32, align 4 %retparam16 = alloca i32, align 4 %taddr24 = alloca i32, align 4 %retparam27 = alloca i64, align 8 - %varargslots28 = alloca [1 x %variant], align 16 + %varargslots28 = alloca [1 x %any], align 16 %retparam29 = alloca i32, align 4 %retparam33 = alloca i32, align 4 %taddr41 = alloca i32, align 4 %retparam44 = alloca i64, align 8 - %varargslots45 = alloca [1 x %variant], align 16 - %taddr46 = alloca i64, align 8 - %retparam49 = alloca i64, align 8 - %varargslots50 = alloca [1 x %variant], align 16 - %taddr51 = alloca i32, align 4 - %retparam54 = alloca i64, align 8 - %varargslots55 = alloca [1 x %variant], align 16 - %taddr56 = alloca i64, align 8 - %retparam59 = alloca i64, align 8 - %varargslots60 = alloca [1 x %variant], align 16 - %error_var = alloca i64, align 8 - %x = alloca i64, align 8 + %varargslots45 = alloca [1 x %any], align 16 + %blockret = alloca i64, align 8 + %f = alloca i64, align 8 + %retparam48 = alloca i64, align 8 + %varargslots49 = alloca [1 x %any], align 16 + %taddr50 = alloca i32, align 4 + %retparam53 = alloca i64, align 8 + %varargslots54 = alloca [1 x %any], align 16 + %blockret55 = alloca i64, align 8 + %f56 = alloca i64, align 8 %retparam65 = alloca i64, align 8 - %varargslots66 = alloca [1 x %variant], align 16 + %varargslots66 = alloca [1 x %any], align 16 + %blockret67 = alloca i64, align 8 + %f68 = alloca i64, align 8 + %x = alloca i64, align 8 + %retparam79 = alloca i64, align 8 + %varargslots80 = alloca [1 x %any], align 16 %xy = alloca i32, align 4 %xy.f = alloca i64, align 8 %0 = call i64 @test.get_a(ptr %retparam1, i32 1) @@ -73,7 +76,7 @@ entry: after_check: ; preds = %entry %2 = load i32, ptr %retparam1, align 4 - br label %phi_block + br label %phi_block6 else_block: ; preds = %entry %3 = call i64 @test.get_b(ptr %retparam2, i32 4) @@ -85,20 +88,20 @@ after_check4: ; preds = %else_block %5 = load i32, ptr %retparam2, align 4 br label %phi_block -phi_block: ; preds = %after_check4, %after_check - %val = phi i32 [ %2, %after_check ], [ %5, %after_check4 ] - br label %phi_block6 - else_block5: ; preds = %else_block + br label %phi_block + +phi_block: ; preds = %else_block5, %after_check4 + %val = phi i32 [ %5, %after_check4 ], [ -1, %else_block5 ] br label %phi_block6 -phi_block6: ; preds = %else_block5, %phi_block - %val7 = phi i32 [ %val, %phi_block ], [ -1, %else_block5 ] +phi_block6: ; preds = %phi_block, %after_check + %val7 = phi i32 [ %2, %after_check ], [ %val, %phi_block ] store i32 %val7, ptr %taddr, align 4 - %6 = insertvalue %variant undef, ptr %taddr, 0 - %7 = insertvalue %variant %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %8 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %7, ptr %8, align 16 + %6 = insertvalue %any undef, ptr %taddr, 0 + %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %8 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %7, ptr %8, align 16 %9 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 4, ptr %varargslots, i64 1) %10 = call i64 @test.get_a(ptr %retparam12, i32 2) %not_err13 = icmp eq i64 %10, 0 @@ -107,32 +110,32 @@ phi_block6: ; preds = %else_block5, %phi_b after_check14: ; preds = %phi_block6 %12 = load i32, ptr %retparam12, align 4 - br label %phi_block19 + br label %phi_block22 else_block15: ; preds = %phi_block6 %13 = call i64 @test.get_b(ptr %retparam16, i32 4) %not_err17 = icmp eq i64 %13, 0 %14 = call i1 @llvm.expect.i1(i1 %not_err17, i1 true) - br i1 %14, label %after_check18, label %else_block21 + br i1 %14, label %after_check18, label %else_block19 after_check18: ; preds = %else_block15 %15 = load i32, ptr %retparam16, align 4 - br label %phi_block19 + br label %phi_block20 -phi_block19: ; preds = %after_check18, %after_check14 - %val20 = phi i32 [ %12, %after_check14 ], [ %15, %after_check18 ] +else_block19: ; preds = %else_block15 + br label %phi_block20 + +phi_block20: ; preds = %else_block19, %after_check18 + %val21 = phi i32 [ %15, %after_check18 ], [ -1, %else_block19 ] br label %phi_block22 -else_block21: ; preds = %else_block15 - br label %phi_block22 - -phi_block22: ; preds = %else_block21, %phi_block19 - %val23 = phi i32 [ %val20, %phi_block19 ], [ -1, %else_block21 ] +phi_block22: ; preds = %phi_block20, %after_check14 + %val23 = phi i32 [ %12, %after_check14 ], [ %val21, %phi_block20 ] store i32 %val23, ptr %taddr24, align 4 - %16 = insertvalue %variant undef, ptr %taddr24, 0 - %17 = insertvalue %variant %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %18 = getelementptr inbounds [1 x %variant], ptr %varargslots11, i64 0, i64 0 - store %variant %17, ptr %18, align 16 + %16 = insertvalue %any undef, ptr %taddr24, 0 + %17 = insertvalue %any %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %18 = getelementptr inbounds [1 x %any], ptr %varargslots11, i64 0, i64 0 + store %any %17, ptr %18, align 16 %19 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.2, i64 4, ptr %varargslots11, i64 1) %20 = call i64 @test.get_a(ptr %retparam29, i32 1) %not_err30 = icmp eq i64 %20, 0 @@ -141,69 +144,126 @@ phi_block22: ; preds = %else_block21, %phi_ after_check31: ; preds = %phi_block22 %22 = load i32, ptr %retparam29, align 4 - br label %phi_block36 + br label %phi_block39 else_block32: ; preds = %phi_block22 %23 = call i64 @test.get_b(ptr %retparam33, i32 5) %not_err34 = icmp eq i64 %23, 0 %24 = call i1 @llvm.expect.i1(i1 %not_err34, i1 true) - br i1 %24, label %after_check35, label %else_block38 + br i1 %24, label %after_check35, label %else_block36 after_check35: ; preds = %else_block32 %25 = load i32, ptr %retparam33, align 4 - br label %phi_block36 + br label %phi_block37 -phi_block36: ; preds = %after_check35, %after_check31 - %val37 = phi i32 [ %22, %after_check31 ], [ %25, %after_check35 ] +else_block36: ; preds = %else_block32 + br label %phi_block37 + +phi_block37: ; preds = %else_block36, %after_check35 + %val38 = phi i32 [ %25, %after_check35 ], [ -1, %else_block36 ] br label %phi_block39 -else_block38: ; preds = %else_block32 - br label %phi_block39 - -phi_block39: ; preds = %else_block38, %phi_block36 - %val40 = phi i32 [ %val37, %phi_block36 ], [ -1, %else_block38 ] +phi_block39: ; preds = %phi_block37, %after_check31 + %val40 = phi i32 [ %22, %after_check31 ], [ %val38, %phi_block37 ] store i32 %val40, ptr %taddr41, align 4 - %26 = insertvalue %variant undef, ptr %taddr41, 0 - %27 = insertvalue %variant %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %28 = getelementptr inbounds [1 x %variant], ptr %varargslots28, i64 0, i64 0 - store %variant %27, ptr %28, align 16 + %26 = insertvalue %any undef, ptr %taddr41, 0 + %27 = insertvalue %any %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %28 = getelementptr inbounds [1 x %any], ptr %varargslots28, i64 0, i64 0 + store %any %27, ptr %28, align 16 %29 = call i64 @std.io.printfn(ptr %retparam27, ptr @.str.3, i64 4, ptr %varargslots28, i64 1) - store i64 ptrtoint (ptr @"test.Foo$DEF" to i64), ptr %taddr46, align 8 - %30 = insertvalue %variant undef, ptr %taddr46, 0 - %31 = insertvalue %variant %30, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %32 = getelementptr inbounds [1 x %variant], ptr %varargslots45, i64 0, i64 0 - store %variant %31, ptr %32, align 16 - %33 = call i64 @std.io.printfn(ptr %retparam44, ptr @.str.4, i64 4, ptr %varargslots45, i64 1) - store i32 3, ptr %taddr51, align 4 - %34 = insertvalue %variant undef, ptr %taddr51, 0 - %35 = insertvalue %variant %34, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %36 = getelementptr inbounds [1 x %variant], ptr %varargslots50, i64 0, i64 0 - store %variant %35, ptr %36, align 16 - %37 = call i64 @std.io.printfn(ptr %retparam49, ptr @.str.5, i64 4, ptr %varargslots50, i64 1) - store i64 ptrtoint (ptr @"test.Foo$DEF" to i64), ptr %taddr56, align 8 - %38 = insertvalue %variant undef, ptr %taddr56, 0 - %39 = insertvalue %variant %38, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %40 = getelementptr inbounds [1 x %variant], ptr %varargslots55, i64 0, i64 0 - store %variant %39, ptr %40, align 16 - %41 = call i64 @std.io.printfn(ptr %retparam54, ptr @.str.6, i64 4, ptr %varargslots55, i64 1) - store i64 0, ptr %error_var, align 8 - br label %phi_block62 + br label %testblock -phi_block62: ; preds = %phi_block39 - br label %noerr_block +testblock: ; preds = %phi_block39 + store i64 ptrtoint (ptr @"test.Foo$DEF" to i64), ptr %f, align 8 + br label %end_block -noerr_block: ; preds = %phi_block62 - %42 = insertvalue %variant undef, ptr %error_var, 0 - %43 = insertvalue %variant %42, i64 ptrtoint (ptr @"$ct.anyerr" to i64), 1 - %44 = getelementptr inbounds [1 x %variant], ptr %varargslots60, i64 0, i64 0 - store %variant %43, ptr %44, align 16 - %45 = call i64 @std.io.printfn(ptr %retparam59, ptr @.str.7, i64 4, ptr %varargslots60, i64 1) +end_block: ; preds = %testblock + %30 = load i64, ptr %f, align 8 + %neq = icmp ne i64 %30, 0 + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + %31 = load i64, ptr %f, align 8 + store i64 %31, ptr %blockret, align 8 + br label %expr_block.exit + +if.exit: ; preds = %end_block + store i64 0, ptr %blockret, align 8 + br label %expr_block.exit + +expr_block.exit: ; preds = %if.exit, %if.then + %32 = insertvalue %any undef, ptr %blockret, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %34 = getelementptr inbounds [1 x %any], ptr %varargslots45, i64 0, i64 0 + store %any %33, ptr %34, align 16 + %35 = call i64 @std.io.printfn(ptr %retparam44, ptr @.str.4, i64 4, ptr %varargslots45, i64 1) + store i32 3, ptr %taddr50, align 4 + %36 = insertvalue %any undef, ptr %taddr50, 0 + %37 = insertvalue %any %36, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %38 = getelementptr inbounds [1 x %any], ptr %varargslots49, i64 0, i64 0 + store %any %37, ptr %38, align 16 + %39 = call i64 @std.io.printfn(ptr %retparam48, ptr @.str.5, i64 4, ptr %varargslots49, i64 1) + br label %testblock57 + +testblock57: ; preds = %expr_block.exit + store i64 ptrtoint (ptr @"test.Foo$DEF" to i64), ptr %f56, align 8 + br label %end_block58 + +end_block58: ; preds = %testblock57 + %40 = load i64, ptr %f56, align 8 + %neq59 = icmp ne i64 %40, 0 + br i1 %neq59, label %if.then60, label %if.exit61 + +if.then60: ; preds = %end_block58 + %41 = load i64, ptr %f56, align 8 + store i64 %41, ptr %blockret55, align 8 + br label %expr_block.exit62 + +if.exit61: ; preds = %end_block58 + store i64 0, ptr %blockret55, align 8 + br label %expr_block.exit62 + +expr_block.exit62: ; preds = %if.exit61, %if.then60 + %42 = insertvalue %any undef, ptr %blockret55, 0 + %43 = insertvalue %any %42, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %44 = getelementptr inbounds [1 x %any], ptr %varargslots54, i64 0, i64 0 + store %any %43, ptr %44, align 16 + %45 = call i64 @std.io.printfn(ptr %retparam53, ptr @.str.6, i64 4, ptr %varargslots54, i64 1) + br label %testblock69 + +testblock69: ; preds = %expr_block.exit62 + br label %phi_block71 + +phi_block71: ; preds = %testblock69 + store i64 0, ptr %f68, align 8 + br label %end_block72 + +end_block72: ; preds = %phi_block71 + %46 = load i64, ptr %f68, align 8 + %neq73 = icmp ne i64 %46, 0 + br i1 %neq73, label %if.then74, label %if.exit75 + +if.then74: ; preds = %end_block72 + %47 = load i64, ptr %f68, align 8 + store i64 %47, ptr %blockret67, align 8 + br label %expr_block.exit76 + +if.exit75: ; preds = %end_block72 + store i64 0, ptr %blockret67, align 8 + br label %expr_block.exit76 + +expr_block.exit76: ; preds = %if.exit75, %if.then74 + %48 = insertvalue %any undef, ptr %blockret67, 0 + %49 = insertvalue %any %48, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %50 = getelementptr inbounds [1 x %any], ptr %varargslots66, i64 0, i64 0 + store %any %49, ptr %50, align 16 + %51 = call i64 @std.io.printfn(ptr %retparam65, ptr @.str.7, i64 4, ptr %varargslots66, i64 1) store i64 3, ptr %x, align 8 - %46 = insertvalue %variant undef, ptr %x, 0 - %47 = insertvalue %variant %46, i64 ptrtoint (ptr @"$ct.long" to i64), 1 - %48 = getelementptr inbounds [1 x %variant], ptr %varargslots66, i64 0, i64 0 - store %variant %47, ptr %48, align 16 - %49 = call i64 @std.io.printfn(ptr %retparam65, ptr @.str.8, i64 4, ptr %varargslots66, i64 1) + %52 = insertvalue %any undef, ptr %x, 0 + %53 = insertvalue %any %52, i64 ptrtoint (ptr @"$ct.long" to i64), 1 + %54 = getelementptr inbounds [1 x %any], ptr %varargslots80, i64 0, i64 0 + store %any %53, ptr %54, align 16 + %55 = call i64 @std.io.printfn(ptr %retparam79, ptr @.str.8, i64 4, ptr %varargslots80, i64 1) store i64 ptrtoint (ptr @"test.Foo$DEF" to i64), ptr %xy.f, align 8 ret void } diff --git a/test/test_suite/errors/or_and_rethrow.c3t b/test/test_suite/errors/or_and_rethrow.c3t index 0e88a192f..22c7afeea 100644 --- a/test/test_suite/errors/or_and_rethrow.c3t +++ b/test/test_suite/errors/or_and_rethrow.c3t @@ -9,32 +9,32 @@ fn void blurb() { io::printn("Blurb");} macro int! tester() { defer blurb(); - return Foo.ABC!; + return Foo.ABC?; } fn void! test(int x) { io::printfn("test(%d)", x); - if (x || (tester()?)) io::printn("Ok1"); + if (x || (tester()!)) io::printn("Ok1"); io::printn("Test next"); - if (tester()? || x) io::printn("Ok?"); + if (tester()! || x) io::printn("Ok?"); io::printn("Test ok"); } fn void! test2(int x) { io::printfn("test2(%d)", x); - if (x && (tester()?)) io::printn("Ok1"); + if (x && (tester()!)) io::printn("Ok1"); io::printn("Test next"); - if ((tester()?) && x) io::printn("Ok?"); + if ((tester()!) && x) io::printn("Ok?"); io::printn("Test ok"); } fn void main() { - anyerr a = test(0); - anyerr b = test(1); - anyerr c = test2(0); - anyerr d = test2(1); + anyfault a = test(0); + anyfault b = test(1); + anyfault c = test2(0); + anyfault d = test2(1); } /* #expect: foo.ll @@ -42,7 +42,7 @@ fn void main() define i64 @foo.test(i32 %0) #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 %error_var = alloca i64, align 8 %blockret = alloca i32, align 4 @@ -62,10 +62,10 @@ entry: %result20 = alloca %File, align 8 %reterr = alloca i64, align 8 store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.1, i64 8, ptr %varargslots, i64 1) %intbool = icmp ne i32 %0, 0 br i1 %intbool, label %or.phi, label %or.rhs @@ -135,7 +135,7 @@ if.exit17: ; No predecessors! define i64 @foo.test2(i32 %0) #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 %error_var = alloca i64, align 8 %blockret = alloca i32, align 4 @@ -149,10 +149,10 @@ entry: %result9 = alloca %File, align 8 %reterr = alloca i64, align 8 store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.6, i64 9, ptr %varargslots, i64 1) %intbool = icmp ne i32 %0, 0 br i1 %intbool, label %and.rhs, label %and.phi diff --git a/test/test_suite/errors/printing_errors.c3t b/test/test_suite/errors/printing_errors.c3t index 58ae2f889..354843208 100644 --- a/test/test_suite/errors/printing_errors.c3t +++ b/test/test_suite/errors/printing_errors.c3t @@ -9,7 +9,7 @@ fault Cde } fn void main() { - anyerr x = Cde.WORLD; + anyfault x = Cde.WORLD; io::printf("%s %s\n", Cde.HELLO.nameof, x.nameof); } @@ -19,15 +19,15 @@ define void @test.main() #0 { entry: %x = alloca i64, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %taddr = alloca %"char[]", align 8 %faultname_zero = alloca %"char[]", align 8 store i64 ptrtoint (ptr @"test.Cde$WORLD" to i64), ptr %x, align 8 store %"char[]" { ptr @.str.2, i64 5 }, ptr %taddr, align 8 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %2 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %1, ptr %2, align 16 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %2 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %1, ptr %2, align 16 %3 = load i64, ptr %x, align 8 %eq = icmp eq i64 %3, 0 br i1 %eq, label %faultname_no, label %faultname_ok @@ -43,10 +43,10 @@ faultname_ok: ; preds = %entry faultname_exit: ; preds = %faultname_ok, %faultname_no %faultname = phi ptr [ %faultname_zero, %faultname_no ], [ %5, %faultname_ok ] - %6 = insertvalue %variant undef, ptr %faultname, 0 - %7 = insertvalue %variant %6, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %8 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %7, ptr %8, align 16 + %6 = insertvalue %any undef, ptr %faultname, 0 + %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %8 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %7, ptr %8, align 16 %9 = call i64 @std.io.printf(ptr %retparam, ptr @.str, i64 6, ptr %varargslots, i64 2) ret void } diff --git a/test/test_suite/errors/rethrow.c3t b/test/test_suite/errors/rethrow.c3t index 177a27e76..f6ea6d328 100644 --- a/test/test_suite/errors/rethrow.c3t +++ b/test/test_suite/errors/rethrow.c3t @@ -3,7 +3,7 @@ fn void! test() { int! i; - i?; + i!; } /* #expect: rethrow.ll diff --git a/test/test_suite/errors/rethrow_mingw.c3t b/test/test_suite/errors/rethrow_mingw.c3t index 31226389d..34297c187 100644 --- a/test/test_suite/errors/rethrow_mingw.c3t +++ b/test/test_suite/errors/rethrow_mingw.c3t @@ -5,7 +5,7 @@ module rethrow; fn void! test() { int! i; - i?; + i!; } /* #expect: rethrow.ll diff --git a/test/test_suite/errors/rethrow_no_err.c3 b/test/test_suite/errors/rethrow_no_err.c3 index f1e3697c7..0a86ff526 100644 --- a/test/test_suite/errors/rethrow_no_err.c3 +++ b/test/test_suite/errors/rethrow_no_err.c3 @@ -1,17 +1,17 @@ fn void test() { - test()?; // #error: No optional to rethrow before '?' in the expression, please remove '?' + test()!; // #error: No optional to rethrow before '!' in the expression, please remove '!' int i = 0; - if (i?) return; // #error: No optional to rethrow before '?' in the expression, please remove '?' + if (i!) return; // #error: No optional to rethrow before '!' in the expression, please remove '!' int! j = 0; - if (j?) return; // #error: This expression implicitly returns with an optional result, but the function - if ((j?)?) return; // #error: This expression implicitly returns with an optional result, but the function + if (j!) return; // #error: This expression implicitly returns with an optional result, but the function + if ((j!)!) return; // #error: This expression implicitly returns with an optional result, but the function } fn void! test2() { int! j = 0; - if (j?) return; - if ((j?)?) return; // #error: No optional to rethrow before '?' in the expression, please remove '?' + if (j!) return; + if ((j!)!) return; // #error: No optional to rethrow before '!' in the expression, please remove '!' } \ No newline at end of file diff --git a/test/test_suite/errors/simple_static_failable.c3t b/test/test_suite/errors/simple_static_failable.c3t index 9465f1669..d284b40cb 100644 --- a/test/test_suite/errors/simple_static_failable.c3t +++ b/test/test_suite/errors/simple_static_failable.c3t @@ -10,7 +10,7 @@ fault Blurg fn void main() { static int! x = 120; - int! i = Blurg.Y!; + int! i = Blurg.Y?; } /* #expect: foo.ll diff --git a/test/test_suite/errors/try_assign.c3t b/test/test_suite/errors/try_assign.c3t index 9770643a7..9842653f8 100644 --- a/test/test_suite/errors/try_assign.c3t +++ b/test/test_suite/errors/try_assign.c3t @@ -18,7 +18,7 @@ fn void main() { printf("Test\n"); } - anyerr e; + anyfault e; if (catch e = z) { printf("Oh noes!\n"); diff --git a/test/test_suite/errors/try_catch_if.c3t b/test/test_suite/errors/try_catch_if.c3t index f42a98b2f..6ab3b2086 100644 --- a/test/test_suite/errors/try_catch_if.c3t +++ b/test/test_suite/errors/try_catch_if.c3t @@ -20,7 +20,7 @@ fault Foo fn void test1() { int! a = 123; - if (catch err = (a, tester())) + if (catch err = a, tester()) { printf("Err\n"); } diff --git a/test/test_suite/errors/try_catch_unwrapping_while_if.c3 b/test/test_suite/errors/try_catch_unwrapping_while_if.c3 index faaf287d7..fac45d9f4 100644 --- a/test/test_suite/errors/try_catch_unwrapping_while_if.c3 +++ b/test/test_suite/errors/try_catch_unwrapping_while_if.c3 @@ -12,7 +12,7 @@ fn void test1() { int y = z; z = 12; - z = FooErr.X!; // #error: The variable is unwrapped in this context + z = FooErr.X?; // #error: The variable is unwrapped in this context } } @@ -87,7 +87,7 @@ fn void test9() { int! z = 234; int! w = 123; - anyerr e; + anyfault e; if (catch e = z) { } diff --git a/test/test_suite/expressions/casts/cast_failable.c3 b/test/test_suite/expressions/casts/cast_failable.c3 index 1a650a252..fdfaa6954 100644 --- a/test/test_suite/expressions/casts/cast_failable.c3 +++ b/test/test_suite/expressions/casts/cast_failable.c3 @@ -5,6 +5,6 @@ fault MyErr fn void test() { - int! x = (int!)(MyErr.FOO!); // #error: Casting to an optional type is not - int! y = MyErr.FOO!; + int! x = (int!)(MyErr.FOO?); // #error: Casting to an optional type is not + int! y = MyErr.FOO?; } \ No newline at end of file diff --git a/test/test_suite/expressions/casts/void_casting.c3 b/test/test_suite/expressions/casts/void_casting.c3 index 068d774fa..808b6c1c7 100644 --- a/test/test_suite/expressions/casts/void_casting.c3 +++ b/test/test_suite/expressions/casts/void_casting.c3 @@ -8,7 +8,7 @@ fault Abc { AAA } macro int! bar() { - return Abc.AAA!; + return Abc.AAA?; } fn int! baz() diff --git a/test/test_suite/expressions/chained_ternary.c3t b/test/test_suite/expressions/chained_ternary.c3t index af8d71ef5..2c41a1fcc 100644 --- a/test/test_suite/expressions/chained_ternary.c3t +++ b/test/test_suite/expressions/chained_ternary.c3t @@ -13,9 +13,9 @@ fn void test() void*! y = !a ? x : b; y = !a ? b : x; y = !a ? x : x; - y = !a ? x : Test.FOO!; - y = !a ? Test.FOO! : x; - y = !a ? Test.FOO! : Test.BAR!; + y = !a ? x : Test.FOO?; + y = !a ? Test.FOO? : x; + y = !a ? Test.FOO? : Test.BAR?; } /* #expect: test.ll diff --git a/test/test_suite/expressions/negate_int.c3 b/test/test_suite/expressions/negate_int.c3 index b9aa196ea..737aa2529 100644 --- a/test/test_suite/expressions/negate_int.c3 +++ b/test/test_suite/expressions/negate_int.c3 @@ -1,41 +1,41 @@ fn void test1() { short! a = 1; - try? -a; + @ok(-a); short b = -a; // #error: 'int!' to 'short'. } fn void test2() { int! a = 1; - try? -a; + @ok(-a); int b = -a; // #error: 'int!' to 'int' } fn void test3() { long! a = 1; - try? -a; + @ok(-a); long b = -a; // #error: 'long!' to 'long' } fn void test4() { short! a = 1; - try? ~a; + @ok(~a); short b = ~a; // #error: 'short!' to 'short' } fn void test5() { int! a = 1; - try? ~a; + @ok(~a); int b = ~a; // #error: 'int!' to 'int' } fn void test6() { long! a = 1; - try? ~a; + @ok(~a); long b = ~a; // #error: 'long!' to 'long' } diff --git a/test/test_suite/expressions/optional_ternary.c3t b/test/test_suite/expressions/optional_ternary.c3t index 904601a83..32205c286 100644 --- a/test/test_suite/expressions/optional_ternary.c3t +++ b/test/test_suite/expressions/optional_ternary.c3t @@ -9,42 +9,42 @@ fault Foo fn int! test(int i) { - return i ?: Foo.X!; + return i ?: Foo.X?; } fn int! test2(int i) { - return i ? Foo.X! : Foo.X!; + return i ? Foo.X? : Foo.X?; } fn int! test3(int i) { - return i ? 2 : Foo.X!; + return i ? 2 : Foo.X?; } fn int! test4(int i) { int! y = i; - return (y?) ?: Foo.X!; + return (y!) ?: Foo.X?; } fn int! test5(int i) { int! y = i; - return (y?) ? Foo.X! : Foo.X!; + return (y!) ? Foo.X? : Foo.X?; } fn int! test6(int i) { int! y = i; - return (y?) ? 2 : Foo.X!; + return (y!) ? 2 : Foo.X?; } fn int! test7(int i) { int! y = i; - return (y?) ? Foo.X! : 2; + return (y!) ? Foo.X? : 2; } fn void main() diff --git a/test/test_suite/expressions/plus_int.c3 b/test/test_suite/expressions/plus_int.c3 index edf4113d2..7a377dc7d 100644 --- a/test/test_suite/expressions/plus_int.c3 +++ b/test/test_suite/expressions/plus_int.c3 @@ -1,20 +1,20 @@ fn void test1() { short! a = 1; - try? +a; + @ok(+a); short b = +a; // #error: 'int!' to 'short'. } fn void test2() { int! a = 1; - try? +a; + @ok(+a); int b = +a; // #error: 'int!' to 'int' } fn void test3() { long! a = 1; - try? +a; + @ok(+a); long b = +a; // #error: 'long!' to 'long' } diff --git a/test/test_suite/expressions/strings.c3t b/test/test_suite/expressions/strings.c3t index e73306b83..5a3d23bc1 100644 --- a/test/test_suite/expressions/strings.c3t +++ b/test/test_suite/expressions/strings.c3t @@ -2,7 +2,7 @@ module test; fn char* foo() { - return "*** Word \"%s\" on line %d is not"; + return "*** Word \"%s\" on line %d is not" "" ""; } // #expect: test.ll diff --git a/test/test_suite/from_docs/examples_if_catch.c3t b/test/test_suite/from_docs/examples_if_catch.c3t index 0b39975a2..d3559fee5 100644 --- a/test/test_suite/from_docs/examples_if_catch.c3t +++ b/test/test_suite/from_docs/examples_if_catch.c3t @@ -13,7 +13,7 @@ fn int bar() { return 0; } fn double! divide(int a, int b) { - if (b == 0) return MathError.DIVISION_BY_ZERO!; + if (b == 0) return MathError.DIVISION_BY_ZERO?; return (double)(a) / (double)(b); } @@ -21,7 +21,7 @@ fn double! divide(int a, int b) // Rethrowing an error uses "?" suffix fn void! testMayError() { - divide(foo(), bar())?; + divide(foo(), bar())!; } fn void main() diff --git a/test/test_suite/functions/default_param_fail.c3 b/test/test_suite/functions/default_param_fail.c3 index 621265af7..aeac261a8 100644 --- a/test/test_suite/functions/default_param_fail.c3 +++ b/test/test_suite/functions/default_param_fail.c3 @@ -8,4 +8,4 @@ fault MyError fn void test(int a = z) {} -fn void test2(int b = MyError.FOO!) {} \ No newline at end of file +fn void test2(int b = MyError.FOO?) {} \ No newline at end of file diff --git a/test/test_suite/functions/func_ptr_conversions_and_names.c3t b/test/test_suite/functions/func_ptr_conversions_and_names.c3t index 997fdee5d..ce8c7d9ee 100644 --- a/test/test_suite/functions/func_ptr_conversions_and_names.c3t +++ b/test/test_suite/functions/func_ptr_conversions_and_names.c3t @@ -56,29 +56,29 @@ entry: %a = alloca ptr, align 8 %b = alloca ptr, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [1 x %variant], align 16 + %varargslots2 = alloca [1 x %any], align 16 %taddr3 = alloca i32, align 4 %z = alloca ptr, align 8 %retparam4 = alloca i64, align 8 - %varargslots5 = alloca [1 x %variant], align 16 + %varargslots5 = alloca [1 x %any], align 16 %taddr6 = alloca i32, align 4 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %taddr9 = alloca %"char[]", align 8 %retparam10 = alloca i64, align 8 - %varargslots11 = alloca [1 x %variant], align 16 + %varargslots11 = alloca [1 x %any], align 16 %taddr12 = alloca %"char[]", align 8 %retparam13 = alloca i64, align 8 - %varargslots14 = alloca [1 x %variant], align 16 + %varargslots14 = alloca [1 x %any], align 16 %taddr15 = alloca %"char[]", align 8 %retparam16 = alloca i64, align 8 - %varargslots17 = alloca [1 x %variant], align 16 + %varargslots17 = alloca [1 x %any], align 16 %taddr18 = alloca %"char[]", align 8 %retparam19 = alloca i64, align 8 - %varargslots20 = alloca [1 x %variant], align 16 + %varargslots20 = alloca [1 x %any], align 16 %taddr21 = alloca %"char[]", align 8 %y = alloca ptr, align 8 %zfoke = alloca i64, align 8 @@ -87,56 +87,56 @@ entry: %0 = load ptr, ptr %a, align 8 %1 = call i32 %0(i32 123) store i32 %1, ptr %taddr, align 4 - %2 = insertvalue %variant undef, ptr %taddr, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %4 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %3, ptr %4, align 16 + %2 = insertvalue %any undef, ptr %taddr, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %4 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %3, ptr %4, align 16 %5 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) %6 = call i32 @test.test2(i32 3) store i32 %6, ptr %taddr3, align 4 - %7 = insertvalue %variant undef, ptr %taddr3, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %9 = getelementptr inbounds [1 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %8, ptr %9, align 16 + %7 = insertvalue %any undef, ptr %taddr3, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %9 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %8, ptr %9, align 16 %10 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.1, i64 2, ptr %varargslots2, i64 1) store ptr @test.test2, ptr %z, align 8 %11 = load ptr, ptr %z, align 8 %12 = call i32 %11(i32 444) store i32 %12, ptr %taddr6, align 4 - %13 = insertvalue %variant undef, ptr %taddr6, 0 - %14 = insertvalue %variant %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %15 = getelementptr inbounds [1 x %variant], ptr %varargslots5, i64 0, i64 0 - store %variant %14, ptr %15, align 16 + %13 = insertvalue %any undef, ptr %taddr6, 0 + %14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %15 = getelementptr inbounds [1 x %any], ptr %varargslots5, i64 0, i64 0 + store %any %14, ptr %15, align 16 %16 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.2, i64 2, ptr %varargslots5, i64 1) store %"char[]" { ptr @.str.4, i64 12 }, ptr %taddr9, align 8 - %17 = insertvalue %variant undef, ptr %taddr9, 0 - %18 = insertvalue %variant %17, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %19 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %18, ptr %19, align 16 + %17 = insertvalue %any undef, ptr %taddr9, 0 + %18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %19 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %18, ptr %19, align 16 %20 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.3, i64 2, ptr %varargslots8, i64 1) store %"char[]" { ptr @.str.6, i64 12 }, ptr %taddr12, align 8 - %21 = insertvalue %variant undef, ptr %taddr12, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %23 = getelementptr inbounds [1 x %variant], ptr %varargslots11, i64 0, i64 0 - store %variant %22, ptr %23, align 16 + %21 = insertvalue %any undef, ptr %taddr12, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %23 = getelementptr inbounds [1 x %any], ptr %varargslots11, i64 0, i64 0 + store %any %22, ptr %23, align 16 %24 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.5, i64 2, ptr %varargslots11, i64 1) store %"char[]" { ptr @.str.8, i64 12 }, ptr %taddr15, align 8 - %25 = insertvalue %variant undef, ptr %taddr15, 0 - %26 = insertvalue %variant %25, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %27 = getelementptr inbounds [1 x %variant], ptr %varargslots14, i64 0, i64 0 - store %variant %26, ptr %27, align 16 + %25 = insertvalue %any undef, ptr %taddr15, 0 + %26 = insertvalue %any %25, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %27 = getelementptr inbounds [1 x %any], ptr %varargslots14, i64 0, i64 0 + store %any %26, ptr %27, align 16 %28 = call i64 @std.io.printfn(ptr %retparam13, ptr @.str.7, i64 2, ptr %varargslots14, i64 1) store %"char[]" { ptr @.str.10, i64 6 }, ptr %taddr18, align 8 - %29 = insertvalue %variant undef, ptr %taddr18, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %31 = getelementptr inbounds [1 x %variant], ptr %varargslots17, i64 0, i64 0 - store %variant %30, ptr %31, align 16 + %29 = insertvalue %any undef, ptr %taddr18, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %31 = getelementptr inbounds [1 x %any], ptr %varargslots17, i64 0, i64 0 + store %any %30, ptr %31, align 16 %32 = call i64 @std.io.printfn(ptr %retparam16, ptr @.str.9, i64 2, ptr %varargslots17, i64 1) store %"char[]" { ptr @.str.12, i64 13 }, ptr %taddr21, align 8 - %33 = insertvalue %variant undef, ptr %taddr21, 0 - %34 = insertvalue %variant %33, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %35 = getelementptr inbounds [1 x %variant], ptr %varargslots20, i64 0, i64 0 - store %variant %34, ptr %35, align 16 + %33 = insertvalue %any undef, ptr %taddr21, 0 + %34 = insertvalue %any %33, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %35 = getelementptr inbounds [1 x %any], ptr %varargslots20, i64 0, i64 0 + store %any %34, ptr %35, align 16 %36 = call i64 @std.io.printfn(ptr %retparam19, ptr @.str.11, i64 2, ptr %varargslots20, i64 1) store ptr @test.test2, ptr %y, align 8 store i64 ptrtoint (ptr @"$ct.p$fn$int$int$" to i64), ptr %zfoke, align 8 diff --git a/test/test_suite/functions/typeless_varargs.c3t b/test/test_suite/functions/typeless_varargs.c3t index b65875c2b..bf273e5d6 100644 --- a/test/test_suite/functions/typeless_varargs.c3t +++ b/test/test_suite/functions/typeless_varargs.c3t @@ -26,13 +26,13 @@ fn int main() define void @test.retest(ptr %0, i64 %1) #0 { entry: - %foo = alloca %"variant[]", align 8 + %foo = alloca %"any[]", align 8 store ptr %0, ptr %foo, align 8 %ptroffset = getelementptr inbounds i64, ptr %foo, i64 1 store i64 %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %"variant[]", ptr %foo, i32 0, i32 0 + %2 = getelementptr inbounds %"any[]", ptr %foo, i32 0, i32 0 %lo = load ptr, ptr %2, align 8 - %3 = getelementptr inbounds %"variant[]", ptr %foo, i32 0, i32 1 + %3 = getelementptr inbounds %"any[]", ptr %foo, i32 0, i32 1 %hi = load i64, ptr %3, align 8 call void @test.test(ptr %lo, i64 %hi) ret void @@ -40,14 +40,14 @@ entry: define void @test.test(ptr %0, i64 %1) #0 { entry: - %foo = alloca %"variant[]", align 8 + %foo = alloca %"any[]", align 8 store ptr %0, ptr %foo, align 8 %ptroffset = getelementptr inbounds i64, ptr %foo, i64 1 store i64 %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %"variant[]", ptr %foo, i32 0, i32 0 + %2 = getelementptr inbounds %"any[]", ptr %foo, i32 0, i32 0 %3 = load ptr, ptr %2, align 8 - %ptroffset1 = getelementptr inbounds %variant, ptr %3, i64 0 - %4 = getelementptr inbounds %variant, ptr %ptroffset1, i32 0, i32 0 + %ptroffset1 = getelementptr inbounds %any, ptr %3, i64 0 + %4 = getelementptr inbounds %any, ptr %ptroffset1, i32 0, i32 0 %5 = load ptr, ptr %4, align 8 %6 = load i32, ptr %5, align 4 call void (ptr, ...) @printf(ptr @.str, i32 %6) @@ -57,22 +57,22 @@ entry: define i32 @main() #0 { entry: %i = alloca i32, align 4 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 - %varargslots1 = alloca [1 x %variant], align 16 + %varargslots1 = alloca [1 x %any], align 16 %taddr2 = alloca i32, align 4 store i32 1, ptr %i, align 4 store i32 1, ptr %taddr, align 4 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %2 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %1, ptr %2, align 16 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %2 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %1, ptr %2, align 16 call void @test.test(ptr %varargslots, i64 1) store i32 1, ptr %taddr2, align 4 - %3 = insertvalue %variant undef, ptr %taddr2, 0 - %4 = insertvalue %variant %3, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %5 = getelementptr inbounds [1 x %variant], ptr %varargslots1, i64 0, i64 0 - store %variant %4, ptr %5, align 16 + %3 = insertvalue %any undef, ptr %taddr2, 0 + %4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %5 = getelementptr inbounds [1 x %any], ptr %varargslots1, i64 0, i64 0 + store %any %4, ptr %5, align 16 call void @test.retest(ptr %varargslots1, i64 1) ret i32 1 } \ No newline at end of file diff --git a/test/test_suite/functions/varargs_followed_by_named.c3t b/test/test_suite/functions/varargs_followed_by_named.c3t index 814bc700b..619b60c4a 100644 --- a/test/test_suite/functions/varargs_followed_by_named.c3t +++ b/test/test_suite/functions/varargs_followed_by_named.c3t @@ -42,11 +42,11 @@ entry: ; Function Attrs: nounwind define void @foo.test2(i32 %0, ptr %1, i64 %2, i32 %3) #0 { entry: - %y = alloca %"variant[]", align 8 + %y = alloca %"any[]", align 8 store ptr %1, ptr %y, align 8 %ptroffset = getelementptr inbounds i64, ptr %y, i64 1 store i64 %2, ptr %ptroffset, align 8 - %4 = getelementptr inbounds %"variant[]", ptr %y, i32 0, i32 1 + %4 = getelementptr inbounds %"any[]", ptr %y, i32 0, i32 1 %5 = load i64, ptr %4, align 8 %trunc = trunc i64 %5 to i32 call void (ptr, ...) @printf(ptr @.str.1, i32 %0, i32 %trunc, i32 %3) @@ -57,11 +57,11 @@ entry: define void @foo.main() #0 { entry: %varargslots = alloca [2 x i32], align 4 - %varargslots1 = alloca [2 x %variant], align 16 + %varargslots1 = alloca [2 x %any], align 16 %taddr = alloca i32, align 4 %taddr2 = alloca i32, align 4 %varargslots3 = alloca [2 x i32], align 4 - %varargslots4 = alloca [2 x %variant], align 16 + %varargslots4 = alloca [2 x %any], align 16 %taddr5 = alloca i32, align 4 %taddr6 = alloca i32, align 4 %0 = getelementptr inbounds [2 x i32], ptr %varargslots, i64 0, i64 0 @@ -70,15 +70,15 @@ entry: store i32 5, ptr %1, align 4 call void @foo.test(i32 3, ptr %varargslots, i64 2, i32 123) store i32 4, ptr %taddr, align 4 - %2 = insertvalue %variant undef, ptr %taddr, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %4 = getelementptr inbounds [2 x %variant], ptr %varargslots1, i64 0, i64 0 - store %variant %3, ptr %4, align 16 + %2 = insertvalue %any undef, ptr %taddr, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %4 = getelementptr inbounds [2 x %any], ptr %varargslots1, i64 0, i64 0 + store %any %3, ptr %4, align 16 store i32 5, ptr %taddr2, align 4 - %5 = insertvalue %variant undef, ptr %taddr2, 0 - %6 = insertvalue %variant %5, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %7 = getelementptr inbounds [2 x %variant], ptr %varargslots1, i64 0, i64 1 - store %variant %6, ptr %7, align 16 + %5 = insertvalue %any undef, ptr %taddr2, 0 + %6 = insertvalue %any %5, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %7 = getelementptr inbounds [2 x %any], ptr %varargslots1, i64 0, i64 1 + store %any %6, ptr %7, align 16 call void @foo.test2(i32 3, ptr %varargslots1, i64 2, i32 123) %8 = getelementptr inbounds [2 x i32], ptr %varargslots3, i64 0, i64 0 store i32 4, ptr %8, align 4 @@ -86,15 +86,15 @@ entry: store i32 5, ptr %9, align 4 call void @foo.test(i32 3, ptr %varargslots3, i64 2, i32 2) store i32 4, ptr %taddr5, align 4 - %10 = insertvalue %variant undef, ptr %taddr5, 0 - %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %12 = getelementptr inbounds [2 x %variant], ptr %varargslots4, i64 0, i64 0 - store %variant %11, ptr %12, align 16 + %10 = insertvalue %any undef, ptr %taddr5, 0 + %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %12 = getelementptr inbounds [2 x %any], ptr %varargslots4, i64 0, i64 0 + store %any %11, ptr %12, align 16 store i32 5, ptr %taddr6, align 4 - %13 = insertvalue %variant undef, ptr %taddr6, 0 - %14 = insertvalue %variant %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %15 = getelementptr inbounds [2 x %variant], ptr %varargslots4, i64 0, i64 1 - store %variant %14, ptr %15, align 16 + %13 = insertvalue %any undef, ptr %taddr6, 0 + %14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %15 = getelementptr inbounds [2 x %any], ptr %varargslots4, i64 0, i64 1 + store %any %14, ptr %15, align 16 call void @foo.test2(i32 3, ptr %varargslots4, i64 2, i32 2) ret void } \ No newline at end of file diff --git a/test/test_suite/functions/void_params.c3 b/test/test_suite/functions/void_params.c3 index e52d2c9a6..e4d0053bb 100644 --- a/test/test_suite/functions/void_params.c3 +++ b/test/test_suite/functions/void_params.c3 @@ -1,2 +1,2 @@ fn void test(int, void) {} // #error: Parameters may not be of type 'void'. -fn void test3(void); // #error: C-style 'foo(void)' style argument declarations are not valid \ No newline at end of file +extern fn void test3(void); // #error: C-style 'foo(void)' style argument declarations are not valid \ No newline at end of file diff --git a/test/test_suite/generic/enum_set_test.c3t b/test/test_suite/generic/enum_set_test.c3t index 10e3ce0d0..594472988 100644 --- a/test/test_suite/generic/enum_set_test.c3t +++ b/test/test_suite/generic/enum_set_test.c3t @@ -31,63 +31,63 @@ define void @test.main() #0 { entry: %set = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i8, align 1 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [1 x %variant], align 16 + %varargslots2 = alloca [1 x %any], align 16 %taddr3 = alloca i8, align 1 %retparam4 = alloca i64, align 8 - %varargslots5 = alloca [1 x %variant], align 16 + %varargslots5 = alloca [1 x %any], align 16 %taddr6 = alloca i8, align 1 %set2 = alloca i32, align 4 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %taddr9 = alloca i8, align 1 %retparam10 = alloca i64, align 8 - %varargslots11 = alloca [1 x %variant], align 16 + %varargslots11 = alloca [1 x %any], align 16 %taddr12 = alloca i8, align 1 store i32 0, ptr %set, align 4 %0 = call i8 @"std.collections.enumset$test.Abc$.EnumSet.has"(ptr %set, i32 1) store i8 %0, ptr %taddr, align 1 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printf(ptr %retparam, ptr @.str, i64 14, ptr %varargslots, i64 1) call void @"std.collections.enumset$test.Abc$.EnumSet.add"(ptr %set, i32 0) %5 = call i8 @"std.collections.enumset$test.Abc$.EnumSet.has"(ptr %set, i32 1) store i8 %5, ptr %taddr3, align 1 - %6 = insertvalue %variant undef, ptr %taddr3, 0 - %7 = insertvalue %variant %6, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %8 = getelementptr inbounds [1 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %7, ptr %8, align 16 + %6 = insertvalue %any undef, ptr %taddr3, 0 + %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %8 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %7, ptr %8, align 16 %9 = call i64 @std.io.printf(ptr %retparam1, ptr @.str.1, i64 14, ptr %varargslots2, i64 1) call void @"std.collections.enumset$test.Abc$.EnumSet.add"(ptr %set, i32 1) %10 = call i8 @"std.collections.enumset$test.Abc$.EnumSet.has"(ptr %set, i32 1) store i8 %10, ptr %taddr6, align 1 - %11 = insertvalue %variant undef, ptr %taddr6, 0 - %12 = insertvalue %variant %11, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %13 = getelementptr inbounds [1 x %variant], ptr %varargslots5, i64 0, i64 0 - store %variant %12, ptr %13, align 16 + %11 = insertvalue %any undef, ptr %taddr6, 0 + %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %13 = getelementptr inbounds [1 x %any], ptr %varargslots5, i64 0, i64 0 + store %any %12, ptr %13, align 16 %14 = call i64 @std.io.printf(ptr %retparam4, ptr @.str.2, i64 14, ptr %varargslots5, i64 1) store i32 0, ptr %set2, align 4 %15 = load i32, ptr %set, align 4 call void @"std.collections.enumset$test.Abc$.EnumSet.add_all"(ptr %set2, i32 %15) %16 = call i8 @"std.collections.enumset$test.Abc$.EnumSet.has"(ptr %set2, i32 1) store i8 %16, ptr %taddr9, align 1 - %17 = insertvalue %variant undef, ptr %taddr9, 0 - %18 = insertvalue %variant %17, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %19 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %18, ptr %19, align 16 + %17 = insertvalue %any undef, ptr %taddr9, 0 + %18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %19 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %18, ptr %19, align 16 %20 = call i64 @std.io.printf(ptr %retparam7, ptr @.str.3, i64 14, ptr %varargslots8, i64 1) %21 = load i32, ptr %set2, align 4 call void @"std.collections.enumset$test.Abc$.EnumSet.remove_all"(ptr %set, i32 %21) %22 = call i8 @"std.collections.enumset$test.Abc$.EnumSet.has"(ptr %set, i32 1) store i8 %22, ptr %taddr12, align 1 - %23 = insertvalue %variant undef, ptr %taddr12, 0 - %24 = insertvalue %variant %23, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %25 = getelementptr inbounds [1 x %variant], ptr %varargslots11, i64 0, i64 0 - store %variant %24, ptr %25, align 16 + %23 = insertvalue %any undef, ptr %taddr12, 0 + %24 = insertvalue %any %23, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %25 = getelementptr inbounds [1 x %any], ptr %varargslots11, i64 0, i64 0 + store %any %24, ptr %25, align 16 %26 = call i64 @std.io.printf(ptr %retparam10, ptr @.str.4, i64 14, ptr %varargslots11, i64 1) ret void } diff --git a/test/test_suite/generic/generic_num.c3t b/test/test_suite/generic/generic_num.c3t index 9d62ffe5c..a04316954 100644 --- a/test/test_suite/generic/generic_num.c3t +++ b/test/test_suite/generic/generic_num.c3t @@ -22,14 +22,14 @@ fn void main() define void @test.main() #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 %0 = call i32 @"hello$int$_123$.x"(i32 4) store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) ret void } diff --git a/test/test_suite/literals/bin_literal.c3t b/test/test_suite/literals/bin_literal.c3t index b8526654b..4312dc5e8 100644 --- a/test/test_suite/literals/bin_literal.c3t +++ b/test/test_suite/literals/bin_literal.c3t @@ -22,10 +22,10 @@ entry: %c = alloca i32, align 4 %d = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %z = alloca i8, align 1 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [3 x %variant], align 16 + %varargslots2 = alloca [3 x %any], align 16 %i = alloca i8, align 1 %shift = alloca i8, align 1 %taddr = alloca i8, align 1 @@ -42,20 +42,20 @@ entry: %4 = load i32, ptr %b, align 4 %5 = call i32 @llvm.smax.i32(i32 %3, i32 %4) store i32 %5, ptr %d, align 4 - %6 = insertvalue %variant undef, ptr %c, 0 - %7 = insertvalue %variant %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %8 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %7, ptr %8, align 16 - %9 = insertvalue %variant undef, ptr %d, 0 - %10 = insertvalue %variant %9, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %11 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %10, ptr %11, align 16 + %6 = insertvalue %any undef, ptr %c, 0 + %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %8 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %7, ptr %8, align 16 + %9 = insertvalue %any undef, ptr %d, 0 + %10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %11 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %10, ptr %11, align 16 %12 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 5, ptr %varargslots, i64 2) store i8 -35, ptr %z, align 1 - %13 = insertvalue %variant undef, ptr %z, 0 - %14 = insertvalue %variant %13, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %15 = getelementptr inbounds [3 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %14, ptr %15, align 16 + %13 = insertvalue %any undef, ptr %z, 0 + %14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %15 = getelementptr inbounds [3 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %14, ptr %15, align 16 %16 = load i8, ptr %z, align 1 store i8 %16, ptr %i, align 1 store i8 1, ptr %shift, align 1 @@ -64,10 +64,10 @@ entry: %19 = load i8, ptr %shift, align 1 %20 = call i8 @llvm.fshr.i8(i8 %17, i8 %18, i8 %19) store i8 %20, ptr %taddr, align 1 - %21 = insertvalue %variant undef, ptr %taddr, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %23 = getelementptr inbounds [3 x %variant], ptr %varargslots2, i64 0, i64 1 - store %variant %22, ptr %23, align 16 + %21 = insertvalue %any undef, ptr %taddr, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %23 = getelementptr inbounds [3 x %any], ptr %varargslots2, i64 0, i64 1 + store %any %22, ptr %23, align 16 %24 = load i8, ptr %z, align 1 store i8 %24, ptr %i3, align 1 store i8 1, ptr %shift4, align 1 @@ -76,10 +76,10 @@ entry: %27 = load i8, ptr %shift4, align 1 %28 = call i8 @llvm.fshl.i8(i8 %25, i8 %26, i8 %27) store i8 %28, ptr %taddr5, align 1 - %29 = insertvalue %variant undef, ptr %taddr5, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.char" to i64), 1 - %31 = getelementptr inbounds [3 x %variant], ptr %varargslots2, i64 0, i64 2 - store %variant %30, ptr %31, align 16 + %29 = insertvalue %any undef, ptr %taddr5, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.char" to i64), 1 + %31 = getelementptr inbounds [3 x %any], ptr %varargslots2, i64 0, i64 2 + store %any %30, ptr %31, align 16 %32 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.1, i64 8, ptr %varargslots2, i64 3) ret void } diff --git a/test/test_suite/macros/macro_body_defer.c3t b/test/test_suite/macros/macro_body_defer.c3t index 8fb9b6614..714846bad 100644 --- a/test/test_suite/macros/macro_body_defer.c3t +++ b/test/test_suite/macros/macro_body_defer.c3t @@ -106,25 +106,40 @@ define i32 @main(i32 %0, ptr %1) #0 { entry: %.anon = alloca i32, align 4 %.anon1 = alloca ptr, align 8 - %error_var = alloca i64, align 8 + %blockret = alloca i32, align 4 + %temp_err = alloca i64, align 8 store i32 %0, ptr %.anon, align 4 store ptr %1, ptr %.anon1, align 8 - store i64 0, ptr %error_var, align 8 + br label %testblock + +testblock: ; preds = %entry %2 = call i64 @foo.main() %not_err = icmp eq i64 %2, 0 %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) br i1 %3, label %after_check, label %assign_optional -assign_optional: ; preds = %entry - store i64 %2, ptr %error_var, align 8 - br label %noerr_block +assign_optional: ; preds = %testblock + store i64 %2, ptr %temp_err, align 8 + br label %end_block -after_check: ; preds = %entry - br label %noerr_block +after_check: ; preds = %testblock + store i64 0, ptr %temp_err, align 8 + br label %end_block -noerr_block: ; preds = %after_check, %assign_optional - %4 = load i64, ptr %error_var, align 8 +end_block: ; preds = %after_check, %assign_optional + %4 = load i64, ptr %temp_err, align 8 %neq = icmp ne i64 %4, 0 - %ternary = select i1 %neq, i32 1, i32 0 - ret i32 %ternary + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + store i32 1, ptr %blockret, align 4 + br label %expr_block.exit + +if.exit: ; preds = %end_block + store i32 0, ptr %blockret, align 4 + br label %expr_block.exit + +expr_block.exit: ; preds = %if.exit, %if.then + %5 = load i32, ptr %blockret, align 4 + ret i32 %5 } diff --git a/test/test_suite/macros/macro_failable_return_rethrow.c3t b/test/test_suite/macros/macro_failable_return_rethrow.c3t index 1e303fd35..a849ece1d 100644 --- a/test/test_suite/macros/macro_failable_return_rethrow.c3t +++ b/test/test_suite/macros/macro_failable_return_rethrow.c3t @@ -6,7 +6,7 @@ fn int! xy() } macro int! foo() { - xy()?; + xy()!; return 1; } fn void main() @@ -19,7 +19,6 @@ fn void main() define void @test.main() #0 { entry: %error_var = alloca i64, align 8 - %blockret = alloca i32, align 4 %error_var1 = alloca i64, align 8 %retparam = alloca i32, align 4 %0 = call i64 @test.xy(ptr %retparam) @@ -38,13 +37,8 @@ guard_block: ; preds = %assign_optional ret void noerr_block: ; preds = %after_check - store i32 1, ptr %blockret, align 4 - br label %expr_block.exit - -expr_block.exit: ; preds = %noerr_block - %2 = load i32, ptr %blockret, align 4 br label %noerr_block2 -noerr_block2: ; preds = %expr_block.exit +noerr_block2: ; preds = %noerr_block ret void } \ No newline at end of file diff --git a/test/test_suite/macros/macro_typed_varargs.c3t b/test/test_suite/macros/macro_typed_varargs.c3t index a218a934b..00e51970b 100644 --- a/test/test_suite/macros/macro_typed_varargs.c3t +++ b/test/test_suite/macros/macro_typed_varargs.c3t @@ -36,18 +36,18 @@ entry: %.anon1 = alloca i64, align 8 %i = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 - %x2 = alloca %"variant[]", align 8 - %literal3 = alloca [4 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 + %x2 = alloca %"any[]", align 8 + %literal3 = alloca [4 x %any], align 16 %taddr = alloca i32, align 4 %taddr4 = alloca i32, align 4 %taddr5 = alloca i32, align 4 %taddr6 = alloca i32, align 4 %.anon7 = alloca i64, align 8 %.anon8 = alloca i64, align 8 - %i12 = alloca %variant, align 8 + %i12 = alloca %any, align 8 %retparam14 = alloca i64, align 8 - %varargslots15 = alloca [1 x %variant], align 16 + %varargslots15 = alloca [1 x %any], align 16 %0 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 0 store i32 1, ptr %0, align 4 %1 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 1 @@ -76,40 +76,40 @@ loop.body: ; preds = %loop.cond %ptroffset = getelementptr inbounds i32, ptr %11, i64 %12 %13 = load i32, ptr %ptroffset, align 4 store i32 %13, ptr %i, align 4 - %14 = insertvalue %variant undef, ptr %i, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %16 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %15, ptr %16, align 16 + %14 = insertvalue %any undef, ptr %i, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %16 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %15, ptr %16, align 16 %17 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1) %18 = load i64, ptr %.anon1, align 8 %add = add i64 %18, 1 store i64 %add, ptr %.anon1, align 8 br label %loop.cond loop.exit: ; preds = %loop.cond - %19 = getelementptr inbounds [4 x %variant], ptr %literal3, i64 0, i64 0 + %19 = getelementptr inbounds [4 x %any], ptr %literal3, i64 0, i64 0 store i32 1, ptr %taddr, align 4 - %20 = insertvalue %variant undef, ptr %taddr, 0 - %21 = insertvalue %variant %20, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %21, ptr %19, align 8 - %22 = getelementptr inbounds [4 x %variant], ptr %literal3, i64 0, i64 1 + %20 = insertvalue %any undef, ptr %taddr, 0 + %21 = insertvalue %any %20, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %21, ptr %19, align 8 + %22 = getelementptr inbounds [4 x %any], ptr %literal3, i64 0, i64 1 store i32 -1, ptr %taddr4, align 4 - %23 = insertvalue %variant undef, ptr %taddr4, 0 - %24 = insertvalue %variant %23, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %24, ptr %22, align 8 - %25 = getelementptr inbounds [4 x %variant], ptr %literal3, i64 0, i64 2 + %23 = insertvalue %any undef, ptr %taddr4, 0 + %24 = insertvalue %any %23, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %24, ptr %22, align 8 + %25 = getelementptr inbounds [4 x %any], ptr %literal3, i64 0, i64 2 store i32 3141, ptr %taddr5, align 4 - %26 = insertvalue %variant undef, ptr %taddr5, 0 - %27 = insertvalue %variant %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %27, ptr %25, align 8 - %28 = getelementptr inbounds [4 x %variant], ptr %literal3, i64 0, i64 3 + %26 = insertvalue %any undef, ptr %taddr5, 0 + %27 = insertvalue %any %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %27, ptr %25, align 8 + %28 = getelementptr inbounds [4 x %any], ptr %literal3, i64 0, i64 3 store i32 1000, ptr %taddr6, align 4 - %29 = insertvalue %variant undef, ptr %taddr6, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %30, ptr %28, align 8 - %31 = insertvalue %"variant[]" undef, ptr %literal3, 0 - %32 = insertvalue %"variant[]" %31, i64 4, 1 - store %"variant[]" %32, ptr %x2, align 8 - %33 = getelementptr inbounds %"variant[]", ptr %x2, i32 0, i32 1 + %29 = insertvalue %any undef, ptr %taddr6, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %30, ptr %28, align 8 + %31 = insertvalue %"any[]" undef, ptr %literal3, 0 + %32 = insertvalue %"any[]" %31, i64 4, 1 + store %"any[]" %32, ptr %x2, align 8 + %33 = getelementptr inbounds %"any[]", ptr %x2, i32 0, i32 1 %34 = load i64, ptr %33, align 8 store i64 %34, ptr %.anon7, align 8 store i64 0, ptr %.anon8, align 8 @@ -120,17 +120,17 @@ loop.cond9: ; preds = %loop.body11, %loop. %lt10 = icmp ult i64 %35, %36 br i1 %lt10, label %loop.body11, label %loop.exit17 loop.body11: ; preds = %loop.cond9 - %37 = getelementptr inbounds %"variant[]", ptr %x2, i32 0, i32 0 + %37 = getelementptr inbounds %"any[]", ptr %x2, i32 0, i32 0 %38 = load ptr, ptr %37, align 8 %39 = load i64, ptr %.anon8, align 8 - %ptroffset13 = getelementptr inbounds %variant, ptr %38, i64 %39 + %ptroffset13 = getelementptr inbounds %any, ptr %38, i64 %39 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %i12, ptr align 8 %ptroffset13, i32 16, i1 false) - %40 = getelementptr inbounds %variant, ptr %i12, i32 0, i32 0 + %40 = getelementptr inbounds %any, ptr %i12, i32 0, i32 0 %41 = load ptr, ptr %40, align 8 - %42 = insertvalue %variant undef, ptr %41, 0 - %43 = insertvalue %variant %42, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %44 = getelementptr inbounds [1 x %variant], ptr %varargslots15, i64 0, i64 0 - store %variant %43, ptr %44, align 16 + %42 = insertvalue %any undef, ptr %41, 0 + %43 = insertvalue %any %42, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %44 = getelementptr inbounds [1 x %any], ptr %varargslots15, i64 0, i64 0 + store %any %43, ptr %44, align 16 %45 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.1, i64 2, ptr %varargslots15, i64 1) %46 = load i64, ptr %.anon8, align 8 %add16 = add i64 %46, 1 diff --git a/test/test_suite/macros/macro_untyped_varargs_2.c3t b/test/test_suite/macros/macro_untyped_varargs_2.c3t index daeb695a6..7500b80af 100644 --- a/test/test_suite/macros/macro_untyped_varargs_2.c3t +++ b/test/test_suite/macros/macro_untyped_varargs_2.c3t @@ -63,13 +63,13 @@ fn void main() define i32 @test.ping(i32 %0) #0 { entry: %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %taddr = alloca i32, align 4 store i32 %0, ptr %taddr, align 4 - %1 = insertvalue %variant undef, ptr %taddr, 0 - %2 = insertvalue %variant %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %3 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %2, ptr %3, align 16 + %1 = insertvalue %any undef, ptr %taddr, 0 + %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %3 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %2, ptr %3, align 16 %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 1) ret i32 %0 } @@ -83,32 +83,32 @@ entry: %i = alloca i32, align 4 %j = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %retparam5 = alloca i64, align 8 - %varargslots6 = alloca [1 x %variant], align 16 + %varargslots6 = alloca [1 x %any], align 16 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %retparam9 = alloca i64, align 8 - %varargslots10 = alloca [1 x %variant], align 16 + %varargslots10 = alloca [1 x %any], align 16 %x = alloca i32, align 4 %retparam11 = alloca i64, align 8 - %varargslots12 = alloca [1 x %variant], align 16 + %varargslots12 = alloca [1 x %any], align 16 %taddr = alloca %"char[]", align 8 %x13 = alloca double, align 8 %retparam14 = alloca i64, align 8 - %varargslots15 = alloca [1 x %variant], align 16 + %varargslots15 = alloca [1 x %any], align 16 %taddr16 = alloca %"char[]", align 8 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [1 x %variant], align 16 + %varargslots18 = alloca [1 x %any], align 16 %taddr19 = alloca i32, align 4 %x20 = alloca i32, align 4 %y = alloca i32, align 4 %a = alloca i32, align 4 %retparam21 = alloca i64, align 8 - %varargslots22 = alloca [2 x %variant], align 16 + %varargslots22 = alloca [2 x %any], align 16 %a23 = alloca i32, align 4 %retparam24 = alloca i64, align 8 - %varargslots25 = alloca [2 x %variant], align 16 + %varargslots25 = alloca [2 x %any], align 16 %0 = call i32 @test.ping(i32 -1) store i32 %0, ptr %.anon, align 4 %1 = call i32 @test.ping(i32 1) @@ -125,45 +125,45 @@ entry: %7 = call i32 @test.ping(i32 3141) %add4 = add i32 %6, %7 store i32 %add4, ptr %j, align 4 - %8 = insertvalue %variant undef, ptr %.anon1, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %10 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %9, ptr %10, align 16 + %8 = insertvalue %any undef, ptr %.anon1, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %10 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %9, ptr %10, align 16 %11 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.1, i64 2, ptr %varargslots, i64 1) - %12 = insertvalue %variant undef, ptr %.anon, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %14 = getelementptr inbounds [1 x %variant], ptr %varargslots6, i64 0, i64 0 - store %variant %13, ptr %14, align 16 + %12 = insertvalue %any undef, ptr %.anon, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %14 = getelementptr inbounds [1 x %any], ptr %varargslots6, i64 0, i64 0 + store %any %13, ptr %14, align 16 %15 = call i64 @std.io.printfn(ptr %retparam5, ptr @.str.2, i64 2, ptr %varargslots6, i64 1) - %16 = insertvalue %variant undef, ptr %.anon2, 0 - %17 = insertvalue %variant %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %18 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %17, ptr %18, align 16 + %16 = insertvalue %any undef, ptr %.anon2, 0 + %17 = insertvalue %any %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %18 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %17, ptr %18, align 16 %19 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.3, i64 2, ptr %varargslots8, i64 1) - %20 = insertvalue %variant undef, ptr %.anon3, 0 - %21 = insertvalue %variant %20, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %22 = getelementptr inbounds [1 x %variant], ptr %varargslots10, i64 0, i64 0 - store %variant %21, ptr %22, align 16 + %20 = insertvalue %any undef, ptr %.anon3, 0 + %21 = insertvalue %any %20, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %22 = getelementptr inbounds [1 x %any], ptr %varargslots10, i64 0, i64 0 + store %any %21, ptr %22, align 16 %23 = call i64 @std.io.printfn(ptr %retparam9, ptr @.str.4, i64 2, ptr %varargslots10, i64 1) store i32 0, ptr %x, align 4 store %"char[]" { ptr @.str.6, i64 3 }, ptr %taddr, align 8 - %24 = insertvalue %variant undef, ptr %taddr, 0 - %25 = insertvalue %variant %24, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %26 = getelementptr inbounds [1 x %variant], ptr %varargslots12, i64 0, i64 0 - store %variant %25, ptr %26, align 16 + %24 = insertvalue %any undef, ptr %taddr, 0 + %25 = insertvalue %any %24, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %26 = getelementptr inbounds [1 x %any], ptr %varargslots12, i64 0, i64 0 + store %any %25, ptr %26, align 16 %27 = call i64 @std.io.printfn(ptr %retparam11, ptr @.str.5, i64 2, ptr %varargslots12, i64 1) store double 0.000000e+00, ptr %x13, align 8 store %"char[]" { ptr @.str.8, i64 6 }, ptr %taddr16, align 8 - %28 = insertvalue %variant undef, ptr %taddr16, 0 - %29 = insertvalue %variant %28, i64 ptrtoint (ptr @"$ct.String" to i64), 1 - %30 = getelementptr inbounds [1 x %variant], ptr %varargslots15, i64 0, i64 0 - store %variant %29, ptr %30, align 16 + %28 = insertvalue %any undef, ptr %taddr16, 0 + %29 = insertvalue %any %28, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + %30 = getelementptr inbounds [1 x %any], ptr %varargslots15, i64 0, i64 0 + store %any %29, ptr %30, align 16 %31 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.7, i64 2, ptr %varargslots15, i64 1) store i32 105, ptr %taddr19, align 4 - %32 = insertvalue %variant undef, ptr %taddr19, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %34 = getelementptr inbounds [1 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %33, ptr %34, align 16 + %32 = insertvalue %any undef, ptr %taddr19, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %34 = getelementptr inbounds [1 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %33, ptr %34, align 16 %35 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.9, i64 2, ptr %varargslots18, i64 1) store i32 123, ptr %x20, align 4 store i32 33, ptr %y, align 4 @@ -173,14 +173,14 @@ entry: store i32 %37, ptr %x20, align 4 %38 = load i32, ptr %a, align 4 store i32 %38, ptr %y, align 4 - %39 = insertvalue %variant undef, ptr %x20, 0 - %40 = insertvalue %variant %39, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %41 = getelementptr inbounds [2 x %variant], ptr %varargslots22, i64 0, i64 0 - store %variant %40, ptr %41, align 16 - %42 = insertvalue %variant undef, ptr %y, 0 - %43 = insertvalue %variant %42, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %44 = getelementptr inbounds [2 x %variant], ptr %varargslots22, i64 0, i64 1 - store %variant %43, ptr %44, align 16 + %39 = insertvalue %any undef, ptr %x20, 0 + %40 = insertvalue %any %39, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %41 = getelementptr inbounds [2 x %any], ptr %varargslots22, i64 0, i64 0 + store %any %40, ptr %41, align 16 + %42 = insertvalue %any undef, ptr %y, 0 + %43 = insertvalue %any %42, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %44 = getelementptr inbounds [2 x %any], ptr %varargslots22, i64 0, i64 1 + store %any %43, ptr %44, align 16 %45 = call i64 @std.io.printfn(ptr %retparam21, ptr @.str.10, i64 6, ptr %varargslots22, i64 2) %46 = load i32, ptr %x20, align 4 store i32 %46, ptr %a23, align 4 @@ -188,14 +188,14 @@ entry: store i32 %47, ptr %x20, align 4 %48 = load i32, ptr %a23, align 4 store i32 %48, ptr %y, align 4 - %49 = insertvalue %variant undef, ptr %x20, 0 - %50 = insertvalue %variant %49, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %51 = getelementptr inbounds [2 x %variant], ptr %varargslots25, i64 0, i64 0 - store %variant %50, ptr %51, align 16 - %52 = insertvalue %variant undef, ptr %y, 0 - %53 = insertvalue %variant %52, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %54 = getelementptr inbounds [2 x %variant], ptr %varargslots25, i64 0, i64 1 - store %variant %53, ptr %54, align 16 + %49 = insertvalue %any undef, ptr %x20, 0 + %50 = insertvalue %any %49, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %51 = getelementptr inbounds [2 x %any], ptr %varargslots25, i64 0, i64 0 + store %any %50, ptr %51, align 16 + %52 = insertvalue %any undef, ptr %y, 0 + %53 = insertvalue %any %52, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %54 = getelementptr inbounds [2 x %any], ptr %varargslots25, i64 0, i64 1 + store %any %53, ptr %54, align 16 %55 = call i64 @std.io.printfn(ptr %retparam24, ptr @.str.11, i64 6, ptr %varargslots25, i64 2) ret void } \ No newline at end of file diff --git a/test/test_suite/macros/macro_vasplat.c3t b/test/test_suite/macros/macro_vasplat.c3t index 458e7292a..9b2f7eb6e 100644 --- a/test/test_suite/macros/macro_vasplat.c3t +++ b/test/test_suite/macros/macro_vasplat.c3t @@ -69,73 +69,73 @@ entry: %i = alloca i64, align 8 %x = alloca i32, align 4 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %a1 = alloca [1 x i32], align 4 %.anon2 = alloca i64, align 8 %i6 = alloca i64, align 8 %x7 = alloca i32, align 4 %retparam8 = alloca i64, align 8 - %varargslots9 = alloca [2 x %variant], align 16 + %varargslots9 = alloca [2 x %any], align 16 %a12 = alloca [4 x i32], align 16 %.anon13 = alloca i64, align 8 %i17 = alloca i64, align 8 %x18 = alloca i32, align 4 %retparam19 = alloca i64, align 8 - %varargslots20 = alloca [2 x %variant], align 16 + %varargslots20 = alloca [2 x %any], align 16 %a23 = alloca [2 x i32], align 4 %.anon24 = alloca i64, align 8 %i28 = alloca i64, align 8 %x29 = alloca i32, align 4 %retparam30 = alloca i64, align 8 - %varargslots31 = alloca [2 x %variant], align 16 + %varargslots31 = alloca [2 x %any], align 16 %a34 = alloca [3 x i32], align 4 %.anon35 = alloca i64, align 8 %i39 = alloca i64, align 8 %x40 = alloca i32, align 4 %retparam41 = alloca i64, align 8 - %varargslots42 = alloca [2 x %variant], align 16 + %varargslots42 = alloca [2 x %any], align 16 %a45 = alloca [1 x i32], align 4 %.anon46 = alloca i64, align 8 %i50 = alloca i64, align 8 %x51 = alloca i32, align 4 %retparam52 = alloca i64, align 8 - %varargslots53 = alloca [2 x %variant], align 16 + %varargslots53 = alloca [2 x %any], align 16 %a56 = alloca [2 x i32], align 4 %.anon57 = alloca i64, align 8 %i61 = alloca i64, align 8 %x62 = alloca i32, align 4 %retparam63 = alloca i64, align 8 - %varargslots64 = alloca [2 x %variant], align 16 + %varargslots64 = alloca [2 x %any], align 16 %a67 = alloca [5 x i32], align 16 %.anon68 = alloca i64, align 8 %i72 = alloca i64, align 8 %x73 = alloca i32, align 4 %retparam74 = alloca i64, align 8 - %varargslots75 = alloca [2 x %variant], align 16 + %varargslots75 = alloca [2 x %any], align 16 %a78 = alloca [8 x i32], align 16 %.anon79 = alloca i64, align 8 %i83 = alloca i64, align 8 %x84 = alloca i32, align 4 %retparam85 = alloca i64, align 8 - %varargslots86 = alloca [2 x %variant], align 16 + %varargslots86 = alloca [2 x %any], align 16 %b = alloca [7 x i32], align 16 %.anon89 = alloca i64, align 8 %i93 = alloca i64, align 8 %x94 = alloca i32, align 4 %retparam95 = alloca i64, align 8 - %varargslots96 = alloca [2 x %variant], align 16 + %varargslots96 = alloca [2 x %any], align 16 %c = alloca [8 x i32], align 16 %.anon99 = alloca i64, align 8 %i103 = alloca i64, align 8 %x104 = alloca i32, align 4 %retparam105 = alloca i64, align 8 - %varargslots106 = alloca [2 x %variant], align 16 + %varargslots106 = alloca [2 x %any], align 16 %a109 = alloca [6 x i32], align 16 %.anon110 = alloca i64, align 8 %i114 = alloca i64, align 8 %x115 = alloca i32, align 4 %retparam116 = alloca i64, align 8 - %varargslots117 = alloca [2 x %variant], align 16 + %varargslots117 = alloca [2 x %any], align 16 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %a, ptr align 4 @.__const, i32 12, i1 false) store i64 0, ptr %.anon, align 8 br label %loop.cond @@ -152,14 +152,14 @@ loop.body: ; preds = %loop.cond %3 = getelementptr inbounds [3 x i32], ptr %a, i64 0, i64 %2 %4 = load i32, ptr %3, align 4 store i32 %4, ptr %x, align 4 - %5 = insertvalue %variant undef, ptr %i, 0 - %6 = insertvalue %variant %5, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %7 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %6, ptr %7, align 16 - %8 = insertvalue %variant undef, ptr %x, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %10 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %9, ptr %10, align 16 + %5 = insertvalue %any undef, ptr %i, 0 + %6 = insertvalue %any %5, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %7 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %6, ptr %7, align 16 + %8 = insertvalue %any undef, ptr %x, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %10 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %9, ptr %10, align 16 %11 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 2) %12 = load i64, ptr %.anon, align 8 %add = add i64 %12, 1 @@ -183,14 +183,14 @@ loop.body5: ; preds = %loop.cond3 %16 = getelementptr inbounds [1 x i32], ptr %a1, i64 0, i64 %15 %17 = load i32, ptr %16, align 4 store i32 %17, ptr %x7, align 4 - %18 = insertvalue %variant undef, ptr %i6, 0 - %19 = insertvalue %variant %18, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %20 = getelementptr inbounds [2 x %variant], ptr %varargslots9, i64 0, i64 0 - store %variant %19, ptr %20, align 16 - %21 = insertvalue %variant undef, ptr %x7, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %23 = getelementptr inbounds [2 x %variant], ptr %varargslots9, i64 0, i64 1 - store %variant %22, ptr %23, align 16 + %18 = insertvalue %any undef, ptr %i6, 0 + %19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %20 = getelementptr inbounds [2 x %any], ptr %varargslots9, i64 0, i64 0 + store %any %19, ptr %20, align 16 + %21 = insertvalue %any undef, ptr %x7, 0 + %22 = insertvalue %any %21, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %23 = getelementptr inbounds [2 x %any], ptr %varargslots9, i64 0, i64 1 + store %any %22, ptr %23, align 16 %24 = call i64 @std.io.printfn(ptr %retparam8, ptr @.str.2, i64 8, ptr %varargslots9, i64 2) %25 = load i64, ptr %.anon2, align 8 %add10 = add i64 %25, 1 @@ -214,14 +214,14 @@ loop.body16: ; preds = %loop.cond14 %29 = getelementptr inbounds [4 x i32], ptr %a12, i64 0, i64 %28 %30 = load i32, ptr %29, align 4 store i32 %30, ptr %x18, align 4 - %31 = insertvalue %variant undef, ptr %i17, 0 - %32 = insertvalue %variant %31, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %33 = getelementptr inbounds [2 x %variant], ptr %varargslots20, i64 0, i64 0 - store %variant %32, ptr %33, align 16 - %34 = insertvalue %variant undef, ptr %x18, 0 - %35 = insertvalue %variant %34, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %36 = getelementptr inbounds [2 x %variant], ptr %varargslots20, i64 0, i64 1 - store %variant %35, ptr %36, align 16 + %31 = insertvalue %any undef, ptr %i17, 0 + %32 = insertvalue %any %31, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %33 = getelementptr inbounds [2 x %any], ptr %varargslots20, i64 0, i64 0 + store %any %32, ptr %33, align 16 + %34 = insertvalue %any undef, ptr %x18, 0 + %35 = insertvalue %any %34, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %36 = getelementptr inbounds [2 x %any], ptr %varargslots20, i64 0, i64 1 + store %any %35, ptr %36, align 16 %37 = call i64 @std.io.printfn(ptr %retparam19, ptr @.str.4, i64 6, ptr %varargslots20, i64 2) %38 = load i64, ptr %.anon13, align 8 %add21 = add i64 %38, 1 @@ -245,14 +245,14 @@ loop.body27: ; preds = %loop.cond25 %42 = getelementptr inbounds [2 x i32], ptr %a23, i64 0, i64 %41 %43 = load i32, ptr %42, align 4 store i32 %43, ptr %x29, align 4 - %44 = insertvalue %variant undef, ptr %i28, 0 - %45 = insertvalue %variant %44, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %46 = getelementptr inbounds [2 x %variant], ptr %varargslots31, i64 0, i64 0 - store %variant %45, ptr %46, align 16 - %47 = insertvalue %variant undef, ptr %x29, 0 - %48 = insertvalue %variant %47, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %49 = getelementptr inbounds [2 x %variant], ptr %varargslots31, i64 0, i64 1 - store %variant %48, ptr %49, align 16 + %44 = insertvalue %any undef, ptr %i28, 0 + %45 = insertvalue %any %44, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %46 = getelementptr inbounds [2 x %any], ptr %varargslots31, i64 0, i64 0 + store %any %45, ptr %46, align 16 + %47 = insertvalue %any undef, ptr %x29, 0 + %48 = insertvalue %any %47, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %49 = getelementptr inbounds [2 x %any], ptr %varargslots31, i64 0, i64 1 + store %any %48, ptr %49, align 16 %50 = call i64 @std.io.printfn(ptr %retparam30, ptr @.str.6, i64 6, ptr %varargslots31, i64 2) %51 = load i64, ptr %.anon24, align 8 %add32 = add i64 %51, 1 @@ -276,14 +276,14 @@ loop.body38: ; preds = %loop.cond36 %55 = getelementptr inbounds [3 x i32], ptr %a34, i64 0, i64 %54 %56 = load i32, ptr %55, align 4 store i32 %56, ptr %x40, align 4 - %57 = insertvalue %variant undef, ptr %i39, 0 - %58 = insertvalue %variant %57, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %59 = getelementptr inbounds [2 x %variant], ptr %varargslots42, i64 0, i64 0 - store %variant %58, ptr %59, align 16 - %60 = insertvalue %variant undef, ptr %x40, 0 - %61 = insertvalue %variant %60, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %62 = getelementptr inbounds [2 x %variant], ptr %varargslots42, i64 0, i64 1 - store %variant %61, ptr %62, align 16 + %57 = insertvalue %any undef, ptr %i39, 0 + %58 = insertvalue %any %57, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %59 = getelementptr inbounds [2 x %any], ptr %varargslots42, i64 0, i64 0 + store %any %58, ptr %59, align 16 + %60 = insertvalue %any undef, ptr %x40, 0 + %61 = insertvalue %any %60, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %62 = getelementptr inbounds [2 x %any], ptr %varargslots42, i64 0, i64 1 + store %any %61, ptr %62, align 16 %63 = call i64 @std.io.printfn(ptr %retparam41, ptr @.str.8, i64 8, ptr %varargslots42, i64 2) %64 = load i64, ptr %.anon35, align 8 %add43 = add i64 %64, 1 @@ -307,14 +307,14 @@ loop.body49: ; preds = %loop.cond47 %68 = getelementptr inbounds [1 x i32], ptr %a45, i64 0, i64 %67 %69 = load i32, ptr %68, align 4 store i32 %69, ptr %x51, align 4 - %70 = insertvalue %variant undef, ptr %i50, 0 - %71 = insertvalue %variant %70, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %72 = getelementptr inbounds [2 x %variant], ptr %varargslots53, i64 0, i64 0 - store %variant %71, ptr %72, align 16 - %73 = insertvalue %variant undef, ptr %x51, 0 - %74 = insertvalue %variant %73, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %75 = getelementptr inbounds [2 x %variant], ptr %varargslots53, i64 0, i64 1 - store %variant %74, ptr %75, align 16 + %70 = insertvalue %any undef, ptr %i50, 0 + %71 = insertvalue %any %70, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %72 = getelementptr inbounds [2 x %any], ptr %varargslots53, i64 0, i64 0 + store %any %71, ptr %72, align 16 + %73 = insertvalue %any undef, ptr %x51, 0 + %74 = insertvalue %any %73, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %75 = getelementptr inbounds [2 x %any], ptr %varargslots53, i64 0, i64 1 + store %any %74, ptr %75, align 16 %76 = call i64 @std.io.printfn(ptr %retparam52, ptr @.str.10, i64 8, ptr %varargslots53, i64 2) %77 = load i64, ptr %.anon46, align 8 %add54 = add i64 %77, 1 @@ -338,14 +338,14 @@ loop.body60: ; preds = %loop.cond58 %81 = getelementptr inbounds [2 x i32], ptr %a56, i64 0, i64 %80 %82 = load i32, ptr %81, align 4 store i32 %82, ptr %x62, align 4 - %83 = insertvalue %variant undef, ptr %i61, 0 - %84 = insertvalue %variant %83, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %85 = getelementptr inbounds [2 x %variant], ptr %varargslots64, i64 0, i64 0 - store %variant %84, ptr %85, align 16 - %86 = insertvalue %variant undef, ptr %x62, 0 - %87 = insertvalue %variant %86, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %88 = getelementptr inbounds [2 x %variant], ptr %varargslots64, i64 0, i64 1 - store %variant %87, ptr %88, align 16 + %83 = insertvalue %any undef, ptr %i61, 0 + %84 = insertvalue %any %83, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %85 = getelementptr inbounds [2 x %any], ptr %varargslots64, i64 0, i64 0 + store %any %84, ptr %85, align 16 + %86 = insertvalue %any undef, ptr %x62, 0 + %87 = insertvalue %any %86, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %88 = getelementptr inbounds [2 x %any], ptr %varargslots64, i64 0, i64 1 + store %any %87, ptr %88, align 16 %89 = call i64 @std.io.printfn(ptr %retparam63, ptr @.str.12, i64 8, ptr %varargslots64, i64 2) %90 = load i64, ptr %.anon57, align 8 %add65 = add i64 %90, 1 @@ -369,14 +369,14 @@ loop.body71: ; preds = %loop.cond69 %94 = getelementptr inbounds [5 x i32], ptr %a67, i64 0, i64 %93 %95 = load i32, ptr %94, align 4 store i32 %95, ptr %x73, align 4 - %96 = insertvalue %variant undef, ptr %i72, 0 - %97 = insertvalue %variant %96, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %98 = getelementptr inbounds [2 x %variant], ptr %varargslots75, i64 0, i64 0 - store %variant %97, ptr %98, align 16 - %99 = insertvalue %variant undef, ptr %x73, 0 - %100 = insertvalue %variant %99, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %101 = getelementptr inbounds [2 x %variant], ptr %varargslots75, i64 0, i64 1 - store %variant %100, ptr %101, align 16 + %96 = insertvalue %any undef, ptr %i72, 0 + %97 = insertvalue %any %96, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %98 = getelementptr inbounds [2 x %any], ptr %varargslots75, i64 0, i64 0 + store %any %97, ptr %98, align 16 + %99 = insertvalue %any undef, ptr %x73, 0 + %100 = insertvalue %any %99, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %101 = getelementptr inbounds [2 x %any], ptr %varargslots75, i64 0, i64 1 + store %any %100, ptr %101, align 16 %102 = call i64 @std.io.printfn(ptr %retparam74, ptr @.str.14, i64 8, ptr %varargslots75, i64 2) %103 = load i64, ptr %.anon68, align 8 %add76 = add i64 %103, 1 @@ -400,14 +400,14 @@ loop.body82: ; preds = %loop.cond80 %107 = getelementptr inbounds [8 x i32], ptr %a78, i64 0, i64 %106 %108 = load i32, ptr %107, align 4 store i32 %108, ptr %x84, align 4 - %109 = insertvalue %variant undef, ptr %i83, 0 - %110 = insertvalue %variant %109, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %111 = getelementptr inbounds [2 x %variant], ptr %varargslots86, i64 0, i64 0 - store %variant %110, ptr %111, align 16 - %112 = insertvalue %variant undef, ptr %x84, 0 - %113 = insertvalue %variant %112, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %114 = getelementptr inbounds [2 x %variant], ptr %varargslots86, i64 0, i64 1 - store %variant %113, ptr %114, align 16 + %109 = insertvalue %any undef, ptr %i83, 0 + %110 = insertvalue %any %109, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %111 = getelementptr inbounds [2 x %any], ptr %varargslots86, i64 0, i64 0 + store %any %110, ptr %111, align 16 + %112 = insertvalue %any undef, ptr %x84, 0 + %113 = insertvalue %any %112, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %114 = getelementptr inbounds [2 x %any], ptr %varargslots86, i64 0, i64 1 + store %any %113, ptr %114, align 16 %115 = call i64 @std.io.printfn(ptr %retparam85, ptr @.str.16, i64 8, ptr %varargslots86, i64 2) %116 = load i64, ptr %.anon79, align 8 %add87 = add i64 %116, 1 @@ -431,14 +431,14 @@ loop.body92: ; preds = %loop.cond90 %120 = getelementptr inbounds [7 x i32], ptr %b, i64 0, i64 %119 %121 = load i32, ptr %120, align 4 store i32 %121, ptr %x94, align 4 - %122 = insertvalue %variant undef, ptr %i93, 0 - %123 = insertvalue %variant %122, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %124 = getelementptr inbounds [2 x %variant], ptr %varargslots96, i64 0, i64 0 - store %variant %123, ptr %124, align 16 - %125 = insertvalue %variant undef, ptr %x94, 0 - %126 = insertvalue %variant %125, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %127 = getelementptr inbounds [2 x %variant], ptr %varargslots96, i64 0, i64 1 - store %variant %126, ptr %127, align 16 + %122 = insertvalue %any undef, ptr %i93, 0 + %123 = insertvalue %any %122, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %124 = getelementptr inbounds [2 x %any], ptr %varargslots96, i64 0, i64 0 + store %any %123, ptr %124, align 16 + %125 = insertvalue %any undef, ptr %x94, 0 + %126 = insertvalue %any %125, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %127 = getelementptr inbounds [2 x %any], ptr %varargslots96, i64 0, i64 1 + store %any %126, ptr %127, align 16 %128 = call i64 @std.io.printfn(ptr %retparam95, ptr @.str.18, i64 8, ptr %varargslots96, i64 2) %129 = load i64, ptr %.anon89, align 8 %add97 = add i64 %129, 1 @@ -462,14 +462,14 @@ loop.body102: ; preds = %loop.cond100 %133 = getelementptr inbounds [8 x i32], ptr %c, i64 0, i64 %132 %134 = load i32, ptr %133, align 4 store i32 %134, ptr %x104, align 4 - %135 = insertvalue %variant undef, ptr %i103, 0 - %136 = insertvalue %variant %135, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %137 = getelementptr inbounds [2 x %variant], ptr %varargslots106, i64 0, i64 0 - store %variant %136, ptr %137, align 16 - %138 = insertvalue %variant undef, ptr %x104, 0 - %139 = insertvalue %variant %138, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %140 = getelementptr inbounds [2 x %variant], ptr %varargslots106, i64 0, i64 1 - store %variant %139, ptr %140, align 16 + %135 = insertvalue %any undef, ptr %i103, 0 + %136 = insertvalue %any %135, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %137 = getelementptr inbounds [2 x %any], ptr %varargslots106, i64 0, i64 0 + store %any %136, ptr %137, align 16 + %138 = insertvalue %any undef, ptr %x104, 0 + %139 = insertvalue %any %138, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %140 = getelementptr inbounds [2 x %any], ptr %varargslots106, i64 0, i64 1 + store %any %139, ptr %140, align 16 %141 = call i64 @std.io.printfn(ptr %retparam105, ptr @.str.20, i64 9, ptr %varargslots106, i64 2) %142 = load i64, ptr %.anon99, align 8 %add107 = add i64 %142, 1 @@ -493,14 +493,14 @@ loop.body113: ; preds = %loop.cond111 %146 = getelementptr inbounds [6 x i32], ptr %a109, i64 0, i64 %145 %147 = load i32, ptr %146, align 4 store i32 %147, ptr %x115, align 4 - %148 = insertvalue %variant undef, ptr %i114, 0 - %149 = insertvalue %variant %148, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 - %150 = getelementptr inbounds [2 x %variant], ptr %varargslots117, i64 0, i64 0 - store %variant %149, ptr %150, align 16 - %151 = insertvalue %variant undef, ptr %x115, 0 - %152 = insertvalue %variant %151, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %153 = getelementptr inbounds [2 x %variant], ptr %varargslots117, i64 0, i64 1 - store %variant %152, ptr %153, align 16 + %148 = insertvalue %any undef, ptr %i114, 0 + %149 = insertvalue %any %148, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1 + %150 = getelementptr inbounds [2 x %any], ptr %varargslots117, i64 0, i64 0 + store %any %149, ptr %150, align 16 + %151 = insertvalue %any undef, ptr %x115, 0 + %152 = insertvalue %any %151, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %153 = getelementptr inbounds [2 x %any], ptr %varargslots117, i64 0, i64 1 + store %any %152, ptr %153, align 16 %154 = call i64 @std.io.printfn(ptr %retparam116, ptr @.str.22, i64 6, ptr %varargslots117, i64 2) %155 = load i64, ptr %.anon110, align 8 %add118 = add i64 %155, 1 diff --git a/test/test_suite/methods/access_private_method.c3 b/test/test_suite/methods/access_private_method.c3 index 41a967185..bd1f763a1 100644 --- a/test/test_suite/methods/access_private_method.c3 +++ b/test/test_suite/methods/access_private_method.c3 @@ -3,7 +3,7 @@ fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, struct TreeNode { int abc; NodeNotifyHandler notifyHandler; } struct TreeView { int abc; } -private fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) +fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) @private { node.notifyHandler = &TreeView.nodeNotifyHandler; // This is the line } \ No newline at end of file diff --git a/test/test_suite/methods/method_from_var.c3 b/test/test_suite/methods/method_from_var.c3 index fcfdacb6c..e0122129c 100644 --- a/test/test_suite/methods/method_from_var.c3 +++ b/test/test_suite/methods/method_from_var.c3 @@ -1,9 +1,9 @@ typedef NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data); -private fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) {} +fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) @private {} struct TreeNode { int abc; NodeNotifyHandler notifyHandler; } struct TreeView { int abc; } -private fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) +fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) @private { node.notifyHandler = &(this.nodeNotifyHandler); // #error: Taking the address of a method } \ No newline at end of file diff --git a/test/test_suite/pointers/subarray_variant_to_ptr.c3t b/test/test_suite/pointers/subarray_variant_to_ptr.c3t index dfc909ae7..4538809d9 100644 --- a/test/test_suite/pointers/subarray_variant_to_ptr.c3t +++ b/test/test_suite/pointers/subarray_variant_to_ptr.c3t @@ -3,7 +3,7 @@ module foo; extern fn void printf(char*, ...); -fn void test1(variant z) +fn void test1(any z) { int* w = z.ptr; printf("%d\n", *w); @@ -26,19 +26,19 @@ fn void main() /* #expect: foo.ll -%variant = type { ptr, i64 } +%any = type { ptr, i64 } %"int[]" = type { ptr, i64 } @"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 define void @foo.test1(i64 %0, ptr %1) #0 { entry: - %z = alloca %variant, align 8 + %z = alloca %any, align 8 %w = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptroffset = getelementptr inbounds ptr, ptr %z, i64 1 store ptr %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %2 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %3 = load ptr, ptr %2, align 8 store ptr %3, ptr %w, align 8 %4 = load ptr, ptr %w, align 8 @@ -68,13 +68,13 @@ entry: %x = alloca i32, align 4 %y = alloca i32, align 4 %w = alloca [2 x i32], align 4 - %taddr = alloca %variant, align 8 + %taddr = alloca %any, align 8 store i32 123, ptr %x, align 4 store i32 293483, ptr %y, align 4 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %w, ptr align 4 @.__const, i32 8, i1 false) - %0 = insertvalue %variant undef, ptr %x, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %1, ptr %taddr, align 8 + %0 = insertvalue %any undef, ptr %x, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %1, ptr %taddr, align 8 %2 = getelementptr inbounds { i64, ptr }, ptr %taddr, i32 0, i32 0 %lo = load i64, ptr %2, align 8 %3 = getelementptr inbounds { i64, ptr }, ptr %taddr, i32 0, i32 1 diff --git a/test/test_suite/safe/deref.c3t b/test/test_suite/safe/deref.c3t index 0fc9e33a0..127d3eb1d 100644 --- a/test/test_suite/safe/deref.c3t +++ b/test/test_suite/safe/deref.c3t @@ -18,12 +18,10 @@ entry: %0 = load ptr, ptr %x, align 8 %checknull = icmp eq ptr %0, null br i1 %checknull, label %panic, label %checkok - panic: ; preds = %entry %1 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %1(ptr @.panic_msg, i64 27, ptr @.file, i64 8, ptr @.func, i64 4, i32 6) + call void %1(ptr @.panic_msg, i64 42, ptr @.file, i64 8, ptr @.func, i64 4, i32 6) br label %checkok - checkok: ; preds = %panic, %entry %2 = load i32, ptr %0, align 4 store i32 %2, ptr %y, align 4 diff --git a/test/test_suite/slices/slice_to_slice_assign.c3t b/test/test_suite/slices/slice_to_slice_assign.c3t index e94219f32..e6a4fc046 100644 --- a/test/test_suite/slices/slice_to_slice_assign.c3t +++ b/test/test_suite/slices/slice_to_slice_assign.c3t @@ -26,10 +26,10 @@ entry: %y = alloca [6 x i32], align 16 %taddr = alloca %"int[]", align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %taddr1 = alloca %"int[]", align 8 %retparam2 = alloca i64, align 8 - %varargslots3 = alloca [2 x %variant], align 16 + %varargslots3 = alloca [2 x %any], align 16 %a = alloca %"int[][]", align 8 %literal = alloca [1 x %"int[]"], align 16 %literal4 = alloca [1 x i32], align 4 @@ -37,12 +37,12 @@ entry: %literal5 = alloca [1 x %"int[]"], align 16 %literal6 = alloca [1 x i32], align 4 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %taddr10 = alloca %"int[][]", align 8 %retparam11 = alloca i64, align 8 - %varargslots12 = alloca [1 x %variant], align 16 + %varargslots12 = alloca [1 x %any], align 16 %retparam14 = alloca i64, align 8 - %varargslots15 = alloca [1 x %variant], align 16 + %varargslots15 = alloca [1 x %any], align 16 call void @llvm.memcpy.p0.p0.i32(ptr align 16 %z, ptr align 16 @.__const, i32 28, i1 false) call void @llvm.memset.p0.i64(ptr align 16 %y, i8 0, i64 24, i1 false) %0 = getelementptr inbounds [7 x i32], ptr %z, i64 0, i64 3 @@ -58,14 +58,14 @@ entry: %9 = load i64, ptr %8, align 8 %10 = mul i64 %9, 4 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %6, ptr align 4 %7, i64 %10, i1 false) - %11 = insertvalue %variant undef, ptr %y, 0 - %12 = insertvalue %variant %11, i64 ptrtoint (ptr @"$ct.a6$int" to i64), 1 - %13 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %12, ptr %13, align 16 - %14 = insertvalue %variant undef, ptr %z, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.a7$int" to i64), 1 - %16 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %15, ptr %16, align 16 + %11 = insertvalue %any undef, ptr %y, 0 + %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.a6$int" to i64), 1 + %13 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %12, ptr %13, align 16 + %14 = insertvalue %any undef, ptr %z, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.a7$int" to i64), 1 + %16 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %15, ptr %16, align 16 %17 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 5, ptr %varargslots, i64 2) %18 = getelementptr inbounds [7 x i32], ptr %z, i64 0, i64 5 %19 = insertvalue %"int[]" undef, ptr %18, 0 @@ -80,14 +80,14 @@ entry: %27 = load i64, ptr %26, align 8 %28 = mul i64 %27, 4 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %24, ptr align 4 %25, i64 %28, i1 false) - %29 = insertvalue %variant undef, ptr %y, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.a6$int" to i64), 1 - %31 = getelementptr inbounds [2 x %variant], ptr %varargslots3, i64 0, i64 0 - store %variant %30, ptr %31, align 16 - %32 = insertvalue %variant undef, ptr %z, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.a7$int" to i64), 1 - %34 = getelementptr inbounds [2 x %variant], ptr %varargslots3, i64 0, i64 1 - store %variant %33, ptr %34, align 16 + %29 = insertvalue %any undef, ptr %y, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.a6$int" to i64), 1 + %31 = getelementptr inbounds [2 x %any], ptr %varargslots3, i64 0, i64 0 + store %any %30, ptr %31, align 16 + %32 = insertvalue %any undef, ptr %z, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.a7$int" to i64), 1 + %34 = getelementptr inbounds [2 x %any], ptr %varargslots3, i64 0, i64 1 + store %any %33, ptr %34, align 16 %35 = call i64 @std.io.printfn(ptr %retparam2, ptr @.str.1, i64 5, ptr %varargslots3, i64 2) %36 = getelementptr inbounds [1 x %"int[]"], ptr %literal, i64 0, i64 0 %37 = getelementptr inbounds [1 x i32], ptr %literal4, i64 0, i64 0 @@ -107,10 +107,10 @@ entry: %46 = insertvalue %"int[][]" undef, ptr %literal5, 0 %47 = insertvalue %"int[][]" %46, i64 1, 1 store %"int[][]" %47, ptr %b, align 8 - %48 = insertvalue %variant undef, ptr %a, 0 - %49 = insertvalue %variant %48, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %50 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %49, ptr %50, align 16 + %48 = insertvalue %any undef, ptr %a, 0 + %49 = insertvalue %any %48, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %50 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %49, ptr %50, align 16 %51 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.2, i64 2, ptr %varargslots8, i64 1) %52 = load %"int[][]", ptr %b, align 8 %53 = extractvalue %"int[][]" %52, 0 @@ -129,10 +129,10 @@ entry: %63 = load i64, ptr %62, align 8 %64 = mul i64 %63, 16 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %60, ptr align 8 %61, i64 %64, i1 false) - %65 = insertvalue %variant undef, ptr %a, 0 - %66 = insertvalue %variant %65, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %67 = getelementptr inbounds [1 x %variant], ptr %varargslots12, i64 0, i64 0 - store %variant %66, ptr %67, align 16 + %65 = insertvalue %any undef, ptr %a, 0 + %66 = insertvalue %any %65, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %67 = getelementptr inbounds [1 x %any], ptr %varargslots12, i64 0, i64 0 + store %any %66, ptr %67, align 16 %68 = call i64 @std.io.printfn(ptr %retparam11, ptr @.str.3, i64 2, ptr %varargslots12, i64 1) %69 = getelementptr inbounds [6 x i32], ptr %y, i64 0, i64 2 %70 = insertvalue %"int[]" undef, ptr %69, 0 @@ -141,10 +141,10 @@ entry: %73 = extractvalue %"int[][]" %72, 0 %ptroffset13 = getelementptr inbounds %"int[]", ptr %73, i64 0 store %"int[]" %71, ptr %ptroffset13, align 8 - %74 = insertvalue %variant undef, ptr %a, 0 - %75 = insertvalue %variant %74, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %76 = getelementptr inbounds [1 x %variant], ptr %varargslots15, i64 0, i64 0 - store %variant %75, ptr %76, align 16 + %74 = insertvalue %any undef, ptr %a, 0 + %75 = insertvalue %any %74, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %76 = getelementptr inbounds [1 x %any], ptr %varargslots15, i64 0, i64 0 + store %any %75, ptr %76, align 16 %77 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.4, i64 2, ptr %varargslots15, i64 1) ret void } diff --git a/test/test_suite/slices/slice_to_slice_vector_assign.c3t b/test/test_suite/slices/slice_to_slice_vector_assign.c3t index 36aa5412e..ed3fc6aa8 100644 --- a/test/test_suite/slices/slice_to_slice_vector_assign.c3t +++ b/test/test_suite/slices/slice_to_slice_vector_assign.c3t @@ -27,10 +27,10 @@ entry: %y = alloca <6 x i32>, align 32 %taddr = alloca %"int[]", align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %taddr1 = alloca %"int[]", align 8 %retparam2 = alloca i64, align 8 - %varargslots3 = alloca [2 x %variant], align 16 + %varargslots3 = alloca [2 x %any], align 16 %a = alloca %"int[][]", align 8 %literal = alloca [1 x %"int[]"], align 16 %literal4 = alloca [1 x i32], align 4 @@ -38,12 +38,12 @@ entry: %literal5 = alloca [1 x %"int[]"], align 16 %literal6 = alloca [1 x i32], align 4 %retparam7 = alloca i64, align 8 - %varargslots8 = alloca [1 x %variant], align 16 + %varargslots8 = alloca [1 x %any], align 16 %taddr10 = alloca %"int[][]", align 8 %retparam11 = alloca i64, align 8 - %varargslots12 = alloca [1 x %variant], align 16 + %varargslots12 = alloca [1 x %any], align 16 %retparam14 = alloca i64, align 8 - %varargslots15 = alloca [1 x %variant], align 16 + %varargslots15 = alloca [1 x %any], align 16 store <7 x i32> , ptr %z, align 32 store <6 x i32> zeroinitializer, ptr %y, align 32 %0 = getelementptr inbounds <7 x i32>, ptr %z, i64 0, i64 3 @@ -59,14 +59,14 @@ entry: %9 = load i64, ptr %8, align 8 %10 = mul i64 %9, 4 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %6, ptr align 4 %7, i64 %10, i1 false) - %11 = insertvalue %variant undef, ptr %y, 0 - %12 = insertvalue %variant %11, i64 ptrtoint (ptr @"$ct.v6$int" to i64), 1 - %13 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %12, ptr %13, align 16 - %14 = insertvalue %variant undef, ptr %z, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.v7$int" to i64), 1 - %16 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %15, ptr %16, align 16 + %11 = insertvalue %any undef, ptr %y, 0 + %12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.v6$int" to i64), 1 + %13 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %12, ptr %13, align 16 + %14 = insertvalue %any undef, ptr %z, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.v7$int" to i64), 1 + %16 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %15, ptr %16, align 16 %17 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 5, ptr %varargslots, i64 2) %18 = getelementptr inbounds <7 x i32>, ptr %z, i64 0, i64 5 %19 = insertvalue %"int[]" undef, ptr %18, 0 @@ -81,14 +81,14 @@ entry: %27 = load i64, ptr %26, align 8 %28 = mul i64 %27, 4 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %24, ptr align 4 %25, i64 %28, i1 false) - %29 = insertvalue %variant undef, ptr %y, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.v6$int" to i64), 1 - %31 = getelementptr inbounds [2 x %variant], ptr %varargslots3, i64 0, i64 0 - store %variant %30, ptr %31, align 16 - %32 = insertvalue %variant undef, ptr %z, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.v7$int" to i64), 1 - %34 = getelementptr inbounds [2 x %variant], ptr %varargslots3, i64 0, i64 1 - store %variant %33, ptr %34, align 16 + %29 = insertvalue %any undef, ptr %y, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.v6$int" to i64), 1 + %31 = getelementptr inbounds [2 x %any], ptr %varargslots3, i64 0, i64 0 + store %any %30, ptr %31, align 16 + %32 = insertvalue %any undef, ptr %z, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.v7$int" to i64), 1 + %34 = getelementptr inbounds [2 x %any], ptr %varargslots3, i64 0, i64 1 + store %any %33, ptr %34, align 16 %35 = call i64 @std.io.printfn(ptr %retparam2, ptr @.str.1, i64 5, ptr %varargslots3, i64 2) %36 = getelementptr inbounds [1 x %"int[]"], ptr %literal, i64 0, i64 0 %37 = getelementptr inbounds [1 x i32], ptr %literal4, i64 0, i64 0 @@ -108,10 +108,10 @@ entry: %46 = insertvalue %"int[][]" undef, ptr %literal5, 0 %47 = insertvalue %"int[][]" %46, i64 1, 1 store %"int[][]" %47, ptr %b, align 8 - %48 = insertvalue %variant undef, ptr %a, 0 - %49 = insertvalue %variant %48, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %50 = getelementptr inbounds [1 x %variant], ptr %varargslots8, i64 0, i64 0 - store %variant %49, ptr %50, align 16 + %48 = insertvalue %any undef, ptr %a, 0 + %49 = insertvalue %any %48, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %50 = getelementptr inbounds [1 x %any], ptr %varargslots8, i64 0, i64 0 + store %any %49, ptr %50, align 16 %51 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.2, i64 2, ptr %varargslots8, i64 1) %52 = load %"int[][]", ptr %b, align 8 %53 = extractvalue %"int[][]" %52, 0 @@ -130,10 +130,10 @@ entry: %63 = load i64, ptr %62, align 8 %64 = mul i64 %63, 16 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %60, ptr align 8 %61, i64 %64, i1 false) - %65 = insertvalue %variant undef, ptr %a, 0 - %66 = insertvalue %variant %65, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %67 = getelementptr inbounds [1 x %variant], ptr %varargslots12, i64 0, i64 0 - store %variant %66, ptr %67, align 16 + %65 = insertvalue %any undef, ptr %a, 0 + %66 = insertvalue %any %65, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %67 = getelementptr inbounds [1 x %any], ptr %varargslots12, i64 0, i64 0 + store %any %66, ptr %67, align 16 %68 = call i64 @std.io.printfn(ptr %retparam11, ptr @.str.3, i64 2, ptr %varargslots12, i64 1) %69 = getelementptr inbounds <6 x i32>, ptr %y, i64 0, i64 2 %70 = insertvalue %"int[]" undef, ptr %69, 0 @@ -142,10 +142,10 @@ entry: %73 = extractvalue %"int[][]" %72, 0 %ptroffset13 = getelementptr inbounds %"int[]", ptr %73, i64 0 store %"int[]" %71, ptr %ptroffset13, align 8 - %74 = insertvalue %variant undef, ptr %a, 0 - %75 = insertvalue %variant %74, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 - %76 = getelementptr inbounds [1 x %variant], ptr %varargslots15, i64 0, i64 0 - store %variant %75, ptr %76, align 16 + %74 = insertvalue %any undef, ptr %a, 0 + %75 = insertvalue %any %74, i64 ptrtoint (ptr @"$ct.sa$sa$int" to i64), 1 + %76 = getelementptr inbounds [1 x %any], ptr %varargslots15, i64 0, i64 0 + store %any %75, ptr %76, align 16 %77 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.4, i64 2, ptr %varargslots15, i64 1) ret void } diff --git a/test/test_suite/statements/foreach_more_implementations.c3t b/test/test_suite/statements/foreach_more_implementations.c3t index db03a546f..b222657b6 100644 --- a/test/test_suite/statements/foreach_more_implementations.c3t +++ b/test/test_suite/statements/foreach_more_implementations.c3t @@ -51,7 +51,7 @@ entry: %vector2 = alloca ptr, align 8 %element = alloca i64, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %.anon4 = alloca i64, align 8 %vector5 = alloca %Vector, align 8 %.anon6 = alloca i64, align 8 @@ -59,7 +59,7 @@ entry: %vector10 = alloca ptr, align 8 %element11 = alloca i64, align 8 %retparam13 = alloca i64, align 8 - %varargslots14 = alloca [1 x %variant], align 16 + %varargslots14 = alloca [1 x %any], align 16 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 8, i1 false) %0 = getelementptr inbounds %Vector, ptr %v, i32 0, i32 0 store i64 2, ptr %0, align 8 @@ -89,10 +89,10 @@ loop.body: ; preds = %loop.cond %ptroffset = getelementptr inbounds i32, ptr %9, i64 %10 store ptr %ptroffset, ptr %ref, align 8 %11 = load ptr, ptr %ref, align 8 - %12 = insertvalue %variant undef, ptr %11, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %14 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %13, ptr %14, align 16 + %12 = insertvalue %any undef, ptr %11, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %14 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %13, ptr %14, align 16 %15 = call i64 @std.io.printf(ptr %retparam, ptr @.str, i64 3, ptr %varargslots, i64 1) %16 = load ptr, ptr %ref, align 8 %17 = load i32, ptr %16, align 4 @@ -128,10 +128,10 @@ loop.body9: ; preds = %loop.cond7 %ptroffset12 = getelementptr inbounds i32, ptr %26, i64 %27 %28 = load i32, ptr %ptroffset12, align 4 store i32 %28, ptr %i, align 4 - %29 = insertvalue %variant undef, ptr %i, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %31 = getelementptr inbounds [1 x %variant], ptr %varargslots14, i64 0, i64 0 - store %variant %30, ptr %31, align 16 + %29 = insertvalue %any undef, ptr %i, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %31 = getelementptr inbounds [1 x %any], ptr %varargslots14, i64 0, i64 0 + store %any %30, ptr %31, align 16 %32 = call i64 @std.io.printf(ptr %retparam13, ptr @.str.1, i64 3, ptr %varargslots14, i64 1) %33 = load i64, ptr %.anon6, align 8 %add15 = add i64 %33, 1 diff --git a/test/test_suite/statements/various_switching.c3t b/test/test_suite/statements/various_switching.c3t index 3bac521d4..3122f2ebd 100644 --- a/test/test_suite/statements/various_switching.c3t +++ b/test/test_suite/statements/various_switching.c3t @@ -15,7 +15,7 @@ fault ByeErr fn void test() { - int! x = ByeErr.BAR!; + int! x = ByeErr.BAR?; typeid z = int.typeid; if (catch err = x) diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t index 2d91e1edf..c67f4cd93 100644 --- a/test/test_suite/stdlib/map.c3t +++ b/test/test_suite/stdlib/map.c3t @@ -11,7 +11,7 @@ typedef IntDoubleMap = HashMap; fn char[] Foo.to_string(Foo* foo, Allocator* allocator = mem::heap()) { - VarString s = string::new_with_capacity(128, allocator); + DString s = dstring::new_with_capacity(128, allocator); s.printf("{%s, %p}", foo.x, foo.bar); return s.str(); } @@ -56,15 +56,18 @@ fn void main() /* #expect: test.ll @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @.static_initialize.0, ptr null }] + define internal void @.static_initialize.0() { entry: %0 = load i64, ptr getelementptr inbounds (%"Entry*[]", ptr @std.io.tostring_functions, i32 0, i32 1), align 8 %not = icmp eq i64 %0, 0 br i1 %not, label %if.then, label %if.exit + if.then: ; preds = %entry %1 = load ptr, ptr @std.core.mem.thread_allocator, align 8 call void @"std.collections.map$typeid$p$std.io$ToStringFunction$.HashMap.init"(ptr @std.io.tostring_functions, i32 64, float 7.500000e-01, ptr %1) br label %if.exit + if.exit: ; preds = %if.then, %entry %2 = call i8 @"std.collections.map$typeid$p$std.io$ToStringFunction$.HashMap.set"(ptr @std.io.tostring_functions, i64 ptrtoint (ptr @"$ct.test.Foo" to i64), ptr @test.Foo.to_string) ret void @@ -74,81 +77,84 @@ define { ptr, i64 } @test.Foo.to_string(ptr %0, ptr %1) #0 { entry: %s = alloca ptr, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [2 x %variant], align 16 + %varargslots = alloca [2 x %any], align 16 %result = alloca %"char[]", align 8 - %2 = call ptr @std.core.string.new_with_capacity(i64 128, ptr %1) + %2 = call ptr @std.core.dstring.new_with_capacity(i64 128, ptr %1) store ptr %2, ptr %s, align 8 %3 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0 - %4 = insertvalue %variant undef, ptr %3, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %6 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %5, ptr %6, align 16 + %4 = insertvalue %any undef, ptr %3, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %6 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0 + store %any %5, ptr %6, align 16 %7 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1 - %8 = insertvalue %variant undef, ptr %7, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1 - %10 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %9, ptr %10, align 16 - %11 = call i64 @std.core.string.VarString.printf(ptr %retparam, ptr %s, ptr @.str.12, i64 8, ptr %varargslots, i64 2) + %8 = insertvalue %any undef, ptr %7, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1 + %10 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1 + store %any %9, ptr %10, align 16 + %11 = call i64 @std.core.dstring.DString.printf(ptr %retparam, ptr %s, ptr @.str.12, i64 8, ptr %varargslots, i64 2) %12 = load ptr, ptr %s, align 8 - %13 = call { ptr, i64 } @std.core.string.VarString.str(ptr %12) + %13 = call { ptr, i64 } @std.core.dstring.DString.str(ptr %12) store { ptr, i64 } %13, ptr %result, align 8 %14 = load { ptr, i64 }, ptr %result, align 8 ret { ptr, i64 } %14 } + ; Function Attrs: nounwind define void @test.main() #0 { entry: %map = alloca %HashMap.0, align 8 %retparam = alloca i64, align 8 - %varargslots = alloca [1 x %variant], align 16 + %varargslots = alloca [1 x %any], align 16 %literal = alloca %Foo, align 8 %retparam1 = alloca i64, align 8 - %varargslots2 = alloca [1 x %variant], align 16 + %varargslots2 = alloca [1 x %any], align 16 %literal3 = alloca %Foo, align 8 %retparam6 = alloca i64, align 8 - %varargslots7 = alloca [1 x %variant], align 16 + %varargslots7 = alloca [1 x %any], align 16 %retparam8 = alloca i64, align 8 - %varargslots9 = alloca [1 x %variant], align 16 + %varargslots9 = alloca [1 x %any], align 16 %retparam10 = alloca %Foo, align 8 %retparam13 = alloca i64, align 8 - %varargslots14 = alloca [1 x %variant], align 16 + %varargslots14 = alloca [1 x %any], align 16 %taddr = alloca i8, align 1 %retparam17 = alloca i64, align 8 - %varargslots18 = alloca [1 x %variant], align 16 + %varargslots18 = alloca [1 x %any], align 16 %taddr19 = alloca i8, align 1 %literal22 = alloca %Foo, align 8 %retparam25 = alloca i64, align 8 - %varargslots26 = alloca [1 x %variant], align 16 + %varargslots26 = alloca [1 x %any], align 16 %result = alloca %"Foo[]", align 8 %map2 = alloca %HashMap.2, align 8 %retparam29 = alloca i64, align 8 - %varargslots30 = alloca [1 x %variant], align 16 + %varargslots30 = alloca [1 x %any], align 16 %taddr31 = alloca i8, align 1 %retparam34 = alloca i64, align 8 - %varargslots35 = alloca [1 x %variant], align 16 + %varargslots35 = alloca [1 x %any], align 16 %taddr36 = alloca i8, align 1 %retparam39 = alloca i64, align 8 - %varargslots40 = alloca [1 x %variant], align 16 + %varargslots40 = alloca [1 x %any], align 16 %result41 = alloca %"int[]", align 8 %retparam44 = alloca i64, align 8 - %varargslots45 = alloca [1 x %variant], align 16 + %varargslots45 = alloca [1 x %any], align 16 %result46 = alloca %"double[]", align 8 %allocator = alloca ptr, align 8 %error_var = alloca i64, align 8 %retparam49 = alloca ptr, align 8 + %varargslots52 = alloca [1 x %any], align 16 + %indirectarg = alloca %"any[]", align 8 %mark = alloca i64, align 8 %map3 = alloca %HashMap.2, align 8 - %retparam52 = alloca i64, align 8 - %varargslots53 = alloca [1 x %variant], align 16 - %result54 = alloca %"int[]", align 8 + %retparam53 = alloca i64, align 8 + %varargslots54 = alloca [1 x %any], align 16 + %result55 = alloca %"int[]", align 8 call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false) %0 = load ptr, ptr @std.core.mem.thread_allocator, align 8 call void @"std.collections.map$int$test.Foo$.HashMap.init"(ptr %map, i32 16, float 7.500000e-01, ptr %0) %1 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2 - %2 = insertvalue %variant undef, ptr %1, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %4 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %3, ptr %4, align 16 + %2 = insertvalue %any undef, ptr %1, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %4 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0 + store %any %3, ptr %4, align 16 %5 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 12, ptr %varargslots, i64 1) %6 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0 store i32 1, ptr %6, align 8 @@ -160,10 +166,10 @@ entry: %hi = load ptr, ptr %9, align 8 %10 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo, ptr %hi) %11 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2 - %12 = insertvalue %variant undef, ptr %11, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %14 = getelementptr inbounds [1 x %variant], ptr %varargslots2, i64 0, i64 0 - store %variant %13, ptr %14, align 16 + %12 = insertvalue %any undef, ptr %11, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %14 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0 + store %any %13, ptr %14, align 16 %15 = call i64 @std.io.printfn(ptr %retparam1, ptr @.str.1, i64 12, ptr %varargslots2, i64 1) %16 = getelementptr inbounds %Foo, ptr %literal3, i32 0, i32 0 store i32 2, ptr %16, align 8 @@ -175,39 +181,41 @@ entry: %hi5 = load ptr, ptr %19, align 8 %20 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo4, ptr %hi5) %21 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2 - %22 = insertvalue %variant undef, ptr %21, 0 - %23 = insertvalue %variant %22, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %24 = getelementptr inbounds [1 x %variant], ptr %varargslots7, i64 0, i64 0 - store %variant %23, ptr %24, align 16 + %22 = insertvalue %any undef, ptr %21, 0 + %23 = insertvalue %any %22, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %24 = getelementptr inbounds [1 x %any], ptr %varargslots7, i64 0, i64 0 + store %any %23, ptr %24, align 16 %25 = call i64 @std.io.printfn(ptr %retparam6, ptr @.str.2, i64 12, ptr %varargslots7, i64 1) %26 = call i64 @"std.collections.map$int$test.Foo$.HashMap.get"(ptr %retparam10, ptr %map, i32 1) %not_err = icmp eq i64 %26, 0 %27 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) br i1 %27, label %after_check, label %after_check12 + after_check: ; preds = %entry %28 = getelementptr inbounds %Foo, ptr %retparam10, i32 0, i32 0 - %29 = insertvalue %variant undef, ptr %28, 0 - %30 = insertvalue %variant %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %31 = getelementptr inbounds [1 x %variant], ptr %varargslots9, i64 0, i64 0 - store %variant %30, ptr %31, align 16 + %29 = insertvalue %any undef, ptr %28, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %31 = getelementptr inbounds [1 x %any], ptr %varargslots9, i64 0, i64 0 + store %any %30, ptr %31, align 16 %32 = call i64 @std.io.printfn(ptr %retparam8, ptr @.str.3, i64 7, ptr %varargslots9, i64 1) %not_err11 = icmp eq i64 %32, 0 %33 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true) br i1 %33, label %after_check12, label %after_check12 + after_check12: ; preds = %entry, %after_check, %after_check %34 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1) store i8 %34, ptr %taddr, align 1 - %35 = insertvalue %variant undef, ptr %taddr, 0 - %36 = insertvalue %variant %35, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %37 = getelementptr inbounds [1 x %variant], ptr %varargslots14, i64 0, i64 0 - store %variant %36, ptr %37, align 16 + %35 = insertvalue %any undef, ptr %taddr, 0 + %36 = insertvalue %any %35, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %37 = getelementptr inbounds [1 x %any], ptr %varargslots14, i64 0, i64 0 + store %any %36, ptr %37, align 16 %38 = call i64 @std.io.printfn(ptr %retparam13, ptr @.str.4, i64 9, ptr %varargslots14, i64 1) %39 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 2) store i8 %39, ptr %taddr19, align 1 - %40 = insertvalue %variant undef, ptr %taddr19, 0 - %41 = insertvalue %variant %40, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %42 = getelementptr inbounds [1 x %variant], ptr %varargslots18, i64 0, i64 0 - store %variant %41, ptr %42, align 16 + %40 = insertvalue %any undef, ptr %taddr19, 0 + %41 = insertvalue %any %40, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %42 = getelementptr inbounds [1 x %any], ptr %varargslots18, i64 0, i64 0 + store %any %41, ptr %42, align 16 %43 = call i64 @std.io.printfn(ptr %retparam17, ptr @.str.5, i64 9, ptr %varargslots18, i64 1) %44 = getelementptr inbounds %Foo, ptr %literal22, i32 0, i32 0 store i32 4, ptr %44, align 8 @@ -221,10 +229,10 @@ after_check12: ; preds = %entry, %after_check %49 = load ptr, ptr @std.core.mem.thread_allocator, align 8 %50 = call { ptr, i64 } @"std.collections.map$int$test.Foo$.HashMap.value_list"(ptr %map, ptr %49) store { ptr, i64 } %50, ptr %result, align 8 - %51 = insertvalue %variant undef, ptr %result, 0 - %52 = insertvalue %variant %51, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1 - %53 = getelementptr inbounds [1 x %variant], ptr %varargslots26, i64 0, i64 0 - store %variant %52, ptr %53, align 16 + %51 = insertvalue %any undef, ptr %result, 0 + %52 = insertvalue %any %51, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1 + %53 = getelementptr inbounds [1 x %any], ptr %varargslots26, i64 0, i64 0 + store %any %52, ptr %53, align 16 %54 = call i64 @std.io.printfn(ptr %retparam25, ptr @.str.6, i64 10, ptr %varargslots26, i64 1) call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 40, i1 false) %55 = load ptr, ptr @std.core.mem.thread_allocator, align 8 @@ -232,80 +240,92 @@ after_check12: ; preds = %entry, %after_check %56 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00) %57 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00) store i8 %57, ptr %taddr31, align 1 - %58 = insertvalue %variant undef, ptr %taddr31, 0 - %59 = insertvalue %variant %58, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %60 = getelementptr inbounds [1 x %variant], ptr %varargslots30, i64 0, i64 0 - store %variant %59, ptr %60, align 16 + %58 = insertvalue %any undef, ptr %taddr31, 0 + %59 = insertvalue %any %58, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %60 = getelementptr inbounds [1 x %any], ptr %varargslots30, i64 0, i64 0 + store %any %59, ptr %60, align 16 %61 = call i64 @std.io.printfn(ptr %retparam29, ptr @.str.7, i64 12, ptr %varargslots30, i64 1) %62 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.200000e+00) store i8 %62, ptr %taddr36, align 1 - %63 = insertvalue %variant undef, ptr %taddr36, 0 - %64 = insertvalue %variant %63, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %65 = getelementptr inbounds [1 x %variant], ptr %varargslots35, i64 0, i64 0 - store %variant %64, ptr %65, align 16 + %63 = insertvalue %any undef, ptr %taddr36, 0 + %64 = insertvalue %any %63, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %65 = getelementptr inbounds [1 x %any], ptr %varargslots35, i64 0, i64 0 + store %any %64, ptr %65, align 16 %66 = call i64 @std.io.printfn(ptr %retparam34, ptr @.str.8, i64 12, ptr %varargslots35, i64 1) %67 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 100, double 3.400000e+00) %68 = load ptr, ptr @std.core.mem.thread_allocator, align 8 %69 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map2, ptr %68) store { ptr, i64 } %69, ptr %result41, align 8 - %70 = insertvalue %variant undef, ptr %result41, 0 - %71 = insertvalue %variant %70, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 - %72 = getelementptr inbounds [1 x %variant], ptr %varargslots40, i64 0, i64 0 - store %variant %71, ptr %72, align 16 + %70 = insertvalue %any undef, ptr %result41, 0 + %71 = insertvalue %any %70, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 + %72 = getelementptr inbounds [1 x %any], ptr %varargslots40, i64 0, i64 0 + store %any %71, ptr %72, align 16 %73 = call i64 @std.io.printfn(ptr %retparam39, ptr @.str.9, i64 2, ptr %varargslots40, i64 1) %74 = load ptr, ptr @std.core.mem.thread_allocator, align 8 %75 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.value_list"(ptr %map2, ptr %74) store { ptr, i64 } %75, ptr %result46, align 8 - %76 = insertvalue %variant undef, ptr %result46, 0 - %77 = insertvalue %variant %76, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1 - %78 = getelementptr inbounds [1 x %variant], ptr %varargslots45, i64 0, i64 0 - store %variant %77, ptr %78, align 16 + %76 = insertvalue %any undef, ptr %result46, 0 + %77 = insertvalue %any %76, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1 + %78 = getelementptr inbounds [1 x %any], ptr %varargslots45, i64 0, i64 0 + store %any %77, ptr %78, align 16 %79 = call i64 @std.io.printfn(ptr %retparam44, ptr @.str.10, i64 2, ptr %varargslots45, i64 1) %80 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 %not = icmp eq ptr %80, null br i1 %not, label %if.then, label %if.exit + if.then: ; preds = %after_check12 %81 = load ptr, ptr @std.core.mem.thread_allocator, align 8 %82 = call i64 @std.core.mem.allocator.new_temp(ptr %retparam49, i64 262144, ptr %81) %not_err50 = icmp eq i64 %82, 0 %83 = call i1 @llvm.expect.i1(i1 %not_err50, i1 true) br i1 %83, label %after_check51, label %assign_optional + assign_optional: ; preds = %if.then store i64 %82, ptr %error_var, align 8 br label %panic_block + after_check51: ; preds = %if.then %84 = load ptr, ptr %retparam49, align 8 br label %noerr_block + panic_block: ; preds = %assign_optional - %85 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %85(ptr @.panic_msg, i64 27, ptr @.file, i64 6, ptr @.func + %85 = insertvalue %any undef, ptr %error_var, 0 + %86 = insertvalue %any %85, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %87 = getelementptr inbounds [1 x %any], ptr %varargslots52, i64 0, i64 0 + store %any %86, ptr %87, align 16 + %88 = insertvalue %"any[]" undef, ptr %varargslots52, 0 + %89 = insertvalue %"any[]" %88, i64 1, 1 + store %"any[]" %89, ptr %indirectarg, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 4, i32 399, ptr byval(%"any[]") align 8 %indirectarg) unreachable + noerr_block: ; preds = %after_check51 store ptr %84, ptr @std.core.mem.thread_temp_allocator, align 8 br label %if.exit + if.exit: ; preds = %noerr_block, %after_check12 - %86 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 - store ptr %86, ptr %allocator, align 8 - %87 = load ptr, ptr %allocator, align 8 - %88 = getelementptr inbounds %TempAllocator, ptr %87, i32 0, i32 3 - %89 = load i64, ptr %88, align 8 - store i64 %89, ptr %mark, align 8 + %90 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 + store ptr %90, ptr %allocator, align 8 + %91 = load ptr, ptr %allocator, align 8 + %92 = getelementptr inbounds %TempAllocator, ptr %91, i32 0, i32 3 + %93 = load i64, ptr %92, align 8 + store i64 %93, ptr %mark, align 8 call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 40, i1 false) - %90 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - call void @"std.collections.map$int$double$.HashMap.init"(ptr %map3, i32 16, float 7.500000e-01, ptr %90) - %91 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00) - %92 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00) - %93 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %94 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, ptr %93) - store { ptr, i64 } %94, ptr %result54, align 8 - %95 = insertvalue %variant undef, ptr %result54, 0 - %96 = insertvalue %variant %95, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 - %97 = getelementptr inbounds [1 x %variant], ptr %varargslots53, i64 0, i64 0 - store %variant %96, ptr %97, align 16 - %98 = call i64 @std.io.printfn(ptr %retparam52, ptr @.str.11, i64 2, ptr %varargslots53, i64 1) - %99 = load ptr, ptr %allocator, align 8 - %100 = getelementptr inbounds %TempAllocator, ptr %99, i32 0, i32 0 - %101 = load i64, ptr %mark, align 8 - call void @std.core.mem.allocator.Allocator.reset(ptr %100, i64 %101) + %94 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + call void @"std.collections.map$int$double$.HashMap.init"(ptr %map3, i32 16, float 7.500000e-01, ptr %94) + %95 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00) + %96 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00) + %97 = load ptr, ptr @std.core.mem.thread_allocator, align 8 + %98 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, ptr %97) + store { ptr, i64 } %98, ptr %result55, align 8 + %99 = insertvalue %any undef, ptr %result55, 0 + %100 = insertvalue %any %99, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 + %101 = getelementptr inbounds [1 x %any], ptr %varargslots54, i64 0, i64 0 + store %any %100, ptr %101, align 16 + %102 = call i64 @std.io.printfn(ptr %retparam53, ptr @.str.11, i64 2, ptr %varargslots54, i64 1) + %103 = load ptr, ptr %allocator, align 8 + %104 = getelementptr inbounds %TempAllocator, ptr %103, i32 0, i32 0 + %105 = load i64, ptr %mark, align 8 + call void @std.core.mem.allocator.Allocator.reset(ptr %104, i64 %105) ret void } diff --git a/test/test_suite/switch/failable_switch.c3 b/test/test_suite/switch/failable_switch.c3 index 4bc2d2197..edac2e92b 100644 --- a/test/test_suite/switch/failable_switch.c3 +++ b/test/test_suite/switch/failable_switch.c3 @@ -8,7 +8,7 @@ fn void test() int x = 0; switch (x) { - case MyError.FOO!: // #error: cannot be converted + case MyError.FOO? : // #error: cannot be converted x = x + 1; } } \ No newline at end of file diff --git a/test/test_suite/variant/variant_assign.c3t b/test/test_suite/variant/variant_assign.c3t index bb5406f83..c5a61e84b 100644 --- a/test/test_suite/variant/variant_assign.c3t +++ b/test/test_suite/variant/variant_assign.c3t @@ -3,7 +3,7 @@ module foo; extern fn void printf(char*, ...); -fn void test(variant z) +fn void test(any z) { switch (z) { @@ -15,7 +15,7 @@ fn void test(variant z) printf("Unknown type.\n"); } } -fn void test2(variant y) +fn void test2(any y) { switch (z = y) { @@ -29,7 +29,7 @@ fn void test2(variant y) } } -fn void test3(variant y) +fn void test3(any y) { switch (z = *y) { @@ -64,14 +64,14 @@ fn int main() define void @foo.test(i64 %0, ptr %1) #0 { entry: - %z = alloca %variant, align 8 + %z = alloca %any, align 8 %switch = alloca i64, align 8 %z1 = alloca ptr, align 8 %z4 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptroffset = getelementptr inbounds ptr, ptr %z, i64 1 store ptr %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %variant, ptr %z, i32 0, i32 1 + %2 = getelementptr inbounds %any, ptr %z, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %switch, align 8 br label %switch.entry @@ -82,7 +82,7 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %5 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %6 = load ptr, ptr %5, align 8 store ptr %6, ptr %z1, align 8 %7 = load ptr, ptr %z1, align 8 @@ -95,7 +95,7 @@ next_if: ; preds = %switch.entry br i1 %eq2, label %switch.case3, label %next_if5 switch.case3: ; preds = %next_if - %9 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %9 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %10 = load ptr, ptr %9, align 8 store ptr %10, ptr %z4, align 8 %11 = load ptr, ptr %z4, align 8 @@ -116,8 +116,8 @@ switch.exit: ; preds = %switch.default, %sw define void @foo.test2(i64 %0, ptr %1) #0 { entry: - %y = alloca %variant, align 8 - %.anon = alloca %variant, align 8 + %y = alloca %any, align 8 + %.anon = alloca %any, align 8 %switch = alloca i64, align 8 %z = alloca ptr, align 8 %taddr = alloca i32, align 4 @@ -126,7 +126,7 @@ entry: %ptroffset = getelementptr inbounds ptr, ptr %y, i64 1 store ptr %1, ptr %ptroffset, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %.anon, ptr align 8 %y, i32 16, i1 false) - %2 = getelementptr inbounds %variant, ptr %y, i32 0, i32 1 + %2 = getelementptr inbounds %any, ptr %y, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %switch, align 8 br label %switch.entry @@ -137,13 +137,13 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %variant, ptr %.anon, i32 0, i32 0 + %5 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 %6 = load ptr, ptr %5, align 8 store ptr %6, ptr %z, align 8 store i32 12, ptr %taddr, align 4 - %7 = insertvalue %variant undef, ptr %taddr, 0 - %8 = insertvalue %variant %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %8, ptr %y, align 8 + %7 = insertvalue %any undef, ptr %taddr, 0 + %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %8, ptr %y, align 8 %9 = load ptr, ptr %z, align 8 %10 = load i32, ptr %9, align 4 call void (ptr, ...) @printf(ptr @.str.3, i32 %10) @@ -154,7 +154,7 @@ next_if: ; preds = %switch.entry br i1 %eq1, label %switch.case2, label %next_if4 switch.case2: ; preds = %next_if - %11 = getelementptr inbounds %variant, ptr %.anon, i32 0, i32 0 + %11 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 %12 = load ptr, ptr %11, align 8 store ptr %12, ptr %z3, align 8 %13 = load ptr, ptr %z3, align 8 @@ -175,8 +175,8 @@ switch.exit: ; preds = %switch.default, %sw define void @foo.test3(i64 %0, ptr %1) #0 { entry: - %y = alloca %variant, align 8 - %.anon = alloca %variant, align 8 + %y = alloca %any, align 8 + %.anon = alloca %any, align 8 %switch = alloca i64, align 8 %z = alloca i32, align 4 %z3 = alloca double, align 8 @@ -184,7 +184,7 @@ entry: %ptroffset = getelementptr inbounds ptr, ptr %y, i64 1 store ptr %1, ptr %ptroffset, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %.anon, ptr align 8 %y, i32 16, i1 false) - %2 = getelementptr inbounds %variant, ptr %y, i32 0, i32 1 + %2 = getelementptr inbounds %any, ptr %y, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %switch, align 8 br label %switch.entry @@ -195,7 +195,7 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %variant, ptr %.anon, i32 0, i32 0 + %5 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 %6 = load ptr, ptr %5, align 8 %7 = load i32, ptr %6, align 4 store i32 %7, ptr %z, align 4 @@ -208,7 +208,7 @@ next_if: ; preds = %switch.entry br i1 %eq1, label %switch.case2, label %next_if4 switch.case2: ; preds = %next_if - %9 = getelementptr inbounds %variant, ptr %.anon, i32 0, i32 0 + %9 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 %10 = load ptr, ptr %9, align 8 %11 = load double, ptr %10, align 8 store double %11, ptr %z3, align 8 @@ -230,99 +230,99 @@ switch.exit: ; preds = %switch.default, %sw define i32 @main() #0 { entry: %taddr = alloca double, align 8 - %taddr1 = alloca %variant, align 8 + %taddr1 = alloca %any, align 8 %taddr2 = alloca i32, align 4 - %taddr3 = alloca %variant, align 8 + %taddr3 = alloca %any, align 8 %taddr6 = alloca i8, align 1 - %taddr7 = alloca %variant, align 8 + %taddr7 = alloca %any, align 8 %taddr10 = alloca double, align 8 - %taddr11 = alloca %variant, align 8 + %taddr11 = alloca %any, align 8 %taddr14 = alloca i32, align 4 - %taddr15 = alloca %variant, align 8 + %taddr15 = alloca %any, align 8 %taddr18 = alloca i8, align 1 - %taddr19 = alloca %variant, align 8 + %taddr19 = alloca %any, align 8 %taddr22 = alloca double, align 8 - %taddr23 = alloca %variant, align 8 + %taddr23 = alloca %any, align 8 %taddr26 = alloca i32, align 4 - %taddr27 = alloca %variant, align 8 + %taddr27 = alloca %any, align 8 %taddr30 = alloca i8, align 1 - %taddr31 = alloca %variant, align 8 + %taddr31 = alloca %any, align 8 store double 1.230000e+02, ptr %taddr, align 8 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %1, ptr %taddr1, align 8 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %1, ptr %taddr1, align 8 %2 = getelementptr inbounds { i64, ptr }, ptr %taddr1, i32 0, i32 0 %lo = load i64, ptr %2, align 8 %3 = getelementptr inbounds { i64, ptr }, ptr %taddr1, i32 0, i32 1 %hi = load ptr, ptr %3, align 8 call void @foo.test(i64 %lo, ptr %hi) store i32 1, ptr %taddr2, align 4 - %4 = insertvalue %variant undef, ptr %taddr2, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %5, ptr %taddr3, align 8 + %4 = insertvalue %any undef, ptr %taddr2, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %5, ptr %taddr3, align 8 %6 = getelementptr inbounds { i64, ptr }, ptr %taddr3, i32 0, i32 0 %lo4 = load i64, ptr %6, align 8 %7 = getelementptr inbounds { i64, ptr }, ptr %taddr3, i32 0, i32 1 %hi5 = load ptr, ptr %7, align 8 call void @foo.test(i64 %lo4, ptr %hi5) store i8 1, ptr %taddr6, align 1 - %8 = insertvalue %variant undef, ptr %taddr6, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %variant %9, ptr %taddr7, align 8 + %8 = insertvalue %any undef, ptr %taddr6, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + store %any %9, ptr %taddr7, align 8 %10 = getelementptr inbounds { i64, ptr }, ptr %taddr7, i32 0, i32 0 %lo8 = load i64, ptr %10, align 8 %11 = getelementptr inbounds { i64, ptr }, ptr %taddr7, i32 0, i32 1 %hi9 = load ptr, ptr %11, align 8 call void @foo.test(i64 %lo8, ptr %hi9) store double 1.235000e+02, ptr %taddr10, align 8 - %12 = insertvalue %variant undef, ptr %taddr10, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %13, ptr %taddr11, align 8 + %12 = insertvalue %any undef, ptr %taddr10, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %13, ptr %taddr11, align 8 %14 = getelementptr inbounds { i64, ptr }, ptr %taddr11, i32 0, i32 0 %lo12 = load i64, ptr %14, align 8 %15 = getelementptr inbounds { i64, ptr }, ptr %taddr11, i32 0, i32 1 %hi13 = load ptr, ptr %15, align 8 call void @foo.test2(i64 %lo12, ptr %hi13) store i32 1, ptr %taddr14, align 4 - %16 = insertvalue %variant undef, ptr %taddr14, 0 - %17 = insertvalue %variant %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %17, ptr %taddr15, align 8 + %16 = insertvalue %any undef, ptr %taddr14, 0 + %17 = insertvalue %any %16, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %17, ptr %taddr15, align 8 %18 = getelementptr inbounds { i64, ptr }, ptr %taddr15, i32 0, i32 0 %lo16 = load i64, ptr %18, align 8 %19 = getelementptr inbounds { i64, ptr }, ptr %taddr15, i32 0, i32 1 %hi17 = load ptr, ptr %19, align 8 call void @foo.test2(i64 %lo16, ptr %hi17) store i8 1, ptr %taddr18, align 1 - %20 = insertvalue %variant undef, ptr %taddr18, 0 - %21 = insertvalue %variant %20, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %variant %21, ptr %taddr19, align 8 + %20 = insertvalue %any undef, ptr %taddr18, 0 + %21 = insertvalue %any %20, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + store %any %21, ptr %taddr19, align 8 %22 = getelementptr inbounds { i64, ptr }, ptr %taddr19, i32 0, i32 0 %lo20 = load i64, ptr %22, align 8 %23 = getelementptr inbounds { i64, ptr }, ptr %taddr19, i32 0, i32 1 %hi21 = load ptr, ptr %23, align 8 call void @foo.test2(i64 %lo20, ptr %hi21) store double 1.240000e+02, ptr %taddr22, align 8 - %24 = insertvalue %variant undef, ptr %taddr22, 0 - %25 = insertvalue %variant %24, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %25, ptr %taddr23, align 8 + %24 = insertvalue %any undef, ptr %taddr22, 0 + %25 = insertvalue %any %24, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %25, ptr %taddr23, align 8 %26 = getelementptr inbounds { i64, ptr }, ptr %taddr23, i32 0, i32 0 %lo24 = load i64, ptr %26, align 8 %27 = getelementptr inbounds { i64, ptr }, ptr %taddr23, i32 0, i32 1 %hi25 = load ptr, ptr %27, align 8 call void @foo.test3(i64 %lo24, ptr %hi25) store i32 2, ptr %taddr26, align 4 - %28 = insertvalue %variant undef, ptr %taddr26, 0 - %29 = insertvalue %variant %28, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %29, ptr %taddr27, align 8 + %28 = insertvalue %any undef, ptr %taddr26, 0 + %29 = insertvalue %any %28, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %29, ptr %taddr27, align 8 %30 = getelementptr inbounds { i64, ptr }, ptr %taddr27, i32 0, i32 0 %lo28 = load i64, ptr %30, align 8 %31 = getelementptr inbounds { i64, ptr }, ptr %taddr27, i32 0, i32 1 %hi29 = load ptr, ptr %31, align 8 call void @foo.test3(i64 %lo28, ptr %hi29) store i8 1, ptr %taddr30, align 1 - %32 = insertvalue %variant undef, ptr %taddr30, 0 - %33 = insertvalue %variant %32, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %variant %33, ptr %taddr31, align 8 + %32 = insertvalue %any undef, ptr %taddr30, 0 + %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + store %any %33, ptr %taddr31, align 8 %34 = getelementptr inbounds { i64, ptr }, ptr %taddr31, i32 0, i32 0 %lo32 = load i64, ptr %34, align 8 %35 = getelementptr inbounds { i64, ptr }, ptr %taddr31, i32 0, i32 1 diff --git a/test/test_suite/variant/variant_switch.c3t b/test/test_suite/variant/variant_switch.c3t index 8c0f86c78..9181c3de3 100644 --- a/test/test_suite/variant/variant_switch.c3t +++ b/test/test_suite/variant/variant_switch.c3t @@ -3,7 +3,7 @@ module foo; extern fn void printf(char*, ...); -fn void test(variant z) +fn void test(any z) { switch (z) { @@ -36,14 +36,14 @@ fn int main() define void @foo.test(i64 %0, ptr %1) #0 { entry: - %z = alloca %variant, align 8 + %z = alloca %any, align 8 %switch = alloca i64, align 8 %z1 = alloca ptr, align 8 %z4 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptroffset = getelementptr inbounds ptr, ptr %z, i64 1 store ptr %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %variant, ptr %z, i32 0, i32 1 + %2 = getelementptr inbounds %any, ptr %z, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %switch, align 8 br label %switch.entry @@ -54,7 +54,7 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %5 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %6 = load ptr, ptr %5, align 8 store ptr %6, ptr %z1, align 8 %7 = load ptr, ptr %z1, align 8 @@ -69,7 +69,7 @@ next_if: ; preds = %switch.entry br i1 %eq2, label %switch.case3, label %next_if5 switch.case3: ; preds = %next_if - %10 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %10 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %11 = load ptr, ptr %10, align 8 store ptr %11, ptr %z4, align 8 %12 = load ptr, ptr %z4, align 8 @@ -85,13 +85,13 @@ switch.default: ; preds = %next_if5 br label %switch.exit switch.exit: ; preds = %switch.default, %switch.case3, %switch.case - %14 = getelementptr inbounds %variant, ptr %z, i32 0, i32 1 + %14 = getelementptr inbounds %any, ptr %z, i32 0, i32 1 %15 = load i64, ptr %14, align 8 %eq6 = icmp eq i64 %15, ptrtoint (ptr @"$ct.int" to i64) br i1 %eq6, label %if.then, label %if.exit if.then: ; preds = %switch.exit - %16 = getelementptr inbounds %variant, ptr %z, i32 0, i32 0 + %16 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %17 = load ptr, ptr %16, align 8 %18 = load i32, ptr %17, align 4 call void (ptr, ...) @printf(ptr @.str.3, i32 %18) @@ -105,33 +105,33 @@ if.exit: ; preds = %if.then, %switch.ex define i32 @main() #0 { entry: %taddr = alloca double, align 8 - %taddr1 = alloca %variant, align 8 + %taddr1 = alloca %any, align 8 %taddr2 = alloca i32, align 4 - %taddr3 = alloca %variant, align 8 + %taddr3 = alloca %any, align 8 %taddr6 = alloca i8, align 1 - %taddr7 = alloca %variant, align 8 + %taddr7 = alloca %any, align 8 store double 1.230000e+02, ptr %taddr, align 8 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %1, ptr %taddr1, align 8 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %1, ptr %taddr1, align 8 %2 = getelementptr inbounds { i64, ptr }, ptr %taddr1, i32 0, i32 0 %lo = load i64, ptr %2, align 8 %3 = getelementptr inbounds { i64, ptr }, ptr %taddr1, i32 0, i32 1 %hi = load ptr, ptr %3, align 8 call void @foo.test(i64 %lo, ptr %hi) store i32 1, ptr %taddr2, align 4 - %4 = insertvalue %variant undef, ptr %taddr2, 0 - %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %5, ptr %taddr3, align 8 + %4 = insertvalue %any undef, ptr %taddr2, 0 + %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %5, ptr %taddr3, align 8 %6 = getelementptr inbounds { i64, ptr }, ptr %taddr3, i32 0, i32 0 %lo4 = load i64, ptr %6, align 8 %7 = getelementptr inbounds { i64, ptr }, ptr %taddr3, i32 0, i32 1 %hi5 = load ptr, ptr %7, align 8 call void @foo.test(i64 %lo4, ptr %hi5) store i8 1, ptr %taddr6, align 1 - %8 = insertvalue %variant undef, ptr %taddr6, 0 - %9 = insertvalue %variant %8, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %variant %9, ptr %taddr7, align 8 + %8 = insertvalue %any undef, ptr %taddr6, 0 + %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + store %any %9, ptr %taddr7, align 8 %10 = getelementptr inbounds { i64, ptr }, ptr %taddr7, i32 0, i32 0 %lo8 = load i64, ptr %10, align 8 %11 = getelementptr inbounds { i64, ptr }, ptr %taddr7, i32 0, i32 1 diff --git a/test/test_suite/variant/variant_test.c3t b/test/test_suite/variant/variant_test.c3t index dcd9a8da2..c2561d9ab 100644 --- a/test/test_suite/variant/variant_test.c3t +++ b/test/test_suite/variant/variant_test.c3t @@ -2,7 +2,7 @@ module foo; extern fn void printf(char*, ...); -fn void test(variant x) +fn void test(any x) { switch (x.type) { @@ -10,7 +10,7 @@ fn void test(variant x) printf("Was int\n"); case double: printf("Was double\n"); - case variant: + case any: printf("Was variant\n"); case int*: printf("Was int*\n"); @@ -19,7 +19,7 @@ fn void test(variant x) } } -fn void test_all(variant... y) +fn void test_all(any... y) { foreach (element : y) { @@ -29,9 +29,9 @@ fn void test_all(variant... y) fn void main() { - variant x = &&1; + any x = &&1; int z; - variant y = &z; + any y = &z; typeid g = y.type; typeid h = x.type; if (y.type == int.typeid) @@ -63,23 +63,23 @@ fn void main() /* #expect: foo.ll -%variant = type { ptr, i64 } -%"variant[]" = type { ptr, i64 } +%any = type { ptr, i64 } +%"any[]" = type { ptr, i64 } @"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.variant" = linkonce constant %.introspect { i8 7, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.any" = linkonce constant %.introspect { i8 7, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.p$int" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.bool" = linkonce constant %.introspect { i8 1, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 define void @foo.test(i64 %0, ptr %1) #0 { entry: - %x = alloca %variant, align 8 + %x = alloca %any, align 8 %switch = alloca i64, align 8 store i64 %0, ptr %x, align 8 %ptroffset = getelementptr inbounds ptr, ptr %x, i64 1 store ptr %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %variant, ptr %x, i32 0, i32 1 + %2 = getelementptr inbounds %any, ptr %x, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %switch, align 8 br label %switch.entry @@ -102,7 +102,7 @@ switch.case2: ; preds = %next_if br label %switch.exit next_if3: ; preds = %next_if - %eq4 = icmp eq i64 ptrtoint (ptr @"$ct.variant" to i64), %4 + %eq4 = icmp eq i64 ptrtoint (ptr @"$ct.any" to i64), %4 br i1 %eq4, label %switch.case5, label %next_if6 switch.case5: ; preds = %next_if3 @@ -131,14 +131,14 @@ switch.exit: ; preds = %switch.default, %sw ; Function Attrs: nounwind define void @foo.test_all(ptr %0, i64 %1) #0 { entry: - %y = alloca %"variant[]", align 8 + %y = alloca %"any[]", align 8 %.anon = alloca i64, align 8 %.anon1 = alloca i64, align 8 - %element = alloca %variant, align 8 + %element = alloca %any, align 8 store ptr %0, ptr %y, align 8 %ptroffset = getelementptr inbounds i64, ptr %y, i64 1 store i64 %1, ptr %ptroffset, align 8 - %2 = getelementptr inbounds %"variant[]", ptr %y, i32 0, i32 1 + %2 = getelementptr inbounds %"any[]", ptr %y, i32 0, i32 1 %3 = load i64, ptr %2, align 8 store i64 %3, ptr %.anon, align 8 store i64 0, ptr %.anon1, align 8 @@ -151,10 +151,10 @@ loop.cond: ; preds = %loop.body, %entry br i1 %lt, label %loop.body, label %loop.exit loop.body: ; preds = %loop.cond - %6 = getelementptr inbounds %"variant[]", ptr %y, i32 0, i32 0 + %6 = getelementptr inbounds %"any[]", ptr %y, i32 0, i32 0 %7 = load ptr, ptr %6, align 8 %8 = load i64, ptr %.anon1, align 8 - %ptroffset2 = getelementptr inbounds %variant, ptr %7, i64 %8 + %ptroffset2 = getelementptr inbounds %any, ptr %7, i64 %8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %element, ptr align 8 %ptroffset2, i32 16, i1 false) %9 = getelementptr inbounds { i64, ptr }, ptr %element, i32 0, i32 0 %lo = load i64, ptr %9, align 8 @@ -173,37 +173,37 @@ loop.exit: ; preds = %loop.cond ; Function Attrs: nounwind define void @foo.main() #0 { entry: - %x = alloca %variant, align 8 + %x = alloca %any, align 8 %taddr = alloca i32, align 4 %z = alloca i32, align 4 - %y = alloca %variant, align 8 + %y = alloca %any, align 8 %g = alloca i64, align 8 %h = alloca i64, align 8 %taddr4 = alloca double, align 8 %taddr11 = alloca double, align 8 - %taddr12 = alloca %variant, align 8 + %taddr12 = alloca %any, align 8 %taddr15 = alloca i32, align 4 - %taddr16 = alloca %variant, align 8 + %taddr16 = alloca %any, align 8 %taddr19 = alloca i8, align 1 - %taddr20 = alloca %variant, align 8 + %taddr20 = alloca %any, align 8 %df = alloca ptr, align 8 - %varargslots = alloca [5 x %variant], align 16 + %varargslots = alloca [5 x %any], align 16 %taddr23 = alloca double, align 8 store i32 1, ptr %taddr, align 4 - %0 = insertvalue %variant undef, ptr %taddr, 0 - %1 = insertvalue %variant %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %1, ptr %x, align 8 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %1, ptr %x, align 8 store i32 0, ptr %z, align 4 - %2 = insertvalue %variant undef, ptr %z, 0 - %3 = insertvalue %variant %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %3, ptr %y, align 8 - %4 = getelementptr inbounds %variant, ptr %y, i32 0, i32 1 + %2 = insertvalue %any undef, ptr %z, 0 + %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %3, ptr %y, align 8 + %4 = getelementptr inbounds %any, ptr %y, i32 0, i32 1 %5 = load i64, ptr %4, align 8 store i64 %5, ptr %g, align 8 - %6 = getelementptr inbounds %variant, ptr %x, i32 0, i32 1 + %6 = getelementptr inbounds %any, ptr %x, i32 0, i32 1 %7 = load i64, ptr %6, align 8 store i64 %7, ptr %h, align 8 - %8 = getelementptr inbounds %variant, ptr %y, i32 0, i32 1 + %8 = getelementptr inbounds %any, ptr %y, i32 0, i32 1 %9 = load i64, ptr %8, align 8 %eq = icmp eq i64 %9, ptrtoint (ptr @"$ct.int" to i64) br i1 %eq, label %if.then, label %if.exit @@ -213,7 +213,7 @@ if.then: ; preds = %entry br label %if.exit if.exit: ; preds = %if.then, %entry - %10 = getelementptr inbounds %variant, ptr %x, i32 0, i32 1 + %10 = getelementptr inbounds %any, ptr %x, i32 0, i32 1 %11 = load i64, ptr %10, align 8 %eq1 = icmp eq i64 %11, ptrtoint (ptr @"$ct.int" to i64) br i1 %eq1, label %if.then2, label %if.exit3 @@ -224,13 +224,13 @@ if.then2: ; preds = %if.exit if.exit3: ; preds = %if.then2, %if.exit store double 1.000000e+00, ptr %taddr4, align 8 - %12 = insertvalue %variant undef, ptr %taddr4, 0 - %13 = insertvalue %variant %12, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %13, ptr %y, align 8 - %14 = insertvalue %variant undef, ptr %x, 0 - %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"$ct.variant" to i64), 1 - store %variant %15, ptr %x, align 8 - %16 = getelementptr inbounds %variant, ptr %y, i32 0, i32 1 + %12 = insertvalue %any undef, ptr %taddr4, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %13, ptr %y, align 8 + %14 = insertvalue %any undef, ptr %x, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.any" to i64), 1 + store %any %15, ptr %x, align 8 + %16 = getelementptr inbounds %any, ptr %y, i32 0, i32 1 %17 = load i64, ptr %16, align 8 %eq5 = icmp eq i64 %17, ptrtoint (ptr @"$ct.int" to i64) br i1 %eq5, label %if.then6, label %if.exit7 @@ -240,7 +240,7 @@ if.then6: ; preds = %if.exit3 br label %if.exit7 if.exit7: ; preds = %if.then6, %if.exit3 - %18 = getelementptr inbounds %variant, ptr %x, i32 0, i32 1 + %18 = getelementptr inbounds %any, ptr %x, i32 0, i32 1 %19 = load i64, ptr %18, align 8 %eq8 = icmp eq i64 %19, ptrtoint (ptr @"$ct.int" to i64) br i1 %eq8, label %if.then9, label %if.exit10 @@ -256,27 +256,27 @@ if.exit10: ; preds = %if.then9, %if.exit7 %hi = load ptr, ptr %21, align 8 call void @foo.test(i64 %lo, ptr %hi) store double 1.000000e+00, ptr %taddr11, align 8 - %22 = insertvalue %variant undef, ptr %taddr11, 0 - %23 = insertvalue %variant %22, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %variant %23, ptr %taddr12, align 8 + %22 = insertvalue %any undef, ptr %taddr11, 0 + %23 = insertvalue %any %22, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + store %any %23, ptr %taddr12, align 8 %24 = getelementptr inbounds { i64, ptr }, ptr %taddr12, i32 0, i32 0 %lo13 = load i64, ptr %24, align 8 %25 = getelementptr inbounds { i64, ptr }, ptr %taddr12, i32 0, i32 1 %hi14 = load ptr, ptr %25, align 8 call void @foo.test(i64 %lo13, ptr %hi14) store i32 1, ptr %taddr15, align 4 - %26 = insertvalue %variant undef, ptr %taddr15, 0 - %27 = insertvalue %variant %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %variant %27, ptr %taddr16, align 8 + %26 = insertvalue %any undef, ptr %taddr15, 0 + %27 = insertvalue %any %26, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %27, ptr %taddr16, align 8 %28 = getelementptr inbounds { i64, ptr }, ptr %taddr16, i32 0, i32 0 %lo17 = load i64, ptr %28, align 8 %29 = getelementptr inbounds { i64, ptr }, ptr %taddr16, i32 0, i32 1 %hi18 = load ptr, ptr %29, align 8 call void @foo.test(i64 %lo17, ptr %hi18) store i8 1, ptr %taddr19, align 1 - %30 = insertvalue %variant undef, ptr %taddr19, 0 - %31 = insertvalue %variant %30, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %variant %31, ptr %taddr20, align 8 + %30 = insertvalue %any undef, ptr %taddr19, 0 + %31 = insertvalue %any %30, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + store %any %31, ptr %taddr20, align 8 %32 = getelementptr inbounds { i64, ptr }, ptr %taddr20, i32 0, i32 0 %lo21 = load i64, ptr %32, align 8 %33 = getelementptr inbounds { i64, ptr }, ptr %taddr20, i32 0, i32 1 @@ -284,23 +284,23 @@ if.exit10: ; preds = %if.then9, %if.exit7 call void @foo.test(i64 %lo21, ptr %hi22) call void (ptr, ...) @printf(ptr @.str.9) store ptr null, ptr %df, align 8 - %34 = getelementptr inbounds [5 x %variant], ptr %varargslots, i64 0, i64 0 + %34 = getelementptr inbounds [5 x %any], ptr %varargslots, i64 0, i64 0 call void @llvm.memcpy.p0.p0.i32(ptr align 16 %34, ptr align 8 %x, i32 16, i1 false) - %35 = getelementptr inbounds [5 x %variant], ptr %varargslots, i64 0, i64 1 + %35 = getelementptr inbounds [5 x %any], ptr %varargslots, i64 0, i64 1 call void @llvm.memcpy.p0.p0.i32(ptr align 16 %35, ptr align 8 %x, i32 16, i1 false) store double 1.000000e+00, ptr %taddr23, align 8 - %36 = insertvalue %variant undef, ptr %taddr23, 0 - %37 = insertvalue %variant %36, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - %38 = getelementptr inbounds [5 x %variant], ptr %varargslots, i64 0, i64 2 - store %variant %37, ptr %38, align 16 - %39 = insertvalue %variant undef, ptr %x, 0 - %40 = insertvalue %variant %39, i64 ptrtoint (ptr @"$ct.variant" to i64), 1 - %41 = getelementptr inbounds [5 x %variant], ptr %varargslots, i64 0, i64 3 - store %variant %40, ptr %41, align 16 - %42 = insertvalue %variant undef, ptr %df, 0 - %43 = insertvalue %variant %42, i64 ptrtoint (ptr @"$ct.p$int" to i64), 1 - %44 = getelementptr inbounds [5 x %variant], ptr %varargslots, i64 0, i64 4 - store %variant %43, ptr %44, align 16 + %36 = insertvalue %any undef, ptr %taddr23, 0 + %37 = insertvalue %any %36, i64 ptrtoint (ptr @"$ct.double" to i64), 1 + %38 = getelementptr inbounds [5 x %any], ptr %varargslots, i64 0, i64 2 + store %any %37, ptr %38, align 16 + %39 = insertvalue %any undef, ptr %x, 0 + %40 = insertvalue %any %39, i64 ptrtoint (ptr @"$ct.any" to i64), 1 + %41 = getelementptr inbounds [5 x %any], ptr %varargslots, i64 0, i64 3 + store %any %40, ptr %41, align 16 + %42 = insertvalue %any undef, ptr %df, 0 + %43 = insertvalue %any %42, i64 ptrtoint (ptr @"$ct.p$int" to i64), 1 + %44 = getelementptr inbounds [5 x %any], ptr %varargslots, i64 0, i64 4 + store %any %43, ptr %44, align 16 call void @foo.test_all(ptr %varargslots, i64 5) ret void } diff --git a/test/unit/regression/swizzle.c3 b/test/unit/regression/swizzle.c3 new file mode 100644 index 000000000..66f4a0b86 --- /dev/null +++ b/test/unit/regression/swizzle.c3 @@ -0,0 +1,9 @@ +module swizzletest @test; + +fn void test_swizzle() +{ + int[<4>] a = { 1, 2, 3, 4 }; + int[<4>] b = { 100, 1000, 10000, 100000 }; + assert($$swizzle(a, 0, 1, 1, 3) == int[<4>] { 1, 2, 2, 4 }); + assert($$swizzle2(a, b, 0, 1, 4, 6, 2) == int[<5>] { 1, 2, 100, 10000, 3 }); +} \ No newline at end of file diff --git a/test/unit/stdlib/collections/linkedlist.c3 b/test/unit/stdlib/collections/linkedlist.c3 index 1acc45f0d..742ec93a6 100644 --- a/test/unit/stdlib/collections/linkedlist.c3 +++ b/test/unit/stdlib/collections/linkedlist.c3 @@ -8,12 +8,12 @@ fn void! test_push() @test IntList list; list.push(23); assert(list.len() == 1); - assert(list.first()? == 23); - assert(list.last()? == 23); + assert(list.first()! == 23); + assert(list.last()! == 23); list.push(55); assert(list.len() == 2); - assert(list.last()? == 23); - assert(list.first()? == 55); + assert(list.last()! == 23); + assert(list.first()! == 55); } fn void! test_push_last() @test @@ -21,12 +21,12 @@ fn void! test_push_last() @test IntList list; list.push_last(23); assert(list.len() == 1); - assert(list.first()? == 23); - assert(list.last()? == 23); + assert(list.first()! == 23); + assert(list.last()! == 23); list.push_last(55); assert(list.len() == 2); - assert(list.last()? == 55); - assert(list.first()? == 23); + assert(list.last()! == 55); + assert(list.first()! == 23); } fn void! test_get() @test @@ -91,24 +91,24 @@ fn void! test_remove_value() @test list.push(55); list.push(-3); assert(list.remove_value(23)); - assert(list.pop()? == -3); - assert(list.pop()? == 55); + assert(list.pop()! == -3); + assert(list.pop()! == 55); assert(!list.len()); list.push(23); list.push(55); list.push(-3); assert(list.remove_value(55)); - assert(list.pop()? == -3); - assert(list.pop()? == 23); + assert(list.pop()! == -3); + assert(list.pop()! == 23); assert(!list.len()); list.push(23); list.push(55); list.push(-3); assert(list.remove_value(-3)); - assert(list.pop()? == 55); - assert(list.pop()? == 23); + assert(list.pop()! == 55); + assert(list.pop()! == 23); assert(!list.len()); } @@ -119,24 +119,24 @@ fn void! test_remove_last_value() @test list.push(55); list.push(-3); assert(list.remove_last_value(23)); - assert(list.pop()? == -3); - assert(list.pop()? == 55); + assert(list.pop()! == -3); + assert(list.pop()! == 55); assert(!list.len()); list.push(23); list.push(55); list.push(-3); assert(list.remove_last_value(55)); - assert(list.pop()? == -3); - assert(list.pop()? == 23); + assert(list.pop()! == -3); + assert(list.pop()! == 23); assert(!list.len()); list.push(23); list.push(55); list.push(-3); assert(list.remove_last_value(-3)); - assert(list.pop()? == 55); - assert(list.pop()? == 23); + assert(list.pop()! == 55); + assert(list.pop()! == 23); assert(!list.len()); } @@ -147,18 +147,18 @@ fn void! test_pop() @test list.push(55); list.push(-3); assert(list.len() == 3); - assert(list.last()? == 23); - assert(list.first()? == -3); - assert(list.pop()? == -3); + assert(list.last()! == 23); + assert(list.first()! == -3); + assert(list.pop()! == -3); assert(list.len() == 2); - assert(list.last()? == 23); - assert(list.first()? == 55); - assert(list.pop()? == 55); - assert(list.last()? == 23); - assert(list.first()? == 23); - assert(list.pop()? == 23); + assert(list.last()! == 23); + assert(list.first()! == 55); + assert(list.pop()! == 55); + assert(list.last()! == 23); + assert(list.first()! == 23); + assert(list.pop()! == 23); assert(list.len() == 0); - assert(catch? list.pop()); + assert(@catchof(list.pop())); assert(list.len() == 0); list.push(55); assert(list.len() == 1); @@ -171,18 +171,18 @@ fn void! test_remove_first() @test list.push(55); list.push(-3); assert(list.len() == 3); - assert(list.last()? == 23); - assert(list.first()? == -3); - assert(try? list.remove_first()); + assert(list.last()! == 23); + assert(list.first()! == -3); + assert(@ok(list.remove_first())); assert(list.len() == 2); - assert(list.last()? == 23); - assert(list.first()? == 55); - assert(try? list.remove_first()); - assert(list.last()? == 23); - assert(list.first()? == 23); - assert(try? list.remove_first()); + assert(list.last()! == 23); + assert(list.first()! == 55); + assert(@ok(list.remove_first())); + assert(list.last()! == 23); + assert(list.first()! == 23); + assert(@ok(list.remove_first())); assert(list.len() == 0); - assert(catch? list.pop()); + assert(@catchof(list.pop())); assert(list.len() == 0); list.push(55); assert(list.len() == 1); @@ -195,18 +195,18 @@ fn void! test_remove_last() @test list.push(55); list.push(-3); assert(list.len() == 3); - assert(list.last()? == 23); - assert(list.first()? == -3); - assert(try? list.remove_last()); + assert(list.last()! == 23); + assert(list.first()! == -3); + assert(@ok(list.remove_last())); assert(list.len() == 2); - assert(list.first()? == -3); - assert(list.last()? == 55); - assert(try? list.remove_last()); - assert(list.first()? == -3); - assert(list.last()? == -3); - assert(try? list.remove_last()); + assert(list.first()! == -3); + assert(list.last()! == 55); + assert(@ok(list.remove_last())); + assert(list.first()! == -3); + assert(list.last()! == -3); + assert(@ok(list.remove_last())); assert(list.len() == 0); - assert(catch? list.remove_last()); + assert(@catchof(list.remove_last())); assert(list.len() == 0); list.push(55); assert(list.len() == 1); diff --git a/test/unit/stdlib/collections/object.c3 b/test/unit/stdlib/collections/object.c3 index cb86c63c4..84a8d3126 100644 --- a/test/unit/stdlib/collections/object.c3 +++ b/test/unit/stdlib/collections/object.c3 @@ -6,17 +6,17 @@ fn void test_general() Object* root = object::new_obj(); root.set("foo", 1); root.set("bar", "baz"); - assert(root.get_int("foo")? == 1); - assert(root.get_string("bar")? == "baz"); + assert(root.get_int("foo")! == 1); + assert(root.get_string("bar")! == "baz"); Object* goo = root.set("goo", object::new_obj()); goo.append("hello"); goo.append(132); - assert(root.get("goo").get_int_at(1)? == 132); - assert(root.get("goo").get_string_at(0)? == "hello"); + assert(root.get("goo").get_int_at(1)! == 132); + assert(root.get("goo").get_string_at(0)! == "hello"); Object* abc = root.get_or_create_obj("abc80"); abc.set("cool", 1.3); - assert(root.get("abc80").get_int("cool")? == 1); - assert(root.get("abc80").get_float("cool")? == 1.3); + assert(root.get("abc80").get_int("cool")! == 1); + assert(root.get("abc80").get_float("cool")! == 1.3); assert((root.get_int("yyy") ?? -1) == -1); root.set("yyy", true); assert(root.get_bool("yyy") ?? false); diff --git a/test/unit/stdlib/conv_tests.c3 b/test/unit/stdlib/conv_tests.c3 index 7fe1ae4e6..27c666d55 100644 --- a/test/unit/stdlib/conv_tests.c3 +++ b/test/unit/stdlib/conv_tests.c3 @@ -4,7 +4,7 @@ import std::io; fn void! comparison_helper_32_to_8(Char32 c32, String expected_output) { char[8] out; - usz len = conv::char32_to_utf8(c32, &out, 4)?; + usz len = conv::char32_to_utf8(c32, &out, 4)!; assert(len == expected_output.len, "Len should be 1"); foreach (i, c : expected_output) { @@ -15,7 +15,7 @@ fn void! comparison_helper_32_to_8(Char32 c32, String expected_output) fn void! comparison_helper_8_to_32(String in, Char32 c32) { usz len = in.len; - Char32 res = conv::utf8_to_char32(in.ptr, &len)?; + Char32 res = conv::utf8_to_char32(in.ptr, &len)!; assert(len == in.len, "All len should be used."); assert(res == c32, "Expected character match."); } @@ -23,45 +23,45 @@ fn void! comparison_helper_8_to_32(String in, Char32 c32) fn void assert_utf8_is_error(String in) { usz len = in.len; - assert(catch? conv::utf8_to_char32(in.ptr, &len), "Expected error"); + assert(@catchof(conv::utf8_to_char32(in.ptr, &len)), "Expected error"); } fn void! test_char32_ut8_boundary() @test { // First sequence per len - comparison_helper_32_to_8(0x00000000, { 0 })?; - comparison_helper_32_to_8(0x00000080, { 0xc2, 0x80 })?; - comparison_helper_32_to_8(0x00000800, { 0xe0, 0xa0, 0x80 })?; - comparison_helper_32_to_8(0x00010000, { 0xf0, 0x90, 0x80, 0x80 })?; - assert(catch? comparison_helper_32_to_8(0x10ffff + 1, { 0 }), "Expected error"); + comparison_helper_32_to_8(0x00000000, { 0 })!; + comparison_helper_32_to_8(0x00000080, { 0xc2, 0x80 })!; + comparison_helper_32_to_8(0x00000800, { 0xe0, 0xa0, 0x80 })!; + comparison_helper_32_to_8(0x00010000, { 0xf0, 0x90, 0x80, 0x80 })!; + assert(@catchof(comparison_helper_32_to_8(0x10ffff + 1, { 0 })), "Expected error"); // Last seq per len - comparison_helper_32_to_8(0x0000007f, { 0x7f })?; - comparison_helper_32_to_8(0x000007ff, { 0xdf, 0xbf })?; - comparison_helper_32_to_8(0x0000ffff, { 0xef, 0xbf, 0xbf })?; - comparison_helper_32_to_8(0x0010ffff, { 0xf4, 0x8f, 0xbf, 0xbf })?; + comparison_helper_32_to_8(0x0000007f, { 0x7f })!; + comparison_helper_32_to_8(0x000007ff, { 0xdf, 0xbf })!; + comparison_helper_32_to_8(0x0000ffff, { 0xef, 0xbf, 0xbf })!; + comparison_helper_32_to_8(0x0010ffff, { 0xf4, 0x8f, 0xbf, 0xbf })!; // Other boundaries - comparison_helper_32_to_8(0x0000d7ff, { 0xed, 0x9f, 0xbf})?; - comparison_helper_32_to_8(0x0000e000, { 0xee, 0x80, 0x80 })?; - comparison_helper_32_to_8(0x0000fffd, { 0xef, 0xbf, 0xbd })?; + comparison_helper_32_to_8(0x0000d7ff, { 0xed, 0x9f, 0xbf})!; + comparison_helper_32_to_8(0x0000e000, { 0xee, 0x80, 0x80 })!; + comparison_helper_32_to_8(0x0000fffd, { 0xef, 0xbf, 0xbd })!; } fn void! test_utf8_to_char32_boundary() @test { // First sequence per len - comparison_helper_8_to_32("\0", 0x0 )?; - comparison_helper_8_to_32({ 0xc2, 0x80 }, 0x80)?; - comparison_helper_8_to_32({ 0xe0, 0xa0, 0x80 }, 0x800, )?; - comparison_helper_8_to_32({ 0xf0, 0x90, 0x80, 0x80 }, 0x10000)?; + comparison_helper_8_to_32("\0", 0x0 )!; + comparison_helper_8_to_32({ 0xc2, 0x80 }, 0x80)!; + comparison_helper_8_to_32({ 0xe0, 0xa0, 0x80 }, 0x800 )!; + comparison_helper_8_to_32({ 0xf0, 0x90, 0x80, 0x80 }, 0x10000)!; // Last seq per len - comparison_helper_8_to_32({ 0x7f }, 0x7f)?; - comparison_helper_8_to_32({ 0xdf, 0xbf }, 0x7ff, )?; - comparison_helper_8_to_32({ 0xef, 0xbf, 0xbf }, 0xffff)?; - comparison_helper_8_to_32({ 0xf4, 0x8f, 0xbf, 0xbf }, 0x10ffff)?; + comparison_helper_8_to_32({ 0x7f }, 0x7f)!; + comparison_helper_8_to_32({ 0xdf, 0xbf }, 0x7ff )!; + comparison_helper_8_to_32({ 0xef, 0xbf, 0xbf }, 0xffff)!; + comparison_helper_8_to_32({ 0xf4, 0x8f, 0xbf, 0xbf }, 0x10ffff)!; // Other boundaries - comparison_helper_8_to_32({ 0xed, 0x9f, 0xbf }, 0xd7ff)?; - comparison_helper_8_to_32({ 0xee, 0x80, 0x80 }, 0xe000)?; - comparison_helper_8_to_32({ 0xef, 0xbf, 0xbd }, 0xfffd)?; + comparison_helper_8_to_32({ 0xed, 0x9f, 0xbf }, 0xd7ff)!; + comparison_helper_8_to_32({ 0xee, 0x80, 0x80 }, 0xe000)!; + comparison_helper_8_to_32({ 0xef, 0xbf, 0xbd }, 0xfffd)!; assert_utf8_is_error({ 0x80 }); assert_utf8_is_error({ 0xbf }); diff --git a/test/unit/stdlib/core/array.c3 b/test/unit/stdlib/core/array.c3 new file mode 100644 index 000000000..a5a1edd02 --- /dev/null +++ b/test/unit/stdlib/core/array.c3 @@ -0,0 +1,31 @@ +module arraytests @test; + +fn void! find() +{ + int[3] a = { 1, 2, 3 }; + assert(array::index_of(a, 2)! == 1); + assert(array::index_of(a, 1)! == 0); + assert(array::index_of(a, 3)! == 2); + assert(@catchof(array::index_of(a, 4)) == SearchResult.MISSING); +} + +fn void! find_subarray() +{ + int[] a = { 1, 2, 3 }; + assert(array::index_of(a, 2)! == 1); + assert(array::index_of(a, 1)! == 0); + assert(array::index_of(a, 3)! == 2); + assert(@catchof(array::index_of(a, 4)) == SearchResult.MISSING); +} + +fn void! concat() +{ + int[3] a = { 1, 2, 3 }; + array::concat(a, a); + array::concat(a[..], a[..]); + array::concat(a[:0], a[:0]); + array::concat(int[2] { 1, 2 }, a[:0]); + array::concat(a[:0], int[2] { 1, 2 }); + int[] c = array::concat(a[1..2], a); + assert (c == int[]{ 2, 3, 1, 2, 3 }); +} diff --git a/test/unit/stdlib/core/builtintests.c3 b/test/unit/stdlib/core/builtintests.c3 new file mode 100644 index 000000000..7b0f886c8 --- /dev/null +++ b/test/unit/stdlib/core/builtintests.c3 @@ -0,0 +1,79 @@ +module std::core::builtins @test; + +fn void! test_anycast() +{ + int a; + any b = &a; + assert(anycast(b, int)! == &a); + assert(@catchof(anycast(b, double)) == CastResult.TYPE_MISMATCH); +} + +fn void! test_bitcast() +{ + int a = 123; + float z = bitcast(a, float); + assert(bitcast(z, int) == a); +} + +enum Tester +{ + ABC, + DEF, +} + +fn void! test_enum_by_name() +{ + assert(enum_by_name(Tester, "ABC")! == Tester.ABC); + assert(enum_by_name(Tester, "DEF")! == Tester.DEF); + assert(@catchof(enum_by_name(Tester, "GHI")) == SearchResult.MISSING); +} + +fn void test_likely() +{ + int a = 2; + int b = 43; + if (@likely(a > b, 0.5)) a++; + if (@likely(a < b)) b++; +} + +fn void test_unlikely() +{ + int a = 2; + int b = 43; + if (@unlikely(a > b, 0.5)) a++; + if (@unlikely(a < b)) b++; +} + +fn void test_expect() +{ + int a = 2; + int b = 43; + int c = @expect(a, 2, 0.5); + int d = @expect(b, 2u8); +} + + +int abc; + +fn void test_prefetch() +{ + prefetch(&abc); +} + +fn void test_hash() +{ + char{}.hash(); + ichar{}.hash(); + short{}.hash(); + ushort{}.hash(); + int{}.hash(); + uint{}.hash(); + long{}.hash(); + ulong{}.hash(); + int128{}.hash(); + uint128{}.hash(); + String x = "abc"; + char[] y = "abc"; + assert(x.hash() == y.hash()); + assert(int.typeid.hash()); +} \ No newline at end of file diff --git a/test/unit/stdlib/core/string.c3 b/test/unit/stdlib/core/string.c3 index c66d56436..4b6d3f799 100644 --- a/test/unit/stdlib/core/string.c3 +++ b/test/unit/stdlib/core/string.c3 @@ -78,17 +78,17 @@ fn void test_split() fn void! test_index_of() { String test = "hello world hello"; - assert(test.index_of("o")? == 4); - assert(test.index_of("ll")? == 2); - assert(catch? test.index_of("wi")); + assert(test.index_of("o")! == 4); + assert(test.index_of("ll")! == 2); + assert(@catchof(test.index_of("wi"))); } fn void! test_rindex_of() { String test = "hello world hello"; - assert(test.rindex_of("o")? == 16); - assert(test.rindex_of("ll")? == 14); - assert(test.rindex_of("he")? == 12); - assert(test.rindex_of("world")? == 6); - assert(catch? test.rindex_of("wi")); + assert(test.rindex_of("o")! == 16); + assert(test.rindex_of("ll")! == 14); + assert(test.rindex_of("he")! == 12); + assert(test.rindex_of("world")! == 6); + assert(@catchof(test.rindex_of("wi"))); } \ No newline at end of file diff --git a/test/unit/stdlib/encoding/json.c3 b/test/unit/stdlib/encoding/json.c3 index 14c2c93a7..cfbf3a832 100644 --- a/test/unit/stdlib/encoding/json.c3 +++ b/test/unit/stdlib/encoding/json.c3 @@ -9,8 +9,8 @@ fn void! simple_test() reader.init(`{ "b": 123, "c": [ { "d": 66 }, null, "hello", false ] }`); JsonParser json; json.init(reader.as_stream()); - Object* o = json.parse_any()?; - assert(o.get_int("b")? == 123); - assert(o.get("c").get_at(0).get_int("d")? == 66); - assert(o.get("c").get_at(1).is_null()?); + Object* o = json.parse_any()!; + assert(o.get_int("b")! == 123); + assert(o.get("c").get_at(0).get_int("d")! == 66); + assert(o.get("c").get_at(1).is_null()!); } diff --git a/test/unit/stdlib/io/bytestream.c3 b/test/unit/stdlib/io/bytestream.c3 index 4f6c13440..8f7c5089a 100644 --- a/test/unit/stdlib/io/bytestream.c3 +++ b/test/unit/stdlib/io/bytestream.c3 @@ -5,21 +5,21 @@ fn void! bytestream() ByteReader r; r.init("abc"); Stream s = r.as_stream(); - assert(s.len()? == 3); + assert(s.len()! == 3); char[5] buffer; - assert('a' == s.read_byte()?); - s.pushback_byte()?; - usz len = s.read(&buffer)?; + assert('a' == s.read_byte()!); + s.pushback_byte()!; + usz len = s.read(&buffer)!; assert((String)buffer[:len] == "abc"); ByteWriter w; w.init(); Stream ws = w.as_stream(); - ws.write("helloworld")?; + ws.write("helloworld")!; assert(w.as_str() == "helloworld"); - s.seek(0, SET)?; - ws.read_from(&s)?; - s.seek(1, SET)?; - s.write_to(&ws)?; + s.seek(0, SET)!; + ws.read_from(&s)!; + s.seek(1, SET)!; + s.write_to(&ws)!; assert(w.as_str() == "helloworldabcbc"); } @@ -33,5 +33,5 @@ fn void! bytewriter_buffer() s.write_byte(0)!!; String o = ((ZString)&z).as_str(); assert(o == "hello"); - assert(catch? s.write("xxxx")); + assert(@catchof(s.write("xxxx"))); } diff --git a/test/unit/stdlib/io/dstringstream.c3 b/test/unit/stdlib/io/dstringstream.c3 index d6640c6f8..b26bbd8c6 100644 --- a/test/unit/stdlib/io/dstringstream.c3 +++ b/test/unit/stdlib/io/dstringstream.c3 @@ -11,7 +11,7 @@ fn void! test_writing() ByteReader r; String test_str = "2134"; r.init(test_str); - s.read_from(&&r.as_stream())?; + s.read_from(&&r.as_stream())!; String o = foo.str(); assert(o == "hello-what?2134"); } diff --git a/test/unit/stdlib/io/path.c3 b/test/unit/stdlib/io/path.c3 index 2424ad432..58607b256 100644 --- a/test/unit/stdlib/io/path.c3 +++ b/test/unit/stdlib/io/path.c3 @@ -3,289 +3,289 @@ module std::io::path @test; fn void! test_parent() { - Path p = path::new("")?; - assert(catch? p.parent()); - p = path::new("/", .path_env = PathEnv.POSIX)?; - assert(catch? p.parent()); - p = path::new("/a/b/c", .path_env = PathEnv.POSIX)?; - assert(p.parent().as_str()? == "/a/b"); - p = path::new("/a/b/c", .path_env = PathEnv.WIN32)?; - assert(p.parent().as_str()? == `\a\b`); + Path p = path::new("")!; + assert(@catchof(p.parent())); + p = path::new("/", .path_env = PathEnv.POSIX)!; + assert(@catchof(p.parent())); + p = path::new("/a/b/c", .path_env = PathEnv.POSIX)!; + assert(p.parent().as_str()! == "/a/b"); + p = path::new("/a/b/c", .path_env = PathEnv.WIN32)!; + assert(p.parent().as_str()! == `\a\b`); } fn void! test_path_normalized() { - assert(path::new("", .path_env = PathEnv.WIN32).as_str()? == ""); - assert(catch? path::new("1:\\a\\b\\c.txt", .path_env = PathEnv.WIN32)); - assert(catch? path::new(":", .path_env = PathEnv.WIN32)); - assert(catch? path::new("1:", .path_env = PathEnv.WIN32)); - assert(catch? path::new("1:a", .path_env = PathEnv.WIN32)); -// assert(catch? path::new(`\\\a\b\c.txt`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`\\server\a\b\..\..\..\c`, .path_env = PathEnv.WIN32)); + assert(path::new("", .path_env = PathEnv.WIN32).as_str()! == ""); + assert(@catchof(path::new("1:\\a\\b\\c.txt", .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(":", .path_env = PathEnv.WIN32))); + assert(@catchof(path::new("1:", .path_env = PathEnv.WIN32))); + assert(@catchof(path::new("1:a", .path_env = PathEnv.WIN32))); +// assert(@catchof(path::new(`\\\a\b\c.txt`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`\\server\a\b\..\..\..\c`, .path_env = PathEnv.WIN32))); - assert(catch? path::new(`\\a`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`/a/b/../../../c`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`/a/b/../../../c`, .path_env = PathEnv.POSIX)); - assert(catch? path::new(`/a/b/../../..`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`/a/b/../../..`, .path_env = PathEnv.POSIX)); - assert(catch? path::new(`/../a`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`/../a`, .path_env = PathEnv.POSIX)); - assert(catch? path::new(`/..`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`/..`, .path_env = PathEnv.POSIX)); - assert(catch? path::new(`C:/a/b/../../../c`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`C:/../a`, .path_env = PathEnv.WIN32)); - assert(catch? path::new(`C:/..`, .path_env = PathEnv.WIN32)); + assert(@catchof(path::new(`\\a`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`/a/b/../../../c`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`/a/b/../../../c`, .path_env = PathEnv.POSIX))); + assert(@catchof(path::new(`/a/b/../../..`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`/a/b/../../..`, .path_env = PathEnv.POSIX))); + assert(@catchof(path::new(`/../a`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`/../a`, .path_env = PathEnv.POSIX))); + assert(@catchof(path::new(`/..`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`/..`, .path_env = PathEnv.POSIX))); + assert(@catchof(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`C:/../a`, .path_env = PathEnv.WIN32))); + assert(@catchof(path::new(`C:/..`, .path_env = PathEnv.WIN32))); - assert(path::new("/", .path_env = PathEnv.POSIX).as_str()? == "/"); - assert(path::new("/./", .path_env = PathEnv.POSIX).as_str()? == "/"); - assert(path::new("/foo/../", .path_env = PathEnv.POSIX).as_str()? == "/"); - assert(path::new("/foo/bar/../", .path_env = PathEnv.POSIX).as_str()? == "/foo"); - assert(path::new("/foo//bar", .path_env = PathEnv.POSIX).as_str()? == "/foo/bar"); - assert(path::new("/foo//bar/../", .path_env = PathEnv.POSIX).as_str()? == "/foo"); - assert(path::new("a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()? == `a\b\c.txt`); - assert(path::new("a\\b/c.txt", .path_env = PathEnv.POSIX).as_str()? == "a\\b/c.txt"); - assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()? == `C:\a\b\c.txt`); - assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.POSIX).as_str()? == "C:\\a\\b/c.txt"); - assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a\b\c.txt`); - assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.POSIX).as_str()? == `\\server\a\b/c.txt`); - assert(path::new(`c:\hello//bar\\\\foo.txt`, .path_env = PathEnv.WIN32).as_str()? == `c:\hello\bar\foo.txt`); + assert(path::new("/", .path_env = PathEnv.POSIX).as_str()! == "/"); + assert(path::new("/./", .path_env = PathEnv.POSIX).as_str()! == "/"); + assert(path::new("/foo/../", .path_env = PathEnv.POSIX).as_str()! == "/"); + assert(path::new("/foo/bar/../", .path_env = PathEnv.POSIX).as_str()! == "/foo"); + assert(path::new("/foo//bar", .path_env = PathEnv.POSIX).as_str()! == "/foo/bar"); + assert(path::new("/foo//bar/../", .path_env = PathEnv.POSIX).as_str()! == "/foo"); + assert(path::new("a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()! == `a\b\c.txt`); + assert(path::new("a\\b/c.txt", .path_env = PathEnv.POSIX).as_str()! == "a\\b/c.txt"); + assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()! == `C:\a\b\c.txt`); + assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.POSIX).as_str()! == "C:\\a\\b/c.txt"); + assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a\b\c.txt`); + assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.POSIX).as_str()! == `\\server\a\b/c.txt`); + assert(path::new(`c:\hello//bar\\\\foo.txt`, .path_env = PathEnv.WIN32).as_str()! == `c:\hello\bar\foo.txt`); - assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.WIN32).as_str()? == `~\a\b\c.txt`); - assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.POSIX).as_str()? == `~\a\b/c.txt`); + assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.WIN32).as_str()! == `~\a\b\c.txt`); + assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.POSIX).as_str()! == `~\a\b/c.txt`); - assert(path::new(`a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()? == `..\c`); - assert(path::new(`a/b/../../../c`, .path_env = PathEnv.POSIX).as_str()? == `../c`); - assert(path::new(`a/b/../../..`, .path_env = PathEnv.WIN32).as_str()? == `..`); - assert(path::new(`a/b/../../..`, .path_env = PathEnv.POSIX).as_str()? == `..`); - assert(path::new(`../a`, .path_env = PathEnv.WIN32).as_str()? == `..\a`); - assert(path::new(`../a`, .path_env = PathEnv.POSIX).as_str()? == `../a`); - assert(path::new(`..`, .path_env = PathEnv.WIN32).as_str()? == `..`); - assert(path::new(`..`, .path_env = PathEnv.POSIX).as_str()? == `..`); - assert(path::new(`a/b/../c`, .path_env = PathEnv.WIN32).as_str()? == `a\c`); - assert(path::new(`a/b/../c`, .path_env = PathEnv.POSIX).as_str()? == `a/c`); - assert(path::new(`a/b/../../c`, .path_env = PathEnv.WIN32).as_str()? == `c`); - assert(path::new(`a/b/../../c`, .path_env = PathEnv.POSIX).as_str()? == `c`); - assert(path::new(`a/b/..`, .path_env = PathEnv.WIN32).as_str()? == `a`); - assert(path::new(`a/b/..`, .path_env = PathEnv.POSIX).as_str()? == `a`); - assert(path::new(`a/b/../`, .path_env = PathEnv.WIN32).as_str()? == `a`); - assert(path::new(`a/b/../`, .path_env = PathEnv.POSIX).as_str()? == `a`); - assert(path::new(`a/b/../..`, .path_env = PathEnv.WIN32).as_str()? == ""); - assert(path::new(`a/b/../..`, .path_env = PathEnv.POSIX).as_str()? == ""); - assert(path::new(`a/b/../../`, .path_env = PathEnv.WIN32).as_str()? == ""); - assert(path::new(`a/b/../../`, .path_env = PathEnv.POSIX).as_str()? == ""); - assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()? == `a\d`); - assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()? == `a/d`); - assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.WIN32).as_str()? == `a\d`); - assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.POSIX).as_str()? == `a/d`); - assert(path::new(`a/b//d`, .path_env = PathEnv.WIN32).as_str()? == `a\b\d`); - assert(path::new(`a/b//d`, .path_env = PathEnv.POSIX).as_str()? == `a/b/d`); - assert(path::new(`a/b/././.`, .path_env = PathEnv.WIN32).as_str()? == `a\b`); - assert(path::new(`a/b/././.`, .path_env = PathEnv.POSIX).as_str()? == `a/b`); - assert(path::new(`a/b/./././`, .path_env = PathEnv.WIN32).as_str()? == `a\b`); - assert(path::new(`a/b/./././`, .path_env = PathEnv.POSIX).as_str()? == `a/b`); - assert(path::new(`./a/`, .path_env = PathEnv.WIN32).as_str()? == `a`); - assert(path::new(`./a/`, .path_env = PathEnv.POSIX).as_str()? == `a`); - assert(path::new(`./`, .path_env = PathEnv.WIN32).as_str()? == ``); - assert(path::new(`./`, .path_env = PathEnv.POSIX).as_str()? == ``); - assert(path::new(`.`, .path_env = PathEnv.WIN32).as_str()? == ``); - assert(path::new(`.`, .path_env = PathEnv.POSIX).as_str()? == ``); - assert(path::new(``, .path_env = PathEnv.WIN32).as_str()? == ``); - assert(path::new(``, .path_env = PathEnv.POSIX).as_str()? == ``); - assert(path::new(`/a`, .path_env = PathEnv.WIN32).as_str()? == `\a`); - assert(path::new(`/a`, .path_env = PathEnv.POSIX).as_str()? == `/a`); - assert(path::new(`/a/`, .path_env = PathEnv.WIN32).as_str()? == `\a`); - assert(path::new(`/a/`, .path_env = PathEnv.POSIX).as_str()? == `/a`); - assert(path::new(`/a/b/../c`, .path_env = PathEnv.WIN32).as_str()? == `\a\c`); - assert(path::new(`/a/b/../c`, .path_env = PathEnv.POSIX).as_str()? == `/a/c`); - assert(path::new(`/a/b/../../c`, .path_env = PathEnv.WIN32).as_str()? == `\c`); - assert(path::new(`/a/b/../../c`, .path_env = PathEnv.POSIX).as_str()? == `/c`); - assert(path::new(`/a/b/..`, .path_env = PathEnv.WIN32).as_str()? == `\a`); - assert(path::new(`/a/b/..`, .path_env = PathEnv.POSIX).as_str()? == `/a`); - assert(path::new(`/a/b/../..`, .path_env = PathEnv.WIN32).as_str()? == `\`); - assert(path::new(`/a/b/../..`, .path_env = PathEnv.POSIX).as_str()? == `/`); - assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()? == `\a\d`); - assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()? == `/a/d`); - assert(path::new(`/a/b//d`, .path_env = PathEnv.WIN32).as_str()? == `\a\b\d`); - assert(path::new(`/a/b//d`, .path_env = PathEnv.POSIX).as_str()? == `/a/b/d`); - assert(path::new(`/./a/`, .path_env = PathEnv.WIN32).as_str()? == `\a`); - assert(path::new(`/./a/`, .path_env = PathEnv.POSIX).as_str()? == `/a`); - assert(path::new(`/./`, .path_env = PathEnv.WIN32).as_str()? == `\`); - assert(path::new(`/./`, .path_env = PathEnv.POSIX).as_str()? == `/`); - assert(path::new(`/.`, .path_env = PathEnv.WIN32).as_str()? == `\`); - assert(path::new(`/.`, .path_env = PathEnv.POSIX).as_str()? == `/`); - assert(path::new(`/`, .path_env = PathEnv.WIN32).as_str()? == `\`); - assert(path::new(`/`, .path_env = PathEnv.POSIX).as_str()? == `/`); - assert(path::new(`C:/a`, .path_env = PathEnv.WIN32).as_str()? == `C:\a`); - assert(path::new(`C:/a`, .path_env = PathEnv.POSIX).as_str()? == `C:/a`); - assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.WIN32).as_str()? == `C:\a\c`); - assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.POSIX).as_str()? == `C:/a/c`); - assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.WIN32).as_str()? == `C:\c`); - assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.POSIX).as_str()? == `C:/c`); - assert(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.POSIX).as_str()? == `c`); - assert(path::new(`C:/a/b/..`, .path_env = PathEnv.WIN32).as_str()? == `C:\a`); - assert(path::new(`C:/a/b/..`, .path_env = PathEnv.POSIX).as_str()? == `C:/a`); - assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.WIN32).as_str()? == `C:\`); - assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.POSIX).as_str()? == `C:`); - assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()? == `C:\a\d`); - assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()? == `C:/a/d`); - assert(path::new(`C:/a/b//d`, .path_env = PathEnv.WIN32).as_str()? == `C:\a\b\d`); - assert(path::new(`C:/a/b//d`, .path_env = PathEnv.POSIX).as_str()? == `C:/a/b/d`); - assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.WIN32).as_str()? == `C:\a\b`); - assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.POSIX).as_str()? == `C:/a/b`); - assert(path::new(`C:/./a`, .path_env = PathEnv.WIN32).as_str()? == `C:\a`); - assert(path::new(`C:/./a`, .path_env = PathEnv.POSIX).as_str()? == `C:/a`); - assert(path::new(`C:/./`, .path_env = PathEnv.WIN32).as_str()? == `C:\`); - assert(path::new(`C:/./`, .path_env = PathEnv.POSIX).as_str()? == `C:`); - assert(path::new(`C:/../a`, .path_env = PathEnv.POSIX).as_str()? == `a`); - assert(path::new(`C:/..`, .path_env = PathEnv.POSIX).as_str()? == ``); - assert(path::new(`C:/`, .path_env = PathEnv.WIN32).as_str()? == `C:\`); - assert(path::new(`C:/`, .path_env = PathEnv.POSIX).as_str()? == `C:`); - assert(path::new(`C:a`, .path_env = PathEnv.WIN32).as_str()? == `C:a`); - assert(path::new(`C:a`, .path_env = PathEnv.POSIX).as_str()? == `C:a`); - assert(path::new(`C:a/`, .path_env = PathEnv.WIN32).as_str()? == `C:a`); - assert(path::new(`C:a/`, .path_env = PathEnv.POSIX).as_str()? == `C:a`); + assert(path::new(`a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()! == `..\c`); + assert(path::new(`a/b/../../../c`, .path_env = PathEnv.POSIX).as_str()! == `../c`); + assert(path::new(`a/b/../../..`, .path_env = PathEnv.WIN32).as_str()! == `..`); + assert(path::new(`a/b/../../..`, .path_env = PathEnv.POSIX).as_str()! == `..`); + assert(path::new(`../a`, .path_env = PathEnv.WIN32).as_str()! == `..\a`); + assert(path::new(`../a`, .path_env = PathEnv.POSIX).as_str()! == `../a`); + assert(path::new(`..`, .path_env = PathEnv.WIN32).as_str()! == `..`); + assert(path::new(`..`, .path_env = PathEnv.POSIX).as_str()! == `..`); + assert(path::new(`a/b/../c`, .path_env = PathEnv.WIN32).as_str()! == `a\c`); + assert(path::new(`a/b/../c`, .path_env = PathEnv.POSIX).as_str()! == `a/c`); + assert(path::new(`a/b/../../c`, .path_env = PathEnv.WIN32).as_str()! == `c`); + assert(path::new(`a/b/../../c`, .path_env = PathEnv.POSIX).as_str()! == `c`); + assert(path::new(`a/b/..`, .path_env = PathEnv.WIN32).as_str()! == `a`); + assert(path::new(`a/b/..`, .path_env = PathEnv.POSIX).as_str()! == `a`); + assert(path::new(`a/b/../`, .path_env = PathEnv.WIN32).as_str()! == `a`); + assert(path::new(`a/b/../`, .path_env = PathEnv.POSIX).as_str()! == `a`); + assert(path::new(`a/b/../..`, .path_env = PathEnv.WIN32).as_str()! == ""); + assert(path::new(`a/b/../..`, .path_env = PathEnv.POSIX).as_str()! == ""); + assert(path::new(`a/b/../../`, .path_env = PathEnv.WIN32).as_str()! == ""); + assert(path::new(`a/b/../../`, .path_env = PathEnv.POSIX).as_str()! == ""); + assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()! == `a\d`); + assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()! == `a/d`); + assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.WIN32).as_str()! == `a\d`); + assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.POSIX).as_str()! == `a/d`); + assert(path::new(`a/b//d`, .path_env = PathEnv.WIN32).as_str()! == `a\b\d`); + assert(path::new(`a/b//d`, .path_env = PathEnv.POSIX).as_str()! == `a/b/d`); + assert(path::new(`a/b/././.`, .path_env = PathEnv.WIN32).as_str()! == `a\b`); + assert(path::new(`a/b/././.`, .path_env = PathEnv.POSIX).as_str()! == `a/b`); + assert(path::new(`a/b/./././`, .path_env = PathEnv.WIN32).as_str()! == `a\b`); + assert(path::new(`a/b/./././`, .path_env = PathEnv.POSIX).as_str()! == `a/b`); + assert(path::new(`./a/`, .path_env = PathEnv.WIN32).as_str()! == `a`); + assert(path::new(`./a/`, .path_env = PathEnv.POSIX).as_str()! == `a`); + assert(path::new(`./`, .path_env = PathEnv.WIN32).as_str()! == ``); + assert(path::new(`./`, .path_env = PathEnv.POSIX).as_str()! == ``); + assert(path::new(`.`, .path_env = PathEnv.WIN32).as_str()! == ``); + assert(path::new(`.`, .path_env = PathEnv.POSIX).as_str()! == ``); + assert(path::new(``, .path_env = PathEnv.WIN32).as_str()! == ``); + assert(path::new(``, .path_env = PathEnv.POSIX).as_str()! == ``); + assert(path::new(`/a`, .path_env = PathEnv.WIN32).as_str()! == `\a`); + assert(path::new(`/a`, .path_env = PathEnv.POSIX).as_str()! == `/a`); + assert(path::new(`/a/`, .path_env = PathEnv.WIN32).as_str()! == `\a`); + assert(path::new(`/a/`, .path_env = PathEnv.POSIX).as_str()! == `/a`); + assert(path::new(`/a/b/../c`, .path_env = PathEnv.WIN32).as_str()! == `\a\c`); + assert(path::new(`/a/b/../c`, .path_env = PathEnv.POSIX).as_str()! == `/a/c`); + assert(path::new(`/a/b/../../c`, .path_env = PathEnv.WIN32).as_str()! == `\c`); + assert(path::new(`/a/b/../../c`, .path_env = PathEnv.POSIX).as_str()! == `/c`); + assert(path::new(`/a/b/..`, .path_env = PathEnv.WIN32).as_str()! == `\a`); + assert(path::new(`/a/b/..`, .path_env = PathEnv.POSIX).as_str()! == `/a`); + assert(path::new(`/a/b/../..`, .path_env = PathEnv.WIN32).as_str()! == `\`); + assert(path::new(`/a/b/../..`, .path_env = PathEnv.POSIX).as_str()! == `/`); + assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()! == `\a\d`); + assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()! == `/a/d`); + assert(path::new(`/a/b//d`, .path_env = PathEnv.WIN32).as_str()! == `\a\b\d`); + assert(path::new(`/a/b//d`, .path_env = PathEnv.POSIX).as_str()! == `/a/b/d`); + assert(path::new(`/./a/`, .path_env = PathEnv.WIN32).as_str()! == `\a`); + assert(path::new(`/./a/`, .path_env = PathEnv.POSIX).as_str()! == `/a`); + assert(path::new(`/./`, .path_env = PathEnv.WIN32).as_str()! == `\`); + assert(path::new(`/./`, .path_env = PathEnv.POSIX).as_str()! == `/`); + assert(path::new(`/.`, .path_env = PathEnv.WIN32).as_str()! == `\`); + assert(path::new(`/.`, .path_env = PathEnv.POSIX).as_str()! == `/`); + assert(path::new(`/`, .path_env = PathEnv.WIN32).as_str()! == `\`); + assert(path::new(`/`, .path_env = PathEnv.POSIX).as_str()! == `/`); + assert(path::new(`C:/a`, .path_env = PathEnv.WIN32).as_str()! == `C:\a`); + assert(path::new(`C:/a`, .path_env = PathEnv.POSIX).as_str()! == `C:/a`); + assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.WIN32).as_str()! == `C:\a\c`); + assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.POSIX).as_str()! == `C:/a/c`); + assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.WIN32).as_str()! == `C:\c`); + assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.POSIX).as_str()! == `C:/c`); + assert(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.POSIX).as_str()! == `c`); + assert(path::new(`C:/a/b/..`, .path_env = PathEnv.WIN32).as_str()! == `C:\a`); + assert(path::new(`C:/a/b/..`, .path_env = PathEnv.POSIX).as_str()! == `C:/a`); + assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.WIN32).as_str()! == `C:\`); + assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.POSIX).as_str()! == `C:`); + assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()! == `C:\a\d`); + assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()! == `C:/a/d`); + assert(path::new(`C:/a/b//d`, .path_env = PathEnv.WIN32).as_str()! == `C:\a\b\d`); + assert(path::new(`C:/a/b//d`, .path_env = PathEnv.POSIX).as_str()! == `C:/a/b/d`); + assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.WIN32).as_str()! == `C:\a\b`); + assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.POSIX).as_str()! == `C:/a/b`); + assert(path::new(`C:/./a`, .path_env = PathEnv.WIN32).as_str()! == `C:\a`); + assert(path::new(`C:/./a`, .path_env = PathEnv.POSIX).as_str()! == `C:/a`); + assert(path::new(`C:/./`, .path_env = PathEnv.WIN32).as_str()! == `C:\`); + assert(path::new(`C:/./`, .path_env = PathEnv.POSIX).as_str()! == `C:`); + assert(path::new(`C:/../a`, .path_env = PathEnv.POSIX).as_str()! == `a`); + assert(path::new(`C:/..`, .path_env = PathEnv.POSIX).as_str()! == ``); + assert(path::new(`C:/`, .path_env = PathEnv.WIN32).as_str()! == `C:\`); + assert(path::new(`C:/`, .path_env = PathEnv.POSIX).as_str()! == `C:`); + assert(path::new(`C:a`, .path_env = PathEnv.WIN32).as_str()! == `C:a`); + assert(path::new(`C:a`, .path_env = PathEnv.POSIX).as_str()! == `C:a`); + assert(path::new(`C:a/`, .path_env = PathEnv.WIN32).as_str()! == `C:a`); + assert(path::new(`C:a/`, .path_env = PathEnv.POSIX).as_str()! == `C:a`); - assert(path::new(`C:a/b/../c`, .path_env = PathEnv.WIN32).as_str()? == `C:a\c`); - assert(path::new(`C:a/b/../c`, .path_env = PathEnv.POSIX).as_str()? == `C:a/c`); - assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.WIN32).as_str()? == `C:c`); - assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.POSIX).as_str()? == `c`); - assert(path::new(`C:a/b/..`, .path_env = PathEnv.WIN32).as_str()? == `C:a`); - assert(path::new(`C:a/b/..`, .path_env = PathEnv.POSIX).as_str()? == `C:a`); - assert(path::new(`C:a/b/../..`, .path_env = PathEnv.WIN32).as_str()? == `C:`); - assert(path::new(`C:a/b/../..`, .path_env = PathEnv.POSIX).as_str()? == ``); - assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()? == `C:a\d`); - assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()? == `C:a/d`); - assert(path::new(`C:a/b//d`, .path_env = PathEnv.WIN32).as_str()? == `C:a\b\d`); - assert(path::new(`C:a/b//d`, .path_env = PathEnv.POSIX).as_str()? == `C:a/b/d`); - assert(path::new(`C:a/b/././.`, .path_env = PathEnv.WIN32).as_str()? == `C:a\b`); - assert(path::new(`C:a/b/././.`, .path_env = PathEnv.POSIX).as_str()? == `C:a/b`); - assert(path::new(`C:a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()? == `C:..\c`); - assert(path::new(`C:./a`, .path_env = PathEnv.WIN32).as_str()? == `C:a`); - assert(path::new(`C:./a`, .path_env = PathEnv.POSIX).as_str()? == `C:./a`); - assert(path::new(`C:./`, .path_env = PathEnv.WIN32).as_str()? == `C:`); - assert(path::new(`C:./`, .path_env = PathEnv.POSIX).as_str()? == `C:.`); - assert(path::new(`C:../a`, .path_env = PathEnv.POSIX).as_str()? == `C:../a`); - assert(path::new(`C:../a`, .path_env = PathEnv.WIN32).as_str()? == `C:..\a`); - assert(path::new(`C:..`, .path_env = PathEnv.POSIX).as_str()? == `C:..`); - assert(path::new(`C:..`, .path_env = PathEnv.WIN32).as_str()? == `C:..`); - assert(path::new(`C:`, .path_env = PathEnv.WIN32).as_str()? == `C:`); - assert(path::new(`C:`, .path_env = PathEnv.POSIX).as_str()? == `C:`); + assert(path::new(`C:a/b/../c`, .path_env = PathEnv.WIN32).as_str()! == `C:a\c`); + assert(path::new(`C:a/b/../c`, .path_env = PathEnv.POSIX).as_str()! == `C:a/c`); + assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.WIN32).as_str()! == `C:c`); + assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.POSIX).as_str()! == `c`); + assert(path::new(`C:a/b/..`, .path_env = PathEnv.WIN32).as_str()! == `C:a`); + assert(path::new(`C:a/b/..`, .path_env = PathEnv.POSIX).as_str()! == `C:a`); + assert(path::new(`C:a/b/../..`, .path_env = PathEnv.WIN32).as_str()! == `C:`); + assert(path::new(`C:a/b/../..`, .path_env = PathEnv.POSIX).as_str()! == ``); + assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.WIN32).as_str()! == `C:a\d`); + assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.POSIX).as_str()! == `C:a/d`); + assert(path::new(`C:a/b//d`, .path_env = PathEnv.WIN32).as_str()! == `C:a\b\d`); + assert(path::new(`C:a/b//d`, .path_env = PathEnv.POSIX).as_str()! == `C:a/b/d`); + assert(path::new(`C:a/b/././.`, .path_env = PathEnv.WIN32).as_str()! == `C:a\b`); + assert(path::new(`C:a/b/././.`, .path_env = PathEnv.POSIX).as_str()! == `C:a/b`); + assert(path::new(`C:a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()! == `C:..\c`); + assert(path::new(`C:./a`, .path_env = PathEnv.WIN32).as_str()! == `C:a`); + assert(path::new(`C:./a`, .path_env = PathEnv.POSIX).as_str()! == `C:./a`); + assert(path::new(`C:./`, .path_env = PathEnv.WIN32).as_str()! == `C:`); + assert(path::new(`C:./`, .path_env = PathEnv.POSIX).as_str()! == `C:.`); + assert(path::new(`C:../a`, .path_env = PathEnv.POSIX).as_str()! == `C:../a`); + assert(path::new(`C:../a`, .path_env = PathEnv.WIN32).as_str()! == `C:..\a`); + assert(path::new(`C:..`, .path_env = PathEnv.POSIX).as_str()! == `C:..`); + assert(path::new(`C:..`, .path_env = PathEnv.WIN32).as_str()! == `C:..`); + assert(path::new(`C:`, .path_env = PathEnv.WIN32).as_str()! == `C:`); + assert(path::new(`C:`, .path_env = PathEnv.POSIX).as_str()! == `C:`); - assert(path::new(`\\server/a`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a`); - assert(path::new(`\\server/a`, .path_env = PathEnv.POSIX).as_str()? == `\\server/a`); - assert(path::new(`\\server\a\b\..\c`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a\c`); - assert(path::new(`\\server\a\b\..\..\c`, .path_env = PathEnv.WIN32).as_str()? == `\\server\c`); - assert(path::new(`\\server\a\b\..`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a`); - assert(path::new(`\\server\a\..`, .path_env = PathEnv.WIN32).as_str()? == `\\server\`); - assert(path::new(`\\server\a\b\..\c\..\d`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a\d`); - assert(path::new(`\\server\a\b\\d`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a\b\d`); - assert(path::new(`\\server\a\b\.\.\.`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a\b`); - assert(path::new(`\\server\.\a`, .path_env = PathEnv.WIN32).as_str()? == `\\server\a`); - assert(path::new(`\\server\.`, .path_env = PathEnv.WIN32).as_str()? == `\\server\`); - assert(path::new(`\\server\`, .path_env = PathEnv.WIN32).as_str()? == `\\server\`); + assert(path::new(`\\server/a`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a`); + assert(path::new(`\\server/a`, .path_env = PathEnv.POSIX).as_str()! == `\\server/a`); + assert(path::new(`\\server\a\b\..\c`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a\c`); + assert(path::new(`\\server\a\b\..\..\c`, .path_env = PathEnv.WIN32).as_str()! == `\\server\c`); + assert(path::new(`\\server\a\b\..`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a`); + assert(path::new(`\\server\a\..`, .path_env = PathEnv.WIN32).as_str()! == `\\server\`); + assert(path::new(`\\server\a\b\..\c\..\d`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a\d`); + assert(path::new(`\\server\a\b\\d`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a\b\d`); + assert(path::new(`\\server\a\b\.\.\.`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a\b`); + assert(path::new(`\\server\.\a`, .path_env = PathEnv.WIN32).as_str()! == `\\server\a`); + assert(path::new(`\\server\.`, .path_env = PathEnv.WIN32).as_str()! == `\\server\`); + assert(path::new(`\\server\`, .path_env = PathEnv.WIN32).as_str()! == `\\server\`); } fn void! test_extension() { - assert(catch? path::new(`C:`, .path_env = PathEnv.WIN32).extension()); - assert(catch? path::new(`C:`, .path_env = PathEnv.POSIX).extension()); - assert(catch? path::new(`file`, .path_env = PathEnv.WIN32).extension()); - assert(catch? path::new(`file`, .path_env = PathEnv.POSIX).extension()); - assert(catch? path::new(`C:\temp\foo.bar\README`, .path_env = PathEnv.WIN32).extension()); + assert(@catchof(path::new(`C:`, .path_env = PathEnv.WIN32).extension())); + assert(@catchof(path::new(`C:`, .path_env = PathEnv.POSIX).extension())); + assert(@catchof(path::new(`file`, .path_env = PathEnv.WIN32).extension())); + assert(@catchof(path::new(`file`, .path_env = PathEnv.POSIX).extension())); + assert(@catchof(path::new(`C:\temp\foo.bar\README`, .path_env = PathEnv.WIN32).extension())); - assert(path::new_windows("file.txt").extension()? == "txt"); - assert(path::new_posix("file.txt").extension()? == "txt"); + assert(path::new_windows("file.txt").extension()! == "txt"); + assert(path::new_posix("file.txt").extension()! == "txt"); - assert(path::new_windows("a/b/file.txt").extension()? == "txt"); - assert(path::new_posix("a/b/file.txt").extension()? == "txt"); + assert(path::new_windows("a/b/file.txt").extension()! == "txt"); + assert(path::new_posix("a/b/file.txt").extension()! == "txt"); - assert(path::new_windows("a\\b\\file.txt").extension()? == "txt"); + assert(path::new_windows("a\\b\\file.txt").extension()! == "txt"); - assert(path::new_windows("a.b/file.txt").extension()? == "txt"); - assert(path::new_posix("a.b/file.txt").extension()? == "txt"); - assert(path::new_windows("a.b/file.txt").extension()? == "txt"); - assert(path::new_posix("a.b/file.txt").extension()? == "txt"); + assert(path::new_windows("a.b/file.txt").extension()! == "txt"); + assert(path::new_posix("a.b/file.txt").extension()! == "txt"); + assert(path::new_windows("a.b/file.txt").extension()! == "txt"); + assert(path::new_posix("a.b/file.txt").extension()! == "txt"); - assert(path::new_windows("a.b\\file.txt").extension()? == "txt"); + assert(path::new_windows("a.b\\file.txt").extension()! == "txt"); - assert(path::new_windows("domain.dot.com").extension()? == "com"); - assert(path::new_posix("domain.dot.com").extension()? == "com"); + assert(path::new_windows("domain.dot.com").extension()! == "com"); + assert(path::new_posix("domain.dot.com").extension()! == "com"); - assert(path::new_windows("image.jpeg").extension()? == "jpeg"); - assert(path::new_posix("image.jpeg").extension()? == "jpeg"); + assert(path::new_windows("image.jpeg").extension()! == "jpeg"); + assert(path::new_posix("image.jpeg").extension()! == "jpeg"); - assert(path::new_windows("../filename.ext").extension()? == "ext"); - assert(path::new_posix("../filename.ext").extension()? == "ext"); + assert(path::new_windows("../filename.ext").extension()! == "ext"); + assert(path::new_posix("../filename.ext").extension()! == "ext"); } fn void! test_basename() { - assert(path::new_windows("file.txt").basename()? == "file.txt"); - assert(path::new_posix("file.txt").basename()? == "file.txt"); + assert(path::new_windows("file.txt").basename()! == "file.txt"); + assert(path::new_posix("file.txt").basename()! == "file.txt"); - assert(path::new_windows("a/b/file.txt").basename()? == "file.txt"); - assert(path::new_posix("a/b/file.txt").basename()? == "file.txt"); + assert(path::new_windows("a/b/file.txt").basename()! == "file.txt"); + assert(path::new_posix("a/b/file.txt").basename()! == "file.txt"); - assert(path::new_windows("a.b/file.txt").basename()? == "file.txt"); - assert(path::new_posix("a.b/file.txt").basename()? == "file.txt"); + assert(path::new_windows("a.b/file.txt").basename()! == "file.txt"); + assert(path::new_posix("a.b/file.txt").basename()! == "file.txt"); - assert(path::new_windows("a.b/file.txt").basename()? == "file.txt"); - assert(path::new_posix("a.b/file.txt").basename()? == "file.txt"); + assert(path::new_windows("a.b/file.txt").basename()! == "file.txt"); + assert(path::new_posix("a.b/file.txt").basename()! == "file.txt"); - assert(path::new_windows("../filename.ext").basename()? == "filename.ext"); - assert(path::new_posix("../filename.ext").basename()? == "filename.ext"); + assert(path::new_windows("../filename.ext").basename()! == "filename.ext"); + assert(path::new_posix("../filename.ext").basename()! == "filename.ext"); - assert(path::new_windows("C:").basename()? == ""); - assert(path::new_posix("C:").basename()? == "C:"); + assert(path::new_windows("C:").basename()! == ""); + assert(path::new_posix("C:").basename()! == "C:"); - assert(path::new_windows("../..").basename()? == ".."); - assert(path::new_posix("../..").basename()? == ".."); + assert(path::new_windows("../..").basename()! == ".."); + assert(path::new_posix("../..").basename()! == ".."); - assert(path::new_windows(`\\server\`).basename()? == ""); - assert(path::new_posix(`\\server\`).basename()? == `\\server\`); + assert(path::new_windows(`\\server\`).basename()! == ""); + assert(path::new_posix(`\\server\`).basename()! == `\\server\`); } fn void! test_dirname() { - assert(path::new_windows("file.txt").dirname()? == ""); - assert(path::new_posix("file.txt").dirname()? == ""); + assert(path::new_windows("file.txt").dirname()! == ""); + assert(path::new_posix("file.txt").dirname()! == ""); - assert(path::new_windows("a/b/file.txt").dirname()? == `a\b`); - assert(path::new_posix("a/b/file.txt").dirname()? == "a/b"); + assert(path::new_windows("a/b/file.txt").dirname()! == `a\b`); + assert(path::new_posix("a/b/file.txt").dirname()! == "a/b"); - assert(path::new_windows("a.b/file.txt").dirname()? == "a.b"); - assert(path::new_posix("a.b/file.txt").dirname()? == "a.b"); + assert(path::new_windows("a.b/file.txt").dirname()! == "a.b"); + assert(path::new_posix("a.b/file.txt").dirname()! == "a.b"); - assert(path::new_windows("../filename.ext").dirname()? == ".."); - assert(path::new_posix("../filename.ext").dirname()? == ".."); + assert(path::new_windows("../filename.ext").dirname()! == ".."); + assert(path::new_posix("../filename.ext").dirname()! == ".."); - assert(path::new_windows("C:").dirname()? == "C:"); - assert(path::new_posix("C:").dirname()? == ""); + assert(path::new_windows("C:").dirname()! == "C:"); + assert(path::new_posix("C:").dirname()! == ""); - assert(path::new_windows("C:/").dirname()? == "C:\\"); - assert(path::new_posix("C:/").dirname()? == ""); + assert(path::new_windows("C:/").dirname()! == "C:\\"); + assert(path::new_posix("C:/").dirname()! == ""); - assert(path::new_windows("C:/a").dirname()? == "C:\\"); - assert(path::new_posix("C:/a").dirname()? == "C:"); + assert(path::new_windows("C:/a").dirname()! == "C:\\"); + assert(path::new_posix("C:/a").dirname()! == "C:"); - assert(path::new_windows("../..").dirname()? == ".."); - assert(path::new_posix("../..").dirname()? == ".."); + assert(path::new_windows("../..").dirname()! == ".."); + assert(path::new_posix("../..").dirname()! == ".."); - assert(path::new_windows(`\\server\`).dirname()? == `\\server\`); - assert(path::new_posix(`\\server\`).dirname()? == ``); + assert(path::new_windows(`\\server\`).dirname()! == `\\server\`); + assert(path::new_posix(`\\server\`).dirname()! == ``); } fn void! test_path_volume() { - assert(path::new_windows(`C:\abs`).volume_name()? == `C:`); - assert(path::new_windows(`C:abs`).volume_name()? == `C:`); - assert(path::new_posix(`C:/abs`).volume_name()? == ``); - assert(path::new_posix(`C:abs`).volume_name()? == ``); - assert(path::new_windows(`\\server\`).volume_name()? == `\\server`); - assert(path::new_windows(`\\server\abc`).volume_name()? == `\\server`); + assert(path::new_windows(`C:\abs`).volume_name()! == `C:`); + assert(path::new_windows(`C:abs`).volume_name()! == `C:`); + assert(path::new_posix(`C:/abs`).volume_name()! == ``); + assert(path::new_posix(`C:abs`).volume_name()! == ``); + assert(path::new_windows(`\\server\`).volume_name()! == `\\server`); + assert(path::new_windows(`\\server\abc`).volume_name()! == `\\server`); } diff --git a/test/unit/stdlib/net/inetaddr.c3 b/test/unit/stdlib/net/inetaddr.c3 index e96e29cdf..d90dbbae9 100644 --- a/test/unit/stdlib/net/inetaddr.c3 +++ b/test/unit/stdlib/net/inetaddr.c3 @@ -11,34 +11,34 @@ fn void test_ipv4() fn void! test_ipv4_to_string() { - InetAddress a = net::ipv4_from_str("127.0.0.1")?; - assert(a.to_string()? == "127.0.0.1"); + InetAddress a = net::ipv4_from_str("127.0.0.1")!; + assert(a.to_string()! == "127.0.0.1"); } fn void! test_ipv6_to_string() { - InetAddress a = net::ipv6_from_str("2001:db8::2:1")?; - a.to_string()?; - assert(a.to_string()? == "2001:0db8:0000:0000:0000:0000:0002:0001"); - assert(net::ipv6_from_str("2001:db8::1").to_string()? == "2001:0db8:0000:0000:0000:0000:0000:0001"); - assert(net::ipv6_from_str("::1").to_string()? == "0000:0000:0000:0000:0000:0000:0000:0001"); - assert(net::ipv6_from_str("2001::1").to_string()? == "2001:0000:0000:0000:0000:0000:0000:0001"); - assert(net::ipv6_from_str("2001:db8:1234::").to_string()? == "2001:0db8:1234:0000:0000:0000:0000:0000"); - assert(net::ipv6_from_str("2001::").to_string()? == "2001:0000:0000:0000:0000:0000:0000:0000"); - assert(net::ipv6_from_str("::").to_string()? == "0000:0000:0000:0000:0000:0000:0000:0000"); + InetAddress a = net::ipv6_from_str("2001:db8::2:1")!; + a.to_string()!; + assert(a.to_string()! == "2001:0db8:0000:0000:0000:0000:0002:0001"); + assert(net::ipv6_from_str("2001:db8::1").to_string()! == "2001:0db8:0000:0000:0000:0000:0000:0001"); + assert(net::ipv6_from_str("::1").to_string()! == "0000:0000:0000:0000:0000:0000:0000:0001"); + assert(net::ipv6_from_str("2001::1").to_string()! == "2001:0000:0000:0000:0000:0000:0000:0001"); + assert(net::ipv6_from_str("2001:db8:1234::").to_string()! == "2001:0db8:1234:0000:0000:0000:0000:0000"); + assert(net::ipv6_from_str("2001::").to_string()! == "2001:0000:0000:0000:0000:0000:0000:0000"); + assert(net::ipv6_from_str("::").to_string()! == "0000:0000:0000:0000:0000:0000:0000:0000"); } fn void! test_ipv4_parse() { - InetAddress a = net::ipv4_from_str("127.0.0.1")?; + InetAddress a = net::ipv4_from_str("127.0.0.1")!; assert(a.ipv4.a == 127 && a.ipv4.b == 0 && a.ipv4.c == 0 && a.ipv4.d == 1); - a = net::ipv4_from_str("255.254.253.255")?; + a = net::ipv4_from_str("255.254.253.255")!; assert(a.ipv4.a == 255 && a.ipv4.b == 254 && a.ipv4.c == 253 && a.ipv4.d == 255); - assert(catch? net::ipv4_from_str(".1.1.1.1")); - assert(catch? net::ipv4_from_str("1..1.1")); - assert(catch? net::ipv4_from_str("1..1.1.1")); - assert(catch? net::ipv4_from_str("1.1.1.256")); - assert(catch? net::ipv4_from_str("256.1.1.1")); + assert(@catchof(net::ipv4_from_str(".1.1.1.1"))); + assert(@catchof(net::ipv4_from_str("1..1.1"))); + assert(@catchof(net::ipv4_from_str("1..1.1.1"))); + assert(@catchof(net::ipv4_from_str("1.1.1.256"))); + assert(@catchof(net::ipv4_from_str("256.1.1.1"))); } fn void test_ipv6() diff --git a/test/unit/stdlib/string.c3 b/test/unit/stdlib/string.c3 index 75971c7d0..b6835cacb 100644 --- a/test/unit/stdlib/string.c3 +++ b/test/unit/stdlib/string.c3 @@ -2,7 +2,7 @@ module string_test; fn void! test_clear() @test { - DynString s = string::new_with_capacity(32); + DString s = dstring::new_with_capacity(32); assert(s.len() == 0); assert(s.capacity() == 32); s.append_repeat('x', 63); diff --git a/test/unit/stdlib/string_to_float.c3 b/test/unit/stdlib/string_to_float.c3 index 71486fe54..771809b3e 100644 --- a/test/unit/stdlib/string_to_float.c3 +++ b/test/unit/stdlib/string_to_float.c3 @@ -2,28 +2,28 @@ module string_to_float_tests; fn void! test_float() @test { - assert(str::to_float("1.2")? == 1.2f); - assert(str::to_float("10")? == 10f); - assert(str::to_float(".7647834")? == 0.7647834f); - assert(str::to_float("0.213232")? == 0.213232f); - assert(str::to_float("000001.487348")? == 000001.487348f); - assert(str::to_float("3.54500000")? == 3.54500000f); - assert(str::to_float("4.0")? == 4.0f); - assert(str::to_float("-23.545")? == -23.545f); - assert(str::to_float("1.5555555555555")? == 1.5555555555555f); - assert(str::to_float("1.5555555555556666")? == 1.5555555555556666f); + assert(String.to_float("1.2")! == 1.2f); + assert(String.to_float("10")! == 10f); + assert(String.to_float(".7647834")! == 0.7647834f); + assert(String.to_float("0.213232")! == 0.213232f); + assert(String.to_float("000001.487348")! == 000001.487348f); + assert(String.to_float("3.54500000")! == 3.54500000f); + assert(String.to_float("4.0")! == 4.0f); + assert(String.to_float("-23.545")! == -23.545f); + assert(String.to_float("1.5555555555555")! == 1.5555555555555f); + assert(String.to_float("1.5555555555556666")! == 1.5555555555556666f); } fn void! test_double() @test { - assert(str::to_double("1.2")? == 1.2); - assert(str::to_double("10")? == 10); - assert(str::to_double(".7647834")? == 0.7647834); - assert(str::to_double("0.213232")? == 0.213232); - assert(str::to_double("000001.487348")? == 000001.487348); - assert(str::to_double("3.54500000")? == 3.54500000); - assert(str::to_double("4.0")? == 4.0); - assert(str::to_double("-23.545")? == -23.545); - assert(str::to_double("1.5555555555555")? == 1.5555555555555); - assert(str::to_double("1.5555555555556666")? == 1.5555555555556666); + assert(String.to_double("1.2")! == 1.2); + assert(String.to_double("10")! == 10); + assert(String.to_double(".7647834")! == 0.7647834); + assert(String.to_double("0.213232")! == 0.213232); + assert(String.to_double("000001.487348")! == 000001.487348); + assert(String.to_double("3.54500000")! == 3.54500000); + assert(String.to_double("4.0")! == 4.0); + assert(String.to_double("-23.545")! == -23.545); + assert(String.to_double("1.5555555555555")! == 1.5555555555555); + assert(String.to_double("1.5555555555556666")! == 1.5555555555556666); } \ No newline at end of file diff --git a/test/unit/stdlib/time/datetime.c3 b/test/unit/stdlib/time/datetime.c3 new file mode 100644 index 000000000..c5820b702 --- /dev/null +++ b/test/unit/stdlib/time/datetime.c3 @@ -0,0 +1,45 @@ +module datetime_test @test; +import std::time; + +fn void test_parse_and_add() +{ +DateTime d = datetime::from_date(1973, APRIL, 27); + assert(d.year == 1973); + assert(d.month == APRIL); + assert(d.day == 27); + assert(d.hour == 0); + assert(d.min == 0); + d = d.add_weeks(1); + assert(d.year == 1973); + assert(d.month == MAY); + assert(d.day == 4); + assert(d.hour == 0); + assert(d.min == 0); + d = d.add_years(2); + assert(d.year == 1975); + assert(d.month == MAY); + assert(d.day == 4); + assert(d.hour == 0); + assert(d.min == 0); + DateTime x = d.add_months(-14); + assert(x.year == 1974); + assert(x.month == MARCH); + assert(x.day == 4); + assert(x.hour == 0); + assert(x.min == 0); + x = d.add_months(-12); + assert(x.year == 1974); + assert(x.month == MAY); + x = d.add_months(12); + assert(x.year == 1976); + assert(x.month == MAY); + x = d.add_months(3); + assert(x.year == 1975); + assert(x.month == AUGUST); + x = d.add_months(15); + assert(x.year == 1976); + assert(x.month == AUGUST); + x = d.add_months(0); + assert(x.year == 1975); + assert(x.month == MAY); +} \ No newline at end of file