From 3a7bc4d253b9d4901c1445d53706f06389e9ba2b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 20 Jun 2024 20:47:24 +0200 Subject: [PATCH] Return the typekind "FUNC" for a function pointer. --- lib/std/sort/sort.c3 | 33 ++++++++++++--------- releasenotes.md | 1 + src/compiler/sema_decls.c | 61 +++++++++++++-------------------------- src/compiler/sema_expr.c | 6 ++-- 4 files changed, 44 insertions(+), 57 deletions(-) diff --git a/lib/std/sort/sort.c3 b/lib/std/sort/sort.c3 index c88bc4920..e2ecad10f 100644 --- a/lib/std/sort/sort.c3 +++ b/lib/std/sort/sort.c3 @@ -12,22 +12,27 @@ macro usz @len_from_list(&list) macro bool @is_comparer(#cmp, #list) { - var $params = $typeof(#cmp).params; - $if $params.len != 2: - return false; - $else - $if $params[0] != $params[1]: + var $Type = $typeof(#cmp); + $if $and($Type.kindof == FUNC, $Type.returns.kindof == SIGNED_INT): + var $params = $Type.params; + $if $params.len != 2: return false; $else - var $element = @typeid(#list[0]); - $switch - $case $element == $params[0]: - return true; - $case $and($params[0].kindof == POINTER, $params[0].inner == $element): - return true; - $default: - return false; - $endswitch + $if $params[0] != $params[1]: + return false; + $else + var $element = @typeid(#list[0]); + $switch + $case $element == $params[0]: + return true; + $case $and($params[0].kindof == POINTER, $params[0].inner == $element): + return true; + $default: + return false; + $endswitch + $endif $endif + $else + return false; $endif } \ No newline at end of file diff --git a/releasenotes.md b/releasenotes.md index 558d22155..08b2cb2bc 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -12,6 +12,7 @@ - Prevent Mach-O from removing `@init` and `@dynamic` in a more reliable way #1200. - Fix of missing copy of parameterized custom attributes. - Fixed crash on certain recursive function definitions #1209. +- Return the typekind "FUNC" for a function pointer. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 40f6068ca..dbb6034ad 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1997,7 +1997,7 @@ static inline Decl *sema_find_interface_for_method(SemaContext *context, Canonic * * 1. Check return types. * 2. Check parameter count. - * 3. Check each parameter for matching types (TODO, should there be more checks?) + * 3. Check each parameter for matching types * * @return true if it matches, false otherwise. */ @@ -2670,10 +2670,7 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr } // Walk through all of the attributes. - int count = vec_size(attrs); - for (int i = 0; i < count; i++) - { - Attr *attr = attrs[i]; + FOREACH_BEGIN(Attr *attr, attrs) if (attr->is_custom) { if (!sema_analyse_custom_attribute(context, decl, attr, domain, top, erase_decl)) return false; @@ -2684,7 +2681,7 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr if (!sema_analyse_attribute(context, decl, attr, domain, erase_decl)) return false; } if (*erase_decl) return true; - } + FOREACH_END(); return true; } @@ -2772,7 +2769,6 @@ static inline MainType sema_find_main_type(SemaContext *context, Signature *sig, { case 0: return MAIN_TYPE_NO_ARGS; - break; case 1: arg_type = type_flatten(params[0]->type); if (arg_type == type_get_slice(type_string)) return MAIN_TYPE_ARGS; @@ -3003,8 +2999,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) if (is_int_return && type_flatten(rtype) != type_cint) { - SEMA_ERROR(rtype_info, "Expected a return type of 'void' or %s.", type_quoted_error_string(type_cint)); - return false; + RETURN_SEMA_ERROR(rtype_info, "Expected a return type of 'void' or %s.", type_quoted_error_string(type_cint)); } // At this point the style is either MAIN_INT_VOID, MAIN_VOID_VOID or MAIN_ERR_VOID MainType type = sema_find_main_type(context, signature, is_winmain); @@ -3018,8 +3013,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) } if (type == MAIN_TYPE_RAW && !is_int_return) { - SEMA_ERROR(rtype_info, "Int return is required for C style main."); - return false; + RETURN_SEMA_ERROR(rtype_info, "Int return is required for a C style main."); } // Suppress winmain on non-win32 if (platform_target.os != OS_TYPE_WIN32) is_winmain = false; @@ -3055,10 +3049,7 @@ REGISTER_MAIN: static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl) { assert((domain & CALLABLE_TYPE) == domain); - if (!sema_analyse_attributes(context, - decl, - decl->attributes, - domain, + if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); return true; } @@ -3084,9 +3075,8 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era assert(!is_interface_method); if (vec_size(sig->params)) { - SEMA_ERROR(sig->params[0], "%s functions may not take any parameters.", + RETURN_SEMA_ERROR(sig->params[0], "%s functions may not take any parameters.", is_init_finalizer ? "'@init' and '@finalizer'" : "'@test' and '@benchmark'"); - return decl_poison(decl); } TypeInfo *rtype_info = type_infoptr(sig->rtype); if (!sema_resolve_type_info(context, rtype_info, RESOLVE_TYPE_DEFAULT)) return false; @@ -3095,16 +3085,14 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era { if (rtype->canonical != type_void) { - SEMA_ERROR(rtype_info, "'@init' and '@finalizer' functions may only return 'void'."); - return decl_poison(decl); + RETURN_SEMA_ERROR(rtype_info, "'@init' and '@finalizer' functions may only return 'void'."); } } else { if (type_no_optional(rtype) != type_void) { - SEMA_ERROR(rtype_info, "'@test' and '@benchmark' functions may only return 'void' or 'void!'."); - return decl_poison(decl); + RETURN_SEMA_ERROR(rtype_info, "'@test' and '@benchmark' functions may only return 'void' or 'void!'."); } if (type_is_void(rtype)) { @@ -3122,37 +3110,28 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era { if (type_is_void(rtype)) { - SEMA_ERROR(rtype_info, "@nodiscard cannot be used on functions returning 'void'."); - return decl_poison(decl); + RETURN_SEMA_ERROR(rtype_info, "@nodiscard cannot be used on functions returning 'void'."); } } - if (sig->attrs.maydiscard) + if (sig->attrs.maydiscard && !type_is_optional(rtype)) { - if (!type_is_optional(rtype)) - { - SEMA_ERROR(rtype_info, "@maydiscard can only be used on functions returning optional values."); - return decl_poison(decl); - } + RETURN_SEMA_ERROR(rtype_info, "@maydiscard can only be used on functions returning optional values."); } + if (decl->func_decl.type_parent) { - if (!sema_analyse_method(context, decl)) return decl_poison(decl); + if (!sema_analyse_method(context, decl)) return false; } else if (!is_interface_method) { - if (decl->func_decl.attr_dynamic) - { - SEMA_ERROR(decl, "Only methods may implement interfaces."); - return decl_poison(decl); - } + if (decl->func_decl.attr_dynamic) RETURN_SEMA_ERROR(decl, "Only methods may implement interfaces."); if (decl->name == kw_main) { if (is_test || is_benchmark) { - SEMA_ERROR(decl, "The main function may not be annotated %s.", is_test ? "@test" : "@benchmark"); - return decl_poison(decl); + RETURN_SEMA_ERROR(decl, "The main function may not be annotated %s.", is_test ? "@test" : "@benchmark"); } - if (!sema_analyse_main_function(context, decl)) return decl_poison(decl); + if (!sema_analyse_main_function(context, decl)) return false; } decl_set_external_name(decl); } @@ -3160,12 +3139,12 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era // Do we have fn void any.foo(void*) { ... }? if (!decl->func_decl.body && !decl->is_extern && !decl->unit->is_interface_file && !is_interface_method) { - SEMA_ERROR(decl, "Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file."); - return false; + RETURN_SEMA_ERROR(decl, "Expected a function body, if you want to declare an extern function use " + "'extern' or place it in an .c3i file."); } bool pure = false; if (!sema_analyse_doc_header(context, decl->func_decl.docs, decl->func_decl.signature.params, NULL, - &pure)) return decl_poison(decl); + &pure)) return false; decl->func_decl.signature.attrs.is_pure = pure; if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false; DEBUG_LOG("<<< Function analysis of [%s] successful.", decl_safe_name(decl)); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 043edc814..39500d815 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3412,7 +3412,8 @@ static inline bool sema_create_const_kind(SemaContext *context, Expr *expr, Type { Module *module = global_context_find_module(kw_std__core__types); Decl *type_kind = module ? module_find_symbol(module, kw_typekind) : NULL; - unsigned val = type_get_introspection_kind(type->type_kind); + TypeKind kind = type_is_func_ptr(type) ? TYPE_FUNC : type->type_kind; + unsigned val = type_get_introspection_kind(kind); if (!type_kind) { // No TypeKind defined, fallback to char. @@ -3846,6 +3847,7 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper switch (original_type->type_kind) { case TYPE_POINTER: + return !type_is_func_ptr(original_type); case TYPE_OPTIONAL: case TYPE_DISTINCT: case TYPE_ENUM: @@ -3901,7 +3903,7 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper } case TYPE_PROPERTY_PARAMS: case TYPE_PROPERTY_RETURNS: - return type->type_kind == TYPE_FUNC || (type->type_kind == TYPE_POINTER && type->pointer->type_kind == TYPE_FUNC); + return type_is_func_ptr(type); case TYPE_PROPERTY_EXTNAMEOF: return !type_is_builtin(type->type_kind); }