| author | |
| committer | |
| log | 9ae43567a3ef14a815482ccaa2a5b412a716743e |
| tree | cdd535a650d7fdde5eb6c43e1d8e2b040fee5366 |
| parent | 8579904ddd489b73cb61721c31b9e9c14ed9e264 |
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 @@ |
| 1 | export fn entry() void { | 1 | export fn entry1() void { |
| 2 | _ = foo(); | 2 | _ = foo(); |
| 3 | } | 3 | } |
| 4 | fn foo() !void { | 4 | fn foo() !void { |
| 5 | return error.OutOfMemory; | 5 | return error.OutOfMemory; |
| 6 | } | 6 | } |
| 7 | export fn entry2() void { | ||
| 8 | const x: error{a} = undefined; | ||
| 9 | _ = x; | ||
| 10 | } | ||
| 7 | 11 | ||
| 8 | // error | 12 | // error |
| 9 | // backend=stage2 | 13 | // backend=stage2 |
| 10 | // target=native | 14 | // target=native |
| 11 | // | 15 | // |
| 12 | // :2:12: error: error is discarded | 16 | // :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 | } |
| 7 | 7 | ||
| 8 | export fn foo2() void { | ||
| 9 | defer bar2(); | ||
| 10 | } | ||
| 11 | fn bar2() anyerror { | ||
| 12 | return error.a; | ||
| 13 | } | ||
| 14 | |||
| 8 | // error | 15 | // error |
| 9 | // backend=stage2 | 16 | // backend=stage2 |
| 10 | // target=native | 17 | // target=native |
| 11 | // | 18 | // |
| 12 | // :2:14: error: error is ignored | 19 | // :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 | } |
| 17 | 17 | ||
| 18 | export fn d() void { | ||
| 19 | while (true) : (bad2()) {} | ||
| 20 | } | ||
| 21 | fn bad2() anyerror { | ||
| 22 | return error.Bad; | ||
| 23 | } | ||
| 24 | |||
| 18 | // error | 25 | // error |
| 19 | // backend=stage2 | 26 | // backend=stage2 |
| 20 | // target=native | 27 | // target=native |
| 21 | // | 28 | // |
| 22 | // :2:24: error: error is ignored | 29 | // :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 ignored | 31 | // :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 ignored | 33 | // :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 |