authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-03-11 14:26:56+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-12 18:47:02+02:00
log948926c513befd95dc1ff90fe05329245f1c81db
treed66d7d70aeac096de253ecb77551ffd87f4a5be1
parenta097779b611577b75475336ee282615984f77edf

Sema: improve error message when calling non-member function as method

Resolves: #14880

3 files changed, 18 insertions(+), 7 deletions(-)

src/Sema.zig+15-6
...@@ -23605,10 +23605,13 @@ fn fieldCallBind(...@@ -23605,10 +23605,13 @@ fn fieldCallBind(
23605 }23605 }
2360623606
23607 // If we get here, we need to look for a decl in the struct type instead.23607 // If we get here, we need to look for a decl in the struct type instead.
23608 switch (concrete_ty.zigTypeTag()) {23608 const found_decl = switch (concrete_ty.zigTypeTag()) {
23609 .Struct, .Opaque, .Union, .Enum => {23609 .Struct, .Opaque, .Union, .Enum => found_decl: {
23610 if (concrete_ty.getNamespace()) |namespace| {23610 if (concrete_ty.getNamespace()) |namespace| {
23611 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {23611 if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| {
23612 try sema.addReferencedBy(block, src, decl_idx);
23613 const inst = try sema.analyzeDeclRef(decl_idx);
23614
23612 const decl_val = try sema.analyzeLoad(block, src, inst, src);23615 const decl_val = try sema.analyzeLoad(block, src, inst, src);
23613 const decl_type = sema.typeOf(decl_val);23616 const decl_type = sema.typeOf(decl_val);
23614 if (decl_type.zigTypeTag() == .Fn and23617 if (decl_type.zigTypeTag() == .Fn and
...@@ -23625,7 +23628,7 @@ fn fieldCallBind(...@@ -23625,7 +23628,7 @@ fn fieldCallBind(
23625 first_param_type.ptrSize() == .C) and23628 first_param_type.ptrSize() == .C) and
23626 first_param_type.childType().eql(concrete_ty, sema.mod)))23629 first_param_type.childType().eql(concrete_ty, sema.mod)))
23627 {23630 {
23628 // zig fmt: on23631 // zig fmt: on
23629 // TODO: bound fn calls on rvalues should probably23632 // TODO: bound fn calls on rvalues should probably
23630 // generate a by-value argument somehow.23633 // generate a by-value argument somehow.
23631 const ty = Type.Tag.bound_fn.init();23634 const ty = Type.Tag.bound_fn.init();
...@@ -23664,16 +23667,22 @@ fn fieldCallBind(...@@ -23664,16 +23667,22 @@ fn fieldCallBind(
23664 return sema.addConstant(ty, value);23667 return sema.addConstant(ty, value);
23665 }23668 }
23666 }23669 }
23670 break :found_decl decl_idx;
23667 }23671 }
23668 }23672 }
23673 break :found_decl null;
23669 },23674 },
23670 else => {},23675 else => null,
23671 }23676 };
2367223677
23673 const msg = msg: {23678 const msg = msg: {
23674 const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) });23679 const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) });
23675 errdefer msg.destroy(sema.gpa);23680 errdefer msg.destroy(sema.gpa);
23676 try sema.addDeclaredHereNote(msg, concrete_ty);23681 try sema.addDeclaredHereNote(msg, concrete_ty);
23682 if (found_decl) |decl_idx| {
23683 const decl = sema.mod.declPtr(decl_idx);
23684 try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "'{s}' is not a member function", .{field_name});
23685 }
23677 break :msg msg;23686 break :msg msg;
23678 };23687 };
23679 return sema.failWithOwnedErrorMsg(msg);23688 return sema.failWithOwnedErrorMsg(msg);
test/cases/compile_errors/method_call_with_first_arg_type_primitive.zig+2-1
...@@ -2,7 +2,7 @@ const Foo = struct {...@@ -2,7 +2,7 @@ const Foo = struct {
2 x: i32,2 x: i32,
33
4 fn init(x: i32) Foo {4 fn init(x: i32) Foo {
5 return Foo {5 return Foo{
6 .x = x,6 .x = x,
7 };7 };
8 }8 }
...@@ -20,3 +20,4 @@ export fn f() void {...@@ -20,3 +20,4 @@ export fn f() void {
20//20//
21// :14:9: error: no field or member function named 'init' in 'tmp.Foo'21// :14:9: error: no field or member function named 'init' in 'tmp.Foo'
22// :1:13: note: struct declared here22// :1:13: note: struct declared here
23// :4:5: note: 'init' is not a member function
test/cases/compile_errors/method_call_with_first_arg_type_wrong_container.zig+1
...@@ -29,3 +29,4 @@ export fn foo() void {...@@ -29,3 +29,4 @@ export fn foo() void {
29//29//
30// :23:6: error: no field or member function named 'init' in 'tmp.List'30// :23:6: error: no field or member function named 'init' in 'tmp.List'
31// :1:18: note: struct declared here31// :1:18: note: struct declared here
32// :5:9: note: 'init' is not a member function