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