| ... | ... | @@ -10927,7 +10927,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 10927 | 10927 | const switch_src = block.nodeOffset(inst_data.src_node); |
| 10928 | 10928 | const switch_src_node_offset = inst_data.src_node; |
| 10929 | 10929 | const switch_operand_src = block.src(.{ .node_offset_switch_operand = switch_src_node_offset }); |
| 10930 | | const else_prong_src = block.src(.{ .node_offset_switch_special_prong = switch_src_node_offset }); |
| 10930 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = switch_src_node_offset }); |
| 10931 | 10931 | const extra = sema.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index); |
| 10932 | 10932 | const main_operand_src = block.src(.{ .node_offset_if_cond = extra.data.main_src_node_offset }); |
| 10933 | 10933 | const main_src = block.src(.{ .node_offset_main_token = extra.data.main_src_node_offset }); |
| ... | ... | @@ -11121,6 +11121,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11121 | 11121 | err_val, |
| 11122 | 11122 | operand_err_set_ty, |
| 11123 | 11123 | switch_src_node_offset, |
| 11124 | null, |
| 11124 | 11125 | .{ |
| 11125 | 11126 | .body = else_case.body, |
| 11126 | 11127 | .end = else_case.end, |
| ... | ... | @@ -11128,6 +11129,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11128 | 11129 | .is_inline = else_case.is_inline, |
| 11129 | 11130 | .has_tag_capture = false, |
| 11130 | 11131 | }, |
| 11132 | false, |
| 11131 | 11133 | case_vals, |
| 11132 | 11134 | scalar_cases_len, |
| 11133 | 11135 | multi_cases_len, |
| ... | ... | @@ -11199,6 +11201,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11199 | 11201 | true, |
| 11200 | 11202 | switch_src_node_offset, |
| 11201 | 11203 | else_prong_src, |
| 11204 | false, |
| 11202 | 11205 | undefined, |
| 11203 | 11206 | seen_errors, |
| 11204 | 11207 | undefined, |
| ... | ... | @@ -11206,6 +11209,10 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 11206 | 11209 | undefined, |
| 11207 | 11210 | cond_dbg_node_index, |
| 11208 | 11211 | true, |
| 11212 | null, |
| 11213 | undefined, |
| 11214 | &.{}, |
| 11215 | &.{}, |
| 11209 | 11216 | ); |
| 11210 | 11217 | |
| 11211 | 11218 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + |
| ... | ... | @@ -11242,12 +11249,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11242 | 11249 | |
| 11243 | 11250 | const pt = sema.pt; |
| 11244 | 11251 | const zcu = pt.zcu; |
| 11252 | const ip = &zcu.intern_pool; |
| 11245 | 11253 | const gpa = sema.gpa; |
| 11246 | 11254 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 11247 | 11255 | const src = block.nodeOffset(inst_data.src_node); |
| 11248 | 11256 | const src_node_offset = inst_data.src_node; |
| 11249 | 11257 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11250 | | const special_prong_src = block.src(.{ .node_offset_switch_special_prong = src_node_offset }); |
| 11258 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); |
| 11259 | const under_prong_src = block.src(.{ .node_offset_switch_under_prong = src_node_offset }); |
| 11251 | 11260 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 11252 | 11261 | |
| 11253 | 11262 | const operand: SwitchProngAnalysis.Operand, const raw_operand_ty: Type = op: { |
| ... | ... | @@ -11334,27 +11343,63 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11334 | 11343 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 11335 | 11344 | defer case_vals.deinit(gpa); |
| 11336 | 11345 | |
| 11337 | | const special_prong = extra.data.bits.specialProng(); |
| 11338 | | const special: SpecialProng = switch (special_prong) { |
| 11339 | | .none => .{ |
| 11340 | | .body = &.{}, |
| 11341 | | .end = header_extra_index, |
| 11342 | | .capture = .none, |
| 11343 | | .is_inline = false, |
| 11344 | | .has_tag_capture = false, |
| 11345 | | }, |
| 11346 | | .under, .@"else" => blk: { |
| 11347 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]); |
| 11348 | | const extra_body_start = header_extra_index + 1; |
| 11349 | | break :blk .{ |
| 11350 | | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11351 | | .end = extra_body_start + info.body_len, |
| 11352 | | .capture = info.capture, |
| 11353 | | .is_inline = info.is_inline, |
| 11354 | | .has_tag_capture = info.has_tag_capture, |
| 11355 | | }; |
| 11356 | | }, |
| 11346 | var single_absorbed_item: Zir.Inst.Ref = .none; |
| 11347 | var absorbed_items: []const Zir.Inst.Ref = &.{}; |
| 11348 | var absorbed_ranges: []const Zir.Inst.Ref = &.{}; |
| 11349 | |
| 11350 | const special_prongs = extra.data.bits.special_prongs; |
| 11351 | const has_else = special_prongs.hasElse(); |
| 11352 | const has_under = special_prongs.hasUnder(); |
| 11353 | const special_else: SpecialProng = if (has_else) blk: { |
| 11354 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]); |
| 11355 | const extra_body_start = header_extra_index + 1; |
| 11356 | break :blk .{ |
| 11357 | .body = sema.code.bodySlice(extra_body_start, info.body_len), |
| 11358 | .end = extra_body_start + info.body_len, |
| 11359 | .capture = info.capture, |
| 11360 | .is_inline = info.is_inline, |
| 11361 | .has_tag_capture = info.has_tag_capture, |
| 11362 | }; |
| 11363 | } else .{ |
| 11364 | .body = &.{}, |
| 11365 | .end = header_extra_index, |
| 11366 | .capture = .none, |
| 11367 | .is_inline = false, |
| 11368 | .has_tag_capture = false, |
| 11357 | 11369 | }; |
| 11370 | const special_under: SpecialProng = if (has_under) blk: { |
| 11371 | var extra_index = special_else.end; |
| 11372 | var trailing_items_len: usize = 0; |
| 11373 | if (special_prongs.hasOneAdditionalItem()) { |
| 11374 | single_absorbed_item = @enumFromInt(sema.code.extra[extra_index]); |
| 11375 | extra_index += 1; |
| 11376 | absorbed_items = @ptrCast(&single_absorbed_item); |
| 11377 | } else if (special_prongs.hasManyAdditionalItems()) { |
| 11378 | const items_len = sema.code.extra[extra_index]; |
| 11379 | extra_index += 1; |
| 11380 | const ranges_len = sema.code.extra[extra_index]; |
| 11381 | extra_index += 1; |
| 11382 | absorbed_items = sema.code.refSlice(extra_index + 1, items_len); |
| 11383 | absorbed_ranges = sema.code.refSlice(extra_index + 1 + items_len, ranges_len * 2); |
| 11384 | trailing_items_len = items_len + ranges_len * 2; |
| 11385 | } |
| 11386 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11387 | extra_index += 1 + trailing_items_len; |
| 11388 | break :blk .{ |
| 11389 | .body = sema.code.bodySlice(extra_index, info.body_len), |
| 11390 | .end = extra_index + info.body_len, |
| 11391 | .capture = info.capture, |
| 11392 | .is_inline = info.is_inline, |
| 11393 | .has_tag_capture = info.has_tag_capture, |
| 11394 | }; |
| 11395 | } else .{ |
| 11396 | .body = &.{}, |
| 11397 | .end = special_else.end, |
| 11398 | .capture = .none, |
| 11399 | .is_inline = false, |
| 11400 | .has_tag_capture = false, |
| 11401 | }; |
| 11402 | const special_end = special_under.end; |
| 11358 | 11403 | |
| 11359 | 11404 | // Duplicate checking variables later also used for `inline else`. |
| 11360 | 11405 | var seen_enum_fields: []?LazySrcLoc = &.{}; |
| ... | ... | @@ -11374,7 +11419,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11374 | 11419 | var else_error_ty: ?Type = null; |
| 11375 | 11420 | |
| 11376 | 11421 | // Validate usage of '_' prongs. |
| 11377 | | if (special_prong == .under and !raw_operand_ty.isNonexhaustiveEnum(zcu)) { |
| 11422 | if (has_under and !raw_operand_ty.isNonexhaustiveEnum(zcu)) { |
| 11378 | 11423 | const msg = msg: { |
| 11379 | 11424 | const msg = try sema.errMsg( |
| 11380 | 11425 | src, |
| ... | ... | @@ -11383,7 +11428,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11383 | 11428 | ); |
| 11384 | 11429 | errdefer msg.destroy(gpa); |
| 11385 | 11430 | try sema.errNote( |
| 11386 | | special_prong_src, |
| 11431 | under_prong_src, |
| 11387 | 11432 | msg, |
| 11388 | 11433 | "'_' prong here", |
| 11389 | 11434 | .{}, |
| ... | ... | @@ -11408,7 +11453,23 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11408 | 11453 | @memset(seen_enum_fields, null); |
| 11409 | 11454 | // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. |
| 11410 | 11455 | |
| 11411 | | var extra_index: usize = special.end; |
| 11456 | for (absorbed_items, 0..) |item_ref, item_i| { |
| 11457 | _ = try sema.validateSwitchItemEnum( |
| 11458 | block, |
| 11459 | seen_enum_fields, |
| 11460 | &range_set, |
| 11461 | item_ref, |
| 11462 | cond_ty, |
| 11463 | block.src(.{ .switch_case_item = .{ |
| 11464 | .switch_node_offset = src_node_offset, |
| 11465 | .case_idx = .special_under, |
| 11466 | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 11467 | } }), |
| 11468 | ); |
| 11469 | } |
| 11470 | try sema.validateSwitchNoRange(block, @intCast(absorbed_ranges.len), cond_ty, src_node_offset); |
| 11471 | |
| 11472 | var extra_index: usize = special_end; |
| 11412 | 11473 | { |
| 11413 | 11474 | var scalar_i: u32 = 0; |
| 11414 | 11475 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11466,13 +11527,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11466 | 11527 | if (seen_src == null) break false; |
| 11467 | 11528 | } else true; |
| 11468 | 11529 | |
| 11469 | | if (special_prong == .@"else") { |
| 11470 | | if (all_tags_handled and !cond_ty.isNonexhaustiveEnum(zcu)) return sema.fail( |
| 11471 | | block, |
| 11472 | | special_prong_src, |
| 11473 | | "unreachable else prong; all cases already handled", |
| 11474 | | .{}, |
| 11475 | | ); |
| 11530 | if (has_else) { |
| 11531 | if (all_tags_handled) { |
| 11532 | if (cond_ty.isNonexhaustiveEnum(zcu)) { |
| 11533 | if (has_under) return sema.fail( |
| 11534 | block, |
| 11535 | else_prong_src, |
| 11536 | "unreachable else prong; all explicit cases already handled", |
| 11537 | .{}, |
| 11538 | ); |
| 11539 | } else return sema.fail( |
| 11540 | block, |
| 11541 | else_prong_src, |
| 11542 | "unreachable else prong; all cases already handled", |
| 11543 | .{}, |
| 11544 | ); |
| 11545 | } |
| 11476 | 11546 | } else if (!all_tags_handled) { |
| 11477 | 11547 | const msg = msg: { |
| 11478 | 11548 | const msg = try sema.errMsg( |
| ... | ... | @@ -11490,7 +11560,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11490 | 11560 | i, |
| 11491 | 11561 | msg, |
| 11492 | 11562 | "unhandled enumeration value: '{f}'", |
| 11493 | | .{field_name.fmt(&zcu.intern_pool)}, |
| 11563 | .{field_name.fmt(ip)}, |
| 11494 | 11564 | ); |
| 11495 | 11565 | } |
| 11496 | 11566 | try sema.errNote( |
| ... | ... | @@ -11502,11 +11572,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11502 | 11572 | break :msg msg; |
| 11503 | 11573 | }; |
| 11504 | 11574 | return sema.failWithOwnedErrorMsg(block, msg); |
| 11505 | | } else if (special_prong == .none and cond_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 11575 | } else if (special_prongs == .none and cond_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 11506 | 11576 | return sema.fail( |
| 11507 | 11577 | block, |
| 11508 | 11578 | src, |
| 11509 | | "switch on non-exhaustive enum must include 'else' or '_' prong", |
| 11579 | "switch on non-exhaustive enum must include 'else' or '_' prong or both", |
| 11510 | 11580 | .{}, |
| 11511 | 11581 | ); |
| 11512 | 11582 | } |
| ... | ... | @@ -11520,11 +11590,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11520 | 11590 | inst_data, |
| 11521 | 11591 | scalar_cases_len, |
| 11522 | 11592 | multi_cases_len, |
| 11523 | | .{ .body = special.body, .end = special.end, .src = special_prong_src }, |
| 11524 | | special_prong == .@"else", |
| 11593 | .{ .body = special_else.body, .end = special_else.end, .src = else_prong_src }, |
| 11594 | has_else, |
| 11525 | 11595 | ), |
| 11526 | 11596 | .int, .comptime_int => { |
| 11527 | | var extra_index: usize = special.end; |
| 11597 | var extra_index: usize = special_end; |
| 11528 | 11598 | { |
| 11529 | 11599 | var scalar_i: u32 = 0; |
| 11530 | 11600 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11606,10 +11676,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11606 | 11676 | const min_int = try cond_ty.minInt(pt, cond_ty); |
| 11607 | 11677 | const max_int = try cond_ty.maxInt(pt, cond_ty); |
| 11608 | 11678 | if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) { |
| 11609 | | if (special_prong == .@"else") { |
| 11679 | if (has_else) { |
| 11610 | 11680 | return sema.fail( |
| 11611 | 11681 | block, |
| 11612 | | special_prong_src, |
| 11682 | else_prong_src, |
| 11613 | 11683 | "unreachable else prong; all cases already handled", |
| 11614 | 11684 | .{}, |
| 11615 | 11685 | ); |
| ... | ... | @@ -11617,7 +11687,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11617 | 11687 | break :check_range; |
| 11618 | 11688 | } |
| 11619 | 11689 | } |
| 11620 | | if (special_prong != .@"else") { |
| 11690 | if (special_prongs == .none) { |
| 11621 | 11691 | return sema.fail( |
| 11622 | 11692 | block, |
| 11623 | 11693 | src, |
| ... | ... | @@ -11628,7 +11698,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11628 | 11698 | } |
| 11629 | 11699 | }, |
| 11630 | 11700 | .bool => { |
| 11631 | | var extra_index: usize = special.end; |
| 11701 | var extra_index: usize = special_end; |
| 11632 | 11702 | { |
| 11633 | 11703 | var scalar_i: u32 = 0; |
| 11634 | 11704 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11680,31 +11750,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11680 | 11750 | try sema.validateSwitchNoRange(block, ranges_len, cond_ty, src_node_offset); |
| 11681 | 11751 | } |
| 11682 | 11752 | } |
| 11683 | | switch (special_prong) { |
| 11684 | | .@"else" => { |
| 11685 | | if (true_count + false_count == 2) { |
| 11686 | | return sema.fail( |
| 11687 | | block, |
| 11688 | | special_prong_src, |
| 11689 | | "unreachable else prong; all cases already handled", |
| 11690 | | .{}, |
| 11691 | | ); |
| 11692 | | } |
| 11693 | | }, |
| 11694 | | .under, .none => { |
| 11695 | | if (true_count + false_count < 2) { |
| 11696 | | return sema.fail( |
| 11697 | | block, |
| 11698 | | src, |
| 11699 | | "switch must handle all possibilities", |
| 11700 | | .{}, |
| 11701 | | ); |
| 11702 | | } |
| 11703 | | }, |
| 11753 | if (has_else) { |
| 11754 | if (true_count + false_count == 2) { |
| 11755 | return sema.fail( |
| 11756 | block, |
| 11757 | else_prong_src, |
| 11758 | "unreachable else prong; all cases already handled", |
| 11759 | .{}, |
| 11760 | ); |
| 11761 | } |
| 11762 | } else { |
| 11763 | if (true_count + false_count < 2) { |
| 11764 | return sema.fail( |
| 11765 | block, |
| 11766 | src, |
| 11767 | "switch must handle all possibilities", |
| 11768 | .{}, |
| 11769 | ); |
| 11770 | } |
| 11704 | 11771 | } |
| 11705 | 11772 | }, |
| 11706 | 11773 | .enum_literal, .void, .@"fn", .pointer, .type => { |
| 11707 | | if (special_prong != .@"else") { |
| 11774 | if (!has_else) { |
| 11708 | 11775 | return sema.fail( |
| 11709 | 11776 | block, |
| 11710 | 11777 | src, |
| ... | ... | @@ -11716,7 +11783,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11716 | 11783 | var seen_values = ValueSrcMap{}; |
| 11717 | 11784 | defer seen_values.deinit(gpa); |
| 11718 | 11785 | |
| 11719 | | var extra_index: usize = special.end; |
| 11786 | var extra_index: usize = special_end; |
| 11720 | 11787 | { |
| 11721 | 11788 | var scalar_i: u32 = 0; |
| 11722 | 11789 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -11789,6 +11856,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11789 | 11856 | }), |
| 11790 | 11857 | } |
| 11791 | 11858 | |
| 11859 | var special_members_only: ?SpecialProng = null; |
| 11860 | var special_members_only_src: LazySrcLoc = undefined; |
| 11861 | const special_generic, const special_generic_src = if (has_under) b: { |
| 11862 | if (has_else) { |
| 11863 | special_members_only = special_else; |
| 11864 | special_members_only_src = else_prong_src; |
| 11865 | } |
| 11866 | break :b .{ special_under, under_prong_src }; |
| 11867 | } else .{ special_else, else_prong_src }; |
| 11868 | |
| 11792 | 11869 | const spa: SwitchProngAnalysis = .{ |
| 11793 | 11870 | .sema = sema, |
| 11794 | 11871 | .parent_block = block, |
| ... | ... | @@ -11835,11 +11912,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11835 | 11912 | defer child_block.instructions.deinit(gpa); |
| 11836 | 11913 | defer merges.deinit(gpa); |
| 11837 | 11914 | |
| 11838 | | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| 11915 | if (scalar_cases_len + multi_cases_len == 0 and |
| 11916 | special_members_only == null and |
| 11917 | !special_generic.is_inline) |
| 11918 | { |
| 11839 | 11919 | if (empty_enum) { |
| 11840 | 11920 | return .void_value; |
| 11841 | 11921 | } |
| 11842 | | if (special_prong == .none) { |
| 11922 | if (special_prongs == .none) { |
| 11843 | 11923 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 11844 | 11924 | } |
| 11845 | 11925 | const init_cond = switch (operand) { |
| ... | ... | @@ -11853,7 +11933,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11853 | 11933 | const ok = try block.addUnOp(.is_named_enum_value, init_cond); |
| 11854 | 11934 | try sema.addSafetyCheck(block, src, ok, .corrupt_switch); |
| 11855 | 11935 | } |
| 11856 | | if (err_set and try sema.maybeErrorUnwrap(block, special.body, init_cond, operand_src, false)) { |
| 11936 | if (err_set and try sema.maybeErrorUnwrap(block, special_generic.body, init_cond, operand_src, false)) { |
| 11857 | 11937 | return .unreachable_value; |
| 11858 | 11938 | } |
| 11859 | 11939 | } |
| ... | ... | @@ -11873,7 +11953,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11873 | 11953 | cond_ty, |
| 11874 | 11954 | cond_val, |
| 11875 | 11955 | src_node_offset, |
| 11876 | | special, |
| 11956 | special_members_only, |
| 11957 | special_generic, |
| 11958 | has_under, |
| 11877 | 11959 | case_vals, |
| 11878 | 11960 | scalar_cases_len, |
| 11879 | 11961 | multi_cases_len, |
| ... | ... | @@ -11883,15 +11965,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11883 | 11965 | ); |
| 11884 | 11966 | } |
| 11885 | 11967 | |
| 11886 | | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline and !extra.data.bits.has_continue) { |
| 11968 | if (scalar_cases_len + multi_cases_len == 0 and |
| 11969 | special_members_only == null and |
| 11970 | !special_generic.is_inline and |
| 11971 | !extra.data.bits.has_continue) |
| 11972 | { |
| 11887 | 11973 | return spa.resolveProngComptime( |
| 11888 | 11974 | &child_block, |
| 11889 | 11975 | .special, |
| 11890 | | special.body, |
| 11891 | | special.capture, |
| 11976 | special_generic.body, |
| 11977 | special_generic.capture, |
| 11892 | 11978 | block.src(.{ .switch_capture = .{ |
| 11893 | 11979 | .switch_node_offset = src_node_offset, |
| 11894 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 11980 | .case_idx = if (has_under) .special_under else .special_else, |
| 11895 | 11981 | } }), |
| 11896 | 11982 | undefined, // case_vals may be undefined for special prongs |
| 11897 | 11983 | .none, |
| ... | ... | @@ -11907,6 +11993,87 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11907 | 11993 | unreachable; |
| 11908 | 11994 | } |
| 11909 | 11995 | |
| 11996 | var extra_case_vals: struct { |
| 11997 | items: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 11998 | ranges: std.ArrayListUnmanaged([2]Air.Inst.Ref), |
| 11999 | } = .{ .items = .empty, .ranges = .empty }; |
| 12000 | defer { |
| 12001 | extra_case_vals.items.deinit(gpa); |
| 12002 | extra_case_vals.ranges.deinit(gpa); |
| 12003 | } |
| 12004 | |
| 12005 | // Runtime switch, if we have a special_members_only prong we need to unroll |
| 12006 | // it to a prong with explicit items. |
| 12007 | // Although this is potentially the same as `inline else` it does not count |
| 12008 | // towards the backward branch quota because it's an implementation detail. |
| 12009 | if (special_members_only != null) gen: { |
| 12010 | assert(cond_ty.isNonexhaustiveEnum(zcu)); |
| 12011 | |
| 12012 | var min_i: usize = math.maxInt(usize); |
| 12013 | var max_i: usize = 0; |
| 12014 | var seen_field_count: usize = 0; |
| 12015 | for (seen_enum_fields, 0..) |seen, enum_i| { |
| 12016 | if (seen != null) { |
| 12017 | seen_field_count += 1; |
| 12018 | } else { |
| 12019 | min_i = @min(min_i, enum_i); |
| 12020 | max_i = @max(max_i, enum_i); |
| 12021 | } |
| 12022 | } |
| 12023 | if (min_i == max_i) { |
| 12024 | seen_enum_fields[min_i] = special_members_only_src; |
| 12025 | const item_val = try pt.enumValueFieldIndex(cond_ty, @intCast(min_i)); |
| 12026 | const item_ref = Air.internedToRef(item_val.toIntern()); |
| 12027 | try extra_case_vals.items.append(gpa, item_ref); |
| 12028 | break :gen; |
| 12029 | } |
| 12030 | const missing_field_count = seen_enum_fields.len - seen_field_count; |
| 12031 | |
| 12032 | extra_case_vals.items = try .initCapacity(gpa, missing_field_count / 2); |
| 12033 | extra_case_vals.ranges = try .initCapacity(gpa, missing_field_count / 4); |
| 12034 | const int_ty = cond_ty.intTagType(zcu); |
| 12035 | |
| 12036 | var last_val = try pt.enumValueFieldIndex(cond_ty, @intCast(min_i)); |
| 12037 | var first_ref = Air.internedToRef(last_val.toIntern()); |
| 12038 | seen_enum_fields[min_i] = special_members_only_src; |
| 12039 | for (seen_enum_fields[(min_i + 1)..(max_i + 1)], (min_i + 1)..) |seen, enum_i| { |
| 12040 | if (seen != null) continue; |
| 12041 | seen_enum_fields[enum_i] = special_members_only_src; |
| 12042 | |
| 12043 | const item_val = try pt.enumValueFieldIndex(cond_ty, @intCast(enum_i)); |
| 12044 | const item_ref = Air.internedToRef(item_val.toIntern()); |
| 12045 | |
| 12046 | const is_next = is_next: { |
| 12047 | const prev_int = ip.indexToKey(last_val.toIntern()).enum_tag.int; |
| 12048 | |
| 12049 | const result = try arith.incrementDefinedInt(sema, int_ty, .fromInterned(prev_int)); |
| 12050 | if (result.overflow) break :is_next false; |
| 12051 | |
| 12052 | const item_int = ip.indexToKey(item_val.toIntern()).enum_tag.int; |
| 12053 | break :is_next try sema.valuesEqual(.fromInterned(item_int), result.val, int_ty); |
| 12054 | }; |
| 12055 | |
| 12056 | if (is_next) { |
| 12057 | last_val = item_val; |
| 12058 | } else { |
| 12059 | const last_ref = Air.internedToRef(last_val.toIntern()); |
| 12060 | if (first_ref == last_ref) { |
| 12061 | try extra_case_vals.items.append(gpa, first_ref); |
| 12062 | } else { |
| 12063 | try extra_case_vals.ranges.append(gpa, .{ first_ref, last_ref }); |
| 12064 | } |
| 12065 | first_ref = item_ref; |
| 12066 | last_val = item_val; |
| 12067 | } |
| 12068 | } |
| 12069 | const last_ref = Air.internedToRef(last_val.toIntern()); |
| 12070 | if (first_ref == last_ref) { |
| 12071 | try extra_case_vals.items.append(gpa, first_ref); |
| 12072 | } else { |
| 12073 | try extra_case_vals.ranges.append(gpa, .{ first_ref, last_ref }); |
| 12074 | } |
| 12075 | } |
| 12076 | |
| 11910 | 12077 | const air_switch_ref = try sema.analyzeSwitchRuntimeBlock( |
| 11911 | 12078 | spa, |
| 11912 | 12079 | &child_block, |
| ... | ... | @@ -11918,14 +12085,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11918 | 12085 | cond_ty, |
| 11919 | 12086 | operand_src, |
| 11920 | 12087 | case_vals, |
| 11921 | | special, |
| 12088 | special_generic, |
| 11922 | 12089 | scalar_cases_len, |
| 11923 | 12090 | multi_cases_len, |
| 11924 | 12091 | union_originally, |
| 11925 | 12092 | raw_operand_ty, |
| 11926 | 12093 | err_set, |
| 11927 | 12094 | src_node_offset, |
| 11928 | | special_prong_src, |
| 12095 | special_generic_src, |
| 12096 | has_under, |
| 11929 | 12097 | seen_enum_fields, |
| 11930 | 12098 | seen_errors, |
| 11931 | 12099 | range_set, |
| ... | ... | @@ -11933,6 +12101,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11933 | 12101 | false_count, |
| 11934 | 12102 | cond_dbg_node_index, |
| 11935 | 12103 | false, |
| 12104 | special_members_only, |
| 12105 | special_members_only_src, |
| 12106 | extra_case_vals.items.items, |
| 12107 | extra_case_vals.ranges.items, |
| 11936 | 12108 | ); |
| 11937 | 12109 | |
| 11938 | 12110 | for (merges.extra_insts.items, merges.extra_src_locs.items) |placeholder_inst, dispatch_src| { |
| ... | ... | @@ -12016,14 +12188,15 @@ fn analyzeSwitchRuntimeBlock( |
| 12016 | 12188 | operand_ty: Type, |
| 12017 | 12189 | operand_src: LazySrcLoc, |
| 12018 | 12190 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12019 | | special: SpecialProng, |
| 12191 | else_prong: SpecialProng, |
| 12020 | 12192 | scalar_cases_len: usize, |
| 12021 | 12193 | multi_cases_len: usize, |
| 12022 | 12194 | union_originally: bool, |
| 12023 | 12195 | maybe_union_ty: Type, |
| 12024 | 12196 | err_set: bool, |
| 12025 | 12197 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12026 | | special_prong_src: LazySrcLoc, |
| 12198 | else_prong_src: LazySrcLoc, |
| 12199 | else_prong_is_underscore: bool, |
| 12027 | 12200 | seen_enum_fields: []?LazySrcLoc, |
| 12028 | 12201 | seen_errors: SwitchErrorSet, |
| 12029 | 12202 | range_set: RangeSet, |
| ... | ... | @@ -12031,6 +12204,11 @@ fn analyzeSwitchRuntimeBlock( |
| 12031 | 12204 | false_count: u8, |
| 12032 | 12205 | cond_dbg_node_index: Zir.Inst.Index, |
| 12033 | 12206 | allow_err_code_unwrap: bool, |
| 12207 | extra_prong: ?SpecialProng, |
| 12208 | /// May be `undefined` if `extra_prong` is `null` |
| 12209 | extra_prong_src: LazySrcLoc, |
| 12210 | extra_prong_items: []const Air.Inst.Ref, |
| 12211 | extra_prong_ranges: []const [2]Air.Inst.Ref, |
| 12034 | 12212 | ) CompileError!Air.Inst.Ref { |
| 12035 | 12213 | const pt = sema.pt; |
| 12036 | 12214 | const zcu = pt.zcu; |
| ... | ... | @@ -12054,7 +12232,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12054 | 12232 | case_block.need_debug_scope = null; // this body is emitted regardless |
| 12055 | 12233 | defer case_block.instructions.deinit(gpa); |
| 12056 | 12234 | |
| 12057 | | var extra_index: usize = special.end; |
| 12235 | var extra_index: usize = else_prong.end; |
| 12058 | 12236 | |
| 12059 | 12237 | var scalar_i: usize = 0; |
| 12060 | 12238 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -12116,23 +12294,42 @@ fn analyzeSwitchRuntimeBlock( |
| 12116 | 12294 | |
| 12117 | 12295 | var cases_len = scalar_cases_len; |
| 12118 | 12296 | var case_val_idx: usize = scalar_cases_len; |
| 12297 | const multi_cases_len_with_extra_prong = multi_cases_len + @intFromBool(extra_prong != null); |
| 12119 | 12298 | var multi_i: u32 = 0; |
| 12120 | | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 12121 | | const items_len = sema.code.extra[extra_index]; |
| 12122 | | extra_index += 1; |
| 12123 | | const ranges_len = sema.code.extra[extra_index]; |
| 12124 | | extra_index += 1; |
| 12125 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12126 | | extra_index += 1 + items_len + 2 * ranges_len; |
| 12299 | while (multi_i < multi_cases_len_with_extra_prong) : (multi_i += 1) { |
| 12300 | const is_extra_prong = multi_i == multi_cases_len; |
| 12301 | var items: []const Air.Inst.Ref = undefined; |
| 12302 | var info: Zir.Inst.SwitchBlock.ProngInfo = undefined; |
| 12303 | var ranges: []const [2]Air.Inst.Ref = undefined; |
| 12304 | var body: []const Zir.Inst.Index = undefined; |
| 12305 | if (is_extra_prong) { |
| 12306 | const prong = extra_prong.?; |
| 12307 | items = extra_prong_items; |
| 12308 | ranges = extra_prong_ranges; |
| 12309 | body = prong.body; |
| 12310 | info = .{ |
| 12311 | .body_len = undefined, |
| 12312 | .capture = prong.capture, |
| 12313 | .is_inline = prong.is_inline, |
| 12314 | .has_tag_capture = prong.has_tag_capture, |
| 12315 | }; |
| 12316 | } else { |
| 12317 | @branchHint(.likely); |
| 12318 | const items_len = sema.code.extra[extra_index]; |
| 12319 | extra_index += 1; |
| 12320 | const ranges_len = sema.code.extra[extra_index]; |
| 12321 | extra_index += 1; |
| 12322 | info = @bitCast(sema.code.extra[extra_index]); |
| 12323 | extra_index += 1 + items_len + ranges_len * 2; |
| 12127 | 12324 | |
| 12128 | | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 12129 | | case_val_idx += items_len; |
| 12130 | | // TODO: @ptrCast slice once Sema supports it |
| 12131 | | const ranges: []const [2]Air.Inst.Ref = @as([*]const [2]Air.Inst.Ref, @ptrCast(case_vals.items[case_val_idx..]))[0..ranges_len]; |
| 12132 | | case_val_idx += ranges_len * 2; |
| 12325 | items = case_vals.items[case_val_idx..][0..items_len]; |
| 12326 | case_val_idx += items_len; |
| 12327 | ranges = @ptrCast(case_vals.items[case_val_idx..][0 .. ranges_len * 2]); |
| 12328 | case_val_idx += ranges_len * 2; |
| 12133 | 12329 | |
| 12134 | | const body = sema.code.bodySlice(extra_index, info.body_len); |
| 12135 | | extra_index += info.body_len; |
| 12330 | body = sema.code.bodySlice(extra_index, info.body_len); |
| 12331 | extra_index += info.body_len; |
| 12332 | } |
| 12136 | 12333 | |
| 12137 | 12334 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12138 | 12335 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| ... | ... | @@ -12142,14 +12339,29 @@ fn analyzeSwitchRuntimeBlock( |
| 12142 | 12339 | var emit_bb = false; |
| 12143 | 12340 | |
| 12144 | 12341 | for (ranges, 0..) |range_items, range_i| { |
| 12145 | | var item = sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, range_items[0], undefined) catch unreachable; |
| 12146 | | const item_last = sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, range_items[1], undefined) catch unreachable; |
| 12342 | var item = sema.resolveConstDefinedValue(block, .unneeded, range_items[0], undefined) catch unreachable; |
| 12343 | const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_items[1], undefined) catch unreachable; |
| 12147 | 12344 | |
| 12148 | 12345 | while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({ |
| 12149 | 12346 | // Previous validation has resolved any possible lazy values. |
| 12150 | | const result = try arith.incrementDefinedInt(sema, operand_ty, item); |
| 12347 | const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) { |
| 12348 | .int => .{ item, operand_ty }, |
| 12349 | .@"enum" => b: { |
| 12350 | const int_val = Value.fromInterned(ip.indexToKey(item.toIntern()).enum_tag.int); |
| 12351 | break :b .{ int_val, int_val.typeOf(zcu) }; |
| 12352 | }, |
| 12353 | else => unreachable, |
| 12354 | }; |
| 12355 | const result = try arith.incrementDefinedInt(sema, int_ty, int_val); |
| 12151 | 12356 | assert(!result.overflow); |
| 12152 | | item = result.val; |
| 12357 | item = switch (operand_ty.zigTypeTag(zcu)) { |
| 12358 | .int => result.val, |
| 12359 | .@"enum" => .fromInterned(try pt.intern(.{ .enum_tag = .{ |
| 12360 | .ty = operand_ty.toIntern(), |
| 12361 | .int = result.val.toIntern(), |
| 12362 | } })), |
| 12363 | else => unreachable, |
| 12364 | }; |
| 12153 | 12365 | }) { |
| 12154 | 12366 | cases_len += 1; |
| 12155 | 12367 | |
| ... | ... | @@ -12158,11 +12370,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12158 | 12370 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12159 | 12371 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12160 | 12372 | |
| 12161 | | if (emit_bb) try sema.emitBackwardBranch(block, block.src(.{ .switch_case_item = .{ |
| 12162 | | .switch_node_offset = switch_node_offset, |
| 12163 | | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12164 | | .item_idx = .{ .kind = .range, .index = @intCast(range_i) }, |
| 12165 | | } })); |
| 12373 | if (emit_bb) { |
| 12374 | const bb_src = if (is_extra_prong) extra_prong_src else block.src(.{ .switch_case_item = .{ |
| 12375 | .switch_node_offset = switch_node_offset, |
| 12376 | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12377 | .item_idx = .{ .kind = .range, .index = @intCast(range_i) }, |
| 12378 | } }); |
| 12379 | try sema.emitBackwardBranch(block, bb_src); |
| 12380 | } |
| 12166 | 12381 | emit_bb = true; |
| 12167 | 12382 | |
| 12168 | 12383 | const prong_hint = try spa.analyzeProngRuntime( |
| ... | ... | @@ -12207,11 +12422,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12207 | 12422 | break :blk field_ty.zigTypeTag(zcu) != .noreturn; |
| 12208 | 12423 | } else true; |
| 12209 | 12424 | |
| 12210 | | if (emit_bb) try sema.emitBackwardBranch(block, block.src(.{ .switch_case_item = .{ |
| 12211 | | .switch_node_offset = switch_node_offset, |
| 12212 | | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12213 | | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 12214 | | } })); |
| 12425 | if (emit_bb) { |
| 12426 | const bb_src = if (is_extra_prong) extra_prong_src else block.src(.{ .switch_case_item = .{ |
| 12427 | .switch_node_offset = switch_node_offset, |
| 12428 | .case_idx = .{ .kind = .multi, .index = @intCast(multi_i) }, |
| 12429 | .item_idx = .{ .kind = .single, .index = @intCast(item_i) }, |
| 12430 | } }); |
| 12431 | try sema.emitBackwardBranch(block, bb_src); |
| 12432 | } |
| 12215 | 12433 | emit_bb = true; |
| 12216 | 12434 | |
| 12217 | 12435 | const prong_hint: std.builtin.BranchHint = if (analyze_body) h: { |
| ... | ... | @@ -12287,11 +12505,11 @@ fn analyzeSwitchRuntimeBlock( |
| 12287 | 12505 | try branch_hints.append(gpa, prong_hint); |
| 12288 | 12506 | |
| 12289 | 12507 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + |
| 12290 | | items.len + 2 * ranges_len + |
| 12508 | items.len + ranges.len * 2 + |
| 12291 | 12509 | case_block.instructions.items.len); |
| 12292 | 12510 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ |
| 12293 | 12511 | .items_len = @intCast(items.len), |
| 12294 | | .ranges_len = @intCast(ranges_len), |
| 12512 | .ranges_len = @intCast(ranges.len), |
| 12295 | 12513 | .body_len = @intCast(case_block.instructions.items.len), |
| 12296 | 12514 | })); |
| 12297 | 12515 | |
| ... | ... | @@ -12308,12 +12526,14 @@ fn analyzeSwitchRuntimeBlock( |
| 12308 | 12526 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); |
| 12309 | 12527 | } |
| 12310 | 12528 | |
| 12311 | | const else_body: []const Air.Inst.Index = if (special.body.len != 0 or case_block.wantSafety()) else_body: { |
| 12529 | const else_body: []const Air.Inst.Index = if (else_prong.body.len != 0 or case_block.wantSafety()) else_body: { |
| 12312 | 12530 | var emit_bb = false; |
| 12313 | | if (special.is_inline) switch (operand_ty.zigTypeTag(zcu)) { |
| 12531 | // If this is true we must have a 'true' else prong and not an underscore because |
| 12532 | // underscore prongs can never be inlined. We've already checked for this. |
| 12533 | if (else_prong.is_inline) switch (operand_ty.zigTypeTag(zcu)) { |
| 12314 | 12534 | .@"enum" => { |
| 12315 | 12535 | if (operand_ty.isNonexhaustiveEnum(zcu) and !union_originally) { |
| 12316 | | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12536 | return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12317 | 12537 | operand_ty.fmt(pt), |
| 12318 | 12538 | }); |
| 12319 | 12539 | } |
| ... | ... | @@ -12332,22 +12552,22 @@ fn analyzeSwitchRuntimeBlock( |
| 12332 | 12552 | break :blk field_ty.zigTypeTag(zcu) != .noreturn; |
| 12333 | 12553 | } else true; |
| 12334 | 12554 | |
| 12335 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12555 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12336 | 12556 | emit_bb = true; |
| 12337 | 12557 | |
| 12338 | 12558 | const prong_hint: std.builtin.BranchHint = if (analyze_body) h: { |
| 12339 | 12559 | break :h try spa.analyzeProngRuntime( |
| 12340 | 12560 | &case_block, |
| 12341 | 12561 | .special, |
| 12342 | | special.body, |
| 12343 | | special.capture, |
| 12562 | else_prong.body, |
| 12563 | else_prong.capture, |
| 12344 | 12564 | child_block.src(.{ .switch_capture = .{ |
| 12345 | 12565 | .switch_node_offset = switch_node_offset, |
| 12346 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12566 | .case_idx = .special_else, |
| 12347 | 12567 | } }), |
| 12348 | 12568 | &.{item_ref}, |
| 12349 | 12569 | item_ref, |
| 12350 | | special.has_tag_capture, |
| 12570 | else_prong.has_tag_capture, |
| 12351 | 12571 | ); |
| 12352 | 12572 | } else h: { |
| 12353 | 12573 | _ = try case_block.addNoOp(.unreach); |
| ... | ... | @@ -12369,7 +12589,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12369 | 12589 | }, |
| 12370 | 12590 | .error_set => { |
| 12371 | 12591 | if (operand_ty.isAnyError(zcu)) { |
| 12372 | | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12592 | return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12373 | 12593 | operand_ty.fmt(pt), |
| 12374 | 12594 | }); |
| 12375 | 12595 | } |
| ... | ... | @@ -12388,21 +12608,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12388 | 12608 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12389 | 12609 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12390 | 12610 | |
| 12391 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12611 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12392 | 12612 | emit_bb = true; |
| 12393 | 12613 | |
| 12394 | 12614 | const prong_hint = try spa.analyzeProngRuntime( |
| 12395 | 12615 | &case_block, |
| 12396 | 12616 | .special, |
| 12397 | | special.body, |
| 12398 | | special.capture, |
| 12617 | else_prong.body, |
| 12618 | else_prong.capture, |
| 12399 | 12619 | child_block.src(.{ .switch_capture = .{ |
| 12400 | 12620 | .switch_node_offset = switch_node_offset, |
| 12401 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12621 | .case_idx = .special_else, |
| 12402 | 12622 | } }), |
| 12403 | 12623 | &.{item_ref}, |
| 12404 | 12624 | item_ref, |
| 12405 | | special.has_tag_capture, |
| 12625 | else_prong.has_tag_capture, |
| 12406 | 12626 | ); |
| 12407 | 12627 | try branch_hints.append(gpa, prong_hint); |
| 12408 | 12628 | |
| ... | ... | @@ -12428,21 +12648,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12428 | 12648 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12429 | 12649 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12430 | 12650 | |
| 12431 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12651 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12432 | 12652 | emit_bb = true; |
| 12433 | 12653 | |
| 12434 | 12654 | const prong_hint = try spa.analyzeProngRuntime( |
| 12435 | 12655 | &case_block, |
| 12436 | 12656 | .special, |
| 12437 | | special.body, |
| 12438 | | special.capture, |
| 12657 | else_prong.body, |
| 12658 | else_prong.capture, |
| 12439 | 12659 | child_block.src(.{ .switch_capture = .{ |
| 12440 | 12660 | .switch_node_offset = switch_node_offset, |
| 12441 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12661 | .case_idx = .special_else, |
| 12442 | 12662 | } }), |
| 12443 | 12663 | &.{item_ref}, |
| 12444 | 12664 | item_ref, |
| 12445 | | special.has_tag_capture, |
| 12665 | else_prong.has_tag_capture, |
| 12446 | 12666 | ); |
| 12447 | 12667 | try branch_hints.append(gpa, prong_hint); |
| 12448 | 12668 | |
| ... | ... | @@ -12465,21 +12685,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12465 | 12685 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12466 | 12686 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12467 | 12687 | |
| 12468 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12688 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12469 | 12689 | emit_bb = true; |
| 12470 | 12690 | |
| 12471 | 12691 | const prong_hint = try spa.analyzeProngRuntime( |
| 12472 | 12692 | &case_block, |
| 12473 | 12693 | .special, |
| 12474 | | special.body, |
| 12475 | | special.capture, |
| 12694 | else_prong.body, |
| 12695 | else_prong.capture, |
| 12476 | 12696 | child_block.src(.{ .switch_capture = .{ |
| 12477 | 12697 | .switch_node_offset = switch_node_offset, |
| 12478 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12698 | .case_idx = .special_else, |
| 12479 | 12699 | } }), |
| 12480 | 12700 | &.{.bool_true}, |
| 12481 | 12701 | .bool_true, |
| 12482 | | special.has_tag_capture, |
| 12702 | else_prong.has_tag_capture, |
| 12483 | 12703 | ); |
| 12484 | 12704 | try branch_hints.append(gpa, prong_hint); |
| 12485 | 12705 | |
| ... | ... | @@ -12500,21 +12720,21 @@ fn analyzeSwitchRuntimeBlock( |
| 12500 | 12720 | case_block.instructions.shrinkRetainingCapacity(0); |
| 12501 | 12721 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12502 | 12722 | |
| 12503 | | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 12723 | if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src); |
| 12504 | 12724 | emit_bb = true; |
| 12505 | 12725 | |
| 12506 | 12726 | const prong_hint = try spa.analyzeProngRuntime( |
| 12507 | 12727 | &case_block, |
| 12508 | 12728 | .special, |
| 12509 | | special.body, |
| 12510 | | special.capture, |
| 12729 | else_prong.body, |
| 12730 | else_prong.capture, |
| 12511 | 12731 | child_block.src(.{ .switch_capture = .{ |
| 12512 | 12732 | .switch_node_offset = switch_node_offset, |
| 12513 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12733 | .case_idx = .special_else, |
| 12514 | 12734 | } }), |
| 12515 | 12735 | &.{.bool_false}, |
| 12516 | 12736 | .bool_false, |
| 12517 | | special.has_tag_capture, |
| 12737 | else_prong.has_tag_capture, |
| 12518 | 12738 | ); |
| 12519 | 12739 | try branch_hints.append(gpa, prong_hint); |
| 12520 | 12740 | |
| ... | ... | @@ -12530,7 +12750,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12530 | 12750 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); |
| 12531 | 12751 | } |
| 12532 | 12752 | }, |
| 12533 | | else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12753 | else => return sema.fail(block, else_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ |
| 12534 | 12754 | operand_ty.fmt(pt), |
| 12535 | 12755 | }), |
| 12536 | 12756 | }; |
| ... | ... | @@ -12539,7 +12759,7 @@ fn analyzeSwitchRuntimeBlock( |
| 12539 | 12759 | case_block.error_return_trace_index = child_block.error_return_trace_index; |
| 12540 | 12760 | |
| 12541 | 12761 | if (zcu.backendSupportsFeature(.is_named_enum_value) and |
| 12542 | | special.body.len != 0 and block.wantSafety() and |
| 12762 | else_prong.body.len != 0 and block.wantSafety() and |
| 12543 | 12763 | operand_ty.zigTypeTag(zcu) == .@"enum" and |
| 12544 | 12764 | (!operand_ty.isNonexhaustiveEnum(zcu) or union_originally)) |
| 12545 | 12765 | { |
| ... | ... | @@ -12548,7 +12768,12 @@ fn analyzeSwitchRuntimeBlock( |
| 12548 | 12768 | try sema.addSafetyCheck(&case_block, src, ok, .corrupt_switch); |
| 12549 | 12769 | } |
| 12550 | 12770 | |
| 12551 | | const analyze_body = if (union_originally and !special.is_inline) |
| 12771 | const else_src_idx: LazySrcLoc.Offset.SwitchCaseIndex = if (else_prong_is_underscore) |
| 12772 | .special_under |
| 12773 | else |
| 12774 | .special_else; |
| 12775 | |
| 12776 | const analyze_body = if (union_originally and !else_prong.is_inline) |
| 12552 | 12777 | for (seen_enum_fields, 0..) |seen_field, index| { |
| 12553 | 12778 | if (seen_field != null) continue; |
| 12554 | 12779 | const union_obj = zcu.typeToUnion(maybe_union_ty).?; |
| ... | ... | @@ -12557,20 +12782,20 @@ fn analyzeSwitchRuntimeBlock( |
| 12557 | 12782 | } else false |
| 12558 | 12783 | else |
| 12559 | 12784 | true; |
| 12560 | | const else_hint: std.builtin.BranchHint = if (special.body.len != 0 and err_set and |
| 12561 | | try sema.maybeErrorUnwrap(&case_block, special.body, operand, operand_src, allow_err_code_unwrap)) |
| 12785 | const else_hint: std.builtin.BranchHint = if (else_prong.body.len != 0 and err_set and |
| 12786 | try sema.maybeErrorUnwrap(&case_block, else_prong.body, operand, operand_src, allow_err_code_unwrap)) |
| 12562 | 12787 | h: { |
| 12563 | 12788 | // nothing to do here. weight against error branch |
| 12564 | 12789 | break :h .unlikely; |
| 12565 | | } else if (special.body.len != 0 and analyze_body and !special.is_inline) h: { |
| 12790 | } else if (else_prong.body.len != 0 and analyze_body and !else_prong.is_inline) h: { |
| 12566 | 12791 | break :h try spa.analyzeProngRuntime( |
| 12567 | 12792 | &case_block, |
| 12568 | 12793 | .special, |
| 12569 | | special.body, |
| 12570 | | special.capture, |
| 12794 | else_prong.body, |
| 12795 | else_prong.capture, |
| 12571 | 12796 | child_block.src(.{ .switch_capture = .{ |
| 12572 | 12797 | .switch_node_offset = switch_node_offset, |
| 12573 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 12798 | .case_idx = else_src_idx, |
| 12574 | 12799 | } }), |
| 12575 | 12800 | undefined, // case_vals may be undefined for special prongs |
| 12576 | 12801 | .none, |
| ... | ... | @@ -12644,7 +12869,9 @@ fn resolveSwitchComptimeLoop( |
| 12644 | 12869 | cond_ty: Type, |
| 12645 | 12870 | init_cond_val: Value, |
| 12646 | 12871 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12647 | | special: SpecialProng, |
| 12872 | special_members_only: ?SpecialProng, |
| 12873 | special_generic: SpecialProng, |
| 12874 | special_generic_is_under: bool, |
| 12648 | 12875 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12649 | 12876 | scalar_cases_len: u32, |
| 12650 | 12877 | multi_cases_len: u32, |
| ... | ... | @@ -12664,7 +12891,9 @@ fn resolveSwitchComptimeLoop( |
| 12664 | 12891 | cond_val, |
| 12665 | 12892 | cond_ty, |
| 12666 | 12893 | switch_node_offset, |
| 12667 | | special, |
| 12894 | special_members_only, |
| 12895 | special_generic, |
| 12896 | special_generic_is_under, |
| 12668 | 12897 | case_vals, |
| 12669 | 12898 | scalar_cases_len, |
| 12670 | 12899 | multi_cases_len, |
| ... | ... | @@ -12712,17 +12941,20 @@ fn resolveSwitchComptime( |
| 12712 | 12941 | operand_val: Value, |
| 12713 | 12942 | operand_ty: Type, |
| 12714 | 12943 | switch_node_offset: std.zig.Ast.Node.Offset, |
| 12715 | | special: SpecialProng, |
| 12944 | special_members_only: ?SpecialProng, |
| 12945 | special_generic: SpecialProng, |
| 12946 | special_generic_is_under: bool, |
| 12716 | 12947 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12717 | 12948 | scalar_cases_len: u32, |
| 12718 | 12949 | multi_cases_len: u32, |
| 12719 | 12950 | err_set: bool, |
| 12720 | 12951 | empty_enum: bool, |
| 12721 | 12952 | ) CompileError!Air.Inst.Ref { |
| 12953 | const zcu = sema.pt.zcu; |
| 12722 | 12954 | const merges = &child_block.label.?.merges; |
| 12723 | 12955 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); |
| 12724 | 12956 | |
| 12725 | | var extra_index: usize = special.end; |
| 12957 | var extra_index: usize = special_generic.end; |
| 12726 | 12958 | { |
| 12727 | 12959 | var scalar_i: usize = 0; |
| 12728 | 12960 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| ... | ... | @@ -12823,23 +13055,45 @@ fn resolveSwitchComptime( |
| 12823 | 13055 | extra_index += info.body_len; |
| 12824 | 13056 | } |
| 12825 | 13057 | } |
| 12826 | | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, special.body, cond_operand); |
| 13058 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, special_generic.body, cond_operand); |
| 12827 | 13059 | if (empty_enum) { |
| 12828 | 13060 | return .void_value; |
| 12829 | 13061 | } |
| 13062 | if (special_members_only) |special| { |
| 13063 | assert(operand_ty.isNonexhaustiveEnum(zcu)); |
| 13064 | if (operand_ty.enumTagFieldIndex(operand_val, zcu)) |_| { |
| 13065 | return spa.resolveProngComptime( |
| 13066 | child_block, |
| 13067 | .special, |
| 13068 | special.body, |
| 13069 | special.capture, |
| 13070 | child_block.src(.{ .switch_capture = .{ |
| 13071 | .switch_node_offset = switch_node_offset, |
| 13072 | .case_idx = .special_else, |
| 13073 | } }), |
| 13074 | undefined, // case_vals may be undefined for special prongs |
| 13075 | if (special.is_inline) cond_operand else .none, |
| 13076 | special.has_tag_capture, |
| 13077 | merges, |
| 13078 | ); |
| 13079 | } |
| 13080 | } |
| 12830 | 13081 | |
| 12831 | 13082 | return spa.resolveProngComptime( |
| 12832 | 13083 | child_block, |
| 12833 | 13084 | .special, |
| 12834 | | special.body, |
| 12835 | | special.capture, |
| 13085 | special_generic.body, |
| 13086 | special_generic.capture, |
| 12836 | 13087 | child_block.src(.{ .switch_capture = .{ |
| 12837 | 13088 | .switch_node_offset = switch_node_offset, |
| 12838 | | .case_idx = LazySrcLoc.Offset.SwitchCaseIndex.special, |
| 13089 | .case_idx = if (special_generic_is_under) |
| 13090 | .special_under |
| 13091 | else |
| 13092 | .special_else, |
| 12839 | 13093 | } }), |
| 12840 | 13094 | undefined, // case_vals may be undefined for special prongs |
| 12841 | | if (special.is_inline) cond_operand else .none, |
| 12842 | | special.has_tag_capture, |
| 13095 | if (special_generic.is_inline) cond_operand else .none, |
| 13096 | special_generic.has_tag_capture, |
| 12843 | 13097 | merges, |
| 12844 | 13098 | ); |
| 12845 | 13099 | } |