authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-25 13:21:22+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-25 22:32:14+02:00
log5ff518fbb9ea2fb5a745841731912acbe2f046d9
treefc80a1951aa90248ad108463a10eaaa688ab07dd
parent26dfbf8122618de865e847bed18554f6b023198a

Sema: implement zirSwitchCapture for error sets


3 files changed, 80 insertions(+), 4 deletions(-)

src/Sema.zig+29-3
......@@ -6938,7 +6938,6 @@ fn zirSwitchCapture(
69386938 const switch_info = zir_datas[capture_info.switch_inst].pl_node;
69396939 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
69406940 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
6941 const switch_src = switch_info.src();
69426941 const operand_is_ref = switch_extra.data.bits.is_ref;
69436942 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
69446943 const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node;
......@@ -6965,7 +6964,29 @@ fn zirSwitchCapture(
69656964 }
69666965
69676966 if (is_multi) {
6968 return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{});
6967 const items = switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items;
6968
6969 var names: Module.ErrorSet.NameMap = .{};
6970 try names.ensureUnusedCapacity(sema.arena, items.len);
6971 for (items) |item| {
6972 const item_ref = sema.resolveInst(item);
6973 // Previous switch validation ensured this will succeed
6974 const item_val = sema.resolveConstValue(block, .unneeded, item_ref) catch unreachable;
6975 names.putAssumeCapacityNoClobber(
6976 item_val.getError().?,
6977 {},
6978 );
6979 }
6980
6981 // names must be sorted
6982 Module.ErrorSet.sortNames(&names);
6983 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
6984
6985 const operand = if (operand_is_ref)
6986 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
6987 else
6988 operand_ptr;
6989 return sema.bitCast(block, else_error_ty, operand, operand_src);
69696990 }
69706991 const scalar_prong = switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index);
69716992 const item = sema.resolveInst(scalar_prong.item);
......@@ -7022,7 +7043,12 @@ fn zirSwitchCapture(
70227043 return block.addStructFieldVal(operand, field_index, field.ty);
70237044 },
70247045 .ErrorSet => {
7025 return sema.fail(block, operand_src, "TODO implement Sema for zirSwitchCapture for error sets", .{});
7046 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
7047 const operand = if (operand_is_ref)
7048 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
7049 else
7050 operand_ptr;
7051 return sema.bitCast(block, item_ty, operand, operand_src);
70267052 },
70277053 else => {
70287054 return sema.fail(block, operand_src, "switch on type '{}' provides no capture value", .{
src/Zir.zig+47
......@@ -2620,6 +2620,53 @@ pub const Inst = struct {
26202620 };
26212621 }
26222622 }
2623
2624 pub const MultiProng = struct {
2625 items: []const Ref,
2626 body: []const Index,
2627 };
2628
2629 pub fn getMultiProng(
2630 self: SwitchBlock,
2631 zir: Zir,
2632 extra_end: usize,
2633 prong_index: usize,
2634 ) MultiProng {
2635 // +1 for self.bits.has_multi_cases == true
2636 var extra_index: usize = extra_end + 1;
2637
2638 if (self.bits.specialProng() != .none) {
2639 const body_len = zir.extra[extra_index];
2640 extra_index += 1;
2641 const body = zir.extra[extra_index..][0..body_len];
2642 extra_index += body.len;
2643 }
2644
2645 var scalar_i: usize = 0;
2646 while (scalar_i < self.bits.scalar_cases_len) : (scalar_i += 1) {
2647 extra_index += 1;
2648 const body_len = zir.extra[extra_index];
2649 extra_index += 1;
2650 extra_index += body_len;
2651 }
2652 var multi_i: u32 = 0;
2653 while (true) : (multi_i += 1) {
2654 const items_len = zir.extra[extra_index];
2655 extra_index += 2;
2656 const body_len = zir.extra[extra_index];
2657 extra_index += 1;
2658 const items = zir.refSlice(extra_index, items_len);
2659 extra_index += items_len;
2660 const body = zir.extra[extra_index..][0..body_len];
2661 extra_index += body_len;
2662
2663 if (multi_i < prong_index) continue;
2664 return .{
2665 .items = items,
2666 .body = body,
2667 };
2668 }
2669 }
26232670 };
26242671
26252672 pub const Field = struct {
test/behavior/switch.zig+4-1
......@@ -465,7 +465,10 @@ test "else prong of switch on error set excludes other cases" {
465465}
466466
467467test "switch prongs with error set cases make a new error set type for capture value" {
468 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
469472
470473 const S = struct {
471474 fn doTheTest() !void {