authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-11-16 21:48:57+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2024-01-09 14:42:11+11:00
log41360975669177ba8665a59d8074cee452467fc0
tree10af314021ee3027b888116a08f4815c74d169a6
parent063d55c50479659b171f72ac2ba2d13197f12138

zir: add switch_block_err_union


4 files changed, 159 insertions(+), 1 deletions(-)

src/AstGen.zig+2
......@@ -93,6 +93,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
9393 Zir.Inst.Call.Flags,
9494 Zir.Inst.BuiltinCall.Flags,
9595 Zir.Inst.SwitchBlock.Bits,
96 Zir.Inst.SwitchBlockErrUnion.Bits,
9697 Zir.Inst.FuncFancy.Bits,
9798 => @bitCast(@field(extra, field.name)),
9899
......@@ -2640,6 +2641,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26402641 .import,
26412642 .switch_block,
26422643 .switch_block_ref,
2644 .switch_block_err_union,
26432645 .union_init,
26442646 .field_type_ref,
26452647 .error_set_decl,
src/Sema.zig+1
......@@ -1097,6 +1097,7 @@ fn analyzeBodyInner(
10971097 .str => try sema.zirStr(inst),
10981098 .switch_block => try sema.zirSwitchBlock(block, inst, false),
10991099 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1100 .switch_block_err_union => @panic("TODO: implement lowering of switch_block_err_union"),
11001101 .type_info => try sema.zirTypeInfo(block, inst),
11011102 .size_of => try sema.zirSizeOf(block, inst),
11021103 .bit_size_of => try sema.zirBitSizeOf(block, inst),
src/Zir.zig+28-1
......@@ -100,6 +100,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
100100 Inst.Call.Flags,
101101 Inst.BuiltinCall.Flags,
102102 Inst.SwitchBlock.Bits,
103 Inst.SwitchBlockErrUnion.Bits,
103104 Inst.FuncFancy.Bits,
104105 => @bitCast(code.extra[i]),
105106
......@@ -685,6 +686,9 @@ pub const Inst = struct {
685686 /// A switch expression. Uses the `pl_node` union field.
686687 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
687688 switch_block_ref,
689 /// A switch on an error union `a catch |err| switch (err) {...}`.
690 /// Uses the `pl_node` union field. AST node is the `catch`, payload is `SwitchBlockErrUnion`.
691 switch_block_err_union,
688692 /// Check that operand type supports the dereference operand (.*).
689693 /// Uses the `un_node` field.
690694 validate_deref,
......@@ -1186,6 +1190,7 @@ pub const Inst = struct {
11861190 .set_eval_branch_quota,
11871191 .switch_block,
11881192 .switch_block_ref,
1193 .switch_block_err_union,
11891194 .validate_deref,
11901195 .validate_destructure,
11911196 .union_init,
......@@ -1483,6 +1488,7 @@ pub const Inst = struct {
14831488 .typeof_log2_int_type,
14841489 .switch_block,
14851490 .switch_block_ref,
1491 .switch_block_err_union,
14861492 .union_init,
14871493 .field_type_ref,
14881494 .enum_from_int,
......@@ -1735,6 +1741,7 @@ pub const Inst = struct {
17351741 .enum_literal = .str_tok,
17361742 .switch_block = .pl_node,
17371743 .switch_block_ref = .pl_node,
1744 .switch_block_err_union = .pl_node,
17381745 .validate_deref = .un_node,
17391746 .validate_destructure = .pl_node,
17401747 .field_type_ref = .pl_node,
......@@ -2776,6 +2783,26 @@ pub const Inst = struct {
27762783 index: u32,
27772784 };
27782785
2786 pub const SwitchBlockErrUnion = struct {
2787 operand: Ref,
2788 bits: Bits,
2789
2790 pub const Bits = packed struct(u32) {
2791 /// If true, one or more prongs have multiple items.
2792 has_multi_cases: bool,
2793 /// If true, there is an else prong. This is mutually exclusive with `has_under`.
2794 has_else: bool,
2795 scalar_cases_len: ScalarCasesLen,
2796
2797 pub const ScalarCasesLen = u30;
2798 };
2799
2800 pub const MultiProng = struct {
2801 items: []const Ref,
2802 body: []const Index,
2803 };
2804 };
2805
27792806 /// 0. multi_cases_len: u32 // If has_multi_cases is set.
27802807 /// 1. tag_capture_inst: u32 // If any_has_tag_capture is set. Index of instruction prongs use to refer to the inline tag capture.
27812808 /// 2. else_body { // If has_else or has_under is set.
......@@ -2824,7 +2851,7 @@ pub const Inst = struct {
28242851 };
28252852 };
28262853
2827 pub const Bits = packed struct {
2854 pub const Bits = packed struct(u32) {
28282855 /// If true, one or more prongs have multiple items.
28292856 has_multi_cases: bool,
28302857 /// If true, there is an else prong. This is mutually exclusive with `has_under`.
src/print_zir.zig+128
......@@ -464,6 +464,8 @@ const Writer = struct {
464464 .switch_block_ref,
465465 => try self.writeSwitchBlock(stream, inst),
466466
467 .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst),
468
467469 .field_val,
468470 .field_ptr,
469471 => try self.writePlNodeField(stream, inst),
......@@ -2026,6 +2028,132 @@ const Writer = struct {
20262028 try self.writeSrc(stream, inst_data.src());
20272029 }
20282030
2031 fn writeSwitchBlockErrUnion(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2032 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2033 const extra = self.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
2034
2035 var extra_index: usize = extra.end;
2036
2037 const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
2038 const multi_cases_len = self.code.extra[extra_index];
2039 extra_index += 1;
2040 break :blk multi_cases_len;
2041 } else 0;
2042
2043 try self.writeInstRef(stream, extra.data.operand);
2044
2045 self.indent += 2;
2046
2047 {
2048 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
2049 extra_index += 1;
2050
2051 assert(!info.is_inline);
2052 const body = self.code.bodySlice(extra_index, info.body_len);
2053 extra_index += body.len;
2054
2055 try stream.writeAll(",\n");
2056 try stream.writeByteNTimes(' ', self.indent);
2057 try stream.writeAll("non_err => ");
2058 try self.writeBracedBody(stream, body);
2059 }
2060
2061 if (extra.data.bits.has_else) {
2062 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
2063 extra_index += 1;
2064 const capture_text = switch (info.capture) {
2065 .none => "",
2066 .by_val => "by_val ",
2067 .by_ref => "by_ref ",
2068 };
2069 const inline_text = if (info.is_inline) "inline " else "";
2070 const body = self.code.bodySlice(extra_index, info.body_len);
2071 extra_index += body.len;
2072
2073 try stream.writeAll(",\n");
2074 try stream.writeByteNTimes(' ', self.indent);
2075 try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
2076 try self.writeBracedBody(stream, body);
2077 }
2078
2079 {
2080 const scalar_cases_len = extra.data.bits.scalar_cases_len;
2081 var scalar_i: usize = 0;
2082 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
2083 const item_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
2084 extra_index += 1;
2085 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
2086 extra_index += 1;
2087 const body = self.code.bodySlice(extra_index, info.body_len);
2088 extra_index += info.body_len;
2089
2090 try stream.writeAll(",\n");
2091 try stream.writeByteNTimes(' ', self.indent);
2092 switch (info.capture) {
2093 .none => {},
2094 .by_val => try stream.writeAll("by_val "),
2095 .by_ref => try stream.writeAll("by_ref "),
2096 }
2097 if (info.is_inline) try stream.writeAll("inline ");
2098 try self.writeInstRef(stream, item_ref);
2099 try stream.writeAll(" => ");
2100 try self.writeBracedBody(stream, body);
2101 }
2102 }
2103 {
2104 var multi_i: usize = 0;
2105 while (multi_i < multi_cases_len) : (multi_i += 1) {
2106 const items_len = self.code.extra[extra_index];
2107 extra_index += 1;
2108 const ranges_len = self.code.extra[extra_index];
2109 extra_index += 1;
2110 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
2111 extra_index += 1;
2112 const items = self.code.refSlice(extra_index, items_len);
2113 extra_index += items_len;
2114
2115 try stream.writeAll(",\n");
2116 try stream.writeByteNTimes(' ', self.indent);
2117 switch (info.capture) {
2118 .none => {},
2119 .by_val => try stream.writeAll("by_val "),
2120 .by_ref => try stream.writeAll("by_ref "),
2121 }
2122 if (info.is_inline) try stream.writeAll("inline ");
2123
2124 for (items, 0..) |item_ref, item_i| {
2125 if (item_i != 0) try stream.writeAll(", ");
2126 try self.writeInstRef(stream, item_ref);
2127 }
2128
2129 var range_i: usize = 0;
2130 while (range_i < ranges_len) : (range_i += 1) {
2131 const item_first = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
2132 extra_index += 1;
2133 const item_last = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
2134 extra_index += 1;
2135
2136 if (range_i != 0 or items.len != 0) {
2137 try stream.writeAll(", ");
2138 }
2139 try self.writeInstRef(stream, item_first);
2140 try stream.writeAll("...");
2141 try self.writeInstRef(stream, item_last);
2142 }
2143
2144 const body = self.code.bodySlice(extra_index, info.body_len);
2145 extra_index += info.body_len;
2146 try stream.writeAll(" => ");
2147 try self.writeBracedBody(stream, body);
2148 }
2149 }
2150
2151 self.indent -= 2;
2152
2153 try stream.writeAll(") ");
2154 try self.writeSrc(stream, inst_data.src());
2155 }
2156
20292157 fn writeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
20302158 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
20312159 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);