authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-27 07:29:55+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 12:55:01+01:00
log39510cc7d1f6035e16aaa4f97991abbaddef463c
treeb30f1bdc56f73aab84ec2996111a96a7fdb88e4e
parentec27524da9b4200dc9ea39285e9c4c30cad28a98
signaturelock-open Commit is signed but in an unrecognized format.

Eliminate switch_capture_tag ZIR instruction

This is a follow-up to a previous commit which eliminated switch_capture and switch_capture_ref. All captures are now handled directly by `switch_block`, which has also eliminated some unnecessary Block data in Sema.

4 files changed, 194 insertions(+), 91 deletions(-)

src/AstGen.zig+47-15
...@@ -2612,7 +2612,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2612,7 +2612,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2612 .switch_block,2612 .switch_block,
2613 .switch_cond,2613 .switch_cond,
2614 .switch_cond_ref,2614 .switch_cond_ref,
2615 .switch_capture_tag,
2616 .struct_init_empty,2615 .struct_init_empty,
2617 .struct_init,2616 .struct_init,
2618 .struct_init_ref,2617 .struct_init_ref,
...@@ -2956,7 +2955,7 @@ fn deferStmt(...@@ -2956,7 +2955,7 @@ fn deferStmt(
2956 try gz.astgen.instructions.append(gz.astgen.gpa, .{2955 try gz.astgen.instructions.append(gz.astgen.gpa, .{
2957 .tag = .extended,2956 .tag = .extended,
2958 .data = .{ .extended = .{2957 .data = .{ .extended = .{
2959 .opcode = .errdefer_err_code,2958 .opcode = .value_placeholder,
2960 .small = undefined,2959 .small = undefined,
2961 .operand = undefined,2960 .operand = undefined,
2962 } },2961 } },
...@@ -6711,6 +6710,7 @@ fn switchExpr(...@@ -6711,6 +6710,7 @@ fn switchExpr(
6711 // for the following variables, make note of the special prong AST node index,6710 // for the following variables, make note of the special prong AST node index,
6712 // and bail out with a compile error if there are multiple special prongs present.6711 // and bail out with a compile error if there are multiple special prongs present.
6713 var any_payload_is_ref = false;6712 var any_payload_is_ref = false;
6713 var any_has_tag_capture = false;
6714 var scalar_cases_len: u32 = 0;6714 var scalar_cases_len: u32 = 0;
6715 var multi_cases_len: u32 = 0;6715 var multi_cases_len: u32 = 0;
6716 var inline_cases_len: u32 = 0;6716 var inline_cases_len: u32 = 0;
...@@ -6721,8 +6721,12 @@ fn switchExpr(...@@ -6721,8 +6721,12 @@ fn switchExpr(
6721 for (case_nodes) |case_node| {6721 for (case_nodes) |case_node| {
6722 const case = tree.fullSwitchCase(case_node).?;6722 const case = tree.fullSwitchCase(case_node).?;
6723 if (case.payload_token) |payload_token| {6723 if (case.payload_token) |payload_token| {
6724 if (token_tags[payload_token] == .asterisk) {6724 const ident = if (token_tags[payload_token] == .asterisk) blk: {
6725 any_payload_is_ref = true;6725 any_payload_is_ref = true;
6726 break :blk payload_token + 1;
6727 } else payload_token;
6728 if (token_tags[ident + 1] == .comma) {
6729 any_has_tag_capture = true;
6726 }6730 }
6727 }6731 }
6728 // Check for else/`_` prong.6732 // Check for else/`_` prong.
...@@ -6861,6 +6865,20 @@ fn switchExpr(...@@ -6861,6 +6865,20 @@ fn switchExpr(
6861 var case_scope = parent_gz.makeSubBlock(&block_scope.base);6865 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
6862 case_scope.instructions_top = GenZir.unstacked_top;6866 case_scope.instructions_top = GenZir.unstacked_top;
68636867
6868 // If any prong has an inline tag capture, allocate a shared dummy instruction for it
6869 const tag_inst = if (any_has_tag_capture) tag_inst: {
6870 const inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
6871 try astgen.instructions.append(astgen.gpa, .{
6872 .tag = .extended,
6873 .data = .{ .extended = .{
6874 .opcode = .value_placeholder,
6875 .small = undefined,
6876 .operand = undefined,
6877 } }, // TODO rename opcode
6878 });
6879 break :tag_inst inst;
6880 } else undefined;
6881
6864 // In this pass we generate all the item and prong expressions.6882 // In this pass we generate all the item and prong expressions.
6865 var multi_case_index: u32 = 0;6883 var multi_case_index: u32 = 0;
6866 var scalar_case_index: u32 = 0;6884 var scalar_case_index: u32 = 0;
...@@ -6874,7 +6892,7 @@ fn switchExpr(...@@ -6874,7 +6892,7 @@ fn switchExpr(
6874 var dbg_var_inst: Zir.Inst.Ref = undefined;6892 var dbg_var_inst: Zir.Inst.Ref = undefined;
6875 var dbg_var_tag_name: ?u32 = null;6893 var dbg_var_tag_name: ?u32 = null;
6876 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;6894 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;
6877 var tag_inst: Zir.Inst.Index = 0;6895 var has_tag_capture = false;
6878 var capture_val_scope: Scope.LocalVal = undefined;6896 var capture_val_scope: Scope.LocalVal = undefined;
6879 var tag_scope: Scope.LocalVal = undefined;6897 var tag_scope: Scope.LocalVal = undefined;
68806898
...@@ -6925,14 +6943,9 @@ fn switchExpr(...@@ -6925,14 +6943,9 @@ fn switchExpr(
6925 }6943 }
6926 const tag_name = try astgen.identAsString(tag_token);6944 const tag_name = try astgen.identAsString(tag_token);
6927 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");6945 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");
6928 tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);6946
6929 try astgen.instructions.append(gpa, .{6947 assert(any_has_tag_capture);
6930 .tag = .switch_capture_tag,6948 has_tag_capture = true;
6931 .data = .{ .un_tok = .{
6932 .operand = cond,
6933 .src_tok = case_scope.tokenIndexToRelative(tag_token),
6934 } },
6935 });
69366949
6937 tag_scope = .{6950 tag_scope = .{
6938 .parent = payload_sub_scope,6951 .parent = payload_sub_scope,
...@@ -6998,7 +7011,6 @@ fn switchExpr(...@@ -6998,7 +7011,6 @@ fn switchExpr(
6998 case_scope.instructions_top = parent_gz.instructions.items.len;7011 case_scope.instructions_top = parent_gz.instructions.items.len;
6999 defer case_scope.unstack();7012 defer case_scope.unstack();
70007013
7001 if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst);
7002 try case_scope.addDbgBlockBegin();7014 try case_scope.addDbgBlockBegin();
7003 if (dbg_var_name) |some| {7015 if (dbg_var_name) |some| {
7004 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);7016 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
...@@ -7018,7 +7030,8 @@ fn switchExpr(...@@ -7018,7 +7030,8 @@ fn switchExpr(
7018 const case_slice = case_scope.instructionsSlice();7030 const case_slice = case_scope.instructionsSlice();
7019 // Since we use the switch_block instruction itself to refer to the7031 // Since we use the switch_block instruction itself to refer to the
7020 // capture, which will not be added to the child block, we need to7032 // capture, which will not be added to the child block, we need to
7021 // handle ref_table manually.7033 // handle ref_table manually, and the same for the inline tag
7034 // capture instruction.
7022 const refs_len = refs: {7035 const refs_len = refs: {
7023 var n: usize = 0;7036 var n: usize = 0;
7024 var check_inst = switch_block;7037 var check_inst = switch_block;
...@@ -7026,18 +7039,31 @@ fn switchExpr(...@@ -7026,18 +7039,31 @@ fn switchExpr(
7026 n += 1;7039 n += 1;
7027 check_inst = ref_inst;7040 check_inst = ref_inst;
7028 }7041 }
7042 if (has_tag_capture) {
7043 check_inst = tag_inst;
7044 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7045 n += 1;
7046 check_inst = ref_inst;
7047 }
7048 }
7029 break :refs n;7049 break :refs n;
7030 };7050 };
7031 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);7051 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7032 try payloads.ensureUnusedCapacity(gpa, body_len);7052 try payloads.ensureUnusedCapacity(gpa, body_len);
7033 payloads.items[body_len_index] = @bitCast(u32, Zir.Inst.SwitchBlock.ProngInfo{7053 payloads.items[body_len_index] = @bitCast(u32, Zir.Inst.SwitchBlock.ProngInfo{
7034 .body_len = @intCast(u29, body_len),7054 .body_len = @intCast(u28, body_len),
7035 .capture = capture,7055 .capture = capture,
7036 .is_inline = case.inline_token != null,7056 .is_inline = case.inline_token != null,
7057 .has_tag_capture = has_tag_capture,
7037 });7058 });
7038 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {7059 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
7039 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);7060 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7040 }7061 }
7062 if (has_tag_capture) {
7063 if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
7064 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7065 }
7066 }
7041 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);7067 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7042 }7068 }
7043 }7069 }
...@@ -7046,6 +7072,7 @@ fn switchExpr(...@@ -7046,6 +7072,7 @@ fn switchExpr(
70467072
7047 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +7073 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
7048 @boolToInt(multi_cases_len != 0) +7074 @boolToInt(multi_cases_len != 0) +
7075 @boolToInt(any_has_tag_capture) +
7049 payloads.items.len - case_table_end);7076 payloads.items.len - case_table_end);
70507077
7051 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{7078 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
...@@ -7054,6 +7081,7 @@ fn switchExpr(...@@ -7054,6 +7081,7 @@ fn switchExpr(
7054 .has_multi_cases = multi_cases_len != 0,7081 .has_multi_cases = multi_cases_len != 0,
7055 .has_else = special_prong == .@"else",7082 .has_else = special_prong == .@"else",
7056 .has_under = special_prong == .under,7083 .has_under = special_prong == .under,
7084 .any_has_tag_capture = any_has_tag_capture,
7057 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),7085 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),
7058 },7086 },
7059 });7087 });
...@@ -7062,6 +7090,10 @@ fn switchExpr(...@@ -7062,6 +7090,10 @@ fn switchExpr(
7062 astgen.extra.appendAssumeCapacity(multi_cases_len);7090 astgen.extra.appendAssumeCapacity(multi_cases_len);
7063 }7091 }
70647092
7093 if (any_has_tag_capture) {
7094 astgen.extra.appendAssumeCapacity(tag_inst);
7095 }
7096
7065 const zir_datas = astgen.instructions.items(.data);7097 const zir_datas = astgen.instructions.items(.data);
7066 const zir_tags = astgen.instructions.items(.tag);7098 const zir_tags = astgen.instructions.items(.tag);
70677099
src/Sema.zig+122-60
...@@ -277,9 +277,6 @@ pub const Block = struct {...@@ -277,9 +277,6 @@ pub const Block = struct {
277277
278 c_import_buf: ?*std.ArrayList(u8) = null,278 c_import_buf: ?*std.ArrayList(u8) = null,
279279
280 /// Value for switch_capture in an inline case
281 inline_case_capture: Air.Inst.Ref = .none,
282
283 const ComptimeReason = union(enum) {280 const ComptimeReason = union(enum) {
284 c_import: struct {281 c_import: struct {
285 block: *Block,282 block: *Block,
...@@ -1013,7 +1010,6 @@ fn analyzeBodyInner(...@@ -1013,7 +1010,6 @@ fn analyzeBodyInner(
1013 .switch_block => try sema.zirSwitchBlock(block, inst),1010 .switch_block => try sema.zirSwitchBlock(block, inst),
1014 .switch_cond => try sema.zirSwitchCond(block, inst, false),1011 .switch_cond => try sema.zirSwitchCond(block, inst, false),
1015 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),1012 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
1016 .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst),
1017 .type_info => try sema.zirTypeInfo(block, inst),1013 .type_info => try sema.zirTypeInfo(block, inst),
1018 .size_of => try sema.zirSizeOf(block, inst),1014 .size_of => try sema.zirSizeOf(block, inst),
1019 .bit_size_of => try sema.zirBitSizeOf(block, inst),1015 .bit_size_of => try sema.zirBitSizeOf(block, inst),
...@@ -1217,7 +1213,7 @@ fn analyzeBodyInner(...@@ -1217,7 +1213,7 @@ fn analyzeBodyInner(
1217 i += 1;1213 i += 1;
1218 continue;1214 continue;
1219 },1215 },
1220 .errdefer_err_code => unreachable, // never appears in a body1216 .value_placeholder => unreachable, // never appears in a body
1221 };1217 };
1222 },1218 },
12231219
...@@ -10092,6 +10088,9 @@ const SwitchProngAnalysis = struct {...@@ -10092,6 +10088,9 @@ const SwitchProngAnalysis = struct {
10092 else_error_ty: ?Type,10088 else_error_ty: ?Type,
10093 /// The index of the `switch_block` instruction itself.10089 /// The index of the `switch_block` instruction itself.
10094 switch_block_inst: Zir.Inst.Index,10090 switch_block_inst: Zir.Inst.Index,
10091 /// The dummy index into which inline tag captures should be placed. May be
10092 /// undefined if no prong has a tag capture.
10093 tag_capture_inst: Zir.Inst.Index,
1009510094
10096 /// Resolve a switch prong which is determined at comptime to have no peers.10095 /// Resolve a switch prong which is determined at comptime to have no peers.
10097 /// Uses `resolveBlockBody`. Sets up captures as needed.10096 /// Uses `resolveBlockBody`. Sets up captures as needed.
...@@ -10106,10 +10105,23 @@ const SwitchProngAnalysis = struct {...@@ -10106,10 +10105,23 @@ const SwitchProngAnalysis = struct {
10106 /// The set of all values which can reach this prong. May be undefined10105 /// The set of all values which can reach this prong. May be undefined
10107 /// if the prong is special or contains ranges.10106 /// if the prong is special or contains ranges.
10108 case_vals: []const Air.Inst.Ref,10107 case_vals: []const Air.Inst.Ref,
10108 /// The inline capture of this prong. If this is not an inline prong,
10109 /// this is `.none`.
10110 inline_case_capture: Air.Inst.Ref,
10111 /// Whether this prong has an inline tag capture. If `true`, then
10112 /// `inline_case_capture` cannot be `.none`.
10113 has_tag_capture: bool,
10109 merges: *Block.Merges,10114 merges: *Block.Merges,
10110 ) CompileError!Air.Inst.Ref {10115 ) CompileError!Air.Inst.Ref {
10111 const sema = spa.sema;10116 const sema = spa.sema;
10112 const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src();10117 const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src();
10118
10119 if (has_tag_capture) {
10120 const tag_ref = try spa.analyzeTagCapture(child_block, raw_capture_src, inline_case_capture);
10121 sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
10122 }
10123 defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
10124
10113 switch (capture) {10125 switch (capture) {
10114 .none => {10126 .none => {
10115 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);10127 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
...@@ -10122,6 +10134,7 @@ const SwitchProngAnalysis = struct {...@@ -10122,6 +10134,7 @@ const SwitchProngAnalysis = struct {
10122 prong_type == .special,10134 prong_type == .special,
10123 raw_capture_src,10135 raw_capture_src,
10124 case_vals,10136 case_vals,
10137 inline_case_capture,
10125 );10138 );
1012610139
10127 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {10140 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
...@@ -10150,8 +10163,21 @@ const SwitchProngAnalysis = struct {...@@ -10150,8 +10163,21 @@ const SwitchProngAnalysis = struct {
10150 /// The set of all values which can reach this prong. May be undefined10163 /// The set of all values which can reach this prong. May be undefined
10151 /// if the prong is special or contains ranges.10164 /// if the prong is special or contains ranges.
10152 case_vals: []const Air.Inst.Ref,10165 case_vals: []const Air.Inst.Ref,
10166 /// The inline capture of this prong. If this is not an inline prong,
10167 /// this is `.none`.
10168 inline_case_capture: Air.Inst.Ref,
10169 /// Whether this prong has an inline tag capture. If `true`, then
10170 /// `inline_case_capture` cannot be `.none`.
10171 has_tag_capture: bool,
10153 ) CompileError!void {10172 ) CompileError!void {
10154 const sema = spa.sema;10173 const sema = spa.sema;
10174
10175 if (has_tag_capture) {
10176 const tag_ref = try spa.analyzeTagCapture(case_block, raw_capture_src, inline_case_capture);
10177 sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
10178 }
10179 defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
10180
10155 switch (capture) {10181 switch (capture) {
10156 .none => {10182 .none => {
10157 return sema.analyzeBodyRuntimeBreak(case_block, prong_body);10183 return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
...@@ -10164,6 +10190,7 @@ const SwitchProngAnalysis = struct {...@@ -10164,6 +10190,7 @@ const SwitchProngAnalysis = struct {
10164 prong_type == .special,10190 prong_type == .special,
10165 raw_capture_src,10191 raw_capture_src,
10166 case_vals,10192 case_vals,
10193 inline_case_capture,
10167 );10194 );
1016810195
10169 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {10196 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
...@@ -10179,6 +10206,33 @@ const SwitchProngAnalysis = struct {...@@ -10179,6 +10206,33 @@ const SwitchProngAnalysis = struct {
10179 }10206 }
10180 }10207 }
1018110208
10209 fn analyzeTagCapture(
10210 spa: SwitchProngAnalysis,
10211 block: *Block,
10212 raw_capture_src: Module.SwitchProngSrc,
10213 inline_case_capture: Air.Inst.Ref,
10214 ) CompileError!Air.Inst.Ref {
10215 const sema = spa.sema;
10216 const mod = sema.mod;
10217 const operand_ty = sema.typeOf(spa.operand);
10218 if (operand_ty.zigTypeTag(mod) != .Union) {
10219 const zir_datas = sema.code.instructions.items(.data);
10220 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
10221 const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
10222 const msg = msg: {
10223 const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
10224 operand_ty.fmt(mod),
10225 });
10226 errdefer msg.destroy(sema.gpa);
10227 try sema.addDeclaredHereNote(msg, operand_ty);
10228 break :msg msg;
10229 };
10230 return sema.failWithOwnedErrorMsg(msg);
10231 }
10232 assert(inline_case_capture != .none);
10233 return inline_case_capture;
10234 }
10235
10182 fn analyzeCapture(10236 fn analyzeCapture(
10183 spa: SwitchProngAnalysis,10237 spa: SwitchProngAnalysis,
10184 block: *Block,10238 block: *Block,
...@@ -10186,6 +10240,7 @@ const SwitchProngAnalysis = struct {...@@ -10186,6 +10240,7 @@ const SwitchProngAnalysis = struct {
10186 is_special_prong: bool,10240 is_special_prong: bool,
10187 raw_capture_src: Module.SwitchProngSrc,10241 raw_capture_src: Module.SwitchProngSrc,
10188 case_vals: []const Air.Inst.Ref,10242 case_vals: []const Air.Inst.Ref,
10243 inline_case_capture: Air.Inst.Ref,
10189 ) CompileError!Air.Inst.Ref {10244 ) CompileError!Air.Inst.Ref {
10190 const sema = spa.sema;10245 const sema = spa.sema;
10191 const mod = sema.mod;10246 const mod = sema.mod;
...@@ -10197,8 +10252,8 @@ const SwitchProngAnalysis = struct {...@@ -10197,8 +10252,8 @@ const SwitchProngAnalysis = struct {
10197 const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;10252 const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;
10198 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };10253 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
1019910254
10200 if (block.inline_case_capture != .none) {10255 if (inline_case_capture != .none) {
10201 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, "") catch unreachable;10256 const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;
10202 if (operand_ty.zigTypeTag(mod) == .Union) {10257 if (operand_ty.zigTypeTag(mod) == .Union) {
10203 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);10258 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
10204 const union_obj = mod.typeToUnion(operand_ty).?;10259 const union_obj = mod.typeToUnion(operand_ty).?;
...@@ -10233,7 +10288,7 @@ const SwitchProngAnalysis = struct {...@@ -10233,7 +10288,7 @@ const SwitchProngAnalysis = struct {
10233 } else if (capture_byref) {10288 } else if (capture_byref) {
10234 return sema.addConstantMaybeRef(block, operand_ty, item_val, true);10289 return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
10235 } else {10290 } else {
10236 return block.inline_case_capture;10291 return inline_case_capture;
10237 }10292 }
10238 }10293 }
1023910294
...@@ -10356,34 +10411,6 @@ const SwitchProngAnalysis = struct {...@@ -10356,34 +10411,6 @@ const SwitchProngAnalysis = struct {
10356 }10411 }
10357};10412};
1035810413
10359fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10360 const mod = sema.mod;
10361 const zir_datas = sema.code.instructions.items(.data);
10362 const inst_data = zir_datas[inst].un_tok;
10363 const src = inst_data.src();
10364
10365 const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?];
10366 const is_ref = switch_tag == .switch_cond_ref;
10367 const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node;
10368 const operand_ptr = try sema.resolveInst(cond_data.operand);
10369 const operand_ptr_ty = sema.typeOf(operand_ptr);
10370 const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;
10371
10372 if (operand_ty.zigTypeTag(mod) != .Union) {
10373 const msg = msg: {
10374 const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{
10375 operand_ty.fmt(mod),
10376 });
10377 errdefer msg.destroy(sema.gpa);
10378 try sema.addDeclaredHereNote(msg, operand_ty);
10379 break :msg msg;
10380 };
10381 return sema.failWithOwnedErrorMsg(msg);
10382 }
10383
10384 return block.inline_case_capture;
10385}
10386
10387fn zirSwitchCond(10414fn zirSwitchCond(
10388 sema: *Sema,10415 sema: *Sema,
10389 block: *Block,10416 block: *Block,
...@@ -10485,6 +10512,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10485,6 +10512,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10485 break :blk multi_cases_len;10512 break :blk multi_cases_len;
10486 } else 0;10513 } else 0;
1048710514
10515 const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
10516 const tag_capture_inst = sema.code.extra[header_extra_index];
10517 header_extra_index += 1;
10518 // SwitchProngAnalysis wants inst_map to have space for the tag capture.
10519 // Note that the normal capture is referred to via the switch block
10520 // index, which there is already necessarily space for.
10521 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});
10522 break :blk tag_capture_inst;
10523 } else undefined;
10524
10488 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);10525 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
10489 defer case_vals.deinit(gpa);10526 defer case_vals.deinit(gpa);
1049010527
...@@ -10493,11 +10530,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10493,11 +10530,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10493 end: usize,10530 end: usize,
10494 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,10531 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10495 is_inline: bool,10532 is_inline: bool,
10533 has_tag_capture: bool,
10496 };10534 };
1049710535
10498 const special_prong = extra.data.bits.specialProng();10536 const special_prong = extra.data.bits.specialProng();
10499 const special: Special = switch (special_prong) {10537 const special: Special = switch (special_prong) {
10500 .none => .{ .body = &.{}, .end = header_extra_index, .capture = .none, .is_inline = false },10538 .none => .{
10539 .body = &.{},
10540 .end = header_extra_index,
10541 .capture = .none,
10542 .is_inline = false,
10543 .has_tag_capture = false,
10544 },
10501 .under, .@"else" => blk: {10545 .under, .@"else" => blk: {
10502 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]);10546 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]);
10503 const extra_body_start = header_extra_index + 1;10547 const extra_body_start = header_extra_index + 1;
...@@ -10506,6 +10550,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10506,6 +10550,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10506 .end = extra_body_start + info.body_len,10550 .end = extra_body_start + info.body_len,
10507 .capture = info.capture,10551 .capture = info.capture,
10508 .is_inline = info.is_inline,10552 .is_inline = info.is_inline,
10553 .has_tag_capture = info.has_tag_capture,
10509 };10554 };
10510 },10555 },
10511 };10556 };
...@@ -11068,6 +11113,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11068,6 +11113,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11068 .operand_ptr = raw_operand.ptr,11113 .operand_ptr = raw_operand.ptr,
11069 .else_error_ty = else_error_ty,11114 .else_error_ty = else_error_ty,
11070 .switch_block_inst = inst,11115 .switch_block_inst = inst,
11116 .tag_capture_inst = tag_capture_inst,
11071 };11117 };
1107211118
11073 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);11119 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
...@@ -11122,7 +11168,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11122,7 +11168,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11122 const item = case_vals.items[scalar_i];11168 const item = case_vals.items[scalar_i];
11123 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;11169 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
11124 if (operand_val.eql(item_val, operand_ty, sema.mod)) {11170 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11125 if (info.is_inline) child_block.inline_case_capture = operand;
11126 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11171 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11127 return spa.resolveProngComptime(11172 return spa.resolveProngComptime(
11128 &child_block,11173 &child_block,
...@@ -11131,6 +11176,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11131,6 +11176,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11131 info.capture,11176 info.capture,
11132 .{ .scalar = @intCast(u32, scalar_i) },11177 .{ .scalar = @intCast(u32, scalar_i) },
11133 &.{item},11178 &.{item},
11179 if (info.is_inline) operand else .none,
11180 info.has_tag_capture,
11134 merges,11181 merges,
11135 );11182 );
11136 }11183 }
...@@ -11155,7 +11202,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11155,7 +11202,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11155 // Validation above ensured these will succeed.11202 // Validation above ensured these will succeed.
11156 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;11203 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
11157 if (operand_val.eql(item_val, operand_ty, sema.mod)) {11204 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11158 if (info.is_inline) child_block.inline_case_capture = operand;
11159 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11205 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11160 return spa.resolveProngComptime(11206 return spa.resolveProngComptime(
11161 &child_block,11207 &child_block,
...@@ -11164,6 +11210,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11164,6 +11210,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11164 info.capture,11210 info.capture,
11165 .{ .multi_capture = @intCast(u32, multi_i) },11211 .{ .multi_capture = @intCast(u32, multi_i) },
11166 items,11212 items,
11213 if (info.is_inline) operand else .none,
11214 info.has_tag_capture,
11167 merges,11215 merges,
11168 );11216 );
11169 }11217 }
...@@ -11181,7 +11229,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11181,7 +11229,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11181 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and11229 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
11182 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))11230 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
11183 {11231 {
11184 if (info.is_inline) child_block.inline_case_capture = operand;
11185 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11232 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11186 return spa.resolveProngComptime(11233 return spa.resolveProngComptime(
11187 &child_block,11234 &child_block,
...@@ -11190,6 +11237,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11190,6 +11237,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11190 info.capture,11237 info.capture,
11191 .{ .multi_capture = @intCast(u32, multi_i) },11238 .{ .multi_capture = @intCast(u32, multi_i) },
11192 undefined, // case_vals may be undefined for ranges11239 undefined, // case_vals may be undefined for ranges
11240 if (info.is_inline) operand else .none,
11241 info.has_tag_capture,
11193 merges,11242 merges,
11194 );11243 );
11195 }11244 }
...@@ -11199,7 +11248,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11199,7 +11248,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11199 }11248 }
11200 }11249 }
11201 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);11250 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
11202 if (special.is_inline) child_block.inline_case_capture = operand;
11203 if (empty_enum) {11251 if (empty_enum) {
11204 return Air.Inst.Ref.void_value;11252 return Air.Inst.Ref.void_value;
11205 }11253 }
...@@ -11211,6 +11259,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11211,6 +11259,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11211 special.capture,11259 special.capture,
11212 .special,11260 .special,
11213 undefined, // case_vals may be undefined for special prongs11261 undefined, // case_vals may be undefined for special prongs
11262 if (special.is_inline) operand else .none,
11263 special.has_tag_capture,
11214 merges,11264 merges,
11215 );11265 );
11216 }11266 }
...@@ -11240,6 +11290,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11240,6 +11290,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11240 special.capture,11290 special.capture,
11241 .special,11291 .special,
11242 undefined, // case_vals may be undefined for special prongs11292 undefined, // case_vals may be undefined for special prongs
11293 .none,
11294 false,
11243 merges,11295 merges,
11244 );11296 );
11245 }11297 }
...@@ -11278,10 +11330,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11278,10 +11330,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1127811330
11279 case_block.instructions.shrinkRetainingCapacity(0);11331 case_block.instructions.shrinkRetainingCapacity(0);
11280 case_block.wip_capture_scope = wip_captures.scope;11332 case_block.wip_capture_scope = wip_captures.scope;
11281 case_block.inline_case_capture = .none;
1128211333
11283 const item = case_vals.items[scalar_i];11334 const item = case_vals.items[scalar_i];
11284 if (info.is_inline) case_block.inline_case_capture = item;
11285 // `item` is already guaranteed to be constant known.11335 // `item` is already guaranteed to be constant known.
1128611336
11287 const analyze_body = if (union_originally) blk: {11337 const analyze_body = if (union_originally) blk: {
...@@ -11300,6 +11350,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11300,6 +11350,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11300 info.capture,11350 info.capture,
11301 .{ .scalar = @intCast(u32, scalar_i) },11351 .{ .scalar = @intCast(u32, scalar_i) },
11302 &.{item},11352 &.{item},
11353 if (info.is_inline) item else .none,
11354 info.has_tag_capture,
11303 );11355 );
11304 } else {11356 } else {
11305 _ = try case_block.addNoOp(.unreach);11357 _ = try case_block.addNoOp(.unreach);
...@@ -11337,7 +11389,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11337,7 +11389,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1133711389
11338 case_block.instructions.shrinkRetainingCapacity(0);11390 case_block.instructions.shrinkRetainingCapacity(0);
11339 case_block.wip_capture_scope = child_block.wip_capture_scope;11391 case_block.wip_capture_scope = child_block.wip_capture_scope;
11340 case_block.inline_case_capture = .none;
1134111392
11342 // Generate all possible cases as scalar prongs.11393 // Generate all possible cases as scalar prongs.
11343 if (info.is_inline) {11394 if (info.is_inline) {
...@@ -11367,7 +11418,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11367,7 +11418,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11367 cases_len += 1;11418 cases_len += 1;
1136811419
11369 const item_ref = try sema.addConstant(operand_ty, item);11420 const item_ref = try sema.addConstant(operand_ty, item);
11370 case_block.inline_case_capture = item_ref;
1137111421
11372 case_block.instructions.shrinkRetainingCapacity(0);11422 case_block.instructions.shrinkRetainingCapacity(0);
11373 case_block.wip_capture_scope = child_block.wip_capture_scope;11423 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11390,12 +11440,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11390,12 +11440,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11390 info.capture,11440 info.capture,
11391 .{ .multi_capture = multi_i },11441 .{ .multi_capture = multi_i },
11392 undefined, // case_vals may be undefined for ranges11442 undefined, // case_vals may be undefined for ranges
11443 item_ref,
11444 info.has_tag_capture,
11393 );11445 );
1139411446
11395 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11447 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11396 cases_extra.appendAssumeCapacity(1); // items_len11448 cases_extra.appendAssumeCapacity(1); // items_len
11397 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11449 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11398 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11450 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11399 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11451 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11400 }11452 }
11401 }11453 }
...@@ -11403,8 +11455,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11403,8 +11455,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11403 for (items, 0..) |item, item_i| {11455 for (items, 0..) |item, item_i| {
11404 cases_len += 1;11456 cases_len += 1;
1140511457
11406 case_block.inline_case_capture = item;
11407
11408 case_block.instructions.shrinkRetainingCapacity(0);11458 case_block.instructions.shrinkRetainingCapacity(0);
11409 case_block.wip_capture_scope = child_block.wip_capture_scope;11459 case_block.wip_capture_scope = child_block.wip_capture_scope;
1141011460
...@@ -11433,6 +11483,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11433,6 +11483,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11433 info.capture,11483 info.capture,
11434 .{ .multi_capture = multi_i },11484 .{ .multi_capture = multi_i },
11435 &.{item},11485 &.{item},
11486 item,
11487 info.has_tag_capture,
11436 );11488 );
11437 } else {11489 } else {
11438 _ = try case_block.addNoOp(.unreach);11490 _ = try case_block.addNoOp(.unreach);
...@@ -11441,7 +11493,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11441,7 +11493,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11441 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11493 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11442 cases_extra.appendAssumeCapacity(1); // items_len11494 cases_extra.appendAssumeCapacity(1); // items_len
11443 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11495 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11444 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11496 cases_extra.appendAssumeCapacity(@enumToInt(item));
11445 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11497 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11446 }11498 }
1144711499
...@@ -11478,6 +11530,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11478,6 +11530,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11478 info.capture,11530 info.capture,
11479 .{ .multi_capture = multi_i },11531 .{ .multi_capture = multi_i },
11480 items,11532 items,
11533 .none,
11534 false,
11481 );11535 );
11482 } else {11536 } else {
11483 _ = try case_block.addNoOp(.unreach);11537 _ = try case_block.addNoOp(.unreach);
...@@ -11563,6 +11617,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11563,6 +11617,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11563 info.capture,11617 info.capture,
11564 .{ .multi_capture = multi_i },11618 .{ .multi_capture = multi_i },
11565 items,11619 items,
11620 .none,
11621 false,
11566 );11622 );
11567 }11623 }
1156811624
...@@ -11608,7 +11664,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11608,7 +11664,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1160811664
11609 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));11665 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
11610 const item_ref = try sema.addConstant(operand_ty, item_val);11666 const item_ref = try sema.addConstant(operand_ty, item_val);
11611 case_block.inline_case_capture = item_ref;
1161211667
11613 case_block.instructions.shrinkRetainingCapacity(0);11668 case_block.instructions.shrinkRetainingCapacity(0);
11614 case_block.wip_capture_scope = child_block.wip_capture_scope;11669 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11629,6 +11684,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11629,6 +11684,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11629 special.capture,11684 special.capture,
11630 .special,11685 .special,
11631 &.{item_ref},11686 &.{item_ref},
11687 item_ref,
11688 special.has_tag_capture,
11632 );11689 );
11633 } else {11690 } else {
11634 _ = try case_block.addNoOp(.unreach);11691 _ = try case_block.addNoOp(.unreach);
...@@ -11637,7 +11694,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11637,7 +11694,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11637 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11694 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11638 cases_extra.appendAssumeCapacity(1); // items_len11695 cases_extra.appendAssumeCapacity(1); // items_len
11639 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11696 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11640 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11697 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11641 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11698 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11642 }11699 }
11643 },11700 },
...@@ -11657,7 +11714,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11657,7 +11714,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11657 .name = error_name,11714 .name = error_name,
11658 } });11715 } });
11659 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());11716 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
11660 case_block.inline_case_capture = item_ref;
1166111717
11662 case_block.instructions.shrinkRetainingCapacity(0);11718 case_block.instructions.shrinkRetainingCapacity(0);
11663 case_block.wip_capture_scope = child_block.wip_capture_scope;11719 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11672,12 +11728,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11672,12 +11728,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11672 special.capture,11728 special.capture,
11673 .special,11729 .special,
11674 &.{item_ref},11730 &.{item_ref},
11731 item_ref,
11732 special.has_tag_capture,
11675 );11733 );
1167611734
11677 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11735 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11678 cases_extra.appendAssumeCapacity(1); // items_len11736 cases_extra.appendAssumeCapacity(1); // items_len
11679 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11737 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11680 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11738 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11681 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11739 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11682 }11740 }
11683 },11741 },
...@@ -11687,7 +11745,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11687,7 +11745,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11687 cases_len += 1;11745 cases_len += 1;
1168811746
11689 const item_ref = try sema.addConstant(operand_ty, cur.toValue());11747 const item_ref = try sema.addConstant(operand_ty, cur.toValue());
11690 case_block.inline_case_capture = item_ref;
1169111748
11692 case_block.instructions.shrinkRetainingCapacity(0);11749 case_block.instructions.shrinkRetainingCapacity(0);
11693 case_block.wip_capture_scope = child_block.wip_capture_scope;11750 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11702,19 +11759,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11702,19 +11759,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11702 special.capture,11759 special.capture,
11703 .special,11760 .special,
11704 &.{item_ref},11761 &.{item_ref},
11762 item_ref,
11763 special.has_tag_capture,
11705 );11764 );
1170611765
11707 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11766 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11708 cases_extra.appendAssumeCapacity(1); // items_len11767 cases_extra.appendAssumeCapacity(1); // items_len
11709 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11768 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11710 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11769 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11711 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11770 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11712 }11771 }
11713 },11772 },
11714 .Bool => {11773 .Bool => {
11715 if (true_count == 0) {11774 if (true_count == 0) {
11716 cases_len += 1;11775 cases_len += 1;
11717 case_block.inline_case_capture = Air.Inst.Ref.bool_true;
1171811776
11719 case_block.instructions.shrinkRetainingCapacity(0);11777 case_block.instructions.shrinkRetainingCapacity(0);
11720 case_block.wip_capture_scope = child_block.wip_capture_scope;11778 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11729,17 +11787,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11729,17 +11787,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11729 special.capture,11787 special.capture,
11730 .special,11788 .special,
11731 &.{Air.Inst.Ref.bool_true},11789 &.{Air.Inst.Ref.bool_true},
11790 Air.Inst.Ref.bool_true,
11791 special.has_tag_capture,
11732 );11792 );
1173311793
11734 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11794 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11735 cases_extra.appendAssumeCapacity(1); // items_len11795 cases_extra.appendAssumeCapacity(1); // items_len
11736 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11796 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11737 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11797 cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_true));
11738 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11798 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11739 }11799 }
11740 if (false_count == 0) {11800 if (false_count == 0) {
11741 cases_len += 1;11801 cases_len += 1;
11742 case_block.inline_case_capture = Air.Inst.Ref.bool_false;
1174311802
11744 case_block.instructions.shrinkRetainingCapacity(0);11803 case_block.instructions.shrinkRetainingCapacity(0);
11745 case_block.wip_capture_scope = child_block.wip_capture_scope;11804 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11754,12 +11813,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11754,12 +11813,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11754 special.capture,11813 special.capture,
11755 .special,11814 .special,
11756 &.{Air.Inst.Ref.bool_false},11815 &.{Air.Inst.Ref.bool_false},
11816 Air.Inst.Ref.bool_false,
11817 special.has_tag_capture,
11757 );11818 );
1175811819
11759 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11820 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11760 cases_extra.appendAssumeCapacity(1); // items_len11821 cases_extra.appendAssumeCapacity(1); // items_len
11761 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11822 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11762 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11823 cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_false));
11763 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11824 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11764 }11825 }
11765 },11826 },
...@@ -11773,7 +11834,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11773,7 +11834,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1177311834
11774 case_block.instructions.shrinkRetainingCapacity(0);11835 case_block.instructions.shrinkRetainingCapacity(0);
11775 case_block.wip_capture_scope = wip_captures.scope;11836 case_block.wip_capture_scope = wip_captures.scope;
11776 case_block.inline_case_capture = .none;
1177711837
11778 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and11838 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
11779 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))11839 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
...@@ -11804,6 +11864,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11804,6 +11864,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11804 special.capture,11864 special.capture,
11805 .special,11865 .special,
11806 undefined, // case_vals may be undefined for special prongs11866 undefined, // case_vals may be undefined for special prongs
11867 .none,
11868 false,
11807 );11869 );
11808 } else {11870 } else {
11809 // We still need a terminator in this block, but we have proven11871 // We still need a terminator in this block, but we have proven
src/Zir.zig+13-14
...@@ -676,9 +676,6 @@ pub const Inst = struct {...@@ -676,9 +676,6 @@ pub const Inst = struct {
676 /// what will be switched on.676 /// what will be switched on.
677 /// Uses the `un_node` union field.677 /// Uses the `un_node` union field.
678 switch_cond_ref,678 switch_cond_ref,
679 /// Produces the capture value for an inline switch prong tag capture.
680 /// Uses the `un_tok` field.
681 switch_capture_tag,
682 /// Given a679 /// Given a
683 /// *A returns *A680 /// *A returns *A
684 /// *E!A returns *A681 /// *E!A returns *A
...@@ -1124,7 +1121,6 @@ pub const Inst = struct {...@@ -1124,7 +1121,6 @@ pub const Inst = struct {
1124 .typeof_log2_int_type,1121 .typeof_log2_int_type,
1125 .resolve_inferred_alloc,1122 .resolve_inferred_alloc,
1126 .set_eval_branch_quota,1123 .set_eval_branch_quota,
1127 .switch_capture_tag,
1128 .switch_block,1124 .switch_block,
1129 .switch_cond,1125 .switch_cond,
1130 .switch_cond_ref,1126 .switch_cond_ref,
...@@ -1414,7 +1410,6 @@ pub const Inst = struct {...@@ -1414,7 +1410,6 @@ pub const Inst = struct {
1414 .slice_length,1410 .slice_length,
1415 .import,1411 .import,
1416 .typeof_log2_int_type,1412 .typeof_log2_int_type,
1417 .switch_capture_tag,
1418 .switch_block,1413 .switch_block,
1419 .switch_cond,1414 .switch_cond,
1420 .switch_cond_ref,1415 .switch_cond_ref,
...@@ -1670,7 +1665,6 @@ pub const Inst = struct {...@@ -1670,7 +1665,6 @@ pub const Inst = struct {
1670 .switch_block = .pl_node,1665 .switch_block = .pl_node,
1671 .switch_cond = .un_node,1666 .switch_cond = .un_node,
1672 .switch_cond_ref = .un_node,1667 .switch_cond_ref = .un_node,
1673 .switch_capture_tag = .un_tok,
1674 .array_base_ptr = .un_node,1668 .array_base_ptr = .un_node,
1675 .field_base_ptr = .un_node,1669 .field_base_ptr = .un_node,
1676 .validate_array_init_ty = .pl_node,1670 .validate_array_init_ty = .pl_node,
...@@ -1996,9 +1990,10 @@ pub const Inst = struct {...@@ -1996,9 +1990,10 @@ pub const Inst = struct {
1996 /// Implements the `@inComptime` builtin.1990 /// Implements the `@inComptime` builtin.
1997 /// `operand` is `src_node: i32`.1991 /// `operand` is `src_node: i32`.
1998 in_comptime,1992 in_comptime,
1999 /// Used as a placeholder for the capture of an `errdefer`.1993 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
2000 /// This is replaced by Sema with the captured value.1994 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
2001 errdefer_err_code,1995 /// This should never appear in a body.
1996 value_placeholder,
20021997
2003 pub const InstData = struct {1998 pub const InstData = struct {
2004 opcode: Extended,1999 opcode: Extended,
...@@ -2644,16 +2639,17 @@ pub const Inst = struct {...@@ -2644,16 +2639,17 @@ pub const Inst = struct {
2644 };2639 };
26452640
2646 /// 0. multi_cases_len: u32 // If has_multi_cases is set.2641 /// 0. multi_cases_len: u32 // If has_multi_cases is set.
2647 /// 1. else_body { // If has_else or has_under is set.2642 /// 1. tag_capture_inst: u32 // If any_has_tag_capture is set. Index of instruction prongs use to refer to the inline tag capture.
2643 /// 2. else_body { // If has_else or has_under is set.
2648 /// info: ProngInfo,2644 /// info: ProngInfo,
2649 /// body member Index for every info.body_len2645 /// body member Index for every info.body_len
2650 /// }2646 /// }
2651 /// 2. scalar_cases: { // for every scalar_cases_len2647 /// 3. scalar_cases: { // for every scalar_cases_len
2652 /// item: Ref,2648 /// item: Ref,
2653 /// info: ProngInfo,2649 /// info: ProngInfo,
2654 /// body member Index for every info.body_len2650 /// body member Index for every info.body_len
2655 /// }2651 /// }
2656 /// 3. multi_cases: { // for every multi_cases_len2652 /// 4. multi_cases: { // for every multi_cases_len
2657 /// items_len: u32,2653 /// items_len: u32,
2658 /// ranges_len: u32,2654 /// ranges_len: u32,
2659 /// info: ProngInfo,2655 /// info: ProngInfo,
...@@ -2681,9 +2677,10 @@ pub const Inst = struct {...@@ -2681,9 +2677,10 @@ pub const Inst = struct {
26812677
2682 /// These are stored in trailing data in `extra` for each prong.2678 /// These are stored in trailing data in `extra` for each prong.
2683 pub const ProngInfo = packed struct(u32) {2679 pub const ProngInfo = packed struct(u32) {
2684 body_len: u29,2680 body_len: u28,
2685 capture: Capture,2681 capture: Capture,
2686 is_inline: bool,2682 is_inline: bool,
2683 has_tag_capture: bool,
26872684
2688 pub const Capture = enum(u2) {2685 pub const Capture = enum(u2) {
2689 none,2686 none,
...@@ -2699,9 +2696,11 @@ pub const Inst = struct {...@@ -2699,9 +2696,11 @@ pub const Inst = struct {
2699 has_else: bool,2696 has_else: bool,
2700 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.2697 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.
2701 has_under: bool,2698 has_under: bool,
2699 /// If true, at least one prong has an inline tag capture.
2700 any_has_tag_capture: bool,
2702 scalar_cases_len: ScalarCasesLen,2701 scalar_cases_len: ScalarCasesLen,
27032702
2704 pub const ScalarCasesLen = u29;2703 pub const ScalarCasesLen = u28;
27052704
2706 pub fn specialProng(bits: Bits) SpecialProng {2705 pub fn specialProng(bits: Bits) SpecialProng {
2707 const has_else: u2 = @boolToInt(bits.has_else);2706 const has_else: u2 = @boolToInt(bits.has_else);
src/print_zir.zig+12-2
...@@ -235,7 +235,6 @@ const Writer = struct {...@@ -235,7 +235,6 @@ const Writer = struct {
235 .ref,235 .ref,
236 .ret_implicit,236 .ret_implicit,
237 .closure_capture,237 .closure_capture,
238 .switch_capture_tag,
239 => try self.writeUnTok(stream, inst),238 => try self.writeUnTok(stream, inst),
240239
241 .bool_br_and,240 .bool_br_and,
...@@ -463,7 +462,7 @@ const Writer = struct {...@@ -463,7 +462,7 @@ const Writer = struct {
463 .breakpoint,462 .breakpoint,
464 .c_va_start,463 .c_va_start,
465 .in_comptime,464 .in_comptime,
466 .errdefer_err_code,465 .value_placeholder,
467 => try self.writeExtNode(stream, extended),466 => try self.writeExtNode(stream, extended),
468467
469 .builtin_src => {468 .builtin_src => {
...@@ -1897,8 +1896,19 @@ const Writer = struct {...@@ -1897,8 +1896,19 @@ const Writer = struct {
1897 break :blk multi_cases_len;1896 break :blk multi_cases_len;
1898 } else 0;1897 } else 0;
18991898
1899 const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
1900 const tag_capture_inst = self.code.extra[extra_index];
1901 extra_index += 1;
1902 break :blk tag_capture_inst;
1903 } else undefined;
1904
1900 try self.writeInstRef(stream, extra.data.operand);1905 try self.writeInstRef(stream, extra.data.operand);
19011906
1907 if (extra.data.bits.any_has_tag_capture) {
1908 try stream.writeAll(", tag_capture=");
1909 try self.writeInstIndex(stream, tag_capture_inst);
1910 }
1911
1902 self.indent += 2;1912 self.indent += 2;
19031913
1904 else_prong: {1914 else_prong: {