| ... | ... | @@ -277,9 +277,6 @@ pub const Block = struct { |
| 277 | 277 | |
| 278 | 278 | c_import_buf: ?*std.ArrayList(u8) = null, |
| 279 | 279 | |
| 280 | | /// type of `err` in `else => |err|` |
| 281 | | switch_else_err_ty: ?Type = null, |
| 282 | | |
| 283 | 280 | /// Value for switch_capture in an inline case |
| 284 | 281 | inline_case_capture: Air.Inst.Ref = .none, |
| 285 | 282 | |
| ... | ... | @@ -397,7 +394,6 @@ pub const Block = struct { |
| 397 | 394 | .want_safety = parent.want_safety, |
| 398 | 395 | .float_mode = parent.float_mode, |
| 399 | 396 | .c_import_buf = parent.c_import_buf, |
| 400 | | .switch_else_err_ty = parent.switch_else_err_ty, |
| 401 | 397 | .error_return_trace_index = parent.error_return_trace_index, |
| 402 | 398 | }; |
| 403 | 399 | } |
| ... | ... | @@ -1017,8 +1013,6 @@ fn analyzeBodyInner( |
| 1017 | 1013 | .switch_block => try sema.zirSwitchBlock(block, inst), |
| 1018 | 1014 | .switch_cond => try sema.zirSwitchCond(block, inst, false), |
| 1019 | 1015 | .switch_cond_ref => try sema.zirSwitchCond(block, inst, true), |
| 1020 | | .switch_capture => try sema.zirSwitchCapture(block, inst, false), |
| 1021 | | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, true), |
| 1022 | 1016 | .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst), |
| 1023 | 1017 | .type_info => try sema.zirTypeInfo(block, inst), |
| 1024 | 1018 | .size_of => try sema.zirSizeOf(block, inst), |
| ... | ... | @@ -10083,61 +10077,160 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10083 | 10077 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); |
| 10084 | 10078 | } |
| 10085 | 10079 | |
| 10086 | | fn zirSwitchCapture( |
| 10080 | /// Resolve a switch prong which is determined at comptime to have no peers. Uses |
| 10081 | /// `resolveBlockBody`. Sets up captures as needed. |
| 10082 | fn resolveSwitchProngComptime( |
| 10087 | 10083 | sema: *Sema, |
| 10088 | | block: *Block, |
| 10089 | | inst: Zir.Inst.Index, |
| 10090 | | is_ref: bool, |
| 10084 | parent_block: *Block, |
| 10085 | child_block: *Block, |
| 10086 | src: LazySrcLoc, |
| 10087 | operand: Air.Inst.Ref, |
| 10088 | operand_ptr: Air.Inst.Ref, |
| 10089 | prong_type: enum { normal, special }, |
| 10090 | prong_body: []const Zir.Inst.Index, |
| 10091 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10092 | raw_capture_src: Module.SwitchProngSrc, |
| 10093 | else_error_ty: ?Type, |
| 10094 | case_vals: []const Air.Inst.Ref, |
| 10095 | switch_block_inst: Zir.Inst.Index, |
| 10096 | merges: *Block.Merges, |
| 10091 | 10097 | ) CompileError!Air.Inst.Ref { |
| 10092 | | const tracy = trace(@src()); |
| 10093 | | defer tracy.end(); |
| 10098 | switch (capture) { |
| 10099 | .none => { |
| 10100 | return sema.resolveBlockBody(parent_block, src, child_block, prong_body, switch_block_inst, merges); |
| 10101 | }, |
| 10102 | |
| 10103 | .by_val, .by_ref => { |
| 10104 | const zir_datas = sema.code.instructions.items(.data); |
| 10105 | const switch_info = zir_datas[switch_block_inst].pl_node; |
| 10106 | |
| 10107 | const capture_ref = try sema.analyzeSwitchCapture( |
| 10108 | child_block, |
| 10109 | capture == .by_ref, |
| 10110 | operand, |
| 10111 | operand_ptr, |
| 10112 | switch_info.src_node, |
| 10113 | prong_type == .special, |
| 10114 | raw_capture_src, |
| 10115 | else_error_ty, |
| 10116 | case_vals, |
| 10117 | ); |
| 10118 | |
| 10119 | if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) { |
| 10120 | // This prong should be unreachable! |
| 10121 | return Air.Inst.Ref.unreachable_value; |
| 10122 | } |
| 10123 | |
| 10124 | sema.inst_map.putAssumeCapacity(switch_block_inst, capture_ref); |
| 10125 | defer assert(sema.inst_map.remove(switch_block_inst)); |
| 10126 | |
| 10127 | return sema.resolveBlockBody(parent_block, src, child_block, prong_body, switch_block_inst, merges); |
| 10128 | }, |
| 10129 | } |
| 10130 | } |
| 10131 | |
| 10132 | /// Analyze a switch prong which may have peers at runtime. Uses |
| 10133 | /// `analyzeBodyRuntimeBreak`. Sets up captures as needed. |
| 10134 | fn analyzeSwitchProngRuntime( |
| 10135 | sema: *Sema, |
| 10136 | case_block: *Block, |
| 10137 | operand: Air.Inst.Ref, |
| 10138 | operand_ptr: Air.Inst.Ref, |
| 10139 | prong_type: enum { normal, special }, |
| 10140 | prong_body: []const Zir.Inst.Index, |
| 10141 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10142 | raw_capture_src: Module.SwitchProngSrc, |
| 10143 | else_error_ty: ?Type, |
| 10144 | case_vals: []const Air.Inst.Ref, |
| 10145 | switch_block_inst: Zir.Inst.Index, |
| 10146 | ) CompileError!void { |
| 10147 | switch (capture) { |
| 10148 | .none => { |
| 10149 | return sema.analyzeBodyRuntimeBreak(case_block, prong_body); |
| 10150 | }, |
| 10151 | |
| 10152 | .by_val, .by_ref => { |
| 10153 | const zir_datas = sema.code.instructions.items(.data); |
| 10154 | const switch_info = zir_datas[switch_block_inst].pl_node; |
| 10155 | |
| 10156 | const capture_ref = try sema.analyzeSwitchCapture( |
| 10157 | case_block, |
| 10158 | capture == .by_ref, |
| 10159 | operand, |
| 10160 | operand_ptr, |
| 10161 | switch_info.src_node, |
| 10162 | prong_type == .special, |
| 10163 | raw_capture_src, |
| 10164 | else_error_ty, |
| 10165 | case_vals, |
| 10166 | ); |
| 10094 | 10167 | |
| 10168 | if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) { |
| 10169 | // No need to analyze any further, the prong is unreachable |
| 10170 | return; |
| 10171 | } |
| 10172 | |
| 10173 | sema.inst_map.putAssumeCapacity(switch_block_inst, capture_ref); |
| 10174 | defer assert(sema.inst_map.remove(switch_block_inst)); |
| 10175 | |
| 10176 | return sema.analyzeBodyRuntimeBreak(case_block, prong_body); |
| 10177 | }, |
| 10178 | } |
| 10179 | } |
| 10180 | |
| 10181 | fn analyzeSwitchCapture( |
| 10182 | sema: *Sema, |
| 10183 | /// Must be the child block so that `inline_case_capture` is set for inline prongs. |
| 10184 | block: *Block, |
| 10185 | capture_byref: bool, |
| 10186 | /// The raw switch operand value. |
| 10187 | operand: Air.Inst.Ref, |
| 10188 | /// Pointer to the raw switch operand. May be undefined if `capture_byref` is false. |
| 10189 | operand_ptr: Air.Inst.Ref, |
| 10190 | switch_node_offset: i32, |
| 10191 | /// `true` if this is the `else` or `_` prong of a switch. |
| 10192 | is_special_prong: bool, |
| 10193 | /// Must use the `scalar`, `special`, or `multi_capture` union field. |
| 10194 | raw_capture_src: Module.SwitchProngSrc, |
| 10195 | /// If this is the `else` prong of a switch on an error set, this is the |
| 10196 | /// type that should be assigned to the capture. If `null`, the prong should |
| 10197 | /// be unreachable. |
| 10198 | else_error_ty: ?Type, |
| 10199 | /// The set of all values which can reach this prong. May be undefined if |
| 10200 | /// the prong has `is_special_prong` or contains ranges. |
| 10201 | case_vals: []const Air.Inst.Ref, |
| 10202 | ) CompileError!Air.Inst.Ref { |
| 10095 | 10203 | const mod = sema.mod; |
| 10096 | 10204 | const gpa = sema.gpa; |
| 10097 | | const zir_datas = sema.code.instructions.items(.data); |
| 10098 | | const capture_info = zir_datas[inst].switch_capture; |
| 10099 | | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| 10100 | | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); |
| 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); |
| 10104 | | const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; |
| 10105 | | const cond_info = zir_datas[cond_inst].un_node; |
| 10106 | | const cond_tag = sema.code.instructions.items(.tag)[cond_inst]; |
| 10107 | | const operand_is_ref = cond_tag == .switch_cond_ref; |
| 10108 | | const operand_ptr = try sema.resolveInst(cond_info.operand); |
| 10109 | | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 10110 | | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; |
| 10205 | const operand_ty = sema.typeOf(operand); |
| 10206 | const operand_ptr_ty = if (capture_byref) sema.typeOf(operand_ptr) else undefined; |
| 10207 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset }; |
| 10111 | 10208 | |
| 10112 | 10209 | if (block.inline_case_capture != .none) { |
| 10113 | | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; |
| 10114 | | const resolved_item_val = try sema.resolveLazyValue(item_val); |
| 10210 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, "") catch unreachable; |
| 10115 | 10211 | if (operand_ty.zigTypeTag(mod) == .Union) { |
| 10116 | | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?); |
| 10212 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?); |
| 10117 | 10213 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10118 | 10214 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 10119 | | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { |
| 10120 | | if (is_ref) { |
| 10215 | if (capture_byref) { |
| 10216 | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_ptr| { |
| 10121 | 10217 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10122 | 10218 | .pointee_type = field_ty, |
| 10123 | 10219 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10124 | 10220 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10125 | 10221 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10126 | 10222 | }); |
| 10127 | | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 10128 | | .ty = ptr_field_ty.toIntern(), |
| 10129 | | .addr = .{ .field = .{ |
| 10130 | | .base = union_val.toIntern(), |
| 10131 | | .index = field_index, |
| 10132 | | } }, |
| 10133 | | } })).toValue()); |
| 10223 | return sema.addConstant( |
| 10224 | ptr_field_ty, |
| 10225 | (try mod.intern(.{ .ptr = .{ |
| 10226 | .ty = ptr_field_ty.toIntern(), |
| 10227 | .addr = .{ .field = .{ |
| 10228 | .base = union_ptr.toIntern(), |
| 10229 | .index = field_index, |
| 10230 | } }, |
| 10231 | } })).toValue(), |
| 10232 | ); |
| 10134 | 10233 | } |
| 10135 | | return sema.addConstant( |
| 10136 | | field_ty, |
| 10137 | | mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(), |
| 10138 | | ); |
| 10139 | | } |
| 10140 | | if (is_ref) { |
| 10141 | 10234 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10142 | 10235 | .pointee_type = field_ty, |
| 10143 | 10236 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -10146,29 +10239,27 @@ fn zirSwitchCapture( |
| 10146 | 10239 | }); |
| 10147 | 10240 | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); |
| 10148 | 10241 | } else { |
| 10149 | | return block.addStructFieldVal(operand_ptr, field_index, field_ty); |
| 10242 | if (try sema.resolveDefinedValue(block, sema.src, operand)) |union_val| { |
| 10243 | const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un; |
| 10244 | return sema.addConstant(field_ty, tag_and_val.val.toValue()); |
| 10245 | } |
| 10246 | return block.addStructFieldVal(operand, field_index, field_ty); |
| 10150 | 10247 | } |
| 10151 | | } else if (is_ref) { |
| 10152 | | return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true); |
| 10248 | } else if (capture_byref) { |
| 10249 | return sema.addConstantMaybeRef(block, operand_ty, item_val, true); |
| 10153 | 10250 | } else { |
| 10154 | 10251 | return block.inline_case_capture; |
| 10155 | 10252 | } |
| 10156 | 10253 | } |
| 10157 | 10254 | |
| 10158 | | const operand = if (operand_is_ref) |
| 10159 | | try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) |
| 10160 | | else |
| 10161 | | operand_ptr; |
| 10162 | | |
| 10163 | | if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { |
| 10164 | | // It is the else/`_` prong. |
| 10165 | | if (is_ref) { |
| 10255 | if (is_special_prong) { |
| 10256 | if (capture_byref) { |
| 10166 | 10257 | return operand_ptr; |
| 10167 | 10258 | } |
| 10168 | 10259 | |
| 10169 | 10260 | switch (operand_ty.zigTypeTag(mod)) { |
| 10170 | | .ErrorSet => if (block.switch_else_err_ty) |some| { |
| 10171 | | return sema.bitCast(block, some, operand, operand_src, null); |
| 10261 | .ErrorSet => if (else_error_ty) |ty| { |
| 10262 | return sema.bitCast(block, ty, operand, operand_src, null); |
| 10172 | 10263 | } else { |
| 10173 | 10264 | try block.addUnreachable(false); |
| 10174 | 10265 | return Air.Inst.Ref.unreachable_value; |
| ... | ... | @@ -10177,41 +10268,33 @@ fn zirSwitchCapture( |
| 10177 | 10268 | } |
| 10178 | 10269 | } |
| 10179 | 10270 | |
| 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. |
| 10182 | | const items = switch_extra.data.getProng(sema.code, switch_extra.end, capture_info.prong_index).items; |
| 10183 | | |
| 10184 | 10271 | switch (operand_ty.zigTypeTag(mod)) { |
| 10185 | 10272 | .Union => { |
| 10186 | 10273 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10187 | | const first_item = try sema.resolveInst(items[0]); |
| 10188 | | // Previous switch validation ensured this will succeed |
| 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; |
| 10274 | const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable; |
| 10191 | 10275 | |
| 10192 | 10276 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10193 | 10277 | const first_field = union_obj.fields.values()[first_field_index]; |
| 10194 | 10278 | |
| 10195 | | for (items[1..], 0..) |item, i| { |
| 10196 | | const item_ref = try sema.resolveInst(item); |
| 10197 | | // Previous switch validation ensured this will succeed |
| 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; |
| 10279 | for (case_vals[1..], 0..) |item, i| { |
| 10280 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 10200 | 10281 | |
| 10201 | 10282 | const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?; |
| 10202 | 10283 | const field = union_obj.fields.values()[field_index]; |
| 10203 | 10284 | if (!field.ty.eql(first_field.ty, mod)) { |
| 10204 | 10285 | const msg = msg: { |
| 10205 | | const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; |
| 10206 | | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10286 | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none); |
| 10207 | 10287 | |
| 10208 | 10288 | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); |
| 10209 | 10289 | errdefer msg.destroy(gpa); |
| 10210 | 10290 | |
| 10211 | | const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; |
| 10212 | | const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10213 | | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; |
| 10214 | | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10291 | // This must be a multi-prong so this must be a `multi_capture` src |
| 10292 | const multi_idx = raw_capture_src.multi_capture; |
| 10293 | |
| 10294 | const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 0 } }; |
| 10295 | const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first); |
| 10296 | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 1 + @intCast(u32, i) } }; |
| 10297 | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first); |
| 10215 | 10298 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)}); |
| 10216 | 10299 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)}); |
| 10217 | 10300 | break :msg msg; |
| ... | ... | @@ -10220,7 +10303,7 @@ fn zirSwitchCapture( |
| 10220 | 10303 | } |
| 10221 | 10304 | } |
| 10222 | 10305 | |
| 10223 | | if (is_ref) { |
| 10306 | if (capture_byref) { |
| 10224 | 10307 | const field_ty_ptr = try Type.ptr(sema.arena, mod, .{ |
| 10225 | 10308 | .pointee_type = first_field.ty, |
| 10226 | 10309 | .@"addrspace" = .generic, |
| ... | ... | @@ -10250,31 +10333,35 @@ fn zirSwitchCapture( |
| 10250 | 10333 | return block.addStructFieldVal(operand, first_field_index, first_field.ty); |
| 10251 | 10334 | }, |
| 10252 | 10335 | .ErrorSet => { |
| 10253 | | if (items.len > 1) { |
| 10254 | | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10255 | | try names.ensureUnusedCapacity(sema.arena, items.len); |
| 10256 | | for (items) |item| { |
| 10257 | | const item_ref = try sema.resolveInst(item); |
| 10258 | | // Previous switch validation ensured this will succeed |
| 10259 | | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10260 | | names.putAssumeCapacityNoClobber(item_val.getErrorName(mod).unwrap().?, {}); |
| 10261 | | } |
| 10262 | | const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10263 | | |
| 10264 | | return sema.bitCast(block, else_error_ty, operand, operand_src, null); |
| 10265 | | } else { |
| 10266 | | const item_ref = try sema.resolveInst(items[0]); |
| 10267 | | // Previous switch validation ensured this will succeed |
| 10268 | | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10336 | if (capture_byref) { |
| 10337 | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none); |
| 10338 | return sema.fail( |
| 10339 | block, |
| 10340 | capture_src, |
| 10341 | "error set cannot be captured by reference", |
| 10342 | .{}, |
| 10343 | ); |
| 10344 | } |
| 10269 | 10345 | |
| 10346 | if (case_vals.len == 1) { |
| 10347 | const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable; |
| 10270 | 10348 | const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?); |
| 10271 | 10349 | return sema.bitCast(block, item_ty, operand, operand_src, null); |
| 10272 | 10350 | } |
| 10351 | |
| 10352 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10353 | try names.ensureUnusedCapacity(sema.arena, case_vals.len); |
| 10354 | for (case_vals) |err| { |
| 10355 | const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable; |
| 10356 | names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {}); |
| 10357 | } |
| 10358 | const error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10359 | return sema.bitCast(block, error_ty, operand, operand_src, null); |
| 10273 | 10360 | }, |
| 10274 | 10361 | else => { |
| 10275 | | // In this case the capture value is just the passed-through value of the |
| 10276 | | // switch condition. |
| 10277 | | if (is_ref) { |
| 10362 | // In this case the capture value is just the passed-through value |
| 10363 | // of the switch condition. |
| 10364 | if (capture_byref) { |
| 10278 | 10365 | return operand_ptr; |
| 10279 | 10366 | } else { |
| 10280 | 10367 | return operand; |
| ... | ... | @@ -10415,28 +10502,42 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10415 | 10502 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 10416 | 10503 | defer case_vals.deinit(gpa); |
| 10417 | 10504 | |
| 10505 | const Special = struct { |
| 10506 | body: []const Zir.Inst.Index, |
| 10507 | end: usize, |
| 10508 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10509 | is_inline: bool, |
| 10510 | }; |
| 10511 | |
| 10418 | 10512 | const special_prong = extra.data.bits.specialProng(); |
| 10419 | | const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) { |
| 10420 | | .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, |
| 10513 | const special: Special = switch (special_prong) { |
| 10514 | .none => .{ .body = &.{}, .end = header_extra_index, .capture = .none, .is_inline = false }, |
| 10421 | 10515 | .under, .@"else" => blk: { |
| 10422 | | const body_len = @truncate(u31, sema.code.extra[header_extra_index]); |
| 10516 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]); |
| 10423 | 10517 | const extra_body_start = header_extra_index + 1; |
| 10424 | 10518 | break :blk .{ |
| 10425 | | .body = sema.code.extra[extra_body_start..][0..body_len], |
| 10426 | | .end = extra_body_start + body_len, |
| 10427 | | .is_inline = sema.code.extra[header_extra_index] >> 31 != 0, |
| 10519 | .body = sema.code.extra[extra_body_start..][0..info.body_len], |
| 10520 | .end = extra_body_start + info.body_len, |
| 10521 | .capture = info.capture, |
| 10522 | .is_inline = info.is_inline, |
| 10428 | 10523 | }; |
| 10429 | 10524 | }, |
| 10430 | 10525 | }; |
| 10431 | 10526 | |
| 10432 | | const maybe_union_ty = blk: { |
| 10527 | const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: { |
| 10433 | 10528 | const zir_tags = sema.code.instructions.items(.tag); |
| 10434 | 10529 | const zir_data = sema.code.instructions.items(.data); |
| 10435 | 10530 | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 10436 | | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 10437 | | const target_ty = sema.typeOf(raw_operand); |
| 10438 | | break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty; |
| 10531 | const raw = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 10532 | if (zir_tags[cond_index] == .switch_cond_ref) { |
| 10533 | const val = try sema.analyzeLoad(block, src, raw, operand_src); |
| 10534 | break :blk .{ .val = val, .ptr = raw }; |
| 10535 | } else { |
| 10536 | break :blk .{ .val = raw, .ptr = undefined }; |
| 10537 | } |
| 10439 | 10538 | }; |
| 10539 | |
| 10540 | const maybe_union_ty = sema.typeOf(raw_operand.val); |
| 10440 | 10541 | const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; |
| 10441 | 10542 | |
| 10442 | 10543 | // Duplicate checking variables later also used for `inline else`. |
| ... | ... | @@ -10496,9 +10597,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10496 | 10597 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10497 | 10598 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10498 | 10599 | extra_index += 1; |
| 10499 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10500 | | extra_index += 1; |
| 10501 | | extra_index += body_len; |
| 10600 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10601 | extra_index += 1 + info.body_len; |
| 10502 | 10602 | |
| 10503 | 10603 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10504 | 10604 | block, |
| ... | ... | @@ -10518,10 +10618,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10518 | 10618 | extra_index += 1; |
| 10519 | 10619 | const ranges_len = sema.code.extra[extra_index]; |
| 10520 | 10620 | extra_index += 1; |
| 10521 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10621 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10522 | 10622 | extra_index += 1; |
| 10523 | 10623 | const items = sema.code.refSlice(extra_index, items_len); |
| 10524 | | extra_index += items_len + body_len; |
| 10624 | extra_index += items_len + info.body_len; |
| 10525 | 10625 | |
| 10526 | 10626 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10527 | 10627 | for (items, 0..) |item_ref, item_i| { |
| ... | ... | @@ -10596,9 +10696,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10596 | 10696 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10597 | 10697 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10598 | 10698 | extra_index += 1; |
| 10599 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10600 | | extra_index += 1; |
| 10601 | | extra_index += body_len; |
| 10699 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10700 | extra_index += 1 + info.body_len; |
| 10602 | 10701 | |
| 10603 | 10702 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10604 | 10703 | block, |
| ... | ... | @@ -10617,10 +10716,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10617 | 10716 | extra_index += 1; |
| 10618 | 10717 | const ranges_len = sema.code.extra[extra_index]; |
| 10619 | 10718 | extra_index += 1; |
| 10620 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10719 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10621 | 10720 | extra_index += 1; |
| 10622 | 10721 | const items = sema.code.refSlice(extra_index, items_len); |
| 10623 | | extra_index += items_len + body_len; |
| 10722 | extra_index += items_len + info.body_len; |
| 10624 | 10723 | |
| 10625 | 10724 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10626 | 10725 | for (items, 0..) |item_ref, item_i| { |
| ... | ... | @@ -10694,7 +10793,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10694 | 10793 | .dbg_block_end, |
| 10695 | 10794 | .dbg_stmt, |
| 10696 | 10795 | .dbg_var_val, |
| 10697 | | .switch_capture, |
| 10698 | 10796 | .ret_type, |
| 10699 | 10797 | .as_node, |
| 10700 | 10798 | .ret_node, |
| ... | ... | @@ -10739,9 +10837,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10739 | 10837 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10740 | 10838 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10741 | 10839 | extra_index += 1; |
| 10742 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10743 | | extra_index += 1; |
| 10744 | | extra_index += body_len; |
| 10840 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10841 | extra_index += 1 + info.body_len; |
| 10745 | 10842 | |
| 10746 | 10843 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10747 | 10844 | block, |
| ... | ... | @@ -10760,7 +10857,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10760 | 10857 | extra_index += 1; |
| 10761 | 10858 | const ranges_len = sema.code.extra[extra_index]; |
| 10762 | 10859 | extra_index += 1; |
| 10763 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10860 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10764 | 10861 | extra_index += 1; |
| 10765 | 10862 | const items = sema.code.refSlice(extra_index, items_len); |
| 10766 | 10863 | extra_index += items_len; |
| ... | ... | @@ -10798,7 +10895,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10798 | 10895 | case_vals.appendAssumeCapacity(vals[1]); |
| 10799 | 10896 | } |
| 10800 | 10897 | |
| 10801 | | extra_index += body_len; |
| 10898 | extra_index += info.body_len; |
| 10802 | 10899 | } |
| 10803 | 10900 | } |
| 10804 | 10901 | |
| ... | ... | @@ -10835,9 +10932,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10835 | 10932 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10836 | 10933 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10837 | 10934 | extra_index += 1; |
| 10838 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10839 | | extra_index += 1; |
| 10840 | | extra_index += body_len; |
| 10935 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10936 | extra_index += 1 + info.body_len; |
| 10841 | 10937 | |
| 10842 | 10938 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10843 | 10939 | block, |
| ... | ... | @@ -10856,10 +10952,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10856 | 10952 | extra_index += 1; |
| 10857 | 10953 | const ranges_len = sema.code.extra[extra_index]; |
| 10858 | 10954 | extra_index += 1; |
| 10859 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10955 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10860 | 10956 | extra_index += 1; |
| 10861 | 10957 | const items = sema.code.refSlice(extra_index, items_len); |
| 10862 | | extra_index += items_len + body_len; |
| 10958 | extra_index += items_len + info.body_len; |
| 10863 | 10959 | |
| 10864 | 10960 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10865 | 10961 | for (items, 0..) |item_ref, item_i| { |
| ... | ... | @@ -10918,9 +11014,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10918 | 11014 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10919 | 11015 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10920 | 11016 | extra_index += 1; |
| 10921 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11017 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10922 | 11018 | extra_index += 1; |
| 10923 | | extra_index += body_len; |
| 11019 | extra_index += info.body_len; |
| 10924 | 11020 | |
| 10925 | 11021 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10926 | 11022 | block, |
| ... | ... | @@ -10939,10 +11035,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10939 | 11035 | extra_index += 1; |
| 10940 | 11036 | const ranges_len = sema.code.extra[extra_index]; |
| 10941 | 11037 | extra_index += 1; |
| 10942 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11038 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10943 | 11039 | extra_index += 1; |
| 10944 | 11040 | const items = sema.code.refSlice(extra_index, items_len); |
| 10945 | | extra_index += items_len + body_len; |
| 11041 | extra_index += items_len + info.body_len; |
| 10946 | 11042 | |
| 10947 | 11043 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10948 | 11044 | for (items, 0..) |item_ref, item_i| { |
| ... | ... | @@ -11006,7 +11102,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11006 | 11102 | .is_comptime = block.is_comptime, |
| 11007 | 11103 | .comptime_reason = block.comptime_reason, |
| 11008 | 11104 | .is_typeof = block.is_typeof, |
| 11009 | | .switch_else_err_ty = else_error_ty, |
| 11010 | 11105 | .c_import_buf = block.c_import_buf, |
| 11011 | 11106 | .runtime_cond = block.runtime_cond, |
| 11012 | 11107 | .runtime_loop = block.runtime_loop, |
| ... | ... | @@ -11024,19 +11119,31 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11024 | 11119 | var scalar_i: usize = 0; |
| 11025 | 11120 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11026 | 11121 | extra_index += 1; |
| 11027 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11028 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11122 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11029 | 11123 | extra_index += 1; |
| 11030 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11031 | | extra_index += body_len; |
| 11124 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11125 | extra_index += info.body_len; |
| 11032 | 11126 | |
| 11033 | 11127 | const item = case_vals.items[scalar_i]; |
| 11034 | | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11035 | | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11036 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11037 | | |
| 11128 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11129 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11130 | if (info.is_inline) child_block.inline_case_capture = operand; |
| 11038 | 11131 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11039 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11132 | return sema.resolveSwitchProngComptime( |
| 11133 | block, |
| 11134 | &child_block, |
| 11135 | src, |
| 11136 | raw_operand.val, |
| 11137 | raw_operand.ptr, |
| 11138 | .normal, |
| 11139 | body, |
| 11140 | info.capture, |
| 11141 | .{ .scalar = @intCast(u32, scalar_i) }, |
| 11142 | else_error_ty, |
| 11143 | &.{item}, |
| 11144 | inst, |
| 11145 | merges, |
| 11146 | ); |
| 11040 | 11147 | } |
| 11041 | 11148 | } |
| 11042 | 11149 | } |
| ... | ... | @@ -11048,22 +11155,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11048 | 11155 | extra_index += 1; |
| 11049 | 11156 | const ranges_len = sema.code.extra[extra_index]; |
| 11050 | 11157 | extra_index += 1; |
| 11051 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11052 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11158 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11053 | 11159 | extra_index += 1 + items_len; |
| 11054 | | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len]; |
| 11160 | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len]; |
| 11055 | 11161 | |
| 11056 | 11162 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11057 | 11163 | case_val_idx += items_len; |
| 11058 | 11164 | |
| 11059 | 11165 | for (items) |item| { |
| 11060 | 11166 | // Validation above ensured these will succeed. |
| 11061 | | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11062 | | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11063 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11064 | | |
| 11167 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11168 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11169 | if (info.is_inline) child_block.inline_case_capture = operand; |
| 11065 | 11170 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11066 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11171 | return sema.resolveSwitchProngComptime( |
| 11172 | block, |
| 11173 | &child_block, |
| 11174 | src, |
| 11175 | raw_operand.val, |
| 11176 | raw_operand.ptr, |
| 11177 | .normal, |
| 11178 | body, |
| 11179 | info.capture, |
| 11180 | .{ .multi_capture = @intCast(u32, multi_i) }, |
| 11181 | else_error_ty, |
| 11182 | items, |
| 11183 | inst, |
| 11184 | merges, |
| 11185 | ); |
| 11067 | 11186 | } |
| 11068 | 11187 | } |
| 11069 | 11188 | |
| ... | ... | @@ -11079,13 +11198,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11079 | 11198 | if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and |
| 11080 | 11199 | (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty))) |
| 11081 | 11200 | { |
| 11082 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11201 | if (info.is_inline) child_block.inline_case_capture = operand; |
| 11083 | 11202 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11084 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11203 | return sema.resolveSwitchProngComptime( |
| 11204 | block, |
| 11205 | &child_block, |
| 11206 | src, |
| 11207 | raw_operand.val, |
| 11208 | raw_operand.ptr, |
| 11209 | .normal, |
| 11210 | body, |
| 11211 | info.capture, |
| 11212 | .{ .multi_capture = @intCast(u32, multi_i) }, |
| 11213 | else_error_ty, |
| 11214 | undefined, |
| 11215 | inst, |
| 11216 | merges, |
| 11217 | ); |
| 11085 | 11218 | } |
| 11086 | 11219 | } |
| 11087 | 11220 | |
| 11088 | | extra_index += body_len; |
| 11221 | extra_index += info.body_len; |
| 11089 | 11222 | } |
| 11090 | 11223 | } |
| 11091 | 11224 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); |
| ... | ... | @@ -11093,7 +11226,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11093 | 11226 | if (empty_enum) { |
| 11094 | 11227 | return Air.Inst.Ref.void_value; |
| 11095 | 11228 | } |
| 11096 | | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 11229 | |
| 11230 | return sema.resolveSwitchProngComptime( |
| 11231 | block, |
| 11232 | &child_block, |
| 11233 | src, |
| 11234 | raw_operand.val, |
| 11235 | raw_operand.ptr, |
| 11236 | .special, |
| 11237 | special.body, |
| 11238 | special.capture, |
| 11239 | .special, |
| 11240 | else_error_ty, |
| 11241 | undefined, |
| 11242 | inst, |
| 11243 | merges, |
| 11244 | ); |
| 11097 | 11245 | } |
| 11098 | 11246 | |
| 11099 | 11247 | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| ... | ... | @@ -11113,7 +11261,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11113 | 11261 | const ok = try block.addUnOp(.is_named_enum_value, operand); |
| 11114 | 11262 | try sema.addSafetyCheck(block, ok, .corrupt_switch); |
| 11115 | 11263 | } |
| 11116 | | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 11264 | |
| 11265 | return sema.resolveSwitchProngComptime( |
| 11266 | block, |
| 11267 | &child_block, |
| 11268 | src, |
| 11269 | raw_operand.val, |
| 11270 | raw_operand.ptr, |
| 11271 | .special, |
| 11272 | special.body, |
| 11273 | special.capture, |
| 11274 | .special, |
| 11275 | else_error_ty, |
| 11276 | undefined, |
| 11277 | inst, |
| 11278 | merges, |
| 11279 | ); |
| 11117 | 11280 | } |
| 11118 | 11281 | |
| 11119 | 11282 | if (child_block.is_comptime) { |
| ... | ... | @@ -11140,11 +11303,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11140 | 11303 | var scalar_i: usize = 0; |
| 11141 | 11304 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11142 | 11305 | extra_index += 1; |
| 11143 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11144 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11306 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11145 | 11307 | extra_index += 1; |
| 11146 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11147 | | extra_index += body_len; |
| 11308 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11309 | extra_index += info.body_len; |
| 11148 | 11310 | |
| 11149 | 11311 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11150 | 11312 | defer wip_captures.deinit(); |
| ... | ... | @@ -11154,7 +11316,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11154 | 11316 | case_block.inline_case_capture = .none; |
| 11155 | 11317 | |
| 11156 | 11318 | const item = case_vals.items[scalar_i]; |
| 11157 | | if (is_inline) case_block.inline_case_capture = item; |
| 11319 | if (info.is_inline) case_block.inline_case_capture = item; |
| 11158 | 11320 | // `item` is already guaranteed to be constant known. |
| 11159 | 11321 | |
| 11160 | 11322 | const analyze_body = if (union_originally) blk: { |
| ... | ... | @@ -11166,7 +11328,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11166 | 11328 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11167 | 11329 | // nothing to do here |
| 11168 | 11330 | } else if (analyze_body) { |
| 11169 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11331 | try sema.analyzeSwitchProngRuntime( |
| 11332 | &case_block, |
| 11333 | raw_operand.val, |
| 11334 | raw_operand.ptr, |
| 11335 | .normal, |
| 11336 | body, |
| 11337 | info.capture, |
| 11338 | .{ .scalar = @intCast(u32, scalar_i) }, |
| 11339 | else_error_ty, |
| 11340 | &.{item}, |
| 11341 | inst, |
| 11342 | ); |
| 11170 | 11343 | } else { |
| 11171 | 11344 | _ = try case_block.addNoOp(.unreach); |
| 11172 | 11345 | } |
| ... | ... | @@ -11195,8 +11368,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11195 | 11368 | extra_index += 1; |
| 11196 | 11369 | const ranges_len = sema.code.extra[extra_index]; |
| 11197 | 11370 | extra_index += 1; |
| 11198 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11199 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11371 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11200 | 11372 | extra_index += 1 + items_len; |
| 11201 | 11373 | |
| 11202 | 11374 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| ... | ... | @@ -11207,9 +11379,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11207 | 11379 | case_block.inline_case_capture = .none; |
| 11208 | 11380 | |
| 11209 | 11381 | // Generate all possible cases as scalar prongs. |
| 11210 | | if (is_inline) { |
| 11382 | if (info.is_inline) { |
| 11211 | 11383 | const body_start = extra_index + 2 * ranges_len; |
| 11212 | | const body = sema.code.extra[body_start..][0..body_len]; |
| 11384 | const body = sema.code.extra[body_start..][0..info.body_len]; |
| 11213 | 11385 | var emit_bb = false; |
| 11214 | 11386 | |
| 11215 | 11387 | var range_i: u32 = 0; |
| ... | ... | @@ -11250,7 +11422,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11250 | 11422 | }; |
| 11251 | 11423 | emit_bb = true; |
| 11252 | 11424 | |
| 11253 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11425 | try sema.analyzeSwitchProngRuntime( |
| 11426 | &case_block, |
| 11427 | raw_operand.val, |
| 11428 | raw_operand.ptr, |
| 11429 | .normal, |
| 11430 | body, |
| 11431 | info.capture, |
| 11432 | .{ .multi_capture = multi_i }, |
| 11433 | else_error_ty, |
| 11434 | undefined, |
| 11435 | inst, |
| 11436 | ); |
| 11254 | 11437 | |
| 11255 | 11438 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11256 | 11439 | cases_extra.appendAssumeCapacity(1); // items_len |
| ... | ... | @@ -11286,7 +11469,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11286 | 11469 | emit_bb = true; |
| 11287 | 11470 | |
| 11288 | 11471 | if (analyze_body) { |
| 11289 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11472 | try sema.analyzeSwitchProngRuntime( |
| 11473 | &case_block, |
| 11474 | raw_operand.val, |
| 11475 | raw_operand.ptr, |
| 11476 | .normal, |
| 11477 | body, |
| 11478 | info.capture, |
| 11479 | .{ .multi_capture = multi_i }, |
| 11480 | else_error_ty, |
| 11481 | &.{item}, |
| 11482 | inst, |
| 11483 | ); |
| 11290 | 11484 | } else { |
| 11291 | 11485 | _ = try case_block.addNoOp(.unreach); |
| 11292 | 11486 | } |
| ... | ... | @@ -11298,7 +11492,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11298 | 11492 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11299 | 11493 | } |
| 11300 | 11494 | |
| 11301 | | extra_index += body_len; |
| 11495 | extra_index += info.body_len; |
| 11302 | 11496 | continue; |
| 11303 | 11497 | } |
| 11304 | 11498 | |
| ... | ... | @@ -11319,12 +11513,23 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11319 | 11513 | else |
| 11320 | 11514 | true; |
| 11321 | 11515 | |
| 11322 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11323 | | extra_index += body_len; |
| 11516 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11517 | extra_index += info.body_len; |
| 11324 | 11518 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11325 | 11519 | // nothing to do here |
| 11326 | 11520 | } else if (analyze_body) { |
| 11327 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11521 | try sema.analyzeSwitchProngRuntime( |
| 11522 | &case_block, |
| 11523 | raw_operand.val, |
| 11524 | raw_operand.ptr, |
| 11525 | .normal, |
| 11526 | body, |
| 11527 | info.capture, |
| 11528 | .{ .multi_capture = multi_i }, |
| 11529 | else_error_ty, |
| 11530 | items, |
| 11531 | inst, |
| 11532 | ); |
| 11328 | 11533 | } else { |
| 11329 | 11534 | _ = try case_block.addNoOp(.unreach); |
| 11330 | 11535 | } |
| ... | ... | @@ -11397,12 +11602,23 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11397 | 11602 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11398 | 11603 | case_block.wip_capture_scope = wip_captures.scope; |
| 11399 | 11604 | |
| 11400 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11401 | | extra_index += body_len; |
| 11605 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11606 | extra_index += info.body_len; |
| 11402 | 11607 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11403 | 11608 | // nothing to do here |
| 11404 | 11609 | } else { |
| 11405 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11610 | try sema.analyzeSwitchProngRuntime( |
| 11611 | &case_block, |
| 11612 | raw_operand.val, |
| 11613 | raw_operand.ptr, |
| 11614 | .normal, |
| 11615 | body, |
| 11616 | info.capture, |
| 11617 | .{ .multi_capture = multi_i }, |
| 11618 | else_error_ty, |
| 11619 | items, |
| 11620 | inst, |
| 11621 | ); |
| 11406 | 11622 | } |
| 11407 | 11623 | |
| 11408 | 11624 | try wip_captures.finalize(); |
| ... | ... | @@ -11461,7 +11677,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11461 | 11677 | emit_bb = true; |
| 11462 | 11678 | |
| 11463 | 11679 | if (analyze_body) { |
| 11464 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11680 | try sema.analyzeSwitchProngRuntime( |
| 11681 | &case_block, |
| 11682 | raw_operand.val, |
| 11683 | raw_operand.ptr, |
| 11684 | .special, |
| 11685 | special.body, |
| 11686 | special.capture, |
| 11687 | .special, |
| 11688 | else_error_ty, |
| 11689 | &.{item_ref}, |
| 11690 | inst, |
| 11691 | ); |
| 11465 | 11692 | } else { |
| 11466 | 11693 | _ = try case_block.addNoOp(.unreach); |
| 11467 | 11694 | } |
| ... | ... | @@ -11497,7 +11724,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11497 | 11724 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11498 | 11725 | emit_bb = true; |
| 11499 | 11726 | |
| 11500 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11727 | try sema.analyzeSwitchProngRuntime( |
| 11728 | &case_block, |
| 11729 | raw_operand.val, |
| 11730 | raw_operand.ptr, |
| 11731 | .special, |
| 11732 | special.body, |
| 11733 | special.capture, |
| 11734 | .special, |
| 11735 | else_error_ty, |
| 11736 | &.{item_ref}, |
| 11737 | inst, |
| 11738 | ); |
| 11501 | 11739 | |
| 11502 | 11740 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11503 | 11741 | cases_extra.appendAssumeCapacity(1); // items_len |
| ... | ... | @@ -11520,7 +11758,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11520 | 11758 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11521 | 11759 | emit_bb = true; |
| 11522 | 11760 | |
| 11523 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11761 | try sema.analyzeSwitchProngRuntime( |
| 11762 | &case_block, |
| 11763 | raw_operand.val, |
| 11764 | raw_operand.ptr, |
| 11765 | .special, |
| 11766 | special.body, |
| 11767 | special.capture, |
| 11768 | .special, |
| 11769 | else_error_ty, |
| 11770 | &.{item_ref}, |
| 11771 | inst, |
| 11772 | ); |
| 11524 | 11773 | |
| 11525 | 11774 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11526 | 11775 | cases_extra.appendAssumeCapacity(1); // items_len |
| ... | ... | @@ -11540,7 +11789,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11540 | 11789 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11541 | 11790 | emit_bb = true; |
| 11542 | 11791 | |
| 11543 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11792 | try sema.analyzeSwitchProngRuntime( |
| 11793 | &case_block, |
| 11794 | raw_operand.val, |
| 11795 | raw_operand.ptr, |
| 11796 | .special, |
| 11797 | special.body, |
| 11798 | special.capture, |
| 11799 | .special, |
| 11800 | else_error_ty, |
| 11801 | &.{Air.Inst.Ref.bool_true}, |
| 11802 | inst, |
| 11803 | ); |
| 11544 | 11804 | |
| 11545 | 11805 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11546 | 11806 | cases_extra.appendAssumeCapacity(1); // items_len |
| ... | ... | @@ -11558,7 +11818,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11558 | 11818 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11559 | 11819 | emit_bb = true; |
| 11560 | 11820 | |
| 11561 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11821 | try sema.analyzeSwitchProngRuntime( |
| 11822 | &case_block, |
| 11823 | raw_operand.val, |
| 11824 | raw_operand.ptr, |
| 11825 | .special, |
| 11826 | special.body, |
| 11827 | special.capture, |
| 11828 | .special, |
| 11829 | else_error_ty, |
| 11830 | &.{Air.Inst.Ref.bool_false}, |
| 11831 | inst, |
| 11832 | ); |
| 11562 | 11833 | |
| 11563 | 11834 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11564 | 11835 | cases_extra.appendAssumeCapacity(1); // items_len |
| ... | ... | @@ -11601,7 +11872,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11601 | 11872 | { |
| 11602 | 11873 | // nothing to do here |
| 11603 | 11874 | } else if (special.body.len != 0 and analyze_body and !special.is_inline) { |
| 11604 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11875 | try sema.analyzeSwitchProngRuntime( |
| 11876 | &case_block, |
| 11877 | raw_operand.val, |
| 11878 | raw_operand.ptr, |
| 11879 | .special, |
| 11880 | special.body, |
| 11881 | special.capture, |
| 11882 | .special, |
| 11883 | else_error_ty, |
| 11884 | undefined, |
| 11885 | inst, |
| 11886 | ); |
| 11605 | 11887 | } else { |
| 11606 | 11888 | // We still need a terminator in this block, but we have proven |
| 11607 | 11889 | // that it is unreachable. |
| ... | ... | @@ -11746,7 +12028,7 @@ fn resolveSwitchItemVal( |
| 11746 | 12028 | else => |e| return e, |
| 11747 | 12029 | }; |
| 11748 | 12030 | |
| 11749 | | const val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch |err| switch (err) { |
| 12031 | const maybe_lazy = sema.resolveConstValue(block, .unneeded, item, "") catch |err| switch (err) { |
| 11750 | 12032 | error.NeededSourceLocation => { |
| 11751 | 12033 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 11752 | 12034 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| ... | ... | @@ -11755,7 +12037,12 @@ fn resolveSwitchItemVal( |
| 11755 | 12037 | else => |e| return e, |
| 11756 | 12038 | }; |
| 11757 | 12039 | |
| 11758 | | return .{ .ref = item, .val = val.toIntern() }; |
| 12040 | const val = try sema.resolveLazyValue(maybe_lazy); |
| 12041 | const new_item = if (val.toIntern() != maybe_lazy.toIntern()) blk: { |
| 12042 | break :blk try sema.addConstant(coerce_ty, val); |
| 12043 | } else item; |
| 12044 | |
| 12045 | return .{ .ref = new_item, .val = val.toIntern() }; |
| 11759 | 12046 | } |
| 11760 | 12047 | |
| 11761 | 12048 | fn validateSwitchRange( |