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 {...@@ -93,6 +93,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
93 Zir.Inst.Call.Flags,93 Zir.Inst.Call.Flags,
94 Zir.Inst.BuiltinCall.Flags,94 Zir.Inst.BuiltinCall.Flags,
95 Zir.Inst.SwitchBlock.Bits,95 Zir.Inst.SwitchBlock.Bits,
96 Zir.Inst.SwitchBlockErrUnion.Bits,
96 Zir.Inst.FuncFancy.Bits,97 Zir.Inst.FuncFancy.Bits,
97 => @bitCast(@field(extra, field.name)),98 => @bitCast(@field(extra, field.name)),
9899
...@@ -2640,6 +2641,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2640,6 +2641,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2640 .import,2641 .import,
2641 .switch_block,2642 .switch_block,
2642 .switch_block_ref,2643 .switch_block_ref,
2644 .switch_block_err_union,
2643 .union_init,2645 .union_init,
2644 .field_type_ref,2646 .field_type_ref,
2645 .error_set_decl,2647 .error_set_decl,
src/Sema.zig+1
...@@ -1097,6 +1097,7 @@ fn analyzeBodyInner(...@@ -1097,6 +1097,7 @@ fn analyzeBodyInner(
1097 .str => try sema.zirStr(inst),1097 .str => try sema.zirStr(inst),
1098 .switch_block => try sema.zirSwitchBlock(block, inst, false),1098 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1099 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),1099 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1100 .switch_block_err_union => @panic("TODO: implement lowering of switch_block_err_union"),
1100 .type_info => try sema.zirTypeInfo(block, inst),1101 .type_info => try sema.zirTypeInfo(block, inst),
1101 .size_of => try sema.zirSizeOf(block, inst),1102 .size_of => try sema.zirSizeOf(block, inst),
1102 .bit_size_of => try sema.zirBitSizeOf(block, inst),1103 .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) {...@@ -100,6 +100,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
100 Inst.Call.Flags,100 Inst.Call.Flags,
101 Inst.BuiltinCall.Flags,101 Inst.BuiltinCall.Flags,
102 Inst.SwitchBlock.Bits,102 Inst.SwitchBlock.Bits,
103 Inst.SwitchBlockErrUnion.Bits,
103 Inst.FuncFancy.Bits,104 Inst.FuncFancy.Bits,
104 => @bitCast(code.extra[i]),105 => @bitCast(code.extra[i]),
105106
...@@ -685,6 +686,9 @@ pub const Inst = struct {...@@ -685,6 +686,9 @@ pub const Inst = struct {
685 /// A switch expression. Uses the `pl_node` union field.686 /// A switch expression. Uses the `pl_node` union field.
686 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.687 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
687 switch_block_ref,688 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,
688 /// Check that operand type supports the dereference operand (.*).692 /// Check that operand type supports the dereference operand (.*).
689 /// Uses the `un_node` field.693 /// Uses the `un_node` field.
690 validate_deref,694 validate_deref,
...@@ -1186,6 +1190,7 @@ pub const Inst = struct {...@@ -1186,6 +1190,7 @@ pub const Inst = struct {
1186 .set_eval_branch_quota,1190 .set_eval_branch_quota,
1187 .switch_block,1191 .switch_block,
1188 .switch_block_ref,1192 .switch_block_ref,
1193 .switch_block_err_union,
1189 .validate_deref,1194 .validate_deref,
1190 .validate_destructure,1195 .validate_destructure,
1191 .union_init,1196 .union_init,
...@@ -1483,6 +1488,7 @@ pub const Inst = struct {...@@ -1483,6 +1488,7 @@ pub const Inst = struct {
1483 .typeof_log2_int_type,1488 .typeof_log2_int_type,
1484 .switch_block,1489 .switch_block,
1485 .switch_block_ref,1490 .switch_block_ref,
1491 .switch_block_err_union,
1486 .union_init,1492 .union_init,
1487 .field_type_ref,1493 .field_type_ref,
1488 .enum_from_int,1494 .enum_from_int,
...@@ -1735,6 +1741,7 @@ pub const Inst = struct {...@@ -1735,6 +1741,7 @@ pub const Inst = struct {
1735 .enum_literal = .str_tok,1741 .enum_literal = .str_tok,
1736 .switch_block = .pl_node,1742 .switch_block = .pl_node,
1737 .switch_block_ref = .pl_node,1743 .switch_block_ref = .pl_node,
1744 .switch_block_err_union = .pl_node,
1738 .validate_deref = .un_node,1745 .validate_deref = .un_node,
1739 .validate_destructure = .pl_node,1746 .validate_destructure = .pl_node,
1740 .field_type_ref = .pl_node,1747 .field_type_ref = .pl_node,
...@@ -2776,6 +2783,26 @@ pub const Inst = struct {...@@ -2776,6 +2783,26 @@ pub const Inst = struct {
2776 index: u32,2783 index: u32,
2777 };2784 };
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
2779 /// 0. multi_cases_len: u32 // If has_multi_cases is set.2806 /// 0. multi_cases_len: u32 // If has_multi_cases is set.
2780 /// 1. tag_capture_inst: u32 // If any_has_tag_capture is set. Index of instruction prongs use to refer to the inline tag capture.2807 /// 1. tag_capture_inst: u32 // If any_has_tag_capture is set. Index of instruction prongs use to refer to the inline tag capture.
2781 /// 2. else_body { // If has_else or has_under is set.2808 /// 2. else_body { // If has_else or has_under is set.
...@@ -2824,7 +2851,7 @@ pub const Inst = struct {...@@ -2824,7 +2851,7 @@ pub const Inst = struct {
2824 };2851 };
2825 };2852 };
28262853
2827 pub const Bits = packed struct {2854 pub const Bits = packed struct(u32) {
2828 /// If true, one or more prongs have multiple items.2855 /// If true, one or more prongs have multiple items.
2829 has_multi_cases: bool,2856 has_multi_cases: bool,
2830 /// If true, there is an else prong. This is mutually exclusive with `has_under`.2857 /// 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 {...@@ -464,6 +464,8 @@ const Writer = struct {
464 .switch_block_ref,464 .switch_block_ref,
465 => try self.writeSwitchBlock(stream, inst),465 => try self.writeSwitchBlock(stream, inst),
466466
467 .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst),
468
467 .field_val,469 .field_val,
468 .field_ptr,470 .field_ptr,
469 => try self.writePlNodeField(stream, inst),471 => try self.writePlNodeField(stream, inst),
...@@ -2026,6 +2028,132 @@ const Writer = struct {...@@ -2026,6 +2028,132 @@ const Writer = struct {
2026 try self.writeSrc(stream, inst_data.src());2028 try self.writeSrc(stream, inst_data.src());
2027 }2029 }
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
2029 fn writeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {2157 fn writeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2030 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;2158 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2031 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);2159 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);