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.
This commit is contained in:
Matthew Lugg 2025-12-20 19:03:22 +00:00
parent 3f08073f7d
commit 5611779f39
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E

View file

@ -29023,33 +29023,6 @@ fn coerceExtra(
else => {},
},
.error_union => switch (inst_ty.zigTypeTag(zcu)) {
.error_union => eu: {
if (maybe_inst_val) |inst_val| {
switch (inst_val.toIntern()) {
.undef => return pt.undefRef(dest_ty),
else => switch (zcu.intern_pool.indexToKey(inst_val.toIntern())) {
.error_union => |error_union| switch (error_union.val) {
.err_name => |err_name| {
const error_set_ty = inst_ty.errorUnionSet(zcu);
const error_set_val = Air.internedToRef((try pt.intern(.{ .err = .{
.ty = error_set_ty.toIntern(),
.name = err_name,
} })));
return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src);
},
.payload => |payload| {
const payload_val = Air.internedToRef(payload);
return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) {
error.NotCoercible => break :eu,
else => |e| return e,
};
},
},
else => unreachable,
},
}
}
},
.error_set => {
// E to E!T
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);