authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-05 23:04:34+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 12:50:49+01:00
logcebd80032a2dcc9f516f8183d1bfade5d1f12e45
treef4c669061d753840d12d8dbb4b232e5f2d4bafb0
parenta377bf87ce6f021f958087bcf080425845a7bae6
signaturelock-open Commit is signed but in an unrecognized format.

Move switch case value coercion from AstGen to Sema

This is in preparation for #2473. Also fixes a bug where switching on bools allows invalid case combinations.

2 files changed, 150 insertions(+), 104 deletions(-)

src/AstGen.zig+1-3
......@@ -6837,9 +6837,7 @@ fn switchExpr(
68376837 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
68386838 // Sema expects a dbg_stmt immediately after switch_cond(_ref)
68396839 try emitDbgStmt(parent_gz, operand_lc);
6840 // We need the type of the operand to use as the result location for all the prong items.
6841 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node);
6842 const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } };
6840 const item_ri: ResultInfo = .{ .rl = .none };
68436841
68446842 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
68456843 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with
src/Sema.zig+149-101
......@@ -10099,6 +10099,8 @@ fn zirSwitchCapture(
1009910099 const switch_info = zir_datas[capture_info.switch_inst].pl_node;
1010010100 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
1010110101 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
10102 const cond = try sema.resolveInst(switch_extra.data.operand);
10103 const cond_ty = sema.typeOf(cond);
1010210104 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
1010310105 const cond_info = zir_datas[cond_inst].un_node;
1010410106 const cond_tag = sema.code.instructions.items(.tag)[cond_inst];
......@@ -10175,6 +10177,8 @@ fn zirSwitchCapture(
1017510177 }
1017610178 }
1017710179
10180 // Note that these are the *uncasted* prong items.
10181 // Also note that items from ranges are not included so this only works for non-ranged types.
1017810182 const items = switch_extra.data.getProng(sema.code, switch_extra.end, capture_info.prong_index).items;
1017910183
1018010184 switch (operand_ty.zigTypeTag(mod)) {
......@@ -10182,7 +10186,8 @@ fn zirSwitchCapture(
1018210186 const union_obj = mod.typeToUnion(operand_ty).?;
1018310187 const first_item = try sema.resolveInst(items[0]);
1018410188 // Previous switch validation ensured this will succeed
10185 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
10189 const first_item_coerced = try sema.coerce(block, cond_ty, first_item, .unneeded);
10190 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item_coerced, "") catch unreachable;
1018610191
1018710192 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
1018810193 const first_field = union_obj.fields.values()[first_field_index];
......@@ -10190,7 +10195,8 @@ fn zirSwitchCapture(
1019010195 for (items[1..], 0..) |item, i| {
1019110196 const item_ref = try sema.resolveInst(item);
1019210197 // Previous switch validation ensured this will succeed
10193 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
10198 const item_coerced = try sema.coerce(block, cond_ty, item_ref, .unneeded);
10199 const item_val = sema.resolveConstValue(block, .unneeded, item_coerced, "") catch unreachable;
1019410200
1019510201 const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?;
1019610202 const field = union_obj.fields.values()[field_index];
......@@ -10406,6 +10412,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1040610412 break :blk multi_cases_len;
1040710413 } else 0;
1040810414
10415 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
10416 defer case_vals.deinit(gpa);
10417
1040910418 const special_prong = extra.data.bits.specialProng();
1041010419 const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) {
1041110420 .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false },
......@@ -10491,14 +10500,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1049110500 extra_index += 1;
1049210501 extra_index += body_len;
1049310502
10494 try sema.validateSwitchItemEnum(
10503 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
1049510504 block,
1049610505 seen_enum_fields,
1049710506 &range_set,
1049810507 item_ref,
10508 operand_ty,
1049910509 src_node_offset,
1050010510 .{ .scalar = scalar_i },
10501 );
10511 ));
1050210512 }
1050310513 }
1050410514 {
......@@ -10513,15 +10523,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1051310523 const items = sema.code.refSlice(extra_index, items_len);
1051410524 extra_index += items_len + body_len;
1051510525
10526 try case_vals.ensureUnusedCapacity(gpa, items.len);
1051610527 for (items, 0..) |item_ref, item_i| {
10517 try sema.validateSwitchItemEnum(
10528 case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
1051810529 block,
1051910530 seen_enum_fields,
1052010531 &range_set,
1052110532 item_ref,
10533 operand_ty,
1052210534 src_node_offset,
1052310535 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10524 );
10536 ));
1052510537 }
1052610538
1052710539 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
......@@ -10588,13 +10600,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1058810600 extra_index += 1;
1058910601 extra_index += body_len;
1059010602
10591 try sema.validateSwitchItemError(
10603 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
1059210604 block,
1059310605 &seen_errors,
1059410606 item_ref,
10607 operand_ty,
1059510608 src_node_offset,
1059610609 .{ .scalar = scalar_i },
10597 );
10610 ));
1059810611 }
1059910612 }
1060010613 {
......@@ -10609,14 +10622,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1060910622 const items = sema.code.refSlice(extra_index, items_len);
1061010623 extra_index += items_len + body_len;
1061110624
10625 try case_vals.ensureUnusedCapacity(gpa, items.len);
1061210626 for (items, 0..) |item_ref, item_i| {
10613 try sema.validateSwitchItemError(
10627 case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
1061410628 block,
1061510629 &seen_errors,
1061610630 item_ref,
10631 operand_ty,
1061710632 src_node_offset,
1061810633 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10619 );
10634 ));
1062010635 }
1062110636
1062210637 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
......@@ -10728,13 +10743,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1072810743 extra_index += 1;
1072910744 extra_index += body_len;
1073010745
10731 try sema.validateSwitchItem(
10746 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
1073210747 block,
1073310748 &range_set,
1073410749 item_ref,
10750 operand_ty,
1073510751 src_node_offset,
1073610752 .{ .scalar = scalar_i },
10737 );
10753 ));
1073810754 }
1073910755 }
1074010756 {
......@@ -10749,16 +10765,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1074910765 const items = sema.code.refSlice(extra_index, items_len);
1075010766 extra_index += items_len;
1075110767
10768 try case_vals.ensureUnusedCapacity(gpa, items.len);
1075210769 for (items, 0..) |item_ref, item_i| {
10753 try sema.validateSwitchItem(
10770 case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
1075410771 block,
1075510772 &range_set,
1075610773 item_ref,
10774 operand_ty,
1075710775 src_node_offset,
1075810776 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10759 );
10777 ));
1076010778 }
1076110779
10780 try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len);
1076210781 var range_i: u32 = 0;
1076310782 while (range_i < ranges_len) : (range_i += 1) {
1076410783 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
......@@ -10766,14 +10785,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1076610785 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1076710786 extra_index += 1;
1076810787
10769 try sema.validateSwitchRange(
10788 const vals = try sema.validateSwitchRange(
1077010789 block,
1077110790 &range_set,
1077210791 item_first,
1077310792 item_last,
10793 operand_ty,
1077410794 src_node_offset,
1077510795 .{ .range = .{ .prong = multi_i, .item = range_i } },
1077610796 );
10797 case_vals.appendAssumeCapacity(vals[0]);
10798 case_vals.appendAssumeCapacity(vals[1]);
1077710799 }
1077810800
1077910801 extra_index += body_len;
......@@ -10817,14 +10839,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1081710839 extra_index += 1;
1081810840 extra_index += body_len;
1081910841
10820 try sema.validateSwitchItemBool(
10842 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
1082110843 block,
1082210844 &true_count,
1082310845 &false_count,
1082410846 item_ref,
1082510847 src_node_offset,
1082610848 .{ .scalar = scalar_i },
10827 );
10849 ));
1082810850 }
1082910851 }
1083010852 {
......@@ -10839,15 +10861,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1083910861 const items = sema.code.refSlice(extra_index, items_len);
1084010862 extra_index += items_len + body_len;
1084110863
10864 try case_vals.ensureUnusedCapacity(gpa, items.len);
1084210865 for (items, 0..) |item_ref, item_i| {
10843 try sema.validateSwitchItemBool(
10866 case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
1084410867 block,
1084510868 &true_count,
1084610869 &false_count,
1084710870 item_ref,
1084810871 src_node_offset,
1084910872 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10850 );
10873 ));
1085110874 }
1085210875
1085310876 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
......@@ -10899,13 +10922,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1089910922 extra_index += 1;
1090010923 extra_index += body_len;
1090110924
10902 try sema.validateSwitchItemSparse(
10925 case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
1090310926 block,
1090410927 &seen_values,
1090510928 item_ref,
10929 operand_ty,
1090610930 src_node_offset,
1090710931 .{ .scalar = scalar_i },
10908 );
10932 ));
1090910933 }
1091010934 }
1091110935 {
......@@ -10920,14 +10944,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1092010944 const items = sema.code.refSlice(extra_index, items_len);
1092110945 extra_index += items_len + body_len;
1092210946
10947 try case_vals.ensureUnusedCapacity(gpa, items.len);
1092310948 for (items, 0..) |item_ref, item_i| {
10924 try sema.validateSwitchItemSparse(
10949 case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
1092510950 block,
1092610951 &seen_values,
1092710952 item_ref,
10953 operand_ty,
1092810954 src_node_offset,
1092910955 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
10930 );
10956 ));
1093110957 }
1093210958
1093310959 try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
......@@ -10997,7 +11023,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1099711023 {
1099811024 var scalar_i: usize = 0;
1099911025 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11000 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1100111026 extra_index += 1;
1100211027 const body_len = @truncate(u31, sema.code.extra[extra_index]);
1100311028 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
......@@ -11005,8 +11030,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1100511030 const body = sema.code.extra[extra_index..][0..body_len];
1100611031 extra_index += body_len;
1100711032
11008 const item = try sema.resolveInst(item_ref);
11009 // Validation above ensured these will succeed.
11033 const item = case_vals.items[scalar_i];
1101011034 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
1101111035 if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
1101211036 if (is_inline) child_block.inline_case_capture = operand;
......@@ -11018,6 +11042,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1101811042 }
1101911043 {
1102011044 var multi_i: usize = 0;
11045 var case_val_idx: usize = scalar_cases_len;
1102111046 while (multi_i < multi_cases_len) : (multi_i += 1) {
1102211047 const items_len = sema.code.extra[extra_index];
1102311048 extra_index += 1;
......@@ -11025,13 +11050,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1102511050 extra_index += 1;
1102611051 const body_len = @truncate(u31, sema.code.extra[extra_index]);
1102711052 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11028 extra_index += 1;
11029 const items = sema.code.refSlice(extra_index, items_len);
11030 extra_index += items_len;
11053 extra_index += 1 + items_len;
1103111054 const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
1103211055
11033 for (items) |item_ref| {
11034 const item = try sema.resolveInst(item_ref);
11056 const items = case_vals.items[case_val_idx..][0..items_len];
11057 case_val_idx += items_len;
11058
11059 for (items) |item| {
1103511060 // Validation above ensured these will succeed.
1103611061 const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable;
1103711062 if (resolved_operand_val.eql(item_val, operand_ty, mod)) {
......@@ -11044,16 +11069,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1104411069
1104511070 var range_i: usize = 0;
1104611071 while (range_i < ranges_len) : (range_i += 1) {
11047 const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11048 extra_index += 1;
11049 const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11050 extra_index += 1;
11072 const range_items = case_vals.items[case_val_idx..][0..2];
11073 extra_index += 2;
11074 case_val_idx += 2;
1105111075
1105211076 // Validation above ensured these will succeed.
11053 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
11054 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;
11055 if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and
11056 (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty)))
11077 const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable;
11078 const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable;
11079 if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
11080 (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
1105711081 {
1105811082 if (is_inline) child_block.inline_case_capture = operand;
1105911083 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
......@@ -11115,7 +11139,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1111511139
1111611140 var scalar_i: usize = 0;
1111711141 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
11118 const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1111911142 extra_index += 1;
1112011143 const body_len = @truncate(u31, sema.code.extra[extra_index]);
1112111144 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
......@@ -11130,7 +11153,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1113011153 case_block.wip_capture_scope = wip_captures.scope;
1113111154 case_block.inline_case_capture = .none;
1113211155
11133 const item = try sema.resolveInst(item_ref);
11156 const item = case_vals.items[scalar_i];
1113411157 if (is_inline) case_block.inline_case_capture = item;
1113511158 // `item` is already guaranteed to be constant known.
1113611159
......@@ -11165,6 +11188,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1116511188 defer gpa.free(prev_then_body);
1116611189
1116711190 var cases_len = scalar_cases_len;
11191 var case_val_idx: usize = scalar_cases_len;
1116811192 var multi_i: u32 = 0;
1116911193 while (multi_i < multi_cases_len) : (multi_i += 1) {
1117011194 const items_len = sema.code.extra[extra_index];
......@@ -11173,9 +11197,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1117311197 extra_index += 1;
1117411198 const body_len = @truncate(u31, sema.code.extra[extra_index]);
1117511199 const is_inline = sema.code.extra[extra_index] >> 31 != 0;
11176 extra_index += 1;
11177 const items = sema.code.refSlice(extra_index, items_len);
11178 extra_index += items_len;
11200 extra_index += 1 + items_len;
11201
11202 const items = case_vals.items[case_val_idx..][0..items_len];
11203 case_val_idx += items_len;
1117911204
1118011205 case_block.instructions.shrinkRetainingCapacity(0);
1118111206 case_block.wip_capture_scope = child_block.wip_capture_scope;
......@@ -11189,14 +11214,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1118911214
1119011215 var range_i: u32 = 0;
1119111216 while (range_i < ranges_len) : (range_i += 1) {
11192 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11193 extra_index += 1;
11194 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11195 extra_index += 1;
11217 const range_items = case_vals.items[case_val_idx..][0..2];
11218 extra_index += 2;
11219 case_val_idx += 2;
11220
11221 const item_first_ref = range_items[0];
11222 const item_last_ref = range_items[1];
1119611223
11197 const item_first_ref = try sema.resolveInst(first_ref);
1119811224 var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;
11199 const item_last_ref = try sema.resolveInst(last_ref);
1120011225 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
1120111226
1120211227 while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({
......@@ -11235,10 +11260,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1123511260 }
1123611261 }
1123711262
11238 for (items, 0..) |item_ref, item_i| {
11263 for (items, 0..) |item, item_i| {
1123911264 cases_len += 1;
1124011265
11241 const item = try sema.resolveInst(item_ref);
1124211266 case_block.inline_case_capture = item;
1124311267
1124411268 case_block.instructions.shrinkRetainingCapacity(0);
......@@ -11287,8 +11311,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1128711311 cases_len += 1;
1128811312
1128911313 const analyze_body = if (union_originally)
11290 for (items) |item_ref| {
11291 const item = try sema.resolveInst(item_ref);
11314 for (items) |item| {
1129211315 const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
1129311316 const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
1129411317 if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
......@@ -11312,15 +11335,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1131211335 cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
1131311336 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
1131411337
11315 for (items) |item_ref| {
11316 const item = try sema.resolveInst(item_ref);
11338 for (items) |item| {
1131711339 cases_extra.appendAssumeCapacity(@enumToInt(item));
1131811340 }
1131911341
1132011342 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
1132111343 } else {
11322 for (items) |item_ref| {
11323 const item = try sema.resolveInst(item_ref);
11344 for (items) |item| {
1132411345 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
1132511346 if (any_ok != .none) {
1132611347 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
......@@ -11331,13 +11352,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1133111352
1133211353 var range_i: usize = 0;
1133311354 while (range_i < ranges_len) : (range_i += 1) {
11334 const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11335 extra_index += 1;
11336 const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
11337 extra_index += 1;
11355 const range_items = case_vals.items[case_val_idx..][0..2];
11356 extra_index += 2;
11357 case_val_idx += 2;
1133811358
11339 const item_first = try sema.resolveInst(first_ref);
11340 const item_last = try sema.resolveInst(last_ref);
11359 const item_first = range_items[0];
11360 const item_last = range_items[1];
1134111361
1134211362 // operand >= first and operand <= last
1134311363 const range_first_ok = try case_block.addBinOp(
......@@ -11696,29 +11716,46 @@ const RangeSetUnhandledIterator = struct {
1169611716 }
1169711717};
1169811718
11719const ResolvedSwitchItem = struct {
11720 ref: Air.Inst.Ref,
11721 val: InternPool.Index,
11722};
1169911723fn resolveSwitchItemVal(
1170011724 sema: *Sema,
1170111725 block: *Block,
1170211726 item_ref: Zir.Inst.Ref,
11727 /// Coerce `item_ref` to this type.
11728 coerce_ty: Type,
1170311729 switch_node_offset: i32,
1170411730 switch_prong_src: Module.SwitchProngSrc,
1170511731 range_expand: Module.SwitchProngSrc.RangeExpand,
11706) CompileError!InternPool.Index {
11732) CompileError!ResolvedSwitchItem {
1170711733 const mod = sema.mod;
11708 const item = try sema.resolveInst(item_ref);
11734 const uncoerced_item = try sema.resolveInst(item_ref);
11735
1170911736 // Constructing a LazySrcLoc is costly because we only have the switch AST node.
1171011737 // Only if we know for sure we need to report a compile error do we resolve the
1171111738 // full source locations.
11712 if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| {
11713 return val.toIntern();
11714 } else |err| switch (err) {
11739
11740 const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |err| switch (err) {
11741 error.NeededSourceLocation => {
11742 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
11743 _ = try sema.coerce(block, coerce_ty, uncoerced_item, src);
11744 unreachable;
11745 },
11746 else => |e| return e,
11747 };
11748
11749 const val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch |err| switch (err) {
1171511750 error.NeededSourceLocation => {
1171611751 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
1171711752 _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");
1171811753 unreachable;
1171911754 },
1172011755 else => |e| return e,
11721 }
11756 };
11757
11758 return .{ .ref = item, .val = val.toIntern() };
1172211759}
1172311760
1172411761fn validateSwitchRange(
......@@ -11727,31 +11764,35 @@ fn validateSwitchRange(
1172711764 range_set: *RangeSet,
1172811765 first_ref: Zir.Inst.Ref,
1172911766 last_ref: Zir.Inst.Ref,
11767 operand_ty: Type,
1173011768 src_node_offset: i32,
1173111769 switch_prong_src: Module.SwitchProngSrc,
11732) CompileError!void {
11770) CompileError![2]Air.Inst.Ref {
1173311771 const mod = sema.mod;
11734 const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
11735 const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
11736 if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) {
11772 const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first);
11773 const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last);
11774 if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) {
1173711775 const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
1173811776 return sema.fail(block, src, "range start value is greater than the end value", .{});
1173911777 }
11740 const maybe_prev_src = try range_set.add(first, last, switch_prong_src);
11741 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11778 const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src);
11779 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11780 return .{ first.ref, last.ref };
1174211781}
1174311782
11744fn validateSwitchItem(
11783fn validateSwitchItemInt(
1174511784 sema: *Sema,
1174611785 block: *Block,
1174711786 range_set: *RangeSet,
1174811787 item_ref: Zir.Inst.Ref,
11788 operand_ty: Type,
1174911789 src_node_offset: i32,
1175011790 switch_prong_src: Module.SwitchProngSrc,
11751) CompileError!void {
11752 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11753 const maybe_prev_src = try range_set.add(item, item, switch_prong_src);
11754 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11791) CompileError!Air.Inst.Ref {
11792 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11793 const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src);
11794 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11795 return item.ref;
1175511796}
1175611797
1175711798fn validateSwitchItemEnum(
......@@ -11760,19 +11801,22 @@ fn validateSwitchItemEnum(
1176011801 seen_fields: []?Module.SwitchProngSrc,
1176111802 range_set: *RangeSet,
1176211803 item_ref: Zir.Inst.Ref,
11804 operand_ty: Type,
1176311805 src_node_offset: i32,
1176411806 switch_prong_src: Module.SwitchProngSrc,
11765) CompileError!void {
11807) CompileError!Air.Inst.Ref {
1176611808 const ip = &sema.mod.intern_pool;
11767 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11768 const int = ip.indexToKey(item).enum_tag.int;
11769 const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse {
11809 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11810 const int = ip.indexToKey(item.val).enum_tag.int;
11811 const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse {
1177011812 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
11771 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11813 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11814 return item.ref;
1177211815 };
1177311816 const maybe_prev_src = seen_fields[field_index];
1177411817 seen_fields[field_index] = switch_prong_src;
11775 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11818 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11819 return item.ref;
1177611820}
1177711821
1177811822fn validateSwitchItemError(
......@@ -11780,18 +11824,19 @@ fn validateSwitchItemError(
1178011824 block: *Block,
1178111825 seen_errors: *SwitchErrorSet,
1178211826 item_ref: Zir.Inst.Ref,
11827 operand_ty: Type,
1178311828 src_node_offset: i32,
1178411829 switch_prong_src: Module.SwitchProngSrc,
11785) CompileError!void {
11830) CompileError!Air.Inst.Ref {
1178611831 const ip = &sema.mod.intern_pool;
11787 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11788 // TODO: Do i need to typecheck here?
11789 const error_name = ip.indexToKey(item).err.name;
11832 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11833 const error_name = ip.indexToKey(item.val).err.name;
1179011834 const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
1179111835 prev.value
1179211836 else
1179311837 null;
11794 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11838 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
11839 return item.ref;
1179511840}
1179611841
1179711842fn validateSwitchDupe(
......@@ -11834,19 +11879,20 @@ fn validateSwitchItemBool(
1183411879 item_ref: Zir.Inst.Ref,
1183511880 src_node_offset: i32,
1183611881 switch_prong_src: Module.SwitchProngSrc,
11837) CompileError!void {
11882) CompileError!Air.Inst.Ref {
1183811883 const mod = sema.mod;
11839 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11840 if (item.toValue().toBool()) {
11884 const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none);
11885 if (item.val.toValue().toBool()) {
1184111886 true_count.* += 1;
1184211887 } else {
1184311888 false_count.* += 1;
1184411889 }
11845 if (true_count.* + false_count.* > 2) {
11846 const block_src_decl = mod.declPtr(block.src_decl);
11890 if (true_count.* > 1 or false_count.* > 1) {
11891 const block_src_decl = sema.mod.declPtr(block.src_decl);
1184711892 const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
1184811893 return sema.fail(block, src, "duplicate switch value", .{});
1184911894 }
11895 return item.ref;
1185011896}
1185111897
1185211898const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
......@@ -11856,12 +11902,14 @@ fn validateSwitchItemSparse(
1185611902 block: *Block,
1185711903 seen_values: *ValueSrcMap,
1185811904 item_ref: Zir.Inst.Ref,
11905 operand_ty: Type,
1185911906 src_node_offset: i32,
1186011907 switch_prong_src: Module.SwitchProngSrc,
11861) CompileError!void {
11862 const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
11863 const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return;
11864 return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
11908) CompileError!Air.Inst.Ref {
11909 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
11910 const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref;
11911 try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
11912 unreachable;
1186511913}
1186611914
1186711915fn validateSwitchNoRange(