authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-05-21 22:37:00+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-05-21 22:37:00+03:00
logeb0f871cb90cf7e3a1cfa7a160d3f224b42fd799
tree9f7eb7266e469439ecb3ab3205060b1b6eb47914
parentae44e199a8caa8d26db04b81867acb81d54ba217
parentac55685a94b3db97e9d2eadef0432948b3c16a03
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19961 from wooster0/errorstuff

Sema: improvements to error messages related to the handling of (error) values

16 files changed, 108 insertions(+), 32 deletions(-)

src/Sema.zig+26-9
...@@ -2228,8 +2228,20 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T...@@ -2228,8 +2228,20 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T
2228 });2228 });
2229}2229}
22302230
2231fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError {2231fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError {
2232 return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)});2232 const mod = sema.mod;
2233 const msg = msg: {
2234 const msg = try sema.errMsg(block, src, "expected optional type, found '{}'", .{
2235 non_optional_ty.fmt(mod),
2236 });
2237 errdefer msg.destroy(sema.gpa);
2238 if (non_optional_ty.zigTypeTag(mod) == .ErrorUnion) {
2239 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
2240 }
2241 try addDeclaredHereNote(sema, msg, non_optional_ty);
2242 break :msg msg;
2243 };
2244 return sema.failWithOwnedErrorMsg(block, msg);
2233}2245}
22342246
2235fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {2247fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
...@@ -3557,9 +3569,10 @@ fn ensureResultUsed(...@@ -3557,9 +3569,10 @@ fn ensureResultUsed(
3557 const mod = sema.mod;3569 const mod = sema.mod;
3558 switch (ty.zigTypeTag(mod)) {3570 switch (ty.zigTypeTag(mod)) {
3559 .Void, .NoReturn => return,3571 .Void, .NoReturn => return,
3560 .ErrorSet, .ErrorUnion => {3572 .ErrorSet => return sema.fail(block, src, "error set is ignored", .{}),
3573 .ErrorUnion => {
3561 const msg = msg: {3574 const msg = msg: {
3562 const msg = try sema.errMsg(block, src, "error is ignored", .{});3575 const msg = try sema.errMsg(block, src, "error union is ignored", .{});
3563 errdefer msg.destroy(sema.gpa);3576 errdefer msg.destroy(sema.gpa);
3564 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});3577 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
3565 break :msg msg;3578 break :msg msg;
...@@ -3571,7 +3584,7 @@ fn ensureResultUsed(...@@ -3571,7 +3584,7 @@ fn ensureResultUsed(
3571 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)});3584 const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)});
3572 errdefer msg.destroy(sema.gpa);3585 errdefer msg.destroy(sema.gpa);
3573 try sema.errNote(block, src, msg, "all non-void values must be used", .{});3586 try sema.errNote(block, src, msg, "all non-void values must be used", .{});
3574 try sema.errNote(block, src, msg, "this error can be suppressed by assigning the value to '_'", .{});3587 try sema.errNote(block, src, msg, "to discard the value, assign it to '_'", .{});
3575 break :msg msg;3588 break :msg msg;
3576 };3589 };
3577 return sema.failWithOwnedErrorMsg(block, msg);3590 return sema.failWithOwnedErrorMsg(block, msg);
...@@ -3589,9 +3602,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3589,9 +3602,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3589 const src = inst_data.src();3602 const src = inst_data.src();
3590 const operand_ty = sema.typeOf(operand);3603 const operand_ty = sema.typeOf(operand);
3591 switch (operand_ty.zigTypeTag(mod)) {3604 switch (operand_ty.zigTypeTag(mod)) {
3592 .ErrorSet, .ErrorUnion => {3605 .ErrorSet => return sema.fail(block, src, "error set is discarded", .{}),
3606 .ErrorUnion => {
3593 const msg = msg: {3607 const msg = msg: {
3594 const msg = try sema.errMsg(block, src, "error is discarded", .{});3608 const msg = try sema.errMsg(block, src, "error union is discarded", .{});
3595 errdefer msg.destroy(sema.gpa);3609 errdefer msg.destroy(sema.gpa);
3596 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});3610 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
3597 break :msg msg;3611 break :msg msg;
...@@ -9038,7 +9052,7 @@ fn analyzeOptionalPayloadPtr(...@@ -9038,7 +9052,7 @@ fn analyzeOptionalPayloadPtr(
90389052
9039 const opt_type = optional_ptr_ty.childType(zcu);9053 const opt_type = optional_ptr_ty.childType(zcu);
9040 if (opt_type.zigTypeTag(zcu) != .Optional) {9054 if (opt_type.zigTypeTag(zcu) != .Optional) {
9041 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(zcu)});9055 return sema.failWithExpectedOptionalType(block, src, opt_type);
9042 }9056 }
90439057
9044 const child_type = opt_type.optionalChild(zcu);9058 const child_type = opt_type.optionalChild(zcu);
...@@ -9531,7 +9545,7 @@ fn handleExternLibName(...@@ -9531,7 +9545,7 @@ fn handleExternLibName(
9531 return sema.fail(9545 return sema.fail(
9532 block,9546 block,
9533 src_loc,9547 src_loc,
9534 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.",9548 "dependency on dynamic library '{s}' requires enabling Position Independent Code; fixed by '-l{s}' or '-fPIC'",
9535 .{ lib_name, lib_name },9549 .{ lib_name, lib_name },
9536 );9550 );
9537 }9551 }
...@@ -27875,6 +27889,9 @@ fn fieldCallBind(...@@ -27875,6 +27889,9 @@ fn fieldCallBind(
27875 const decl = mod.declPtr(decl_idx);27889 const decl = mod.declPtr(decl_idx);
27876 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)});27890 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)});
27877 }27891 }
27892 if (concrete_ty.zigTypeTag(mod) == .ErrorUnion) {
27893 try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
27894 }
27878 break :msg msg;27895 break :msg msg;
27879 };27896 };
27880 return sema.failWithOwnedErrorMsg(block, msg);27897 return sema.failWithOwnedErrorMsg(block, 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/expected_optional_type_got_container.zig created+16
...@@ -0,0 +1,16 @@
1export fn foo() void {
2 while (bar()) |x| {
3 _ = x;
4 }
5}
6const X = enum { a };
7fn bar() X {
8 return .a;
9}
10
11// error
12// backend=stage2
13// target=native
14//
15// :2:15: error: expected optional type, found 'tmp.X'
16// :6:11: note: enum declared here
test/cases/compile_errors/for_loop_body_expression_ignored.zig+4-4
...@@ -23,13 +23,13 @@ export fn f4() void {...@@ -23,13 +23,13 @@ export fn f4() void {
23//23//
24// :5:30: error: value of type 'usize' ignored24// :5:30: error: value of type 'usize' ignored
25// :5:30: note: all non-void values must be used25// :5:30: note: all non-void values must be used
26// :5:30: note: this error can be suppressed by assigning the value to '_'26// :5:30: note: to discard the value, assign it to '_'
27// :9:30: error: value of type 'usize' ignored27// :9:30: error: value of type 'usize' ignored
28// :9:30: note: all non-void values must be used28// :9:30: note: all non-void values must be used
29// :9:30: note: this error can be suppressed by assigning the value to '_'29// :9:30: note: to discard the value, assign it to '_'
30// :13:31: error: value of type 'bool' ignored30// :13:31: error: value of type 'bool' ignored
31// :13:31: note: all non-void values must be used31// :13:31: note: all non-void values must be used
32// :13:31: note: this error can be suppressed by assigning the value to '_'32// :13:31: note: to discard the value, assign it to '_'
33// :16:42: error: value of type 'usize' ignored33// :16:42: error: value of type 'usize' ignored
34// :16:42: note: all non-void values must be used34// :16:42: note: all non-void values must be used
35// :16:42: note: this error can be suppressed by assigning the value to '_'35// :16:42: note: to discard the value, assign it to '_'
test/cases/compile_errors/generic_instantiation_failure.zig+1-1
...@@ -24,4 +24,4 @@ pub export fn entry() void {...@@ -24,4 +24,4 @@ pub export fn entry() void {
24//24//
25// :18:43: error: value of type 'type' ignored25// :18:43: error: value of type 'type' ignored
26// :18:43: note: all non-void values must be used26// :18:43: note: all non-void values must be used
27// :18:43: note: this error can be suppressed by assigning the value to '_'27// :18:43: note: to discard the value, assign it to '_'
test/cases/compile_errors/ignored_assert-err-ok_return_value.zig+1-1
...@@ -11,4 +11,4 @@ fn bar() anyerror!i32 {...@@ -11,4 +11,4 @@ fn bar() anyerror!i32 {
11//11//
12// :2:11: error: value of type 'i32' ignored12// :2:11: error: value of type 'i32' ignored
13// :2:11: note: all non-void values must be used13// :2:11: note: all non-void values must be used
14// :2:11: note: this error can be suppressed by assigning the value to '_'14// :2:11: note: to discard the value, assign it to '_'
test/cases/compile_errors/ignored_comptime_statement_value.zig+1-1
...@@ -10,4 +10,4 @@ export fn foo() void {...@@ -10,4 +10,4 @@ export fn foo() void {
10//10//
11// :3:9: error: value of type 'comptime_int' ignored11// :3:9: error: value of type 'comptime_int' ignored
12// :3:9: note: all non-void values must be used12// :3:9: note: all non-void values must be used
13// :3:9: note: this error can be suppressed by assigning the value to '_'13// :3:9: note: to discard the value, assign it to '_'
test/cases/compile_errors/ignored_comptime_value.zig+2-2
...@@ -14,7 +14,7 @@ fn bar() u8 {...@@ -14,7 +14,7 @@ fn bar() u8 {
14//14//
15// :2:5: error: value of type 'comptime_int' ignored15// :2:5: error: value of type 'comptime_int' ignored
16// :2:5: note: all non-void values must be used16// :2:5: note: all non-void values must be used
17// :2:5: note: this error can be suppressed by assigning the value to '_'17// :2:5: note: to discard the value, assign it to '_'
18// :5:5: error: value of type 'u8' ignored18// :5:5: error: value of type 'u8' ignored
19// :5:5: note: all non-void values must be used19// :5:5: note: all non-void values must be used
20// :5:5: note: this error can be suppressed by assigning the value to '_'20// :5:5: note: to discard the value, assign it to '_'
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_deferred_statement_value.zig+1-1
...@@ -10,4 +10,4 @@ export fn foo() void {...@@ -10,4 +10,4 @@ export fn foo() void {
10//10//
11// :3:9: error: value of type 'comptime_int' ignored11// :3:9: error: value of type 'comptime_int' ignored
12// :3:9: note: all non-void values must be used12// :3:9: note: all non-void values must be used
13// :3:9: note: this error can be suppressed by assigning the value to '_'13// :3:9: note: to discard the value, assign it to '_'
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
test/cases/compile_errors/ignored_return_value.zig+1-1
...@@ -11,4 +11,4 @@ fn bar() i32 {...@@ -11,4 +11,4 @@ fn bar() i32 {
11//11//
12// :2:8: error: value of type 'i32' ignored12// :2:8: error: value of type 'i32' ignored
13// :2:8: note: all non-void values must be used13// :2:8: note: all non-void values must be used
14// :2:8: note: this error can be suppressed by assigning the value to '_'14// :2:8: note: to discard the value, assign it to '_'
test/cases/compile_errors/ignored_statement_value.zig+1-1
...@@ -8,4 +8,4 @@ export fn foo() void {...@@ -8,4 +8,4 @@ export fn foo() void {
8//8//
9// :2:5: error: value of type 'comptime_int' ignored9// :2:5: error: value of type 'comptime_int' ignored
10// :2:5: note: all non-void values must be used10// :2:5: note: all non-void values must be used
11// :2:5: note: this error can be suppressed by assigning the value to '_'11// :2:5: note: to discard the value, assign it to '_'
test/cases/compile_errors/method_call_on_error_union.zig created+21
...@@ -0,0 +1,21 @@
1const X = struct {
2 fn init() !X {
3 return error.a;
4 }
5
6 fn a(x: X) void {
7 _ = x;
8 }
9};
10
11export fn entry() void {
12 const x = X.init();
13 x.a();
14}
15
16// error
17// backend=stage2
18// target=native
19//
20// :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'
21// :13:6: note: consider using 'try', 'catch', or 'if'
test/cases/compile_errors/while_expected_optional_got_error_union.zig+1
...@@ -12,3 +12,4 @@ fn bar() anyerror!i32 {...@@ -12,3 +12,4 @@ fn bar() anyerror!i32 {
12// target=native12// target=native
13//13//
14// :2:15: error: expected optional type, found 'anyerror!i32'14// :2:15: error: expected optional type, found 'anyerror!i32'
15// :2:15: note: consider using 'try', 'catch', or 'if'
test/cases/compile_errors/while_loop_body_expression_ignored.zig+5-5
...@@ -32,16 +32,16 @@ export fn f5() void {...@@ -32,16 +32,16 @@ export fn f5() void {
32//32//
33// :5:25: error: value of type 'usize' ignored33// :5:25: error: value of type 'usize' ignored
34// :5:25: note: all non-void values must be used34// :5:25: note: all non-void values must be used
35// :5:25: note: this error can be suppressed by assigning the value to '_'35// :5:25: note: to discard the value, assign it to '_'
36// :10:26: error: value of type 'usize' ignored36// :10:26: error: value of type 'usize' ignored
37// :10:26: note: all non-void values must be used37// :10:26: note: all non-void values must be used
38// :10:26: note: this error can be suppressed by assigning the value to '_'38// :10:26: note: to discard the value, assign it to '_'
39// :15:26: error: value of type 'usize' ignored39// :15:26: error: value of type 'usize' ignored
40// :15:26: note: all non-void values must be used40// :15:26: note: all non-void values must be used
41// :15:26: note: this error can be suppressed by assigning the value to '_'41// :15:26: note: to discard the value, assign it to '_'
42// :20:23: error: value of type 'bool' ignored42// :20:23: error: value of type 'bool' ignored
43// :20:23: note: all non-void values must be used43// :20:23: note: all non-void values must be used
44// :20:23: note: this error can be suppressed by assigning the value to '_'44// :20:23: note: to discard the value, assign it to '_'
45// :25:34: error: value of type 'usize' ignored45// :25:34: error: value of type 'usize' ignored
46// :25:34: note: all non-void values must be used46// :25:34: note: all non-void values must be used
47// :25:34: note: this error can be suppressed by assigning the value to '_'47// :25:34: note: to discard the value, assign it to '_'