Sema: allow simple else body even when all errors handled

This commit is contained in:
Veikka Tuominen 2022-06-07 17:48:53 +03:00
parent d5e3d5d74c
commit e4c0b848a4
2 changed files with 55 additions and 2 deletions

View File

@ -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,

View File

@ -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);
}