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
26122612 .switch_block,
26132613 .switch_cond,
26142614 .switch_cond_ref,
2615 .switch_capture_tag,
26162615 .struct_init_empty,
26172616 .struct_init,
26182617 .struct_init_ref,
......@@ -2956,7 +2955,7 @@ fn deferStmt(
29562955 try gz.astgen.instructions.append(gz.astgen.gpa, .{
29572956 .tag = .extended,
29582957 .data = .{ .extended = .{
2959 .opcode = .errdefer_err_code,
2958 .opcode = .value_placeholder,
29602959 .small = undefined,
29612960 .operand = undefined,
29622961 } },
......@@ -6711,6 +6710,7 @@ fn switchExpr(
67116710 // for the following variables, make note of the special prong AST node index,
67126711 // and bail out with a compile error if there are multiple special prongs present.
67136712 var any_payload_is_ref = false;
6713 var any_has_tag_capture = false;
67146714 var scalar_cases_len: u32 = 0;
67156715 var multi_cases_len: u32 = 0;
67166716 var inline_cases_len: u32 = 0;
......@@ -6721,8 +6721,12 @@ fn switchExpr(
67216721 for (case_nodes) |case_node| {
67226722 const case = tree.fullSwitchCase(case_node).?;
67236723 if (case.payload_token) |payload_token| {
6724 if (token_tags[payload_token] == .asterisk) {
6724 const ident = if (token_tags[payload_token] == .asterisk) blk: {
67256725 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;
67266730 }
67276731 }
67286732 // Check for else/`_` prong.
......@@ -6861,6 +6865,20 @@ fn switchExpr(
68616865 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
68626866 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
68646882 // In this pass we generate all the item and prong expressions.
68656883 var multi_case_index: u32 = 0;
68666884 var scalar_case_index: u32 = 0;
......@@ -6874,7 +6892,7 @@ fn switchExpr(
68746892 var dbg_var_inst: Zir.Inst.Ref = undefined;
68756893 var dbg_var_tag_name: ?u32 = null;
68766894 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;
6877 var tag_inst: Zir.Inst.Index = 0;
6895 var has_tag_capture = false;
68786896 var capture_val_scope: Scope.LocalVal = undefined;
68796897 var tag_scope: Scope.LocalVal = undefined;
68806898
......@@ -6925,14 +6943,9 @@ fn switchExpr(
69256943 }
69266944 const tag_name = try astgen.identAsString(tag_token);
69276945 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);
6929 try astgen.instructions.append(gpa, .{
6930 .tag = .switch_capture_tag,
6931 .data = .{ .un_tok = .{
6932 .operand = cond,
6933 .src_tok = case_scope.tokenIndexToRelative(tag_token),
6934 } },
6935 });
6946
6947 assert(any_has_tag_capture);
6948 has_tag_capture = true;
69366949
69376950 tag_scope = .{
69386951 .parent = payload_sub_scope,
......@@ -6998,7 +7011,6 @@ fn switchExpr(
69987011 case_scope.instructions_top = parent_gz.instructions.items.len;
69997012 defer case_scope.unstack();
70007013
7001 if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst);
70027014 try case_scope.addDbgBlockBegin();
70037015 if (dbg_var_name) |some| {
70047016 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
......@@ -7018,7 +7030,8 @@ fn switchExpr(
70187030 const case_slice = case_scope.instructionsSlice();
70197031 // Since we use the switch_block instruction itself to refer to the
70207032 // 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.
70227035 const refs_len = refs: {
70237036 var n: usize = 0;
70247037 var check_inst = switch_block;
......@@ -7026,18 +7039,31 @@ fn switchExpr(
70267039 n += 1;
70277040 check_inst = ref_inst;
70287041 }
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 }
70297049 break :refs n;
70307050 };
70317051 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
70327052 try payloads.ensureUnusedCapacity(gpa, body_len);
70337053 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),
70357055 .capture = capture,
70367056 .is_inline = case.inline_token != null,
7057 .has_tag_capture = has_tag_capture,
70377058 });
70387059 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
70397060 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
70407061 }
7062 if (has_tag_capture) {
7063 if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
7064 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7065 }
7066 }
70417067 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
70427068 }
70437069 }
......@@ -7046,6 +7072,7 @@ fn switchExpr(
70467072
70477073 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
70487074 @boolToInt(multi_cases_len != 0) +
7075 @boolToInt(any_has_tag_capture) +
70497076 payloads.items.len - case_table_end);
70507077
70517078 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
......@@ -7054,6 +7081,7 @@ fn switchExpr(
70547081 .has_multi_cases = multi_cases_len != 0,
70557082 .has_else = special_prong == .@"else",
70567083 .has_under = special_prong == .under,
7084 .any_has_tag_capture = any_has_tag_capture,
70577085 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),
70587086 },
70597087 });
......@@ -7062,6 +7090,10 @@ fn switchExpr(
70627090 astgen.extra.appendAssumeCapacity(multi_cases_len);
70637091 }
70647092
7093 if (any_has_tag_capture) {
7094 astgen.extra.appendAssumeCapacity(tag_inst);
7095 }
7096
70657097 const zir_datas = astgen.instructions.items(.data);
70667098 const zir_tags = astgen.instructions.items(.tag);
70677099
src/Sema.zig+122-60
......@@ -277,9 +277,6 @@ pub const Block = struct {
277277
278278 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
283280 const ComptimeReason = union(enum) {
284281 c_import: struct {
285282 block: *Block,
......@@ -1013,7 +1010,6 @@ fn analyzeBodyInner(
10131010 .switch_block => try sema.zirSwitchBlock(block, inst),
10141011 .switch_cond => try sema.zirSwitchCond(block, inst, false),
10151012 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
1016 .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst),
10171013 .type_info => try sema.zirTypeInfo(block, inst),
10181014 .size_of => try sema.zirSizeOf(block, inst),
10191015 .bit_size_of => try sema.zirBitSizeOf(block, inst),
......@@ -1217,7 +1213,7 @@ fn analyzeBodyInner(
12171213 i += 1;
12181214 continue;
12191215 },
1220 .errdefer_err_code => unreachable, // never appears in a body
1216 .value_placeholder => unreachable, // never appears in a body
12211217 };
12221218 },
12231219
......@@ -10092,6 +10088,9 @@ const SwitchProngAnalysis = struct {
1009210088 else_error_ty: ?Type,
1009310089 /// The index of the `switch_block` instruction itself.
1009410090 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
1009610095 /// Resolve a switch prong which is determined at comptime to have no peers.
1009710096 /// Uses `resolveBlockBody`. Sets up captures as needed.
......@@ -10106,10 +10105,23 @@ const SwitchProngAnalysis = struct {
1010610105 /// The set of all values which can reach this prong. May be undefined
1010710106 /// if the prong is special or contains ranges.
1010810107 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,
1010910114 merges: *Block.Merges,
1011010115 ) CompileError!Air.Inst.Ref {
1011110116 const sema = spa.sema;
1011210117 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
1011310125 switch (capture) {
1011410126 .none => {
1011510127 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
......@@ -10122,6 +10134,7 @@ const SwitchProngAnalysis = struct {
1012210134 prong_type == .special,
1012310135 raw_capture_src,
1012410136 case_vals,
10137 inline_case_capture,
1012510138 );
1012610139
1012710140 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
......@@ -10150,8 +10163,21 @@ const SwitchProngAnalysis = struct {
1015010163 /// The set of all values which can reach this prong. May be undefined
1015110164 /// if the prong is special or contains ranges.
1015210165 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,
1015310172 ) CompileError!void {
1015410173 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
1015510181 switch (capture) {
1015610182 .none => {
1015710183 return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
......@@ -10164,6 +10190,7 @@ const SwitchProngAnalysis = struct {
1016410190 prong_type == .special,
1016510191 raw_capture_src,
1016610192 case_vals,
10193 inline_case_capture,
1016710194 );
1016810195
1016910196 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
......@@ -10179,6 +10206,33 @@ const SwitchProngAnalysis = struct {
1017910206 }
1018010207 }
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
1018210236 fn analyzeCapture(
1018310237 spa: SwitchProngAnalysis,
1018410238 block: *Block,
......@@ -10186,6 +10240,7 @@ const SwitchProngAnalysis = struct {
1018610240 is_special_prong: bool,
1018710241 raw_capture_src: Module.SwitchProngSrc,
1018810242 case_vals: []const Air.Inst.Ref,
10243 inline_case_capture: Air.Inst.Ref,
1018910244 ) CompileError!Air.Inst.Ref {
1019010245 const sema = spa.sema;
1019110246 const mod = sema.mod;
......@@ -10197,8 +10252,8 @@ const SwitchProngAnalysis = struct {
1019710252 const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;
1019810253 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
1019910254
10200 if (block.inline_case_capture != .none) {
10201 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, "") catch unreachable;
10255 if (inline_case_capture != .none) {
10256 const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;
1020210257 if (operand_ty.zigTypeTag(mod) == .Union) {
1020310258 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
1020410259 const union_obj = mod.typeToUnion(operand_ty).?;
......@@ -10233,7 +10288,7 @@ const SwitchProngAnalysis = struct {
1023310288 } else if (capture_byref) {
1023410289 return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
1023510290 } else {
10236 return block.inline_case_capture;
10291 return inline_case_capture;
1023710292 }
1023810293 }
1023910294
......@@ -10356,34 +10411,6 @@ const SwitchProngAnalysis = struct {
1035610411 }
1035710412};
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
1038710414fn zirSwitchCond(
1038810415 sema: *Sema,
1038910416 block: *Block,
......@@ -10485,6 +10512,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1048510512 break :blk multi_cases_len;
1048610513 } 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
1048810525 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
1048910526 defer case_vals.deinit(gpa);
1049010527
......@@ -10493,11 +10530,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1049310530 end: usize,
1049410531 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
1049510532 is_inline: bool,
10533 has_tag_capture: bool,
1049610534 };
1049710535
1049810536 const special_prong = extra.data.bits.specialProng();
1049910537 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 },
1050110545 .under, .@"else" => blk: {
1050210546 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]);
1050310547 const extra_body_start = header_extra_index + 1;
......@@ -10506,6 +10550,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1050610550 .end = extra_body_start + info.body_len,
1050710551 .capture = info.capture,
1050810552 .is_inline = info.is_inline,
10553 .has_tag_capture = info.has_tag_capture,
1050910554 };
1051010555 },
1051110556 };
......@@ -11068,6 +11113,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1106811113 .operand_ptr = raw_operand.ptr,
1106911114 .else_error_ty = else_error_ty,
1107011115 .switch_block_inst = inst,
11116 .tag_capture_inst = tag_capture_inst,
1107111117 };
1107211118
1107311119 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
1112211168 const item = case_vals.items[scalar_i];
1112311169 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
1112411170 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11125 if (info.is_inline) child_block.inline_case_capture = operand;
1112611171 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
1112711172 return spa.resolveProngComptime(
1112811173 &child_block,
......@@ -11131,6 +11176,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1113111176 info.capture,
1113211177 .{ .scalar = @intCast(u32, scalar_i) },
1113311178 &.{item},
11179 if (info.is_inline) operand else .none,
11180 info.has_tag_capture,
1113411181 merges,
1113511182 );
1113611183 }
......@@ -11155,7 +11202,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1115511202 // Validation above ensured these will succeed.
1115611203 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
1115711204 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11158 if (info.is_inline) child_block.inline_case_capture = operand;
1115911205 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
1116011206 return spa.resolveProngComptime(
1116111207 &child_block,
......@@ -11164,6 +11210,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1116411210 info.capture,
1116511211 .{ .multi_capture = @intCast(u32, multi_i) },
1116611212 items,
11213 if (info.is_inline) operand else .none,
11214 info.has_tag_capture,
1116711215 merges,
1116811216 );
1116911217 }
......@@ -11181,7 +11229,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1118111229 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
1118211230 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
1118311231 {
11184 if (info.is_inline) child_block.inline_case_capture = operand;
1118511232 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
1118611233 return spa.resolveProngComptime(
1118711234 &child_block,
......@@ -11190,6 +11237,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1119011237 info.capture,
1119111238 .{ .multi_capture = @intCast(u32, multi_i) },
1119211239 undefined, // case_vals may be undefined for ranges
11240 if (info.is_inline) operand else .none,
11241 info.has_tag_capture,
1119311242 merges,
1119411243 );
1119511244 }
......@@ -11199,7 +11248,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1119911248 }
1120011249 }
1120111250 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
11202 if (special.is_inline) child_block.inline_case_capture = operand;
1120311251 if (empty_enum) {
1120411252 return Air.Inst.Ref.void_value;
1120511253 }
......@@ -11211,6 +11259,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1121111259 special.capture,
1121211260 .special,
1121311261 undefined, // case_vals may be undefined for special prongs
11262 if (special.is_inline) operand else .none,
11263 special.has_tag_capture,
1121411264 merges,
1121511265 );
1121611266 }
......@@ -11240,6 +11290,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1124011290 special.capture,
1124111291 .special,
1124211292 undefined, // case_vals may be undefined for special prongs
11293 .none,
11294 false,
1124311295 merges,
1124411296 );
1124511297 }
......@@ -11278,10 +11330,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1127811330
1127911331 case_block.instructions.shrinkRetainingCapacity(0);
1128011332 case_block.wip_capture_scope = wip_captures.scope;
11281 case_block.inline_case_capture = .none;
1128211333
1128311334 const item = case_vals.items[scalar_i];
11284 if (info.is_inline) case_block.inline_case_capture = item;
1128511335 // `item` is already guaranteed to be constant known.
1128611336
1128711337 const analyze_body = if (union_originally) blk: {
......@@ -11300,6 +11350,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1130011350 info.capture,
1130111351 .{ .scalar = @intCast(u32, scalar_i) },
1130211352 &.{item},
11353 if (info.is_inline) item else .none,
11354 info.has_tag_capture,
1130311355 );
1130411356 } else {
1130511357 _ = try case_block.addNoOp(.unreach);
......@@ -11337,7 +11389,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1133711389
1133811390 case_block.instructions.shrinkRetainingCapacity(0);
1133911391 case_block.wip_capture_scope = child_block.wip_capture_scope;
11340 case_block.inline_case_capture = .none;
1134111392
1134211393 // Generate all possible cases as scalar prongs.
1134311394 if (info.is_inline) {
......@@ -11367,7 +11418,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1136711418 cases_len += 1;
1136811419
1136911420 const item_ref = try sema.addConstant(operand_ty, item);
11370 case_block.inline_case_capture = item_ref;
1137111421
1137211422 case_block.instructions.shrinkRetainingCapacity(0);
1137311423 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
1139011440 info.capture,
1139111441 .{ .multi_capture = multi_i },
1139211442 undefined, // case_vals may be undefined for ranges
11443 item_ref,
11444 info.has_tag_capture,
1139311445 );
1139411446
1139511447 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1139611448 cases_extra.appendAssumeCapacity(1); // items_len
1139711449 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));
1139911451 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1140011452 }
1140111453 }
......@@ -11403,8 +11455,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1140311455 for (items, 0..) |item, item_i| {
1140411456 cases_len += 1;
1140511457
11406 case_block.inline_case_capture = item;
11407
1140811458 case_block.instructions.shrinkRetainingCapacity(0);
1140911459 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
1143311483 info.capture,
1143411484 .{ .multi_capture = multi_i },
1143511485 &.{item},
11486 item,
11487 info.has_tag_capture,
1143611488 );
1143711489 } else {
1143811490 _ = try case_block.addNoOp(.unreach);
......@@ -11441,7 +11493,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1144111493 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1144211494 cases_extra.appendAssumeCapacity(1); // items_len
1144311495 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));
1144511497 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1144611498 }
1144711499
......@@ -11478,6 +11530,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1147811530 info.capture,
1147911531 .{ .multi_capture = multi_i },
1148011532 items,
11533 .none,
11534 false,
1148111535 );
1148211536 } else {
1148311537 _ = try case_block.addNoOp(.unreach);
......@@ -11563,6 +11617,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1156311617 info.capture,
1156411618 .{ .multi_capture = multi_i },
1156511619 items,
11620 .none,
11621 false,
1156611622 );
1156711623 }
1156811624
......@@ -11608,7 +11664,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1160811664
1160911665 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
1161011666 const item_ref = try sema.addConstant(operand_ty, item_val);
11611 case_block.inline_case_capture = item_ref;
1161211667
1161311668 case_block.instructions.shrinkRetainingCapacity(0);
1161411669 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
1162911684 special.capture,
1163011685 .special,
1163111686 &.{item_ref},
11687 item_ref,
11688 special.has_tag_capture,
1163211689 );
1163311690 } else {
1163411691 _ = try case_block.addNoOp(.unreach);
......@@ -11637,7 +11694,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1163711694 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1163811695 cases_extra.appendAssumeCapacity(1); // items_len
1163911696 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));
1164111698 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1164211699 }
1164311700 },
......@@ -11657,7 +11714,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1165711714 .name = error_name,
1165811715 } });
1165911716 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
11660 case_block.inline_case_capture = item_ref;
1166111717
1166211718 case_block.instructions.shrinkRetainingCapacity(0);
1166311719 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
1167211728 special.capture,
1167311729 .special,
1167411730 &.{item_ref},
11731 item_ref,
11732 special.has_tag_capture,
1167511733 );
1167611734
1167711735 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1167811736 cases_extra.appendAssumeCapacity(1); // items_len
1167911737 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));
1168111739 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1168211740 }
1168311741 },
......@@ -11687,7 +11745,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1168711745 cases_len += 1;
1168811746
1168911747 const item_ref = try sema.addConstant(operand_ty, cur.toValue());
11690 case_block.inline_case_capture = item_ref;
1169111748
1169211749 case_block.instructions.shrinkRetainingCapacity(0);
1169311750 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
1170211759 special.capture,
1170311760 .special,
1170411761 &.{item_ref},
11762 item_ref,
11763 special.has_tag_capture,
1170511764 );
1170611765
1170711766 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1170811767 cases_extra.appendAssumeCapacity(1); // items_len
1170911768 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));
1171111770 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1171211771 }
1171311772 },
1171411773 .Bool => {
1171511774 if (true_count == 0) {
1171611775 cases_len += 1;
11717 case_block.inline_case_capture = Air.Inst.Ref.bool_true;
1171811776
1171911777 case_block.instructions.shrinkRetainingCapacity(0);
1172011778 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
1172911787 special.capture,
1173011788 .special,
1173111789 &.{Air.Inst.Ref.bool_true},
11790 Air.Inst.Ref.bool_true,
11791 special.has_tag_capture,
1173211792 );
1173311793
1173411794 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1173511795 cases_extra.appendAssumeCapacity(1); // items_len
1173611796 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));
1173811798 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1173911799 }
1174011800 if (false_count == 0) {
1174111801 cases_len += 1;
11742 case_block.inline_case_capture = Air.Inst.Ref.bool_false;
1174311802
1174411803 case_block.instructions.shrinkRetainingCapacity(0);
1174511804 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
1175411813 special.capture,
1175511814 .special,
1175611815 &.{Air.Inst.Ref.bool_false},
11816 Air.Inst.Ref.bool_false,
11817 special.has_tag_capture,
1175711818 );
1175811819
1175911820 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1176011821 cases_extra.appendAssumeCapacity(1); // items_len
1176111822 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));
1176311824 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1176411825 }
1176511826 },
......@@ -11773,7 +11834,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1177311834
1177411835 case_block.instructions.shrinkRetainingCapacity(0);
1177511836 case_block.wip_capture_scope = wip_captures.scope;
11776 case_block.inline_case_capture = .none;
1177711837
1177811838 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
1177911839 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
1180411864 special.capture,
1180511865 .special,
1180611866 undefined, // case_vals may be undefined for special prongs
11867 .none,
11868 false,
1180711869 );
1180811870 } else {
1180911871 // 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 {
676676 /// what will be switched on.
677677 /// Uses the `un_node` union field.
678678 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,
682679 /// Given a
683680 /// *A returns *A
684681 /// *E!A returns *A
......@@ -1124,7 +1121,6 @@ pub const Inst = struct {
11241121 .typeof_log2_int_type,
11251122 .resolve_inferred_alloc,
11261123 .set_eval_branch_quota,
1127 .switch_capture_tag,
11281124 .switch_block,
11291125 .switch_cond,
11301126 .switch_cond_ref,
......@@ -1414,7 +1410,6 @@ pub const Inst = struct {
14141410 .slice_length,
14151411 .import,
14161412 .typeof_log2_int_type,
1417 .switch_capture_tag,
14181413 .switch_block,
14191414 .switch_cond,
14201415 .switch_cond_ref,
......@@ -1670,7 +1665,6 @@ pub const Inst = struct {
16701665 .switch_block = .pl_node,
16711666 .switch_cond = .un_node,
16721667 .switch_cond_ref = .un_node,
1673 .switch_capture_tag = .un_tok,
16741668 .array_base_ptr = .un_node,
16751669 .field_base_ptr = .un_node,
16761670 .validate_array_init_ty = .pl_node,
......@@ -1996,9 +1990,10 @@ pub const Inst = struct {
19961990 /// Implements the `@inComptime` builtin.
19971991 /// `operand` is `src_node: i32`.
19981992 in_comptime,
1999 /// Used as a placeholder for the capture of an `errdefer`.
2000 /// This is replaced by Sema with the captured value.
2001 errdefer_err_code,
1993 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
1994 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
1995 /// This should never appear in a body.
1996 value_placeholder,
20021997
20031998 pub const InstData = struct {
20041999 opcode: Extended,
......@@ -2644,16 +2639,17 @@ pub const Inst = struct {
26442639 };
26452640
26462641 /// 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.
26482644 /// info: ProngInfo,
26492645 /// body member Index for every info.body_len
26502646 /// }
2651 /// 2. scalar_cases: { // for every scalar_cases_len
2647 /// 3. scalar_cases: { // for every scalar_cases_len
26522648 /// item: Ref,
26532649 /// info: ProngInfo,
26542650 /// body member Index for every info.body_len
26552651 /// }
2656 /// 3. multi_cases: { // for every multi_cases_len
2652 /// 4. multi_cases: { // for every multi_cases_len
26572653 /// items_len: u32,
26582654 /// ranges_len: u32,
26592655 /// info: ProngInfo,
......@@ -2681,9 +2677,10 @@ pub const Inst = struct {
26812677
26822678 /// These are stored in trailing data in `extra` for each prong.
26832679 pub const ProngInfo = packed struct(u32) {
2684 body_len: u29,
2680 body_len: u28,
26852681 capture: Capture,
26862682 is_inline: bool,
2683 has_tag_capture: bool,
26872684
26882685 pub const Capture = enum(u2) {
26892686 none,
......@@ -2699,9 +2696,11 @@ pub const Inst = struct {
26992696 has_else: bool,
27002697 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.
27012698 has_under: bool,
2699 /// If true, at least one prong has an inline tag capture.
2700 any_has_tag_capture: bool,
27022701 scalar_cases_len: ScalarCasesLen,
27032702
2704 pub const ScalarCasesLen = u29;
2703 pub const ScalarCasesLen = u28;
27052704
27062705 pub fn specialProng(bits: Bits) SpecialProng {
27072706 const has_else: u2 = @boolToInt(bits.has_else);
src/print_zir.zig+12-2
......@@ -235,7 +235,6 @@ const Writer = struct {
235235 .ref,
236236 .ret_implicit,
237237 .closure_capture,
238 .switch_capture_tag,
239238 => try self.writeUnTok(stream, inst),
240239
241240 .bool_br_and,
......@@ -463,7 +462,7 @@ const Writer = struct {
463462 .breakpoint,
464463 .c_va_start,
465464 .in_comptime,
466 .errdefer_err_code,
465 .value_placeholder,
467466 => try self.writeExtNode(stream, extended),
468467
469468 .builtin_src => {
......@@ -1897,8 +1896,19 @@ const Writer = struct {
18971896 break :blk multi_cases_len;
18981897 } 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
19001905 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
19021912 self.indent += 2;
19031913
19041914 else_prong: {