diff --git a/src/Sema.zig b/src/Sema.zig index 37fdf0adb5..7a1885d652 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2228,8 +2228,20 @@ 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'", .{}); + } + try addDeclaredHereNote(sema, msg, non_optional_ty); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); } fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { @@ -3557,9 +3569,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; @@ -3571,7 +3584,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); @@ -3589,9 +3602,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; @@ -9038,7 +9052,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); @@ -9531,7 +9545,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 }, ); } @@ -27875,6 +27889,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/discarding_error_value.zig b/test/cases/compile_errors/discarding_error_value.zig index c24d517d3e..eab3ecaf98 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/expected_optional_type_got_container.zig b/test/cases/compile_errors/expected_optional_type_got_container.zig new file mode 100644 index 0000000000..12bb629629 --- /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 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 a0247139ea..9c5e381e63 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 42e4c4e8c8..d820f8f410 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 1257636622..abe2b006b7 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 2067f3b716..4dd0e0fc39 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 3414d0861f..ed7eb80b50 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_function_call.zig b/test/cases/compile_errors/ignored_deferred_function_call.zig index 9537255d33..90c978b40f 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_deferred_statement_value.zig b/test/cases/compile_errors/ignored_deferred_statement_value.zig index 1f42efc3f5..70b88a4deb 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_expression_in_while_continuation.zig b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig index 4fa396190a..ca1b60da5e 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 diff --git a/test/cases/compile_errors/ignored_return_value.zig b/test/cases/compile_errors/ignored_return_value.zig index 08424c4fe9..f721bc8655 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 c73da84420..6c4ff442c5 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/method_call_on_error_union.zig b/test/cases/compile_errors/method_call_on_error_union.zig new file mode 100644 index 0000000000..4ce6b3baa8 --- /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' 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 7bde2c866d..1b4a64770b 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' 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 b3e83f202a..dae546df02 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 '_'