bugfixes with polymorphic procedures
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 10 Sep 2022 23:36:53 +0000 (18:36 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 10 Sep 2022 23:36:53 +0000 (18:36 -0500)
compiler/src/checker.c
compiler/src/polymorph.h
compiler/src/symres.c
compiler/src/utils.c
core/container/array.onyx

index f32be5d2dc14dd3efc00026484e930d4d3bf4ad2..01b7eb2955bf48d9217e2834852c68a7b7de84ac 100644 (file)
@@ -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;
index 693e1f771d2278e563033f79bd0ddb3d502bf991..b62f45afd60568c3e4954e73641ef59d3b780312 100644 (file)
@@ -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'.",
index 0a671e8de855e6da56dece9929bb17653b12a994..6877718d93bdf902c3b5905f5e2b275a1e0d8c43 100644 (file)
@@ -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;
index 7f4ea49b187e55dcc6823a9803d6ca5d81d450d6..5cbef6399623da0d8f724ddf889e654e5e0edbc3 100644 (file)
@@ -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;
index 50980be1234b1a9e26fc0136d147bd131b5cd60a..5a3717b18967e680eef45f96518d66aa812d05b1 100644 (file)
@@ -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;