From abf0f64ac0a2cedef2c84ee7edc12b65c1933a6e Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 14 Dec 2022 10:55:35 +0100 Subject: [PATCH] Share method extensions across modules by default. Fix bug in string split. --- lib/std/core/str.c3 | 2 +- lib/std/math.c3 | 9 ++++++++ src/compiler/compiler.c | 1 + src/compiler/compiler_internal.h | 5 +++-- src/compiler/sema_decls.c | 21 +++++++++++++------ src/compiler/sema_name_resolution.c | 10 ++++++--- src/version.h | 2 +- .../macro_methods_defined_twice.c3 | 5 +++-- .../methods/methods_defined_twice.c3 | 2 +- .../macro_methods_defined_twice.c3 | 5 +++-- .../methods/methods_defined_twice.c3 | 2 +- 11 files changed, 45 insertions(+), 19 deletions(-) diff --git a/lib/std/core/str.c3 b/lib/std/core/str.c3 index 0084db41d..24ea1aeb7 100644 --- a/lib/std/core/str.c3 +++ b/lib/std/core/str.c3 @@ -172,7 +172,7 @@ fn char[][] split(char[] s, char[] needle, Allocator* allocator = mem::current_a if (i == capacity) { capacity *= 2; - holder = allocator.realloc(holder, capacity)!!; + holder = allocator.realloc(holder, char[].sizeof * capacity)!!; } holder[i++] = res; } diff --git a/lib/std/math.c3 b/lib/std/math.c3 index 26abe431e..355c14cae 100644 --- a/lib/std/math.c3 +++ b/lib/std/math.c3 @@ -86,6 +86,15 @@ define Complex64 = Complex; **/ macro abs(x) = $$abs(x); +/** + * @require values::@is_int(x) `The input must be an integer` + **/ +macro sign(x) +{ + if (!x) return ($typeof(x))0; + return ($typeof(x))(x < 0 ? -1 : 1); +} + /** * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` **/ diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 66898ff15..45dc4b9ef 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -51,6 +51,7 @@ void compiler_init(const char *std_lib_dir) htable_init(&global_context.compiler_defines, 16 * 1024); global_context.module_list = NULL; global_context.generic_module_list = NULL; + global_context.method_extensions = NULL; vmem_init(&ast_arena, 512); ast_calloc(); vmem_init(&expr_arena, 512); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7b96a2a8b..cda4669c3 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1452,7 +1452,7 @@ typedef struct Module_ AnalysisStage stage : 6; AstId docs; - Decl** method_extensions; + Decl** private_method_extensions; HTable symbols; struct CompilationUnit_ **units; Module *parent_module; @@ -1645,6 +1645,7 @@ typedef struct Module **module_list; Module **generic_module_list; Type **type; + Decl** method_extensions; const char *lib_dir; const char **sources; File **loaded_sources; @@ -2204,7 +2205,7 @@ Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *in Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve); Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref); Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref); -Decl *sema_find_extension_method_in_module(Module *module, Type *type, const char *method_name); +Decl *sema_find_extension_method_in_module(Decl **extensions, Type *type, const char *method_name); Decl *sema_find_symbol(SemaContext *context, const char *symbol); Decl *sema_find_path_symbol(SemaContext *context, const char *symbol, Path *path); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 8271ed196..d91a0d145 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1184,7 +1184,7 @@ static bool sema_analyse_operator_common(Decl *method, TypeInfo **rtype_ptr, Dec static inline Decl *operator_in_module(SemaContext *c, Module *module, OperatorOverload operator_overload) { if (module->is_generic) return NULL; - Decl **extensions = module->method_extensions; + Decl **extensions = module->private_method_extensions; VECEACH(extensions, j) { Decl *extension = extensions[j]; @@ -1299,7 +1299,14 @@ static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *p method_like->extname = scratch_buffer_copy(); } DEBUG_LOG("Method-like '%s.%s' analysed.", parent_type->name, method_like->name); - vec_add(unit->module->method_extensions, method_like); + if (method_like->visibility == VISIBLE_LOCAL) + { + vec_add(unit->module->private_method_extensions, method_like); + } + else + { + vec_add(global_context.method_extensions, method_like); + } return true; } @@ -1307,13 +1314,15 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type { assert(parent_type->canonical == parent_type); const char *name = method_like->name; - Decl *method = sema_find_extension_method_in_module(unit->module, parent_type, name); + Decl *method = sema_find_extension_method_in_module(unit->module->private_method_extensions, parent_type, name); + if (!method) sema_find_extension_method_in_module(global_context.method_extensions, parent_type, name); if (method) { - SEMA_ERROR(method_like, "This %s is already defined in this module.", method_name_by_decl(method_like)); + SEMA_ERROR(method_like, "This %s is already defined.", method_name_by_decl(method_like)); SEMA_NOTE(method, "The previous definition was here."); return false; } + if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(unit, parent_type, method_like); Decl *parent = parent_type->decl; Decl *ambiguous = NULL; @@ -1346,13 +1355,13 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type method_like->extname = scratch_buffer_copy(); } DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method_like->name); - if (parent->unit->module == unit->module) + if (parent->unit->module == unit->module || method_like->visibility != VISIBLE_LOCAL) { vec_add(parent->methods, method_like); } else { - vec_add(unit->module->method_extensions, method_like); + vec_add(unit->module->private_method_extensions, method_like); } return true; diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index d44f618c4..d85f7194c 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -568,9 +568,8 @@ INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_ return decl; } -Decl *sema_find_extension_method_in_module(Module *module, Type *type, const char *method_name) +Decl *sema_find_extension_method_in_module(Decl **extensions, Type *type, const char *method_name) { - Decl **extensions = module->method_extensions; VECEACH(extensions, i) { Decl *extension = extensions[i]; @@ -593,7 +592,7 @@ Decl *sema_resolve_method_in_module(Module *module, Type *actual_type, const cha Decl **private_found, Decl **ambiguous, MethodSearchType search_type) { if (module->is_generic) return NULL; - Decl *found = sema_find_extension_method_in_module(module, actual_type, method_name); + Decl *found = sema_find_extension_method_in_module(module->private_method_extensions, actual_type, method_name); // The found one might not be visible if (found && search_type < METHOD_SEARCH_CURRENT && found->visibility < VISIBLE_PUBLIC) { @@ -676,6 +675,11 @@ Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *me *ambiguous_ref = ambiguous; return found; } + if (!found) + { + found = sema_find_extension_method_in_module(global_context.method_extensions, type, method_name); + private = NULL; + } if (private) *private_ref = private; if (!found) { diff --git a/src/version.h b/src/version.h index afac6961e..71e4bb12a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.117" \ No newline at end of file +#define COMPILER_VERSION "0.3.118" \ No newline at end of file diff --git a/test/test_suite/macro_methods/macro_methods_defined_twice.c3 b/test/test_suite/macro_methods/macro_methods_defined_twice.c3 index 8bb57cdd0..ebfd29857 100644 --- a/test/test_suite/macro_methods/macro_methods_defined_twice.c3 +++ b/test/test_suite/macro_methods/macro_methods_defined_twice.c3 @@ -14,14 +14,15 @@ macro void foo::Bar.@test(Bar &bar) io::println("Inside of baz::Bar.test"); } -macro void Bar.@test(Bar &bar) // #error: This macro method is already defined in this module +module bad; +import foo; +macro void Bar.@test(Bar &bar) // #error: This macro method is already defined for 'Bar'. { io::println("Inside of baz::Bar.test"); } module abc; import foo; -import baz; fn void main() { diff --git a/test/test_suite/methods/methods_defined_twice.c3 b/test/test_suite/methods/methods_defined_twice.c3 index 60d809b6f..b03f6580c 100644 --- a/test/test_suite/methods/methods_defined_twice.c3 +++ b/test/test_suite/methods/methods_defined_twice.c3 @@ -14,7 +14,7 @@ fn void foo::Bar.test(Bar *bar) io::println("Inside of baz::Bar.test"); } -fn void Bar.test(Bar *bar) // #error: This method is already defined in this module +fn void Bar.test(Bar *bar) // #error: This method is already defined for { io::println("Inside of baz::Bar.test"); } diff --git a/test/test_suite2/macro_methods/macro_methods_defined_twice.c3 b/test/test_suite2/macro_methods/macro_methods_defined_twice.c3 index 8bb57cdd0..ebfd29857 100644 --- a/test/test_suite2/macro_methods/macro_methods_defined_twice.c3 +++ b/test/test_suite2/macro_methods/macro_methods_defined_twice.c3 @@ -14,14 +14,15 @@ macro void foo::Bar.@test(Bar &bar) io::println("Inside of baz::Bar.test"); } -macro void Bar.@test(Bar &bar) // #error: This macro method is already defined in this module +module bad; +import foo; +macro void Bar.@test(Bar &bar) // #error: This macro method is already defined for 'Bar'. { io::println("Inside of baz::Bar.test"); } module abc; import foo; -import baz; fn void main() { diff --git a/test/test_suite2/methods/methods_defined_twice.c3 b/test/test_suite2/methods/methods_defined_twice.c3 index 60d809b6f..b03f6580c 100644 --- a/test/test_suite2/methods/methods_defined_twice.c3 +++ b/test/test_suite2/methods/methods_defined_twice.c3 @@ -14,7 +14,7 @@ fn void foo::Bar.test(Bar *bar) io::println("Inside of baz::Bar.test"); } -fn void Bar.test(Bar *bar) // #error: This method is already defined in this module +fn void Bar.test(Bar *bar) // #error: This method is already defined for { io::println("Inside of baz::Bar.test"); }