| author | |
| committer | |
| log | eb0f871cb90cf7e3a1cfa7a160d3f224b42fd799 |
| tree | 9f7eb7266e469439ecb3ab3205060b1b6eb47914 |
| parent | ae44e199a8caa8d26db04b81867acb81d54ba217 |
| parent | ac55685a94b3db97e9d2eadef0432948b3c16a03 |
| signature |
Sema: improvements to error messages related to the handling of (error) values16 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 | 2228 | }); |
| 2229 | 2229 | } |
| 2230 | 2230 | |
| 2231 | fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError { | |
| 2232 | return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)}); | |
| 2231 | fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError { | |
| 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 | } |
| 2234 | 2246 | |
| 2235 | 2247 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { |
| ... | ... | @@ -3557,9 +3569,10 @@ fn ensureResultUsed( |
| 3557 | 3569 | const mod = sema.mod; |
| 3558 | 3570 | switch (ty.zigTypeTag(mod)) { |
| 3559 | 3571 | .Void, .NoReturn => return, |
| 3560 | .ErrorSet, .ErrorUnion => { | |
| 3572 | .ErrorSet => return sema.fail(block, src, "error set is ignored", .{}), | |
| 3573 | .ErrorUnion => { | |
| 3561 | 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 | 3576 | errdefer msg.destroy(sema.gpa); |
| 3564 | 3577 | try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 3565 | 3578 | break :msg msg; |
| ... | ... | @@ -3571,7 +3584,7 @@ fn ensureResultUsed( |
| 3571 | 3584 | const msg = try sema.errMsg(block, src, "value of type '{}' ignored", .{ty.fmt(sema.mod)}); |
| 3572 | 3585 | errdefer msg.destroy(sema.gpa); |
| 3573 | 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 | 3588 | break :msg msg; |
| 3576 | 3589 | }; |
| 3577 | 3590 | return sema.failWithOwnedErrorMsg(block, msg); |
| ... | ... | @@ -3589,9 +3602,10 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3589 | 3602 | const src = inst_data.src(); |
| 3590 | 3603 | const operand_ty = sema.typeOf(operand); |
| 3591 | 3604 | switch (operand_ty.zigTypeTag(mod)) { |
| 3592 | .ErrorSet, .ErrorUnion => { | |
| 3605 | .ErrorSet => return sema.fail(block, src, "error set is discarded", .{}), | |
| 3606 | .ErrorUnion => { | |
| 3593 | 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 | 3609 | errdefer msg.destroy(sema.gpa); |
| 3596 | 3610 | try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 3597 | 3611 | break :msg msg; |
| ... | ... | @@ -9038,7 +9052,7 @@ fn analyzeOptionalPayloadPtr( |
| 9038 | 9052 | |
| 9039 | 9053 | const opt_type = optional_ptr_ty.childType(zcu); |
| 9040 | 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 | } |
| 9043 | 9057 | |
| 9044 | 9058 | const child_type = opt_type.optionalChild(zcu); |
| ... | ... | @@ -9531,7 +9545,7 @@ fn handleExternLibName( |
| 9531 | 9545 | return sema.fail( |
| 9532 | 9546 | block, |
| 9533 | 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 | 9549 | .{ lib_name, lib_name }, |
| 9536 | 9550 | ); |
| 9537 | 9551 | } |
| ... | ... | @@ -27875,6 +27889,9 @@ fn fieldCallBind( |
| 27875 | 27889 | const decl = mod.declPtr(decl_idx); |
| 27876 | 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 | 27895 | break :msg msg; |
| 27879 | 27896 | }; |
| 27880 | 27897 | return sema.failWithOwnedErrorMsg(block, msg); |
test/cases/compile_errors/discarding_error_value.zig+7-2| ... | ... | @@ -1,13 +1,18 @@ |
| 1 | export fn entry() void { | |
| 1 | export fn entry1() void { | |
| 2 | 2 | _ = foo(); |
| 3 | 3 | } |
| 4 | 4 | fn foo() !void { |
| 5 | 5 | return error.OutOfMemory; |
| 6 | 6 | } |
| 7 | export fn entry2() void { | |
| 8 | const x: error{a} = undefined; | |
| 9 | _ = x; | |
| 10 | } | |
| 7 | 11 | |
| 8 | 12 | // error |
| 9 | 13 | // backend=stage2 |
| 10 | 14 | // target=native |
| 11 | 15 | // |
| 12 | // :2:12: error: error is discarded | |
| 16 | // :2:12: error: error union is discarded | |
| 13 | 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 @@ |
| 1 | export fn foo() void { | |
| 2 | while (bar()) |x| { | |
| 3 | _ = x; | |
| 4 | } | |
| 5 | } | |
| 6 | const X = enum { a }; | |
| 7 | fn 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 | 23 | // |
| 24 | 24 | // :5:30: error: value of type 'usize' ignored |
| 25 | 25 | // :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 | 27 | // :9:30: error: value of type 'usize' ignored |
| 28 | 28 | // :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 | 30 | // :13:31: error: value of type 'bool' ignored |
| 31 | 31 | // :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 | 33 | // :16:42: error: value of type 'usize' ignored |
| 34 | 34 | // :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 | 24 | // |
| 25 | 25 | // :18:43: error: value of type 'type' ignored |
| 26 | 26 | // :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 | 11 | // |
| 12 | 12 | // :2:11: error: value of type 'i32' ignored |
| 13 | 13 | // :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 | 10 | // |
| 11 | 11 | // :3:9: error: value of type 'comptime_int' ignored |
| 12 | 12 | // :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 | 14 | // |
| 15 | 15 | // :2:5: error: value of type 'comptime_int' ignored |
| 16 | 16 | // :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 | 18 | // :5:5: error: value of type 'u8' ignored |
| 19 | 19 | // :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 | 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 | 15 | // error |
| 9 | 16 | // backend=stage2 |
| 10 | 17 | // target=native |
| 11 | 18 | // |
| 12 | // :2:14: error: error is ignored | |
| 19 | // :2:14: error: error union is ignored | |
| 13 | 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 | 10 | // |
| 11 | 11 | // :3:9: error: value of type 'comptime_int' ignored |
| 12 | 12 | // :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 | 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 | 25 | // error |
| 19 | 26 | // backend=stage2 |
| 20 | 27 | // target=native |
| 21 | 28 | // |
| 22 | // :2:24: error: error is ignored | |
| 29 | // :2:24: error: error union is ignored | |
| 23 | 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 | 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 | 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 | 11 | // |
| 12 | 12 | // :2:8: error: value of type 'i32' ignored |
| 13 | 13 | // :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 | 8 | // |
| 9 | 9 | // :2:5: error: value of type 'comptime_int' ignored |
| 10 | 10 | // :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 @@ |
| 1 | const X = struct { | |
| 2 | fn init() !X { | |
| 3 | return error.a; | |
| 4 | } | |
| 5 | ||
| 6 | fn a(x: X) void { | |
| 7 | _ = x; | |
| 8 | } | |
| 9 | }; | |
| 10 | ||
| 11 | export 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 | 12 | // target=native |
| 13 | 13 | // |
| 14 | 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 | 32 | // |
| 33 | 33 | // :5:25: error: value of type 'usize' ignored |
| 34 | 34 | // :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 | 36 | // :10:26: error: value of type 'usize' ignored |
| 37 | 37 | // :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 | 39 | // :15:26: error: value of type 'usize' ignored |
| 40 | 40 | // :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 | 42 | // :20:23: error: value of type 'bool' ignored |
| 43 | 43 | // :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 | 45 | // :25:34: error: value of type 'usize' ignored |
| 46 | 46 | // :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 '_' |