authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 13:21:07+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 20:10:18+03:00
logb0a55e1b3be3a274546f9c18016e9609d546bdb0
tree7517ed5fbbb06db79a9bac053eb60d098fd32c4d
parentdb0f372da8b25f4a911cd8e0b7f8e5cdfc64f940

Sema: make noreturn error union behave correctly


3 files changed, 88 insertions(+), 1 deletions(-)

src/Sema.zig+14
...@@ -6789,6 +6789,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6789,6 +6789,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
6789 error_set.fmt(sema.mod),6789 error_set.fmt(sema.mod),
6790 });6790 });
6791 }6791 }
6792 if (payload.zigTypeTag() == .Opaque) {
6793 return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
6794 payload.fmt(sema.mod),
6795 });
6796 } else if (payload.zigTypeTag() == .ErrorSet) {
6797 return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
6798 payload.fmt(sema.mod),
6799 });
6800 }
6792 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);6801 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
6793 return sema.addType(err_union_ty);6802 return sema.addType(err_union_ty);
6794}6803}
...@@ -25763,6 +25772,11 @@ fn analyzeIsNonErrComptimeOnly(...@@ -25763,6 +25772,11 @@ fn analyzeIsNonErrComptimeOnly(
25763 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;25772 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
25764 assert(ot == .ErrorUnion);25773 assert(ot == .ErrorUnion);
2576525774
25775 const payload_ty = operand_ty.errorUnionPayload();
25776 if (payload_ty.zigTypeTag() == .NoReturn) {
25777 return Air.Inst.Ref.bool_false;
25778 }
25779
25766 if (Air.refToIndex(operand)) |operand_inst| {25780 if (Air.refToIndex(operand)) |operand_inst| {
25767 switch (sema.air_instructions.items(.tag)[operand_inst]) {25781 switch (sema.air_instructions.items(.tag)[operand_inst]) {
25768 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,25782 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
test/behavior/error.zig+61-1
...@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {...@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725 try expect(value == 255);725 try expect(value == 255);
726}726}
727727
728test {728test "pointer to error union payload" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -736,3 +736,63 @@ test {...@@ -736,3 +736,63 @@ test {
736 const payload_ptr = &(err_union catch unreachable);736 const payload_ptr = &(err_union catch unreachable);
737 try expect(payload_ptr.* == 15);737 try expect(payload_ptr.* == 15);
738}738}
739
740const NoReturn = struct {
741 var a: u32 = undefined;
742 fn someData() bool {
743 a -= 1;
744 return a == 0;
745 }
746 fn loop() !noreturn {
747 while (true) {
748 if (someData())
749 return error.GenericFailure;
750 }
751 }
752 fn testTry() anyerror {
753 try loop();
754 }
755 fn testCatch() anyerror {
756 loop() catch return error.OtherFailure;
757 @compileError("bad");
758 }
759};
760
761test "error union of noreturn used with if" {
762 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
767
768 NoReturn.a = 64;
769 if (NoReturn.loop()) {
770 @compileError("bad");
771 } else |err| {
772 try expect(err == error.GenericFailure);
773 }
774}
775
776test "error union of noreturn used with try" {
777 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
778 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
782
783 NoReturn.a = 64;
784 const err = NoReturn.testTry();
785 try expect(err == error.GenericFailure);
786}
787
788test "error union of noreturn used with catch" {
789 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
793 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
794
795 NoReturn.a = 64;
796 const err = NoReturn.testCatch();
797 try expect(err == error.OtherFailure);
798}
test/cases/compile_errors/invalid_error_union_payload_type.zig created+13
...@@ -0,0 +1,13 @@
1comptime {
2 _ = anyerror!anyopaque;
3}
4comptime {
5 _ = anyerror!anyerror;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:18: error: error union with payload of opaque type 'anyopaque' not allowed
13// :5:18: error: error union with payload of error set type 'anyerror' not allowed