From: Brendan Hansen Date: Sat, 10 Sep 2022 23:36:53 +0000 (-0500) Subject: bugfixes with polymorphic procedures X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=a3b1132e1b33305ef69b8d43768ba6d0d805d398;p=onyx.git bugfixes with polymorphic procedures --- diff --git a/compiler/src/checker.c b/compiler/src/checker.c index f32be5d2..01b7eb29 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -1748,17 +1748,18 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { CheckStatus check_method_call(AstBinaryOp** pmcall) { AstBinaryOp* mcall = *pmcall; - CHECK(expression, &mcall->left); - if (mcall->left->type == NULL) YIELD(mcall->token->pos, "Trying to resolve type of left hand side."); - - AstTyped* implicit_argument = mcall->left; - - // Symbol resolution should have ensured that this is call node. - AstCall* call_node = (AstCall *) mcall->right; - assert(call_node->kind == Ast_Kind_Call); // :Idempotency if ((mcall->flags & Ast_Flag_Has_Been_Checked) == 0) { + CHECK(expression, &mcall->left); + if (mcall->left->type == NULL) YIELD(mcall->token->pos, "Trying to resolve type of left hand side."); + + AstTyped* implicit_argument = mcall->left; + AstCall* call_node = (AstCall *) mcall->right; + + // Symbol resolution should have ensured that this is call node. + assert(call_node->kind == Ast_Kind_Call); + // Implicitly take the address of the value if it is not already a pointer type. // This could be weird to think about semantically so some testing with real code // would be good. - brendanfh 2020/02/05 @@ -1775,8 +1776,8 @@ CheckStatus check_method_call(AstBinaryOp** pmcall) { *pmcall = (AstBinaryOp *) mcall->right; mcall->right->next = mcall->next; + mcall->flags |= Ast_Flag_Has_Been_Checked; } - mcall->flags |= Ast_Flag_Has_Been_Checked; CHECK(call, (AstCall **) pmcall); return Check_Success; diff --git a/compiler/src/polymorph.h b/compiler/src/polymorph.h index 693e1f77..b62f45af 100644 --- a/compiler/src/polymorph.h +++ b/compiler/src/polymorph.h @@ -39,7 +39,12 @@ void insert_poly_sln_into_scope(Scope* scope, AstPolySolution *sln) { case PSK_Value: // CLEANUP: Maybe clone this? - assert(sln->value->flags & Ast_Flag_Comptime); + // assert(sln->value->flags & Ast_Flag_Comptime); + if ((sln->value->flags & Ast_Flag_Comptime) == 0) { + onyx_report_error(sln->value->token->pos, Error_Critical, "Expected value to be compile time known."); + return; + } + node = (AstNode *) sln->value; break; } @@ -478,6 +483,7 @@ static AstTyped* try_lookup_based_on_partial_function_type(AstFunction *pp, AstF // the type that the parameter but be. static void solve_for_polymorphic_param_type(PolySolveResult* resolved, AstFunction* func, AstPolyParam* param, PolyProcLookupMethod pp_lookup, ptr actual, char** err_msg) { Type* actual_type = NULL; + b32 can_strip_pointer = 0; switch (pp_lookup) { case PPLM_By_Arguments: { @@ -489,6 +495,14 @@ static void solve_for_polymorphic_param_type(PolySolveResult* resolved, AstFunct if (typed_param->kind != Ast_Kind_Argument) goto skip_nested_polymorph_case; AstTyped* potential = ((AstArgument *) typed_param)->value; + + if (potential->kind == Ast_Kind_Address_Of) { + AstAddressOf *aof = (AstAddressOf *) potential; + if (aof->can_be_removed) { + can_strip_pointer = 1; + } + } + if (potential->kind != Ast_Kind_Polymorphic_Proc) goto skip_nested_polymorph_case; if (param->idx >= (u32) bh_arr_length(func->params)) goto skip_nested_polymorph_case; @@ -530,6 +544,19 @@ static void solve_for_polymorphic_param_type(PolySolveResult* resolved, AstFunct } PolySolveResult res = solve_poly_type(param->poly_sym, param->type_expr, actual_type); + + // If we are trying to match against an "address of" node that was + // placed because of a method call, there's a small change that the + // address of is unnecessary and can be removed. This happens in + // unify_node_and_type, but because that relies on knowning the type, + // it cannot happen until after polymorphic arguments are determined. + // This case simply tries matching everything again, but without the + // outer most pointer node. If everything succeeds, the pointer node + // will be removed when the actual value is checked later. + if (res.kind == PSK_Undefined && can_strip_pointer) { + res = solve_poly_type(param->poly_sym, param->type_expr, actual_type->Pointer.elem); + } + if (res.kind == PSK_Undefined) { *err_msg = bh_aprintf(global_scratch_allocator, "Unable to solve for polymorphic variable '%b', given the type '%s'.", diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 0a671e8d..6877718d 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -419,11 +419,11 @@ static SymresStatus symres_pipe(AstBinaryOp** pipe) { // // foo->member_function(...) static SymresStatus symres_method_call(AstBinaryOp** mcall) { - SYMRES(expression, &(*mcall)->left); - if ((*mcall)->left == NULL) return Symres_Error; - // :EliminatingSymres if (((*mcall)->flags & Ast_Flag_Has_Been_Symres) == 0) { + SYMRES(expression, &(*mcall)->left); + if ((*mcall)->left == NULL) return Symres_Error; + if ((*mcall)->right->kind != Ast_Kind_Call) { onyx_report_error((*mcall)->token->pos, Error_Critical, "'->' expected procedure call on right side."); return Symres_Error; diff --git a/compiler/src/utils.c b/compiler/src/utils.c index 7f4ea49b..5cbef639 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -576,6 +576,8 @@ void expand_macro(AstCall** pcall, AstFunction* template) { AstNode* subst = (AstNode *) expansion; if (template->type->Function.return_type != &basic_types[Basic_Kind_Void]) { + expansion->rules = Block_Rule_Do_Block; + AstDoBlock* doblock = (AstDoBlock *) onyx_ast_node_new(context.ast_alloc, sizeof(AstDoBlock), Ast_Kind_Do_Block); doblock->token = expansion->token; doblock->block = expansion; diff --git a/core/container/array.onyx b/core/container/array.onyx index 50980be1..5a3717b1 100644 --- a/core/container/array.onyx +++ b/core/container/array.onyx @@ -507,6 +507,9 @@ to_list :: (arr: [] $T, allocator := context.allocator) -> List(T) { return new_list; } +find :: #match #local {} + +#overload find :: (arr: [] $T, value: T) -> i32 { for i: arr.count { if value == arr.data[i] do return i; @@ -515,6 +518,16 @@ find :: (arr: [] $T, value: T) -> i32 { return -1; } +#overload +find :: macro (arr: [] $T, pred: Code) -> i32 { + for i: arr.count { + it := ^arr[i]; + if #unquote pred do return i; + } + + return -1; +} + find_ptr :: (arr: [] $T, value: T) -> ^T { for ^it: arr { if value == *it do return it;