From e4c0b848a46347fccced787488605ac66e83c38a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 7 Jun 2022 17:48:53 +0300 Subject: [PATCH] Sema: allow simple else body even when all errors handled --- src/Sema.zig | 30 ++++++++++++++++++++++++++++-- test/behavior/error.zig | 27 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 7bc011e226..550190654b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7774,7 +7774,12 @@ fn zirSwitchCapture( } switch (operand_ty.zigTypeTag()) { - .ErrorSet => return sema.bitCast(block, block.switch_else_err_ty.?, operand, operand_src), + .ErrorSet => if (block.switch_else_err_ty) |some| { + return sema.bitCast(block, some, operand, operand_src); + } else { + try block.addUnreachable(operand_src, false); + return Air.Inst.Ref.unreachable_value; + }, else => return operand, } } @@ -8194,7 +8199,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError ); } else_error_ty = Type.@"anyerror"; - } else { + } else else_validation: { var maybe_msg: ?*Module.ErrorMsg = null; errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); @@ -8231,6 +8236,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) { + + // In order to enable common patterns for generic code allow simple else bodies + // else => unreachable, + // else => return, + // else => |e| return e, + // even if all the possible errors were already handled. + const tags = sema.code.instructions.items(.tag); + for (special.body) |else_inst| switch (tags[else_inst]) { + .dbg_block_begin, + .dbg_block_end, + .dbg_stmt, + .dbg_var_val, + .switch_capture, + .ret_type, + .as_node, + .ret_node, + .@"unreachable", + => {}, + else => break, + } else break :else_validation; + return sema.fail( block, special_prong_src, diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 0fedd7dff0..ac51ec1eae 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -769,3 +769,30 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" { }; try S.doTheTest(); } + +test "simple else prong allowed even when all errors handled" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const S = struct { + fn foo() !u8 { + return error.Foo; + } + }; + var value = S.foo() catch |err| switch (err) { + error.Foo => 255, + else => |e| return e, + }; + try expect(value == 255); + value = S.foo() catch |err| switch (err) { + error.Foo => 255, + else => unreachable, + }; + try expect(value == 255); + value = S.foo() catch |err| switch (err) { + error.Foo => 255, + else => return, + }; + try expect(value == 255); +}