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
26102610 .slice_length,
26112611 .import,
26122612 .switch_block,
2613 .switch_cond,
2614 .switch_cond_ref,
2615 .switch_capture,
2616 .switch_capture_ref,
2617 .switch_capture_multi,
2618 .switch_capture_multi_ref,
2619 .switch_capture_tag,
2613 .switch_block_ref,
26202614 .struct_init_empty,
26212615 .struct_init,
26222616 .struct_init_ref,
......@@ -2960,7 +2954,7 @@ fn deferStmt(
29602954 try gz.astgen.instructions.append(gz.astgen.gpa, .{
29612955 .tag = .extended,
29622956 .data = .{ .extended = .{
2963 .opcode = .errdefer_err_code,
2957 .opcode = .value_placeholder,
29642958 .small = undefined,
29652959 .operand = undefined,
29662960 } },
......@@ -6715,6 +6709,7 @@ fn switchExpr(
67156709 // for the following variables, make note of the special prong AST node index,
67166710 // and bail out with a compile error if there are multiple special prongs present.
67176711 var any_payload_is_ref = false;
6712 var any_has_tag_capture = false;
67186713 var scalar_cases_len: u32 = 0;
67196714 var multi_cases_len: u32 = 0;
67206715 var inline_cases_len: u32 = 0;
......@@ -6725,8 +6720,12 @@ fn switchExpr(
67256720 for (case_nodes) |case_node| {
67266721 const case = tree.fullSwitchCase(case_node).?;
67276722 if (case.payload_token) |payload_token| {
6728 if (token_tags[payload_token] == .asterisk) {
6723 const ident = if (token_tags[payload_token] == .asterisk) blk: {
67296724 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;
67306729 }
67316730 }
67326731 // Check for else/`_` prong.
......@@ -6835,13 +6834,7 @@ fn switchExpr(
68356834 const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
68366835
68376836 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;
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 } };
6837 const item_ri: ResultInfo = .{ .rl = .none };
68456838
68466839 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
68476840 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with
......@@ -6860,13 +6853,30 @@ fn switchExpr(
68606853 block_scope.instructions_top = GenZir.unstacked_top;
68616854 block_scope.setBreakResultInfo(ri);
68626855
6856 // Sema expects a dbg_stmt immediately before switch_block(_ref)
6857 try emitDbgStmt(parent_gz, operand_lc);
68636858 // 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
68666862 // We re-use this same scope for all cases, including the special prong, if any.
68676863 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
68686864 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
68706880 // In this pass we generate all the item and prong expressions.
68716881 var multi_case_index: u32 = 0;
68726882 var scalar_case_index: u32 = 0;
......@@ -6880,17 +6890,22 @@ fn switchExpr(
68806890 var dbg_var_inst: Zir.Inst.Ref = undefined;
68816891 var dbg_var_tag_name: ?u32 = null;
68826892 var dbg_var_tag_inst: Zir.Inst.Ref = undefined;
6883 var capture_inst: Zir.Inst.Index = 0;
6884 var tag_inst: Zir.Inst.Index = 0;
6893 var has_tag_capture = false;
68856894 var capture_val_scope: Scope.LocalVal = undefined;
68866895 var tag_scope: Scope.LocalVal = undefined;
6896
6897 var capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = .none;
6898
68876899 const sub_scope = blk: {
68886900 const payload_token = case.payload_token orelse break :blk &case_scope.base;
68896901 const ident = if (token_tags[payload_token] == .asterisk)
68906902 payload_token + 1
68916903 else
68926904 payload_token;
6905
68936906 const is_ptr = ident != payload_token;
6907 capture = if (is_ptr) .by_ref else .by_val;
6908
68946909 const ident_slice = tree.tokenSlice(ident);
68956910 var payload_sub_scope: *Scope = undefined;
68966911 if (mem.eql(u8, ident_slice, "_")) {
......@@ -6899,53 +6914,18 @@ fn switchExpr(
68996914 }
69006915 payload_sub_scope = &case_scope.base;
69016916 } 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 }
69376917 const capture_name = try astgen.identAsString(ident);
69386918 try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice, .capture);
69396919 capture_val_scope = .{
69406920 .parent = &case_scope.base,
69416921 .gen_zir = &case_scope,
69426922 .name = capture_name,
6943 .inst = indexToRef(capture_inst),
6923 .inst = indexToRef(switch_block),
69446924 .token_src = payload_token,
69456925 .id_cat = .capture,
69466926 };
69476927 dbg_var_name = capture_name;
6948 dbg_var_inst = indexToRef(capture_inst);
6928 dbg_var_inst = indexToRef(switch_block);
69496929 payload_sub_scope = &capture_val_scope.base;
69506930 }
69516931
......@@ -6961,14 +6941,9 @@ fn switchExpr(
69616941 }
69626942 const tag_name = try astgen.identAsString(tag_token);
69636943 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);
6965 try astgen.instructions.append(gpa, .{
6966 .tag = .switch_capture_tag,
6967 .data = .{ .un_tok = .{
6968 .operand = cond,
6969 .src_tok = case_scope.tokenIndexToRelative(tag_token),
6970 } },
6971 });
6944
6945 assert(any_has_tag_capture);
6946 has_tag_capture = true;
69726947
69736948 tag_scope = .{
69746949 .parent = payload_sub_scope,
......@@ -7034,8 +7009,6 @@ fn switchExpr(
70347009 case_scope.instructions_top = parent_gz.instructions.items.len;
70357010 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);
70397012 try case_scope.addDbgBlockBegin();
70407013 if (dbg_var_name) |some| {
70417014 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
......@@ -7053,10 +7026,42 @@ fn switchExpr(
70537026 }
70547027
70557028 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);
70577050 try payloads.ensureUnusedCapacity(gpa, body_len);
7058 const inline_bit = @as(u32, @boolToInt(case.inline_token != null)) << 31;
7059 payloads.items[body_len_index] = body_len | inline_bit;
7051 payloads.items[body_len_index] = @bitCast(u32, Zir.Inst.SwitchBlock.ProngInfo{
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 }
70607065 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
70617066 }
70627067 }
......@@ -7065,14 +7070,16 @@ fn switchExpr(
70657070
70667071 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
70677072 @boolToInt(multi_cases_len != 0) +
7073 @boolToInt(any_has_tag_capture) +
70687074 payloads.items.len - case_table_end);
70697075
70707076 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
7071 .operand = cond,
7077 .operand = raw_operand,
70727078 .bits = Zir.Inst.SwitchBlock.Bits{
70737079 .has_multi_cases = multi_cases_len != 0,
70747080 .has_else = special_prong == .@"else",
70757081 .has_under = special_prong == .under,
7082 .any_has_tag_capture = any_has_tag_capture,
70767083 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),
70777084 },
70787085 });
......@@ -7081,6 +7088,10 @@ fn switchExpr(
70817088 astgen.extra.appendAssumeCapacity(multi_cases_len);
70827089 }
70837090
7091 if (any_has_tag_capture) {
7092 astgen.extra.appendAssumeCapacity(tag_inst);
7093 }
7094
70847095 const zir_datas = astgen.instructions.items(.data);
70857096 const zir_tags = astgen.instructions.items(.tag);
70867097
......@@ -7103,7 +7114,7 @@ fn switchExpr(
71037114 end_index += 3 + items_len + 2 * ranges_len;
71047115 }
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;
71077118 end_index += body_len;
71087119
71097120 switch (strat.tag) {
src/Autodoc.zig-25
......@@ -1993,31 +1993,6 @@ fn walkInstruction(
19931993 .expr = .{ .switchIndex = switch_index },
19941994 };
19951995 },
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
20221997 .typeof => {
20231998 const un_node = data[inst_index].un_node;
src/Module.zig+112-46
......@@ -2471,12 +2471,23 @@ pub const SrcLoc = struct {
24712471 }
24722472 } else unreachable;
24732473 },
2474 .node_offset_switch_prong_capture => |node_off| {
2474 .node_offset_switch_prong_capture,
2475 .node_offset_switch_prong_tag_capture,
2476 => |node_off| {
24752477 const tree = try src_loc.file_scope.getTree(gpa);
24762478 const case_node = src_loc.declRelativeToNodeIndex(node_off);
24772479 const case = tree.fullSwitchCase(case_node).?;
2478 const start_tok = case.payload_token.?;
24792480 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 };
24802491 const end_tok = switch (token_tags[start_tok]) {
24812492 .asterisk => start_tok + 1,
24822493 else => start_tok,
......@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {
29572968 /// The source location points to the capture of a switch_prong.
29582969 /// The Decl is determined contextually.
29592970 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,
29602974 /// The source location points to the align expr of a function type
29612975 /// expression, found by taking this AST node index offset from the containing
29622976 /// Decl AST node, which points to a function type AST node. Next, navigate to
......@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {
31303144 .node_offset_switch_special_prong,
31313145 .node_offset_switch_range,
31323146 .node_offset_switch_prong_capture,
3147 .node_offset_switch_prong_tag_capture,
31333148 .node_offset_fn_type_align,
31343149 .node_offset_fn_type_addrspace,
31353150 .node_offset_fn_type_section,
......@@ -5867,10 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
58675882}
58685883
58695884pub const SwitchProngSrc = union(enum) {
5885 /// The item for a scalar prong.
58705886 scalar: u32,
5887 /// A given single item for a multi prong.
58715888 multi: Multi,
5889 /// A given range item for a multi prong.
58725890 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.
58735896 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
58755906 pub const Multi = struct {
58765907 prong: u32,
......@@ -5886,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {
58865917 mod: *Module,
58875918 decl: *Decl,
58885919 switch_node_offset: i32,
5920 /// Ignored if `prong_src` is not `.range`
58895921 range_expand: RangeExpand,
58905922 ) LazySrcLoc {
58915923 @setCold(true);
......@@ -5906,63 +5938,97 @@ pub const SwitchProngSrc = union(enum) {
59065938
59075939 var multi_i: u32 = 0;
59085940 var scalar_i: u32 = 0;
5909 for (case_nodes) |case_node| {
5941 const case_node = for (case_nodes) |case_node| {
59105942 const case = tree.fullSwitchCase(case_node).?;
5911 if (case.ast.values.len == 0)
5912 continue;
5913 if (case.ast.values.len == 1 and
5914 node_tags[case.ast.values[0]] == .identifier and
5915 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
5916 {
5917 continue;
5943
5944 const is_special = special: {
5945 if (case.ast.values.len == 0) break :special true;
5946 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
5947 break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
5948 }
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 }
59185957 }
5958
59195959 const is_multi = case.ast.values.len != 1 or
59205960 node_tags[case.ast.values[0]] == .switch_range;
59215961
59225962 switch (prong_src) {
5923 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(
5924 decl.nodeIndexToRelative(case.ast.values[0]),
5925 ),
5926 .multi_capture => |i| if (is_multi and i == multi_i) {
5927 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
5928 },
5929 .multi => |s| if (is_multi and s.prong == multi_i) {
5930 var item_i: u32 = 0;
5931 for (case.ast.values) |item_node| {
5932 if (node_tags[item_node] == .switch_range) continue;
5933
5934 if (item_i == s.item) return LazySrcLoc.nodeOffset(
5935 decl.nodeIndexToRelative(item_node),
5936 );
5937 item_i += 1;
5938 } else unreachable;
5939 },
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 },
5963 .scalar,
5964 .scalar_capture,
5965 .scalar_tag_capture,
5966 => |i| if (!is_multi and i == scalar_i) break case_node,
5967
5968 .multi_capture,
5969 .multi_tag_capture,
5970 => |i| if (is_multi and i == multi_i) break case_node,
5971
5972 .multi,
5973 .range,
5974 => |m| if (is_multi and m.prong == multi_i) break case_node,
5975
5976 .special,
5977 .special_capture,
5978 .special_tag_capture,
5979 => {},
59595980 }
5981
59605982 if (is_multi) {
59615983 multi_i += 1;
59625984 } else {
59635985 scalar_i += 1;
59645986 }
59655987 } 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 }
59666032 }
59676033};
59686034
src/Sema.zig+950-431
......@@ -277,12 +277,6 @@ pub const Block = struct {
277277
278278 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
286280 const ComptimeReason = union(enum) {
287281 c_import: struct {
288282 block: *Block,
......@@ -397,7 +391,6 @@ pub const Block = struct {
397391 .want_safety = parent.want_safety,
398392 .float_mode = parent.float_mode,
399393 .c_import_buf = parent.c_import_buf,
400 .switch_else_err_ty = parent.switch_else_err_ty,
401394 .error_return_trace_index = parent.error_return_trace_index,
402395 };
403396 }
......@@ -1014,14 +1007,8 @@ fn analyzeBodyInner(
10141007 .slice_start => try sema.zirSliceStart(block, inst),
10151008 .slice_length => try sema.zirSliceLength(block, inst),
10161009 .str => try sema.zirStr(block, inst),
1017 .switch_block => try sema.zirSwitchBlock(block, inst),
1018 .switch_cond => try sema.zirSwitchCond(block, inst, false),
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),
1010 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1011 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
10251012 .type_info => try sema.zirTypeInfo(block, inst),
10261013 .size_of => try sema.zirSizeOf(block, inst),
10271014 .bit_size_of => try sema.zirBitSizeOf(block, inst),
......@@ -1225,7 +1212,7 @@ fn analyzeBodyInner(
12251212 i += 1;
12261213 continue;
12271214 },
1228 .errdefer_err_code => unreachable, // never appears in a body
1215 .value_placeholder => unreachable, // never appears in a body
12291216 };
12301217 },
12311218
......@@ -2405,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
24052392 return error.AnalysisFail;
24062393}
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
24082423const align_ty = Type.u29;
24092424
24102425fn analyzeAsAlign(
......@@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1008510100 return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
1008610101}
1008710102
10088fn zirSwitchCapture(
10103/// Holds common data used when analyzing or resolving switch prong bodies,
10104/// including setting up captures.
10105const SwitchProngAnalysis = struct {
1008910106 sema: *Sema,
10090 block: *Block,
10091 inst: Zir.Inst.Index,
10092 is_multi: bool,
10093 is_ref: bool,
10094) CompileError!Air.Inst.Ref {
10095 const tracy = trace(@src());
10096 defer tracy.end();
10107 /// The block containing the `switch_block` itself.
10108 parent_block: *Block,
10109 /// The raw switch operand value (*not* the condition). Always defined.
10110 operand: Air.Inst.Ref,
10111 /// May be `undefined` if no prong has a by-ref capture.
10112 operand_ptr: Air.Inst.Ref,
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;
10099 const gpa = sema.gpa;
10100 const zir_datas = sema.code.instructions.items(.data);
10101 const capture_info = zir_datas[inst].switch_capture;
10102 const switch_info = zir_datas[capture_info.switch_inst].pl_node;
10103 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
10104 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
10105 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
10106 const cond_info = zir_datas[cond_inst].un_node;
10107 const cond_tag = sema.code.instructions.items(.tag)[cond_inst];
10108 const operand_is_ref = cond_tag == .switch_cond_ref;
10109 const operand_ptr = try sema.resolveInst(cond_info.operand);
10110 const operand_ptr_ty = sema.typeOf(operand_ptr);
10111 const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;
10112
10113 if (block.inline_case_capture != .none) {
10114 const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
10115 const resolved_item_val = try sema.resolveLazyValue(item_val);
10116 if (operand_ty.zigTypeTag(mod) == .Union) {
10117 const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?);
10118 const union_obj = mod.typeToUnion(operand_ty).?;
10119 const field_ty = union_obj.fields.values()[field_index].ty;
10120 if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
10121 if (is_ref) {
10169 if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
10170 // This prong should be unreachable!
10171 return Air.Inst.Ref.unreachable_value;
10172 }
10173
10174 sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
10175 defer assert(sema.inst_map.remove(spa.switch_block_inst));
10176
10177 return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
10178 },
10179 }
10180 }
10181
10182 /// Analyze a switch prong which may have peers at runtime.
10183 /// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed.
10184 fn analyzeProngRuntime(
10185 spa: SwitchProngAnalysis,
10186 case_block: *Block,
10187 prong_type: enum { normal, special },
10188 prong_body: []const Zir.Inst.Index,
10189 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10190 /// Must use the `scalar`, `special`, or `multi_capture` union field.
10191 raw_capture_src: Module.SwitchProngSrc,
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) {
1012210297 const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
1012310298 .pointee_type = field_ty,
1012410299 .mutable = operand_ptr_ty.ptrIsMutable(mod),
1012510300 .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
1012610301 .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
1012710302 });
10128 return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
10129 .ty = ptr_field_ty.toIntern(),
10130 .addr = .{ .field = .{
10131 .base = union_val.toIntern(),
10132 .index = field_index,
10133 } },
10134 } })).toValue());
10303 if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| {
10304 return sema.addConstant(
10305 ptr_field_ty,
10306 (try mod.intern(.{ .ptr = .{
10307 .ty = ptr_field_ty.toIntern(),
10308 .addr = .{ .field = .{
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);
1013510322 }
10136 return sema.addConstant(
10137 field_ty,
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);
10323 } else if (capture_byref) {
10324 return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
1014910325 } else {
10150 return block.addStructFieldVal(operand_ptr, field_index, field_ty);
10326 return inline_case_capture;
1015110327 }
10152 } else if (is_ref) {
10153 return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true);
10154 } else {
10155 return block.inline_case_capture;
1015610328 }
10157 }
1015810329
10159 const operand = if (operand_is_ref)
10160 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
10161 else
10162 operand_ptr;
10330 if (is_special_prong) {
10331 if (capture_byref) {
10332 return spa.operand_ptr;
10333 }
1016310334
10164 if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
10165 // It is the else/`_` prong.
10166 if (is_ref) {
10167 return operand_ptr;
10335 switch (operand_ty.zigTypeTag(mod)) {
10336 .ErrorSet => if (spa.else_error_ty) |ty| {
10337 return sema.bitCast(block, ty, spa.operand, operand_src, null);
10338 } else {
10339 try block.addUnreachable(false);
10340 return Air.Inst.Ref.unreachable_value;
10341 },
10342 else => return spa.operand,
10343 }
1016810344 }
1016910345
1017010346 switch (operand_ty.zigTypeTag(mod)) {
10171 .ErrorSet => if (block.switch_else_err_ty) |some| {
10172 return sema.bitCast(block, some, operand, operand_src, null);
10173 } else {
10174 try block.addUnreachable(false);
10175 return Air.Inst.Ref.unreachable_value;
10176 },
10177 else => return operand,
10178 }
10179 }
10347 .Union => {
10348 const union_obj = mod.typeToUnion(operand_ty).?;
10349 const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
1018010350
10181 const items = if (is_multi)
10182 switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items
10183 else
10184 &[_]Zir.Inst.Ref{
10185 switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item,
10186 };
10351 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
10352 const first_field = union_obj.fields.values()[first_field_index];
1018710353
10188 switch (operand_ty.zigTypeTag(mod)) {
10189 .Union => {
10190 const union_obj = mod.typeToUnion(operand_ty).?;
10191 const first_item = try sema.resolveInst(items[0]);
10192 // Previous switch validation ensured this will succeed
10193 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
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);
10354 const field_tys = try sema.arena.alloc(Type, case_vals.len);
10355 for (case_vals, field_tys) |item, *field_ty| {
10356 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
10357 const field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
10358 field_ty.* = union_obj.fields.values()[field_idx].ty;
10359 }
1020910360
10210 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
10211 errdefer msg.destroy(gpa);
10361 // Fast path: if all the operands are the same type already, we don't need to hit
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 } };
10214 const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first);
10215 const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };
10216 const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first);
10217 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)});
10218 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)});
10219 break :msg msg;
10367 const capture_ty = if (same_types) field_tys[0] else capture_ty: {
10368 // We need values to run PTR on, so make a bunch of undef constants.
10369 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
10370 for (dummy_captures, field_tys) |*dummy, field_ty| {
10371 dummy.* = try sema.addConstUndef(field_ty);
10372 }
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,
1022010398 };
10221 return sema.failWithOwnedErrorMsg(msg);
10222 }
10223 }
10399 };
1022410400
10225 if (is_ref) {
10226 const field_ty_ptr = try Type.ptr(sema.arena, mod, .{
10227 .pointee_type = first_field.ty,
10228 .@"addrspace" = .generic,
10229 .mutable = operand_ptr_ty.ptrIsMutable(mod),
10230 });
10401 // By-reference captures have some further restrictions which make them easier to emit
10402 if (capture_byref) {
10403 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);
10404 const capture_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
10405 .pointee_type = capture_ty,
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| {
10233 return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{
10234 .ty = field_ty_ptr.toIntern(),
10235 .addr = .{ .field = .{
10236 .base = op_ptr_val.toIntern(),
10237 .index = first_field_index,
10238 } },
10239 } })).toValue());
10412 // By-ref captures of hetereogeneous types are only allowed if each field
10413 // pointer type is in-memory coercible to the capture pointer type.
10414 if (!same_types) {
10415 for (field_tys, 0..) |field_ty, i| {
10416 const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
10417 .pointee_type = field_ty,
10418 .@"addrspace" = operand_ptr_info.@"addrspace",
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);
1024010470 }
10471
1024110472 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| {
10246 return sema.addConstant(
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().?, {});
10474 if (same_types) {
10475 return block.addStructFieldVal(spa.operand, first_field_index, capture_ty);
1026310476 }
10264 const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys());
1026510477
10266 return sema.bitCast(block, else_error_ty, operand, operand_src, null);
10267 } else {
10268 const item_ref = try sema.resolveInst(items[0]);
10269 // Previous switch validation ensured this will succeed
10270 const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable;
10478 // We may have to emit a switch block which coerces the operand to the capture type.
10479 // If we can, try to avoid that using in-memory coercions.
10480 const first_non_imc = in_mem: {
10481 for (field_tys, 0..) |field_ty, i| {
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().?);
10273 return sema.bitCast(block, item_ty, operand, operand_src, null);
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}
10492 // By-val capture with heterogeneous types which are not all in-memory coercible to
10493 // the resolved capture type. We finally have to fall back to the ugly method.
1028710494
10288fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10289 const mod = sema.mod;
10290 const zir_datas = sema.code.instructions.items(.data);
10291 const inst_data = zir_datas[inst].un_tok;
10292 const src = inst_data.src();
10495 // However, let's first track which operands are in-memory coercible. There may well
10496 // be several, and we can squash all of these cases into the same switch prong using
10497 // a simple bitcast. We'll make this the 'else' prong.
1029310498
10294 const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?];
10295 const is_ref = switch_tag == .switch_cond_ref;
10296 const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node;
10297 const operand_ptr = try sema.resolveInst(cond_data.operand);
10298 const operand_ptr_ty = sema.typeOf(operand_ptr);
10299 const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty;
10499 var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len);
10500 in_mem_coercible.unset(first_non_imc);
10501 {
10502 const next = first_non_imc + 1;
10503 for (field_tys[next..], next..) |field_ty, i| {
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) {
10302 const msg = msg: {
10303 const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{
10304 operand_ty.fmt(mod),
10305 });
10306 errdefer msg.destroy(sema.gpa);
10307 try sema.addDeclaredHereNote(msg, operand_ty);
10308 break :msg msg;
10309 };
10310 return sema.failWithOwnedErrorMsg(msg);
10311 }
10510 const capture_block_inst = try block.addInstAsIndex(.{
10511 .tag = .block,
10512 .data = .{
10513 .ty_pl = .{
10514 .ty = try sema.addType(capture_ty),
10515 .payload = undefined, // updated below
10516 },
10517 },
10518 });
1031210519
10313 return block.inline_case_capture;
10314}
10520 const prong_count = field_tys.len - in_mem_coercible.count();
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(
1031710634 sema: *Sema,
1031810635 block: *Block,
10319 inst: Zir.Inst.Index,
10320 is_ref: bool,
10636 src: LazySrcLoc,
10637 operand: Air.Inst.Ref,
1032110638) CompileError!Air.Inst.Ref {
1032210639 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;
1033110640 const operand_ty = sema.typeOf(operand);
10332
1033310641 switch (operand_ty.zigTypeTag(mod)) {
1033410642 .Type,
1033510643 .Void,
......@@ -10386,7 +10694,7 @@ fn zirSwitchCond(
1038610694
1038710695const 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 {
1039010698 const tracy = trace(@src());
1039110699 defer tracy.end();
1039210700
......@@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1040010708 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
1040110709 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
1040210710
10403 const operand = try sema.resolveInst(extra.data.operand);
10404 // AstGen guarantees that the instruction immediately following
10405 // switch_cond(_ref) is a dbg_stmt
10406 const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;
10711 const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
10712 const maybe_ptr = try sema.resolveInst(extra.data.operand);
10713 if (operand_is_ref) {
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
1040810727 var header_extra_index: usize = extra.end;
1040910728
......@@ -10414,28 +10733,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1041410733 break :blk multi_cases_len;
1041510734 } 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
1041710757 const special_prong = extra.data.bits.specialProng();
10418 const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) {
10419 .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false },
10758 const special: Special = switch (special_prong) {
10759 .none => .{
10760 .body = &.{},
10761 .end = header_extra_index,
10762 .capture = .none,
10763 .is_inline = false,
10764 .has_tag_capture = false,
10765 },
1042010766 .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]);
1042210768 const extra_body_start = header_extra_index + 1;
1042310769 break :blk .{
10424 .body = sema.code.extra[extra_body_start..][0..body_len],
10425 .end = extra_body_start + body_len,
10426 .is_inline = sema.code.extra[header_extra_index] >> 31 != 0,
10770 .body = sema.code.extra[extra_body_start..][0..info.body_len],
10771 .end = extra_body_start + info.body_len,
10772 .capture = info.capture,
10773 .is_inline = info.is_inline,
10774 .has_tag_capture = info.has_tag_capture,
1042710775 };
1042810776 },
1042910777 };
1043010778
10431 const maybe_union_ty = blk: {
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 };
10779 const maybe_union_ty = sema.typeOf(raw_operand.val);
1043910780 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
1044010781
1044110782 // Duplicate checking variables later also used for `inline else`.
......@@ -10495,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1049510836 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1049610837 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1049710838 extra_index += 1;
10498 const body_len = @truncate(u31, sema.code.extra[extra_index]);
10499 extra_index += 1;
10500 extra_index += body_len;
10839 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10840 extra_index += 1 + info.body_len;
1050110841
10502 try sema.validateSwitchItemEnum(
10842 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
1050310843 block,
1050410844 seen_enum_fields,
1050510845 &range_set,
1050610846 item_ref,
10847 operand_ty,
1050710848 src_node_offset,
1050810849 .{ .scalar = scalar_i },
10509 );
10850 ));
1051010851 }
1051110852 }
1051210853 {
......@@ -10516,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1051610857 extra_index += 1;
1051710858 const ranges_len = sema.code.extra[extra_index];
1051810859 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]);
1052010861 extra_index += 1;
1052110862 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);
1052410866 for (items, 0..) |item_ref, item_i| {
10525 try sema.validateSwitchItemEnum(
10867 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
1052610868 block,
1052710869 seen_enum_fields,
1052810870 &range_set,
1052910871 item_ref,
10872 operand_ty,
1053010873 src_node_offset,
1053110874 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10532 );
10875 ));
1053310876 }
1053410877
1053510878 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
1059210935 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1059310936 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1059410937 extra_index += 1;
10595 const body_len = @truncate(u31, sema.code.extra[extra_index]);
10596 extra_index += 1;
10597 extra_index += body_len;
10938 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
10939 extra_index += 1 + info.body_len;
1059810940
10599 try sema.validateSwitchItemError(
10941 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
1060010942 block,
1060110943 &seen_errors,
1060210944 item_ref,
10945 operand_ty,
1060310946 src_node_offset,
1060410947 .{ .scalar = scalar_i },
10605 );
10948 ));
1060610949 }
1060710950 }
1060810951 {
......@@ -10612,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1061210955 extra_index += 1;
1061310956 const ranges_len = sema.code.extra[extra_index];
1061410957 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]);
1061610959 extra_index += 1;
1061710960 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);
1062010964 for (items, 0..) |item_ref, item_i| {
10621 try sema.validateSwitchItemError(
10965 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
1062210966 block,
1062310967 &seen_errors,
1062410968 item_ref,
10969 operand_ty,
1062510970 src_node_offset,
1062610971 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10627 );
10972 ));
1062810973 }
1062910974
1063010975 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
1068711032 .dbg_block_end,
1068811033 .dbg_stmt,
1068911034 .dbg_var_val,
10690 .switch_capture,
1069111035 .ret_type,
1069211036 .as_node,
1069311037 .ret_node,
......@@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1073211076 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1073311077 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1073411078 extra_index += 1;
10735 const body_len = @truncate(u31, sema.code.extra[extra_index]);
10736 extra_index += 1;
10737 extra_index += body_len;
11079 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11080 extra_index += 1 + info.body_len;
1073811081
10739 try sema.validateSwitchItem(
11082 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
1074011083 block,
1074111084 &range_set,
1074211085 item_ref,
11086 operand_ty,
1074311087 src_node_offset,
1074411088 .{ .scalar = scalar_i },
10745 );
11089 ));
1074611090 }
1074711091 }
1074811092 {
......@@ -10752,21 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1075211096 extra_index += 1;
1075311097 const ranges_len = sema.code.extra[extra_index];
1075411098 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]);
1075611100 extra_index += 1;
1075711101 const items = sema.code.refSlice(extra_index, items_len);
1075811102 extra_index += items_len;
1075911103
11104 try case_vals.ensureUnusedCapacity(gpa, items.len);
1076011105 for (items, 0..) |item_ref, item_i| {
10761 try sema.validateSwitchItem(
11106 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
1076211107 block,
1076311108 &range_set,
1076411109 item_ref,
11110 operand_ty,
1076511111 src_node_offset,
1076611112 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10767 );
11113 ));
1076811114 }
1076911115
11116 try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len);
1077011117 var range_i: u32 = 0;
1077111118 while (range_i < ranges_len) : (range_i += 1) {
1077211119 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
1077411121 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1077511122 extra_index += 1;
1077611123
10777 try sema.validateSwitchRange(
11124 const vals = try sema.validateSwitchRange(
1077811125 block,
1077911126 &range_set,
1078011127 item_first,
1078111128 item_last,
11129 operand_ty,
1078211130 src_node_offset,
1078311131 .{ .range = .{ .prong = multi_i, .item = range_i } },
1078411132 );
11133 case_vals.appendAssumeCapacity(vals[0]);
11134 case_vals.appendAssumeCapacity(vals[1]);
1078511135 }
1078611136
10787 extra_index += body_len;
11137 extra_index += info.body_len;
1078811138 }
1078911139 }
1079011140
......@@ -10821,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1082111171 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1082211172 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1082311173 extra_index += 1;
10824 const body_len = @truncate(u31, sema.code.extra[extra_index]);
10825 extra_index += 1;
10826 extra_index += body_len;
11174 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11175 extra_index += 1 + info.body_len;
1082711176
10828 try sema.validateSwitchItemBool(
11177 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
1082911178 block,
1083011179 &true_count,
1083111180 &false_count,
1083211181 item_ref,
1083311182 src_node_offset,
1083411183 .{ .scalar = scalar_i },
10835 );
11184 ));
1083611185 }
1083711186 }
1083811187 {
......@@ -10842,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1084211191 extra_index += 1;
1084311192 const ranges_len = sema.code.extra[extra_index];
1084411193 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]);
1084611195 extra_index += 1;
1084711196 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);
1085011200 for (items, 0..) |item_ref, item_i| {
10851 try sema.validateSwitchItemBool(
11201 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
1085211202 block,
1085311203 &true_count,
1085411204 &false_count,
1085511205 item_ref,
1085611206 src_node_offset,
1085711207 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10858 );
11208 ));
1085911209 }
1086011210
1086111211 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
1090311253 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
1090411254 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1090511255 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]);
1090711257 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(
1091111261 block,
1091211262 &seen_values,
1091311263 item_ref,
11264 operand_ty,
1091411265 src_node_offset,
1091511266 .{ .scalar = scalar_i },
10916 );
11267 ));
1091711268 }
1091811269 }
1091911270 {
......@@ -10923,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1092311274 extra_index += 1;
1092411275 const ranges_len = sema.code.extra[extra_index];
1092511276 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]);
1092711278 extra_index += 1;
1092811279 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);
1093111283 for (items, 0..) |item_ref, item_i| {
10932 try sema.validateSwitchItemSparse(
11284 case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
1093311285 block,
1093411286 &seen_values,
1093511287 item_ref,
11288 operand_ty,
1093611289 src_node_offset,
1093711290 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10938 );
11291 ));
1093911292 }
1094011293
1094111294 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
1096111314 }),
1096211315 }
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
1096411328 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
1096511329 try sema.air_instructions.append(gpa, .{
1096611330 .tag = .block,
......@@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1098811352 .is_comptime = block.is_comptime,
1098911353 .comptime_reason = block.comptime_reason,
1099011354 .is_typeof = block.is_typeof,
10991 .switch_else_err_ty = else_error_ty,
1099211355 .c_import_buf = block.c_import_buf,
1099311356 .runtime_cond = block.runtime_cond,
1099411357 .runtime_loop = block.runtime_loop,
......@@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1100511368 {
1100611369 var scalar_i: usize = 0;
1100711370 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11008 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1100911371 extra_index += 1;
11010 const body_len = @truncate(u31, sema.code.extra[extra_index]);
11011 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11372 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
1101211373 extra_index += 1;
11013 const body = sema.code.extra[extra_index..][0..body_len];
11014 extra_index += 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;
11374 const body = sema.code.extra[extra_index..][0..info.body_len];
11375 extra_index += info.body_len;
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)) {
1102211380 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 );
1102411392 }
1102511393 }
1102611394 }
1102711395 {
1102811396 var multi_i: usize = 0;
11397 var case_val_idx: usize = scalar_cases_len;
1102911398 while (multi_i < multi_cases_len) : (multi_i += 1) {
1103011399 const items_len = sema.code.extra[extra_index];
1103111400 extra_index += 1;
1103211401 const ranges_len = sema.code.extra[extra_index];
1103311402 extra_index += 1;
11034 const body_len = @truncate(u31, sema.code.extra[extra_index]);
11035 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11036 extra_index += 1;
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];
11403 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11404 extra_index += 1 + items_len;
11405 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len];
1104011406
11041 for (items) |item_ref| {
11042 const item = try sema.resolveInst(item_ref);
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;
11407 const items = case_vals.items[case_val_idx..][0..items_len];
11408 case_val_idx += items_len;
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)) {
1104811414 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 );
1105011426 }
1105111427 }
1105211428
1105311429 var range_i: usize = 0;
1105411430 while (range_i < ranges_len) : (range_i += 1) {
11055 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11056 extra_index += 1;
11057 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11058 extra_index += 1;
11431 const range_items = case_vals.items[case_val_idx..][0..2];
11432 extra_index += 2;
11433 case_val_idx += 2;
1105911434
1106011435 // Validation above ensured these will succeed.
11061 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
11062 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;
11063 if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and
11064 (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty)))
11436 const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable;
11437 const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable;
11438 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
11439 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
1106511440 {
11066 if (is_inline) child_block.inline_case_capture = operand;
1106711441 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 );
1106911453 }
1107011454 }
1107111455
11072 extra_index += body_len;
11456 extra_index += info.body_len;
1107311457 }
1107411458 }
1107511459 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
11076 if (special.is_inline) child_block.inline_case_capture = operand;
1107711460 if (empty_enum) {
1107811461 return Air.Inst.Ref.void_value;
1107911462 }
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 );
1108111475 }
1108211476
1108311477 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
1109711491 const ok = try block.addUnOp(.is_named_enum_value, operand);
1109811492 try sema.addSafetyCheck(block, ok, .corrupt_switch);
1109911493 }
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 );
1110111506 }
1110211507
1110311508 if (child_block.is_comptime) {
......@@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1112311528
1112411529 var scalar_i: usize = 0;
1112511530 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11126 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1112711531 extra_index += 1;
11128 const body_len = @truncate(u31, sema.code.extra[extra_index]);
11129 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11532 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
1113011533 extra_index += 1;
11131 const body = sema.code.extra[extra_index..][0..body_len];
11132 extra_index += body_len;
11534 const body = sema.code.extra[extra_index..][0..info.body_len];
11535 extra_index += info.body_len;
1113311536
1113411537 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
1113511538 defer wip_captures.deinit();
1113611539
1113711540 case_block.instructions.shrinkRetainingCapacity(0);
1113811541 case_block.wip_capture_scope = wip_captures.scope;
11139 case_block.inline_case_capture = .none;
1114011542
11141 const item = try sema.resolveInst(item_ref);
11142 if (is_inline) case_block.inline_case_capture = item;
11543 const item = case_vals.items[scalar_i];
1114311544 // `item` is already guaranteed to be constant known.
1114411545
1114511546 const analyze_body = if (union_originally) blk: {
......@@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1115111552 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
1115211553 // nothing to do here
1115311554 } 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 );
1115511565 } else {
1115611566 _ = try case_block.addNoOp(.unreach);
1115711567 }
......@@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1117311583 defer gpa.free(prev_then_body);
1117411584
1117511585 var cases_len = scalar_cases_len;
11586 var case_val_idx: usize = scalar_cases_len;
1117611587 var multi_i: u32 = 0;
1117711588 while (multi_i < multi_cases_len) : (multi_i += 1) {
1117811589 const items_len = sema.code.extra[extra_index];
1117911590 extra_index += 1;
1118011591 const ranges_len = sema.code.extra[extra_index];
1118111592 extra_index += 1;
11182 const body_len = @truncate(u31, sema.code.extra[extra_index]);
11183 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11184 extra_index += 1;
11185 const items = sema.code.refSlice(extra_index, items_len);
11186 extra_index += items_len;
11593 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
11594 extra_index += 1 + items_len;
11595
11596 const items = case_vals.items[case_val_idx..][0..items_len];
11597 case_val_idx += items_len;
1118711598
1118811599 case_block.instructions.shrinkRetainingCapacity(0);
1118911600 case_block.wip_capture_scope = child_block.wip_capture_scope;
11190 case_block.inline_case_capture = .none;
1119111601
1119211602 // Generate all possible cases as scalar prongs.
11193 if (is_inline) {
11603 if (info.is_inline) {
1119411604 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];
1119611606 var emit_bb = false;
1119711607
1119811608 var range_i: u32 = 0;
1119911609 while (range_i < ranges_len) : (range_i += 1) {
11200 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11201 extra_index += 1;
11202 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11203 extra_index += 1;
11610 const range_items = case_vals.items[case_val_idx..][0..2];
11611 extra_index += 2;
11612 case_val_idx += 2;
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);
1120611617 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;
11207 const item_last_ref = try sema.resolveInst(last_ref);
1120811618 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
1120911619
1121011620 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({
......@@ -11217,7 +11627,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1121711627 cases_len += 1;
1121811628
1121911629 const item_ref = try sema.addConstant(operand_ty, item);
11220 case_block.inline_case_capture = item_ref;
1122111630
1122211631 case_block.instructions.shrinkRetainingCapacity(0);
1122311632 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
1123311642 };
1123411643 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
1123811656 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1123911657 cases_extra.appendAssumeCapacity(1); // items_len
1124011658 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));
1124211660 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1124311661 }
1124411662 }
1124511663
11246 for (items, 0..) |item_ref, item_i| {
11664 for (items, 0..) |item, item_i| {
1124711665 cases_len += 1;
1124811666
11249 const item = try sema.resolveInst(item_ref);
11250 case_block.inline_case_capture = item;
11251
1125211667 case_block.instructions.shrinkRetainingCapacity(0);
1125311668 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
1127011685 emit_bb = true;
1127111686
1127211687 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 );
1127411698 } else {
1127511699 _ = try case_block.addNoOp(.unreach);
1127611700 }
......@@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1127811702 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1127911703 cases_extra.appendAssumeCapacity(1); // items_len
1128011704 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));
1128211706 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1128311707 }
1128411708
11285 extra_index += body_len;
11709 extra_index += info.body_len;
1128611710 continue;
1128711711 }
1128811712
......@@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1129511719 cases_len += 1;
1129611720
1129711721 const analyze_body = if (union_originally)
11298 for (items) |item_ref| {
11299 const item = try sema.resolveInst(item_ref);
11722 for (items) |item| {
1130011723 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
1130111724 const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
1130211725 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
......@@ -11304,12 +11727,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1130411727 else
1130511728 true;
1130611729
11307 const body = sema.code.extra[extra_index..][0..body_len];
11308 extra_index += body_len;
11730 const body = sema.code.extra[extra_index..][0..info.body_len];
11731 extra_index += info.body_len;
1130911732 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
1131011733 // nothing to do here
1131111734 } 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 );
1131311745 } else {
1131411746 _ = try case_block.addNoOp(.unreach);
1131511747 }
......@@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1132011752 cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
1132111753 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
1132211754
11323 for (items) |item_ref| {
11324 const item = try sema.resolveInst(item_ref);
11755 for (items) |item| {
1132511756 cases_extra.appendAssumeCapacity(@enumToInt(item));
1132611757 }
1132711758
1132811759 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1132911760 } else {
11330 for (items) |item_ref| {
11331 const item = try sema.resolveInst(item_ref);
11761 for (items) |item| {
1133211762 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
1133311763 if (any_ok != .none) {
1133411764 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
1133911769
1134011770 var range_i: usize = 0;
1134111771 while (range_i < ranges_len) : (range_i += 1) {
11342 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11343 extra_index += 1;
11344 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11345 extra_index += 1;
11772 const range_items = case_vals.items[case_val_idx..][0..2];
11773 extra_index += 2;
11774 case_val_idx += 2;
1134611775
11347 const item_first = try sema.resolveInst(first_ref);
11348 const item_last = try sema.resolveInst(last_ref);
11776 const item_first = range_items[0];
11777 const item_last = range_items[1];
1134911778
1135011779 // operand >= first and operand <= last
1135111780 const range_first_ok = try case_block.addBinOp(
......@@ -11385,12 +11814,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1138511814 case_block.instructions.shrinkRetainingCapacity(0);
1138611815 case_block.wip_capture_scope = wip_captures.scope;
1138711816
11388 const body = sema.code.extra[extra_index..][0..body_len];
11389 extra_index += body_len;
11817 const body = sema.code.extra[extra_index..][0..info.body_len];
11818 extra_index += info.body_len;
1139011819 if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
1139111820 // nothing to do here
1139211821 } 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 );
1139411832 }
1139511833
1139611834 try wip_captures.finalize();
......@@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1143511873
1143611874 const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
1143711875 const item_ref = try sema.addConstant(operand_ty, item_val);
11438 case_block.inline_case_capture = item_ref;
1143911876
1144011877 case_block.instructions.shrinkRetainingCapacity(0);
1144111878 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
1144911886 emit_bb = true;
1145011887
1145111888 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 );
1145311899 } else {
1145411900 _ = try case_block.addNoOp(.unreach);
1145511901 }
......@@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1145711903 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1145811904 cases_extra.appendAssumeCapacity(1); // items_len
1145911905 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));
1146111907 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1146211908 }
1146311909 },
......@@ -11477,7 +11923,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1147711923 .name = error_name,
1147811924 } });
1147911925 const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
11480 case_block.inline_case_capture = item_ref;
1148111926
1148211927 case_block.instructions.shrinkRetainingCapacity(0);
1148311928 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
1148511930 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1148611931 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
1149011944 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1149111945 cases_extra.appendAssumeCapacity(1); // items_len
1149211946 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));
1149411948 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1149511949 }
1149611950 },
......@@ -11500,7 +11954,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1150011954 cases_len += 1;
1150111955
1150211956 const item_ref = try sema.addConstant(operand_ty, cur.toValue());
11503 case_block.inline_case_capture = item_ref;
1150411957
1150511958 case_block.instructions.shrinkRetainingCapacity(0);
1150611959 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
1150811961 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1150911962 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
1151311975 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1151411976 cases_extra.appendAssumeCapacity(1); // items_len
1151511977 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));
1151711979 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1151811980 }
1151911981 },
1152011982 .Bool => {
1152111983 if (true_count == 0) {
1152211984 cases_len += 1;
11523 case_block.inline_case_capture = Air.Inst.Ref.bool_true;
1152411985
1152511986 case_block.instructions.shrinkRetainingCapacity(0);
1152611987 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
1152811989 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1152911990 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
1153312003 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1153412004 cases_extra.appendAssumeCapacity(1); // items_len
1153512005 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));
1153712007 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1153812008 }
1153912009 if (false_count == 0) {
1154012010 cases_len += 1;
11541 case_block.inline_case_capture = Air.Inst.Ref.bool_false;
1154212011
1154312012 case_block.instructions.shrinkRetainingCapacity(0);
1154412013 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
1154612015 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1154712016 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
1155112029 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1155212030 cases_extra.appendAssumeCapacity(1); // items_len
1155312031 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));
1155512033 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1155612034 }
1155712035 },
......@@ -11565,7 +12043,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1156512043
1156612044 case_block.instructions.shrinkRetainingCapacity(0);
1156712045 case_block.wip_capture_scope = wip_captures.scope;
11568 case_block.inline_case_capture = .none;
1156912046
1157012047 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
1157112048 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
1158912066 {
1159012067 // nothing to do here
1159112068 } 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 );
1159312079 } else {
1159412080 // We still need a terminator in this block, but we have proven
1159512081 // that it is unreachable.
......@@ -11704,29 +12190,51 @@ const RangeSetUnhandledIterator = struct {
1170412190 }
1170512191};
1170612192
12193const ResolvedSwitchItem = struct {
12194 ref: Air.Inst.Ref,
12195 val: InternPool.Index,
12196};
1170712197fn resolveSwitchItemVal(
1170812198 sema: *Sema,
1170912199 block: *Block,
1171012200 item_ref: Zir.Inst.Ref,
12201 /// Coerce `item_ref` to this type.
12202 coerce_ty: Type,
1171112203 switch_node_offset: i32,
1171212204 switch_prong_src: Module.SwitchProngSrc,
1171312205 range_expand: Module.SwitchProngSrc.RangeExpand,
11714) CompileError!InternPool.Index {
12206) CompileError!ResolvedSwitchItem {
1171512207 const mod = sema.mod;
11716 const item = try sema.resolveInst(item_ref);
12208 const uncoerced_item = try sema.resolveInst(item_ref);
12209
1171712210 // Constructing a LazySrcLoc is costly because we only have the switch AST node.
1171812211 // Only if we know for sure we need to report a compile error do we resolve the
1171912212 // full source locations.
11720 if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| {
11721 return val.toIntern();
11722 } else |err| switch (err) {
12213
12214 const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |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) {
1172312224 error.NeededSourceLocation => {
1172412225 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
1172512226 _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");
1172612227 unreachable;
1172712228 },
1172812229 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() };
1173012238}
1173112239
1173212240fn validateSwitchRange(
......@@ -11735,31 +12243,35 @@ fn validateSwitchRange(
1173512243 range_set: *RangeSet,
1173612244 first_ref: Zir.Inst.Ref,
1173712245 last_ref: Zir.Inst.Ref,
12246 operand_ty: Type,
1173812247 src_node_offset: i32,
1173912248 switch_prong_src: Module.SwitchProngSrc,
11740) CompileError!void {
12249) CompileError![2]Air.Inst.Ref {
1174112250 const mod = sema.mod;
11742 const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
11743 const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
11744 if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) {
12251 const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first);
12252 const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last);
12253 if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) {
1174512254 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
1174612255 return sema.fail(block, src, "range start value is greater than the end value", .{});
1174712256 }
11748 const maybe_prev_src = try range_set.add(first, last, switch_prong_src);
11749 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12257 const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src);
12258 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12259 return .{ first.ref, last.ref };
1175012260}
1175112261
11752fn validateSwitchItem(
12262fn validateSwitchItemInt(
1175312263 sema: *Sema,
1175412264 block: *Block,
1175512265 range_set: *RangeSet,
1175612266 item_ref: Zir.Inst.Ref,
12267 operand_ty: Type,
1175712268 src_node_offset: i32,
1175812269 switch_prong_src: Module.SwitchProngSrc,
11759) CompileError!void {
11760 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11761 const maybe_prev_src = try range_set.add(item, item, switch_prong_src);
11762 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12270) CompileError!Air.Inst.Ref {
12271 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
12272 const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src);
12273 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
12274 return item.ref;
1176312275}
1176412276
1176512277fn validateSwitchItemEnum(
......@@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum(
1176812280 seen_fields: []?Module.SwitchProngSrc,
1176912281 range_set: *RangeSet,
1177012282 item_ref: Zir.Inst.Ref,
12283 operand_ty: Type,
1177112284 src_node_offset: i32,
1177212285 switch_prong_src: Module.SwitchProngSrc,
11773) CompileError!void {
12286) CompileError!Air.Inst.Ref {
1177412287 const ip = &sema.mod.intern_pool;
11775 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11776 const int = ip.indexToKey(item).enum_tag.int;
11777 const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse {
12288 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
12289 const int = ip.indexToKey(item.val).enum_tag.int;
12290 const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse {
1177812291 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;
1178012294 };
1178112295 const maybe_prev_src = seen_fields[field_index];
1178212296 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;
1178412299}
1178512300
1178612301fn validateSwitchItemError(
......@@ -11788,18 +12303,19 @@ fn validateSwitchItemError(
1178812303 block: *Block,
1178912304 seen_errors: *SwitchErrorSet,
1179012305 item_ref: Zir.Inst.Ref,
12306 operand_ty: Type,
1179112307 src_node_offset: i32,
1179212308 switch_prong_src: Module.SwitchProngSrc,
11793) CompileError!void {
12309) CompileError!Air.Inst.Ref {
1179412310 const ip = &sema.mod.intern_pool;
11795 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11796 // TODO: Do i need to typecheck here?
11797 const error_name = ip.indexToKey(item).err.name;
12311 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
12312 const error_name = ip.indexToKey(item.val).err.name;
1179812313 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
1179912314 prev.value
1180012315 else
1180112316 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;
1180312319}
1180412320
1180512321fn validateSwitchDupe(
......@@ -11842,19 +12358,20 @@ fn validateSwitchItemBool(
1184212358 item_ref: Zir.Inst.Ref,
1184312359 src_node_offset: i32,
1184412360 switch_prong_src: Module.SwitchProngSrc,
11845) CompileError!void {
12361) CompileError!Air.Inst.Ref {
1184612362 const mod = sema.mod;
11847 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11848 if (item.toValue().toBool()) {
12363 const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none);
12364 if (item.val.toValue().toBool()) {
1184912365 true_count.* += 1;
1185012366 } else {
1185112367 false_count.* += 1;
1185212368 }
11853 if (true_count.* + false_count.* > 2) {
11854 const block_src_decl = mod.declPtr(block.src_decl);
12369 if (true_count.* > 1 or false_count.* > 1) {
12370 const block_src_decl = sema.mod.declPtr(block.src_decl);
1185512371 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
1185612372 return sema.fail(block, src, "duplicate switch value", .{});
1185712373 }
12374 return item.ref;
1185812375}
1185912376
1186012377const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
......@@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse(
1186412381 block: *Block,
1186512382 seen_values: *ValueSrcMap,
1186612383 item_ref: Zir.Inst.Ref,
12384 operand_ty: Type,
1186712385 src_node_offset: i32,
1186812386 switch_prong_src: Module.SwitchProngSrc,
11869) CompileError!void {
11870 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11871 const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return;
11872 return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
12387) CompileError!Air.Inst.Ref {
12388 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
12389 const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref;
12390 try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
12391 unreachable;
1187312392}
1187412393
1187512394fn validateSwitchNoRange(
src/Zir.zig+45-171
......@@ -667,38 +667,9 @@ pub const Inst = struct {
667667 /// A switch expression. Uses the `pl_node` union field.
668668 /// AST node is the switch, payload is `SwitchBlock`.
669669 switch_block,
670 /// Produces the value that will be switched on. For example, for
671 /// integers, it returns the integer with no modifications. For tagged unions, it
672 /// returns the active enum tag.
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,
670 /// A switch expression. Uses the `pl_node` union field.
671 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
672 switch_block_ref,
702673 /// Given a
703674 /// *A returns *A
704675 /// *E!A returns *A
......@@ -1144,14 +1115,8 @@ pub const Inst = struct {
11441115 .typeof_log2_int_type,
11451116 .resolve_inferred_alloc,
11461117 .set_eval_branch_quota,
1147 .switch_capture,
1148 .switch_capture_ref,
1149 .switch_capture_multi,
1150 .switch_capture_multi_ref,
1151 .switch_capture_tag,
11521118 .switch_block,
1153 .switch_cond,
1154 .switch_cond_ref,
1119 .switch_block_ref,
11551120 .array_base_ptr,
11561121 .field_base_ptr,
11571122 .validate_array_init_ty,
......@@ -1438,14 +1403,8 @@ pub const Inst = struct {
14381403 .slice_length,
14391404 .import,
14401405 .typeof_log2_int_type,
1441 .switch_capture,
1442 .switch_capture_ref,
1443 .switch_capture_multi,
1444 .switch_capture_multi_ref,
1445 .switch_capture_tag,
14461406 .switch_block,
1447 .switch_cond,
1448 .switch_cond_ref,
1407 .switch_block_ref,
14491408 .array_base_ptr,
14501409 .field_base_ptr,
14511410 .struct_init_empty,
......@@ -1696,13 +1655,7 @@ pub const Inst = struct {
16961655 .err_union_code_ptr = .un_node,
16971656 .enum_literal = .str_tok,
16981657 .switch_block = .pl_node,
1699 .switch_cond = .un_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,
1658 .switch_block_ref = .pl_node,
17061659 .array_base_ptr = .un_node,
17071660 .field_base_ptr = .un_node,
17081661 .validate_array_init_ty = .pl_node,
......@@ -2028,9 +1981,10 @@ pub const Inst = struct {
20281981 /// Implements the `@inComptime` builtin.
20291982 /// `operand` is `src_node: i32`.
20301983 in_comptime,
2031 /// Used as a placeholder for the capture of an `errdefer`.
2032 /// This is replaced by Sema with the captured value.
2033 errdefer_err_code,
1984 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
1985 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
1986 /// This should never appear in a body.
1987 value_placeholder,
20341988
20351989 pub const InstData = struct {
20361990 opcode: Extended,
......@@ -2269,10 +2223,6 @@ pub const Inst = struct {
22692223 operand: Ref,
22702224 payload_index: u32,
22712225 },
2272 switch_capture: struct {
2273 switch_inst: Index,
2274 prong_index: u32,
2275 },
22762226 dbg_stmt: LineColumn,
22772227 /// Used for unary operators which reference an inst,
22782228 /// with an AST node source location.
......@@ -2342,7 +2292,6 @@ pub const Inst = struct {
23422292 bool_br,
23432293 @"unreachable",
23442294 @"break",
2345 switch_capture,
23462295 dbg_stmt,
23472296 inst_node,
23482297 str_op,
......@@ -2681,37 +2630,53 @@ pub const Inst = struct {
26812630 };
26822631
26832632 /// 0. multi_cases_len: u32 // If has_multi_cases is set.
2684 /// 1. else_body { // If has_else or has_under is set.
2685 /// body_len: u32,
2686 /// body member Index for every body_len
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.
2634 /// 2. else_body { // If has_else or has_under is set.
2635 /// info: ProngInfo,
2636 /// body member Index for every info.body_len
26872637 /// }
2688 /// 2. scalar_cases: { // for every scalar_cases_len
2638 /// 3. scalar_cases: { // for every scalar_cases_len
26892639 /// item: Ref,
2690 /// body_len: u32,
2691 /// body member Index for every body_len
2640 /// info: ProngInfo,
2641 /// body member Index for every info.body_len
26922642 /// }
2693 /// 3. multi_cases: { // for every multi_cases_len
2643 /// 4. multi_cases: { // for every multi_cases_len
26942644 /// items_len: u32,
26952645 /// ranges_len: u32,
2696 /// body_len: u32,
2646 /// info: ProngInfo,
26972647 /// item: Ref // for every items_len
26982648 /// ranges: { // for every ranges_len
26992649 /// item_first: Ref,
27002650 /// item_last: Ref,
27012651 /// }
2702 /// body member Index for every body_len
2652 /// body member Index for every info.body_len
27032653 /// }
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.
27042658 pub const SwitchBlock = struct {
2705 /// This is always a `switch_cond` or `switch_cond_ref` instruction.
2706 /// If it is a `switch_cond_ref` instruction, bits.is_ref is always true.
2707 /// If it is a `switch_cond` instruction, bits.is_ref is always false.
2708 /// Both `switch_cond` and `switch_cond_ref` return a value, not a pointer,
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.
2659 /// The operand passed to the `switch` expression. If this is a
2660 /// `switch_block`, this is the operand value; if `switch_block_ref` it
2661 /// is a pointer to the operand. `switch_block_ref` is always used if
2662 /// any prong has a byref capture.
27122663 operand: Ref,
27132664 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
27152680 pub const Bits = packed struct {
27162681 /// If true, one or more prongs have multiple items.
27172682 has_multi_cases: bool,
......@@ -2719,9 +2684,11 @@ pub const Inst = struct {
27192684 has_else: bool,
27202685 /// If true, there is an underscore prong. This is mutually exclusive with `has_else`.
27212686 has_under: bool,
2687 /// If true, at least one prong has an inline tag capture.
2688 any_has_tag_capture: bool,
27222689 scalar_cases_len: ScalarCasesLen,
27232690
2724 pub const ScalarCasesLen = u29;
2691 pub const ScalarCasesLen = u28;
27252692
27262693 pub fn specialProng(bits: Bits) SpecialProng {
27272694 const has_else: u2 = @boolToInt(bits.has_else);
......@@ -2735,103 +2702,10 @@ pub const Inst = struct {
27352702 }
27362703 };
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
27842705 pub const MultiProng = struct {
27852706 items: []const Ref,
27862707 body: []const Index,
27872708 };
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 }
28352709 };
28362710
28372711 pub const Field = struct {
src/print_zir.zig+42-31
......@@ -222,8 +222,6 @@ const Writer = struct {
222222 .bit_reverse,
223223 .@"resume",
224224 .@"await",
225 .switch_cond,
226 .switch_cond_ref,
227225 .array_base_ptr,
228226 .field_base_ptr,
229227 .validate_struct_init_ty,
......@@ -235,7 +233,6 @@ const Writer = struct {
235233 .ref,
236234 .ret_implicit,
237235 .closure_capture,
238 .switch_capture_tag,
239236 => try self.writeUnTok(stream, inst),
240237
241238 .bool_br_and,
......@@ -389,7 +386,9 @@ const Writer = struct {
389386 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
390387 .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
394393 .field_ptr,
395394 .field_ptr_init,
......@@ -436,12 +435,6 @@ const Writer = struct {
436435
437436 .@"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
445438 .dbg_stmt => try self.writeDbgStmt(stream, inst),
446439
447440 .dbg_block_begin,
......@@ -469,7 +462,7 @@ const Writer = struct {
469462 .breakpoint,
470463 .c_va_start,
471464 .in_comptime,
472 .errdefer_err_code,
465 .value_placeholder,
473466 => try self.writeExtNode(stream, extended),
474467
475468 .builtin_src => {
......@@ -1903,8 +1896,19 @@ const Writer = struct {
19031896 break :blk multi_cases_len;
19041897 } 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
19061905 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
19081912 self.indent += 2;
19091913
19101914 else_prong: {
......@@ -1915,15 +1919,20 @@ const Writer = struct {
19151919 else => break :else_prong,
19161920 };
19171921
1918 const body_len = @truncate(u31, self.code.extra[extra_index]);
1919 const inline_text = if (self.code.extra[extra_index] >> 31 != 0) "inline " else "";
1922 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
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 "";
19201929 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];
19221931 extra_index += body.len;
19231932
19241933 try stream.writeAll(",\n");
19251934 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 });
19271936 try self.writeBracedBody(stream, body);
19281937 }
19291938
......@@ -1933,15 +1942,19 @@ const Writer = struct {
19331942 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
19341943 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
19351944 extra_index += 1;
1936 const body_len = @truncate(u31, self.code.extra[extra_index]);
1937 const is_inline = self.code.extra[extra_index] >> 31 != 0;
1945 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
19381946 extra_index += 1;
1939 const body = self.code.extra[extra_index..][0..body_len];
1940 extra_index += body_len;
1947 const body = self.code.extra[extra_index..][0..info.body_len];
1948 extra_index += info.body_len;
19411949
19421950 try stream.writeAll(",\n");
19431951 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 ");
19451958 try self.writeInstRef(stream, item_ref);
19461959 try stream.writeAll(" => ");
19471960 try self.writeBracedBody(stream, body);
......@@ -1954,15 +1967,19 @@ const Writer = struct {
19541967 extra_index += 1;
19551968 const ranges_len = self.code.extra[extra_index];
19561969 extra_index += 1;
1957 const body_len = @truncate(u31, self.code.extra[extra_index]);
1958 const is_inline = self.code.extra[extra_index] >> 31 != 0;
1970 const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, self.code.extra[extra_index]);
19591971 extra_index += 1;
19601972 const items = self.code.refSlice(extra_index, items_len);
19611973 extra_index += items_len;
19621974
19631975 try stream.writeAll(",\n");
19641976 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
19671984 for (items, 0..) |item_ref, item_i| {
19681985 if (item_i != 0) try stream.writeAll(", ");
......@@ -1984,8 +2001,8 @@ const Writer = struct {
19842001 try self.writeInstRef(stream, item_last);
19852002 }
19862003
1987 const body = self.code.extra[extra_index..][0..body_len];
1988 extra_index += body_len;
2004 const body = self.code.extra[extra_index..][0..info.body_len];
2005 extra_index += info.body_len;
19892006 try stream.writeAll(" => ");
19902007 try self.writeBracedBody(stream, body);
19912008 }
......@@ -2437,12 +2454,6 @@ const Writer = struct {
24372454 try self.writeSrc(stream, src);
24382455 }
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
24462457 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
24472458 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt;
24482459 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
test/behavior/switch.zig+68
......@@ -1,5 +1,6 @@
11const builtin = @import("builtin");
22const std = @import("std");
3const assert = std.debug.assert;
34const expect = std.testing.expect;
45const expectError = std.testing.expectError;
56const expectEqual = std.testing.expectEqual;
......@@ -717,3 +718,70 @@ test "comptime inline switch" {
717718
718719 try expectEqual(u32, value);
719720}
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 {
44 C: bool,
55};
66export fn entry() void {
7 const a = Payload { .A = 1234 };
7 const a = Payload{ .A = 1234 };
88 foo(&a);
99}
1010fn foo(a: *const Payload) void {
1111 switch (a.*) {
12 Payload.A => {},
12 .A => {},
1313 else => unreachable,
1414 }
1515}