| author | |
| committer | |
| log | 19924ca2890964b411362c423dd9f4b10596a18f |
| tree | 0aa9fd860a4518b51d9595c75245797dcde95da2 |
| parent | 4d81e8ee915c3e012131cf90ed87cc8c6a01a934 |
Resolves: #214142 files changed, 44 insertions(+), 11 deletions(-)
src/Sema.zig+7-11| ... | ... | @@ -4487,7 +4487,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo |
| 4487 | 4487 | break :ty operand_ty.childType(zcu); |
| 4488 | 4488 | } else operand_ty; |
| 4489 | 4489 | |
| 4490 | const err_set_ty = err_set: { | |
| 4490 | const err_set_ty: Type = err_set: { | |
| 4491 | 4491 | // There are awkward cases, like `?E`. Our strategy is to repeatedly unwrap optionals |
| 4492 | 4492 | // until we hit an error union or set. |
| 4493 | 4493 | var cur_ty = sema.fn_ret_ty; |
| ... | ... | @@ -4496,16 +4496,12 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo |
| 4496 | 4496 | .error_set => break :err_set cur_ty, |
| 4497 | 4497 | .error_union => break :err_set cur_ty.errorUnionSet(zcu), |
| 4498 | 4498 | .optional => cur_ty = cur_ty.optionalChild(zcu), |
| 4499 | else => return sema.failWithOwnedErrorMsg(block, msg: { | |
| 4500 | const msg = try sema.errMsg(src, "expected '{}', found error set", .{sema.fn_ret_ty.fmt(pt)}); | |
| 4501 | errdefer msg.destroy(sema.gpa); | |
| 4502 | const ret_ty_src: LazySrcLoc = .{ | |
| 4503 | .base_node_inst = sema.getOwnerFuncDeclInst(), | |
| 4504 | .offset = .{ .node_offset_fn_type_ret_ty = 0 }, | |
| 4505 | }; | |
| 4506 | try sema.errNote(ret_ty_src, msg, "function cannot return an error", .{}); | |
| 4507 | break :msg msg; | |
| 4508 | }), | |
| 4499 | else => { | |
| 4500 | // This function cannot return an error. | |
| 4501 | // `try` is still valid if the error case is impossible, i.e. no error is returned. | |
| 4502 | // So, the result type has an error set of `error{}`. | |
| 4503 | break :err_set .fromInterned(try zcu.intern_pool.getErrorSetType(zcu.gpa, pt.tid, &.{})); | |
| 4504 | }, | |
| 4509 | 4505 | } |
| 4510 | 4506 | } |
| 4511 | 4507 | }; |
test/behavior/try.zig+37| ... | ... | @@ -86,3 +86,40 @@ test "try forwards result location" { |
| 86 | 86 | try expect((S.foo(false) catch return error.TestUnexpectedResult) == 123); |
| 87 | 87 | try std.testing.expectError(error.Foo, S.foo(true)); |
| 88 | 88 | } |
| 89 | ||
| 90 | test "'return try' of empty error set in function returning non-error" { | |
| 91 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO | |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 93 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 94 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 95 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 96 | ||
| 97 | const S = struct { | |
| 98 | fn succeed0() error{}!u32 { | |
| 99 | return 123; | |
| 100 | } | |
| 101 | fn succeed1() !u32 { | |
| 102 | return 456; | |
| 103 | } | |
| 104 | fn tryNoError0() u32 { | |
| 105 | return try succeed0(); | |
| 106 | } | |
| 107 | fn tryNoError1() u32 { | |
| 108 | return try succeed1(); | |
| 109 | } | |
| 110 | fn tryNoError2() u32 { | |
| 111 | const e: error{}!u32 = 789; | |
| 112 | return try e; | |
| 113 | } | |
| 114 | fn doTheTest() !void { | |
| 115 | const res0 = tryNoError0(); | |
| 116 | const res1 = tryNoError1(); | |
| 117 | const res2 = tryNoError2(); | |
| 118 | try expect(res0 == 123); | |
| 119 | try expect(res1 == 456); | |
| 120 | try expect(res2 == 789); | |
| 121 | } | |
| 122 | }; | |
| 123 | try S.doTheTest(); | |
| 124 | try comptime S.doTheTest(); | |
| 125 | } |