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);
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);
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);
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);
// 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
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;
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;
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;
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);
}
case Ast_Kind_Use_Package: {
- // nocheckin
ent.state = Entity_State_Comptime_Resolve_Symbols;
ent.type = Entity_Type_Use_Package;
ent.use_package = (AstUsePackage *) node;
} 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);
}
}
//
-// Polymorphic things
+// Polymorphic Procedures
//
static void ensure_polyproc_cache_is_created(AstPolyProc* pp) {
if (pp->concrete_funcs == NULL) {
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;
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;
}