Commit 7aa42f47b7

HydroH <iodizon@163.com>
2024-03-28 11:23:32
allow `@errorcast` to cast error sets to error unions
1 parent 1705388
Changed files (3)
src
test
behavior
cases
src/Sema.zig
@@ -22626,20 +22626,18 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
     const base_operand_ty = sema.typeOf(operand);
     const dest_tag = base_dest_ty.zigTypeTag(mod);
     const operand_tag = base_operand_ty.zigTypeTag(mod);
-    if (dest_tag != operand_tag) {
-        return sema.fail(block, src, "expected source and destination types to match, found '{s}' and '{s}'", .{
-            @tagName(operand_tag), @tagName(dest_tag),
-        });
-    } else if (dest_tag != .ErrorSet and dest_tag != .ErrorUnion) {
+
+    if (dest_tag != .ErrorSet and dest_tag != .ErrorUnion) {
         return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)});
     }
-    const dest_ty, const operand_ty = if (dest_tag == .ErrorUnion) .{
-        base_dest_ty.errorUnionSet(mod),
-        base_operand_ty.errorUnionSet(mod),
-    } else .{
-        base_dest_ty,
-        base_operand_ty,
-    };
+    if (operand_tag != .ErrorSet and operand_tag != .ErrorUnion) {
+        return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(operand_tag)});
+    }
+    if (dest_tag == .ErrorSet and operand_tag == .ErrorUnion) {
+        return sema.fail(block, src, "cannot cast an error union type to error set", .{});
+    }
+    const dest_ty = if (dest_tag == .ErrorUnion) base_dest_ty.errorUnionSet(mod) else base_dest_ty;
+    const operand_ty = if (operand_tag == .ErrorUnion) base_operand_ty.errorUnionSet(mod) else base_operand_ty;
 
     // operand must be defined since it can be an invalid error value
     const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand);
@@ -22681,7 +22679,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
         if (!dest_ty.isAnyError(mod)) check: {
             const operand_val = mod.intern_pool.indexToKey(val.toIntern());
             var error_name: InternPool.NullTerminatedString = undefined;
-            if (dest_tag == .ErrorUnion) {
+            if (operand_tag == .ErrorUnion) {
                 if (operand_val.error_union.val != .err_name) break :check;
                 error_name = operand_val.error_union.val.err_name;
             } else {
test/behavior/error.zig
@@ -1039,3 +1039,8 @@ test "errorCast to adhoc inferred error set" {
     };
     try std.testing.expect((try S.baz()) == 1234);
 }
+
+test "errorCast from error sets to error unions" {
+    const err_union: Set1!void = @errorCast(error.A);
+    try expectError(error.A, err_union);
+}
test/cases/compile_errors/@errorCast_with_bad_type.zig
@@ -0,0 +1,23 @@
+const err = error.Foo;
+
+export fn entry1() void {
+    const a: anyerror = @errorCast(1);
+    _ = a;
+}
+export fn entry2() void {
+    const a: i32 = @errorCast(err);
+    _ = a;
+}
+export fn entry3() void {
+    const e: anyerror!void = err;
+    const a: anyerror = @errorCast(e);
+    _ = a;
+}
+
+// error
+// backend=stage2
+// target=x86_64-linux
+//
+// :4:25: error: expected error set or error union type, found 'ComptimeInt'
+// :8:20: error: expected error set or error union type, found 'Int'
+// :13:25: error: cannot cast an error union type to error set