authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2023-07-21 03:22:59+02:00
committergravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2024-05-14 01:13:49+09:00
log9ae43567a3ef14a815482ccaa2a5b412a716743e
treecdd535a650d7fdde5eb6c43e1d8e2b040fee5366
parent8579904ddd489b73cb61721c31b9e9c14ed9e264

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.

4 files changed, 33 insertions(+), 10 deletions(-)

src/Sema.zig+6-4
...@@ -3568,9 +3568,10 @@ fn ensureResultUsed(...@@ -3568,9 +3568,10 @@ fn ensureResultUsed(
3568 const mod = sema.mod;3568 const mod = sema.mod;
3569 switch (ty.zigTypeTag(mod)) {3569 switch (ty.zigTypeTag(mod)) {
3570 .Void, .NoReturn => return,3570 .Void, .NoReturn => return,
3571 .ErrorSet, .ErrorUnion => {3571 .ErrorSet => return sema.fail(block, src, "error set is ignored", .{}),
3572 .ErrorUnion => {
3572 const msg = msg: {3573 const msg = msg: {
3573 const msg = try sema.errMsg(block, src, "error is ignored", .{});3574 const msg = try sema.errMsg(block, src, "error union is ignored", .{});
3574 errdefer msg.destroy(sema.gpa);3575 errdefer msg.destroy(sema.gpa);
3575 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});3576 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
3576 break :msg msg;3577 break :msg msg;
...@@ -3600,9 +3601,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3600,9 +3601,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3600 const src = inst_data.src();3601 const src = inst_data.src();
3601 const operand_ty = sema.typeOf(operand);3602 const operand_ty = sema.typeOf(operand);
3602 switch (operand_ty.zigTypeTag(mod)) {3603 switch (operand_ty.zigTypeTag(mod)) {
3603 .ErrorSet, .ErrorUnion => {3604 .ErrorSet => return sema.fail(block, src, "error set is discarded", .{}),
3605 .ErrorUnion => {
3604 const msg = msg: {3606 const msg = msg: {
3605 const msg = try sema.errMsg(block, src, "error is discarded", .{});3607 const msg = try sema.errMsg(block, src, "error union is discarded", .{});
3606 errdefer msg.destroy(sema.gpa);3608 errdefer msg.destroy(sema.gpa);
3607 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});3609 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
3608 break :msg msg;3610 break :msg msg;
test/cases/compile_errors/discarding_error_value.zig+7-2
...@@ -1,13 +1,18 @@...@@ -1,13 +1,18 @@
1export fn entry() void {1export fn entry1() void {
2 _ = foo();2 _ = foo();
3}3}
4fn foo() !void {4fn foo() !void {
5 return error.OutOfMemory;5 return error.OutOfMemory;
6}6}
7export fn entry2() void {
8 const x: error{a} = undefined;
9 _ = x;
10}
711
8// error12// error
9// backend=stage213// backend=stage2
10// target=native14// target=native
11//15//
12// :2:12: error: error is discarded16// :2:12: error: error union is discarded
13// :2:12: note: consider using 'try', 'catch', or 'if'17// :2:12: note: consider using 'try', 'catch', or 'if'
18// :9:9: error: error set is discarded
test/cases/compile_errors/ignored_deferred_function_call.zig+9-1
...@@ -5,9 +5,17 @@ fn bar() anyerror!i32 {...@@ -5,9 +5,17 @@ fn bar() anyerror!i32 {
5 return 0;5 return 0;
6}6}
77
8export fn foo2() void {
9 defer bar2();
10}
11fn bar2() anyerror {
12 return error.a;
13}
14
8// error15// error
9// backend=stage216// backend=stage2
10// target=native17// target=native
11//18//
12// :2:14: error: error is ignored19// :2:14: error: error union is ignored
13// :2:14: note: consider using 'try', 'catch', or 'if'20// :2:14: note: consider using 'try', 'catch', or 'if'
21// :9:15: error: error set is ignored
test/cases/compile_errors/ignored_expression_in_while_continuation.zig+11-3
...@@ -15,13 +15,21 @@ fn bad() anyerror!void {...@@ -15,13 +15,21 @@ fn bad() anyerror!void {
15 return error.Bad;15 return error.Bad;
16}16}
1717
18export fn d() void {
19 while (true) : (bad2()) {}
20}
21fn bad2() anyerror {
22 return error.Bad;
23}
24
18// error25// error
19// backend=stage226// backend=stage2
20// target=native27// target=native
21//28//
22// :2:24: error: error is ignored29// :2:24: error: error union is ignored
23// :2:24: note: consider using 'try', 'catch', or 'if'30// :2:24: note: consider using 'try', 'catch', or 'if'
24// :7:25: error: error is ignored31// :7:25: error: error union is ignored
25// :7:25: note: consider using 'try', 'catch', or 'if'32// :7:25: note: consider using 'try', 'catch', or 'if'
26// :12:25: error: error is ignored33// :12:25: error: error union is ignored
27// :12:25: note: consider using 'try', 'catch', or 'if'34// :12:25: note: consider using 'try', 'catch', or 'if'
35// :19:25: error: error set is ignored