From 8059dc15398c090d21433ff34a30fa3e075f89a8 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 21 Apr 2023 12:15:35 +0200 Subject: [PATCH] delete_if, retain_if, rindex_of, compact, compact_count added to List. --- lib/std/collections/list.c3 | 131 +++++++++++++++++++-- lib/std/core/array.c3 | 29 ++++- lib/std/core/builtin.c3 | 12 +- lib/std/core/env.c3 | 8 +- lib/std/core/private/main_stub.c3 | 2 +- lib/std/libc/libc.c3 | 14 +-- lib/std/net/os/darwin.c3 | 2 +- lib/std/net/os/linux.c3 | 2 +- lib/std/net/os/posix.c3 | 2 +- lib/std/net/os/win32.c3 | 2 +- lib/std/os/macos/cf_allocator.c3 | 2 +- lib/std/os/macos/cf_array.c3 | 2 +- lib/std/os/macos/core_foundation.c3 | 2 +- lib/std/os/macos/objc.c3 | 2 +- lib/std/threads/os/thread_posix.c3 | 2 +- lib/std/threads/thread.c3 | 2 +- releasenotes.md | 2 +- resources/testproject/hello_world.c3 | 2 +- src/compiler/sema_decls.c | 5 + src/compiler/sema_expr.c | 51 ++++---- src/compiler/sema_name_resolution.c | 1 + src/version.h | 2 +- test/unit/stdlib/collections/linkedlist.c3 | 24 ++-- test/unit/stdlib/collections/list.c3 | 45 +++++++ 24 files changed, 278 insertions(+), 70 deletions(-) create mode 100644 test/unit/stdlib/collections/list.c3 diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index c037bcdc6..dc4921cfb 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -4,6 +4,8 @@ module std::collections::list; import std::math; +typedef ElementPredicate = fn bool(Type *type); + struct List { usz size; @@ -196,6 +198,47 @@ fn void List.swap(List* list, usz i, usz j) @swap(list.entries[i], list.entries[j]); } +/** + * @param [&inout] list "The list to remove elements from" + * @param filter "The function to determine if it should be removed or not" + * @return "the number of deleted elements" + **/ +fn usz List.delete_if(List* list, ElementPredicate filter) +{ + usz size = list.size; + for (usz i = size; i > 0; i--) + { + if (filter(&list.entries[i - 1])) continue; + for (usz j = i; j < size; j++) + { + list.entries[j - 1] = list.entries[j]; + } + list.size--; + } + return size - list.size; +} + +/** + * @param [&inout] list "The list to remove elements from" + * @param selection "The function to determine if it should be kept or not" + * @return "the number of deleted elements" + **/ +fn usz List.retain_if(List* list, ElementPredicate selection) +{ + usz size = list.size; + for (usz i = size; i > 0; i--) + { + if (!selection(&list.entries[i - 1])) continue; + for (usz j = i; j < size; j++) + { + list.entries[j - 1] = list.entries[j]; + } + list.size--; + } + return size - list.size; +} + + /** * Reserve at least min_capacity **/ @@ -219,6 +262,19 @@ fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline return &list.entries[index]; } +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); +} + +// Functions for equatable types + $if (types::is_equatable_type(Type)) fn usz! List.index_of(List* list, Type type) @@ -230,6 +286,15 @@ fn usz! List.index_of(List* list, Type type) return SearchResult.MISSING?; } +fn usz! List.rindex_of(List* list, Type type) +{ + foreach_r (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; @@ -240,24 +305,70 @@ fn bool List.equals(List* list, List other_list) return true; } -fn bool List.contains(List* list, Type type) +/** + * Check for presence of a value in a list. + * + * @param [&in] list "the list to find elements in" + * @param value "The value to search for" + * @return "True if the value is found, false otherwise" + **/ +fn bool List.contains(List* list, Type value) { foreach (i, v : list) { - if (v == type) return true; + if (v == value) return true; } return false; } +/** + * @param [&inout] list "The list to remove elements from" + * @param value "The value to remove" + * @return "the number of deleted elements." + **/ +fn usz List.delete(List* list, Type value) +{ + usz size = list.size; + for (usz i = size; i > 0; i--) + { + if (list.entries[i - 1] != value) continue; + for (usz j = i; j < size; j++) + { + list.entries[j - 1] = list.entries[j]; + } + list.size--; + } + return size - list.size; +} + $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; +$if (Type.kindof == POINTER) - 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); +/** + * @param [&in] list + * @return "The number non-null values in the list" + **/ +fn usz List.compact_count(List* list) +{ + usz vals = 0; + foreach (v : list) if (v) vals++; + return vals; } + +fn usz List.compact(List* list) +{ + usz size = list.size; + for (usz i = size; i > 0; i--) + { + if (list.entries[i - 1]) continue; + for (usz j = i; j < size; j++) + { + list.entries[j - 1] = list.entries[j]; + } + list.size--; + } + return size - list.size; +} + +$endif \ No newline at end of file diff --git a/lib/std/core/array.c3 b/lib/std/core/array.c3 index 833ec238e..f62918b4e 100644 --- a/lib/std/core/array.c3 +++ b/lib/std/core/array.c3 @@ -3,7 +3,7 @@ module std::core::array; /** * @param [in] array * @param [in] element - * @return "the index of the element" + * @return "the first index of the element" * @return! SearchResult.MISSING **/ macro index_of(array, element) @@ -15,11 +15,27 @@ macro index_of(array, element) return SearchResult.MISSING?; } +/** + * @param [in] array + * @param [in] element + * @return "the last index of the element" + * @return! SearchResult.MISSING + **/ +macro rindex_of(array, element) +{ + foreach_r (i, &e : array) + { + if (*e == element) return i; + } + return SearchResult.MISSING?; +} + /** * Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them. * * @param [in] arr1 * @param [in] arr2 + * @param [&inout] using "The allocator to use, default is the heap allocator" * @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" @@ -40,4 +56,15 @@ macro concat(arr1, arr2, Allocator* using = mem::heap()) return result; } +/** + * Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them, + * allocated using the temp allocator. + * + * @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 tconcat(arr1, arr2) => concat(arr1, arr2, mem::temp()); diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 19b613531..a020e78da 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -122,7 +122,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...) /** * 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" + * @param [in] string "The panic message or format string" **/ macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn { @@ -130,6 +130,16 @@ macro void unreachable(String string = "Unreachable statement reached.", ...) @b $$unreachable(); } +/** + * Marks the path as unsupported, this is similar to unreachable. + * @param [in] string "The error message" + **/ +macro void unsupported(String string = "Unsupported function invoked") @builtin @noreturn +{ + panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat()); + $$unreachable(); +} + /** * @param expr "the expression to cast" * @param $Type "the type to cast to" diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 8ee1ee924..3b43b947c 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -130,7 +130,7 @@ const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT; macro bool os_is_win32() { - return OS_TYPE == OsType.WIN32; + return OS_TYPE == WIN32; } macro bool os_is_darwin() @@ -177,7 +177,7 @@ macro bool os_is_posix() **/ fn String! get_var(String name) { -$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32) +$if (COMPILER_LIBC_AVAILABLE && !os_is_win32()) @pool() { ZString val = libc::getenv(name.zstr_tcopy()); @@ -196,7 +196,7 @@ $endif **/ fn void set_var(String name, String value, bool overwrite = true) { -$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32) +$if (COMPILER_LIBC_AVAILABLE && !os_is_win32()) @pool() { if (libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite)) @@ -213,7 +213,7 @@ $endif **/ fn void clear_var(String name) { -$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32) +$if (COMPILER_LIBC_AVAILABLE && !os_is_win32()) @pool() { if (libc::unsetenv(name.zstr_tcopy())) diff --git a/lib/std/core/private/main_stub.c3 b/lib/std/core/private/main_stub.c3 index d77f7f278..b8066f7b3 100644 --- a/lib/std/core/private/main_stub.c3 +++ b/lib/std/core/private/main_stub.c3 @@ -55,7 +55,7 @@ macro int @main_to_void_main_args(#m, int argc, char** argv) return 0; } -$if (env::OS_TYPE == OsType.WIN32) +$if (env::os_is_win32()) extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @extern("CommandLineToArgvW"); diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index d0677bc82..1ffb7c656 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -59,7 +59,7 @@ extern fn int rand(); extern fn void srand(uint seed); extern fn void longjmp(JmpBuf* buffer, CInt value); -$if (env::OS_TYPE == OsType.WIN32) +$if (env::os_is_win32()) // TODO win32 aarch64 extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer); macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(), buffer); @@ -152,7 +152,7 @@ typedef Fpos = long; typedef CFile = void*; $switch -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.LINUX: +$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX: extern CFile __stdin @extern("stdin"); extern CFile __stdout @extern("stdout"); extern CFile __stderr @extern("stderr"); @@ -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.MACOS: +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_darwin(): extern CFile __stdinp; extern CFile __stdoutp; extern CFile __stderrp; @@ -171,7 +171,7 @@ $case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOS: macro CFile stdin() { return __stdinp; } macro CFile stdout() { return __stdoutp; } macro CFile stderr() { return __stderrp; } -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.WIN32: +$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): extern fn CFile __acrt_iob_func(CInt c); extern fn usz _msize(void* ptr); macro usz malloc_size(void* ptr) { return _msize(ptr); } @@ -185,9 +185,9 @@ $default: $endswitch const HAS_MALLOC_SIZE = - env::OS_TYPE == OsType.LINUX - || env::OS_TYPE == OsType.WIN32 - || env::OS_TYPE == OsType.MACOS; + env::OS_TYPE == LINUX + || env::os_is_win32() + || env::os_is_darwin(); // The following needs to be set per arch+os // For now I have simply pulled the defaults from MacOS diff --git a/lib/std/net/os/darwin.c3 b/lib/std/net/os/darwin.c3 index e73353a3d..d057b3153 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.MACOS) +$if (env::os_is_darwin()) const AI_NUMERICSERV = 0x1000; const AI_ALL = 0x100; diff --git a/lib/std/net/os/linux.c3 b/lib/std/net/os/linux.c3 index ac4b5caa6..a8d5a60cb 100644 --- a/lib/std/net/os/linux.c3 +++ b/lib/std/net/os/linux.c3 @@ -1,7 +1,7 @@ module std::net::os; import libc; -$if (env::OS_TYPE == OsType.LINUX) +$if (env::OS_TYPE == LINUX) struct AddrInfo { diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index d07bc2baa..9677e03f9 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -1,7 +1,7 @@ module std::net::os; import libc; -$if (env::OS_TYPE != OsType.WIN32 && $defined(AddrInfo)) +$if (env::os_is_win32() && $defined(AddrInfo)) const int F_GETFL = 3; const int F_SETFL = 4; diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index 672375f93..fa09acc38 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -1,6 +1,6 @@ module std::net::os; -$if (env::OS_TYPE == OsType.WIN32) +$if (env::os_is_win32()) const int PLATFORM_AF_INET = 1; const int PLATFORM_AF_IPX = 6; diff --git a/lib/std/os/macos/cf_allocator.c3 b/lib/std/os/macos/cf_allocator.c3 index f0b468fc6..ac61a201e 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.MACOS) +$if (env::os_is_darwin()) 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 2d45deab4..18ea90883 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.MACOS) +$if (env::os_is_darwin()) 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 8143f9519..86a806c59 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.MACOS) +$if (env::os_is_darwin()) typedef CFTypeRef = distinct void*; typedef CFIndex = isz; diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index f4afdb476..c2d63a8dd 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.MACOS) +$if (env::os_is_darwin()) typedef Class = distinct void*; typedef Method = distinct void*; diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index 8dc2ea941..394286499 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -14,7 +14,7 @@ typedef NativeOnceFlag = PthreadOnce; typedef Pthread = distinct void*; -$if (env::OS_TYPE == OsType.LINUX) +$if (env::OS_TYPE == LINUX) typedef PthreadMutex = distinct ulong[5]; typedef PthreadAttribute = distinct ulong[7]; typedef PthreadMutexAttribute = distinct uint; diff --git a/lib/std/threads/thread.c3 b/lib/std/threads/thread.c3 index 54bc4c94f..c292e4f40 100644 --- a/lib/std/threads/thread.c3 +++ b/lib/std/threads/thread.c3 @@ -8,7 +8,7 @@ enum ThreadModel } const ThreadModel THREAD_MODEL = env::COMPILER_LIBC_AVAILABLE - ? (env::OS_TYPE == OsType.WIN32 ? ThreadModel.WIN32 : ThreadModel.POSIX) + ? (env::os_is_win32() ? ThreadModel.WIN32 : ThreadModel.POSIX) : ThreadModel.NONE; typedef MutexType = distinct int; diff --git a/releasenotes.md b/releasenotes.md index 2e80aa9d0..624db88e2 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -77,7 +77,7 @@ ### Stdlib changes - Stdlib updates to string. -- Additions to `List` +- Many additions to `List`: `delete`, `array_view`, `add_all`, `compact` etc - Added dstringwriter. - Improved printf formatting. - is_finite/is_nam/is_inf added. diff --git a/resources/testproject/hello_world.c3 b/resources/testproject/hello_world.c3 index dea16be15..bf26977b0 100644 --- a/resources/testproject/hello_world.c3 +++ b/resources/testproject/hello_world.c3 @@ -1,7 +1,7 @@ module hello_world; import std; import bar; -$if (env::OS_TYPE == OsType.WIN32) +$if (env::os_is_win32()) fn int test_doubler(int x) { return x * x; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index bb2322ea5..c499bef22 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -133,6 +133,11 @@ static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *curr static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl) { + if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); + if (decl->resolve_status == RESOLVE_RUNNING) + { + RETURN_SEMA_ERROR(decl, "Circular dependency resolving member."); + } assert(!decl->unit || decl->unit->module->is_generic); decl->unit = parent->unit; if (decl->name) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8caa06dbc..7e60c6210 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -157,7 +157,7 @@ static inline Expr *sema_ct_checks_exprlist_compiles(SemaContext *context, Expr static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr); static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *expr, Expr *typeid, const char *kw); static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, Type *type, TypeProperty property, - AlignSize alignment, AlignSize offset); + Type *parent_type); static bool sema_expr_rewrite_typeid_call(Expr *expr, Expr *typeid, TypeIdInfoKind kind, Type *result_type); static inline void sema_expr_rewrite_typeid_kind(Expr *expr, Expr *parent); static inline void sema_expr_replace_with_enum_array(Expr *enum_array_expr, Decl *enum_decl); @@ -177,8 +177,8 @@ static inline int64_t expr_get_index_max(Expr *expr); static inline bool expr_both_any_integer_or_integer_vector(Expr *left, Expr *right); static inline bool expr_both_any_integer_or_integer_bool_vector(Expr *left, Expr *right); static inline bool expr_both_const(Expr *left, Expr *right); -static inline bool sema_identifier_find_possible_inferred(Type *to, Expr *expr); -static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl); +static inline bool sema_identifier_find_possible_inferred(SemaContext *context, Type *to, Expr *expr); +static inline bool sema_expr_analyse_enum_constant(SemaContext *context, Expr *expr, const char *name, Decl *decl); static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr); static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr); @@ -712,9 +712,11 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) return true; } -static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl) +static inline bool sema_expr_analyse_enum_constant(SemaContext *context, Expr *expr, const char *name, Decl *decl) { Decl *enum_constant = decl_find_enum_constant(decl, name); + + if (!sema_resolve_type_decl(context, decl->type)) return false; if (!enum_constant) return false; assert(enum_constant->resolve_status == RESOLVE_DONE); @@ -726,7 +728,7 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, } -static inline bool sema_identifier_find_possible_inferred(Type *to, Expr *expr) +static inline bool sema_identifier_find_possible_inferred(SemaContext *context, Type *to, Expr *expr) { if (to->canonical->type_kind != TYPE_ENUM && to->canonical->type_kind != TYPE_FAULTTYPE) return false; Decl *parent_decl = to->canonical->decl; @@ -734,7 +736,7 @@ static inline bool sema_identifier_find_possible_inferred(Type *to, Expr *expr) { case DECL_ENUM: case DECL_FAULT: - return sema_expr_analyse_enum_constant(expr, expr->identifier_expr.ident, parent_decl); + return sema_expr_analyse_enum_constant(context, expr, expr->identifier_expr.ident, parent_decl); case DECL_UNION: case DECL_STRUCT: case DECL_BITSTRUCT: @@ -770,7 +772,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, // Just start with inference if (!expr->identifier_expr.path && to) { - if (sema_identifier_find_possible_inferred(to, expr)) return true; + if (sema_identifier_find_possible_inferred(context, to, expr)) return true; } Decl *decl = sema_find_path_symbol(context, expr->identifier_expr.ident, expr->identifier_expr.path); @@ -2760,6 +2762,7 @@ static inline void sema_expr_replace_with_enum_array(Expr *enum_array_expr, Decl static inline void sema_expr_replace_with_enum_name_array(Expr *enum_array_expr, Decl *enum_decl) { + Decl **values = enum_decl->enums.values; SourceSpan span = enum_array_expr->span; Expr *initializer = expr_new(EXPR_INITIALIZER_LIST, span); @@ -2789,10 +2792,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp if (!is_const) { - AlignSize align; - 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 (sema_expr_rewrite_to_type_property(context, expr, canonical, type_property_by_name(name), parent_type)) return true; } if (!type_may_have_sub_elements(canonical)) @@ -2810,7 +2810,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp case DECL_ENUM: if (is_const) { - if (!sema_expr_analyse_enum_constant(expr, name, decl)) + if (!sema_expr_analyse_enum_constant(context, expr, name, decl)) { SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name); return false; @@ -2822,7 +2822,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp unit_register_external_symbol(context->compilation_unit, decl); if (is_const) { - if (!sema_expr_analyse_enum_constant(expr, name, decl)) + if (!sema_expr_analyse_enum_constant(context, expr, name, decl)) { SEMA_ERROR(expr, "'%s' has no error value '%s'.", decl->name, name); return false; @@ -2924,9 +2924,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e return true; case TYPE_PROPERTY_KINDOF: case TYPE_PROPERTY_SIZEOF: - if (sema_expr_rewrite_to_type_property(context, expr, decl->type, type_property, - parent->const_expr.member.align, - parent->const_expr.member.offset)) return true; + if (sema_expr_rewrite_to_type_property(context, expr, decl->type, type_property, decl->type)) return true; return true; case TYPE_PROPERTY_ELEMENTS: case TYPE_PROPERTY_EXTNAMEOF: @@ -3008,6 +3006,7 @@ static inline bool sema_create_const_kind(Expr *expr, Type *type) static inline bool sema_create_const_len(SemaContext *context, Expr *expr, Type *type) { assert(type == type_flatten(type) && "Should be flattened already."); + size_t len; switch (type->type_kind) { @@ -3031,6 +3030,7 @@ static inline bool sema_create_const_len(SemaContext *context, Expr *expr, Type static inline bool sema_create_const_inner(SemaContext *context, Expr *expr, Type *type) { + if (!sema_resolve_type_decl(context, type)) return false; Type *inner = NULL; switch (type->type_kind) { @@ -3283,9 +3283,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp if (typeid->expr_kind == EXPR_CONST) { Type *type = typeid->const_expr.typeid; - AlignSize align; - if (!sema_set_abi_alignment(context, type, &align)) return false; - return sema_expr_rewrite_to_type_property(context, expr, type, property, align, 0); + return sema_expr_rewrite_to_type_property(context, expr, type, property, type); } switch (property) { @@ -3379,7 +3377,7 @@ EVAL: } static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, Type *type, TypeProperty property, - AlignSize alignment, AlignSize offset) + Type *parent_type) { assert(type == type->canonical); if (property == TYPE_PROPERTY_NONE) return false; @@ -3407,16 +3405,19 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, return sema_create_const_max(context, expr, type, flat); case TYPE_PROPERTY_NAMES: if (!type_kind_is_enumlike(flat->type_kind)) return false; + if (!sema_resolve_type_decl(context, type)) 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; + if (!sema_resolve_type_decl(context, type)) return false; expr_rewrite_const_int(expr, type_isz, vec_size(flat->decl->enums.values)); return true; case TYPE_PROPERTY_VALUES: if (!type_kind_is_enumlike(flat->type_kind)) return false; + if (!sema_resolve_type_decl(context, type)) return false; sema_expr_replace_with_enum_array(expr, flat->decl); return sema_analyse_expr(context, expr); case TYPE_PROPERTY_NAN: @@ -3428,8 +3429,12 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, expr->resolve_status = RESOLVE_DONE; return true; case TYPE_PROPERTY_MEMBERSOF: - sema_create_const_membersof(context, expr, flat, alignment, offset); + { + AlignSize align; + if (!sema_set_abi_alignment(context, parent_type, &align)) return false; + sema_create_const_membersof(context, expr, flat, align, 0); 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); @@ -3439,12 +3444,15 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, expr_rewrite_const_typeid(expr, type_infoptr(flat->function.signature->rtype)->type); return true; case TYPE_PROPERTY_SIZEOF: + if (!sema_resolve_type_decl(context, type)) return false; expr_rewrite_const_int(expr, type_usz, type_size(type)); return true; case TYPE_PROPERTY_NAMEOF: + if (!sema_resolve_type_decl(context, type)) return false; sema_expr_rewrite_to_type_nameof(expr, type, TOKEN_CT_NAMEOF); return true; case TYPE_PROPERTY_QNAMEOF: + if (!sema_resolve_type_decl(context, type)) return false; sema_expr_rewrite_to_type_nameof(expr, type, TOKEN_CT_QNAMEOF); return true; case TYPE_PROPERTY_ALIGNOF: @@ -3456,6 +3464,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, } case TYPE_PROPERTY_EXTNAMEOF: if (type_is_builtin(type->type_kind)) return false; + if (!sema_resolve_type_decl(context, type)) return false; sema_expr_rewrite_to_type_nameof(expr, type, TOKEN_CT_EXTNAMEOF); return true; case TYPE_PROPERTY_NONE: diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 555437b74..b61db37c2 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -622,6 +622,7 @@ Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_ return sema_resolve_type_method(unit, type->type, method_name, ambiguous_ref, private_ref); } + bool sema_resolve_type_decl(SemaContext *context, Type *type) { switch (type->type_kind) diff --git a/src/version.h b/src/version.h index 20885b636..93ea1a6ab 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.500" \ No newline at end of file +#define COMPILER_VERSION "0.4.501" \ No newline at end of file diff --git a/test/unit/stdlib/collections/linkedlist.c3 b/test/unit/stdlib/collections/linkedlist.c3 index 742ec93a6..923d05152 100644 --- a/test/unit/stdlib/collections/linkedlist.c3 +++ b/test/unit/stdlib/collections/linkedlist.c3 @@ -1,9 +1,9 @@ -module linkedlist_test; +module linkedlist_test @test; import std::collections::linkedlist; typedef IntList = LinkedList; -fn void! test_push() @test +fn void! test_push() { IntList list; list.push(23); @@ -16,7 +16,7 @@ fn void! test_push() @test assert(list.first()! == 55); } -fn void! test_push_last() @test +fn void! test_push_last() { IntList list; list.push_last(23); @@ -29,7 +29,7 @@ fn void! test_push_last() @test assert(list.first()! == 23); } -fn void! test_get() @test +fn void! test_get() { IntList list; list.push(23); @@ -40,7 +40,7 @@ fn void! test_get() @test assert(list.get(2) == 23); } -fn void! test_insert() @test +fn void! test_insert() { IntList list; list.push(23); @@ -59,7 +59,7 @@ fn void! test_insert() @test assert(list.get(6) == 1111); } -fn void! test_set() @test +fn void! test_set() { IntList list; list.push(23); @@ -71,7 +71,7 @@ fn void! test_set() @test assert(list.get(2) == 24); } -fn void! test_remove() @test +fn void! test_remove() { IntList list; for (int i = 0; i < 10; i++) list.push(i); @@ -84,7 +84,7 @@ fn void! test_remove() @test assert(list.get(5) == 1); assert(list.get(4) == 3); } -fn void! test_remove_value() @test +fn void! test_remove_value() { IntList list; list.push(23); @@ -112,7 +112,7 @@ fn void! test_remove_value() @test assert(!list.len()); } -fn void! test_remove_last_value() @test +fn void! test_remove_last_value() { IntList list; list.push(23); @@ -140,7 +140,7 @@ fn void! test_remove_last_value() @test assert(!list.len()); } -fn void! test_pop() @test +fn void! test_pop() { IntList list; list.push(23); @@ -164,7 +164,7 @@ fn void! test_pop() @test assert(list.len() == 1); } -fn void! test_remove_first() @test +fn void! test_remove_first() { IntList list; list.push(23); @@ -188,7 +188,7 @@ fn void! test_remove_first() @test assert(list.len() == 1); } -fn void! test_remove_last() @test +fn void! test_remove_last() { IntList list; list.push(23); diff --git a/test/unit/stdlib/collections/list.c3 b/test/unit/stdlib/collections/list.c3 new file mode 100644 index 000000000..3bf2cf05e --- /dev/null +++ b/test/unit/stdlib/collections/list.c3 @@ -0,0 +1,45 @@ +module listtests @test; +import std::collections::list; + +typedef IntList = List; +typedef PtrList = List; + +fn void! test_delete_contains_index() +{ + IntList test; + test.add_array({ 1, 2 }); + assert(test.contains(1)); + assert(test.contains(2)); + assert(!test.contains(0)); + assert(!test.contains(3)); + assert(test.array_view() == int[]{ 1, 2 }); + test.push(3); + assert(test.array_view() == int[]{ 1, 2, 3 }); + assert(test.contains(3)); + test.delete(1); + assert(test.array_view() == int[]{ 2, 3 }); + assert(!test.contains(1)); + assert(test.contains(2)); + assert(test.len() == 2); + test.push(0); + test.insert_at(0, 0); + assert(test.array_view() == int[]{ 0, 2, 3, 0 }); + assert(test.index_of(0)! == 0); + assert(test.rindex_of(0)! == 3); + test.delete(0); + assert(test.len() == 2); + assert(test.array_view() == int[]{ 2, 3 }); +} + +fn void! test_compact() +{ + PtrList test; + test.add_array({ null, &test }); + assert(test.compact_count() == 1); + test.push(null); + assert(test.compact_count() == 1); + assert(test.len() == 3); + assert(test.compact() == 2); + assert(test.len() == 1); + assert(test.compact() == 0); +} \ No newline at end of file