added: better error message when `->` is used incorrectly
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Dec 2023 00:35:28 +0000 (18:35 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Dec 2023 00:35:28 +0000 (18:35 -0600)
compiler/include/astnodes.h
compiler/src/checker.c
compiler/src/utils.c

index 84a112effa36fa5c182ed1585c6237e1d834c5be..73c5138024b4abed4fd9eb5fa4b0c4c9744d5e1d 100644 (file)
@@ -696,6 +696,7 @@ struct AstArgument      {
     VarArgKind va_kind;
     b32 is_baked : 1;
     b32 pass_as_any : 1;
+    b32 used_as_lval_of_method_call : 1;
 };
 struct AstSubscript   {
     AstTyped_base;
index bdf8277f9074cba7dce1f5bd9d63844c605e116c..f09f8e9a18d87b320315f4b62b6d4a6b56ea2f36 100644 (file)
@@ -2249,10 +2249,11 @@ CheckStatus check_method_call(AstBinaryOp** pmcall) {
             implicit_argument = (AstTyped *) address_of;
         }
 
-        implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
+        AstArgument *new_arg = make_argument(context.ast_alloc, implicit_argument);
+        new_arg->used_as_lval_of_method_call = 1;
 
         bh_arr_insertn(call_node->args.values, 0, 1);
-        call_node->args.values[0] = implicit_argument;
+        call_node->args.values[0] = (AstTyped *) new_arg;
 
         mcall->right->next = mcall->next;
         mcall->flags |= Ast_Flag_Has_Been_Checked;
index 1262c01fe66e5bef8f917aab81f99e4590f90f6d..dab018477c6512572d76941be5a66afc993c45ef 100644 (file)
@@ -1113,6 +1113,21 @@ TypeMatch check_arguments_against_type(Arguments* args, TypeFunction* func_type,
                 if (tm == TYPE_MATCH_SPECIAL) return tm;
                 if (tm == TYPE_MATCH_FAILED) {
                     if (error != NULL) {
+                        AstArgument *the_arg = (void *) arg_arr[arg_pos];
+                        if (the_arg->used_as_lval_of_method_call) {
+                            if (formal_params[arg_pos]->kind == Type_Kind_Pointer &&
+                                formal_params[arg_pos]->Pointer.elem == arg_arr[arg_pos]->type) {
+                                // We didn't match the type, and this arg was from a method call,
+                                // and its because it wanted a &T, but got a T. This is likely
+                                // due to the fact that the method call argument is not an lval.
+                                error->pos = arg_arr[arg_pos]->token->pos;
+                                error->text = bh_aprintf(global_heap_allocator,
+                                        "This method expects a pointer to the first argument, which normally `->` would do automatically, but in this case, the left-hand side is not an l-value, so its address cannot be taken. Try storing it in a temporary variable first, then calling the method."
+                                );
+                                return tm;
+                            }
+                        }
+
                         error->pos = arg_arr[arg_pos]->token->pos;
                         error->text = bh_aprintf(global_heap_allocator,
                                 "The procedure '%s' expects a value of type '%s' for %d%s parameter, got '%s'.",