diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-07-11 15:39:21 +0300 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-07-11 17:55:19 +0300 |
| commit | 20d4f7213dde1ffabe0880bbee46a1de44d586fc (patch) | |
| tree | e60caf13833e99bbd092b67743baceeac4bf4e6e | |
| parent | c9e1360cdba2bc0c20dc04a3d22fbc0002bcd70b (diff) | |
| download | zig-20d4f7213dde1ffabe0880bbee46a1de44d586fc.tar.gz zig-20d4f7213dde1ffabe0880bbee46a1de44d586fc.zip | |
Sema: add notes about function return type
16 files changed, 100 insertions, 32 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index a10695df1f..8356f06159 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4135,23 +4135,24 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v const ptr = try sema.resolveInst(extra.lhs); const operand = try sema.resolveInst(extra.rhs); + const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index| + zir_tags[ptr_index] == .ret_ptr + else + false; + // Check for the possibility of this pattern: // %a = ret_ptr // %b = store(%a, %c) // Where %c is an error union or error set. In such case we need to add // to the current function's inferred error set, if any. - if ((sema.typeOf(operand).zigTypeTag() == .ErrorUnion or + if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or sema.typeOf(operand).zigTypeTag() == .ErrorSet) and sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { - if (Zir.refToIndex(extra.lhs)) |ptr_index| { - if (zir_tags[ptr_index] == .ret_ptr) { - try sema.addToInferredErrorSet(operand); - } - } + try sema.addToInferredErrorSet(operand); } - return sema.storePtr(block, src, ptr, operand); + return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); } fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -5543,7 +5544,7 @@ fn analyzeCall( try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) else try sema.resolveInst(fn_info.ret_ty_ref); - const ret_ty_src = func_src; // TODO better source location + const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); // Create a fresh inferred error set type for inline/comptime calls. const fn_ret_ty = blk: { @@ -6885,7 +6886,7 @@ fn zirFunc( const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); const target = sema.mod.getTarget(); - const ret_ty_src = inst_data.src(); // TODO better source location + const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; var extra_index = extra.end; @@ -7467,13 +7468,20 @@ fn analyzeAs( zir_dest_type: Zir.Inst.Ref, zir_operand: Zir.Inst.Ref, ) CompileError!Air.Inst.Ref { + const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| + sema.code.instructions.items(.tag)[ptr_index] == .ret_type + else + false; const dest_ty = try sema.resolveType(block, src, zir_dest_type); const operand = try sema.resolveInst(zir_operand); if (dest_ty.tag() == .var_args_param) return operand; if (dest_ty.zigTypeTag() == .NoReturn) { return sema.fail(block, src, "cannot cast to noreturn", .{}); } - return sema.coerce(block, dest_ty, operand, src); + return sema.coerceExtra(block, dest_ty, operand, src, true, is_ret) catch |err| switch (err) { + error.NotCoercible => unreachable, + else => |e| return e, + }; } fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -13656,7 +13664,10 @@ fn analyzeRet( if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { try sema.addToInferredErrorSet(uncasted_operand); } - const operand = try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src); + const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, true, true) catch |err| switch (err) { + error.NotCoercible => unreachable, + else => |e| return e, + }; if (block.inlining) |inlining| { if (block.is_comptime) { @@ -19869,7 +19880,7 @@ fn coerce( inst: Air.Inst.Ref, inst_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { - return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true) catch |err| switch (err) { + return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true, false) catch |err| switch (err) { error.NotCoercible => unreachable, else => |e| return e, }; @@ -19888,6 +19899,7 @@ fn coerceExtra( inst: Air.Inst.Ref, inst_src: LazySrcLoc, report_err: bool, + is_ret: bool, ) CoersionError!Air.Inst.Ref { switch (dest_ty_unresolved.tag()) { .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), @@ -19939,7 +19951,7 @@ fn coerceExtra( // T to ?T const child_type = try dest_ty.optionalChildAlloc(sema.arena); - const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false) catch |err| switch (err) { + const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false, is_ret) catch |err| switch (err) { error.NotCoercible => { if (in_memory_result == .no_match) { // Try to give more useful notes @@ -20056,7 +20068,7 @@ fn coerceExtra( return sema.addConstant(dest_ty, Value.@"null"); }, .ComptimeInt => { - const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false) catch |err| switch (err) { + const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false, is_ret) catch |err| switch (err) { error.NotCoercible => break :pointer, else => |e| return e, }; @@ -20067,7 +20079,7 @@ fn coerceExtra( .signed => Type.isize, .unsigned => Type.usize, }; - const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false) catch |err| switch (err) { + const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false, is_ret) catch |err| switch (err) { error.NotCoercible => { // Try to give more useful notes in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); @@ -20414,6 +20426,19 @@ fn coerceExtra( if (!report_err) return error.NotCoercible; + if (is_ret and dest_ty.zigTypeTag() == .NoReturn) { + const msg = msg: { + const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); + errdefer msg.destroy(sema.gpa); + + const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; + const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); + try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } + const msg = msg: { const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); errdefer msg.destroy(sema.gpa); @@ -20436,6 +20461,20 @@ fn coerceExtra( } try in_memory_result.report(sema, block, inst_src, msg); + + // Add notes about function return type + if (is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { + const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; + const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); + if (inst_ty.isError() and !dest_ty.isError()) { + try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{}); + } else { + try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{}); + } + } + + // TODO maybe add "cannot store an error in type '{}'" note + break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); @@ -21372,6 +21411,8 @@ fn storePtr2( // TODO do the same thing for anon structs as for tuples above. // However, beware of the need to handle missing/extra fields. + const is_ret = air_tag == .ret_ptr; + // Detect if we are storing an array operand to a bitcasted vector pointer. // If so, we instead reach through the bitcasted pointer to the vector pointer, // bitcast the array operand to a vector, and then lower this as a store of @@ -21380,12 +21421,18 @@ fn storePtr2( // https://github.com/ziglang/zig/issues/11154 if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { const vector_ty = sema.typeOf(vector_ptr).childType(); - const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src); + const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { + error.NotCoercible => unreachable, + else => |e| return e, + }; try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); return; } - const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src); + const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { + error.NotCoercible => unreachable, + else => |e| return e, + }; const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { @@ -21415,7 +21462,11 @@ fn storePtr2( try sema.requireRuntimeBlock(block, runtime_src); try sema.queueFullTypeResolution(elem_ty); - _ = try block.addBinOp(air_tag, ptr, operand); + if (is_ret) { + _ = try block.addBinOp(.store, ptr, operand); + } else { + _ = try block.addBinOp(air_tag, ptr, operand); + } } /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector diff --git a/test/cases/aarch64-macos/hello_world_with_updates.1.zig b/test/cases/aarch64-macos/hello_world_with_updates.1.zig index 435747c2ee..e18a4c6a1e 100644 --- a/test/cases/aarch64-macos/hello_world_with_updates.1.zig +++ b/test/cases/aarch64-macos/hello_world_with_updates.1.zig @@ -2,4 +2,5 @@ pub export fn main() noreturn {} // error // -// :1:32: error: expected type 'noreturn', found 'void' +// :1:32: error: function declared 'noreturn' returns +// :1:22: note: 'noreturn' declared here diff --git a/test/cases/compile_errors/address_of_number_literal.zig b/test/cases/compile_errors/address_of_number_literal.zig index 2000561207..c6b41a1495 100644 --- a/test/cases/compile_errors/address_of_number_literal.zig +++ b/test/cases/compile_errors/address_of_number_literal.zig @@ -9,3 +9,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } // // :3:30: error: expected type '*const i32', found '*const comptime_int' // :3:30: note: pointer type child 'comptime_int' cannot cast into pointer type child 'i32' +// :3:10: note: function return type declared here diff --git a/test/cases/compile_errors/incompatible_sentinels.zig b/test/cases/compile_errors/incompatible_sentinels.zig index a2ed320e18..821a0a8c69 100644 --- a/test/cases/compile_errors/incompatible_sentinels.zig +++ b/test/cases/compile_errors/incompatible_sentinels.zig @@ -21,8 +21,10 @@ export fn entry4() void { // // :4:12: error: expected type '[*:0]u8', found '[*:255]u8' // :4:12: note: pointer sentinel '255' cannot cast into pointer sentinel '0' +// :3:35: note: function return type declared here // :7:12: error: expected type '[*:0]u8', found '[*]u8' // :7:12: note: destination pointer requires '0' sentinel +// :6:31: note: function return type declared here // :10:35: error: expected type '[2:0]u8', found '[2:255]u8' // :10:35: note: array sentinel '255' cannot cast into array sentinel '0' // :14:31: error: expected type '[2:0]u8', found '[2]u8' diff --git a/test/cases/compile_errors/incorrect_return_type.zig b/test/cases/compile_errors/incorrect_return_type.zig index 7b678b68e3..57cf54a023 100644 --- a/test/cases/compile_errors/incorrect_return_type.zig +++ b/test/cases/compile_errors/incorrect_return_type.zig @@ -21,3 +21,4 @@ // :8:16: error: expected type 'tmp.A', found 'tmp.B' // :10:12: note: struct declared here // :4:12: note: struct declared here +// :7:11: note: function return type declared here diff --git a/test/cases/compile_errors/invalid_address_space_coercion.zig b/test/cases/compile_errors/invalid_address_space_coercion.zig index 1c42260a0e..4633b12e0f 100644 --- a/test/cases/compile_errors/invalid_address_space_coercion.zig +++ b/test/cases/compile_errors/invalid_address_space_coercion.zig @@ -12,3 +12,4 @@ pub fn main() void { // // :2:12: error: expected type '*i32', found '*addrspace(.gs) i32' // :2:12: note: address space 'gs' cannot cast into address space 'generic' +// :1:34: note: function return type declared here diff --git a/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig b/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig index fb8e0d5fd4..4d7b3c627b 100644 --- a/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig +++ b/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig @@ -12,3 +12,4 @@ pub fn main() void { // // :2:12: error: expected type '*i32', found '*addrspace(.gs) i32' // :2:12: note: address space 'gs' cannot cast into address space 'generic' +// :1:34: note: function return type declared here diff --git a/test/cases/compile_errors/pointer_with_different_address_spaces.zig b/test/cases/compile_errors/pointer_with_different_address_spaces.zig index 3f8c961174..2bbea3d3b6 100644 --- a/test/cases/compile_errors/pointer_with_different_address_spaces.zig +++ b/test/cases/compile_errors/pointer_with_different_address_spaces.zig @@ -12,3 +12,4 @@ export fn entry2() void { // // :2:12: error: expected type '*addrspace(.fs) i32', found '*addrspace(.gs) i32' // :2:12: note: address space 'gs' cannot cast into address space 'fs' +// :1:34: note: function return type declared here diff --git a/test/cases/compile_errors/pointers_with_different_address_spaces.zig b/test/cases/compile_errors/pointers_with_different_address_spaces.zig index 2a7698d0d9..e952da2af5 100644 --- a/test/cases/compile_errors/pointers_with_different_address_spaces.zig +++ b/test/cases/compile_errors/pointers_with_different_address_spaces.zig @@ -12,3 +12,4 @@ pub fn main() void { // // :2:13: error: expected type '*i32', found '*addrspace(.gs) i32' // :2:13: note: address space 'gs' cannot cast into address space 'generic' +// :1:35: note: function return type declared here diff --git a/test/cases/compile_errors/slice_sentinel_mismatch-2.zig b/test/cases/compile_errors/slice_sentinel_mismatch-2.zig index b1ff905e26..3cc5ac4c39 100644 --- a/test/cases/compile_errors/slice_sentinel_mismatch-2.zig +++ b/test/cases/compile_errors/slice_sentinel_mismatch-2.zig @@ -10,3 +10,4 @@ comptime { _ = foo; } // // :3:12: error: expected type '[:0]u8', found '[]u8' // :3:12: note: destination pointer requires '0' sentinel +// :1:10: note: function return type declared here diff --git a/test/cases/compile_errors/stage1/test/helpful_return_type_error_message.zig b/test/cases/compile_errors/stage1/test/helpful_return_type_error_message.zig index 0e97c09de2..b8e48036de 100644 --- a/test/cases/compile_errors/stage1/test/helpful_return_type_error_message.zig +++ b/test/cases/compile_errors/stage1/test/helpful_return_type_error_message.zig @@ -16,15 +16,17 @@ export fn quux() u32 { } // error -// backend=stage1 +// backend=stage2 // target=native -// is_test=1 // -// tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}' -// tmp.zig:1:17: note: function cannot return an error -// tmp.zig:8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set' -// tmp.zig:7:17: note: function cannot return an error -// tmp.zig:11:15: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32' -// tmp.zig:10:17: note: function cannot return an error -// tmp.zig:15:14: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32' -// tmp.zig:14:5: note: cannot store an error in type 'u32' +// :2:18: error: expected type 'u32', found 'error{Ohno}' +// :1:17: note: function cannot return an error +// :8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set' +// :7:17: note: function cannot return an error +// :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' +// :10:17: note: function cannot return an error +// :11:15: note: cannot convert error union to payload type +// :11:15: note: consider using `try`, `catch`, or `if` +// :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' +// :15:14: note: cannot convert error union to payload type +// :15:14: note: consider using `try`, `catch`, or `if` diff --git a/test/cases/compile_errors/try_in_function_with_non_error_return_type.zig b/test/cases/compile_errors/try_in_function_with_non_error_return_type.zig index 2107c2a397..44d8b9ee56 100644 --- a/test/cases/compile_errors/try_in_function_with_non_error_return_type.zig +++ b/test/cases/compile_errors/try_in_function_with_non_error_return_type.zig @@ -8,3 +8,4 @@ fn something() anyerror!void { } // target=native // // :2:5: error: expected type 'void', found 'anyerror' +// :1:15: note: function cannot return an error diff --git a/test/cases/compile_errors/unreachable_with_return.zig b/test/cases/compile_errors/unreachable_with_return.zig index cc6439ca0f..5293734c82 100644 --- a/test/cases/compile_errors/unreachable_with_return.zig +++ b/test/cases/compile_errors/unreachable_with_return.zig @@ -5,4 +5,5 @@ export fn entry() void { a(); } // backend=stage2 // target=native // -// :1:18: error: expected type 'noreturn', found 'void' +// :1:18: error: function declared 'noreturn' returns +// :1:8: note: 'noreturn' declared here diff --git a/test/cases/compile_errors/variable_has_wrong_type.zig b/test/cases/compile_errors/variable_has_wrong_type.zig index ec21c610e0..e99921db9f 100644 --- a/test/cases/compile_errors/variable_has_wrong_type.zig +++ b/test/cases/compile_errors/variable_has_wrong_type.zig @@ -8,3 +8,4 @@ export fn f() i32 { // target=native // // :3:12: error: expected type 'i32', found '*const [1:0]u8' +// :1:15: note: function return type declared here diff --git a/test/cases/x86_64-linux/hello_world_with_updates.1.zig b/test/cases/x86_64-linux/hello_world_with_updates.1.zig index 9be388ab63..1f1a6a9682 100644 --- a/test/cases/x86_64-linux/hello_world_with_updates.1.zig +++ b/test/cases/x86_64-linux/hello_world_with_updates.1.zig @@ -2,4 +2,5 @@ pub export fn _start() noreturn {} // error // -// :1:34: error: expected type 'noreturn', found 'void' +// :1:34: error: function declared 'noreturn' returns +// :1:24: note: 'noreturn' declared here diff --git a/test/cases/x86_64-macos/hello_world_with_updates.1.zig b/test/cases/x86_64-macos/hello_world_with_updates.1.zig index 435747c2ee..e18a4c6a1e 100644 --- a/test/cases/x86_64-macos/hello_world_with_updates.1.zig +++ b/test/cases/x86_64-macos/hello_world_with_updates.1.zig @@ -2,4 +2,5 @@ pub export fn main() noreturn {} // error // -// :1:32: error: expected type 'noreturn', found 'void' +// :1:32: error: function declared 'noreturn' returns +// :1:22: note: 'noreturn' declared here |
