| author | |
| committer | |
| log | 41360975669177ba8665a59d8074cee452467fc0 |
| tree | 10af314021ee3027b888116a08f4815c74d169a6 |
| parent | 063d55c50479659b171f72ac2ba2d13197f12138 |
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)), |
| 98 | 99 | ||
| ... | @@ -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]), |
| 105 | 106 | ||
| ... | @@ -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 | }; |
| 2778 | 2785 | ||
| 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 | }; |
| 2826 | 2853 | ||
| 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), |
| 466 | 466 | ||
| 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 | } |
| 2028 | 2030 | ||
| 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); |