| ... | ... | @@ -1097,7 +1097,7 @@ fn analyzeBodyInner( |
| 1097 | 1097 | .str => try sema.zirStr(inst), |
| 1098 | 1098 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1099 | 1099 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| 1100 | | .switch_block_err_union => @panic("TODO: implement lowering of switch_block_err_union"), |
| 1100 | .switch_block_err_union => try sema.zirSwitchBlockErrUnion(block, inst), |
| 1101 | 1101 | .type_info => try sema.zirTypeInfo(block, inst), |
| 1102 | 1102 | .size_of => try sema.zirSizeOf(block, inst), |
| 1103 | 1103 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| ... | ... | @@ -11160,6 +11160,195 @@ fn switchCond( |
| 11160 | 11160 | |
| 11161 | 11161 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); |
| 11162 | 11162 | |
| 11163 | fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11164 | const tracy = trace(@src()); |
| 11165 | defer tracy.end(); |
| 11166 | |
| 11167 | const mod = sema.mod; |
| 11168 | const gpa = sema.gpa; |
| 11169 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 11170 | const src = inst_data.src(); |
| 11171 | const src_node_offset = inst_data.src_node; |
| 11172 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; |
| 11173 | const else_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; |
| 11174 | const extra = sema.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index); |
| 11175 | |
| 11176 | const raw_operand_val = try sema.resolveInst(extra.data.operand); |
| 11177 | assert(sema.typeOf(raw_operand_val).zigTypeTag(mod) == .ErrorUnion); |
| 11178 | |
| 11179 | // AstGen guarantees that the instruction immediately preceding |
| 11180 | // switch_block_err_union is a dbg_stmt |
| 11181 | const cond_dbg_node_index: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1); |
| 11182 | _ = cond_dbg_node_index; |
| 11183 | |
| 11184 | var header_extra_index: usize = extra.end; |
| 11185 | |
| 11186 | const scalar_cases_len = extra.data.bits.scalar_cases_len; |
| 11187 | const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { |
| 11188 | const multi_cases_len = sema.code.extra[header_extra_index]; |
| 11189 | header_extra_index += 1; |
| 11190 | break :blk multi_cases_len; |
| 11191 | } else 0; |
| 11192 | |
| 11193 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 11194 | defer case_vals.deinit(gpa); |
| 11195 | |
| 11196 | const NonError = struct { |
| 11197 | body: []const Zir.Inst.Index, |
| 11198 | end: usize, |
| 11199 | }; |
| 11200 | |
| 11201 | const non_error_case: NonError = non_error: { |
| 11202 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]); |
| 11203 | const extra_body_start = header_extra_index + 1; |
| 11204 | break :non_error .{ |
| 11205 | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11206 | .end = extra_body_start + info.body_len, |
| 11207 | }; |
| 11208 | }; |
| 11209 | |
| 11210 | const Else = struct { |
| 11211 | body: []const Zir.Inst.Index, |
| 11212 | end: usize, |
| 11213 | is_inline: bool, |
| 11214 | has_capture: bool, |
| 11215 | }; |
| 11216 | |
| 11217 | const else_case: Else = if (!extra.data.bits.has_else) .{ |
| 11218 | .body = &.{}, |
| 11219 | .end = non_error_case.end, |
| 11220 | .is_inline = false, |
| 11221 | .has_capture = false, |
| 11222 | } else special: { |
| 11223 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[non_error_case.end]); |
| 11224 | const extra_body_start = non_error_case.end + 1; |
| 11225 | assert(info.capture != .by_ref); |
| 11226 | assert(!info.has_tag_capture); |
| 11227 | break :special .{ |
| 11228 | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11229 | .end = extra_body_start + info.body_len, |
| 11230 | .is_inline = info.is_inline, |
| 11231 | .has_capture = info.capture == .by_val, |
| 11232 | }; |
| 11233 | }; |
| 11234 | |
| 11235 | var seen_errors = SwitchErrorSet.init(gpa); |
| 11236 | defer seen_errors.deinit(); |
| 11237 | |
| 11238 | const operand_ty = sema.typeOf(raw_operand_val); |
| 11239 | const operand_err_set_ty = operand_ty.errorUnionSet(mod); |
| 11240 | |
| 11241 | const else_error_ty: ?Type = try validateErrSetSwitch( |
| 11242 | sema, |
| 11243 | block, |
| 11244 | &seen_errors, |
| 11245 | &case_vals, |
| 11246 | operand_err_set_ty, |
| 11247 | inst_data, |
| 11248 | scalar_cases_len, |
| 11249 | multi_cases_len, |
| 11250 | .{ .body = else_case.body, .end = else_case.end, .src = else_prong_src }, |
| 11251 | extra.data.bits.has_else, |
| 11252 | ); |
| 11253 | |
| 11254 | var spa: SwitchProngAnalysis = .{ |
| 11255 | .sema = sema, |
| 11256 | .parent_block = block, |
| 11257 | .operand = raw_operand_val, |
| 11258 | .operand_ptr = .none, |
| 11259 | .cond = raw_operand_val, |
| 11260 | .else_error_ty = else_error_ty, |
| 11261 | .switch_block_inst = inst, |
| 11262 | .tag_capture_inst = undefined, |
| 11263 | }; |
| 11264 | |
| 11265 | const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); |
| 11266 | try sema.air_instructions.append(gpa, .{ |
| 11267 | .tag = .block, |
| 11268 | .data = undefined, |
| 11269 | }); |
| 11270 | var label: Block.Label = .{ |
| 11271 | .zir_block = inst, |
| 11272 | .merges = .{ |
| 11273 | .src_locs = .{}, |
| 11274 | .results = .{}, |
| 11275 | .br_list = .{}, |
| 11276 | .block_inst = block_inst, |
| 11277 | }, |
| 11278 | }; |
| 11279 | |
| 11280 | var child_block: Block = .{ |
| 11281 | .parent = block, |
| 11282 | .sema = sema, |
| 11283 | .src_decl = block.src_decl, |
| 11284 | .namespace = block.namespace, |
| 11285 | .wip_capture_scope = block.wip_capture_scope, |
| 11286 | .instructions = .{}, |
| 11287 | .label = &label, |
| 11288 | .inlining = block.inlining, |
| 11289 | .is_comptime = block.is_comptime, |
| 11290 | .comptime_reason = block.comptime_reason, |
| 11291 | .is_typeof = block.is_typeof, |
| 11292 | .c_import_buf = block.c_import_buf, |
| 11293 | .runtime_cond = block.runtime_cond, |
| 11294 | .runtime_loop = block.runtime_loop, |
| 11295 | .runtime_index = block.runtime_index, |
| 11296 | .error_return_trace_index = block.error_return_trace_index, |
| 11297 | }; |
| 11298 | const merges = &child_block.label.?.merges; |
| 11299 | defer child_block.instructions.deinit(gpa); |
| 11300 | defer merges.deinit(gpa); |
| 11301 | |
| 11302 | if (try sema.resolveDefinedValue(&child_block, src, raw_operand_val)) |operand_val| { |
| 11303 | if (operand_val.errorUnionIsPayload(mod)) { |
| 11304 | return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges); |
| 11305 | } else { |
| 11306 | const err_val = Value.fromInterned(try mod.intern(.{ |
| 11307 | .err = .{ |
| 11308 | .ty = operand_err_set_ty.toIntern(), |
| 11309 | .name = operand_val.getErrorName(mod).unwrap().?, |
| 11310 | }, |
| 11311 | })); |
| 11312 | spa.operand = try sema.analyzeErrUnionCode(block, operand_src, raw_operand_val); |
| 11313 | return resolveSwitchComptime( |
| 11314 | sema, |
| 11315 | spa, |
| 11316 | &child_block, |
| 11317 | try sema.switchCond(block, operand_src, spa.operand), |
| 11318 | err_val, |
| 11319 | operand_err_set_ty, |
| 11320 | .{ |
| 11321 | .body = else_case.body, |
| 11322 | .end = else_case.end, |
| 11323 | .capture = if (else_case.has_capture) .by_val else .none, |
| 11324 | .is_inline = else_case.is_inline, |
| 11325 | .has_tag_capture = false, |
| 11326 | }, |
| 11327 | case_vals, |
| 11328 | scalar_cases_len, |
| 11329 | multi_cases_len, |
| 11330 | true, |
| 11331 | false, |
| 11332 | ); |
| 11333 | } |
| 11334 | } |
| 11335 | |
| 11336 | if (scalar_cases_len + multi_cases_len == 0) { |
| 11337 | if (else_error_ty) |ty| if (ty.errorSetIsEmpty(mod)) { |
| 11338 | return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges); |
| 11339 | }; |
| 11340 | } |
| 11341 | |
| 11342 | if (child_block.is_comptime) { |
| 11343 | _ = try sema.resolveConstDefinedValue(&child_block, operand_src, operand, .{ |
| 11344 | .needed_comptime_reason = "condition in comptime switch must be comptime-known", |
| 11345 | .block_comptime_reason = child_block.comptime_reason, |
| 11346 | }); |
| 11347 | unreachable; |
| 11348 | } |
| 11349 | return sema.fail(block, src, "TODO: implement more of switch_block_err_union", .{}); |
| 11350 | } |
| 11351 | |
| 11163 | 11352 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref { |
| 11164 | 11353 | const tracy = trace(@src()); |
| 11165 | 11354 | defer tracy.end(); |