From: Brendan Hansen Date: Mon, 8 Mar 2021 03:52:54 +0000 (-0600) Subject: cleaned up code relating to overloaded procedures X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=64648488cacb0b1887be4c10754d0751610ae8fa;p=onyx.git cleaned up code relating to overloaded procedures --- diff --git a/bin/onyx b/bin/onyx index 7e78bd70..8aa4189d 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 7303159b..827072bb 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -1159,6 +1159,7 @@ AstNode* make_symbol(bh_allocator a, OnyxToken* sym); void arguments_initialize(Arguments* args); b32 fill_in_arguments(Arguments* args, AstNode* provider, char** err_msg); void arguments_ensure_length(Arguments* args, u32 count); +void arguments_copy(Arguments* dest, Arguments* src); void arguments_clone(Arguments* dest, Arguments* src); void arguments_deep_clone(bh_allocator a, Arguments* dest, Arguments* src); void arguments_remove_baked(Arguments* args); @@ -1175,6 +1176,8 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxToken* tkn); AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual); +AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Arguments* args); +void report_unable_to_match_overload(AstCall* call); AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos); diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index f1204715..52c7ecc7 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -762,7 +762,15 @@ void arguments_ensure_length(Arguments* args, u32 count) { bh_arr_set_length(args->values, bh_max(count, (u32) bh_arr_length(args->values))); } -// In clone, the named_values are not copied. This is used in match_overloaded_function since it doesn't need them to be copied. +void arguments_copy(Arguments* dest, Arguments* src) { + dest->named_values = src->named_values; + + arguments_ensure_length(dest, bh_arr_length(src->values)); + bh_arr_each(AstTyped*, arg, dest->values) *arg = NULL; + fori (i, 0, bh_arr_length(src->values)) dest->values[i] = src->values[i]; +} + +// In clone, the named_values are not copied. This is used in find_matching_overload_by_arguments since it doesn't need them to be copied. void arguments_clone(Arguments* dest, Arguments* src) { dest->named_values = src->named_values; dest->values = bh_arr_copy(global_heap_allocator, src->values); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 3b3b23c6..12898e2b 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -307,99 +307,6 @@ CheckStatus check_switch(AstSwitch* switchnode) { return 0; } -static AstTyped* match_overloaded_function(Arguments* args, bh_arr(AstTyped *) overloads) { - bh_arr_each(AstTyped *, node, overloads) { - AstFunction* overload = NULL; - if ((*node)->kind == Ast_Kind_Function) { - overload = (AstFunction *) *node; - } - else if ((*node)->kind == Ast_Kind_Polymorphic_Proc) { - overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Arguments, args); - } - - if (overload == NULL) continue; - - Arguments* args_to_use = args; - if (args->named_values != NULL && bh_arr_length(args->named_values) > 0) { - args_to_use = bh_alloc_item(global_scratch_allocator, Arguments); - - arguments_clone(args_to_use, args); - arguments_ensure_length(args_to_use, bh_arr_length(args->values) + bh_arr_length(args->named_values)); - - b32 values_place_correctly = fill_in_arguments(args_to_use, (AstNode *) overload, NULL); - - if (!values_place_correctly) goto no_match; - } - - fill_in_type((AstTyped *) overload); - - TypeFunction* ol_type = &overload->type->Function; - if (bh_arr_length(args_to_use->values) < (i32) ol_type->needed_param_count) continue; - - i32 param_left = ol_type->param_count; - Type** param_type = ol_type->params; - bh_arr_each(AstTyped*, arg, args_to_use->values) { - if (param_left == 0) goto no_match; - param_left--; - - fill_in_type(*arg); - - Type* type_to_match = *param_type; - if ((*param_type)->kind == Type_Kind_VarArgs) - type_to_match = (*param_type)->VarArgs.ptr_to_data->Pointer.elem; - - AstTyped** value = arg; - if ((*arg)->kind == Ast_Kind_Argument) - value = &((AstArgument *) *arg)->value; - - if (!type_check_or_auto_cast(value, type_to_match)) goto no_match; - - param_type++; - } - - return (AstTyped *) *node; - -no_match: - if (args->named_values != NULL && bh_arr_length(args->named_values) > 0) { - bh_arr_free(args_to_use->values); - } - - continue; - } - - return NULL; -} - -static void report_unable_to_match_overload(AstCall* call) { - char* arg_str = bh_alloc(global_scratch_allocator, 1024); - arg_str[0] = '\0'; - - bh_arr_each(AstTyped *, arg, call->args.values) { - strncat(arg_str, node_get_type_name(*arg), 1023); - - if (arg != &bh_arr_last(call->args.values)) - strncat(arg_str, ", ", 1023); - } - - if (bh_arr_length(call->args.named_values) > 0) { - bh_arr_each(AstNamedValue *, named_value, call->args.named_values) { - token_toggle_end((*named_value)->token); - strncat(arg_str, (*named_value)->token->text, 1023); - token_toggle_end((*named_value)->token); - - strncat(arg_str, "=", 1023); - strncat(arg_str, node_get_type_name((*named_value)->value), 1023); // CHECK: this might say 'unknown'. - - if (named_value != &bh_arr_last(call->args.named_values)) - strncat(arg_str, ", ", 1023); - } - } - - onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str); - - bh_free(global_scratch_allocator, arg_str); -} - CheckStatus check_arguments(Arguments* args) { bh_arr_each(AstTyped *, actual, args->values) CHECK(expression, actual); @@ -451,12 +358,10 @@ CheckStatus check_call(AstCall* call) { // 1. Ensure the callee is not a symbol // 2. Check the callee expression (since it could be a variable or a field access, etc) // 3. Check all arguments - // * Cannot pass overloaded functions - // * Cannot pass a non-simple struct + // * Cannot pass overloaded functions (ROBUSTNESS) // 4. If callee is an overloaded function, use the argument types to determine which overload is used. // 5. If callee is polymorphic, use the arguments type to generate a polymorphic function. - // 6. If an argument is polymorphic, generate the correct polymorphic function. - // 7. Fill in default arguments + // 7. Fill in arguments // 8. If callee is an intrinsic, turn call into an Intrinsic_Call node // 9. Check types of formal and actual params against each other, handling varargs @@ -464,7 +369,7 @@ CheckStatus check_call(AstCall* call) { check_arguments(&call->args); if (call->callee->kind == Ast_Kind_Overloaded_Function) { - call->callee = match_overloaded_function(&call->args, ((AstOverloadedFunction *) call->callee)->overloads); + call->callee = find_matching_overload_by_arguments(((AstOverloadedFunction *) call->callee)->overloads, &call->args); if (call->callee == NULL) { report_unable_to_match_overload(call); return Check_Error; @@ -716,13 +621,6 @@ CheckStatus check_binop_assignment(AstBinaryOp* binop, b32 assignment_is_ok) { return Check_Error; } - // CLEANUP: This seems like it should be here. But I don't know where - // or what the right place is for it. - // if (binop->right->type == NULL) { - // onyx_report_error(binop->right->token->pos, "Unable to resolve type for this expression."); - // return Check_Error; - // } - binop->type = &basic_types[Basic_Kind_Void]; return Check_Success; @@ -803,7 +701,7 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop) { bh_arr_push(args.values, binop->left); bh_arr_push(args.values, binop->right); - AstTyped* overload = match_overloaded_function(&args, operator_overloads[binop->operation]); + AstTyped* overload = find_matching_overload_by_arguments(operator_overloads[binop->operation], &args); if (overload == NULL) { bh_arr_free(args.values); return NULL; diff --git a/src/onyxentities.c b/src/onyxentities.c index bf3e88c4..d415b62d 100644 --- a/src/onyxentities.c +++ b/src/onyxentities.c @@ -68,7 +68,6 @@ void entity_heap_init(EntityHeap* entities) { bh_arena_init(&entities->entity_arena, global_heap_allocator, 32 * 1024); } -// nocheckin // Allocates the entity in the entity heap. Don't quite feel this is necessary... Entity* entity_heap_register(EntityHeap* entities, Entity e) { bh_allocator alloc = bh_arena_allocator(&entities->entity_arena); @@ -254,7 +253,6 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s } case Ast_Kind_Use_Package: { - // nocheckin ent.state = Entity_State_Comptime_Resolve_Symbols; ent.type = Entity_Type_Use_Package; ent.use_package = (AstUsePackage *) node; diff --git a/src/onyxparser.c b/src/onyxparser.c index e3e8f70f..7e53af02 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -26,8 +26,6 @@ void submit_entity_in_scope(OnyxParser* parser, AstNode* node, Scope* scope, Pac } else { bh_arr(Entity *) *entity_array = bh_arr_last(parser->alternate_entity_placement_stack); - - // nocheckin This should also be able to place them in the false entities add_entities_for_node(entity_array, node, scope, package); } } diff --git a/src/onyxutils.c b/src/onyxutils.c index f176a1b2..91de1ac0 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -211,7 +211,7 @@ void scope_clear(Scope* scope) { // -// Polymorphic things +// Polymorphic Procedures // static void ensure_polyproc_cache_is_created(AstPolyProc* pp) { if (pp->concrete_funcs == NULL) { @@ -913,6 +913,123 @@ AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupM return solidified_func.func; } +// +// Overloaded Procedures +// + +// +// @Cleanup: Everything having to do with overload resolving! +// Things that need to be available: +// * A copy of the arguments list that can be mutated +// - The named_values do not need to be copied, because they are not modified when fill_in_arguments happens. +// - Only values needs to have a copy available +// - This copy needs to be reset after checking every option +// +// Steps needed to check if an overload option is "the one": +// 1. Figure out what the overload is +// a. If polymorphic, generate the header for the procedure only +// 2. Place the arguments in the copy, according to the overload option +// 3. Ensure the option has a type filled out +// 4. For each argument +// a. Ensure it has a place to go (not too many arguments) +// b. Ensure it has a type +// c. Ensure the types match (currently there could be a problem if an option is attempted and doesn't work all the way that polymorphic procedures as arguments could still be solidified) +// +// Additional features that this needs to account for: +// * Resolving an overload from a list of parameter types +// * Resolving an overload from a TypeFunction (so an overloaded procedure can be passed as a parameter) +// + +AstTyped* find_matching_overload_by_arguments(bh_arr(AstTyped *) overloads, Arguments* param_args) { + Arguments args; + arguments_clone(&args, param_args); + arguments_ensure_length(&args, bh_arr_length(args.values) + bh_arr_length(args.named_values)); + + AstTyped *matched_overload = NULL; + + bh_arr_each(AstTyped *, node, overloads) { + arguments_copy(&args, param_args); + + AstFunction* overload = NULL; + switch ((*node)->kind) { + case Ast_Kind_Function: overload = (AstFunction *) *node; break; + case Ast_Kind_Polymorphic_Proc: overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Arguments, param_args); break; + } + + // NOTE: Overload is not something that is known to be overloadable. + if (overload == NULL) continue; + if (overload->kind != Ast_Kind_Function) continue; + + // NOTE: If the arguments cannot be placed successfully in the parameters list + if (!fill_in_arguments(&args, (AstNode *) overload, NULL)) continue; + + TypeFunction* ol_type = &overload->type->Function; + if (bh_arr_length(args.values) < (i32) ol_type->needed_param_count) continue; + + b32 all_arguments_work = 1; + fori (i, 0, bh_arr_length(args.values)) { + if (i >= ol_type->param_count) { + all_arguments_work = 0; + break; + } + + Type* type_to_match = ol_type->params[i]; + AstTyped** value = &args.values[i]; + + if (type_to_match->kind == Type_Kind_VarArgs) type_to_match = type_to_match->VarArgs.ptr_to_data->Pointer.elem; + if ((*value)->kind == Ast_Kind_Argument) value = &((AstArgument *) *value)->value; + + if (!type_check_or_auto_cast(value, type_to_match)) { + all_arguments_work = 0; + break; + } + } + + if (all_arguments_work) { + matched_overload = *node; + break; + } + } + + bh_arr_free(args.values); + return matched_overload; +} + +void report_unable_to_match_overload(AstCall* call) { + char* arg_str = bh_alloc(global_scratch_allocator, 1024); + arg_str[0] = '\0'; + + bh_arr_each(AstTyped *, arg, call->args.values) { + strncat(arg_str, node_get_type_name(*arg), 1023); + + if (arg != &bh_arr_last(call->args.values)) + strncat(arg_str, ", ", 1023); + } + + if (bh_arr_length(call->args.named_values) > 0) { + bh_arr_each(AstNamedValue *, named_value, call->args.named_values) { + token_toggle_end((*named_value)->token); + strncat(arg_str, (*named_value)->token->text, 1023); + token_toggle_end((*named_value)->token); + + strncat(arg_str, "=", 1023); + strncat(arg_str, node_get_type_name((*named_value)->value), 1023); // CHECK: this might say 'unknown'. + + if (named_value != &bh_arr_last(call->args.named_values)) + strncat(arg_str, ", ", 1023); + } + } + + onyx_report_error(call->token->pos, "unable to match overloaded function with provided argument types: (%s)", arg_str); + + bh_free(global_scratch_allocator, arg_str); +} + + + +// +// Polymorphic Structures +// char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) { char name_buf[256]; fori (i, 0, 256) name_buf[i] = 0; @@ -1042,7 +1159,7 @@ AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstP entity_bring_to_state(&struct_default_entity, Entity_State_Code_Gen); if (onyx_has_errors()) { - onyx_report_error(pos, "Error in creating polymoprhic struct instantiation here."); + onyx_report_error(pos, "Error in creating polymorphic struct instantiation here."); bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, NULL); return NULL; }