authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-13 08:45:12-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-06-13 08:45:12-07:00
logdf6319418a08b611bae23307ace6688f95bedea2
tree6cdf873c6800aebccdd8c03a443f9594acb84729
parent387f9568ad0dabd426d382efb45b9c52a4ccc5bb
parent42dc7539c5b0a39e9b64c5ad92757945b0ca05ad
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15880 from mlugg/feat/better-switch-zir-2

Simplify and compact switch ZIR, and resolve union payload captures with PTR

10 files changed, 1328 insertions(+), 798 deletions(-)

src/AstGen.zig+82-71
...@@ -2610,13 +2610,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2610,13 +2610,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2610 .slice_length,2610 .slice_length,
2611 .import,2611 .import,
2612 .switch_block,2612 .switch_block,
2613 .switch_cond,2613 .switch_block_ref,
2614 .switch_cond_ref,
2615 .switch_capture,
2616 .switch_capture_ref,
2617 .switch_capture_multi,
2618 .switch_capture_multi_ref,
2619 .switch_capture_tag,
2620 .struct_init_empty,2614 .struct_init_empty,
2621 .struct_init,2615 .struct_init,
2622 .struct_init_ref,2616 .struct_init_ref,
...@@ -2960,7 +2954,7 @@ fn deferStmt(...@@ -2960,7 +2954,7 @@ fn deferStmt(
2960 try gz.astgen.instructions.append(gz.astgen.gpa, .{2954 try gz.astgen.instructions.append(gz.astgen.gpa, .{
2961 .tag = .extended,2955 .tag = .extended,
2962 .data = .{ .extended = .{2956 .data = .{ .extended = .{
2963 .opcode = .errdefer_err_code,2957 .opcode = .value_placeholder,
2964 .small = undefined,2958 .small = undefined,
2965 .operand = undefined,2959 .operand = undefined,
2966 } },2960 } },
...@@ -6715,6 +6709,7 @@ fn switchExpr(...@@ -6715,6 +6709,7 @@ fn switchExpr(
6715 // for the following variables, make note of the special prong AST node index,6709 // for the following variables, make note of the special prong AST node index,
6716 // and bail out with a compile error if there are multiple special prongs present.6710 // and bail out with a compile error if there are multiple special prongs present.
6717 var any_payload_is_ref = false;6711 var any_payload_is_ref = false;
6712 var any_has_tag_capture = false;
6718 var scalar_cases_len: u32 = 0;6713 var scalar_cases_len: u32 = 0;
6719 var multi_cases_len: u32 = 0;6714 var multi_cases_len: u32 = 0;
6720 var inline_cases_len: u32 = 0;6715 var inline_cases_len: u32 = 0;
...@@ -6725,8 +6720,12 @@ fn switchExpr(...@@ -6725,8 +6720,12 @@ fn switchExpr(
6725 for (case_nodes) |case_node| {6720 for (case_nodes) |case_node| {
6726 const case = tree.fullSwitchCase(case_node).?;6721 const case = tree.fullSwitchCase(case_node).?;
6727 if (case.payload_token) |payload_token| {6722 if (case.payload_token) |payload_token| {
6728 if (token_tags[payload_token] == .asterisk) {6723 const ident = if (token_tags[payload_token] == .asterisk) blk: {
6729 any_payload_is_ref = true;6724 any_payload_is_ref = true;
6725 break :blk payload_token + 1;
6726 } else payload_token;
6727 if (token_tags[ident + 1] == .comma) {
6728 any_has_tag_capture = true;
6730 }6729 }
6731 }6730 }
6732 // Check for else/`_` prong.6731 // Check for else/`_` prong.
...@@ -6835,13 +6834,7 @@ fn switchExpr(...@@ -6835,13 +6834,7 @@ fn switchExpr(
6835 const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };6834 const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
68366835
6837 const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);6836 const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
6838 const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond;6837 const item_ri: ResultInfo = .{ .rl = .none };
6839 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
6840 // Sema expects a dbg_stmt immediately after switch_cond(_ref)
6841 try emitDbgStmt(parent_gz, operand_lc);
6842 // We need the type of the operand to use as the result location for all the prong items.
6843 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node);
6844 const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } };
68456838
6846 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,6839 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
6847 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with6840 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with
...@@ -6860,13 +6853,30 @@ fn switchExpr(...@@ -6860,13 +6853,30 @@ fn switchExpr(
6860 block_scope.instructions_top = GenZir.unstacked_top;6853 block_scope.instructions_top = GenZir.unstacked_top;
6861 block_scope.setBreakResultInfo(ri);6854 block_scope.setBreakResultInfo(ri);
68626855
6856 // Sema expects a dbg_stmt immediately before switch_block(_ref)
6857 try emitDbgStmt(parent_gz, operand_lc);
6863 // This gets added to the parent block later, after the item expressions.6858 // This gets added to the parent block later, after the item expressions.
6864 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node);6859 const switch_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_block_ref else .switch_block;
6860 const switch_block = try parent_gz.makeBlockInst(switch_tag, switch_node);
68656861
6866 // We re-use this same scope for all cases, including the special prong, if any.6862 // We re-use this same scope for all cases, including the special prong, if any.
6867 var case_scope = parent_gz.makeSubBlock(&block_scope.base);6863 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
6868 case_scope.instructions_top = GenZir.unstacked_top;6864 case_scope.instructions_top = GenZir.unstacked_top;
68696865
6866 // If any prong has an inline tag capture, allocate a shared dummy instruction for it
6867 const tag_inst = if (any_has_tag_capture) tag_inst: {
6868 const inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
6869 try astgen.instructions.append(astgen.gpa, .{
6870 .tag = .extended,
6871 .data = .{ .extended = .{
6872 .opcode = .value_placeholder,
6873 .small = undefined,
6874 .operand = undefined,
6875 } }, // TODO rename opcode
6876 });
6877 break :tag_inst inst;
6878 } else undefined;
6879
6870 // In this pass we generate all the item and prong expressions.6880 // In this pass we generate all the item and prong expressions.
6871 var multi_case_index: u32 = 0;6881 var multi_case_index: u32 = 0;
6872 var scalar_case_index: u32 = 0;6882 var scalar_case_index: u32 = 0;
...@@ -6880,17 +6890,22 @@ fn switchExpr(...@@ -6880,17 +6890,22 @@ fn switchExpr(
6880 var dbg_var_inst: Zir.Inst.Ref = undefined;6890 var dbg_var_inst: Zir.Inst.Ref = undefined;
6881 var dbg_var_tag_name: ?u32 = null;6891 var dbg_var_tag_name: ?u32 = null;
6882 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;6892 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;
6883 var capture_inst: Zir.Inst.Index = 0;6893 var has_tag_capture = false;
6884 var tag_inst: Zir.Inst.Index = 0;
6885 var capture_val_scope: Scope.LocalVal = undefined;6894 var capture_val_scope: Scope.LocalVal = undefined;
6886 var tag_scope: Scope.LocalVal = undefined;6895 var tag_scope: Scope.LocalVal = undefined;
6896
6897 var capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = .none;
6898
6887 const sub_scope = blk: {6899 const sub_scope = blk: {
6888 const payload_token = case.payload_token orelse break :blk &case_scope.base;6900 const payload_token = case.payload_token orelse break :blk &case_scope.base;
6889 const ident = if (token_tags[payload_token] == .asterisk)6901 const ident = if (token_tags[payload_token] == .asterisk)
6890 payload_token + 16902 payload_token + 1
6891 else6903 else
6892 payload_token;6904 payload_token;
6905
6893 const is_ptr = ident != payload_token;6906 const is_ptr = ident != payload_token;
6907 capture = if (is_ptr) .by_ref else .by_val;
6908
6894 const ident_slice = tree.tokenSlice(ident);6909 const ident_slice = tree.tokenSlice(ident);
6895 var payload_sub_scope: *Scope = undefined;6910 var payload_sub_scope: *Scope = undefined;
6896 if (mem.eql(u8, ident_slice, "_")) {6911 if (mem.eql(u8, ident_slice, "_")) {
...@@ -6899,53 +6914,18 @@ fn switchExpr(...@@ -6899,53 +6914,18 @@ fn switchExpr(
6899 }6914 }
6900 payload_sub_scope = &case_scope.base;6915 payload_sub_scope = &case_scope.base;
6901 } else {6916 } else {
6902 if (case_node == special_node) {
6903 const capture_tag: Zir.Inst.Tag = if (is_ptr)
6904 .switch_capture_ref
6905 else
6906 .switch_capture;
6907 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
6908 try astgen.instructions.append(gpa, .{
6909 .tag = capture_tag,
6910 .data = .{
6911 .switch_capture = .{
6912 .switch_inst = switch_block,
6913 // Max int communicates that this is the else/underscore prong.
6914 .prong_index = std.math.maxInt(u32),
6915 },
6916 },
6917 });
6918 } else {
6919 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
6920 const is_ptr_bits: u2 = @boolToInt(is_ptr);
6921 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
6922 0b00 => .switch_capture,
6923 0b01 => .switch_capture_ref,
6924 0b10 => .switch_capture_multi,
6925 0b11 => .switch_capture_multi_ref,
6926 };
6927 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index;
6928 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
6929 try astgen.instructions.append(gpa, .{
6930 .tag = capture_tag,
6931 .data = .{ .switch_capture = .{
6932 .switch_inst = switch_block,
6933 .prong_index = capture_index,
6934 } },
6935 });
6936 }
6937 const capture_name = try astgen.identAsString(ident);6917 const capture_name = try astgen.identAsString(ident);
6938 try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice, .capture);6918 try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice, .capture);
6939 capture_val_scope = .{6919 capture_val_scope = .{
6940 .parent = &case_scope.base,6920 .parent = &case_scope.base,
6941 .gen_zir = &case_scope,6921 .gen_zir = &case_scope,
6942 .name = capture_name,6922 .name = capture_name,
6943 .inst = indexToRef(capture_inst),6923 .inst = indexToRef(switch_block),
6944 .token_src = payload_token,6924 .token_src = payload_token,
6945 .id_cat = .capture,6925 .id_cat = .capture,
6946 };6926 };
6947 dbg_var_name = capture_name;6927 dbg_var_name = capture_name;
6948 dbg_var_inst = indexToRef(capture_inst);6928 dbg_var_inst = indexToRef(switch_block);
6949 payload_sub_scope = &capture_val_scope.base;6929 payload_sub_scope = &capture_val_scope.base;
6950 }6930 }
69516931
...@@ -6961,14 +6941,9 @@ fn switchExpr(...@@ -6961,14 +6941,9 @@ fn switchExpr(
6961 }6941 }
6962 const tag_name = try astgen.identAsString(tag_token);6942 const tag_name = try astgen.identAsString(tag_token);
6963 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");6943 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");
6964 tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);6944
6965 try astgen.instructions.append(gpa, .{6945 assert(any_has_tag_capture);
6966 .tag = .switch_capture_tag,6946 has_tag_capture = true;
6967 .data = .{ .un_tok = .{
6968 .operand = cond,
6969 .src_tok = case_scope.tokenIndexToRelative(tag_token),
6970 } },
6971 });
69726947
6973 tag_scope = .{6948 tag_scope = .{
6974 .parent = payload_sub_scope,6949 .parent = payload_sub_scope,
...@@ -7034,8 +7009,6 @@ fn switchExpr(...@@ -7034,8 +7009,6 @@ fn switchExpr(
7034 case_scope.instructions_top = parent_gz.instructions.items.len;7009 case_scope.instructions_top = parent_gz.instructions.items.len;
7035 defer case_scope.unstack();7010 defer case_scope.unstack();
70367011
7037 if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst);
7038 if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst);
7039 try case_scope.addDbgBlockBegin();7012 try case_scope.addDbgBlockBegin();
7040 if (dbg_var_name) |some| {7013 if (dbg_var_name) |some| {
7041 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);7014 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
...@@ -7053,10 +7026,42 @@ fn switchExpr(...@@ -7053,10 +7026,42 @@ fn switchExpr(
7053 }7026 }
70547027
7055 const case_slice = case_scope.instructionsSlice();7028 const case_slice = case_scope.instructionsSlice();
7056 const body_len = astgen.countBodyLenAfterFixups(case_slice);7029 // Since we use the switch_block instruction itself to refer to the
7030 // capture, which will not be added to the child block, we need to
7031 // handle ref_table manually, and the same for the inline tag
7032 // capture instruction.
7033 const refs_len = refs: {
7034 var n: usize = 0;
7035 var check_inst = switch_block;
7036 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7037 n += 1;
7038 check_inst = ref_inst;
7039 }
7040 if (has_tag_capture) {
7041 check_inst = tag_inst;
7042 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7043 n += 1;
7044 check_inst = ref_inst;
7045 }
7046 }
7047 break :refs n;
7048 };
7049 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7057 try payloads.ensureUnusedCapacity(gpa, body_len);7050 try payloads.ensureUnusedCapacity(gpa, body_len);
7058 const inline_bit = @as(u32, @boolToInt(case.inline_token != null)) << 31;7051 payloads.items[body_len_index] = @bitCast(u32, Zir.Inst.SwitchBlock.ProngInfo{
7059 payloads.items[body_len_index] = body_len | inline_bit;7052 .body_len = @intCast(u28, body_len),
7053 .capture = capture,
7054 .is_inline = case.inline_token != null,
7055 .has_tag_capture = has_tag_capture,
7056 });
7057 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
7058 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7059 }
7060 if (has_tag_capture) {
7061 if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
7062 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7063 }
7064 }
7060 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);7065 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7061 }7066 }
7062 }7067 }
...@@ -7065,14 +7070,16 @@ fn switchExpr(...@@ -7065,14 +7070,16 @@ fn switchExpr(
70657070
7066 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +7071 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
7067 @boolToInt(multi_cases_len != 0) +7072 @boolToInt(multi_cases_len != 0) +
7073 @boolToInt(any_has_tag_capture) +
7068 payloads.items.len - case_table_end);7074 payloads.items.len - case_table_end);
70697075
7070 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{7076 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
7071 .operand = cond,7077 .operand = raw_operand,
7072 .bits = Zir.Inst.SwitchBlock.Bits{7078 .bits = Zir.Inst.SwitchBlock.Bits{
7073 .has_multi_cases = multi_cases_len != 0,7079 .has_multi_cases = multi_cases_len != 0,
7074 .has_else = special_prong == .@"else",7080 .has_else = special_prong == .@"else",
7075 .has_under = special_prong == .under,7081 .has_under = special_prong == .under,
7082 .any_has_tag_capture = any_has_tag_capture,
7076 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),7083 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),
7077 },7084 },
7078 });7085 });
...@@ -7081,6 +7088,10 @@ fn switchExpr(...@@ -7081,6 +7088,10 @@ fn switchExpr(
7081 astgen.extra.appendAssumeCapacity(multi_cases_len);7088 astgen.extra.appendAssumeCapacity(multi_cases_len);
7082 }7089 }
70837090
7091 if (any_has_tag_capture) {
7092 astgen.extra.appendAssumeCapacity(tag_inst);
7093 }
7094
7084 const zir_datas = astgen.instructions.items(.data);7095 const zir_datas = astgen.instructions.items(.data);
7085 const zir_tags = astgen.instructions.items(.tag);7096 const zir_tags = astgen.instructions.items(.tag);
70867097
...@@ -7103,7 +7114,7 @@ fn switchExpr(...@@ -7103,7 +7114,7 @@ fn switchExpr(
7103 end_index += 3 + items_len + 2 * ranges_len;7114 end_index += 3 + items_len + 2 * ranges_len;
7104 }7115 }
71057116
7106 const body_len = @truncate(u31, payloads.items[body_len_index]);7117 const body_len = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, payloads.items[body_len_index]).body_len;
7107 end_index += body_len;7118 end_index += body_len;
71087119
7109 switch (strat.tag) {7120 switch (strat.tag) {
src/Autodoc.zig-25
...@@ -1993,31 +1993,6 @@ fn walkInstruction(...@@ -1993,31 +1993,6 @@ fn walkInstruction(
1993 .expr = .{ .switchIndex = switch_index },1993 .expr = .{ .switchIndex = switch_index },
1994 };1994 };
1995 },1995 },
1996 .switch_cond => {
1997 const un_node = data[inst_index].un_node;
1998 const operand = try self.walkRef(
1999 file,
2000 parent_scope,
2001 parent_src,
2002 un_node.operand,
2003 need_type,
2004 );
2005 const operand_index = self.exprs.items.len;
2006 try self.exprs.append(self.arena, operand.expr);
2007
2008 // const ast_index = self.ast_nodes.items.len;
2009 // const sep = "=" ** 200;
2010 // log.debug("{s}", .{sep});
2011 // log.debug("SWITCH COND", .{});
2012 // log.debug("ast index = {}", .{ast_index});
2013 // log.debug("ast previous = {}", .{self.ast_nodes.items[ast_index - 1]});
2014 // log.debug("{s}", .{sep});
2015
2016 return DocData.WalkResult{
2017 .typeRef = operand.typeRef,
2018 .expr = .{ .typeOf = operand_index },
2019 };
2020 },
20211996
2022 .typeof => {1997 .typeof => {
2023 const un_node = data[inst_index].un_node;1998 const un_node = data[inst_index].un_node;
src/Module.zig+112-46
...@@ -2471,12 +2471,23 @@ pub const SrcLoc = struct {...@@ -2471,12 +2471,23 @@ pub const SrcLoc = struct {
2471 }2471 }
2472 } else unreachable;2472 } else unreachable;
2473 },2473 },
2474 .node_offset_switch_prong_capture => |node_off| {2474 .node_offset_switch_prong_capture,
2475 .node_offset_switch_prong_tag_capture,
2476 => |node_off| {
2475 const tree = try src_loc.file_scope.getTree(gpa);2477 const tree = try src_loc.file_scope.getTree(gpa);
2476 const case_node = src_loc.declRelativeToNodeIndex(node_off);2478 const case_node = src_loc.declRelativeToNodeIndex(node_off);
2477 const case = tree.fullSwitchCase(case_node).?;2479 const case = tree.fullSwitchCase(case_node).?;
2478 const start_tok = case.payload_token.?;
2479 const token_tags = tree.tokens.items(.tag);2480 const token_tags = tree.tokens.items(.tag);
2481 const start_tok = switch (src_loc.lazy) {
2482 .node_offset_switch_prong_capture => case.payload_token.?,
2483 .node_offset_switch_prong_tag_capture => blk: {
2484 var tok = case.payload_token.?;
2485 if (token_tags[tok] == .asterisk) tok += 1;
2486 tok += 2; // skip over comma
2487 break :blk tok;
2488 },
2489 else => unreachable,
2490 };
2480 const end_tok = switch (token_tags[start_tok]) {2491 const end_tok = switch (token_tags[start_tok]) {
2481 .asterisk => start_tok + 1,2492 .asterisk => start_tok + 1,
2482 else => start_tok,2493 else => start_tok,
...@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {...@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {
2957 /// The source location points to the capture of a switch_prong.2968 /// The source location points to the capture of a switch_prong.
2958 /// The Decl is determined contextually.2969 /// The Decl is determined contextually.
2959 node_offset_switch_prong_capture: i32,2970 node_offset_switch_prong_capture: i32,
2971 /// The source location points to the tag capture of a switch_prong.
2972 /// The Decl is determined contextually.
2973 node_offset_switch_prong_tag_capture: i32,
2960 /// The source location points to the align expr of a function type2974 /// The source location points to the align expr of a function type
2961 /// expression, found by taking this AST node index offset from the containing2975 /// expression, found by taking this AST node index offset from the containing
2962 /// Decl AST node, which points to a function type AST node. Next, navigate to2976 /// Decl AST node, which points to a function type AST node. Next, navigate to
...@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {
3130 .node_offset_switch_special_prong,3144 .node_offset_switch_special_prong,
3131 .node_offset_switch_range,3145 .node_offset_switch_range,
3132 .node_offset_switch_prong_capture,3146 .node_offset_switch_prong_capture,
3147 .node_offset_switch_prong_tag_capture,
3133 .node_offset_fn_type_align,3148 .node_offset_fn_type_align,
3134 .node_offset_fn_type_addrspace,3149 .node_offset_fn_type_addrspace,
3135 .node_offset_fn_type_section,3150 .node_offset_fn_type_section,
...@@ -5867,10 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {...@@ -5867,10 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
5867}5882}
58685883
5869pub const SwitchProngSrc = union(enum) {5884pub const SwitchProngSrc = union(enum) {
5885 /// The item for a scalar prong.
5870 scalar: u32,5886 scalar: u32,
5887 /// A given single item for a multi prong.
5871 multi: Multi,5888 multi: Multi,
5889 /// A given range item for a multi prong.
5872 range: Multi,5890 range: Multi,
5891 /// The item for the special prong.
5892 special,
5893 /// The main capture for a scalar prong.
5894 scalar_capture: u32,
5895 /// The main capture for a multi prong.
5873 multi_capture: u32,5896 multi_capture: u32,
5897 /// The main capture for the special prong.
5898 special_capture,
5899 /// The tag capture for a scalar prong.
5900 scalar_tag_capture: u32,
5901 /// The tag capture for a multi prong.
5902 multi_tag_capture: u32,
5903 /// The tag capture for the special prong.
5904 special_tag_capture,
58745905
5875 pub const Multi = struct {5906 pub const Multi = struct {
5876 prong: u32,5907 prong: u32,
...@@ -5886,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -5886,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {
5886 mod: *Module,5917 mod: *Module,
5887 decl: *Decl,5918 decl: *Decl,
5888 switch_node_offset: i32,5919 switch_node_offset: i32,
5920 /// Ignored if `prong_src` is not `.range`
5889 range_expand: RangeExpand,5921 range_expand: RangeExpand,
5890 ) LazySrcLoc {5922 ) LazySrcLoc {
5891 @setCold(true);5923 @setCold(true);
...@@ -5906,63 +5938,97 @@ pub const SwitchProngSrc = union(enum) {...@@ -5906,63 +5938,97 @@ pub const SwitchProngSrc = union(enum) {
59065938
5907 var multi_i: u32 = 0;5939 var multi_i: u32 = 0;
5908 var scalar_i: u32 = 0;5940 var scalar_i: u32 = 0;
5909 for (case_nodes) |case_node| {5941 const case_node = for (case_nodes) |case_node| {
5910 const case = tree.fullSwitchCase(case_node).?;5942 const case = tree.fullSwitchCase(case_node).?;
5911 if (case.ast.values.len == 0)5943
5912 continue;5944 const is_special = special: {
5913 if (case.ast.values.len == 1 and5945 if (case.ast.values.len == 0) break :special true;
5914 node_tags[case.ast.values[0]] == .identifier and5946 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
5915 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))5947 break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
5916 {5948 }
5917 continue;5949 break :special false;
5950 };
5951
5952 if (is_special) {
5953 switch (prong_src) {
5954 .special, .special_capture, .special_tag_capture => break case_node,
5955 else => continue,
5956 }
5918 }5957 }
5958
5919 const is_multi = case.ast.values.len != 1 or5959 const is_multi = case.ast.values.len != 1 or
5920 node_tags[case.ast.values[0]] == .switch_range;5960 node_tags[case.ast.values[0]] == .switch_range;
59215961
5922 switch (prong_src) {5962 switch (prong_src) {
5923 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(5963 .scalar,
5924 decl.nodeIndexToRelative(case.ast.values[0]),5964 .scalar_capture,
5925 ),5965 .scalar_tag_capture,
5926 .multi_capture => |i| if (is_multi and i == multi_i) {5966 => |i| if (!is_multi and i == scalar_i) break case_node,
5927 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };5967
5928 },5968 .multi_capture,
5929 .multi => |s| if (is_multi and s.prong == multi_i) {5969 .multi_tag_capture,
5930 var item_i: u32 = 0;5970 => |i| if (is_multi and i == multi_i) break case_node,
5931 for (case.ast.values) |item_node| {5971
5932 if (node_tags[item_node] == .switch_range) continue;5972 .multi,
59335973 .range,
5934 if (item_i == s.item) return LazySrcLoc.nodeOffset(5974 => |m| if (is_multi and m.prong == multi_i) break case_node,
5935 decl.nodeIndexToRelative(item_node),5975
5936 );5976 .special,
5937 item_i += 1;5977 .special_capture,
5938 } else unreachable;5978 .special_tag_capture,
5939 },5979 => {},
5940 .range => |s| if (is_multi and s.prong == multi_i) {
5941 var range_i: u32 = 0;
5942 for (case.ast.values) |range| {
5943 if (node_tags[range] != .switch_range) continue;
5944
5945 if (range_i == s.item) switch (range_expand) {
5946 .none => return LazySrcLoc.nodeOffset(
5947 decl.nodeIndexToRelative(range),
5948 ),
5949 .first => return LazySrcLoc.nodeOffset(
5950 decl.nodeIndexToRelative(node_datas[range].lhs),
5951 ),
5952 .last => return LazySrcLoc.nodeOffset(
5953 decl.nodeIndexToRelative(node_datas[range].rhs),
5954 ),
5955 };
5956 range_i += 1;
5957 } else unreachable;
5958 },
5959 }5980 }
5981
5960 if (is_multi) {5982 if (is_multi) {
5961 multi_i += 1;5983 multi_i += 1;
5962 } else {5984 } else {
5963 scalar_i += 1;5985 scalar_i += 1;
5964 }5986 }
5965 } else unreachable;5987 } else unreachable;
5988
5989 const case = tree.fullSwitchCase(case_node).?;
5990
5991 switch (prong_src) {
5992 .scalar, .special => return LazySrcLoc.nodeOffset(
5993 decl.nodeIndexToRelative(case.ast.values[0]),
5994 ),
5995 .multi => |m| {
5996 var item_i: u32 = 0;
5997 for (case.ast.values) |item_node| {
5998 if (node_tags[item_node] == .switch_range) continue;
5999 if (item_i == m.item) return LazySrcLoc.nodeOffset(
6000 decl.nodeIndexToRelative(item_node),
6001 );
6002 item_i += 1;
6003 }
6004 unreachable;
6005 },
6006 .range => |m| {
6007 var range_i: u32 = 0;
6008 for (case.ast.values) |range| {
6009 if (node_tags[range] != .switch_range) continue;
6010 if (range_i == m.item) switch (range_expand) {
6011 .none => return LazySrcLoc.nodeOffset(
6012 decl.nodeIndexToRelative(range),
6013 ),
6014 .first => return LazySrcLoc.nodeOffset(
6015 decl.nodeIndexToRelative(node_datas[range].lhs),
6016 ),
6017 .last => return LazySrcLoc.nodeOffset(
6018 decl.nodeIndexToRelative(node_datas[range].rhs),
6019 ),
6020 };
6021 range_i += 1;
6022 }
6023 unreachable;
6024 },
6025 .scalar_capture, .multi_capture, .special_capture => {
6026 return .{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
6027 },
6028 .scalar_tag_capture, .multi_tag_capture, .special_tag_capture => {
6029 return .{ .node_offset_switch_prong_tag_capture = decl.nodeIndexToRelative(case_node) };
6030 },
6031 }
5966 }6032 }
5967};6033};
59686034
src/Sema.zig+950-431
...@@ -277,12 +277,6 @@ pub const Block = struct {...@@ -277,12 +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 /// type of `err` in `else => |err|`
281 switch_else_err_ty: ?Type = null,
282
283 /// Value for switch_capture in an inline case
284 inline_case_capture: Air.Inst.Ref = .none,
285
286 const ComptimeReason = union(enum) {280 const ComptimeReason = union(enum) {
287 c_import: struct {281 c_import: struct {
288 block: *Block,282 block: *Block,
...@@ -397,7 +391,6 @@ pub const Block = struct {...@@ -397,7 +391,6 @@ pub const Block = struct {
397 .want_safety = parent.want_safety,391 .want_safety = parent.want_safety,
398 .float_mode = parent.float_mode,392 .float_mode = parent.float_mode,
399 .c_import_buf = parent.c_import_buf,393 .c_import_buf = parent.c_import_buf,
400 .switch_else_err_ty = parent.switch_else_err_ty,
401 .error_return_trace_index = parent.error_return_trace_index,394 .error_return_trace_index = parent.error_return_trace_index,
402 };395 };
403 }396 }
...@@ -1014,14 +1007,8 @@ fn analyzeBodyInner(...@@ -1014,14 +1007,8 @@ fn analyzeBodyInner(
1014 .slice_start => try sema.zirSliceStart(block, inst),1007 .slice_start => try sema.zirSliceStart(block, inst),
1015 .slice_length => try sema.zirSliceLength(block, inst),1008 .slice_length => try sema.zirSliceLength(block, inst),
1016 .str => try sema.zirStr(block, inst),1009 .str => try sema.zirStr(block, inst),
1017 .switch_block => try sema.zirSwitchBlock(block, inst),1010 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1018 .switch_cond => try sema.zirSwitchCond(block, inst, false),1011 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1019 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
1020 .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
1021 .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
1022 .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
1023 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
1024 .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst),
1025 .type_info => try sema.zirTypeInfo(block, inst),1012 .type_info => try sema.zirTypeInfo(block, inst),
1026 .size_of => try sema.zirSizeOf(block, inst),1013 .size_of => try sema.zirSizeOf(block, inst),
1027 .bit_size_of => try sema.zirBitSizeOf(block, inst),1014 .bit_size_of => try sema.zirBitSizeOf(block, inst),
...@@ -1225,7 +1212,7 @@ fn analyzeBodyInner(...@@ -1225,7 +1212,7 @@ fn analyzeBodyInner(
1225 i += 1;1212 i += 1;
1226 continue;1213 continue;
1227 },1214 },
1228 .errdefer_err_code => unreachable, // never appears in a body1215 .value_placeholder => unreachable, // never appears in a body
1229 };1216 };
1230 },1217 },
12311218
...@@ -2405,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -2405,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
2405 return error.AnalysisFail;2392 return error.AnalysisFail;
2406}2393}
24072394
2395/// Given an ErrorMsg, modify its message and source location to the given values, turning the
2396/// original message into a note. Notes on the original message are preserved as further notes.
2397/// Reference trace is preserved.
2398fn reparentOwnedErrorMsg(
2399 sema: *Sema,
2400 block: *Block,
2401 src: LazySrcLoc,
2402 msg: *Module.ErrorMsg,
2403 comptime format: []const u8,
2404 args: anytype,
2405) !void {
2406 const mod = sema.mod;
2407 const src_decl = mod.declPtr(block.src_decl);
2408 const resolved_src = src.toSrcLoc(src_decl, mod);
2409 const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
2410
2411 const orig_notes = msg.notes.len;
2412 msg.notes = try sema.gpa.realloc(msg.notes, orig_notes + 1);
2413 std.mem.copyBackwards(Module.ErrorMsg, msg.notes[1..], msg.notes[0..orig_notes]);
2414 msg.notes[0] = .{
2415 .src_loc = msg.src_loc,
2416 .msg = msg.msg,
2417 };
2418
2419 msg.src_loc = resolved_src;
2420 msg.msg = msg_str;
2421}
2422
2408const align_ty = Type.u29;2423const align_ty = Type.u29;
24092424
2410fn analyzeAsAlign(2425fn analyzeAsAlign(
...@@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10085 return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);10100 return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
10086}10101}
1008710102
10088fn zirSwitchCapture(10103/// Holds common data used when analyzing or resolving switch prong bodies,
10104/// including setting up captures.
10105const SwitchProngAnalysis = struct {
10089 sema: *Sema,10106 sema: *Sema,
10090 block: *Block,10107 /// The block containing the `switch_block` itself.
10091 inst: Zir.Inst.Index,10108 parent_block: *Block,
10092 is_multi: bool,10109 /// The raw switch operand value (*not* the condition). Always defined.
10093 is_ref: bool,10110 operand: Air.Inst.Ref,
10094) CompileError!Air.Inst.Ref {10111 /// May be `undefined` if no prong has a by-ref capture.
10095 const tracy = trace(@src());10112 operand_ptr: Air.Inst.Ref,
10096 defer tracy.end();10113 /// The switch condition value. For unions, `operand` is the union and `cond` is its tag.
10114 cond: Air.Inst.Ref,
10115 /// If this switch is on an error set, this is the type to assign to the
10116 /// `else` prong. If `null`, the prong should be unreachable.
10117 else_error_ty: ?Type,
10118 /// The index of the `switch_block` instruction itself.
10119 switch_block_inst: Zir.Inst.Index,
10120 /// The dummy index into which inline tag captures should be placed. May be
10121 /// undefined if no prong has a tag capture.
10122 tag_capture_inst: Zir.Inst.Index,
10123
10124 /// Resolve a switch prong which is determined at comptime to have no peers.
10125 /// Uses `resolveBlockBody`. Sets up captures as needed.
10126 fn resolveProngComptime(
10127 spa: SwitchProngAnalysis,
10128 child_block: *Block,
10129 prong_type: enum { normal, special },
10130 prong_body: []const Zir.Inst.Index,
10131 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10132 /// Must use the `scalar_capture`, `special_capture`, or `multi_capture` union field.
10133 raw_capture_src: Module.SwitchProngSrc,
10134 /// The set of all values which can reach this prong. May be undefined
10135 /// if the prong is special or contains ranges.
10136 case_vals: []const Air.Inst.Ref,
10137 /// The inline capture of this prong. If this is not an inline prong,
10138 /// this is `.none`.
10139 inline_case_capture: Air.Inst.Ref,
10140 /// Whether this prong has an inline tag capture. If `true`, then
10141 /// `inline_case_capture` cannot be `.none`.
10142 has_tag_capture: bool,
10143 merges: *Block.Merges,
10144 ) CompileError!Air.Inst.Ref {
10145 const sema = spa.sema;
10146 const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src();
10147
10148 if (has_tag_capture) {
10149 const tag_ref = try spa.analyzeTagCapture(child_block, raw_capture_src, inline_case_capture);
10150 sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
10151 }
10152 defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
10153
10154 switch (capture) {
10155 .none => {
10156 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
10157 },
10158
10159 .by_val, .by_ref => {
10160 const capture_ref = try spa.analyzeCapture(
10161 child_block,
10162 capture == .by_ref,
10163 prong_type == .special,
10164 raw_capture_src,
10165 case_vals,
10166 inline_case_capture,
10167 );
1009710168
10098 const mod = sema.mod;10169 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
10099 const gpa = sema.gpa;10170 // This prong should be unreachable!
10100 const zir_datas = sema.code.instructions.items(.data);10171 return Air.Inst.Ref.unreachable_value;
10101 const capture_info = zir_datas[inst].switch_capture;10172 }
10102 const switch_info = zir_datas[capture_info.switch_inst].pl_node;10173
10103 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);10174 sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
10104 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };10175 defer assert(sema.inst_map.remove(spa.switch_block_inst));
10105 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;10176
10106 const cond_info = zir_datas[cond_inst].un_node;10177 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
10107 const cond_tag = sema.code.instructions.items(.tag)[cond_inst];10178 },
10108 const operand_is_ref = cond_tag == .switch_cond_ref;10179 }
10109 const operand_ptr = try sema.resolveInst(cond_info.operand);10180 }
10110 const operand_ptr_ty = sema.typeOf(operand_ptr);10181
10111 const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;10182 /// Analyze a switch prong which may have peers at runtime.
1011210183 /// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed.
10113 if (block.inline_case_capture != .none) {10184 fn analyzeProngRuntime(
10114 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;10185 spa: SwitchProngAnalysis,
10115 const resolved_item_val = try sema.resolveLazyValue(item_val);10186 case_block: *Block,
10116 if (operand_ty.zigTypeTag(mod) == .Union) {10187 prong_type: enum { normal, special },
10117 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?);10188 prong_body: []const Zir.Inst.Index,
10118 const union_obj = mod.typeToUnion(operand_ty).?;10189 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10119 const field_ty = union_obj.fields.values()[field_index].ty;10190 /// Must use the `scalar`, `special`, or `multi_capture` union field.
10120 if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {10191 raw_capture_src: Module.SwitchProngSrc,
10121 if (is_ref) {10192 /// The set of all values which can reach this prong. May be undefined
10193 /// if the prong is special or contains ranges.
10194 case_vals: []const Air.Inst.Ref,
10195 /// The inline capture of this prong. If this is not an inline prong,
10196 /// this is `.none`.
10197 inline_case_capture: Air.Inst.Ref,
10198 /// Whether this prong has an inline tag capture. If `true`, then
10199 /// `inline_case_capture` cannot be `.none`.
10200 has_tag_capture: bool,
10201 ) CompileError!void {
10202 const sema = spa.sema;
10203
10204 if (has_tag_capture) {
10205 const tag_ref = try spa.analyzeTagCapture(case_block, raw_capture_src, inline_case_capture);
10206 sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
10207 }
10208 defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
10209
10210 switch (capture) {
10211 .none => {
10212 return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
10213 },
10214
10215 .by_val, .by_ref => {
10216 const capture_ref = try spa.analyzeCapture(
10217 case_block,
10218 capture == .by_ref,
10219 prong_type == .special,
10220 raw_capture_src,
10221 case_vals,
10222 inline_case_capture,
10223 );
10224
10225 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
10226 // No need to analyze any further, the prong is unreachable
10227 return;
10228 }
10229
10230 sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
10231 defer assert(sema.inst_map.remove(spa.switch_block_inst));
10232
10233 return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
10234 },
10235 }
10236 }
10237
10238 fn analyzeTagCapture(
10239 spa: SwitchProngAnalysis,
10240 block: *Block,
10241 raw_capture_src: Module.SwitchProngSrc,
10242 inline_case_capture: Air.Inst.Ref,
10243 ) CompileError!Air.Inst.Ref {
10244 const sema = spa.sema;
10245 const mod = sema.mod;
10246 const operand_ty = sema.typeOf(spa.operand);
10247 if (operand_ty.zigTypeTag(mod) != .Union) {
10248 const zir_datas = sema.code.instructions.items(.data);
10249 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
10250 const raw_tag_capture_src: Module.SwitchProngSrc = switch (raw_capture_src) {
10251 .scalar_capture => |i| .{ .scalar_tag_capture = i },
10252 .multi_capture => |i| .{ .multi_tag_capture = i },
10253 .special_capture => .special_tag_capture,
10254 else => unreachable,
10255 };
10256 const capture_src = raw_tag_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
10257 const msg = msg: {
10258 const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
10259 operand_ty.fmt(mod),
10260 });
10261 errdefer msg.destroy(sema.gpa);
10262 try sema.addDeclaredHereNote(msg, operand_ty);
10263 break :msg msg;
10264 };
10265 return sema.failWithOwnedErrorMsg(msg);
10266 }
10267 assert(inline_case_capture != .none);
10268 return inline_case_capture;
10269 }
10270
10271 fn analyzeCapture(
10272 spa: SwitchProngAnalysis,
10273 block: *Block,
10274 capture_byref: bool,
10275 is_special_prong: bool,
10276 raw_capture_src: Module.SwitchProngSrc,
10277 case_vals: []const Air.Inst.Ref,
10278 inline_case_capture: Air.Inst.Ref,
10279 ) CompileError!Air.Inst.Ref {
10280 const sema = spa.sema;
10281 const mod = sema.mod;
10282
10283 const zir_datas = sema.code.instructions.items(.data);
10284 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
10285
10286 const operand_ty = sema.typeOf(spa.operand);
10287 const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;
10288 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
10289
10290 if (inline_case_capture != .none) {
10291 const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;
10292 if (operand_ty.zigTypeTag(mod) == .Union) {
10293 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
10294 const union_obj = mod.typeToUnion(operand_ty).?;
10295 const field_ty = union_obj.fields.values()[field_index].ty;
10296 if (capture_byref) {
10122 const ptr_field_ty = try Type.ptr(sema.arena, mod, .{10297 const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
10123 .pointee_type = field_ty,10298 .pointee_type = field_ty,
10124 .mutable = operand_ptr_ty.ptrIsMutable(mod),10299 .mutable = operand_ptr_ty.ptrIsMutable(mod),
10125 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),10300 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
10126 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),10301 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
10127 });10302 });
10128 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{10303 if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| {
10129 .ty = ptr_field_ty.toIntern(),10304 return sema.addConstant(
10130 .addr = .{ .field = .{10305 ptr_field_ty,
10131 .base = union_val.toIntern(),10306 (try mod.intern(.{ .ptr = .{
10132 .index = field_index,10307 .ty = ptr_field_ty.toIntern(),
10133 } },10308 .addr = .{ .field = .{
10134 } })).toValue());10309 .base = union_ptr.toIntern(),
10310 .index = field_index,
10311 } },
10312 } })).toValue(),
10313 );
10314 }
10315 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
10316 } else {
10317 if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| {
10318 const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un;
10319 return sema.addConstant(field_ty, tag_and_val.val.toValue());
10320 }
10321 return block.addStructFieldVal(spa.operand, field_index, field_ty);
10135 }10322 }
10136 return sema.addConstant(10323 } else if (capture_byref) {
10137 field_ty,10324 return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
10138 mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(),
10139 );
10140 }
10141 if (is_ref) {
10142 const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
10143 .pointee_type = field_ty,
10144 .mutable = operand_ptr_ty.ptrIsMutable(mod),
10145 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
10146 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
10147 });
10148 return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty);
10149 } else {10325 } else {
10150 return block.addStructFieldVal(operand_ptr, field_index, field_ty);10326 return inline_case_capture;
10151 }10327 }
10152 } else if (is_ref) {
10153 return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true);
10154 } else {
10155 return block.inline_case_capture;
10156 }10328 }
10157 }
1015810329
10159 const operand = if (operand_is_ref)10330 if (is_special_prong) {
10160 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)10331 if (capture_byref) {
10161 else10332 return spa.operand_ptr;
10162 operand_ptr;10333 }
1016310334
10164 if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {10335 switch (operand_ty.zigTypeTag(mod)) {
10165 // It is the else/`_` prong.10336 .ErrorSet => if (spa.else_error_ty) |ty| {
10166 if (is_ref) {10337 return sema.bitCast(block, ty, spa.operand, operand_src, null);
10167 return operand_ptr;10338 } else {
10339 try block.addUnreachable(false);
10340 return Air.Inst.Ref.unreachable_value;
10341 },
10342 else => return spa.operand,
10343 }
10168 }10344 }
1016910345
10170 switch (operand_ty.zigTypeTag(mod)) {10346 switch (operand_ty.zigTypeTag(mod)) {
10171 .ErrorSet => if (block.switch_else_err_ty) |some| {10347 .Union => {
10172 return sema.bitCast(block, some, operand, operand_src, null);10348 const union_obj = mod.typeToUnion(operand_ty).?;
10173 } else {10349 const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
10174 try block.addUnreachable(false);
10175 return Air.Inst.Ref.unreachable_value;
10176 },
10177 else => return operand,
10178 }
10179 }
1018010350
10181 const items = if (is_multi)10351 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
10182 switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items10352 const first_field = union_obj.fields.values()[first_field_index];
10183 else
10184 &[_]Zir.Inst.Ref{
10185 switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item,
10186 };
1018710353
10188 switch (operand_ty.zigTypeTag(mod)) {10354 const field_tys = try sema.arena.alloc(Type, case_vals.len);
10189 .Union => {10355 for (case_vals, field_tys) |item, *field_ty| {
10190 const union_obj = mod.typeToUnion(operand_ty).?;10356 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
10191 const first_item = try sema.resolveInst(items[0]);10357 const field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
10192 // Previous switch validation ensured this will succeed10358 field_ty.* = union_obj.fields.values()[field_idx].ty;
10193 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;10359 }
10194
10195 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
10196 const first_field = union_obj.fields.values()[first_field_index];
10197
10198 for (items[1..], 0..) |item, i| {
10199 const item_ref = try sema.resolveInst(item);
10200 // Previous switch validation ensured this will succeed
10201 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
10202
10203 const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?;
10204 const field = union_obj.fields.values()[field_index];
10205 if (!field.ty.eql(first_field.ty, mod)) {
10206 const msg = msg: {
10207 const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index };
10208 const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first);
1020910360
10210 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});10361 // Fast path: if all the operands are the same type already, we don't need to hit
10211 errdefer msg.destroy(gpa);10362 // PTR! This will also allow us to emit simpler code.
10363 const same_types = for (field_tys[1..]) |field_ty| {
10364 if (!field_ty.eql(field_tys[0], sema.mod)) break false;
10365 } else true;
1021210366
10213 const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } };10367 const capture_ty = if (same_types) field_tys[0] else capture_ty: {
10214 const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first);10368 // We need values to run PTR on, so make a bunch of undef constants.
10215 const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };10369 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
10216 const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first);10370 for (dummy_captures, field_tys) |*dummy, field_ty| {
10217 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)});10371 dummy.* = try sema.addConstUndef(field_ty);
10218 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)});10372 }
10219 break :msg msg;10373
10374 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
10375 @memset(case_srcs, .unneeded);
10376
10377 break :capture_ty sema.resolvePeerTypes(block, .unneeded, dummy_captures, .{ .override = case_srcs }) catch |err| switch (err) {
10378 error.NeededSourceLocation => {
10379 // This must be a multi-prong so this must be a `multi_capture` src
10380 const multi_idx = raw_capture_src.multi_capture;
10381 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
10382 for (case_srcs, 0..) |*case_src, i| {
10383 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } };
10384 case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
10385 }
10386 const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
10387 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
10388 error.AnalysisFail => {
10389 const msg = sema.err orelse return error.AnalysisFail;
10390 try sema.reparentOwnedErrorMsg(block, capture_src, msg, "capture group with incompatible types", .{});
10391 return error.AnalysisFail;
10392 },
10393 else => |e| return e,
10394 };
10395 unreachable;
10396 },
10397 else => |e| return e,
10220 };10398 };
10221 return sema.failWithOwnedErrorMsg(msg);10399 };
10222 }
10223 }
1022410400
10225 if (is_ref) {10401 // By-reference captures have some further restrictions which make them easier to emit
10226 const field_ty_ptr = try Type.ptr(sema.arena, mod, .{10402 if (capture_byref) {
10227 .pointee_type = first_field.ty,10403 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);
10228 .@"addrspace" = .generic,10404 const capture_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
10229 .mutable = operand_ptr_ty.ptrIsMutable(mod),10405 .pointee_type = capture_ty,
10230 });10406 .@"addrspace" = operand_ptr_info.@"addrspace",
10407 .mutable = operand_ptr_info.mutable,
10408 .@"volatile" = operand_ptr_info.@"volatile",
10409 // TODO: alignment!
10410 });
1023110411
10232 if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| {10412 // By-ref captures of hetereogeneous types are only allowed if each field
10233 return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{10413 // pointer type is in-memory coercible to the capture pointer type.
10234 .ty = field_ty_ptr.toIntern(),10414 if (!same_types) {
10235 .addr = .{ .field = .{10415 for (field_tys, 0..) |field_ty, i| {
10236 .base = op_ptr_val.toIntern(),10416 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
10237 .index = first_field_index,10417 .pointee_type = field_ty,
10238 } },10418 .@"addrspace" = operand_ptr_info.@"addrspace",
10239 } })).toValue());10419 .mutable = operand_ptr_info.mutable,
10420 .@"volatile" = operand_ptr_info.@"volatile",
10421 // TODO: alignment!
10422 });
10423 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ptr_ty, field_ptr_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
10424 const multi_idx = raw_capture_src.multi_capture;
10425 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
10426 const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
10427 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } };
10428 const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
10429 const msg = msg: {
10430 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
10431 errdefer msg.destroy(sema.gpa);
10432 try sema.errNote(block, case_src, msg, "pointer type child '{}' cannot cast into resolved pointer type child '{}'", .{
10433 field_ty.fmt(sema.mod),
10434 capture_ty.fmt(sema.mod),
10435 });
10436 try sema.errNote(block, capture_src, msg, "this coercion is only possible when capturing by value", .{});
10437 break :msg msg;
10438 };
10439 return sema.failWithOwnedErrorMsg(msg);
10440 }
10441 }
10442 }
10443
10444 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {
10445 if (op_ptr_val.isUndef(mod)) return sema.addConstUndef(capture_ptr_ty);
10446 return sema.addConstant(
10447 capture_ptr_ty,
10448 (try mod.intern(.{ .ptr = .{
10449 .ty = capture_ptr_ty.toIntern(),
10450 .addr = .{ .field = .{
10451 .base = op_ptr_val.toIntern(),
10452 .index = first_field_index,
10453 } },
10454 } })).toValue(),
10455 );
10456 }
10457
10458 try sema.requireRuntimeBlock(block, operand_src, null);
10459 return block.addStructFieldPtr(spa.operand_ptr, first_field_index, capture_ptr_ty);
10460 }
10461
10462 if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {
10463 if (operand_val.isUndef(mod)) return sema.addConstUndef(capture_ty);
10464 const union_val = mod.intern_pool.indexToKey(operand_val.toIntern()).un;
10465 if (union_val.tag.toValue().isUndef(mod)) return sema.addConstUndef(capture_ty);
10466 const active_field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(union_val.tag.toValue(), sema.mod).?);
10467 const field_ty = union_obj.fields.values()[active_field_idx].ty;
10468 const uncoerced = try sema.addConstant(field_ty, union_val.val.toValue());
10469 return sema.coerce(block, capture_ty, uncoerced, operand_src);
10240 }10470 }
10471
10241 try sema.requireRuntimeBlock(block, operand_src, null);10472 try sema.requireRuntimeBlock(block, operand_src, null);
10242 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
10243 }
1024410473
10245 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {10474 if (same_types) {
10246 return sema.addConstant(10475 return block.addStructFieldVal(spa.operand, first_field_index, capture_ty);
10247 first_field.ty,
10248 mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(),
10249 );
10250 }
10251 try sema.requireRuntimeBlock(block, operand_src, null);
10252 return block.addStructFieldVal(operand, first_field_index, first_field.ty);
10253 },
10254 .ErrorSet => {
10255 if (is_multi) {
10256 var names: Module.Fn.InferredErrorSet.NameMap = .{};
10257 try names.ensureUnusedCapacity(sema.arena, items.len);
10258 for (items) |item| {
10259 const item_ref = try sema.resolveInst(item);
10260 // Previous switch validation ensured this will succeed
10261 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable;
10262 names.putAssumeCapacityNoClobber(item_val.getErrorName(mod).unwrap().?, {});
10263 }10476 }
10264 const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys());
1026510477
10266 return sema.bitCast(block, else_error_ty, operand, operand_src, null);10478 // We may have to emit a switch block which coerces the operand to the capture type.
10267 } else {10479 // If we can, try to avoid that using in-memory coercions.
10268 const item_ref = try sema.resolveInst(items[0]);10480 const first_non_imc = in_mem: {
10269 // Previous switch validation ensured this will succeed10481 for (field_tys, 0..) |field_ty, i| {
10270 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable;10482 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
10483 break :in_mem i;
10484 }
10485 }
10486 // All fields are in-memory coercible to the resolved type!
10487 // Just take the first field and bitcast the result.
10488 const uncoerced = try block.addStructFieldVal(spa.operand, first_field_index, first_field.ty);
10489 return block.addBitCast(capture_ty, uncoerced);
10490 };
1027110491
10272 const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);10492 // By-val capture with heterogeneous types which are not all in-memory coercible to
10273 return sema.bitCast(block, item_ty, operand, operand_src, null);10493 // the resolved capture type. We finally have to fall back to the ugly method.
10274 }
10275 },
10276 else => {
10277 // In this case the capture value is just the passed-through value of the
10278 // switch condition.
10279 if (is_ref) {
10280 return operand_ptr;
10281 } else {
10282 return operand;
10283 }
10284 },
10285 }
10286}
1028710494
10288fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10495 // However, let's first track which operands are in-memory coercible. There may well
10289 const mod = sema.mod;10496 // be several, and we can squash all of these cases into the same switch prong using
10290 const zir_datas = sema.code.instructions.items(.data);10497 // a simple bitcast. We'll make this the 'else' prong.
10291 const inst_data = zir_datas[inst].un_tok;
10292 const src = inst_data.src();
1029310498
10294 const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?];10499 var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len);
10295 const is_ref = switch_tag == .switch_cond_ref;10500 in_mem_coercible.unset(first_non_imc);
10296 const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node;10501 {
10297 const operand_ptr = try sema.resolveInst(cond_data.operand);10502 const next = first_non_imc + 1;
10298 const operand_ptr_ty = sema.typeOf(operand_ptr);10503 for (field_tys[next..], next..) |field_ty, i| {
10299 const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;10504 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
10505 in_mem_coercible.unset(i);
10506 }
10507 }
10508 }
1030010509
10301 if (operand_ty.zigTypeTag(mod) != .Union) {10510 const capture_block_inst = try block.addInstAsIndex(.{
10302 const msg = msg: {10511 .tag = .block,
10303 const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{10512 .data = .{
10304 operand_ty.fmt(mod),10513 .ty_pl = .{
10305 });10514 .ty = try sema.addType(capture_ty),
10306 errdefer msg.destroy(sema.gpa);10515 .payload = undefined, // updated below
10307 try sema.addDeclaredHereNote(msg, operand_ty);10516 },
10308 break :msg msg;10517 },
10309 };10518 });
10310 return sema.failWithOwnedErrorMsg(msg);
10311 }
1031210519
10313 return block.inline_case_capture;10520 const prong_count = field_tys.len - in_mem_coercible.count();
10314}10521
10522 const estimated_extra = prong_count * 6; // 2 for Case, 1 item, probably 3 insts
10523 var cases_extra = try std.ArrayList(u32).initCapacity(sema.gpa, estimated_extra);
10524 defer cases_extra.deinit();
10525
10526 {
10527 // Non-bitcast cases
10528 var it = in_mem_coercible.iterator(.{ .kind = .unset });
10529 while (it.next()) |idx| {
10530 var coerce_block = block.makeSubBlock();
10531 defer coerce_block.instructions.deinit(sema.gpa);
10532
10533 const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, idx), field_tys[idx]);
10534 const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) {
10535 error.NeededSourceLocation => {
10536 const multi_idx = raw_capture_src.multi_capture;
10537 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
10538 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, idx) } };
10539 const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
10540 _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src);
10541 unreachable;
10542 },
10543 else => |e| return e,
10544 };
10545 _ = try coerce_block.addBr(capture_block_inst, coerced);
10546
10547 try cases_extra.ensureUnusedCapacity(3 + coerce_block.instructions.items.len);
10548 cases_extra.appendAssumeCapacity(1); // items_len
10549 cases_extra.appendAssumeCapacity(@intCast(u32, coerce_block.instructions.items.len)); // body_len
10550 cases_extra.appendAssumeCapacity(@enumToInt(case_vals[idx])); // item
10551 cases_extra.appendSliceAssumeCapacity(coerce_block.instructions.items); // body
10552 }
10553 }
10554 const else_body_len = len: {
10555 // 'else' prong uses a bitcast
10556 var coerce_block = block.makeSubBlock();
10557 defer coerce_block.instructions.deinit(sema.gpa);
10558
10559 const first_imc = in_mem_coercible.findFirstSet().?;
10560 const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, first_imc), field_tys[first_imc]);
10561 const coerced = try coerce_block.addBitCast(capture_ty, uncoerced);
10562 _ = try coerce_block.addBr(capture_block_inst, coerced);
10563
10564 try cases_extra.appendSlice(coerce_block.instructions.items);
10565 break :len coerce_block.instructions.items.len;
10566 };
10567
10568 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.SwitchBr).Struct.fields.len +
10569 cases_extra.items.len +
10570 @typeInfo(Air.Block).Struct.fields.len +
10571 1);
10572
10573 const switch_br_inst = @intCast(u32, sema.air_instructions.len);
10574 try sema.air_instructions.append(sema.gpa, .{
10575 .tag = .switch_br,
10576 .data = .{ .pl_op = .{
10577 .operand = spa.cond,
10578 .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{
10579 .cases_len = @intCast(u32, prong_count),
10580 .else_body_len = @intCast(u32, else_body_len),
10581 }),
10582 } },
10583 });
10584 sema.air_extra.appendSliceAssumeCapacity(cases_extra.items);
10585
10586 // Set up block body
10587 sema.air_instructions.items(.data)[capture_block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{
10588 .body_len = 1,
10589 });
10590 sema.air_extra.appendAssumeCapacity(switch_br_inst);
10591
10592 return Air.indexToRef(capture_block_inst);
10593 },
10594 .ErrorSet => {
10595 if (capture_byref) {
10596 const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
10597 return sema.fail(
10598 block,
10599 capture_src,
10600 "error set cannot be captured by reference",
10601 .{},
10602 );
10603 }
10604
10605 if (case_vals.len == 1) {
10606 const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
10607 const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);
10608 return sema.bitCast(block, item_ty, spa.operand, operand_src, null);
10609 }
10610
10611 var names: Module.Fn.InferredErrorSet.NameMap = .{};
10612 try names.ensureUnusedCapacity(sema.arena, case_vals.len);
10613 for (case_vals) |err| {
10614 const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable;
10615 names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {});
10616 }
10617 const error_ty = try mod.errorSetFromUnsortedNames(names.keys());
10618 return sema.bitCast(block, error_ty, spa.operand, operand_src, null);
10619 },
10620 else => {
10621 // In this case the capture value is just the passed-through value
10622 // of the switch condition.
10623 if (capture_byref) {
10624 return spa.operand_ptr;
10625 } else {
10626 return spa.operand;
10627 }
10628 },
10629 }
10630 }
10631};
1031510632
10316fn zirSwitchCond(10633fn switchCond(
10317 sema: *Sema,10634 sema: *Sema,
10318 block: *Block,10635 block: *Block,
10319 inst: Zir.Inst.Index,10636 src: LazySrcLoc,
10320 is_ref: bool,10637 operand: Air.Inst.Ref,
10321) CompileError!Air.Inst.Ref {10638) CompileError!Air.Inst.Ref {
10322 const mod = sema.mod;10639 const mod = sema.mod;
10323 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
10324 const src = inst_data.src();
10325 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
10326 const operand_ptr = try sema.resolveInst(inst_data.operand);
10327 const operand = if (is_ref)
10328 try sema.analyzeLoad(block, src, operand_ptr, operand_src)
10329 else
10330 operand_ptr;
10331 const operand_ty = sema.typeOf(operand);10640 const operand_ty = sema.typeOf(operand);
10332
10333 switch (operand_ty.zigTypeTag(mod)) {10641 switch (operand_ty.zigTypeTag(mod)) {
10334 .Type,10642 .Type,
10335 .Void,10643 .Void,
...@@ -10386,7 +10694,7 @@ fn zirSwitchCond(...@@ -10386,7 +10694,7 @@ fn zirSwitchCond(
1038610694
10387const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);10695const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);
1038810696
10389fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10697fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
10390 const tracy = trace(@src());10698 const tracy = trace(@src());
10391 defer tracy.end();10699 defer tracy.end();
1039210700
...@@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10400 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };10708 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
10401 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);10709 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
1040210710
10403 const operand = try sema.resolveInst(extra.data.operand);10711 const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
10404 // AstGen guarantees that the instruction immediately following10712 const maybe_ptr = try sema.resolveInst(extra.data.operand);
10405 // switch_cond(_ref) is a dbg_stmt10713 if (operand_is_ref) {
10406 const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;10714 const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src);
10715 break :blk .{ .val = val, .ptr = maybe_ptr };
10716 } else {
10717 break :blk .{ .val = maybe_ptr, .ptr = undefined };
10718 }
10719 };
10720
10721 const operand = try sema.switchCond(block, operand_src, raw_operand.val);
10722
10723 // AstGen guarantees that the instruction immediately preceding
10724 // switch_block(_ref) is a dbg_stmt
10725 const cond_dbg_node_index = inst - 1;
1040710726
10408 var header_extra_index: usize = extra.end;10727 var header_extra_index: usize = extra.end;
1040910728
...@@ -10414,28 +10733,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10414,28 +10733,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10414 break :blk multi_cases_len;10733 break :blk multi_cases_len;
10415 } else 0;10734 } else 0;
1041610735
10736 const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
10737 const tag_capture_inst = sema.code.extra[header_extra_index];
10738 header_extra_index += 1;
10739 // SwitchProngAnalysis wants inst_map to have space for the tag capture.
10740 // Note that the normal capture is referred to via the switch block
10741 // index, which there is already necessarily space for.
10742 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});
10743 break :blk tag_capture_inst;
10744 } else undefined;
10745
10746 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
10747 defer case_vals.deinit(gpa);
10748
10749 const Special = struct {
10750 body: []const Zir.Inst.Index,
10751 end: usize,
10752 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10753 is_inline: bool,
10754 has_tag_capture: bool,
10755 };
10756
10417 const special_prong = extra.data.bits.specialProng();10757 const special_prong = extra.data.bits.specialProng();
10418 const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) {10758 const special: Special = switch (special_prong) {
10419 .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false },10759 .none => .{
10760 .body = &.{},
10761 .end = header_extra_index,
10762 .capture = .none,
10763 .is_inline = false,
10764 .has_tag_capture = false,
10765 },
10420 .under, .@"else" => blk: {10766 .under, .@"else" => blk: {
10421 const body_len = @truncate(u31, sema.code.extra[header_extra_index]);10767 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]);
10422 const extra_body_start = header_extra_index + 1;10768 const extra_body_start = header_extra_index + 1;
10423 break :blk .{10769 break :blk .{
10424 .body = sema.code.extra[extra_body_start..][0..body_len],10770 .body = sema.code.extra[extra_body_start..][0..info.body_len],
10425 .end = extra_body_start + body_len,10771 .end = extra_body_start + info.body_len,
10426 .is_inline = sema.code.extra[header_extra_index] >> 31 != 0,10772 .capture = info.capture,
10773 .is_inline = info.is_inline,
10774 .has_tag_capture = info.has_tag_capture,
10427 };10775 };
10428 },10776 },
10429 };10777 };
1043010778
10431 const maybe_union_ty = blk: {10779 const maybe_union_ty = sema.typeOf(raw_operand.val);
10432 const zir_tags = sema.code.instructions.items(.tag);
10433 const zir_data = sema.code.instructions.items(.data);
10434 const cond_index = Zir.refToIndex(extra.data.operand).?;
10435 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
10436 const target_ty = sema.typeOf(raw_operand);
10437 break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty;
10438 };
10439 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;10780 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
1044010781
10441 // Duplicate checking variables later also used for `inline else`.10782 // Duplicate checking variables later also used for `inline else`.
...@@ -10495,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10495,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10495 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {10836 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
10496 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);10837 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10497 extra_index += 1;10838 extra_index += 1;
10498 const body_len = @truncate(u31, sema.code.extra[extra_index]);10839 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10499 extra_index += 1;10840 extra_index += 1 + info.body_len;
10500 extra_index += body_len;
1050110841
10502 try sema.validateSwitchItemEnum(10842 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
10503 block,10843 block,
10504 seen_enum_fields,10844 seen_enum_fields,
10505 &range_set,10845 &range_set,
10506 item_ref,10846 item_ref,
10847 operand_ty,
10507 src_node_offset,10848 src_node_offset,
10508 .{ .scalar = scalar_i },10849 .{ .scalar = scalar_i },
10509 );10850 ));
10510 }10851 }
10511 }10852 }
10512 {10853 {
...@@ -10516,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10516,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10516 extra_index += 1;10857 extra_index += 1;
10517 const ranges_len = sema.code.extra[extra_index];10858 const ranges_len = sema.code.extra[extra_index];
10518 extra_index += 1;10859 extra_index += 1;
10519 const body_len = @truncate(u31, sema.code.extra[extra_index]);10860 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10520 extra_index += 1;10861 extra_index += 1;
10521 const items = sema.code.refSlice(extra_index, items_len);10862 const items = sema.code.refSlice(extra_index, items_len);
10522 extra_index += items_len + body_len;10863 extra_index += items_len + info.body_len;
1052310864
10865 try case_vals.ensureUnusedCapacity(gpa, items.len);
10524 for (items, 0..) |item_ref, item_i| {10866 for (items, 0..) |item_ref, item_i| {
10525 try sema.validateSwitchItemEnum(10867 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
10526 block,10868 block,
10527 seen_enum_fields,10869 seen_enum_fields,
10528 &range_set,10870 &range_set,
10529 item_ref,10871 item_ref,
10872 operand_ty,
10530 src_node_offset,10873 src_node_offset,
10531 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },10874 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10532 );10875 ));
10533 }10876 }
1053410877
10535 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);10878 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
...@@ -10592,17 +10935,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10592,17 +10935,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10592 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {10935 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
10593 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);10936 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10594 extra_index += 1;10937 extra_index += 1;
10595 const body_len = @truncate(u31, sema.code.extra[extra_index]);10938 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10596 extra_index += 1;10939 extra_index += 1 + info.body_len;
10597 extra_index += body_len;
1059810940
10599 try sema.validateSwitchItemError(10941 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
10600 block,10942 block,
10601 &seen_errors,10943 &seen_errors,
10602 item_ref,10944 item_ref,
10945 operand_ty,
10603 src_node_offset,10946 src_node_offset,
10604 .{ .scalar = scalar_i },10947 .{ .scalar = scalar_i },
10605 );10948 ));
10606 }10949 }
10607 }10950 }
10608 {10951 {
...@@ -10612,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10612,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10612 extra_index += 1;10955 extra_index += 1;
10613 const ranges_len = sema.code.extra[extra_index];10956 const ranges_len = sema.code.extra[extra_index];
10614 extra_index += 1;10957 extra_index += 1;
10615 const body_len = @truncate(u31, sema.code.extra[extra_index]);10958 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10616 extra_index += 1;10959 extra_index += 1;
10617 const items = sema.code.refSlice(extra_index, items_len);10960 const items = sema.code.refSlice(extra_index, items_len);
10618 extra_index += items_len + body_len;10961 extra_index += items_len + info.body_len;
1061910962
10963 try case_vals.ensureUnusedCapacity(gpa, items.len);
10620 for (items, 0..) |item_ref, item_i| {10964 for (items, 0..) |item_ref, item_i| {
10621 try sema.validateSwitchItemError(10965 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
10622 block,10966 block,
10623 &seen_errors,10967 &seen_errors,
10624 item_ref,10968 item_ref,
10969 operand_ty,
10625 src_node_offset,10970 src_node_offset,
10626 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },10971 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10627 );10972 ));
10628 }10973 }
1062910974
10630 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);10975 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
...@@ -10687,7 +11032,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10687,7 +11032,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10687 .dbg_block_end,11032 .dbg_block_end,
10688 .dbg_stmt,11033 .dbg_stmt,
10689 .dbg_var_val,11034 .dbg_var_val,
10690 .switch_capture,
10691 .ret_type,11035 .ret_type,
10692 .as_node,11036 .as_node,
10693 .ret_node,11037 .ret_node,
...@@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10732 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {11076 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
10733 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11077 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10734 extra_index += 1;11078 extra_index += 1;
10735 const body_len = @truncate(u31, sema.code.extra[extra_index]);11079 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10736 extra_index += 1;11080 extra_index += 1 + info.body_len;
10737 extra_index += body_len;
1073811081
10739 try sema.validateSwitchItem(11082 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
10740 block,11083 block,
10741 &range_set,11084 &range_set,
10742 item_ref,11085 item_ref,
11086 operand_ty,
10743 src_node_offset,11087 src_node_offset,
10744 .{ .scalar = scalar_i },11088 .{ .scalar = scalar_i },
10745 );11089 ));
10746 }11090 }
10747 }11091 }
10748 {11092 {
...@@ -10752,21 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10752,21 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10752 extra_index += 1;11096 extra_index += 1;
10753 const ranges_len = sema.code.extra[extra_index];11097 const ranges_len = sema.code.extra[extra_index];
10754 extra_index += 1;11098 extra_index += 1;
10755 const body_len = @truncate(u31, sema.code.extra[extra_index]);11099 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10756 extra_index += 1;11100 extra_index += 1;
10757 const items = sema.code.refSlice(extra_index, items_len);11101 const items = sema.code.refSlice(extra_index, items_len);
10758 extra_index += items_len;11102 extra_index += items_len;
1075911103
11104 try case_vals.ensureUnusedCapacity(gpa, items.len);
10760 for (items, 0..) |item_ref, item_i| {11105 for (items, 0..) |item_ref, item_i| {
10761 try sema.validateSwitchItem(11106 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
10762 block,11107 block,
10763 &range_set,11108 &range_set,
10764 item_ref,11109 item_ref,
11110 operand_ty,
10765 src_node_offset,11111 src_node_offset,
10766 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },11112 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10767 );11113 ));
10768 }11114 }
1076911115
11116 try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len);
10770 var range_i: u32 = 0;11117 var range_i: u32 = 0;
10771 while (range_i < ranges_len) : (range_i += 1) {11118 while (range_i < ranges_len) : (range_i += 1) {
10772 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11119 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
...@@ -10774,17 +11121,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10774,17 +11121,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10774 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11121 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10775 extra_index += 1;11122 extra_index += 1;
1077611123
10777 try sema.validateSwitchRange(11124 const vals = try sema.validateSwitchRange(
10778 block,11125 block,
10779 &range_set,11126 &range_set,
10780 item_first,11127 item_first,
10781 item_last,11128 item_last,
11129 operand_ty,
10782 src_node_offset,11130 src_node_offset,
10783 .{ .range = .{ .prong = multi_i, .item = range_i } },11131 .{ .range = .{ .prong = multi_i, .item = range_i } },
10784 );11132 );
11133 case_vals.appendAssumeCapacity(vals[0]);
11134 case_vals.appendAssumeCapacity(vals[1]);
10785 }11135 }
1078611136
10787 extra_index += body_len;11137 extra_index += info.body_len;
10788 }11138 }
10789 }11139 }
1079011140
...@@ -10821,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10821,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10821 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {11171 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
10822 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11172 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10823 extra_index += 1;11173 extra_index += 1;
10824 const body_len = @truncate(u31, sema.code.extra[extra_index]);11174 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10825 extra_index += 1;11175 extra_index += 1 + info.body_len;
10826 extra_index += body_len;
1082711176
10828 try sema.validateSwitchItemBool(11177 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
10829 block,11178 block,
10830 &true_count,11179 &true_count,
10831 &false_count,11180 &false_count,
10832 item_ref,11181 item_ref,
10833 src_node_offset,11182 src_node_offset,
10834 .{ .scalar = scalar_i },11183 .{ .scalar = scalar_i },
10835 );11184 ));
10836 }11185 }
10837 }11186 }
10838 {11187 {
...@@ -10842,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10842,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10842 extra_index += 1;11191 extra_index += 1;
10843 const ranges_len = sema.code.extra[extra_index];11192 const ranges_len = sema.code.extra[extra_index];
10844 extra_index += 1;11193 extra_index += 1;
10845 const body_len = @truncate(u31, sema.code.extra[extra_index]);11194 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10846 extra_index += 1;11195 extra_index += 1;
10847 const items = sema.code.refSlice(extra_index, items_len);11196 const items = sema.code.refSlice(extra_index, items_len);
10848 extra_index += items_len + body_len;11197 extra_index += items_len + info.body_len;
1084911198
11199 try case_vals.ensureUnusedCapacity(gpa, items.len);
10850 for (items, 0..) |item_ref, item_i| {11200 for (items, 0..) |item_ref, item_i| {
10851 try sema.validateSwitchItemBool(11201 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
10852 block,11202 block,
10853 &true_count,11203 &true_count,
10854 &false_count,11204 &false_count,
10855 item_ref,11205 item_ref,
10856 src_node_offset,11206 src_node_offset,
10857 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },11207 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10858 );11208 ));
10859 }11209 }
1086011210
10861 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);11211 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
...@@ -10903,17 +11253,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10903,17 +11253,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10903 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {11253 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
10904 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11254 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
10905 extra_index += 1;11255 extra_index += 1;
10906 const body_len = @truncate(u31, sema.code.extra[extra_index]);11256 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10907 extra_index += 1;11257 extra_index += 1;
10908 extra_index += body_len;11258 extra_index += info.body_len;
1090911259
10910 try sema.validateSwitchItemSparse(11260 case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
10911 block,11261 block,
10912 &seen_values,11262 &seen_values,
10913 item_ref,11263 item_ref,
11264 operand_ty,
10914 src_node_offset,11265 src_node_offset,
10915 .{ .scalar = scalar_i },11266 .{ .scalar = scalar_i },
10916 );11267 ));
10917 }11268 }
10918 }11269 }
10919 {11270 {
...@@ -10923,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10923,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10923 extra_index += 1;11274 extra_index += 1;
10924 const ranges_len = sema.code.extra[extra_index];11275 const ranges_len = sema.code.extra[extra_index];
10925 extra_index += 1;11276 extra_index += 1;
10926 const body_len = @truncate(u31, sema.code.extra[extra_index]);11277 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10927 extra_index += 1;11278 extra_index += 1;
10928 const items = sema.code.refSlice(extra_index, items_len);11279 const items = sema.code.refSlice(extra_index, items_len);
10929 extra_index += items_len + body_len;11280 extra_index += items_len + info.body_len;
1093011281
11282 try case_vals.ensureUnusedCapacity(gpa, items.len);
10931 for (items, 0..) |item_ref, item_i| {11283 for (items, 0..) |item_ref, item_i| {
10932 try sema.validateSwitchItemSparse(11284 case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
10933 block,11285 block,
10934 &seen_values,11286 &seen_values,
10935 item_ref,11287 item_ref,
11288 operand_ty,
10936 src_node_offset,11289 src_node_offset,
10937 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },11290 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10938 );11291 ));
10939 }11292 }
1094011293
10941 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);11294 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
...@@ -10961,6 +11314,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10961,6 +11314,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10961 }),11314 }),
10962 }11315 }
1096311316
11317 const spa: SwitchProngAnalysis = .{
11318 .sema = sema,
11319 .parent_block = block,
11320 .operand = raw_operand.val,
11321 .operand_ptr = raw_operand.ptr,
11322 .cond = operand,
11323 .else_error_ty = else_error_ty,
11324 .switch_block_inst = inst,
11325 .tag_capture_inst = tag_capture_inst,
11326 };
11327
10964 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);11328 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
10965 try sema.air_instructions.append(gpa, .{11329 try sema.air_instructions.append(gpa, .{
10966 .tag = .block,11330 .tag = .block,
...@@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10988 .is_comptime = block.is_comptime,11352 .is_comptime = block.is_comptime,
10989 .comptime_reason = block.comptime_reason,11353 .comptime_reason = block.comptime_reason,
10990 .is_typeof = block.is_typeof,11354 .is_typeof = block.is_typeof,
10991 .switch_else_err_ty = else_error_ty,
10992 .c_import_buf = block.c_import_buf,11355 .c_import_buf = block.c_import_buf,
10993 .runtime_cond = block.runtime_cond,11356 .runtime_cond = block.runtime_cond,
10994 .runtime_loop = block.runtime_loop,11357 .runtime_loop = block.runtime_loop,
...@@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11005 {11368 {
11006 var scalar_i: usize = 0;11369 var scalar_i: usize = 0;
11007 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {11370 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11008 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11009 extra_index += 1;11371 extra_index += 1;
11010 const body_len = @truncate(u31, sema.code.extra[extra_index]);11372 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11011 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11012 extra_index += 1;11373 extra_index += 1;
11013 const body = sema.code.extra[extra_index..][0..body_len];11374 const body = sema.code.extra[extra_index..][0..info.body_len];
11014 extra_index += body_len;11375 extra_index += info.body_len;
11015
11016 const item = try sema.resolveInst(item_ref);
11017 // Validation above ensured these will succeed.
11018 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
11019 if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
11020 if (is_inline) child_block.inline_case_capture = operand;
1102111376
11377 const item = case_vals.items[scalar_i];
11378 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
11379 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11022 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11380 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11023 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);11381 return spa.resolveProngComptime(
11382 &child_block,
11383 .normal,
11384 body,
11385 info.capture,
11386 .{ .scalar_capture = @intCast(u32, scalar_i) },
11387 &.{item},
11388 if (info.is_inline) operand else .none,
11389 info.has_tag_capture,
11390 merges,
11391 );
11024 }11392 }
11025 }11393 }
11026 }11394 }
11027 {11395 {
11028 var multi_i: usize = 0;11396 var multi_i: usize = 0;
11397 var case_val_idx: usize = scalar_cases_len;
11029 while (multi_i < multi_cases_len) : (multi_i += 1) {11398 while (multi_i < multi_cases_len) : (multi_i += 1) {
11030 const items_len = sema.code.extra[extra_index];11399 const items_len = sema.code.extra[extra_index];
11031 extra_index += 1;11400 extra_index += 1;
11032 const ranges_len = sema.code.extra[extra_index];11401 const ranges_len = sema.code.extra[extra_index];
11033 extra_index += 1;11402 extra_index += 1;
11034 const body_len = @truncate(u31, sema.code.extra[extra_index]);11403 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11035 const is_inline = sema.code.extra[extra_index] >> 31 != 0;11404 extra_index += 1 + items_len;
11036 extra_index += 1;11405 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len];
11037 const items = sema.code.refSlice(extra_index, items_len);
11038 extra_index += items_len;
11039 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
1104011406
11041 for (items) |item_ref| {11407 const items = case_vals.items[case_val_idx..][0..items_len];
11042 const item = try sema.resolveInst(item_ref);11408 case_val_idx += items_len;
11043 // Validation above ensured these will succeed.
11044 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
11045 if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
11046 if (is_inline) child_block.inline_case_capture = operand;
1104711409
11410 for (items) |item| {
11411 // Validation above ensured these will succeed.
11412 const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
11413 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
11048 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11414 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11049 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);11415 return spa.resolveProngComptime(
11416 &child_block,
11417 .normal,
11418 body,
11419 info.capture,
11420 .{ .multi_capture = @intCast(u32, multi_i) },
11421 items,
11422 if (info.is_inline) operand else .none,
11423 info.has_tag_capture,
11424 merges,
11425 );
11050 }11426 }
11051 }11427 }
1105211428
11053 var range_i: usize = 0;11429 var range_i: usize = 0;
11054 while (range_i < ranges_len) : (range_i += 1) {11430 while (range_i < ranges_len) : (range_i += 1) {
11055 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11431 const range_items = case_vals.items[case_val_idx..][0..2];
11056 extra_index += 1;11432 extra_index += 2;
11057 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11433 case_val_idx += 2;
11058 extra_index += 1;
1105911434
11060 // Validation above ensured these will succeed.11435 // Validation above ensured these will succeed.
11061 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;11436 const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable;
11062 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;11437 const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable;
11063 if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and11438 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
11064 (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty)))11439 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
11065 {11440 {
11066 if (is_inline) child_block.inline_case_capture = operand;
11067 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);11441 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
11068 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);11442 return spa.resolveProngComptime(
11443 &child_block,
11444 .normal,
11445 body,
11446 info.capture,
11447 .{ .multi_capture = @intCast(u32, multi_i) },
11448 undefined, // case_vals may be undefined for ranges
11449 if (info.is_inline) operand else .none,
11450 info.has_tag_capture,
11451 merges,
11452 );
11069 }11453 }
11070 }11454 }
1107111455
11072 extra_index += body_len;11456 extra_index += info.body_len;
11073 }11457 }
11074 }11458 }
11075 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);11459 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
11076 if (special.is_inline) child_block.inline_case_capture = operand;
11077 if (empty_enum) {11460 if (empty_enum) {
11078 return Air.Inst.Ref.void_value;11461 return Air.Inst.Ref.void_value;
11079 }11462 }
11080 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);11463
11464 return spa.resolveProngComptime(
11465 &child_block,
11466 .special,
11467 special.body,
11468 special.capture,
11469 .special_capture,
11470 undefined, // case_vals may be undefined for special prongs
11471 if (special.is_inline) operand else .none,
11472 special.has_tag_capture,
11473 merges,
11474 );
11081 }11475 }
1108211476
11083 if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {11477 if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {
...@@ -11097,7 +11491,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11097,7 +11491,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11097 const ok = try block.addUnOp(.is_named_enum_value, operand);11491 const ok = try block.addUnOp(.is_named_enum_value, operand);
11098 try sema.addSafetyCheck(block, ok, .corrupt_switch);11492 try sema.addSafetyCheck(block, ok, .corrupt_switch);
11099 }11493 }
11100 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);11494
11495 return spa.resolveProngComptime(
11496 &child_block,
11497 .special,
11498 special.body,
11499 special.capture,
11500 .special_capture,
11501 undefined, // case_vals may be undefined for special prongs
11502 .none,
11503 false,
11504 merges,
11505 );
11101 }11506 }
1110211507
11103 if (child_block.is_comptime) {11508 if (child_block.is_comptime) {
...@@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1112311528
11124 var scalar_i: usize = 0;11529 var scalar_i: usize = 0;
11125 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {11530 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11126 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11127 extra_index += 1;11531 extra_index += 1;
11128 const body_len = @truncate(u31, sema.code.extra[extra_index]);11532 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11129 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11130 extra_index += 1;11533 extra_index += 1;
11131 const body = sema.code.extra[extra_index..][0..body_len];11534 const body = sema.code.extra[extra_index..][0..info.body_len];
11132 extra_index += body_len;11535 extra_index += info.body_len;
1113311536
11134 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);11537 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
11135 defer wip_captures.deinit();11538 defer wip_captures.deinit();
1113611539
11137 case_block.instructions.shrinkRetainingCapacity(0);11540 case_block.instructions.shrinkRetainingCapacity(0);
11138 case_block.wip_capture_scope = wip_captures.scope;11541 case_block.wip_capture_scope = wip_captures.scope;
11139 case_block.inline_case_capture = .none;
1114011542
11141 const item = try sema.resolveInst(item_ref);11543 const item = case_vals.items[scalar_i];
11142 if (is_inline) case_block.inline_case_capture = item;
11143 // `item` is already guaranteed to be constant known.11544 // `item` is already guaranteed to be constant known.
1114411545
11145 const analyze_body = if (union_originally) blk: {11546 const analyze_body = if (union_originally) blk: {
...@@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11151 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {11552 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
11152 // nothing to do here11553 // nothing to do here
11153 } else if (analyze_body) {11554 } else if (analyze_body) {
11154 try sema.analyzeBodyRuntimeBreak(&case_block, body);11555 try spa.analyzeProngRuntime(
11556 &case_block,
11557 .normal,
11558 body,
11559 info.capture,
11560 .{ .scalar_capture = @intCast(u32, scalar_i) },
11561 &.{item},
11562 if (info.is_inline) item else .none,
11563 info.has_tag_capture,
11564 );
11155 } else {11565 } else {
11156 _ = try case_block.addNoOp(.unreach);11566 _ = try case_block.addNoOp(.unreach);
11157 }11567 }
...@@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11173 defer gpa.free(prev_then_body);11583 defer gpa.free(prev_then_body);
1117411584
11175 var cases_len = scalar_cases_len;11585 var cases_len = scalar_cases_len;
11586 var case_val_idx: usize = scalar_cases_len;
11176 var multi_i: u32 = 0;11587 var multi_i: u32 = 0;
11177 while (multi_i < multi_cases_len) : (multi_i += 1) {11588 while (multi_i < multi_cases_len) : (multi_i += 1) {
11178 const items_len = sema.code.extra[extra_index];11589 const items_len = sema.code.extra[extra_index];
11179 extra_index += 1;11590 extra_index += 1;
11180 const ranges_len = sema.code.extra[extra_index];11591 const ranges_len = sema.code.extra[extra_index];
11181 extra_index += 1;11592 extra_index += 1;
11182 const body_len = @truncate(u31, sema.code.extra[extra_index]);11593 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11183 const is_inline = sema.code.extra[extra_index] >> 31 != 0;11594 extra_index += 1 + items_len;
11184 extra_index += 1;11595
11185 const items = sema.code.refSlice(extra_index, items_len);11596 const items = case_vals.items[case_val_idx..][0..items_len];
11186 extra_index += items_len;11597 case_val_idx += items_len;
1118711598
11188 case_block.instructions.shrinkRetainingCapacity(0);11599 case_block.instructions.shrinkRetainingCapacity(0);
11189 case_block.wip_capture_scope = child_block.wip_capture_scope;11600 case_block.wip_capture_scope = child_block.wip_capture_scope;
11190 case_block.inline_case_capture = .none;
1119111601
11192 // Generate all possible cases as scalar prongs.11602 // Generate all possible cases as scalar prongs.
11193 if (is_inline) {11603 if (info.is_inline) {
11194 const body_start = extra_index + 2 * ranges_len;11604 const body_start = extra_index + 2 * ranges_len;
11195 const body = sema.code.extra[body_start..][0..body_len];11605 const body = sema.code.extra[body_start..][0..info.body_len];
11196 var emit_bb = false;11606 var emit_bb = false;
1119711607
11198 var range_i: u32 = 0;11608 var range_i: u32 = 0;
11199 while (range_i < ranges_len) : (range_i += 1) {11609 while (range_i < ranges_len) : (range_i += 1) {
11200 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11610 const range_items = case_vals.items[case_val_idx..][0..2];
11201 extra_index += 1;11611 extra_index += 2;
11202 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11612 case_val_idx += 2;
11203 extra_index += 1;11613
11614 const item_first_ref = range_items[0];
11615 const item_last_ref = range_items[1];
1120411616
11205 const item_first_ref = try sema.resolveInst(first_ref);
11206 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;11617 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;
11207 const item_last_ref = try sema.resolveInst(last_ref);
11208 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;11618 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
1120911619
11210 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({11620 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({
...@@ -11217,7 +11627,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11217,7 +11627,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11217 cases_len += 1;11627 cases_len += 1;
1121811628
11219 const item_ref = try sema.addConstant(operand_ty, item);11629 const item_ref = try sema.addConstant(operand_ty, item);
11220 case_block.inline_case_capture = item_ref;
1122111630
11222 case_block.instructions.shrinkRetainingCapacity(0);11631 case_block.instructions.shrinkRetainingCapacity(0);
11223 case_block.wip_capture_scope = child_block.wip_capture_scope;11632 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11233,22 +11642,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11233,22 +11642,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11233 };11642 };
11234 emit_bb = true;11643 emit_bb = true;
1123511644
11236 try sema.analyzeBodyRuntimeBreak(&case_block, body);11645 try spa.analyzeProngRuntime(
11646 &case_block,
11647 .normal,
11648 body,
11649 info.capture,
11650 .{ .multi_capture = multi_i },
11651 undefined, // case_vals may be undefined for ranges
11652 item_ref,
11653 info.has_tag_capture,
11654 );
1123711655
11238 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11656 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11239 cases_extra.appendAssumeCapacity(1); // items_len11657 cases_extra.appendAssumeCapacity(1); // items_len
11240 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11658 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11241 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11659 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11242 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11660 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11243 }11661 }
11244 }11662 }
1124511663
11246 for (items, 0..) |item_ref, item_i| {11664 for (items, 0..) |item, item_i| {
11247 cases_len += 1;11665 cases_len += 1;
1124811666
11249 const item = try sema.resolveInst(item_ref);
11250 case_block.inline_case_capture = item;
11251
11252 case_block.instructions.shrinkRetainingCapacity(0);11667 case_block.instructions.shrinkRetainingCapacity(0);
11253 case_block.wip_capture_scope = child_block.wip_capture_scope;11668 case_block.wip_capture_scope = child_block.wip_capture_scope;
1125411669
...@@ -11270,7 +11685,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11270,7 +11685,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11270 emit_bb = true;11685 emit_bb = true;
1127111686
11272 if (analyze_body) {11687 if (analyze_body) {
11273 try sema.analyzeBodyRuntimeBreak(&case_block, body);11688 try spa.analyzeProngRuntime(
11689 &case_block,
11690 .normal,
11691 body,
11692 info.capture,
11693 .{ .multi_capture = multi_i },
11694 &.{item},
11695 item,
11696 info.has_tag_capture,
11697 );
11274 } else {11698 } else {
11275 _ = try case_block.addNoOp(.unreach);11699 _ = try case_block.addNoOp(.unreach);
11276 }11700 }
...@@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11278 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11702 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11279 cases_extra.appendAssumeCapacity(1); // items_len11703 cases_extra.appendAssumeCapacity(1); // items_len
11280 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11704 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11281 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11705 cases_extra.appendAssumeCapacity(@enumToInt(item));
11282 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11706 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11283 }11707 }
1128411708
11285 extra_index += body_len;11709 extra_index += info.body_len;
11286 continue;11710 continue;
11287 }11711 }
1128811712
...@@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11295 cases_len += 1;11719 cases_len += 1;
1129611720
11297 const analyze_body = if (union_originally)11721 const analyze_body = if (union_originally)
11298 for (items) |item_ref| {11722 for (items) |item| {
11299 const item = try sema.resolveInst(item_ref);
11300 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;11723 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
11301 const field_ty = maybe_union_ty.unionFieldType(item_val, mod);11724 const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
11302 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;11725 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
...@@ -11304,12 +11727,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11304,12 +11727,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11304 else11727 else
11305 true;11728 true;
1130611729
11307 const body = sema.code.extra[extra_index..][0..body_len];11730 const body = sema.code.extra[extra_index..][0..info.body_len];
11308 extra_index += body_len;11731 extra_index += info.body_len;
11309 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {11732 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
11310 // nothing to do here11733 // nothing to do here
11311 } else if (analyze_body) {11734 } else if (analyze_body) {
11312 try sema.analyzeBodyRuntimeBreak(&case_block, body);11735 try spa.analyzeProngRuntime(
11736 &case_block,
11737 .normal,
11738 body,
11739 info.capture,
11740 .{ .multi_capture = multi_i },
11741 items,
11742 .none,
11743 false,
11744 );
11313 } else {11745 } else {
11314 _ = try case_block.addNoOp(.unreach);11746 _ = try case_block.addNoOp(.unreach);
11315 }11747 }
...@@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11320 cases_extra.appendAssumeCapacity(@intCast(u32, items.len));11752 cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
11321 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11753 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
1132211754
11323 for (items) |item_ref| {11755 for (items) |item| {
11324 const item = try sema.resolveInst(item_ref);
11325 cases_extra.appendAssumeCapacity(@enumToInt(item));11756 cases_extra.appendAssumeCapacity(@enumToInt(item));
11326 }11757 }
1132711758
11328 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11759 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11329 } else {11760 } else {
11330 for (items) |item_ref| {11761 for (items) |item| {
11331 const item = try sema.resolveInst(item_ref);
11332 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);11762 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
11333 if (any_ok != .none) {11763 if (any_ok != .none) {
11334 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);11764 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
...@@ -11339,13 +11769,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11339,13 +11769,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1133911769
11340 var range_i: usize = 0;11770 var range_i: usize = 0;
11341 while (range_i < ranges_len) : (range_i += 1) {11771 while (range_i < ranges_len) : (range_i += 1) {
11342 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11772 const range_items = case_vals.items[case_val_idx..][0..2];
11343 extra_index += 1;11773 extra_index += 2;
11344 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);11774 case_val_idx += 2;
11345 extra_index += 1;
1134611775
11347 const item_first = try sema.resolveInst(first_ref);11776 const item_first = range_items[0];
11348 const item_last = try sema.resolveInst(last_ref);11777 const item_last = range_items[1];
1134911778
11350 // operand >= first and operand <= last11779 // operand >= first and operand <= last
11351 const range_first_ok = try case_block.addBinOp(11780 const range_first_ok = try case_block.addBinOp(
...@@ -11385,12 +11814,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11385,12 +11814,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11385 case_block.instructions.shrinkRetainingCapacity(0);11814 case_block.instructions.shrinkRetainingCapacity(0);
11386 case_block.wip_capture_scope = wip_captures.scope;11815 case_block.wip_capture_scope = wip_captures.scope;
1138711816
11388 const body = sema.code.extra[extra_index..][0..body_len];11817 const body = sema.code.extra[extra_index..][0..info.body_len];
11389 extra_index += body_len;11818 extra_index += info.body_len;
11390 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {11819 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
11391 // nothing to do here11820 // nothing to do here
11392 } else {11821 } else {
11393 try sema.analyzeBodyRuntimeBreak(&case_block, body);11822 try spa.analyzeProngRuntime(
11823 &case_block,
11824 .normal,
11825 body,
11826 info.capture,
11827 .{ .multi_capture = multi_i },
11828 items,
11829 .none,
11830 false,
11831 );
11394 }11832 }
1139511833
11396 try wip_captures.finalize();11834 try wip_captures.finalize();
...@@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1143511873
11436 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));11874 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
11437 const item_ref = try sema.addConstant(operand_ty, item_val);11875 const item_ref = try sema.addConstant(operand_ty, item_val);
11438 case_block.inline_case_capture = item_ref;
1143911876
11440 case_block.instructions.shrinkRetainingCapacity(0);11877 case_block.instructions.shrinkRetainingCapacity(0);
11441 case_block.wip_capture_scope = child_block.wip_capture_scope;11878 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11449,7 +11886,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11449,7 +11886,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11449 emit_bb = true;11886 emit_bb = true;
1145011887
11451 if (analyze_body) {11888 if (analyze_body) {
11452 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);11889 try spa.analyzeProngRuntime(
11890 &case_block,
11891 .special,
11892 special.body,
11893 special.capture,
11894 .special_capture,
11895 &.{item_ref},
11896 item_ref,
11897 special.has_tag_capture,
11898 );
11453 } else {11899 } else {
11454 _ = try case_block.addNoOp(.unreach);11900 _ = try case_block.addNoOp(.unreach);
11455 }11901 }
...@@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11457 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11903 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11458 cases_extra.appendAssumeCapacity(1); // items_len11904 cases_extra.appendAssumeCapacity(1); // items_len
11459 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11905 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11460 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11906 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11461 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11907 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11462 }11908 }
11463 },11909 },
...@@ -11477,7 +11923,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11477,7 +11923,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11477 .name = error_name,11923 .name = error_name,
11478 } });11924 } });
11479 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());11925 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
11480 case_block.inline_case_capture = item_ref;
1148111926
11482 case_block.instructions.shrinkRetainingCapacity(0);11927 case_block.instructions.shrinkRetainingCapacity(0);
11483 case_block.wip_capture_scope = child_block.wip_capture_scope;11928 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11485,12 +11930,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11485,12 +11930,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11485 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);11930 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
11486 emit_bb = true;11931 emit_bb = true;
1148711932
11488 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);11933 try spa.analyzeProngRuntime(
11934 &case_block,
11935 .special,
11936 special.body,
11937 special.capture,
11938 .special_capture,
11939 &.{item_ref},
11940 item_ref,
11941 special.has_tag_capture,
11942 );
1148911943
11490 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11944 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11491 cases_extra.appendAssumeCapacity(1); // items_len11945 cases_extra.appendAssumeCapacity(1); // items_len
11492 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11946 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11493 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11947 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11494 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11948 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11495 }11949 }
11496 },11950 },
...@@ -11500,7 +11954,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11500,7 +11954,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11500 cases_len += 1;11954 cases_len += 1;
1150111955
11502 const item_ref = try sema.addConstant(operand_ty, cur.toValue());11956 const item_ref = try sema.addConstant(operand_ty, cur.toValue());
11503 case_block.inline_case_capture = item_ref;
1150411957
11505 case_block.instructions.shrinkRetainingCapacity(0);11958 case_block.instructions.shrinkRetainingCapacity(0);
11506 case_block.wip_capture_scope = child_block.wip_capture_scope;11959 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11508,19 +11961,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11508,19 +11961,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11508 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);11961 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
11509 emit_bb = true;11962 emit_bb = true;
1151011963
11511 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);11964 try spa.analyzeProngRuntime(
11965 &case_block,
11966 .special,
11967 special.body,
11968 special.capture,
11969 .special_capture,
11970 &.{item_ref},
11971 item_ref,
11972 special.has_tag_capture,
11973 );
1151211974
11513 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);11975 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11514 cases_extra.appendAssumeCapacity(1); // items_len11976 cases_extra.appendAssumeCapacity(1); // items_len
11515 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));11977 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11516 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));11978 cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
11517 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);11979 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11518 }11980 }
11519 },11981 },
11520 .Bool => {11982 .Bool => {
11521 if (true_count == 0) {11983 if (true_count == 0) {
11522 cases_len += 1;11984 cases_len += 1;
11523 case_block.inline_case_capture = Air.Inst.Ref.bool_true;
1152411985
11525 case_block.instructions.shrinkRetainingCapacity(0);11986 case_block.instructions.shrinkRetainingCapacity(0);
11526 case_block.wip_capture_scope = child_block.wip_capture_scope;11987 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11528,17 +11989,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11528,17 +11989,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11528 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);11989 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
11529 emit_bb = true;11990 emit_bb = true;
1153011991
11531 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);11992 try spa.analyzeProngRuntime(
11993 &case_block,
11994 .special,
11995 special.body,
11996 special.capture,
11997 .special_capture,
11998 &.{Air.Inst.Ref.bool_true},
11999 Air.Inst.Ref.bool_true,
12000 special.has_tag_capture,
12001 );
1153212002
11533 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);12003 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11534 cases_extra.appendAssumeCapacity(1); // items_len12004 cases_extra.appendAssumeCapacity(1); // items_len
11535 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));12005 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11536 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));12006 cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_true));
11537 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);12007 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11538 }12008 }
11539 if (false_count == 0) {12009 if (false_count == 0) {
11540 cases_len += 1;12010 cases_len += 1;
11541 case_block.inline_case_capture = Air.Inst.Ref.bool_false;
1154212011
11543 case_block.instructions.shrinkRetainingCapacity(0);12012 case_block.instructions.shrinkRetainingCapacity(0);
11544 case_block.wip_capture_scope = child_block.wip_capture_scope;12013 case_block.wip_capture_scope = child_block.wip_capture_scope;
...@@ -11546,12 +12015,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11546,12 +12015,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11546 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);12015 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
11547 emit_bb = true;12016 emit_bb = true;
1154812017
11549 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);12018 try spa.analyzeProngRuntime(
12019 &case_block,
12020 .special,
12021 special.body,
12022 special.capture,
12023 .special_capture,
12024 &.{Air.Inst.Ref.bool_false},
12025 Air.Inst.Ref.bool_false,
12026 special.has_tag_capture,
12027 );
1155012028
11551 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);12029 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
11552 cases_extra.appendAssumeCapacity(1); // items_len12030 cases_extra.appendAssumeCapacity(1); // items_len
11553 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));12031 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
11554 cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));12032 cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_false));
11555 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);12033 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
11556 }12034 }
11557 },12035 },
...@@ -11565,7 +12043,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11565,7 +12043,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1156512043
11566 case_block.instructions.shrinkRetainingCapacity(0);12044 case_block.instructions.shrinkRetainingCapacity(0);
11567 case_block.wip_capture_scope = wip_captures.scope;12045 case_block.wip_capture_scope = wip_captures.scope;
11568 case_block.inline_case_capture = .none;
1156912046
11570 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and12047 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
11571 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))12048 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
...@@ -11589,7 +12066,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11589,7 +12066,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11589 {12066 {
11590 // nothing to do here12067 // nothing to do here
11591 } else if (special.body.len != 0 and analyze_body and !special.is_inline) {12068 } else if (special.body.len != 0 and analyze_body and !special.is_inline) {
11592 try sema.analyzeBodyRuntimeBreak(&case_block, special.body);12069 try spa.analyzeProngRuntime(
12070 &case_block,
12071 .special,
12072 special.body,
12073 special.capture,
12074 .special_capture,
12075 undefined, // case_vals may be undefined for special prongs
12076 .none,
12077 false,
12078 );
11593 } else {12079 } else {
11594 // We still need a terminator in this block, but we have proven12080 // We still need a terminator in this block, but we have proven
11595 // that it is unreachable.12081 // that it is unreachable.
...@@ -11704,29 +12190,51 @@ const RangeSetUnhandledIterator = struct {...@@ -11704,29 +12190,51 @@ const RangeSetUnhandledIterator = struct {
11704 }12190 }
11705};12191};
1170612192
12193const ResolvedSwitchItem = struct {
12194 ref: Air.Inst.Ref,
12195 val: InternPool.Index,
12196};
11707fn resolveSwitchItemVal(12197fn resolveSwitchItemVal(
11708 sema: *Sema,12198 sema: *Sema,
11709 block: *Block,12199 block: *Block,
11710 item_ref: Zir.Inst.Ref,12200 item_ref: Zir.Inst.Ref,
12201 /// Coerce `item_ref` to this type.
12202 coerce_ty: Type,
11711 switch_node_offset: i32,12203 switch_node_offset: i32,
11712 switch_prong_src: Module.SwitchProngSrc,12204 switch_prong_src: Module.SwitchProngSrc,
11713 range_expand: Module.SwitchProngSrc.RangeExpand,12205 range_expand: Module.SwitchProngSrc.RangeExpand,
11714) CompileError!InternPool.Index {12206) CompileError!ResolvedSwitchItem {
11715 const mod = sema.mod;12207 const mod = sema.mod;
11716 const item = try sema.resolveInst(item_ref);12208 const uncoerced_item = try sema.resolveInst(item_ref);
12209
11717 // Constructing a LazySrcLoc is costly because we only have the switch AST node.12210 // Constructing a LazySrcLoc is costly because we only have the switch AST node.
11718 // Only if we know for sure we need to report a compile error do we resolve the12211 // Only if we know for sure we need to report a compile error do we resolve the
11719 // full source locations.12212 // full source locations.
11720 if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| {12213
11721 return val.toIntern();12214 const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |err| switch (err) {
11722 } else |err| switch (err) {12215 error.NeededSourceLocation => {
12216 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
12217 _ = try sema.coerce(block, coerce_ty, uncoerced_item, src);
12218 unreachable;
12219 },
12220 else => |e| return e,
12221 };
12222
12223 const maybe_lazy = sema.resolveConstValue(block, .unneeded, item, "") catch |err| switch (err) {
11723 error.NeededSourceLocation => {12224 error.NeededSourceLocation => {
11724 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);12225 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
11725 _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");12226 _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");
11726 unreachable;12227 unreachable;
11727 },12228 },
11728 else => |e| return e,12229 else => |e| return e,
11729 }12230 };
12231
12232 const val = try sema.resolveLazyValue(maybe_lazy);
12233 const new_item = if (val.toIntern() != maybe_lazy.toIntern()) blk: {
12234 break :blk try sema.addConstant(coerce_ty, val);
12235 } else item;
12236
12237 return .{ .ref = new_item, .val = val.toIntern() };
11730}12238}
1173112239
11732fn validateSwitchRange(12240fn validateSwitchRange(
...@@ -11735,31 +12243,35 @@ fn validateSwitchRange(...@@ -11735,31 +12243,35 @@ fn validateSwitchRange(
11735 range_set: *RangeSet,12243 range_set: *RangeSet,
11736 first_ref: Zir.Inst.Ref,12244 first_ref: Zir.Inst.Ref,
11737 last_ref: Zir.Inst.Ref,12245 last_ref: Zir.Inst.Ref,
12246 operand_ty: Type,
11738 src_node_offset: i32,12247 src_node_offset: i32,
11739 switch_prong_src: Module.SwitchProngSrc,12248 switch_prong_src: Module.SwitchProngSrc,
11740) CompileError!void {12249) CompileError![2]Air.Inst.Ref {
11741 const mod = sema.mod;12250 const mod = sema.mod;
11742 const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);12251 const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first);
11743 const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);12252 const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last);
11744 if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) {12253 if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) {
11745 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);12254 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
11746 return sema.fail(block, src, "range start value is greater than the end value", .{});12255 return sema.fail(block, src, "range start value is greater than the end value", .{});
11747 }12256 }
11748 const maybe_prev_src = try range_set.add(first, last, switch_prong_src);12257 const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src);
11749 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);12258 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12259 return .{ first.ref, last.ref };
11750}12260}
1175112261
11752fn validateSwitchItem(12262fn validateSwitchItemInt(
11753 sema: *Sema,12263 sema: *Sema,
11754 block: *Block,12264 block: *Block,
11755 range_set: *RangeSet,12265 range_set: *RangeSet,
11756 item_ref: Zir.Inst.Ref,12266 item_ref: Zir.Inst.Ref,
12267 operand_ty: Type,
11757 src_node_offset: i32,12268 src_node_offset: i32,
11758 switch_prong_src: Module.SwitchProngSrc,12269 switch_prong_src: Module.SwitchProngSrc,
11759) CompileError!void {12270) CompileError!Air.Inst.Ref {
11760 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);12271 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11761 const maybe_prev_src = try range_set.add(item, item, switch_prong_src);12272 const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src);
11762 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);12273 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12274 return item.ref;
11763}12275}
1176412276
11765fn validateSwitchItemEnum(12277fn validateSwitchItemEnum(
...@@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum(...@@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum(
11768 seen_fields: []?Module.SwitchProngSrc,12280 seen_fields: []?Module.SwitchProngSrc,
11769 range_set: *RangeSet,12281 range_set: *RangeSet,
11770 item_ref: Zir.Inst.Ref,12282 item_ref: Zir.Inst.Ref,
12283 operand_ty: Type,
11771 src_node_offset: i32,12284 src_node_offset: i32,
11772 switch_prong_src: Module.SwitchProngSrc,12285 switch_prong_src: Module.SwitchProngSrc,
11773) CompileError!void {12286) CompileError!Air.Inst.Ref {
11774 const ip = &sema.mod.intern_pool;12287 const ip = &sema.mod.intern_pool;
11775 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);12288 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11776 const int = ip.indexToKey(item).enum_tag.int;12289 const int = ip.indexToKey(item.val).enum_tag.int;
11777 const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse {12290 const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse {
11778 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);12291 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
11779 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);12292 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12293 return item.ref;
11780 };12294 };
11781 const maybe_prev_src = seen_fields[field_index];12295 const maybe_prev_src = seen_fields[field_index];
11782 seen_fields[field_index] = switch_prong_src;12296 seen_fields[field_index] = switch_prong_src;
11783 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);12297 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12298 return item.ref;
11784}12299}
1178512300
11786fn validateSwitchItemError(12301fn validateSwitchItemError(
...@@ -11788,18 +12303,19 @@ fn validateSwitchItemError(...@@ -11788,18 +12303,19 @@ fn validateSwitchItemError(
11788 block: *Block,12303 block: *Block,
11789 seen_errors: *SwitchErrorSet,12304 seen_errors: *SwitchErrorSet,
11790 item_ref: Zir.Inst.Ref,12305 item_ref: Zir.Inst.Ref,
12306 operand_ty: Type,
11791 src_node_offset: i32,12307 src_node_offset: i32,
11792 switch_prong_src: Module.SwitchProngSrc,12308 switch_prong_src: Module.SwitchProngSrc,
11793) CompileError!void {12309) CompileError!Air.Inst.Ref {
11794 const ip = &sema.mod.intern_pool;12310 const ip = &sema.mod.intern_pool;
11795 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);12311 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11796 // TODO: Do i need to typecheck here?12312 const error_name = ip.indexToKey(item.val).err.name;
11797 const error_name = ip.indexToKey(item).err.name;
11798 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|12313 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
11799 prev.value12314 prev.value
11800 else12315 else
11801 null;12316 null;
11802 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);12317 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12318 return item.ref;
11803}12319}
1180412320
11805fn validateSwitchDupe(12321fn validateSwitchDupe(
...@@ -11842,19 +12358,20 @@ fn validateSwitchItemBool(...@@ -11842,19 +12358,20 @@ fn validateSwitchItemBool(
11842 item_ref: Zir.Inst.Ref,12358 item_ref: Zir.Inst.Ref,
11843 src_node_offset: i32,12359 src_node_offset: i32,
11844 switch_prong_src: Module.SwitchProngSrc,12360 switch_prong_src: Module.SwitchProngSrc,
11845) CompileError!void {12361) CompileError!Air.Inst.Ref {
11846 const mod = sema.mod;12362 const mod = sema.mod;
11847 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);12363 const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none);
11848 if (item.toValue().toBool()) {12364 if (item.val.toValue().toBool()) {
11849 true_count.* += 1;12365 true_count.* += 1;
11850 } else {12366 } else {
11851 false_count.* += 1;12367 false_count.* += 1;
11852 }12368 }
11853 if (true_count.* + false_count.* > 2) {12369 if (true_count.* > 1 or false_count.* > 1) {
11854 const block_src_decl = mod.declPtr(block.src_decl);12370 const block_src_decl = sema.mod.declPtr(block.src_decl);
11855 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);12371 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
11856 return sema.fail(block, src, "duplicate switch value", .{});12372 return sema.fail(block, src, "duplicate switch value", .{});
11857 }12373 }
12374 return item.ref;
11858}12375}
1185912376
11860const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);12377const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
...@@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse(...@@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse(
11864 block: *Block,12381 block: *Block,
11865 seen_values: *ValueSrcMap,12382 seen_values: *ValueSrcMap,
11866 item_ref: Zir.Inst.Ref,12383 item_ref: Zir.Inst.Ref,
12384 operand_ty: Type,
11867 src_node_offset: i32,12385 src_node_offset: i32,
11868 switch_prong_src: Module.SwitchProngSrc,12386 switch_prong_src: Module.SwitchProngSrc,
11869) CompileError!void {12387) CompileError!Air.Inst.Ref {
11870 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);12388 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11871 const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return;12389 const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref;
11872 return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);12390 try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
12391 unreachable;
11873}12392}
1187412393
11875fn validateSwitchNoRange(12394fn validateSwitchNoRange(
src/Zir.zig+45-171
...@@ -667,38 +667,9 @@ pub const Inst = struct {...@@ -667,38 +667,9 @@ pub const Inst = struct {
667 /// A switch expression. Uses the `pl_node` union field.667 /// A switch expression. Uses the `pl_node` union field.
668 /// AST node is the switch, payload is `SwitchBlock`.668 /// AST node is the switch, payload is `SwitchBlock`.
669 switch_block,669 switch_block,
670 /// Produces the value that will be switched on. For example, for670 /// A switch expression. Uses the `pl_node` union field.
671 /// integers, it returns the integer with no modifications. For tagged unions, it671 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
672 /// returns the active enum tag.672 switch_block_ref,
673 /// Uses the `un_node` union field.
674 switch_cond,
675 /// Same as `switch_cond`, except the input operand is a pointer to
676 /// what will be switched on.
677 /// Uses the `un_node` union field.
678 switch_cond_ref,
679 /// Produces the capture value for a switch prong.
680 /// Uses the `switch_capture` field.
681 /// If the `prong_index` field is max int, it means this is the capture
682 /// for the else/`_` prong.
683 switch_capture,
684 /// Produces the capture value for a switch prong.
685 /// Result is a pointer to the value.
686 /// Uses the `switch_capture` field.
687 /// If the `prong_index` field is max int, it means this is the capture
688 /// for the else/`_` prong.
689 switch_capture_ref,
690 /// Produces the capture value for a switch prong.
691 /// The prong is one of the multi cases.
692 /// Uses the `switch_capture` field.
693 switch_capture_multi,
694 /// Produces the capture value for a switch prong.
695 /// The prong is one of the multi cases.
696 /// Result is a pointer to the value.
697 /// Uses the `switch_capture` field.
698 switch_capture_multi_ref,
699 /// Produces the capture value for an inline switch prong tag capture.
700 /// Uses the `un_tok` field.
701 switch_capture_tag,
702 /// Given a673 /// Given a
703 /// *A returns *A674 /// *A returns *A
704 /// *E!A returns *A675 /// *E!A returns *A
...@@ -1144,14 +1115,8 @@ pub const Inst = struct {...@@ -1144,14 +1115,8 @@ pub const Inst = struct {
1144 .typeof_log2_int_type,1115 .typeof_log2_int_type,
1145 .resolve_inferred_alloc,1116 .resolve_inferred_alloc,
1146 .set_eval_branch_quota,1117 .set_eval_branch_quota,
1147 .switch_capture,
1148 .switch_capture_ref,
1149 .switch_capture_multi,
1150 .switch_capture_multi_ref,
1151 .switch_capture_tag,
1152 .switch_block,1118 .switch_block,
1153 .switch_cond,1119 .switch_block_ref,
1154 .switch_cond_ref,
1155 .array_base_ptr,1120 .array_base_ptr,
1156 .field_base_ptr,1121 .field_base_ptr,
1157 .validate_array_init_ty,1122 .validate_array_init_ty,
...@@ -1438,14 +1403,8 @@ pub const Inst = struct {...@@ -1438,14 +1403,8 @@ pub const Inst = struct {
1438 .slice_length,1403 .slice_length,
1439 .import,1404 .import,
1440 .typeof_log2_int_type,1405 .typeof_log2_int_type,
1441 .switch_capture,
1442 .switch_capture_ref,
1443 .switch_capture_multi,
1444 .switch_capture_multi_ref,
1445 .switch_capture_tag,
1446 .switch_block,1406 .switch_block,
1447 .switch_cond,1407 .switch_block_ref,
1448 .switch_cond_ref,
1449 .array_base_ptr,1408 .array_base_ptr,
1450 .field_base_ptr,1409 .field_base_ptr,
1451 .struct_init_empty,1410 .struct_init_empty,
...@@ -1696,13 +1655,7 @@ pub const Inst = struct {...@@ -1696,13 +1655,7 @@ pub const Inst = struct {
1696 .err_union_code_ptr = .un_node,1655 .err_union_code_ptr = .un_node,
1697 .enum_literal = .str_tok,1656 .enum_literal = .str_tok,
1698 .switch_block = .pl_node,1657 .switch_block = .pl_node,
1699 .switch_cond = .un_node,1658 .switch_block_ref = .pl_node,
1700 .switch_cond_ref = .un_node,
1701 .switch_capture = .switch_capture,
1702 .switch_capture_ref = .switch_capture,
1703 .switch_capture_multi = .switch_capture,
1704 .switch_capture_multi_ref = .switch_capture,
1705 .switch_capture_tag = .un_tok,
1706 .array_base_ptr = .un_node,1659 .array_base_ptr = .un_node,
1707 .field_base_ptr = .un_node,1660 .field_base_ptr = .un_node,
1708 .validate_array_init_ty = .pl_node,1661 .validate_array_init_ty = .pl_node,
...@@ -2028,9 +1981,10 @@ pub const Inst = struct {...@@ -2028,9 +1981,10 @@ pub const Inst = struct {
2028 /// Implements the `@inComptime` builtin.1981 /// Implements the `@inComptime` builtin.
2029 /// `operand` is `src_node: i32`.1982 /// `operand` is `src_node: i32`.
2030 in_comptime,1983 in_comptime,
2031 /// Used as a placeholder for the capture of an `errdefer`.1984 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
2032 /// This is replaced by Sema with the captured value.1985 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
2033 errdefer_err_code,1986 /// This should never appear in a body.
1987 value_placeholder,
20341988
2035 pub const InstData = struct {1989 pub const InstData = struct {
2036 opcode: Extended,1990 opcode: Extended,
...@@ -2269,10 +2223,6 @@ pub const Inst = struct {...@@ -2269,10 +2223,6 @@ pub const Inst = struct {
2269 operand: Ref,2223 operand: Ref,
2270 payload_index: u32,2224 payload_index: u32,
2271 },2225 },
2272 switch_capture: struct {
2273 switch_inst: Index,
2274 prong_index: u32,
2275 },
2276 dbg_stmt: LineColumn,2226 dbg_stmt: LineColumn,
2277 /// Used for unary operators which reference an inst,2227 /// Used for unary operators which reference an inst,
2278 /// with an AST node source location.2228 /// with an AST node source location.
...@@ -2342,7 +2292,6 @@ pub const Inst = struct {...@@ -2342,7 +2292,6 @@ pub const Inst = struct {
2342 bool_br,2292 bool_br,
2343 @"unreachable",2293 @"unreachable",
2344 @"break",2294 @"break",
2345 switch_capture,
2346 dbg_stmt,2295 dbg_stmt,
2347 inst_node,2296 inst_node,
2348 str_op,2297 str_op,
...@@ -2681,37 +2630,53 @@ pub const Inst = struct {...@@ -2681,37 +2630,53 @@ pub const Inst = struct {
2681 };2630 };
26822631
2683 /// 0. multi_cases_len: u32 // If has_multi_cases is set.2632 /// 0. multi_cases_len: u32 // If has_multi_cases is set.
2684 /// 1. else_body { // If has_else or has_under is set.2633 /// 1. tag_capture_inst: u32 // If any_has_tag_capture is set. Index of instruction prongs use to refer to the inline tag capture.
2685 /// body_len: u32,2634 /// 2. else_body { // If has_else or has_under is set.
2686 /// body member Index for every body_len2635 /// info: ProngInfo,
2636 /// body member Index for every info.body_len
2687 /// }2637 /// }
2688 /// 2. scalar_cases: { // for every scalar_cases_len2638 /// 3. scalar_cases: { // for every scalar_cases_len
2689 /// item: Ref,2639 /// item: Ref,
2690 /// body_len: u32,2640 /// info: ProngInfo,
2691 /// body member Index for every body_len2641 /// body member Index for every info.body_len
2692 /// }2642 /// }
2693 /// 3. multi_cases: { // for every multi_cases_len2643 /// 4. multi_cases: { // for every multi_cases_len
2694 /// items_len: u32,2644 /// items_len: u32,
2695 /// ranges_len: u32,2645 /// ranges_len: u32,
2696 /// body_len: u32,2646 /// info: ProngInfo,
2697 /// item: Ref // for every items_len2647 /// item: Ref // for every items_len
2698 /// ranges: { // for every ranges_len2648 /// ranges: { // for every ranges_len
2699 /// item_first: Ref,2649 /// item_first: Ref,
2700 /// item_last: Ref,2650 /// item_last: Ref,
2701 /// }2651 /// }
2702 /// body member Index for every body_len2652 /// body member Index for every info.body_len
2703 /// }2653 /// }
2654 ///
2655 /// When analyzing a case body, the switch instruction itself refers to the
2656 /// captured payload. Whether this is captured by reference or by value
2657 /// depends on whether the `byref` bit is set for the corresponding body.
2704 pub const SwitchBlock = struct {2658 pub const SwitchBlock = struct {
2705 /// This is always a `switch_cond` or `switch_cond_ref` instruction.2659 /// The operand passed to the `switch` expression. If this is a
2706 /// If it is a `switch_cond_ref` instruction, bits.is_ref is always true.2660 /// `switch_block`, this is the operand value; if `switch_block_ref` it
2707 /// If it is a `switch_cond` instruction, bits.is_ref is always false.2661 /// is a pointer to the operand. `switch_block_ref` is always used if
2708 /// Both `switch_cond` and `switch_cond_ref` return a value, not a pointer,2662 /// any prong has a byref capture.
2709 /// that is useful for the case items, but cannot be used for capture values.
2710 /// For the capture values, Sema is expected to find the operand of this operand
2711 /// and use that.
2712 operand: Ref,2663 operand: Ref,
2713 bits: Bits,2664 bits: Bits,
27142665
2666 /// These are stored in trailing data in `extra` for each prong.
2667 pub const ProngInfo = packed struct(u32) {
2668 body_len: u28,
2669 capture: Capture,
2670 is_inline: bool,
2671 has_tag_capture: bool,
2672
2673 pub const Capture = enum(u2) {
2674 none,
2675 by_val,
2676 by_ref,
2677 };
2678 };
2679
2715 pub const Bits = packed struct {2680 pub const Bits = packed struct {
2716 /// If true, one or more prongs have multiple items.2681 /// If true, one or more prongs have multiple items.
2717 has_multi_cases: bool,2682 has_multi_cases: bool,
...@@ -2719,9 +2684,11 @@ pub const Inst = struct {...@@ -2719,9 +2684,11 @@ pub const Inst = struct {
2719 has_else: bool,2684 has_else: bool,
2720 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.2685 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.
2721 has_under: bool,2686 has_under: bool,
2687 /// If true, at least one prong has an inline tag capture.
2688 any_has_tag_capture: bool,
2722 scalar_cases_len: ScalarCasesLen,2689 scalar_cases_len: ScalarCasesLen,
27232690
2724 pub const ScalarCasesLen = u29;2691 pub const ScalarCasesLen = u28;
27252692
2726 pub fn specialProng(bits: Bits) SpecialProng {2693 pub fn specialProng(bits: Bits) SpecialProng {
2727 const has_else: u2 = @boolToInt(bits.has_else);2694 const has_else: u2 = @boolToInt(bits.has_else);
...@@ -2735,103 +2702,10 @@ pub const Inst = struct {...@@ -2735,103 +2702,10 @@ pub const Inst = struct {
2735 }2702 }
2736 };2703 };
27372704
2738 pub const ScalarProng = struct {
2739 item: Ref,
2740 body: []const Index,
2741 };
2742
2743 /// TODO performance optimization: instead of having this helper method
2744 /// change the definition of switch_capture instruction to store extra_index
2745 /// instead of prong_index. This way, Sema won't be doing O(N^2) iterations
2746 /// over the switch prongs.
2747 pub fn getScalarProng(
2748 self: SwitchBlock,
2749 zir: Zir,
2750 extra_end: usize,
2751 prong_index: usize,
2752 ) ScalarProng {
2753 var extra_index: usize = extra_end;
2754
2755 if (self.bits.has_multi_cases) {
2756 extra_index += 1;
2757 }
2758
2759 if (self.bits.specialProng() != .none) {
2760 const body_len = @truncate(u31, zir.extra[extra_index]);
2761 extra_index += 1;
2762 const body = zir.extra[extra_index..][0..body_len];
2763 extra_index += body.len;
2764 }
2765
2766 var scalar_i: usize = 0;
2767 while (true) : (scalar_i += 1) {
2768 const item = @intToEnum(Ref, zir.extra[extra_index]);
2769 extra_index += 1;
2770 const body_len = @truncate(u31, zir.extra[extra_index]);
2771 extra_index += 1;
2772 const body = zir.extra[extra_index..][0..body_len];
2773 extra_index += body.len;
2774
2775 if (scalar_i < prong_index) continue;
2776
2777 return .{
2778 .item = item,
2779 .body = body,
2780 };
2781 }
2782 }
2783
2784 pub const MultiProng = struct {2705 pub const MultiProng = struct {
2785 items: []const Ref,2706 items: []const Ref,
2786 body: []const Index,2707 body: []const Index,
2787 };2708 };
2788
2789 pub fn getMultiProng(
2790 self: SwitchBlock,
2791 zir: Zir,
2792 extra_end: usize,
2793 prong_index: usize,
2794 ) MultiProng {
2795 // +1 for self.bits.has_multi_cases == true
2796 var extra_index: usize = extra_end + 1;
2797
2798 if (self.bits.specialProng() != .none) {
2799 const body_len = @truncate(u31, zir.extra[extra_index]);
2800 extra_index += 1;
2801 const body = zir.extra[extra_index..][0..body_len];
2802 extra_index += body.len;
2803 }
2804
2805 var scalar_i: usize = 0;
2806 while (scalar_i < self.bits.scalar_cases_len) : (scalar_i += 1) {
2807 extra_index += 1;
2808 const body_len = @truncate(u31, zir.extra[extra_index]);
2809 extra_index += 1;
2810 extra_index += body_len;
2811 }
2812 var multi_i: u32 = 0;
2813 while (true) : (multi_i += 1) {
2814 const items_len = zir.extra[extra_index];
2815 extra_index += 1;
2816 const ranges_len = zir.extra[extra_index];
2817 extra_index += 1;
2818 const body_len = @truncate(u31, zir.extra[extra_index]);
2819 extra_index += 1;
2820 const items = zir.refSlice(extra_index, items_len);
2821 extra_index += items_len;
2822 // Each range has a start and an end.
2823 extra_index += 2 * ranges_len;
2824
2825 const body = zir.extra[extra_index..][0..body_len];
2826 extra_index += body_len;
2827
2828 if (multi_i < prong_index) continue;
2829 return .{
2830 .items = items,
2831 .body = body,
2832 };
2833 }
2834 }
2835 };2709 };
28362710
2837 pub const Field = struct {2711 pub const Field = struct {
src/print_zir.zig+42-31
...@@ -222,8 +222,6 @@ const Writer = struct {...@@ -222,8 +222,6 @@ const Writer = struct {
222 .bit_reverse,222 .bit_reverse,
223 .@"resume",223 .@"resume",
224 .@"await",224 .@"await",
225 .switch_cond,
226 .switch_cond_ref,
227 .array_base_ptr,225 .array_base_ptr,
228 .field_base_ptr,226 .field_base_ptr,
229 .validate_struct_init_ty,227 .validate_struct_init_ty,
...@@ -235,7 +233,6 @@ const Writer = struct {...@@ -235,7 +233,6 @@ const Writer = struct {
235 .ref,233 .ref,
236 .ret_implicit,234 .ret_implicit,
237 .closure_capture,235 .closure_capture,
238 .switch_capture_tag,
239 => try self.writeUnTok(stream, inst),236 => try self.writeUnTok(stream, inst),
240237
241 .bool_br_and,238 .bool_br_and,
...@@ -389,7 +386,9 @@ const Writer = struct {...@@ -389,7 +386,9 @@ const Writer = struct {
389 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),386 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
390 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),387 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
391388
392 .switch_block => try self.writeSwitchBlock(stream, inst),389 .switch_block,
390 .switch_block_ref,
391 => try self.writeSwitchBlock(stream, inst),
393392
394 .field_ptr,393 .field_ptr,
395 .field_ptr_init,394 .field_ptr_init,
...@@ -436,12 +435,6 @@ const Writer = struct {...@@ -436,12 +435,6 @@ const Writer = struct {
436435
437 .@"unreachable" => try self.writeUnreachable(stream, inst),436 .@"unreachable" => try self.writeUnreachable(stream, inst),
438437
439 .switch_capture,
440 .switch_capture_ref,
441 .switch_capture_multi,
442 .switch_capture_multi_ref,
443 => try self.writeSwitchCapture(stream, inst),
444
445 .dbg_stmt => try self.writeDbgStmt(stream, inst),438 .dbg_stmt => try self.writeDbgStmt(stream, inst),
446439
447 .dbg_block_begin,440 .dbg_block_begin,
...@@ -469,7 +462,7 @@ const Writer = struct {...@@ -469,7 +462,7 @@ const Writer = struct {
469 .breakpoint,462 .breakpoint,
470 .c_va_start,463 .c_va_start,
471 .in_comptime,464 .in_comptime,
472 .errdefer_err_code,465 .value_placeholder,
473 => try self.writeExtNode(stream, extended),466 => try self.writeExtNode(stream, extended),
474467
475 .builtin_src => {468 .builtin_src => {
...@@ -1903,8 +1896,19 @@ const Writer = struct {...@@ -1903,8 +1896,19 @@ const Writer = struct {
1903 break :blk multi_cases_len;1896 break :blk multi_cases_len;
1904 } else 0;1897 } else 0;
19051898
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
1906 try self.writeInstRef(stream, extra.data.operand);1905 try self.writeInstRef(stream, extra.data.operand);
19071906
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
1908 self.indent += 2;1912 self.indent += 2;
19091913
1910 else_prong: {1914 else_prong: {
...@@ -1915,15 +1919,20 @@ const Writer = struct {...@@ -1915,15 +1919,20 @@ const Writer = struct {
1915 else => break :else_prong,1919 else => break :else_prong,
1916 };1920 };
19171921
1918 const body_len = @truncate(u31, self.code.extra[extra_index]);1922 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
1919 const inline_text = if (self.code.extra[extra_index] >> 31 != 0) "inline " else "";1923 const capture_text = switch (info.capture) {
1924 .none => "",
1925 .by_val => "by_val ",
1926 .by_ref => "by_ref ",
1927 };
1928 const inline_text = if (info.is_inline) "inline " else "";
1920 extra_index += 1;1929 extra_index += 1;
1921 const body = self.code.extra[extra_index..][0..body_len];1930 const body = self.code.extra[extra_index..][0..info.body_len];
1922 extra_index += body.len;1931 extra_index += body.len;
19231932
1924 try stream.writeAll(",\n");1933 try stream.writeAll(",\n");
1925 try stream.writeByteNTimes(' ', self.indent);1934 try stream.writeByteNTimes(' ', self.indent);
1926 try stream.print("{s}{s} => ", .{ inline_text, prong_name });1935 try stream.print("{s}{s}{s} => ", .{ capture_text, inline_text, prong_name });
1927 try self.writeBracedBody(stream, body);1936 try self.writeBracedBody(stream, body);
1928 }1937 }
19291938
...@@ -1933,15 +1942,19 @@ const Writer = struct {...@@ -1933,15 +1942,19 @@ const Writer = struct {
1933 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {1942 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1934 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);1943 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1935 extra_index += 1;1944 extra_index += 1;
1936 const body_len = @truncate(u31, self.code.extra[extra_index]);1945 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
1937 const is_inline = self.code.extra[extra_index] >> 31 != 0;
1938 extra_index += 1;1946 extra_index += 1;
1939 const body = self.code.extra[extra_index..][0..body_len];1947 const body = self.code.extra[extra_index..][0..info.body_len];
1940 extra_index += body_len;1948 extra_index += info.body_len;
19411949
1942 try stream.writeAll(",\n");1950 try stream.writeAll(",\n");
1943 try stream.writeByteNTimes(' ', self.indent);1951 try stream.writeByteNTimes(' ', self.indent);
1944 if (is_inline) try stream.writeAll("inline ");1952 switch (info.capture) {
1953 .none => {},
1954 .by_val => try stream.writeAll("by_val "),
1955 .by_ref => try stream.writeAll("by_ref "),
1956 }
1957 if (info.is_inline) try stream.writeAll("inline ");
1945 try self.writeInstRef(stream, item_ref);1958 try self.writeInstRef(stream, item_ref);
1946 try stream.writeAll(" => ");1959 try stream.writeAll(" => ");
1947 try self.writeBracedBody(stream, body);1960 try self.writeBracedBody(stream, body);
...@@ -1954,15 +1967,19 @@ const Writer = struct {...@@ -1954,15 +1967,19 @@ const Writer = struct {
1954 extra_index += 1;1967 extra_index += 1;
1955 const ranges_len = self.code.extra[extra_index];1968 const ranges_len = self.code.extra[extra_index];
1956 extra_index += 1;1969 extra_index += 1;
1957 const body_len = @truncate(u31, self.code.extra[extra_index]);1970 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
1958 const is_inline = self.code.extra[extra_index] >> 31 != 0;
1959 extra_index += 1;1971 extra_index += 1;
1960 const items = self.code.refSlice(extra_index, items_len);1972 const items = self.code.refSlice(extra_index, items_len);
1961 extra_index += items_len;1973 extra_index += items_len;
19621974
1963 try stream.writeAll(",\n");1975 try stream.writeAll(",\n");
1964 try stream.writeByteNTimes(' ', self.indent);1976 try stream.writeByteNTimes(' ', self.indent);
1965 if (is_inline) try stream.writeAll("inline ");1977 switch (info.capture) {
1978 .none => {},
1979 .by_val => try stream.writeAll("by_val "),
1980 .by_ref => try stream.writeAll("by_ref "),
1981 }
1982 if (info.is_inline) try stream.writeAll("inline ");
19661983
1967 for (items, 0..) |item_ref, item_i| {1984 for (items, 0..) |item_ref, item_i| {
1968 if (item_i != 0) try stream.writeAll(", ");1985 if (item_i != 0) try stream.writeAll(", ");
...@@ -1984,8 +2001,8 @@ const Writer = struct {...@@ -1984,8 +2001,8 @@ const Writer = struct {
1984 try self.writeInstRef(stream, item_last);2001 try self.writeInstRef(stream, item_last);
1985 }2002 }
19862003
1987 const body = self.code.extra[extra_index..][0..body_len];2004 const body = self.code.extra[extra_index..][0..info.body_len];
1988 extra_index += body_len;2005 extra_index += info.body_len;
1989 try stream.writeAll(" => ");2006 try stream.writeAll(" => ");
1990 try self.writeBracedBody(stream, body);2007 try self.writeBracedBody(stream, body);
1991 }2008 }
...@@ -2437,12 +2454,6 @@ const Writer = struct {...@@ -2437,12 +2454,6 @@ const Writer = struct {
2437 try self.writeSrc(stream, src);2454 try self.writeSrc(stream, src);
2438 }2455 }
24392456
2440 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2441 const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
2442 try self.writeInstIndex(stream, inst_data.switch_inst);
2443 try stream.print(", {d})", .{inst_data.prong_index});
2444 }
2445
2446 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {2457 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2447 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt;2458 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt;
2448 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });2459 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
test/behavior/switch.zig+68
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const assert = std.debug.assert;
3const expect = std.testing.expect;4const expect = std.testing.expect;
4const expectError = std.testing.expectError;5const expectError = std.testing.expectError;
5const expectEqual = std.testing.expectEqual;6const expectEqual = std.testing.expectEqual;
...@@ -717,3 +718,70 @@ test "comptime inline switch" {...@@ -717,3 +718,70 @@ test "comptime inline switch" {
717718
718 try expectEqual(u32, value);719 try expectEqual(u32, value);
719}720}
721
722test "switch capture peer type resolution" {
723 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
724
725 const U = union(enum) {
726 a: u32,
727 b: u64,
728 fn innerVal(u: @This()) u64 {
729 switch (u) {
730 .a, .b => |x| return x,
731 }
732 }
733 };
734
735 try expectEqual(@as(u64, 100), U.innerVal(.{ .a = 100 }));
736 try expectEqual(@as(u64, 200), U.innerVal(.{ .b = 200 }));
737}
738
739test "switch capture peer type resolution for in-memory coercible payloads" {
740 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
741
742 const T1 = c_int;
743 const T2 = @Type(@typeInfo(T1));
744
745 comptime assert(T1 != T2);
746
747 const U = union(enum) {
748 a: T1,
749 b: T2,
750 fn innerVal(u: @This()) c_int {
751 switch (u) {
752 .a, .b => |x| return x,
753 }
754 }
755 };
756
757 try expectEqual(@as(c_int, 100), U.innerVal(.{ .a = 100 }));
758 try expectEqual(@as(c_int, 200), U.innerVal(.{ .b = 200 }));
759}
760
761test "switch pointer capture peer type resolution" {
762 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
763
764 const T1 = c_int;
765 const T2 = @Type(@typeInfo(T1));
766
767 comptime assert(T1 != T2);
768
769 const U = union(enum) {
770 a: T1,
771 b: T2,
772 fn innerVal(u: *@This()) *c_int {
773 switch (u.*) {
774 .a, .b => |*ptr| return ptr,
775 }
776 }
777 };
778
779 var ua: U = .{ .a = 100 };
780 var ub: U = .{ .b = 200 };
781
782 ua.innerVal().* = 111;
783 ub.innerVal().* = 222;
784
785 try expectEqual(U{ .a = 111 }, ua);
786 try expectEqual(U{ .b = 222 }, ub);
787}
test/cases/compile_errors/capture_group_on_switch_prong_with_incompatible_payload_types.zig deleted-21
...@@ -1,21 +0,0 @@
1const Union = union(enum) {
2 A: usize,
3 B: isize,
4};
5comptime {
6 var u = Union{ .A = 8 };
7 switch (u) {
8 .A, .B => |e| {
9 _ = e;
10 unreachable;
11 },
12 }
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :8:20: error: capture group with incompatible types
20// :8:10: note: type 'usize' here
21// :8:14: note: type 'isize' here
test/cases/compile_errors/switch_capture_incompatible_types.zig created+27
...@@ -0,0 +1,27 @@
1export fn f() void {
2 const U = union(enum) { a: u32, b: *u8 };
3 var u: U = undefined;
4 switch (u) {
5 .a, .b => |val| _ = val,
6 }
7}
8
9export fn g() void {
10 const U = union(enum) { a: u64, b: u32 };
11 var u: U = undefined;
12 switch (u) {
13 .a, .b => |*ptr| _ = ptr,
14 }
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :5:20: error: capture group with incompatible types
22// :5:20: note: incompatible types: 'u32' and '*u8'
23// :5:10: note: type 'u32' here
24// :5:14: note: type '*u8' here
25// :13:20: error: capture group with incompatible types
26// :13:14: note: pointer type child 'u32' cannot cast into resolved pointer type child 'u64'
27// :13:20: note: this coercion is only possible when capturing by value
test/cases/compile_errors/switch_on_union_with_no_attached_enum.zig+2-2
...@@ -4,12 +4,12 @@ const Payload = union {...@@ -4,12 +4,12 @@ const Payload = union {
4 C: bool,4 C: bool,
5};5};
6export fn entry() void {6export fn entry() void {
7 const a = Payload { .A = 1234 };7 const a = Payload{ .A = 1234 };
8 foo(&a);8 foo(&a);
9}9}
10fn foo(a: *const Payload) void {10fn foo(a: *const Payload) void {
11 switch (a.*) {11 switch (a.*) {
12 Payload.A => {},12 .A => {},
13 else => unreachable,13 else => unreachable,
14 }14 }
15}15}