authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-07-28 00:07:15+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-28 04:24:52+00:00
log5f0bde63582c800352b2d11e20bec650bd266a6f
tree894151cb1a91158ed6b98989598dd992c8730c3f
parentb8e22d20022f533de701b5efa9e28a196de664f3

add helpful error note for when function cannot return an error

This has caused frequent confusion since it looks like you are handling errors correctly with a try but you forgot to change your return type.

2 files changed, 43 insertions(+), 6 deletions(-)

src/ir.cpp+21-6
...@@ -20603,17 +20603,25 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -20603,17 +20603,25 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
20603 return ira->codegen->invalid_inst_gen;20603 return ira->codegen->invalid_inst_gen;
20604 }20604 }
2060520605
20606 ZigType *expected_return_type = result_loc->value->type->data.pointer.child_type;
20607
20606 IrInstGen *dummy_value = ir_const(ira, source_instr, return_type);20608 IrInstGen *dummy_value = ir_const(ira, source_instr, return_type);
20607 dummy_value->value->special = ConstValSpecialRuntime;20609 dummy_value->value->special = ConstValSpecialRuntime;
20608 IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr,20610 IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr,
20609 dummy_value, result_loc->value->type->data.pointer.child_type);20611 dummy_value, expected_return_type);
20610 if (type_is_invalid(dummy_result->value->type))20612 if (type_is_invalid(dummy_result->value->type)) {
20613 if ((return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) &&
20614 expected_return_type->id != ZigTypeIdErrorUnion && expected_return_type->id != ZigTypeIdErrorSet)
20615 {
20616 add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg,
20617 ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error"));
20618 }
20611 return ira->codegen->invalid_inst_gen;20619 return ira->codegen->invalid_inst_gen;
20612 ZigType *res_child_type = result_loc->value->type->data.pointer.child_type;
20613 if (res_child_type == ira->codegen->builtin_types.entry_anytype) {
20614 res_child_type = return_type;
20615 }20620 }
20616 if (!handle_is_ptr(ira->codegen, res_child_type)) {20621 if (expected_return_type == ira->codegen->builtin_types.entry_anytype) {
20622 expected_return_type = return_type;
20623 }
20624 if (!handle_is_ptr(ira->codegen, expected_return_type)) {
20617 ir_reset_result(call_result_loc);20625 ir_reset_result(call_result_loc);
20618 result_loc = nullptr;20626 result_loc = nullptr;
20619 }20627 }
...@@ -30907,6 +30915,13 @@ static IrInstGen *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstSrcEndEx...@@ -30907,6 +30915,13 @@ static IrInstGen *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstSrcEndEx
30907 IrInstGen *store_ptr = ir_analyze_store_ptr(ira, &instruction->base.base, result_loc, value,30915 IrInstGen *store_ptr = ir_analyze_store_ptr(ira, &instruction->base.base, result_loc, value,
30908 instruction->result_loc->allow_write_through_const);30916 instruction->result_loc->allow_write_through_const);
30909 if (type_is_invalid(store_ptr->value->type)) {30917 if (type_is_invalid(store_ptr->value->type)) {
30918 if (instruction->result_loc->id == ResultLocIdReturn &&
30919 (value->value->type->id == ZigTypeIdErrorUnion || value->value->type->id == ZigTypeIdErrorSet) &&
30920 ira->explicit_return_type->id != ZigTypeIdErrorUnion && ira->explicit_return_type->id != ZigTypeIdErrorSet)
30921 {
30922 add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg,
30923 ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error"));
30924 }
30910 return ira->codegen->invalid_inst_gen;30925 return ira->codegen->invalid_inst_gen;
30911 }30926 }
30912 }30927 }
test/compile_errors.zig+22
...@@ -18,6 +18,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -18,6 +18,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18 "tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers",18 "tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers",
19 });19 });
2020
21 cases.addTest("helpful return type error message",
22 \\export fn foo() u32 {
23 \\ return error.Ohno;
24 \\}
25 \\fn bar() !u32 {
26 \\ return error.Ohno;
27 \\}
28 \\export fn baz() void {
29 \\ try bar();
30 \\}
31 \\export fn quux() u32 {
32 \\ return bar();
33 \\}
34 , &[_][]const u8{
35 "tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}'",
36 "tmp.zig:1:17: note: function cannot return an error",
37 "tmp.zig:8:5: error: expected type 'void', found '@TypeOf(bar).ReturnType.ErrorSet'",
38 "tmp.zig:7:17: note: function cannot return an error",
39 "tmp.zig:11:15: error: expected type 'u32', found '@TypeOf(bar).ReturnType.ErrorSet!u32'",
40 "tmp.zig:10:18: note: function cannot return an error",
41 });
42
21 cases.addTest("int/float conversion to comptime_int/float",43 cases.addTest("int/float conversion to comptime_int/float",
22 \\export fn foo() void {44 \\export fn foo() void {
23 \\ var a: f32 = 2;45 \\ var a: f32 = 2;