| ... | ... | @@ -10099,6 +10099,8 @@ fn zirSwitchCapture( |
| 10099 | 10099 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| 10100 | 10100 | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); |
| 10101 | 10101 | 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); |
| 10102 | 10104 | const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; |
| 10103 | 10105 | const cond_info = zir_datas[cond_inst].un_node; |
| 10104 | 10106 | const cond_tag = sema.code.instructions.items(.tag)[cond_inst]; |
| ... | ... | @@ -10175,6 +10177,8 @@ fn zirSwitchCapture( |
| 10175 | 10177 | } |
| 10176 | 10178 | } |
| 10177 | 10179 | |
| 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. |
| 10178 | 10182 | const items = switch_extra.data.getProng(sema.code, switch_extra.end, capture_info.prong_index).items; |
| 10179 | 10183 | |
| 10180 | 10184 | switch (operand_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -10182,7 +10186,8 @@ fn zirSwitchCapture( |
| 10182 | 10186 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10183 | 10187 | const first_item = try sema.resolveInst(items[0]); |
| 10184 | 10188 | // 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; |
| 10186 | 10191 | |
| 10187 | 10192 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10188 | 10193 | const first_field = union_obj.fields.values()[first_field_index]; |
| ... | ... | @@ -10190,7 +10195,8 @@ fn zirSwitchCapture( |
| 10190 | 10195 | for (items[1..], 0..) |item, i| { |
| 10191 | 10196 | const item_ref = try sema.resolveInst(item); |
| 10192 | 10197 | // 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; |
| 10194 | 10200 | |
| 10195 | 10201 | const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?; |
| 10196 | 10202 | const field = union_obj.fields.values()[field_index]; |
| ... | ... | @@ -10406,6 +10412,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10406 | 10412 | break :blk multi_cases_len; |
| 10407 | 10413 | } else 0; |
| 10408 | 10414 | |
| 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 | |
| 10409 | 10418 | const special_prong = extra.data.bits.specialProng(); |
| 10410 | 10419 | const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) { |
| 10411 | 10420 | .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, |
| ... | ... | @@ -10491,14 +10500,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10491 | 10500 | extra_index += 1; |
| 10492 | 10501 | extra_index += body_len; |
| 10493 | 10502 | |
| 10494 | | try sema.validateSwitchItemEnum( |
| 10503 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10495 | 10504 | block, |
| 10496 | 10505 | seen_enum_fields, |
| 10497 | 10506 | &range_set, |
| 10498 | 10507 | item_ref, |
| 10508 | operand_ty, |
| 10499 | 10509 | src_node_offset, |
| 10500 | 10510 | .{ .scalar = scalar_i }, |
| 10501 | | ); |
| 10511 | )); |
| 10502 | 10512 | } |
| 10503 | 10513 | } |
| 10504 | 10514 | { |
| ... | ... | @@ -10513,15 +10523,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10513 | 10523 | const items = sema.code.refSlice(extra_index, items_len); |
| 10514 | 10524 | extra_index += items_len + body_len; |
| 10515 | 10525 | |
| 10526 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10516 | 10527 | for (items, 0..) |item_ref, item_i| { |
| 10517 | | try sema.validateSwitchItemEnum( |
| 10528 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10518 | 10529 | block, |
| 10519 | 10530 | seen_enum_fields, |
| 10520 | 10531 | &range_set, |
| 10521 | 10532 | item_ref, |
| 10533 | operand_ty, |
| 10522 | 10534 | src_node_offset, |
| 10523 | 10535 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10524 | | ); |
| 10536 | )); |
| 10525 | 10537 | } |
| 10526 | 10538 | |
| 10527 | 10539 | 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 |
| 10588 | 10600 | extra_index += 1; |
| 10589 | 10601 | extra_index += body_len; |
| 10590 | 10602 | |
| 10591 | | try sema.validateSwitchItemError( |
| 10603 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10592 | 10604 | block, |
| 10593 | 10605 | &seen_errors, |
| 10594 | 10606 | item_ref, |
| 10607 | operand_ty, |
| 10595 | 10608 | src_node_offset, |
| 10596 | 10609 | .{ .scalar = scalar_i }, |
| 10597 | | ); |
| 10610 | )); |
| 10598 | 10611 | } |
| 10599 | 10612 | } |
| 10600 | 10613 | { |
| ... | ... | @@ -10609,14 +10622,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10609 | 10622 | const items = sema.code.refSlice(extra_index, items_len); |
| 10610 | 10623 | extra_index += items_len + body_len; |
| 10611 | 10624 | |
| 10625 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10612 | 10626 | for (items, 0..) |item_ref, item_i| { |
| 10613 | | try sema.validateSwitchItemError( |
| 10627 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10614 | 10628 | block, |
| 10615 | 10629 | &seen_errors, |
| 10616 | 10630 | item_ref, |
| 10631 | operand_ty, |
| 10617 | 10632 | src_node_offset, |
| 10618 | 10633 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10619 | | ); |
| 10634 | )); |
| 10620 | 10635 | } |
| 10621 | 10636 | |
| 10622 | 10637 | 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 |
| 10728 | 10743 | extra_index += 1; |
| 10729 | 10744 | extra_index += body_len; |
| 10730 | 10745 | |
| 10731 | | try sema.validateSwitchItem( |
| 10746 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10732 | 10747 | block, |
| 10733 | 10748 | &range_set, |
| 10734 | 10749 | item_ref, |
| 10750 | operand_ty, |
| 10735 | 10751 | src_node_offset, |
| 10736 | 10752 | .{ .scalar = scalar_i }, |
| 10737 | | ); |
| 10753 | )); |
| 10738 | 10754 | } |
| 10739 | 10755 | } |
| 10740 | 10756 | { |
| ... | ... | @@ -10749,16 +10765,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10749 | 10765 | const items = sema.code.refSlice(extra_index, items_len); |
| 10750 | 10766 | extra_index += items_len; |
| 10751 | 10767 | |
| 10768 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10752 | 10769 | for (items, 0..) |item_ref, item_i| { |
| 10753 | | try sema.validateSwitchItem( |
| 10770 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10754 | 10771 | block, |
| 10755 | 10772 | &range_set, |
| 10756 | 10773 | item_ref, |
| 10774 | operand_ty, |
| 10757 | 10775 | src_node_offset, |
| 10758 | 10776 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10759 | | ); |
| 10777 | )); |
| 10760 | 10778 | } |
| 10761 | 10779 | |
| 10780 | try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len); |
| 10762 | 10781 | var range_i: u32 = 0; |
| 10763 | 10782 | while (range_i < ranges_len) : (range_i += 1) { |
| 10764 | 10783 | 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 |
| 10766 | 10785 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10767 | 10786 | extra_index += 1; |
| 10768 | 10787 | |
| 10769 | | try sema.validateSwitchRange( |
| 10788 | const vals = try sema.validateSwitchRange( |
| 10770 | 10789 | block, |
| 10771 | 10790 | &range_set, |
| 10772 | 10791 | item_first, |
| 10773 | 10792 | item_last, |
| 10793 | operand_ty, |
| 10774 | 10794 | src_node_offset, |
| 10775 | 10795 | .{ .range = .{ .prong = multi_i, .item = range_i } }, |
| 10776 | 10796 | ); |
| 10797 | case_vals.appendAssumeCapacity(vals[0]); |
| 10798 | case_vals.appendAssumeCapacity(vals[1]); |
| 10777 | 10799 | } |
| 10778 | 10800 | |
| 10779 | 10801 | extra_index += body_len; |
| ... | ... | @@ -10817,14 +10839,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10817 | 10839 | extra_index += 1; |
| 10818 | 10840 | extra_index += body_len; |
| 10819 | 10841 | |
| 10820 | | try sema.validateSwitchItemBool( |
| 10842 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10821 | 10843 | block, |
| 10822 | 10844 | &true_count, |
| 10823 | 10845 | &false_count, |
| 10824 | 10846 | item_ref, |
| 10825 | 10847 | src_node_offset, |
| 10826 | 10848 | .{ .scalar = scalar_i }, |
| 10827 | | ); |
| 10849 | )); |
| 10828 | 10850 | } |
| 10829 | 10851 | } |
| 10830 | 10852 | { |
| ... | ... | @@ -10839,15 +10861,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10839 | 10861 | const items = sema.code.refSlice(extra_index, items_len); |
| 10840 | 10862 | extra_index += items_len + body_len; |
| 10841 | 10863 | |
| 10864 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10842 | 10865 | for (items, 0..) |item_ref, item_i| { |
| 10843 | | try sema.validateSwitchItemBool( |
| 10866 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10844 | 10867 | block, |
| 10845 | 10868 | &true_count, |
| 10846 | 10869 | &false_count, |
| 10847 | 10870 | item_ref, |
| 10848 | 10871 | src_node_offset, |
| 10849 | 10872 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10850 | | ); |
| 10873 | )); |
| 10851 | 10874 | } |
| 10852 | 10875 | |
| 10853 | 10876 | 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 |
| 10899 | 10922 | extra_index += 1; |
| 10900 | 10923 | extra_index += body_len; |
| 10901 | 10924 | |
| 10902 | | try sema.validateSwitchItemSparse( |
| 10925 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10903 | 10926 | block, |
| 10904 | 10927 | &seen_values, |
| 10905 | 10928 | item_ref, |
| 10929 | operand_ty, |
| 10906 | 10930 | src_node_offset, |
| 10907 | 10931 | .{ .scalar = scalar_i }, |
| 10908 | | ); |
| 10932 | )); |
| 10909 | 10933 | } |
| 10910 | 10934 | } |
| 10911 | 10935 | { |
| ... | ... | @@ -10920,14 +10944,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10920 | 10944 | const items = sema.code.refSlice(extra_index, items_len); |
| 10921 | 10945 | extra_index += items_len + body_len; |
| 10922 | 10946 | |
| 10947 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10923 | 10948 | for (items, 0..) |item_ref, item_i| { |
| 10924 | | try sema.validateSwitchItemSparse( |
| 10949 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10925 | 10950 | block, |
| 10926 | 10951 | &seen_values, |
| 10927 | 10952 | item_ref, |
| 10953 | operand_ty, |
| 10928 | 10954 | src_node_offset, |
| 10929 | 10955 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10930 | | ); |
| 10956 | )); |
| 10931 | 10957 | } |
| 10932 | 10958 | |
| 10933 | 10959 | 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 |
| 10997 | 11023 | { |
| 10998 | 11024 | var scalar_i: usize = 0; |
| 10999 | 11025 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11000 | | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11001 | 11026 | extra_index += 1; |
| 11002 | 11027 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11003 | 11028 | 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 |
| 11005 | 11030 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11006 | 11031 | extra_index += body_len; |
| 11007 | 11032 | |
| 11008 | | const item = try sema.resolveInst(item_ref); |
| 11009 | | // Validation above ensured these will succeed. |
| 11033 | const item = case_vals.items[scalar_i]; |
| 11010 | 11034 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11011 | 11035 | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11012 | 11036 | if (is_inline) child_block.inline_case_capture = operand; |
| ... | ... | @@ -11018,6 +11042,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11018 | 11042 | } |
| 11019 | 11043 | { |
| 11020 | 11044 | var multi_i: usize = 0; |
| 11045 | var case_val_idx: usize = scalar_cases_len; |
| 11021 | 11046 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11022 | 11047 | const items_len = sema.code.extra[extra_index]; |
| 11023 | 11048 | extra_index += 1; |
| ... | ... | @@ -11025,13 +11050,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11025 | 11050 | extra_index += 1; |
| 11026 | 11051 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11027 | 11052 | 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; |
| 11031 | 11054 | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len]; |
| 11032 | 11055 | |
| 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| { |
| 11035 | 11060 | // Validation above ensured these will succeed. |
| 11036 | 11061 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11037 | 11062 | 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 |
| 11044 | 11069 | |
| 11045 | 11070 | var range_i: usize = 0; |
| 11046 | 11071 | 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; |
| 11051 | 11075 | |
| 11052 | 11076 | // 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))) |
| 11057 | 11081 | { |
| 11058 | 11082 | if (is_inline) child_block.inline_case_capture = operand; |
| 11059 | 11083 | 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 |
| 11115 | 11139 | |
| 11116 | 11140 | var scalar_i: usize = 0; |
| 11117 | 11141 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11118 | | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11119 | 11142 | extra_index += 1; |
| 11120 | 11143 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11121 | 11144 | 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 |
| 11130 | 11153 | case_block.wip_capture_scope = wip_captures.scope; |
| 11131 | 11154 | case_block.inline_case_capture = .none; |
| 11132 | 11155 | |
| 11133 | | const item = try sema.resolveInst(item_ref); |
| 11156 | const item = case_vals.items[scalar_i]; |
| 11134 | 11157 | if (is_inline) case_block.inline_case_capture = item; |
| 11135 | 11158 | // `item` is already guaranteed to be constant known. |
| 11136 | 11159 | |
| ... | ... | @@ -11165,6 +11188,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11165 | 11188 | defer gpa.free(prev_then_body); |
| 11166 | 11189 | |
| 11167 | 11190 | var cases_len = scalar_cases_len; |
| 11191 | var case_val_idx: usize = scalar_cases_len; |
| 11168 | 11192 | var multi_i: u32 = 0; |
| 11169 | 11193 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11170 | 11194 | const items_len = sema.code.extra[extra_index]; |
| ... | ... | @@ -11173,9 +11197,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11173 | 11197 | extra_index += 1; |
| 11174 | 11198 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11175 | 11199 | 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; |
| 11179 | 11204 | |
| 11180 | 11205 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11181 | 11206 | 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 |
| 11189 | 11214 | |
| 11190 | 11215 | var range_i: u32 = 0; |
| 11191 | 11216 | 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]; |
| 11196 | 11223 | |
| 11197 | | const item_first_ref = try sema.resolveInst(first_ref); |
| 11198 | 11224 | var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; |
| 11199 | | const item_last_ref = try sema.resolveInst(last_ref); |
| 11200 | 11225 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; |
| 11201 | 11226 | |
| 11202 | 11227 | while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({ |
| ... | ... | @@ -11235,10 +11260,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11235 | 11260 | } |
| 11236 | 11261 | } |
| 11237 | 11262 | |
| 11238 | | for (items, 0..) |item_ref, item_i| { |
| 11263 | for (items, 0..) |item, item_i| { |
| 11239 | 11264 | cases_len += 1; |
| 11240 | 11265 | |
| 11241 | | const item = try sema.resolveInst(item_ref); |
| 11242 | 11266 | case_block.inline_case_capture = item; |
| 11243 | 11267 | |
| 11244 | 11268 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11287,8 +11311,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11287 | 11311 | cases_len += 1; |
| 11288 | 11312 | |
| 11289 | 11313 | const analyze_body = if (union_originally) |
| 11290 | | for (items) |item_ref| { |
| 11291 | | const item = try sema.resolveInst(item_ref); |
| 11314 | for (items) |item| { |
| 11292 | 11315 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 11293 | 11316 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11294 | 11317 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; |
| ... | ... | @@ -11312,15 +11335,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11312 | 11335 | cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); |
| 11313 | 11336 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11314 | 11337 | |
| 11315 | | for (items) |item_ref| { |
| 11316 | | const item = try sema.resolveInst(item_ref); |
| 11338 | for (items) |item| { |
| 11317 | 11339 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 11318 | 11340 | } |
| 11319 | 11341 | |
| 11320 | 11342 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11321 | 11343 | } else { |
| 11322 | | for (items) |item_ref| { |
| 11323 | | const item = try sema.resolveInst(item_ref); |
| 11344 | for (items) |item| { |
| 11324 | 11345 | const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); |
| 11325 | 11346 | if (any_ok != .none) { |
| 11326 | 11347 | 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 |
| 11331 | 11352 | |
| 11332 | 11353 | var range_i: usize = 0; |
| 11333 | 11354 | 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; |
| 11338 | 11358 | |
| 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]; |
| 11341 | 11361 | |
| 11342 | 11362 | // operand >= first and operand <= last |
| 11343 | 11363 | const range_first_ok = try case_block.addBinOp( |
| ... | ... | @@ -11696,29 +11716,46 @@ const RangeSetUnhandledIterator = struct { |
| 11696 | 11716 | } |
| 11697 | 11717 | }; |
| 11698 | 11718 | |
| 11719 | const ResolvedSwitchItem = struct { |
| 11720 | ref: Air.Inst.Ref, |
| 11721 | val: InternPool.Index, |
| 11722 | }; |
| 11699 | 11723 | fn resolveSwitchItemVal( |
| 11700 | 11724 | sema: *Sema, |
| 11701 | 11725 | block: *Block, |
| 11702 | 11726 | item_ref: Zir.Inst.Ref, |
| 11727 | /// Coerce `item_ref` to this type. |
| 11728 | coerce_ty: Type, |
| 11703 | 11729 | switch_node_offset: i32, |
| 11704 | 11730 | switch_prong_src: Module.SwitchProngSrc, |
| 11705 | 11731 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 11706 | | ) CompileError!InternPool.Index { |
| 11732 | ) CompileError!ResolvedSwitchItem { |
| 11707 | 11733 | const mod = sema.mod; |
| 11708 | | const item = try sema.resolveInst(item_ref); |
| 11734 | const uncoerced_item = try sema.resolveInst(item_ref); |
| 11735 | |
| 11709 | 11736 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. |
| 11710 | 11737 | // Only if we know for sure we need to report a compile error do we resolve the |
| 11711 | 11738 | // 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) { |
| 11715 | 11750 | error.NeededSourceLocation => { |
| 11716 | 11751 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 11717 | 11752 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| 11718 | 11753 | unreachable; |
| 11719 | 11754 | }, |
| 11720 | 11755 | else => |e| return e, |
| 11721 | | } |
| 11756 | }; |
| 11757 | |
| 11758 | return .{ .ref = item, .val = val.toIntern() }; |
| 11722 | 11759 | } |
| 11723 | 11760 | |
| 11724 | 11761 | fn validateSwitchRange( |
| ... | ... | @@ -11727,31 +11764,35 @@ fn validateSwitchRange( |
| 11727 | 11764 | range_set: *RangeSet, |
| 11728 | 11765 | first_ref: Zir.Inst.Ref, |
| 11729 | 11766 | last_ref: Zir.Inst.Ref, |
| 11767 | operand_ty: Type, |
| 11730 | 11768 | src_node_offset: i32, |
| 11731 | 11769 | switch_prong_src: Module.SwitchProngSrc, |
| 11732 | | ) CompileError!void { |
| 11770 | ) CompileError![2]Air.Inst.Ref { |
| 11733 | 11771 | 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)) { |
| 11737 | 11775 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); |
| 11738 | 11776 | return sema.fail(block, src, "range start value is greater than the end value", .{}); |
| 11739 | 11777 | } |
| 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 }; |
| 11742 | 11781 | } |
| 11743 | 11782 | |
| 11744 | | fn validateSwitchItem( |
| 11783 | fn validateSwitchItemInt( |
| 11745 | 11784 | sema: *Sema, |
| 11746 | 11785 | block: *Block, |
| 11747 | 11786 | range_set: *RangeSet, |
| 11748 | 11787 | item_ref: Zir.Inst.Ref, |
| 11788 | operand_ty: Type, |
| 11749 | 11789 | src_node_offset: i32, |
| 11750 | 11790 | 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; |
| 11755 | 11796 | } |
| 11756 | 11797 | |
| 11757 | 11798 | fn validateSwitchItemEnum( |
| ... | ... | @@ -11760,19 +11801,22 @@ fn validateSwitchItemEnum( |
| 11760 | 11801 | seen_fields: []?Module.SwitchProngSrc, |
| 11761 | 11802 | range_set: *RangeSet, |
| 11762 | 11803 | item_ref: Zir.Inst.Ref, |
| 11804 | operand_ty: Type, |
| 11763 | 11805 | src_node_offset: i32, |
| 11764 | 11806 | switch_prong_src: Module.SwitchProngSrc, |
| 11765 | | ) CompileError!void { |
| 11807 | ) CompileError!Air.Inst.Ref { |
| 11766 | 11808 | 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 { |
| 11770 | 11812 | 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; |
| 11772 | 11815 | }; |
| 11773 | 11816 | const maybe_prev_src = seen_fields[field_index]; |
| 11774 | 11817 | 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; |
| 11776 | 11820 | } |
| 11777 | 11821 | |
| 11778 | 11822 | fn validateSwitchItemError( |
| ... | ... | @@ -11780,18 +11824,19 @@ fn validateSwitchItemError( |
| 11780 | 11824 | block: *Block, |
| 11781 | 11825 | seen_errors: *SwitchErrorSet, |
| 11782 | 11826 | item_ref: Zir.Inst.Ref, |
| 11827 | operand_ty: Type, |
| 11783 | 11828 | src_node_offset: i32, |
| 11784 | 11829 | switch_prong_src: Module.SwitchProngSrc, |
| 11785 | | ) CompileError!void { |
| 11830 | ) CompileError!Air.Inst.Ref { |
| 11786 | 11831 | 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; |
| 11790 | 11834 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11791 | 11835 | prev.value |
| 11792 | 11836 | else |
| 11793 | 11837 | 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; |
| 11795 | 11840 | } |
| 11796 | 11841 | |
| 11797 | 11842 | fn validateSwitchDupe( |
| ... | ... | @@ -11834,19 +11879,20 @@ fn validateSwitchItemBool( |
| 11834 | 11879 | item_ref: Zir.Inst.Ref, |
| 11835 | 11880 | src_node_offset: i32, |
| 11836 | 11881 | switch_prong_src: Module.SwitchProngSrc, |
| 11837 | | ) CompileError!void { |
| 11882 | ) CompileError!Air.Inst.Ref { |
| 11838 | 11883 | 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()) { |
| 11841 | 11886 | true_count.* += 1; |
| 11842 | 11887 | } else { |
| 11843 | 11888 | false_count.* += 1; |
| 11844 | 11889 | } |
| 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); |
| 11847 | 11892 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11848 | 11893 | return sema.fail(block, src, "duplicate switch value", .{}); |
| 11849 | 11894 | } |
| 11895 | return item.ref; |
| 11850 | 11896 | } |
| 11851 | 11897 | |
| 11852 | 11898 | const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); |
| ... | ... | @@ -11856,12 +11902,14 @@ fn validateSwitchItemSparse( |
| 11856 | 11902 | block: *Block, |
| 11857 | 11903 | seen_values: *ValueSrcMap, |
| 11858 | 11904 | item_ref: Zir.Inst.Ref, |
| 11905 | operand_ty: Type, |
| 11859 | 11906 | src_node_offset: i32, |
| 11860 | 11907 | 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; |
| 11865 | 11913 | } |
| 11866 | 11914 | |
| 11867 | 11915 | fn validateSwitchNoRange( |