From 9f7ed00f048a1e2d3539256a1fb8e2cb1f5464cc Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 2 Oct 2022 00:22:21 +0200 Subject: [PATCH] Fixes to function pointer conversion. --- src/compiler/compiler_internal.h | 4 +- src/compiler/parse_global.c | 2 +- src/compiler/sema_casts.c | 4 +- src/compiler/sema_expr.c | 2 +- src/compiler/sema_initializers.c | 4 +- src/compiler/sema_types.c | 2 +- src/compiler/types.c | 79 +++++++++++++++++-- src/version.h | 2 +- .../functions/func_ptr_conversion_alias.c3t | 20 +++++ .../functions/func_ptr_conversion_alias.c3t | 20 +++++ 10 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 test/test_suite/functions/func_ptr_conversion_alias.c3t create mode 100644 test/test_suite2/functions/func_ptr_conversion_alias.c3t diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 793125214..a6c73ba37 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2266,7 +2266,7 @@ 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_failable(Type *failable_type); +Type *type_get_optional(Type *failable_type); Type *type_get_vector(Type *vector_type, unsigned len); Type *type_get_vector_bool(Type *original_type); Type *type_int_signed_by_bitsize(BitSize bitsize); @@ -2376,7 +2376,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_FAILABLE_ANY) return type; - return type_get_failable(type); + return type_get_optional(type); } INLINE bool type_len_is_inferred(Type *type) diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index daaa3f391..b659124f9 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -745,7 +745,7 @@ TypeInfo *parse_optional_type(ParseContext *c) info->failable = true; if (info->resolve_status == RESOLVE_DONE) { - info->type = type_get_failable(info->type); + info->type = type_get_optional(info->type); } RANGE_EXTEND_PREV(info); } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 0f22f2c7d..314d46c38 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1437,7 +1437,7 @@ bool cast(Expr *expr, Type *to_type) if (type_is_optional_any(from_type)) { - expr->type = type_get_failable(to_type); + expr->type = type_get_optional(to_type); return true; } @@ -1468,7 +1468,7 @@ bool cast(Expr *expr, Type *to_type) Type *result_type = expr->type; if (from_is_failable && !type_is_optional(result_type)) { - expr->type = type_get_failable(result_type); + expr->type = type_get_optional(result_type); } return true; } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 5c71a6841..a1ebca994 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1498,7 +1498,7 @@ static inline Type *context_unify_returns(SemaContext *context) if (failable) { // If there are only implicit returns, then we assume void!, otherwise it's an "anyfail" - return no_return ? type_get_failable(type_void) : type_anyfail; + return no_return ? type_get_optional(type_void) : type_anyfail; } // No failable => void. return type_void; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index e7804b24a..7dea1896b 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -163,7 +163,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte failable = failable || IS_OPTIONAL(element); } assert(initializer->type); - if (failable) initializer->type = type_get_failable(initializer->type); + if (failable) initializer->type = type_get_optional(initializer->type); // 6. There's the case of too few values as well. Mark the last field as wrong. assert(elements_needed <= size); @@ -251,7 +251,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex failable = failable || IS_OPTIONAL(element); } assert(initializer->type); - if (failable) initializer->type = type_get_failable(initializer->type); + if (failable) initializer->type = type_get_optional(initializer->type); if (expected_members > size) { diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index ac187760b..7c165df77 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -400,7 +400,7 @@ APPEND_QUALIFIERS: if (type_info->failable) { Type *type = type_info->type; - if (!type_is_optional(type)) type_info->type = type_get_failable(type); + if (!type_is_optional(type)) type_info->type = type_get_optional(type); } return true; } diff --git a/src/compiler/types.c b/src/compiler/types.c index 635c8b5fc..2f6b3ec1c 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -4,6 +4,8 @@ #include "compiler_internal.h" +static Type *flatten_raw_function_type(Type *type); + static struct { Type u0, u1, i8, i16, i32, i64, i128, ixx; @@ -839,7 +841,7 @@ Type *type_get_ptr_recurse(Type *ptr_type) if (ptr_type->type_kind == TYPE_OPTIONAL) { ptr_type = ptr_type->failable; - return type_get_failable(type_get_ptr(ptr_type)); + return type_get_optional(type_get_ptr(ptr_type)); } return type_get_ptr(ptr_type); @@ -850,7 +852,7 @@ Type *type_get_ptr(Type *ptr_type) return type_generate_ptr(ptr_type, false); } -Type *type_get_failable(Type *failable_type) +Type *type_get_optional(Type *failable_type) { assert(!type_is_optional(failable_type)); return type_generate_failable(failable_type, false); @@ -1171,16 +1173,42 @@ void type_func_prototype_init(uint32_t capacity) static uint32_t hash_function(Signature *sig) { uintptr_t hash = (unsigned)sig->variadic; - hash = hash * 31 + (uintptr_t)type_infoptr(sig->rtype)->type->canonical; + hash = hash * 31 + (uintptr_t)flatten_raw_function_type(type_infoptr(sig->rtype)->type); Decl **params = sig->params; VECEACH(params, i) { Decl *param = params[i]; - hash = hash * 31 + (uintptr_t)param->type->canonical; + hash = hash * 31 + (uintptr_t)flatten_raw_function_type(param->type->canonical); } return (uint32_t)((hash >> 16) ^ hash); } +static bool compare_func_param(Type *one, Type *other) +{ + if (one == other) return true; + one = one->canonical; + other = other->canonical; + if (one == other) return true; + if (one->type_kind != other->type_kind) return false; + switch (one->type_kind) + { + case TYPE_POINTER: + return compare_func_param(one->pointer, other->pointer); + case TYPE_ARRAY: + if (one->array.len != other->array.len) return false; + FALLTHROUGH; + case TYPE_SUBARRAY: + case TYPE_FLEXIBLE_ARRAY: + return compare_func_param(one->array.base, other->array.base); + case TYPE_FUNC: + return one->function.prototype->raw_type == other->function.prototype->raw_type; + case TYPE_OPTIONAL: + return compare_func_param(one->failable, other->failable); + default: + return false; + } +} + static int compare_function(Signature *sig, FunctionPrototype *proto) { if (sig->variadic != proto->variadic) return -1; @@ -1188,17 +1216,54 @@ static int compare_function(Signature *sig, FunctionPrototype *proto) Type **other_params = proto->param_types; unsigned param_count = vec_size(params); if (param_count != vec_size(other_params)) return -1; - if (type_infoptr(sig->rtype)->type->canonical != proto->rtype->canonical) return -1; + if (!compare_func_param(type_infoptr(sig->rtype)->type, proto->rtype)) return -1; VECEACH(params, i) { Decl *param = params[i]; Type *other_param = other_params[i]; - if (param->type->canonical != other_param->canonical) return -1; + if (!compare_func_param(param->type, other_param->canonical)) return -1; } return 0; } - +static Type *flatten_raw_function_type(Type *type) +{ + Type *other; + Type *current; + switch (type->type_kind) + { + case TYPE_TYPEDEF: + return flatten_raw_function_type(type->canonical); + case TYPE_FUNC: + return type->function.prototype->raw_type; + case TYPE_OPTIONAL: + current = type->failable; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_optional(other); + case TYPE_POINTER: + current = type->pointer; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_ptr(other); + case TYPE_ARRAY: + current = type->array.base; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_array(other, type->array.len); + case TYPE_SUBARRAY: + current = type->array.base; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_subarray(other); + case TYPE_FLEXIBLE_ARRAY: + current = type->array.base; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_flexible_array(other); + case TYPE_INFERRED_ARRAY: + current = type->array.base; + other = flatten_raw_function_type(current); + return other == current ? type : type_get_inferred_array(other); + default: + return type; + } +} static inline Type *func_create_new_func_proto(Signature *sig, CallABI abi, uint32_t hash, FuncTypeEntry *entry) { unsigned param_count = vec_size(sig->params); diff --git a/src/version.h b/src/version.h index 197b1178f..266a87354 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.64" \ No newline at end of file +#define COMPILER_VERSION "0.3.65" \ No newline at end of file diff --git a/test/test_suite/functions/func_ptr_conversion_alias.c3t b/test/test_suite/functions/func_ptr_conversion_alias.c3t new file mode 100644 index 000000000..5f07f32c0 --- /dev/null +++ b/test/test_suite/functions/func_ptr_conversion_alias.c3t @@ -0,0 +1,20 @@ +module test; + +define Callback = fn void(); +define Callback2 = fn void(); + +define GetCallback = fn Callback2**[][123]*(); + +fn Callback**[][123]* tester() +{ + return null; +} + +GetCallback x = &tester; + + +define GetCallbackOpt = fn Callback2!(); + +fn Callback2! tester2() = null; + +GetCallbackOpt y = &tester2; \ No newline at end of file diff --git a/test/test_suite2/functions/func_ptr_conversion_alias.c3t b/test/test_suite2/functions/func_ptr_conversion_alias.c3t new file mode 100644 index 000000000..5f07f32c0 --- /dev/null +++ b/test/test_suite2/functions/func_ptr_conversion_alias.c3t @@ -0,0 +1,20 @@ +module test; + +define Callback = fn void(); +define Callback2 = fn void(); + +define GetCallback = fn Callback2**[][123]*(); + +fn Callback**[][123]* tester() +{ + return null; +} + +GetCallback x = &tester; + + +define GetCallbackOpt = fn Callback2!(); + +fn Callback2! tester2() = null; + +GetCallbackOpt y = &tester2; \ No newline at end of file