From 60830e36e38f49bc797ae731c9dd58d7231039bf Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Fri, 21 Jul 2023 02:19:32 +0200 Subject: [PATCH 1/6] Sema error: talk about discarding instead of suppressing Maybe I'm just being pedantic here (most likely) but I don't like how we're just telling the user here how to "suppress this error" by "assigning the value to '_'". I think it's better if we use the word "discard" here which I think is the official terminology and also tells the user what it actually means to "assign the value to '_'". Also, using the value would also be a way to "suppress the error". It is just one of the two options: discard or use. --- src/Sema.zig | 2 +- .../for_loop_body_expression_ignored.zig | 8 ++++---- .../compile_errors/generic_instantiation_failure.zig | 2 +- .../ignored_assert-err-ok_return_value.zig | 2 +- .../ignored_comptime_statement_value.zig | 2 +- test/cases/compile_errors/ignored_comptime_value.zig | 4 ++-- .../ignored_deferred_statement_value.zig | 2 +- test/cases/compile_errors/ignored_return_value.zig | 2 +- test/cases/compile_errors/ignored_statement_value.zig | 2 +- .../while_loop_body_expression_ignored.zig | 10 +++++----- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 37fdf0adb5d7183b2a4f107661ec35edd54a39a5..3ff817cbd1d796f369b6a448984faf6797697435 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3571,7 +3571,7 @@ fn ensureResultUsed( const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "all non-void values must be used", .{}); - try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{}); + try sema.errNote(block, src, msg, "to discard the value, assign it to '_'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); diff --git a/test/cases/compile_errors/for_loop_body_expression_ignored.zig b/test/cases/compile_errors/for_loop_body_expression_ignored.zig index a0247139ea18361b2f37642e3559fa8bb8f32d7d..9c5e381e63d9e6bd36dac49a98a96729ffb7c1c8 100644 --- a/test/cases/compile_errors/for_loop_body_expression_ignored.zig +++ b/test/cases/compile_errors/for_loop_body_expression_ignored.zig @@ -23,13 +23,13 @@ export fn f4() void { // // :5:30: error: value of type 'usize' ignored // :5:30: note: all non-void values must be used -// :5:30: note: this error can be suppressed by assigning the value to '_' +// :5:30: note: to discard the value, assign it to '_' // :9:30: error: value of type 'usize' ignored // :9:30: note: all non-void values must be used -// :9:30: note: this error can be suppressed by assigning the value to '_' +// :9:30: note: to discard the value, assign it to '_' // :13:31: error: value of type 'bool' ignored // :13:31: note: all non-void values must be used -// :13:31: note: this error can be suppressed by assigning the value to '_' +// :13:31: note: to discard the value, assign it to '_' // :16:42: error: value of type 'usize' ignored // :16:42: note: all non-void values must be used -// :16:42: note: this error can be suppressed by assigning the value to '_' +// :16:42: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/generic_instantiation_failure.zig b/test/cases/compile_errors/generic_instantiation_failure.zig index 42e4c4e8c822db6965b00d0b4ae39409bf9e4a11..d820f8f410b4036a9319a3dc704e0dc7bc154c53 100644 --- a/test/cases/compile_errors/generic_instantiation_failure.zig +++ b/test/cases/compile_errors/generic_instantiation_failure.zig @@ -24,4 +24,4 @@ pub export fn entry() void { // // :18:43: error: value of type 'type' ignored // :18:43: note: all non-void values must be used -// :18:43: note: this error can be suppressed by assigning the value to '_' +// :18:43: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_assert-err-ok_return_value.zig b/test/cases/compile_errors/ignored_assert-err-ok_return_value.zig index 1257636622da7f452b022e931190510bc57f6722..abe2b006b7e4813243e4c71005bd3014af7152dd 100644 --- a/test/cases/compile_errors/ignored_assert-err-ok_return_value.zig +++ b/test/cases/compile_errors/ignored_assert-err-ok_return_value.zig @@ -11,4 +11,4 @@ fn bar() anyerror!i32 { // // :2:11: error: value of type 'i32' ignored // :2:11: note: all non-void values must be used -// :2:11: note: this error can be suppressed by assigning the value to '_' +// :2:11: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_comptime_statement_value.zig b/test/cases/compile_errors/ignored_comptime_statement_value.zig index 2067f3b716095ca30e0f0f1dd1d2a1c1b7aec40e..4dd0e0fc39b54f11bb2c6dd666bca7eb23a4f802 100644 --- a/test/cases/compile_errors/ignored_comptime_statement_value.zig +++ b/test/cases/compile_errors/ignored_comptime_statement_value.zig @@ -10,4 +10,4 @@ export fn foo() void { // // :3:9: error: value of type 'comptime_int' ignored // :3:9: note: all non-void values must be used -// :3:9: note: this error can be suppressed by assigning the value to '_' +// :3:9: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_comptime_value.zig b/test/cases/compile_errors/ignored_comptime_value.zig index 3414d0861f5ae505b50ed82c99158c98efab6c3e..ed7eb80b50a6196d45b40f2ba6cfa1e8c1646ca2 100644 --- a/test/cases/compile_errors/ignored_comptime_value.zig +++ b/test/cases/compile_errors/ignored_comptime_value.zig @@ -14,7 +14,7 @@ fn bar() u8 { // // :2:5: error: value of type 'comptime_int' ignored // :2:5: note: all non-void values must be used -// :2:5: note: this error can be suppressed by assigning the value to '_' +// :2:5: note: to discard the value, assign it to '_' // :5:5: error: value of type 'u8' ignored // :5:5: note: all non-void values must be used -// :5:5: note: this error can be suppressed by assigning the value to '_' +// :5:5: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_deferred_statement_value.zig b/test/cases/compile_errors/ignored_deferred_statement_value.zig index 1f42efc3f5e14fca44df487782c5e2e0850ed0a6..70b88a4deb37d1b4dff9b7af7057420745531022 100644 --- a/test/cases/compile_errors/ignored_deferred_statement_value.zig +++ b/test/cases/compile_errors/ignored_deferred_statement_value.zig @@ -10,4 +10,4 @@ export fn foo() void { // // :3:9: error: value of type 'comptime_int' ignored // :3:9: note: all non-void values must be used -// :3:9: note: this error can be suppressed by assigning the value to '_' +// :3:9: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_return_value.zig b/test/cases/compile_errors/ignored_return_value.zig index 08424c4fe9fc33a790f9d5c606e856438279393f..f721bc86553ec92812f51af5a486d34ece76bdfc 100644 --- a/test/cases/compile_errors/ignored_return_value.zig +++ b/test/cases/compile_errors/ignored_return_value.zig @@ -11,4 +11,4 @@ fn bar() i32 { // // :2:8: error: value of type 'i32' ignored // :2:8: note: all non-void values must be used -// :2:8: note: this error can be suppressed by assigning the value to '_' +// :2:8: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/ignored_statement_value.zig b/test/cases/compile_errors/ignored_statement_value.zig index c73da84420abbe00d71478c58baff729214f912f..6c4ff442c5f7296967f3095284e48094e6595005 100644 --- a/test/cases/compile_errors/ignored_statement_value.zig +++ b/test/cases/compile_errors/ignored_statement_value.zig @@ -8,4 +8,4 @@ export fn foo() void { // // :2:5: error: value of type 'comptime_int' ignored // :2:5: note: all non-void values must be used -// :2:5: note: this error can be suppressed by assigning the value to '_' +// :2:5: note: to discard the value, assign it to '_' diff --git a/test/cases/compile_errors/while_loop_body_expression_ignored.zig b/test/cases/compile_errors/while_loop_body_expression_ignored.zig index b3e83f202ad03ccdf81e9fa5df3d8e723f072801..dae546df0264dfd71ac707ea1d6dc2222366e20e 100644 --- a/test/cases/compile_errors/while_loop_body_expression_ignored.zig +++ b/test/cases/compile_errors/while_loop_body_expression_ignored.zig @@ -32,16 +32,16 @@ export fn f5() void { // // :5:25: error: value of type 'usize' ignored // :5:25: note: all non-void values must be used -// :5:25: note: this error can be suppressed by assigning the value to '_' +// :5:25: note: to discard the value, assign it to '_' // :10:26: error: value of type 'usize' ignored // :10:26: note: all non-void values must be used -// :10:26: note: this error can be suppressed by assigning the value to '_' +// :10:26: note: to discard the value, assign it to '_' // :15:26: error: value of type 'usize' ignored // :15:26: note: all non-void values must be used -// :15:26: note: this error can be suppressed by assigning the value to '_' +// :15:26: note: to discard the value, assign it to '_' // :20:23: error: value of type 'bool' ignored // :20:23: note: all non-void values must be used -// :20:23: note: this error can be suppressed by assigning the value to '_' +// :20:23: note: to discard the value, assign it to '_' // :25:34: error: value of type 'usize' ignored // :25:34: note: all non-void values must be used -// :25:34: note: this error can be suppressed by assigning the value to '_' +// :25:34: note: to discard the value, assign it to '_' -- 2.54.0 From 31689d0dd92a683e5ed04facea7bc677ef47785b Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Fri, 21 Jul 2023 02:30:47 +0200 Subject: [PATCH 2/6] Sema: remove periods from the few error messages that have them For consistency. --- src/Sema.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index 3ff817cbd1d796f369b6a448984faf6797697435..123ba93cbee5c44b9e53c2473dcd6f61dd3cafea 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9531,7 +9531,7 @@ fn handleExternLibName( return sema.fail( block, src_loc, - "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.", + "dependency on dynamic library '{s}' requires enabling Position Independent Code; fixed by '-l{s}' or '-fPIC'", .{ lib_name, lib_name }, ); } -- 2.54.0 From 8579904ddd489b73cb61721c31b9e9c14ed9e264 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Fri, 21 Jul 2023 02:58:41 +0200 Subject: [PATCH 3/6] Sema: add error note for !?Type types when optional type is expected --- src/Sema.zig | 17 ++++++++++++++--- .../while_expected_optional_got_error_union.zig | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 123ba93cbee5c44b9e53c2473dcd6f61dd3cafea..f286b6385f13b5925447d5c3dc518c5fac43bda6 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2228,8 +2228,19 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T }); } -fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError { - return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)}); +fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError { + const mod = sema.mod; + const msg = msg: { + const msg = try sema.errMsg(block, src, "expected optional type, found '{}'", .{ + non_optional_ty.fmt(mod), + }); + errdefer msg.destroy(sema.gpa); + if (non_optional_ty.zigTypeTag(mod) == .ErrorUnion) { + try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); + } + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); } fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { @@ -9038,7 +9049,7 @@ fn analyzeOptionalPayloadPtr( const opt_type = optional_ptr_ty.childType(zcu); if (opt_type.zigTypeTag(zcu) != .Optional) { - return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(zcu)}); + return sema.failWithExpectedOptionalType(block, src, opt_type); } const child_type = opt_type.optionalChild(zcu); diff --git a/test/cases/compile_errors/while_expected_optional_got_error_union.zig b/test/cases/compile_errors/while_expected_optional_got_error_union.zig index 7bde2c866d296a04cbf449bd43769dcf3f8e9d52..1b4a64770b454e3c9e2c0e34ee563df040002765 100644 --- a/test/cases/compile_errors/while_expected_optional_got_error_union.zig +++ b/test/cases/compile_errors/while_expected_optional_got_error_union.zig @@ -12,3 +12,4 @@ fn bar() anyerror!i32 { // target=native // // :2:15: error: expected optional type, found 'anyerror!i32' +// :2:15: note: consider using 'try', 'catch', or 'if' -- 2.54.0 From 9ae43567a3ef14a815482ccaa2a5b412a716743e Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Fri, 21 Jul 2023 03:22:59 +0200 Subject: [PATCH 4/6] Sema: improve error set/union discard/ignore errors Previously the error had a note suggesting to use `try`, `catch`, or `if`, even for error sets where none of those work. Instead, in case of an error set the way you can handle the error depends very much on the specific case. For example you might be in a `catch` where you are discarding or ignoring the error set capture value, in which case one way to handle the error might be to `return` the error. So, in that case, we do not attach that error note. Additionally, this makes the error tell you what kind of an error it is: is it an error set or an error union? This distinction is very relevant in how to handle the error. --- src/Sema.zig | 10 ++++++---- .../compile_errors/discarding_error_value.zig | 9 +++++++-- .../ignored_deferred_function_call.zig | 10 +++++++++- .../ignored_expression_in_while_continuation.zig | 14 +++++++++++--- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index f286b6385f13b5925447d5c3dc518c5fac43bda6..c55531d924d495a3ce72ca3de3d1d60abed6145b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3568,9 +3568,10 @@ fn ensureResultUsed( const mod = sema.mod; switch (ty.zigTypeTag(mod)) { .Void, .NoReturn => return, - .ErrorSet, .ErrorUnion => { + .ErrorSet => return sema.fail(block, src, "error set is ignored", .{}), + .ErrorUnion => { const msg = msg: { - const msg = try sema.errMsg(block, src, "error is ignored", .{}); + const msg = try sema.errMsg(block, src, "error union is ignored", .{}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; @@ -3600,9 +3601,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const src = inst_data.src(); const operand_ty = sema.typeOf(operand); switch (operand_ty.zigTypeTag(mod)) { - .ErrorSet, .ErrorUnion => { + .ErrorSet => return sema.fail(block, src, "error set is discarded", .{}), + .ErrorUnion => { const msg = msg: { - const msg = try sema.errMsg(block, src, "error is discarded", .{}); + const msg = try sema.errMsg(block, src, "error union is discarded", .{}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; diff --git a/test/cases/compile_errors/discarding_error_value.zig b/test/cases/compile_errors/discarding_error_value.zig index c24d517d3e3b39133b0e1ec9af2a79239a24df89..eab3ecaf984de84f21433a6e9450da71165ccdd5 100644 --- a/test/cases/compile_errors/discarding_error_value.zig +++ b/test/cases/compile_errors/discarding_error_value.zig @@ -1,13 +1,18 @@ -export fn entry() void { +export fn entry1() void { _ = foo(); } fn foo() !void { return error.OutOfMemory; } +export fn entry2() void { + const x: error{a} = undefined; + _ = x; +} // error // backend=stage2 // target=native // -// :2:12: error: error is discarded +// :2:12: error: error union is discarded // :2:12: note: consider using 'try', 'catch', or 'if' +// :9:9: error: error set is discarded diff --git a/test/cases/compile_errors/ignored_deferred_function_call.zig b/test/cases/compile_errors/ignored_deferred_function_call.zig index 9537255d33041ae1ae7a4822bf84a5a8a25bf79b..90c978b40fd26c8d51769a6aa4ea1d7bdb4446fa 100644 --- a/test/cases/compile_errors/ignored_deferred_function_call.zig +++ b/test/cases/compile_errors/ignored_deferred_function_call.zig @@ -5,9 +5,17 @@ fn bar() anyerror!i32 { return 0; } +export fn foo2() void { + defer bar2(); +} +fn bar2() anyerror { + return error.a; +} + // error // backend=stage2 // target=native // -// :2:14: error: error is ignored +// :2:14: error: error union is ignored // :2:14: note: consider using 'try', 'catch', or 'if' +// :9:15: error: error set is ignored diff --git a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig index 4fa396190a58501cc9b65bc527113d3470e17225..ca1b60da5ecaf8c3dcf21f29d42cc0eaba7c82bb 100644 --- a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig +++ b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig @@ -15,13 +15,21 @@ fn bad() anyerror!void { return error.Bad; } +export fn d() void { + while (true) : (bad2()) {} +} +fn bad2() anyerror { + return error.Bad; +} + // error // backend=stage2 // target=native // -// :2:24: error: error is ignored +// :2:24: error: error union is ignored // :2:24: note: consider using 'try', 'catch', or 'if' -// :7:25: error: error is ignored +// :7:25: error: error union is ignored // :7:25: note: consider using 'try', 'catch', or 'if' -// :12:25: error: error is ignored +// :12:25: error: error union is ignored // :12:25: note: consider using 'try', 'catch', or 'if' +// :19:25: error: error set is ignored -- 2.54.0 From f14cf13ff8553030c47748a0cbd455514cd1f4a3 Mon Sep 17 00:00:00 2001 From: Wooster Date: Sun, 30 Jul 2023 11:10:41 +0200 Subject: [PATCH 5/6] Sema: suggest using try/catch/if on method call on error union --- src/Sema.zig | 3 +++ .../method_call_on_error_union.zig | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 test/cases/compile_errors/method_call_on_error_union.zig diff --git a/src/Sema.zig b/src/Sema.zig index c55531d924d495a3ce72ca3de3d1d60abed6145b..a5c5f37e4cfc6fd2475b35c7d663243bf3ccd8cd 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -27888,6 +27888,9 @@ fn fieldCallBind( const decl = mod.declPtr(decl_idx); try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)}); } + if (concrete_ty.zigTypeTag(mod) == .ErrorUnion) { + try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); + } break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); diff --git a/test/cases/compile_errors/method_call_on_error_union.zig b/test/cases/compile_errors/method_call_on_error_union.zig new file mode 100644 index 0000000000000000000000000000000000000000..4ce6b3baa8d766759cf9dee338bc3c1d7e3d21b7 --- /dev/null +++ b/test/cases/compile_errors/method_call_on_error_union.zig @@ -0,0 +1,21 @@ +const X = struct { + fn init() !X { + return error.a; + } + + fn a(x: X) void { + _ = x; + } +}; + +export fn entry() void { + const x = X.init(); + x.a(); +} + +// error +// backend=stage2 +// target=native +// +// :13:6: error: no field or member function named 'a' in '@typeInfo(@typeInfo(@TypeOf(tmp.X.init)).Fn.return_type.?).ErrorUnion.error_set!tmp.X' +// :13:6: note: consider using 'try', 'catch', or 'if' -- 2.54.0 From ac55685a94b3db97e9d2eadef0432948b3c16a03 Mon Sep 17 00:00:00 2001 From: wooster0 Date: Wed, 22 May 2024 02:16:56 +0900 Subject: [PATCH 6/6] Sema: add missing declared here note --- src/Sema.zig | 1 + .../expected_optional_type_got_container.zig | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 test/cases/compile_errors/expected_optional_type_got_container.zig diff --git a/src/Sema.zig b/src/Sema.zig index a5c5f37e4cfc6fd2475b35c7d663243bf3ccd8cd..7a1885d652e23da8f1bc8664c1d16527f5367544 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2238,6 +2238,7 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non if (non_optional_ty.zigTypeTag(mod) == .ErrorUnion) { try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); } + try addDeclaredHereNote(sema, msg, non_optional_ty); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); diff --git a/test/cases/compile_errors/expected_optional_type_got_container.zig b/test/cases/compile_errors/expected_optional_type_got_container.zig new file mode 100644 index 0000000000000000000000000000000000000000..12bb6296292992193be2941dc859306c72be2990 --- /dev/null +++ b/test/cases/compile_errors/expected_optional_type_got_container.zig @@ -0,0 +1,16 @@ +export fn foo() void { + while (bar()) |x| { + _ = x; + } +} +const X = enum { a }; +fn bar() X { + return .a; +} + +// error +// backend=stage2 +// target=native +// +// :2:15: error: expected optional type, found 'tmp.X' +// :6:11: note: enum declared here -- 2.54.0