| ... | ... | @@ -10761,7 +10761,7 @@ fn analyzeSwitchBlock( |
| 10761 | 10761 | const val, const ref = if (operand_is_ref) |
| 10762 | 10762 | .{ try sema.analyzeLoad(block, src, raw_operand, operand_src), raw_operand } |
| 10763 | 10763 | else |
| 10764 | | .{ raw_operand, undefined }; |
| 10764 | .{ raw_operand, .none }; |
| 10765 | 10765 | |
| 10766 | 10766 | const operand_ty = sema.typeOf(val); |
| 10767 | 10767 | const maybe_operand_opv = try sema.typeHasOnePossibleValue(operand_ty); |
| ... | ... | @@ -10785,7 +10785,7 @@ fn analyzeSwitchBlock( |
| 10785 | 10785 | const operand_alloc = try block.addTy(.alloc, operand_ptr_ty); |
| 10786 | 10786 | _ = try block.addBinOp(.store, operand_alloc, raw_operand); |
| 10787 | 10787 | break :alloc operand_alloc; |
| 10788 | | } else undefined; |
| 10788 | } else .none; |
| 10789 | 10789 | break :operand .{ .{ .loop = .{ |
| 10790 | 10790 | .operand_alloc = operand_alloc, |
| 10791 | 10791 | .operand_is_ref = operand_is_ref, |
| ... | ... | @@ -10857,7 +10857,7 @@ fn analyzeSwitchBlock( |
| 10857 | 10857 | const new_val, const new_ref = if (operand_is_ref) |
| 10858 | 10858 | .{ try sema.analyzeLoad(child_block, src, new_operand, new_operand_src), new_operand } |
| 10859 | 10859 | else |
| 10860 | | .{ new_operand, undefined }; |
| 10860 | .{ new_operand, .none }; |
| 10861 | 10861 | |
| 10862 | 10862 | const new_cond_ref = if (union_originally) |
| 10863 | 10863 | try sema.unionToTag(child_block, item_ty, new_val, src) |
| ... | ... | @@ -10953,7 +10953,7 @@ fn analyzeSwitchBlock( |
| 10953 | 10953 | const by_val = try sema.analyzeLoad(block, src, loaded, src); |
| 10954 | 10954 | break :load_operand .{ by_val, loaded }; |
| 10955 | 10955 | } else { |
| 10956 | | break :load_operand .{ loaded, undefined }; |
| 10956 | break :load_operand .{ loaded, .none }; |
| 10957 | 10957 | } |
| 10958 | 10958 | }, |
| 10959 | 10959 | }; |
| ... | ... | @@ -11393,33 +11393,31 @@ fn finishSwitchBr( |
| 11393 | 11393 | var emit_bb = false; |
| 11394 | 11394 | if (has_else and else_case.is_inline) { |
| 11395 | 11395 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); |
| 11396 | | var error_names: InternPool.NullTerminatedString.Slice = undefined; |
| 11397 | | var min_int: Value = undefined; |
| 11398 | | check_enumerable: { |
| 11396 | const error_names, const min_int = check_enumerable: { |
| 11399 | 11397 | switch (item_ty.zigTypeTag(zcu)) { |
| 11400 | 11398 | .@"union" => unreachable, |
| 11401 | 11399 | .@"enum" => if (else_is_named_only or |
| 11402 | 11400 | !item_ty.isNonexhaustiveEnum(zcu) or union_originally) |
| 11403 | 11401 | { |
| 11404 | 11402 | try branch_hints.ensureUnusedCapacity(gpa, @intCast(validated_switch.seen_enum_fields.len)); |
| 11405 | | break :check_enumerable; |
| 11403 | break :check_enumerable .{ undefined, undefined }; |
| 11406 | 11404 | }, |
| 11407 | 11405 | .error_set => if (!operand_ty.isAnyError(zcu)) { |
| 11408 | | error_names = item_ty.errorSetNames(zcu); |
| 11406 | const error_names = item_ty.errorSetNames(zcu); |
| 11409 | 11407 | try branch_hints.ensureUnusedCapacity(gpa, error_names.len); |
| 11410 | | break :check_enumerable; |
| 11408 | break :check_enumerable .{ error_names, undefined }; |
| 11411 | 11409 | }, |
| 11412 | 11410 | .int => { |
| 11413 | | min_int = try item_ty.minInt(pt, item_ty); |
| 11414 | | break :check_enumerable; |
| 11411 | const min_int = try item_ty.minInt(pt, item_ty); |
| 11412 | break :check_enumerable .{ undefined, min_int }; |
| 11415 | 11413 | }, |
| 11416 | | .bool, .void => break :check_enumerable, |
| 11414 | .bool, .void => break :check_enumerable .{ undefined, undefined }, |
| 11417 | 11415 | else => {}, |
| 11418 | 11416 | } |
| 11419 | 11417 | return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 11420 | 11418 | item_ty.fmt(pt), |
| 11421 | 11419 | }); |
| 11422 | | } |
| 11420 | }; |
| 11423 | 11421 | var unhandled_it = validated_switch.iterateUnhandledItems(error_names, min_int); |
| 11424 | 11422 | while (try unhandled_it.next(sema, item_ty)) |item_val| { |
| 11425 | 11423 | cases_len += 1; |
| ... | ... | @@ -11660,7 +11658,7 @@ fn fixupSwitchContinues( |
| 11660 | 11658 | operand_is_ref: bool, |
| 11661 | 11659 | item_ty: Type, |
| 11662 | 11660 | mode: enum { normal, opv }, |
| 11663 | | any_non_inline_capture: bool, |
| 11661 | any_maybe_runtime_capture: bool, |
| 11664 | 11662 | merges: *const Block.Merges, |
| 11665 | 11663 | ) CompileError!void { |
| 11666 | 11664 | const pt = sema.pt; |
| ... | ... | @@ -11686,7 +11684,7 @@ fn fixupSwitchContinues( |
| 11686 | 11684 | assert(sema.air_instructions.items(.tag)[@intFromEnum(placeholder_inst)] == .br); |
| 11687 | 11685 | const new_operand_maybe_ref = sema.air_instructions.items(.data)[@intFromEnum(placeholder_inst)].br.operand; |
| 11688 | 11686 | |
| 11689 | | if (any_non_inline_capture and mode != .opv) { |
| 11687 | if (any_maybe_runtime_capture and mode != .opv) { |
| 11690 | 11688 | _ = try replacement_block.addBinOp(.store, operand.loop.operand_alloc, new_operand_maybe_ref); |
| 11691 | 11689 | } |
| 11692 | 11690 | |
| ... | ... | @@ -12431,6 +12429,8 @@ fn resolveSwitchBlock( |
| 12431 | 12429 | } |
| 12432 | 12430 | } |
| 12433 | 12431 | |
| 12432 | assert(zir_switch.else_case != null or under_prong != null); // switch exhaustion check wrong |
| 12433 | |
| 12434 | 12434 | const else_case = validated_switch.else_case; |
| 12435 | 12435 | const else_is_named_only = zir_switch.else_case != null and under_prong != null; |
| 12436 | 12436 | |
| ... | ... | @@ -12507,8 +12507,8 @@ const SwitchOperand = union(enum) { |
| 12507 | 12507 | simple: struct { |
| 12508 | 12508 | /// The raw switch operand value. Always defined. |
| 12509 | 12509 | by_val: Air.Inst.Ref, |
| 12510 | | /// The switch operand *pointer*. Defined only if there is a prong |
| 12511 | | /// with a by-ref capture. |
| 12510 | /// The switch operand *pointer*. `none` if there are no prongs with a |
| 12511 | /// by-ref capture. |
| 12512 | 12512 | by_ref: Air.Inst.Ref, |
| 12513 | 12513 | /// The switch condition value. For unions, `operand` is the union |
| 12514 | 12514 | /// and `cond` is its enum tag value. |
| ... | ... | @@ -12519,7 +12519,7 @@ const SwitchOperand = union(enum) { |
| 12519 | 12519 | loop: struct { |
| 12520 | 12520 | /// The `alloc` containing the `switch` operand for the active dispatch. |
| 12521 | 12521 | /// Each prong must load from this `alloc` to get captures. |
| 12522 | | /// If there are no captures, this may be undefined. |
| 12522 | /// If there are no captures, this may be `none`. |
| 12523 | 12523 | operand_alloc: Air.Inst.Ref, |
| 12524 | 12524 | /// Whether `operand_alloc` contains a by-val operand or a by-ref |
| 12525 | 12525 | /// operand. |
| ... | ... | @@ -12665,19 +12665,31 @@ fn analyzeSwitchProng( |
| 12665 | 12665 | } |
| 12666 | 12666 | } |
| 12667 | 12667 | |
| 12668 | | const operand_val, const operand_ptr = load_operand: { |
| 12668 | const need_load: bool = need_load: { |
| 12669 | 12669 | if (capture == .none and !has_tag_capture) { |
| 12670 | 12670 | // No need to load the operand for this prong! |
| 12671 | | break :load_operand .{ undefined, undefined }; |
| 12671 | break :need_load false; |
| 12672 | 12672 | } |
| 12673 | | if (kind == .inline_ref and |
| 12674 | | !(capture != .none and operand_ty.zigTypeTag(zcu) == .@"union")) |
| 12675 | | { |
| 12676 | | // We only need to load the operand if there's a union payload capture |
| 12677 | | // since it's always runtime-known; only the tag is comptime-known here. |
| 12678 | | break :load_operand .{ undefined, undefined }; |
| 12673 | if (capture != .none and operand_ty.zigTypeTag(zcu) == .@"union") { |
| 12674 | // Non-OPV union payload captures are always runtime-known. |
| 12675 | break :need_load true; |
| 12676 | } |
| 12677 | if (kind == .inline_ref) { |
| 12678 | // `inline_ref` *is* the (comptime-known) capture. |
| 12679 | break :need_load false; |
| 12679 | 12680 | } |
| 12680 | 12681 | assert(zir_switch.any_maybe_runtime_capture); // should have caught everything else by now |
| 12682 | if (capture != .by_ref and |
| 12683 | kind == .item_refs and kind.item_refs.len == 1) |
| 12684 | { |
| 12685 | // Capture is comptime-known because it's the only prong item |
| 12686 | break :need_load false; |
| 12687 | } |
| 12688 | break :need_load true; |
| 12689 | }; |
| 12690 | |
| 12691 | const operand_val: Air.Inst.Ref, const operand_ptr: Air.Inst.Ref = load_operand: { |
| 12692 | if (!need_load) break :load_operand .{ .none, .none }; |
| 12681 | 12693 | switch (operand) { |
| 12682 | 12694 | .simple => |s| break :load_operand .{ s.by_val, s.by_ref }, |
| 12683 | 12695 | .loop => |l| { |
| ... | ... | @@ -12686,7 +12698,7 @@ fn analyzeSwitchProng( |
| 12686 | 12698 | const by_val = try sema.analyzeLoad(case_block, operand_src, loaded, operand_src); |
| 12687 | 12699 | break :load_operand .{ by_val, loaded }; |
| 12688 | 12700 | } else { |
| 12689 | | break :load_operand .{ loaded, undefined }; |
| 12701 | break :load_operand .{ loaded, .none }; |
| 12690 | 12702 | } |
| 12691 | 12703 | }, |
| 12692 | 12704 | } |
| ... | ... | @@ -12735,7 +12747,7 @@ fn analyzeSwitchProng( |
| 12735 | 12747 | fn analyzeSwitchTagCapture( |
| 12736 | 12748 | sema: *Sema, |
| 12737 | 12749 | case_block: *Block, |
| 12738 | | /// May be `undefined` if `inline_case_capture` is not `.none`. |
| 12750 | /// May be `none` if this is an inline capture or if `kind.item_refs.len == 1`. |
| 12739 | 12751 | operand_val: Air.Inst.Ref, |
| 12740 | 12752 | operand_ty: Type, |
| 12741 | 12753 | capture_src: LazySrcLoc, |
| ... | ... | @@ -12768,9 +12780,11 @@ fn analyzeSwitchPayloadCapture( |
| 12768 | 12780 | sema: *Sema, |
| 12769 | 12781 | case_block: *Block, |
| 12770 | 12782 | operand: SwitchOperand, |
| 12771 | | /// May be `undefined` if this is an inline capture and operand is not a union. |
| 12783 | /// Always has to be not-`none` if this is a union payload capture. |
| 12784 | /// For non-union captures, this may be `none` if this is an inline capture |
| 12785 | /// or if `kind.item_refs.len == 1` and capture is by val. |
| 12772 | 12786 | operand_val: Air.Inst.Ref, |
| 12773 | | /// May be `undefined` if `capture_by_ref` is `false` or if `operand_val` is also `undefined`. |
| 12787 | /// May be `none` if `capture_by_ref` is `false` or if `operand_val` is also `none`. |
| 12774 | 12788 | operand_ptr: Air.Inst.Ref, |
| 12775 | 12789 | operand_ty: Type, |
| 12776 | 12790 | operand_src: LazySrcLoc, |
| ... | ... | @@ -12816,8 +12830,6 @@ fn analyzeSwitchPayloadCapture( |
| 12816 | 12830 | } |
| 12817 | 12831 | } |
| 12818 | 12832 | |
| 12819 | | const operand_ptr_ty = if (capture_by_ref) sema.typeOf(operand_ptr) else undefined; |
| 12820 | | |
| 12821 | 12833 | if (kind == .special) { |
| 12822 | 12834 | if (capture_by_ref) return operand_ptr; |
| 12823 | 12835 | return switch (operand_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -12894,7 +12906,7 @@ fn analyzeSwitchPayloadCapture( |
| 12894 | 12906 | |
| 12895 | 12907 | // By-reference captures have some further restrictions which make them easier to emit |
| 12896 | 12908 | if (capture_by_ref) { |
| 12897 | | const operand_ptr_info = operand_ptr_ty.ptrInfo(zcu); |
| 12909 | const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu); |
| 12898 | 12910 | const capture_ptr_ty = resolve: { |
| 12899 | 12911 | // By-ref captures of hetereogeneous types are only allowed if all field |
| 12900 | 12912 | // pointer types are peer resolvable to each other. |
| ... | ... | @@ -13136,7 +13148,7 @@ fn analyzeSwitchPayloadCapture( |
| 13136 | 13148 | if (case_vals.len == 1) { |
| 13137 | 13149 | const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable; |
| 13138 | 13150 | const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?); |
| 13139 | | return sema.bitCast(case_block, item_ty, operand_val, operand_src, null); |
| 13151 | return sema.bitCast(case_block, item_ty, .fromValue(item_val), operand_src, null); |
| 13140 | 13152 | } |
| 13141 | 13153 | |
| 13142 | 13154 | var names: InferredErrorSet.NameMap = .{}; |