Skip to content

Commit 07f14bd

Browse files
committed
stage2-wasm: fix error union handling
1 parent 0e109ad commit 07f14bd

File tree

2 files changed

+28
-15
lines changed

2 files changed

+28
-15
lines changed

src/arch/wasm/CodeGen.zig

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3130,7 +3130,13 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
31303130
.nav => |nav| return .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } },
31313131
.uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } },
31323132
.int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
3133-
.eu_payload => return cg.fail("Wasm TODO: lower error union payload pointer", .{}),
3133+
.eu_payload => |eu_ptr| try cg.lowerPtr(
3134+
eu_ptr,
3135+
offset + codegen.errUnionPayloadOffset(
3136+
Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
3137+
zcu,
3138+
),
3139+
),
31343140
.opt_payload => |opt_ptr| return cg.lowerPtr(opt_ptr, offset),
31353141
.field => |field| {
31363142
const base_ptr = Value.fromInterned(field.base);
@@ -4179,52 +4185,62 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr
41794185
return cg.finishAir(inst, result, &.{un_op});
41804186
}
41814187

4188+
/// E!T -> T op_is_ptr == false
4189+
/// *(E!T) -> *T op_is_prt == true
41824190
fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
41834191
const zcu = cg.pt.zcu;
41844192
const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
41854193

41864194
const operand = try cg.resolveInst(ty_op.operand);
41874195
const op_ty = cg.typeOf(ty_op.operand);
4188-
const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4189-
const payload_ty = err_ty.errorUnionPayload(zcu);
4196+
const eu_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4197+
const payload_ty = eu_ty.errorUnionPayload(zcu);
41904198

41914199
const result: WValue = result: {
41924200
if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
41934201
if (op_is_ptr) {
41944202
break :result cg.reuseOperand(ty_op.operand, operand);
4203+
} else {
4204+
break :result .none;
41954205
}
4196-
break :result .none;
41974206
}
41984207

4199-
const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));
4208+
const pl_offset: u32 = @intCast(errUnionPayloadOffset(payload_ty, zcu));
42004209
if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) {
42014210
break :result try cg.buildPointerOffset(operand, pl_offset, .new);
4211+
} else {
4212+
assert(isByRef(eu_ty, zcu, cg.target));
4213+
break :result try cg.load(operand, payload_ty, pl_offset);
42024214
}
42034215

4204-
break :result try cg.load(operand, payload_ty, pl_offset);
42054216
};
42064217
return cg.finishAir(inst, result, &.{ty_op.operand});
42074218
}
42084219

4220+
/// E!T -> E op_is_ptr == false
4221+
/// *(E!T) -> E op_is_prt == true
4222+
/// NOTE: op_is_ptr will not change return type
42094223
fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
42104224
const zcu = cg.pt.zcu;
42114225
const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42124226

42134227
const operand = try cg.resolveInst(ty_op.operand);
42144228
const op_ty = cg.typeOf(ty_op.operand);
4215-
const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4216-
const payload_ty = err_ty.errorUnionPayload(zcu);
4229+
const eu_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4230+
const payload_ty = eu_ty.errorUnionPayload(zcu);
42174231

42184232
const result: WValue = result: {
4219-
if (err_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
4233+
if (eu_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
42204234
break :result .{ .imm32 = 0 };
42214235
}
42224236

4223-
if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4237+
const err_offset: u32 = @intCast(errUnionErrorOffset(payload_ty, zcu));
4238+
if (op_is_ptr or isByRef(eu_ty, zcu, cg.target)) {
4239+
break :result try cg.load(operand, Type.anyerror, err_offset);
4240+
} else {
4241+
assert(!payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
42244242
break :result cg.reuseOperand(ty_op.operand, operand);
42254243
}
4226-
4227-
break :result try cg.load(operand, Type.anyerror, @intCast(errUnionErrorOffset(payload_ty, zcu)));
42284244
};
42294245
return cg.finishAir(inst, result, &.{ty_op.operand});
42304246
}

test/behavior/switch_on_captured_error.zig

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const builtin = @import("builtin");
77

88
test "switch on error union catch capture" {
99
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10-
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1110
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211

1312
const S = struct {
@@ -302,7 +301,6 @@ test "switch on error union catch capture" {
302301

303302
test "switch on error union if else capture" {
304303
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
305-
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
306304
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
307305

308306
const S = struct {
@@ -794,7 +792,6 @@ test "switch on error union if else capture" {
794792
}
795793

796794
fn testAddressOf() !void {
797-
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
798795
{
799796
const a: anyerror!usize = 0;
800797
const ptr = &(if (a) |*v| v.* else |e| switch (e) {

0 commit comments

Comments
 (0)