Sema: fix comptime coercion of payload to error union

This commit is contained in:
Andrew Kelley 2022-02-22 13:53:10 -07:00
parent 0d422ce342
commit b23f10b424
2 changed files with 28 additions and 23 deletions

View File

@ -14859,21 +14859,25 @@ fn coerce(
inst_ty.errorUnionPayload(),
inst_val.castTag(.eu_payload).?.data,
);
return sema.wrapErrorUnion(block, dest_ty, payload, inst_src);
return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src);
},
else => {
const error_set = try sema.addConstant(
inst_ty.errorUnionSet(),
inst_val,
);
return sema.wrapErrorUnion(block, dest_ty, error_set, inst_src);
return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src);
},
}
}
},
.ErrorSet => {
// E to E!T
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
},
else => {
// T to E!T or E to E!T
return sema.wrapErrorUnion(block, dest_ty, inst, inst_src);
// T to E!T
return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src);
},
},
.Union => switch (inst_ty.zigTypeTag()) {
@ -16688,7 +16692,24 @@ fn wrapOptional(
return block.addTyOp(.wrap_optional, dest_ty, inst);
}
fn wrapErrorUnion(
fn wrapErrorUnionPayload(
sema: *Sema,
block: *Block,
dest_ty: Type,
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
const dest_payload_ty = dest_ty.errorUnionPayload();
const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src);
if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| {
if (val.isUndef()) return sema.addConstUndef(dest_ty);
return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
}
try sema.requireRuntimeBlock(block, inst_src);
return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
}
fn wrapErrorUnionSet(
sema: *Sema,
block: *Block,
dest_ty: Type,
@ -16697,12 +16718,7 @@ fn wrapErrorUnion(
) !Air.Inst.Ref {
const inst_ty = sema.typeOf(inst);
const dest_err_set_ty = dest_ty.errorUnionSet();
const dest_payload_ty = dest_ty.errorUnionPayload();
if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
if (inst_ty.zigTypeTag() != .ErrorSet) {
_ = try sema.coerce(block, dest_payload_ty, inst, inst_src);
return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
}
switch (dest_err_set_ty.tag()) {
.anyerror => {},
.error_set_single => ok: {
@ -16739,15 +16755,8 @@ fn wrapErrorUnion(
}
try sema.requireRuntimeBlock(block, inst_src);
// we are coercing from E to E!T
if (inst_ty.zigTypeTag() == .ErrorSet) {
var coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
} else {
var coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src);
return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
}
const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
}
fn unionToTag(

View File

@ -907,8 +907,6 @@ test "enum literal casting to tagged union" {
const Bar = enum { A, B, C, D };
test "enum literal casting to error union with payload enum" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
var bar: error{B}!Bar = undefined;
bar = .B; // should never cast to the error set
@ -932,8 +930,6 @@ test "exporting enum type and value" {
}
test "constant enum initialization with differing sizes" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
try test3_1(test3_foo);
try test3_2(test3_bar);
}