authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-12-20 19:03:22+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-12-21 13:07:03+00:00
log5611779f391c9ae48c0abf7662b1e9020be6ea14
tree0f9ea2887ce855db832743c9c73f0033161b9118
parent3f08073f7d2f0cd8aa086f1618a74106bf35086d
signaturelock-open Commit is signed but in an unrecognized format.

Sema: fix nested error union coercions

Previously, `E1!void` failed to coerce to `E2!E1!void` because it tried to coerce the `E1` error to an `E2` if comptime-known and refused to attempt any other coercion. This is a strange language rule with no clear justification, and breaks real use cases (such as calling `getOne` on an `Io.Queue(E!T)`). Instead, only error *sets* should try to coerce to an "error" value of an error union type.

1 files changed, 0 insertions(+), 27 deletions(-)

src/Sema.zig-27
...@@ -29023,33 +29023,6 @@ fn coerceExtra(...@@ -29023,33 +29023,6 @@ fn coerceExtra(
29023 else => {},29023 else => {},
29024 },29024 },
29025 .error_union => switch (inst_ty.zigTypeTag(zcu)) {29025 .error_union => switch (inst_ty.zigTypeTag(zcu)) {
29026 .error_union => eu: {
29027 if (maybe_inst_val) |inst_val| {
29028 switch (inst_val.toIntern()) {
29029 .undef => return pt.undefRef(dest_ty),
29030 else => switch (zcu.intern_pool.indexToKey(inst_val.toIntern())) {
29031 .error_union => |error_union| switch (error_union.val) {
29032 .err_name => |err_name| {
29033 const error_set_ty = inst_ty.errorUnionSet(zcu);
29034 const error_set_val = Air.internedToRef((try pt.intern(.{ .err = .{
29035 .ty = error_set_ty.toIntern(),
29036 .name = err_name,
29037 } })));
29038 return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src);
29039 },
29040 .payload => |payload| {
29041 const payload_val = Air.internedToRef(payload);
29042 return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) {
29043 error.NotCoercible => break :eu,
29044 else => |e| return e,
29045 };
29046 },
29047 },
29048 else => unreachable,
29049 },
29050 }
29051 }
29052 },
29053 .error_set => {29026 .error_set => {
29054 // E to E!T29027 // E to E!T
29055 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);29028 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);