| ... | ... | @@ -10928,7 +10928,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 10928 | 10928 | const switch_src = block.nodeOffset(inst_data.src_node); |
| 10929 | 10929 | const switch_src_node_offset = inst_data.src_node; |
| 10930 | 10930 | const switch_operand_src = block.src(.{ .node_offset_switch_operand = switch_src_node_offset }); |
| 10931 | | const else_prong_src = block.src(.{ .node_offset_switch_special_prong = switch_src_node_offset }); |
| 10931 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = switch_src_node_offset }); |
| 10932 | 10932 | const extra = sema.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index); |
| 10933 | 10933 | const main_operand_src = block.src(.{ .node_offset_if_cond = extra.data.main_src_node_offset }); |
| 10934 | 10934 | const main_src = block.src(.{ .node_offset_main_token = extra.data.main_src_node_offset }); |
| ... | ... | @@ -11122,6 +11122,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11122 | 11122 | err_val, |
| 11123 | 11123 | operand_err_set_ty, |
| 11124 | 11124 | switch_src_node_offset, |
| 11125 | null, |
| 11125 | 11126 | .{ |
| 11126 | 11127 | .body = else_case.body, |
| 11127 | 11128 | .end = else_case.end, |
| ... | ... | @@ -11129,6 +11130,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11129 | 11130 | .is_inline = else_case.is_inline, |
| 11130 | 11131 | .has_tag_capture = false, |
| 11131 | 11132 | }, |
| 11133 | false, |
| 11132 | 11134 | case_vals, |
| 11133 | 11135 | scalar_cases_len, |
| 11134 | 11136 | multi_cases_len, |
| ... | ... | @@ -11200,6 +11202,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11200 | 11202 | true, |
| 11201 | 11203 | switch_src_node_offset, |
| 11202 | 11204 | else_prong_src, |
| 11205 | false, |
| 11203 | 11206 | undefined, |
| 11204 | 11207 | seen_errors, |
| 11205 | 11208 | undefined, |
| ... | ... | @@ -11207,6 +11210,10 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11207 | 11210 | undefined, |
| 11208 | 11211 | cond_dbg_node_index, |
| 11209 | 11212 | true, |
| 11213 | null, |
| 11214 | undefined, |
| 11215 | &.{}, |
| 11216 | &.{}, |
| 11210 | 11217 | ); |
| 11211 | 11218 | |
| 11212 | 11219 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + |
| ... | ... | @@ -11243,12 +11250,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11243 | 11250 | |
| 11244 | 11251 | const pt = sema.pt; |
| 11245 | 11252 | const zcu = pt.zcu; |
| 11253 | const ip = &zcu.intern_pool; |
| 11246 | 11254 | const gpa = sema.gpa; |
| 11247 | 11255 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 11248 | 11256 | const src = block.nodeOffset(inst_data.src_node); |
| 11249 | 11257 | const src_node_offset = inst_data.src_node; |
| 11250 | 11258 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11251 | | const special_prong_src = block.src(.{ .node_offset_switch_special_prong = src_node_offset }); |
| 11259 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); |
| 11260 | const under_prong_src = block.src(.{ .node_offset_switch_under_prong = src_node_offset }); |
| 11252 | 11261 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 11253 | 11262 | |
| 11254 | 11263 | const operand: SwitchProngAnalysis.Operand, const raw_operand_ty: Type = op: { |
| ... | ... | @@ -11335,50 +11344,63 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11335 | 11344 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 11336 | 11345 | defer case_vals.deinit(gpa); |
| 11337 | 11346 | |
| 11347 | var single_absorbed_item: Zir.Inst.Ref = .none; |
| 11338 | 11348 | var absorbed_items: []const Zir.Inst.Ref = &.{}; |
| 11339 | 11349 | var absorbed_ranges: []const Zir.Inst.Ref = &.{}; |
| 11340 | 11350 | |
| 11341 | | const special_prong = extra.data.bits.special_prong; |
| 11342 | | const special: SpecialProng = switch (special_prong) { |
| 11343 | | .none => .{ |
| 11344 | | .body = &.{}, |
| 11345 | | .end = header_extra_index, |
| 11346 | | .capture = .none, |
| 11347 | | .is_inline = false, |
| 11348 | | .has_tag_capture = false, |
| 11349 | | }, |
| 11350 | | .under, .@"else" => blk: { |
| 11351 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]); |
| 11352 | | const extra_body_start = header_extra_index + 1; |
| 11353 | | break :blk .{ |
| 11354 | | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11355 | | .end = extra_body_start + info.body_len, |
| 11356 | | .capture = info.capture, |
| 11357 | | .is_inline = info.is_inline, |
| 11358 | | .has_tag_capture = info.has_tag_capture, |
| 11359 | | }; |
| 11360 | | }, |
| 11361 | | .absorbing_under => blk: { |
| 11362 | | var extra_index = header_extra_index; |
| 11351 | const special_prongs = extra.data.bits.special_prongs; |
| 11352 | const has_else = special_prongs.hasElse(); |
| 11353 | const has_under = special_prongs.hasUnder(); |
| 11354 | const special_else: SpecialProng = if (has_else) blk: { |
| 11355 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]); |
| 11356 | const extra_body_start = header_extra_index + 1; |
| 11357 | break :blk .{ |
| 11358 | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11359 | .end = extra_body_start + info.body_len, |
| 11360 | .capture = info.capture, |
| 11361 | .is_inline = info.is_inline, |
| 11362 | .has_tag_capture = info.has_tag_capture, |
| 11363 | }; |
| 11364 | } else .{ |
| 11365 | .body = &.{}, |
| 11366 | .end = header_extra_index, |
| 11367 | .capture = .none, |
| 11368 | .is_inline = false, |
| 11369 | .has_tag_capture = false, |
| 11370 | }; |
| 11371 | const special_under: SpecialProng = if (has_under) blk: { |
| 11372 | var extra_index = special_else.end; |
| 11373 | var trailing_items_len: usize = 0; |
| 11374 | if (special_prongs.hasOneAdditionalItem()) { |
| 11375 | single_absorbed_item = @enumFromInt(sema.code.extra[extra_index]); |
| 11376 | extra_index += 1; |
| 11377 | absorbed_items = @ptrCast(&single_absorbed_item); |
| 11378 | } else if (special_prongs.hasManyAdditionalItems()) { |
| 11363 | 11379 | const items_len = sema.code.extra[extra_index]; |
| 11364 | 11380 | extra_index += 1; |
| 11365 | 11381 | const ranges_len = sema.code.extra[extra_index]; |
| 11366 | 11382 | extra_index += 1; |
| 11367 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11368 | | extra_index += 1; |
| 11369 | | absorbed_items = sema.code.refSlice(extra_index, items_len); |
| 11370 | | extra_index += items_len; |
| 11371 | | absorbed_ranges = sema.code.refSlice(extra_index, ranges_len * 2); |
| 11372 | | extra_index += ranges_len * 2; |
| 11373 | | break :blk .{ |
| 11374 | | .body = sema.code.bodySlice(extra_index, info.body_len), |
| 11375 | | .end = extra_index + info.body_len, |
| 11376 | | .capture = info.capture, |
| 11377 | | .is_inline = info.is_inline, |
| 11378 | | .has_tag_capture = info.has_tag_capture, |
| 11379 | | }; |
| 11380 | | }, |
| 11383 | absorbed_items = sema.code.refSlice(extra_index + 1, items_len); |
| 11384 | absorbed_ranges = sema.code.refSlice(extra_index + 1 + items_len, ranges_len * 2); |
| 11385 | trailing_items_len = items_len + ranges_len * 2; |
| 11386 | } |
| 11387 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11388 | extra_index += 1 + trailing_items_len; |
| 11389 | break :blk .{ |
| 11390 | .body = sema.code.bodySlice(extra_index, info.body_len), |
| 11391 | .end = extra_index + info.body_len, |
| 11392 | .capture = info.capture, |
| 11393 | .is_inline = info.is_inline, |
| 11394 | .has_tag_capture = info.has_tag_capture, |
| 11395 | }; |
| 11396 | } else .{ |
| 11397 | .body = &.{}, |
| 11398 | .end = special_else.end, |
| 11399 | .capture = .none, |
| 11400 | .is_inline = false, |
| 11401 | .has_tag_capture = false, |
| 11381 | 11402 | }; |
| 11403 | const special_end = special_under.end; |
| 11382 | 11404 | |
| 11383 | 11405 | // Duplicate checking variables later also used for `inline else`. |
| 11384 | 11406 | var seen_enum_fields: []?LazySrcLoc = &.{}; |
| ... | ... | @@ -11398,9 +11420,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11398 | 11420 | var else_error_ty: ?Type = null; |
| 11399 | 11421 | |
| 11400 | 11422 | // Validate usage of '_' prongs. |
| 11401 | | if ((special_prong == .under or special_prong == .absorbing_under) and |
| 11402 | | !raw_operand_ty.isNonexhaustiveEnum(zcu)) |
| 11403 | | { |
| 11423 | if (has_under and !raw_operand_ty.isNonexhaustiveEnum(zcu)) { |
| 11404 | 11424 | const msg = msg: { |
| 11405 | 11425 | const msg = try sema.errMsg( |
| 11406 | 11426 | src, |
| ... | ... | @@ -11409,7 +11429,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11409 | 11429 | ); |
| 11410 | 11430 | errdefer msg.destroy(gpa); |
| 11411 | 11431 | try sema.errNote( |
| 11412 | | special_prong_src, |
| 11432 | under_prong_src, |
| 11413 | 11433 | msg, |
| 11414 | 11434 | "'_' prong here", |
| 11415 | 11435 | .{}, |
| ... | ... | @@ -11443,14 +11463,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11443 | 11463 | cond_ty, |
| 11444 | 11464 | block.src(.{ .switch_case_item = .{ |
| 11445 | 11465 | .switch_node_offset = src_node_offset, |
| 11446 | | .case_idx = .special, |
| 11466 | .case_idx = .special_under, |
| 11447 | 11467 | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 11448 | 11468 | } }), |
| 11449 | 11469 | ); |
| 11450 | 11470 | } |
| 11451 | 11471 | try sema.validateSwitchNoRange(block, @intCast(absorbed_ranges.len), cond_ty, src_node_offset); |
| 11452 | 11472 | |
| 11453 | | var extra_index: usize = special.end; |
| 11473 | var extra_index: usize = special_end; |
| 11454 | 11474 | { |
| 11455 | 11475 | var scalar_i: u32 = 0; |
| 11456 | 11476 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11508,13 +11528,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11508 | 11528 | if (seen_src == null) break false; |
| 11509 | 11529 | } else true; |
| 11510 | 11530 | |
| 11511 | | if (special_prong == .@"else") { |
| 11512 | | if (all_tags_handled and !cond_ty.isNonexhaustiveEnum(zcu)) return sema.fail( |
| 11513 | | block, |
| 11514 | | special_prong_src, |
| 11515 | | "unreachable else prong; all cases already handled", |
| 11516 | | .{}, |
| 11517 | | ); |
| 11531 | if (has_else) { |
| 11532 | if (all_tags_handled) { |
| 11533 | if (cond_ty.isNonexhaustiveEnum(zcu)) { |
| 11534 | if (has_under) return sema.fail( |
| 11535 | block, |
| 11536 | else_prong_src, |
| 11537 | "unreachable else prong; all explicit cases already handled", |
| 11538 | .{}, |
| 11539 | ); |
| 11540 | } else return sema.fail( |
| 11541 | block, |
| 11542 | else_prong_src, |
| 11543 | "unreachable else prong; all cases already handled", |
| 11544 | .{}, |
| 11545 | ); |
| 11546 | } |
| 11518 | 11547 | } else if (!all_tags_handled) { |
| 11519 | 11548 | const msg = msg: { |
| 11520 | 11549 | const msg = try sema.errMsg( |
| ... | ... | @@ -11532,7 +11561,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11532 | 11561 | i, |
| 11533 | 11562 | msg, |
| 11534 | 11563 | "unhandled enumeration value: '{f}'", |
| 11535 | | .{field_name.fmt(&zcu.intern_pool)}, |
| 11564 | .{field_name.fmt(ip)}, |
| 11536 | 11565 | ); |
| 11537 | 11566 | } |
| 11538 | 11567 | try sema.errNote( |
| ... | ... | @@ -11544,11 +11573,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11544 | 11573 | break :msg msg; |
| 11545 | 11574 | }; |
| 11546 | 11575 | return sema.failWithOwnedErrorMsg(block, msg); |
| 11547 | | } else if (special_prong == .none and cond_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 11576 | } else if (special_prongs == .none and cond_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 11548 | 11577 | return sema.fail( |
| 11549 | 11578 | block, |
| 11550 | 11579 | src, |
| 11551 | | "switch on non-exhaustive enum must include 'else' or '_' prong", |
| 11580 | "switch on non-exhaustive enum must include 'else' or '_' prong or both", |
| 11552 | 11581 | .{}, |
| 11553 | 11582 | ); |
| 11554 | 11583 | } |
| ... | ... | @@ -11562,11 +11591,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11562 | 11591 | inst_data, |
| 11563 | 11592 | scalar_cases_len, |
| 11564 | 11593 | multi_cases_len, |
| 11565 | | .{ .body = special.body, .end = special.end, .src = special_prong_src }, |
| 11566 | | special_prong == .@"else", |
| 11594 | .{ .body = special_else.body, .end = special_else.end, .src = else_prong_src }, |
| 11595 | has_else, |
| 11567 | 11596 | ), |
| 11568 | 11597 | .int, .comptime_int => { |
| 11569 | | var extra_index: usize = special.end; |
| 11598 | var extra_index: usize = special_end; |
| 11570 | 11599 | { |
| 11571 | 11600 | var scalar_i: u32 = 0; |
| 11572 | 11601 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11648,10 +11677,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11648 | 11677 | const min_int = try cond_ty.minInt(pt, cond_ty); |
| 11649 | 11678 | const max_int = try cond_ty.maxInt(pt, cond_ty); |
| 11650 | 11679 | if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) { |
| 11651 | | if (special_prong == .@"else") { |
| 11680 | if (has_else) { |
| 11652 | 11681 | return sema.fail( |
| 11653 | 11682 | block, |
| 11654 | | special_prong_src, |
| 11683 | else_prong_src, |
| 11655 | 11684 | "unreachable else prong; all cases already handled", |
| 11656 | 11685 | .{}, |
| 11657 | 11686 | ); |
| ... | ... | @@ -11659,7 +11688,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11659 | 11688 | break :check_range; |
| 11660 | 11689 | } |
| 11661 | 11690 | } |
| 11662 | | if (special_prong != .@"else") { |
| 11691 | if (special_prongs == .none) { |
| 11663 | 11692 | return sema.fail( |
| 11664 | 11693 | block, |
| 11665 | 11694 | src, |
| ... | ... | @@ -11670,7 +11699,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11670 | 11699 | } |
| 11671 | 11700 | }, |
| 11672 | 11701 | .bool => { |
| 11673 | | var extra_index: usize = special.end; |
| 11702 | var extra_index: usize = special_end; |
| 11674 | 11703 | { |
| 11675 | 11704 | var scalar_i: u32 = 0; |
| 11676 | 11705 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11722,31 +11751,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11722 | 11751 | try sema.validateSwitchNoRange(block, ranges_len, cond_ty, src_node_offset); |
| 11723 | 11752 | } |
| 11724 | 11753 | } |
| 11725 | | switch (special_prong) { |
| 11726 | | .@"else" => { |
| 11727 | | if (true_count + false_count == 2) { |
| 11728 | | return sema.fail( |
| 11729 | | block, |
| 11730 | | special_prong_src, |
| 11731 | | "unreachable else prong; all cases already handled", |
| 11732 | | .{}, |
| 11733 | | ); |
| 11734 | | } |
| 11735 | | }, |
| 11736 | | .under, .absorbing_under, .none => { |
| 11737 | | if (true_count + false_count < 2) { |
| 11738 | | return sema.fail( |
| 11739 | | block, |
| 11740 | | src, |
| 11741 | | "switch must handle all possibilities", |
| 11742 | | .{}, |
| 11743 | | ); |
| 11744 | | } |
| 11745 | | }, |
| 11754 | if (has_else) { |
| 11755 | if (true_count + false_count == 2) { |
| 11756 | return sema.fail( |
| 11757 | block, |
| 11758 | else_prong_src, |
| 11759 | "unreachable else prong; all cases already handled", |
| 11760 | .{}, |
| 11761 | ); |
| 11762 | } |
| 11763 | } else { |
| 11764 | if (true_count + false_count < 2) { |
| 11765 | return sema.fail( |
| 11766 | block, |
| 11767 | src, |
| 11768 | "switch must handle all possibilities", |
| 11769 | .{}, |
| 11770 | ); |
| 11771 | } |
| 11746 | 11772 | } |
| 11747 | 11773 | }, |
| 11748 | 11774 | .enum_literal, .void, .@"fn", .pointer, .type => { |
| 11749 | | if (special_prong != .@"else") { |
| 11775 | if (!has_else) { |
| 11750 | 11776 | return sema.fail( |
| 11751 | 11777 | block, |
| 11752 | 11778 | src, |
| ... | ... | @@ -11758,7 +11784,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11758 | 11784 | var seen_values = ValueSrcMap{}; |
| 11759 | 11785 | defer seen_values.deinit(gpa); |
| 11760 | 11786 | |
| 11761 | | var extra_index: usize = special.end; |
| 11787 | var extra_index: usize = special_end; |
| 11762 | 11788 | { |
| 11763 | 11789 | var scalar_i: u32 = 0; |
| 11764 | 11790 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11831,6 +11857,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11831 | 11857 | }), |
| 11832 | 11858 | } |
| 11833 | 11859 | |
| 11860 | var special_members_only: ?SpecialProng = null; |
| 11861 | var special_members_only_src: LazySrcLoc = undefined; |
| 11862 | const special_generic, const special_generic_src = if (has_under) b: { |
| 11863 | if (has_else) { |
| 11864 | special_members_only = special_else; |
| 11865 | special_members_only_src = else_prong_src; |
| 11866 | } |
| 11867 | break :b .{ special_under, under_prong_src }; |
| 11868 | } else .{ special_else, else_prong_src }; |
| 11869 | |
| 11834 | 11870 | const spa: SwitchProngAnalysis = .{ |
| 11835 | 11871 | .sema = sema, |
| 11836 | 11872 | .parent_block = block, |
| ... | ... | @@ -11877,11 +11913,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11877 | 11913 | defer child_block.instructions.deinit(gpa); |
| 11878 | 11914 | defer merges.deinit(gpa); |
| 11879 | 11915 | |
| 11880 | | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| 11916 | if (scalar_cases_len + multi_cases_len == 0 and |
| 11917 | special_members_only == null and |
| 11918 | !special_generic.is_inline) |
| 11919 | { |
| 11881 | 11920 | if (empty_enum) { |
| 11882 | 11921 | return .void_value; |
| 11883 | 11922 | } |
| 11884 | | if (special_prong == .none) { |
| 11923 | if (special_prongs == .none) { |
| 11885 | 11924 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 11886 | 11925 | } |
| 11887 | 11926 | const init_cond = switch (operand) { |
| ... | ... | @@ -11895,7 +11934,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11895 | 11934 | const ok = try block.addUnOp(.is_named_enum_value, init_cond); |
| 11896 | 11935 | try sema.addSafetyCheck(block, src, ok, .corrupt_switch); |
| 11897 | 11936 | } |
| 11898 | | if (err_set and try sema.maybeErrorUnwrap(block, special.body, init_cond, operand_src, false)) { |
| 11937 | if (err_set and try sema.maybeErrorUnwrap(block, special_generic.body, init_cond, operand_src, false)) { |
| 11899 | 11938 | return .unreachable_value; |
| 11900 | 11939 | } |
| 11901 | 11940 | } |
| ... | ... | @@ -11915,7 +11954,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11915 | 11954 | cond_ty, |
| 11916 | 11955 | cond_val, |
| 11917 | 11956 | src_node_offset, |
| 11918 | | special, |
| 11957 | special_members_only, |
| 11958 | special_generic, |
| 11959 | has_under, |
| 11919 | 11960 | case_vals, |
| 11920 | 11961 | scalar_cases_len, |
| 11921 | 11962 | multi_cases_len, |
| ... | ... | @@ -11925,15 +11966,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11925 | 11966 | ); |
| 11926 | 11967 | } |
| 11927 | 11968 | |
| 11928 | | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline and !extra.data.bits.has_continue) { |
| 11969 | if (scalar_cases_len + multi_cases_len == 0 and |
| 11970 | special_members_only == null and |
| 11971 | !special_generic.is_inline and |
| 11972 | !extra.data.bits.has_continue) |
| 11973 | { |
| 11929 | 11974 | return spa.resolveProngComptime( |
| 11930 | 11975 | &child_block, |
| 11931 | 11976 | .special, |
| 11932 | | special.body, |
| 11933 | | special.capture, |
| 11977 | special_generic.body, |
| 11978 | special_generic.capture, |
| 11934 | 11979 | block.src(.{ .switch_capture = .{ |
| 11935 | 11980 | .switch_node_offset = src_node_offset, |
| 11936 | | .case_idx = .special, |
| 11981 | .case_idx = if (has_under) .special_under else .special_else, |
| 11937 | 11982 | } }), |
| 11938 | 11983 | undefined, // case_vals may be undefined for special prongs |
| 11939 | 11984 | .none, |
| ... | ... | @@ -11949,6 +11994,88 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11949 | 11994 | unreachable; |
| 11950 | 11995 | } |
| 11951 | 11996 | |
| 11997 | var extra_case_vals: struct { |
| 11998 | items: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 11999 | ranges: std.ArrayListUnmanaged([2]Air.Inst.Ref), |
| 12000 | } = .{ .items = .empty, .ranges = .empty }; |
| 12001 | defer { |
| 12002 | extra_case_vals.items.deinit(gpa); |
| 12003 | extra_case_vals.ranges.deinit(gpa); |
| 12004 | } |
| 12005 | |
| 12006 | // Runtime switch, if we have a special_members_only prong we need to unroll |
| 12007 | // it to a prong with explicit items. |
| 12008 | // Although this is potentially the same as `inline else` it does not count |
| 12009 | // towards the backward branch quota because it's an implementation detail. |
| 12010 | if (special_members_only) |special| gen: { |
| 12011 | assert(cond_ty.isNonexhaustiveEnum(zcu)); |
| 12012 | _ = special; |
| 12013 | |
| 12014 | var min_i: usize = math.maxInt(usize); |
| 12015 | var max_i: usize = 0; |
| 12016 | var seen_field_count: usize = 0; |
| 12017 | for (seen_enum_fields, 0..) |seen, enum_i| { |
| 12018 | if (seen != null) { |
| 12019 | seen_field_count += 1; |
| 12020 | } else { |
| 12021 | min_i = @min(min_i, enum_i); |
| 12022 | max_i = @max(max_i, enum_i); |
| 12023 | } |
| 12024 | } |
| 12025 | if (min_i == max_i) { |
| 12026 | seen_enum_fields[min_i] = special_members_only_src; |
| 12027 | const item_val = try pt.enumValueFieldIndex(cond_ty, @intCast(min_i)); |
| 12028 | const item_ref = Air.internedToRef(item_val.toIntern()); |
| 12029 | try extra_case_vals.items.append(gpa, item_ref); |
| 12030 | break :gen; |
| 12031 | } |
| 12032 | const missing_field_count = seen_enum_fields.len - seen_field_count; |
| 12033 | |
| 12034 | extra_case_vals.items = try .initCapacity(gpa, missing_field_count / 2); |
| 12035 | extra_case_vals.ranges = try .initCapacity(gpa, missing_field_count / 4); |
| 12036 | const int_ty = cond_ty.intTagType(zcu); |
| 12037 | |
| 12038 | var last_val = try pt.enumValueFieldIndex(cond_ty, @intCast(min_i)); |
| 12039 | var first_ref = Air.internedToRef(last_val.toIntern()); |
| 12040 | seen_enum_fields[min_i] = special_members_only_src; |
| 12041 | for (seen_enum_fields[(min_i + 1)..(max_i + 1)], (min_i + 1)..) |seen, enum_i| { |
| 12042 | if (seen != null) continue; |
| 12043 | seen_enum_fields[enum_i] = special_members_only_src; |
| 12044 | |
| 12045 | const item_val = try pt.enumValueFieldIndex(cond_ty, @intCast(enum_i)); |
| 12046 | const item_ref = Air.internedToRef(item_val.toIntern()); |
| 12047 | |
| 12048 | const is_next = is_next: { |
| 12049 | const prev_int = ip.indexToKey(last_val.toIntern()).enum_tag.int; |
| 12050 | |
| 12051 | const result = try arith.incrementDefinedInt(sema, int_ty, .fromInterned(prev_int)); |
| 12052 | if (result.overflow) break :is_next false; |
| 12053 | |
| 12054 | const item_int = ip.indexToKey(item_val.toIntern()).enum_tag.int; |
| 12055 | break :is_next try sema.valuesEqual(.fromInterned(item_int), result.val, int_ty); |
| 12056 | }; |
| 12057 | |
| 12058 | if (is_next) { |
| 12059 | last_val = item_val; |
| 12060 | } else { |
| 12061 | const last_ref = Air.internedToRef(last_val.toIntern()); |
| 12062 | if (first_ref == last_ref) { |
| 12063 | try extra_case_vals.items.append(gpa, first_ref); |
| 12064 | } else { |
| 12065 | try extra_case_vals.ranges.append(gpa, .{ first_ref, last_ref }); |
| 12066 | } |
| 12067 | first_ref = item_ref; |
| 12068 | last_val = item_val; |
| 12069 | } |
| 12070 | } |
| 12071 | const last_ref = Air.internedToRef(last_val.toIntern()); |
| 12072 | if (first_ref == last_ref) { |
| 12073 | try extra_case_vals.items.append(gpa, first_ref); |
| 12074 | } else { |
| 12075 | try extra_case_vals.ranges.append(gpa, .{ first_ref, last_ref }); |
| 12076 | } |
| 12077 | } |
| 12078 | |
| 11952 | 12079 | const air_switch_ref = try sema.analyzeSwitchRuntimeBlock( |
| 11953 | 12080 | spa, |
| 11954 | 12081 | &child_block, |
| ... | ... | @@ -11960,14 +12087,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11960 | 12087 | cond_ty, |
| 11961 | 12088 | operand_src, |
| 11962 | 12089 | case_vals, |
| 11963 | | special, |
| 12090 | special_generic, |
| 11964 | 12091 | scalar_cases_len, |
| 11965 | 12092 | multi_cases_len, |
| 11966 | 12093 | union_originally, |
| 11967 | 12094 | raw_operand_ty, |
| 11968 | 12095 | err_set, |
| 11969 | 12096 | src_node_offset, |
| 11970 | | special_prong_src, |
| 12097 | special_generic_src, |
| 12098 | has_under, |
| 11971 | 12099 | seen_enum_fields, |
| 11972 | 12100 | seen_errors, |
| 11973 | 12101 | range_set, |
| ... | ... | @@ -11975,6 +12103,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11975 | 12103 | false_count, |
| 11976 | 12104 | cond_dbg_node_index, |
| 11977 | 12105 | false, |
| 12106 | special_members_only, |
| 12107 | special_members_only_src, |
| 12108 | extra_case_vals.items.items, |
| 12109 | extra_case_vals.ranges.items, |
| 11978 | 12110 | ); |
| 11979 | 12111 | |
| 11980 | 12112 | for (merges.extra_insts.items, merges.extra_src_locs.items) |placeholder_inst, dispatch_src| { |
| ... | ... | @@ -12058,14 +12190,15 @@ fn analyzeSwitchRuntimeBlock( |
| 12058 | 12190 | operand_ty: Type, |
| 12059 | 12191 | operand_src: LazySrcLoc, |
| 12060 | 12192 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12061 | | special: SpecialProng, |
| 12193 | else_prong: SpecialProng, |
| 12062 | 12194 | scalar_cases_len: usize, |
| 12063 | 12195 | multi_cases_len: usize, |
| 12064 | 12196 | union_originally: bool, |
| 12065 | 12197 | maybe_union_ty: Type, |
| 12066 | 12198 | err_set: bool, |
| 12067 | 12199 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12068 | | special_prong_src: LazySrcLoc, |
| 12200 | else_prong_src: LazySrcLoc, |
| 12201 | else_prong_is_underscore: bool, |
| 12069 | 12202 | seen_enum_fields: []?LazySrcLoc, |
| 12070 | 12203 | seen_errors: SwitchErrorSet, |
| 12071 | 12204 | range_set: RangeSet, |
| ... | ... | @@ -12073,6 +12206,11 @@ fn analyzeSwitchRuntimeBlock( |
| 12073 | 12206 | false_count: u8, |
| 12074 | 12207 | cond_dbg_node_index: Zir.Inst.Index, |
| 12075 | 12208 | allow_err_code_unwrap: bool, |
| 12209 | extra_prong: ?SpecialProng, |
| 12210 | /// May be `undefined` if `extra_prong` is `null` |
| 12211 | extra_prong_src: LazySrcLoc, |
| 12212 | extra_prong_items: []const Air.Inst.Ref, |
| 12213 | extra_prong_ranges: []const [2]Air.Inst.Ref, |
| 12076 | 12214 | ) CompileError!Air.Inst.Ref { |
| 12077 | 12215 | const pt = sema.pt; |
| 12078 | 12216 | const zcu = pt.zcu; |
| ... | ... | @@ -12096,7 +12234,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12096 | 12234 | case_block.need_debug_scope = null; // this body is emitted regardless |
| 12097 | 12235 | defer case_block.instructions.deinit(gpa); |
| 12098 | 12236 | |
| 12099 | | var extra_index: usize = special.end; |
| 12237 | var extra_index: usize = else_prong.end; |
| 12100 | 12238 | |
| 12101 | 12239 | var scalar_i: usize = 0; |
| 12102 | 12240 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -12158,23 +12296,42 @@ fn analyzeSwitchRuntimeBlock( |
| 12158 | 12296 | |
| 12159 | 12297 | var cases_len = scalar_cases_len; |
| 12160 | 12298 | var case_val_idx: usize = scalar_cases_len; |
| 12299 | const multi_cases_len_with_extra_prong = multi_cases_len + @intFromBool(extra_prong != null); |
| 12161 | 12300 | var multi_i: u32 = 0; |
| 12162 | | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 12163 | | const items_len = sema.code.extra[extra_index]; |
| 12164 | | extra_index += 1; |
| 12165 | | const ranges_len = sema.code.extra[extra_index]; |
| 12166 | | extra_index += 1; |
| 12167 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12168 | | extra_index += 1 + items_len + 2 * ranges_len; |
| 12301 | while (multi_i < multi_cases_len_with_extra_prong) : (multi_i += 1) { |
| 12302 | const is_extra_prong = multi_i == multi_cases_len; |
| 12303 | var items: []const Air.Inst.Ref = undefined; |
| 12304 | var info: Zir.Inst.SwitchBlock.ProngInfo = undefined; |
| 12305 | var ranges: []const [2]Air.Inst.Ref = undefined; |
| 12306 | var body: []const Zir.Inst.Index = undefined; |
| 12307 | if (is_extra_prong) { |
| 12308 | const prong = extra_prong.?; |
| 12309 | items = extra_prong_items; |
| 12310 | ranges = extra_prong_ranges; |
| 12311 | body = prong.body; |
| 12312 | info = .{ |
| 12313 | .body_len = undefined, |
| 12314 | .capture = prong.capture, |
| 12315 | .is_inline = prong.is_inline, |
| 12316 | .has_tag_capture = prong.has_tag_capture, |
| 12317 | }; |
| 12318 | } else { |
| 12319 | @branchHint(.likely); |
| 12320 | const items_len = sema.code.extra[extra_index]; |
| 12321 | extra_index += 1; |
| 12322 | const ranges_len = sema.code.extra[extra_index]; |
| 12323 | extra_index += 1; |
| 12324 | info = @bitCast(sema.code.extra[extra_index]); |
| 12325 | extra_index += 1 + items_len + ranges_len * 2; |
| 12169 | 12326 | |
| 12170 | | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 12171 | | case_val_idx += items_len; |
| 12172 | | // TODO: @ptrCast slice once Sema supports it |
| 12173 | | const ranges: []const [2]Air.Inst.Ref = @as([*]const [2]Air.Inst.Ref, @ptrCast(case_vals.items[case_val_idx..]))[0..ranges_len]; |
| 12174 | | case_val_idx += ranges_len * 2; |
| 12327 | items = case_vals.items[case_val_idx..][0..items_len]; |
| 12328 | case_val_idx += items_len; |
| 12329 | ranges = @ptrCast(case_vals.items[case_val_idx..][0 .. ranges_len * 2]); |
| 12330 | case_val_idx += ranges_len * 2; |
| 12175 | 12331 | |
| 12176 | | const body = sema.code.bodySlice(extra_index, info.body_len); |
| 12177 | | extra_index += info.body_len; |
| 12332 | body = sema.code.bodySlice(extra_index, info.body_len); |
| 12333 | extra_index += info.body_len; |
| 12334 | } |
| 12178 | 12335 | |
| 12179 | 12336 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12180 | 12337 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| ... | ... | @@ -12184,14 +12341,29 @@ fn analyzeSwitchRuntimeBlock( |
| 12184 | 12341 | var emit_bb = false; |
| 12185 | 12342 | |
| 12186 | 12343 | for (ranges, 0..) |range_items, range_i| { |
| 12187 | | var item = sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, range_items[0], undefined) catch unreachable; |
| 12188 | | const item_last = sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, range_items[1], undefined) catch unreachable; |
| 12344 | var item = sema.resolveConstDefinedValue(block, .unneeded, range_items[0], undefined) catch unreachable; |
| 12345 | const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_items[1], undefined) catch unreachable; |
| 12189 | 12346 | |
| 12190 | 12347 | while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({ |
| 12191 | 12348 | // Previous validation has resolved any possible lazy values. |
| 12192 | | const result = try arith.incrementDefinedInt(sema, operand_ty, item); |
| 12349 | const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) { |
| 12350 | .int => .{ item, operand_ty }, |
| 12351 | .@"enum" => b: { |
| 12352 | const int_val = Value.fromInterned(ip.indexToKey(item.toIntern()).enum_tag.int); |
| 12353 | break :b .{ int_val, int_val.typeOf(zcu) }; |
| 12354 | }, |
| 12355 | else => unreachable, |
| 12356 | }; |
| 12357 | const result = try arith.incrementDefinedInt(sema, int_ty, int_val); |
| 12193 | 12358 | assert(!result.overflow); |
| 12194 | | item = result.val; |
| 12359 | item = switch (operand_ty.zigTypeTag(zcu)) { |
| 12360 | .int => result.val, |
| 12361 | .@"enum" => .fromInterned(try pt.intern(.{ .enum_tag = .{ |
| 12362 | .ty = operand_ty.toIntern(), |
| 12363 | .int = result.val.toIntern(), |
| 12364 | } })), |
| 12365 | else => unreachable, |
| 12366 | }; |
| 12195 | 12367 | }) { |
| 12196 | 12368 | cases_len += 1; |
| 12197 | 12369 | |
| ... | ... | @@ -12200,11 +12372,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12200 | 12372 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12201 | 12373 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12202 | 12374 | |
| 12203 | | if (emit_bb) try sema.emitBackwardBranch(block, block.src(.{ .switch_case_item = .{ |
| 12204 | | .switch_node_offset = switch_node_offset, |
| 12205 | | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12206 | | .item_idx = .{ .kind = .range, .index = @intCast(range_i) }, |
| 12207 | | } })); |
| 12375 | if (emit_bb) { |
| 12376 | const bb_src = if (is_extra_prong) extra_prong_src else block.src(.{ .switch_case_item = .{ |
| 12377 | .switch_node_offset = switch_node_offset, |
| 12378 | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12379 | .item_idx = .{ .kind = .range, .index = @intCast(range_i) }, |
| 12380 | } }); |
| 12381 | try sema.emitBackwardBranch(block, bb_src); |
| 12382 | } |
| 12208 | 12383 | emit_bb = true; |
| 12209 | 12384 | |
| 12210 | 12385 | const prong_hint = try spa.analyzeProngRuntime( |
| ... | ... | @@ -12249,11 +12424,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12249 | 12424 | break :blk field_ty.zigTypeTag(zcu) != .noreturn; |
| 12250 | 12425 | } else true; |
| 12251 | 12426 | |
| 12252 | | if (emit_bb) try sema.emitBackwardBranch(block, block.src(.{ .switch_case_item = .{ |
| 12253 | | .switch_node_offset = switch_node_offset, |
| 12254 | | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12255 | | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 12256 | | } })); |
| 12427 | if (emit_bb) { |
| 12428 | const bb_src = if (is_extra_prong) extra_prong_src else block.src(.{ .switch_case_item = .{ |
| 12429 | .switch_node_offset = switch_node_offset, |
| 12430 | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12431 | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 12432 | } }); |
| 12433 | try sema.emitBackwardBranch(block, bb_src); |
| 12434 | } |
| 12257 | 12435 | emit_bb = true; |
| 12258 | 12436 | |
| 12259 | 12437 | const prong_hint: std.builtin.BranchHint = if (analyze_body) h: { |
| ... | ... | @@ -12329,11 +12507,11 @@ fn analyzeSwitchRuntimeBlock( |
| 12329 | 12507 | try branch_hints.append(gpa, prong_hint); |
| 12330 | 12508 | |
| 12331 | 12509 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + |
| 12332 | | items.len + 2 * ranges_len + |
| 12510 | items.len + ranges.len * 2 + |
| 12333 | 12511 | case_block.instructions.items.len); |
| 12334 | 12512 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ |
| 12335 | 12513 | .items_len = @intCast(items.len), |
| 12336 | | .ranges_len = @intCast(ranges_len), |
| 12514 | .ranges_len = @intCast(ranges.len), |
| 12337 | 12515 | .body_len = @intCast(case_block.instructions.items.len), |
| 12338 | 12516 | })); |
| 12339 | 12517 | |
| ... | ... | @@ -12350,12 +12528,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12350 | 12528 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); |
| 12351 | 12529 | } |
| 12352 | 12530 | |
| 12353 | | const else_body: []const Air.Inst.Index = if (special.body.len != 0 or case_block.wantSafety()) else_body: { |
| 12531 | const else_body: []const Air.Inst.Index = if (else_prong.body.len != 0 or case_block.wantSafety()) else_body: { |
| 12354 | 12532 | var emit_bb = false; |
| 12355 | | if (special.is_inline) switch (operand_ty.zigTypeTag(zcu)) { |
| 12533 | // If this is true we must have a 'true' else prong and not an underscore because |
| 12534 | // underscore prongs can never be inlined. We've already checked for this. |
| 12535 | if (else_prong.is_inline) switch (operand_ty.zigTypeTag(zcu)) { |
| 12356 | 12536 | .@"enum" => { |
| 12357 | 12537 | if (operand_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 12358 | | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12538 | return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12359 | 12539 | operand_ty.fmt(pt), |
| 12360 | 12540 | }); |
| 12361 | 12541 | } |
| ... | ... | @@ -12374,22 +12554,22 @@ fn analyzeSwitchRuntimeBlock( |
| 12374 | 12554 | break :blk field_ty.zigTypeTag(zcu) != .noreturn; |
| 12375 | 12555 | } else true; |
| 12376 | 12556 | |
| 12377 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12557 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12378 | 12558 | emit_bb = true; |
| 12379 | 12559 | |
| 12380 | 12560 | const prong_hint: std.builtin.BranchHint = if (analyze_body) h: { |
| 12381 | 12561 | break :h try spa.analyzeProngRuntime( |
| 12382 | 12562 | &case_block, |
| 12383 | 12563 | .special, |
| 12384 | | special.body, |
| 12385 | | special.capture, |
| 12564 | else_prong.body, |
| 12565 | else_prong.capture, |
| 12386 | 12566 | child_block.src(.{ .switch_capture = .{ |
| 12387 | 12567 | .switch_node_offset = switch_node_offset, |
| 12388 | | .case_idx = .special, |
| 12568 | .case_idx = .special_else, |
| 12389 | 12569 | } }), |
| 12390 | 12570 | &.{item_ref}, |
| 12391 | 12571 | item_ref, |
| 12392 | | special.has_tag_capture, |
| 12572 | else_prong.has_tag_capture, |
| 12393 | 12573 | ); |
| 12394 | 12574 | } else h: { |
| 12395 | 12575 | _ = try case_block.addNoOp(.unreach); |
| ... | ... | @@ -12411,7 +12591,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12411 | 12591 | }, |
| 12412 | 12592 | .error_set => { |
| 12413 | 12593 | if (operand_ty.isAnyError(zcu)) { |
| 12414 | | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12594 | return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12415 | 12595 | operand_ty.fmt(pt), |
| 12416 | 12596 | }); |
| 12417 | 12597 | } |
| ... | ... | @@ -12430,21 +12610,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12430 | 12610 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12431 | 12611 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12432 | 12612 | |
| 12433 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12613 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12434 | 12614 | emit_bb = true; |
| 12435 | 12615 | |
| 12436 | 12616 | const prong_hint = try spa.analyzeProngRuntime( |
| 12437 | 12617 | &case_block, |
| 12438 | 12618 | .special, |
| 12439 | | special.body, |
| 12440 | | special.capture, |
| 12619 | else_prong.body, |
| 12620 | else_prong.capture, |
| 12441 | 12621 | child_block.src(.{ .switch_capture = .{ |
| 12442 | 12622 | .switch_node_offset = switch_node_offset, |
| 12443 | | .case_idx = .special, |
| 12623 | .case_idx = .special_else, |
| 12444 | 12624 | } }), |
| 12445 | 12625 | &.{item_ref}, |
| 12446 | 12626 | item_ref, |
| 12447 | | special.has_tag_capture, |
| 12627 | else_prong.has_tag_capture, |
| 12448 | 12628 | ); |
| 12449 | 12629 | try branch_hints.append(gpa, prong_hint); |
| 12450 | 12630 | |
| ... | ... | @@ -12470,21 +12650,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12470 | 12650 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12471 | 12651 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12472 | 12652 | |
| 12473 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12653 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12474 | 12654 | emit_bb = true; |
| 12475 | 12655 | |
| 12476 | 12656 | const prong_hint = try spa.analyzeProngRuntime( |
| 12477 | 12657 | &case_block, |
| 12478 | 12658 | .special, |
| 12479 | | special.body, |
| 12480 | | special.capture, |
| 12659 | else_prong.body, |
| 12660 | else_prong.capture, |
| 12481 | 12661 | child_block.src(.{ .switch_capture = .{ |
| 12482 | 12662 | .switch_node_offset = switch_node_offset, |
| 12483 | | .case_idx = .special, |
| 12663 | .case_idx = .special_else, |
| 12484 | 12664 | } }), |
| 12485 | 12665 | &.{item_ref}, |
| 12486 | 12666 | item_ref, |
| 12487 | | special.has_tag_capture, |
| 12667 | else_prong.has_tag_capture, |
| 12488 | 12668 | ); |
| 12489 | 12669 | try branch_hints.append(gpa, prong_hint); |
| 12490 | 12670 | |
| ... | ... | @@ -12507,21 +12687,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12507 | 12687 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12508 | 12688 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12509 | 12689 | |
| 12510 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12690 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12511 | 12691 | emit_bb = true; |
| 12512 | 12692 | |
| 12513 | 12693 | const prong_hint = try spa.analyzeProngRuntime( |
| 12514 | 12694 | &case_block, |
| 12515 | 12695 | .special, |
| 12516 | | special.body, |
| 12517 | | special.capture, |
| 12696 | else_prong.body, |
| 12697 | else_prong.capture, |
| 12518 | 12698 | child_block.src(.{ .switch_capture = .{ |
| 12519 | 12699 | .switch_node_offset = switch_node_offset, |
| 12520 | | .case_idx = .special, |
| 12700 | .case_idx = .special_else, |
| 12521 | 12701 | } }), |
| 12522 | 12702 | &.{.bool_true}, |
| 12523 | 12703 | .bool_true, |
| 12524 | | special.has_tag_capture, |
| 12704 | else_prong.has_tag_capture, |
| 12525 | 12705 | ); |
| 12526 | 12706 | try branch_hints.append(gpa, prong_hint); |
| 12527 | 12707 | |
| ... | ... | @@ -12542,21 +12722,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12542 | 12722 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12543 | 12723 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12544 | 12724 | |
| 12545 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12725 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12546 | 12726 | emit_bb = true; |
| 12547 | 12727 | |
| 12548 | 12728 | const prong_hint = try spa.analyzeProngRuntime( |
| 12549 | 12729 | &case_block, |
| 12550 | 12730 | .special, |
| 12551 | | special.body, |
| 12552 | | special.capture, |
| 12731 | else_prong.body, |
| 12732 | else_prong.capture, |
| 12553 | 12733 | child_block.src(.{ .switch_capture = .{ |
| 12554 | 12734 | .switch_node_offset = switch_node_offset, |
| 12555 | | .case_idx = .special, |
| 12735 | .case_idx = .special_else, |
| 12556 | 12736 | } }), |
| 12557 | 12737 | &.{.bool_false}, |
| 12558 | 12738 | .bool_false, |
| 12559 | | special.has_tag_capture, |
| 12739 | else_prong.has_tag_capture, |
| 12560 | 12740 | ); |
| 12561 | 12741 | try branch_hints.append(gpa, prong_hint); |
| 12562 | 12742 | |
| ... | ... | @@ -12572,7 +12752,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12572 | 12752 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); |
| 12573 | 12753 | } |
| 12574 | 12754 | }, |
| 12575 | | else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12755 | else => return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12576 | 12756 | operand_ty.fmt(pt), |
| 12577 | 12757 | }), |
| 12578 | 12758 | }; |
| ... | ... | @@ -12581,7 +12761,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12581 | 12761 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12582 | 12762 | |
| 12583 | 12763 | if (zcu.backendSupportsFeature(.is_named_enum_value) and |
| 12584 | | special.body.len != 0 and block.wantSafety() and |
| 12764 | else_prong.body.len != 0 and block.wantSafety() and |
| 12585 | 12765 | operand_ty.zigTypeTag(zcu) == .@"enum" and |
| 12586 | 12766 | (!operand_ty.isNonexhaustiveEnum(zcu) or union_originally)) |
| 12587 | 12767 | { |
| ... | ... | @@ -12590,7 +12770,12 @@ fn analyzeSwitchRuntimeBlock( |
| 12590 | 12770 | try sema.addSafetyCheck(&case_block, src, ok, .corrupt_switch); |
| 12591 | 12771 | } |
| 12592 | 12772 | |
| 12593 | | const analyze_body = if (union_originally and !special.is_inline) |
| 12773 | const else_src_idx: LazySrcLoc.Offset.SwitchCaseIndex = if (else_prong_is_underscore) |
| 12774 | .special_under |
| 12775 | else |
| 12776 | .special_else; |
| 12777 | |
| 12778 | const analyze_body = if (union_originally and !else_prong.is_inline) |
| 12594 | 12779 | for (seen_enum_fields, 0..) |seen_field, index| { |
| 12595 | 12780 | if (seen_field != null) continue; |
| 12596 | 12781 | const union_obj = zcu.typeToUnion(maybe_union_ty).?; |
| ... | ... | @@ -12599,20 +12784,20 @@ fn analyzeSwitchRuntimeBlock( |
| 12599 | 12784 | } else false |
| 12600 | 12785 | else |
| 12601 | 12786 | true; |
| 12602 | | const else_hint: std.builtin.BranchHint = if (special.body.len != 0 and err_set and |
| 12603 | | try sema.maybeErrorUnwrap(&case_block, special.body, operand, operand_src, allow_err_code_unwrap)) |
| 12787 | const else_hint: std.builtin.BranchHint = if (else_prong.body.len != 0 and err_set and |
| 12788 | try sema.maybeErrorUnwrap(&case_block, else_prong.body, operand, operand_src, allow_err_code_unwrap)) |
| 12604 | 12789 | h: { |
| 12605 | 12790 | // nothing to do here. weight against error branch |
| 12606 | 12791 | break :h .unlikely; |
| 12607 | | } else if (special.body.len != 0 and analyze_body and !special.is_inline) h: { |
| 12792 | } else if (else_prong.body.len != 0 and analyze_body and !else_prong.is_inline) h: { |
| 12608 | 12793 | break :h try spa.analyzeProngRuntime( |
| 12609 | 12794 | &case_block, |
| 12610 | 12795 | .special, |
| 12611 | | special.body, |
| 12612 | | special.capture, |
| 12796 | else_prong.body, |
| 12797 | else_prong.capture, |
| 12613 | 12798 | child_block.src(.{ .switch_capture = .{ |
| 12614 | 12799 | .switch_node_offset = switch_node_offset, |
| 12615 | | .case_idx = .special, |
| 12800 | .case_idx = else_src_idx, |
| 12616 | 12801 | } }), |
| 12617 | 12802 | undefined, // case_vals may be undefined for special prongs |
| 12618 | 12803 | .none, |
| ... | ... | @@ -12686,7 +12871,9 @@ fn resolveSwitchComptimeLoop( |
| 12686 | 12871 | cond_ty: Type, |
| 12687 | 12872 | init_cond_val: Value, |
| 12688 | 12873 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12689 | | special: SpecialProng, |
| 12874 | special_members_only: ?SpecialProng, |
| 12875 | special_generic: SpecialProng, |
| 12876 | special_generic_is_under: bool, |
| 12690 | 12877 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12691 | 12878 | scalar_cases_len: u32, |
| 12692 | 12879 | multi_cases_len: u32, |
| ... | ... | @@ -12706,7 +12893,9 @@ fn resolveSwitchComptimeLoop( |
| 12706 | 12893 | cond_val, |
| 12707 | 12894 | cond_ty, |
| 12708 | 12895 | switch_node_offset, |
| 12709 | | special, |
| 12896 | special_members_only, |
| 12897 | special_generic, |
| 12898 | special_generic_is_under, |
| 12710 | 12899 | case_vals, |
| 12711 | 12900 | scalar_cases_len, |
| 12712 | 12901 | multi_cases_len, |
| ... | ... | @@ -12754,17 +12943,20 @@ fn resolveSwitchComptime( |
| 12754 | 12943 | operand_val: Value, |
| 12755 | 12944 | operand_ty: Type, |
| 12756 | 12945 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12757 | | special: SpecialProng, |
| 12946 | special_members_only: ?SpecialProng, |
| 12947 | special_generic: SpecialProng, |
| 12948 | special_generic_is_under: bool, |
| 12758 | 12949 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12759 | 12950 | scalar_cases_len: u32, |
| 12760 | 12951 | multi_cases_len: u32, |
| 12761 | 12952 | err_set: bool, |
| 12762 | 12953 | empty_enum: bool, |
| 12763 | 12954 | ) CompileError!Air.Inst.Ref { |
| 12955 | const zcu = sema.pt.zcu; |
| 12764 | 12956 | const merges = &child_block.label.?.merges; |
| 12765 | 12957 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); |
| 12766 | 12958 | |
| 12767 | | var extra_index: usize = special.end; |
| 12959 | var extra_index: usize = special_generic.end; |
| 12768 | 12960 | { |
| 12769 | 12961 | var scalar_i: usize = 0; |
| 12770 | 12962 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -12865,23 +13057,45 @@ fn resolveSwitchComptime( |
| 12865 | 13057 | extra_index += info.body_len; |
| 12866 | 13058 | } |
| 12867 | 13059 | } |
| 12868 | | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, special.body, cond_operand); |
| 13060 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, special_generic.body, cond_operand); |
| 12869 | 13061 | if (empty_enum) { |
| 12870 | 13062 | return .void_value; |
| 12871 | 13063 | } |
| 13064 | if (special_members_only) |special| { |
| 13065 | assert(operand_ty.isNonexhaustiveEnum(zcu)); |
| 13066 | if (operand_ty.enumTagFieldIndex(operand_val, zcu)) |_| { |
| 13067 | return spa.resolveProngComptime( |
| 13068 | child_block, |
| 13069 | .special, |
| 13070 | special.body, |
| 13071 | special.capture, |
| 13072 | child_block.src(.{ .switch_capture = .{ |
| 13073 | .switch_node_offset = switch_node_offset, |
| 13074 | .case_idx = .special_else, |
| 13075 | } }), |
| 13076 | undefined, // case_vals may be undefined for special prongs |
| 13077 | if (special.is_inline) cond_operand else .none, |
| 13078 | special.has_tag_capture, |
| 13079 | merges, |
| 13080 | ); |
| 13081 | } |
| 13082 | } |
| 12872 | 13083 | |
| 12873 | 13084 | return spa.resolveProngComptime( |
| 12874 | 13085 | child_block, |
| 12875 | 13086 | .special, |
| 12876 | | special.body, |
| 12877 | | special.capture, |
| 13087 | special_generic.body, |
| 13088 | special_generic.capture, |
| 12878 | 13089 | child_block.src(.{ .switch_capture = .{ |
| 12879 | 13090 | .switch_node_offset = switch_node_offset, |
| 12880 | | .case_idx = .special, |
| 13091 | .case_idx = if (special_generic_is_under) |
| 13092 | .special_under |
| 13093 | else |
| 13094 | .special_else, |
| 12881 | 13095 | } }), |
| 12882 | 13096 | undefined, // case_vals may be undefined for special prongs |
| 12883 | | if (special.is_inline) cond_operand else .none, |
| 12884 | | special.has_tag_capture, |
| 13097 | if (special_generic.is_inline) cond_operand else .none, |
| 13098 | special_generic.has_tag_capture, |
| 12885 | 13099 | merges, |
| 12886 | 13100 | ); |
| 12887 | 13101 | } |