Commit b757a96d5c

Veikka Tuominen <git@vexu.eu>
2022-08-09 22:37:26
Sema: add declared here note to function call errors
1 parent 0778490
src/Sema.zig
@@ -5409,6 +5409,19 @@ fn lookupInNamespace(
     return null;
 }
 
+fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
+    const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null;
+    if (func_val.isUndef()) return null;
+    const owner_decl_index = switch (func_val.tag()) {
+        .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl,
+        .function => func_val.castTag(.function).?.data.owner_decl,
+        .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
+        else => return null,
+    };
+    const owner_decl = sema.mod.declPtr(owner_decl_index);
+    return owner_decl.srcLoc();
+}
+
 fn zirCall(
     sema: *Sema,
     block: *Block,
@@ -5464,41 +5477,35 @@ fn zirCall(
     const func_ty_info = func_ty.fnInfo();
 
     const fn_params_len = func_ty_info.param_types.len;
-    if (func_ty_info.is_var_args) {
-        assert(func_ty_info.cc == .C);
-        if (total_args < fn_params_len) {
-            // TODO add error note: declared here
-            if (bound_arg_src != null) {
-                return sema.fail(
-                    block,
-                    call_src,
-                    "member function expected at least {d} argument(s), found {d}",
-                    .{ fn_params_len - 1, args_len },
-                );
-            }
-            return sema.fail(
-                block,
-                func_src,
-                "expected at least {d} argument(s), found {d}",
-                .{ fn_params_len, args_len },
-            );
+    check_args: {
+        if (func_ty_info.is_var_args) {
+            assert(func_ty_info.cc == .C);
+            if (total_args >= fn_params_len) break :check_args;
+        } else if (fn_params_len == total_args) {
+            break :check_args;
         }
-    } else if (fn_params_len != total_args) {
-        // TODO add error note: declared here
-        if (bound_arg_src != null) {
-            return sema.fail(
+
+        const decl_src = try sema.funcDeclSrc(block, func_src, func);
+        const member_str = if (bound_arg_src != null) "member function " else "";
+        const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
+        const msg = msg: {
+            const msg = try sema.errMsg(
                 block,
-                call_src,
-                "member function expected {d} argument(s), found {d}",
-                .{ fn_params_len - 1, args_len },
+                func_src,
+                "{s}expected {s}{d} argument(s), found {d}",
+                .{
+                    member_str,
+                    variadic_str,
+                    fn_params_len - @boolToInt(bound_arg_src != null),
+                    args_len,
+                },
             );
-        }
-        return sema.fail(
-            block,
-            call_src,
-            "expected {d} argument(s), found {d}",
-            .{ fn_params_len, args_len },
-        );
+            errdefer msg.destroy(sema.gpa);
+
+            if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(msg);
     }
 
     const args_body = sema.code.extra[extra.end..];
@@ -5625,13 +5632,20 @@ fn analyzeCall(
     const func_ty_info = func_ty.fnInfo();
     const cc = func_ty_info.cc;
     if (cc == .Naked) {
-        // TODO add error note: declared here
-        return sema.fail(
-            block,
-            func_src,
-            "unable to call function with naked calling convention",
-            .{},
-        );
+        const decl_src = try sema.funcDeclSrc(block, func_src, func);
+        const msg = msg: {
+            const msg = try sema.errMsg(
+                block,
+                func_src,
+                "unable to call function with naked calling convention",
+                .{},
+            );
+            errdefer msg.destroy(sema.gpa);
+
+            if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(msg);
     }
     const fn_params_len = func_ty_info.param_types.len;
     if (func_ty_info.is_var_args) {
test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig
@@ -1,11 +0,0 @@
-export fn entry() void {
-    foo();
-}
-fn foo() callconv(.Naked) void { }
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:2:5: error: unable to call function with naked calling convention
-// tmp.zig:4:1: note: declared here
test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig
@@ -1,14 +0,0 @@
-const Foo = struct {
-    fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
-};
-fn f(foo: *const Foo) void {
-
-    foo.method(1, 2);
-}
-export fn entry() usize { return @sizeOf(@TypeOf(f)); }
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:6:15: error: expected 2 argument(s), found 3
test/cases/compile_errors/calling_function_with_naked_calling_convention.zig
@@ -0,0 +1,11 @@
+export fn entry() void {
+    foo();
+}
+fn foo() callconv(.Naked) void { }
+
+// error
+// backend=llvm
+// target=native
+//
+// :2:5: error: unable to call function with naked calling convention
+// :4:1: note: function declared here
test/cases/compile_errors/member_function_arg_mismatch.zig
@@ -11,4 +11,5 @@ pub export fn entry() void {
 // backend=stage2
 // target=native
 //
-// :7:10: error: member function expected 2 argument(s), found 1
+// :7:6: error: member function expected 2 argument(s), found 1
+// :3:5: note: function declared here
test/cases/compile_errors/wrong_number_of_arguments.zig
@@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }
 // backend=stage2
 // target=native
 //
-// :2:6: error: expected 3 argument(s), found 1
+// :2:5: error: expected 3 argument(s), found 1
+// :4:1: note: function declared here
test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig
@@ -0,0 +1,15 @@
+const Foo = struct {
+    fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
+};
+fn f(foo: *const Foo) void {
+
+    foo.method(1, 2);
+}
+export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
+
+// error
+// backend=stage2
+// target=native
+//
+// :6:8: error: member function expected 1 argument(s), found 2
+// :2:5: note: function declared here