| ... | ... | @@ -11212,16 +11212,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11212 | 11212 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 11213 | 11213 | defer case_vals.deinit(gpa); |
| 11214 | 11214 | |
| 11215 | | const Special = struct { |
| 11216 | | body: []const Zir.Inst.Index, |
| 11217 | | end: usize, |
| 11218 | | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 11219 | | is_inline: bool, |
| 11220 | | has_tag_capture: bool, |
| 11221 | | }; |
| 11222 | | |
| 11223 | 11215 | const special_prong = extra.data.bits.specialProng(); |
| 11224 | | const special: Special = switch (special_prong) { |
| 11216 | const special: SpecialProng = switch (special_prong) { |
| 11225 | 11217 | .none => .{ |
| 11226 | 11218 | .body = &.{}, |
| 11227 | 11219 | .end = header_extra_index, |
| ... | ... | @@ -11401,150 +11393,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11401 | 11393 | ); |
| 11402 | 11394 | } |
| 11403 | 11395 | }, |
| 11404 | | .ErrorSet => { |
| 11405 | | var extra_index: usize = special.end; |
| 11406 | | { |
| 11407 | | var scalar_i: u32 = 0; |
| 11408 | | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11409 | | const item_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| 11410 | | extra_index += 1; |
| 11411 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11412 | | extra_index += 1 + info.body_len; |
| 11413 | | |
| 11414 | | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 11415 | | block, |
| 11416 | | &seen_errors, |
| 11417 | | item_ref, |
| 11418 | | operand_ty, |
| 11419 | | src_node_offset, |
| 11420 | | .{ .scalar = scalar_i }, |
| 11421 | | )); |
| 11422 | | } |
| 11423 | | } |
| 11424 | | { |
| 11425 | | var multi_i: u32 = 0; |
| 11426 | | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11427 | | const items_len = sema.code.extra[extra_index]; |
| 11428 | | extra_index += 1; |
| 11429 | | const ranges_len = sema.code.extra[extra_index]; |
| 11430 | | extra_index += 1; |
| 11431 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11432 | | extra_index += 1; |
| 11433 | | const items = sema.code.refSlice(extra_index, items_len); |
| 11434 | | extra_index += items_len + info.body_len; |
| 11435 | | |
| 11436 | | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 11437 | | for (items, 0..) |item_ref, item_i| { |
| 11438 | | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 11439 | | block, |
| 11440 | | &seen_errors, |
| 11441 | | item_ref, |
| 11442 | | operand_ty, |
| 11443 | | src_node_offset, |
| 11444 | | .{ .multi = .{ .prong = multi_i, .item = @intCast(item_i) } }, |
| 11445 | | )); |
| 11446 | | } |
| 11447 | | |
| 11448 | | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| 11449 | | } |
| 11450 | | } |
| 11451 | | |
| 11452 | | switch (try sema.resolveInferredErrorSetTy(block, src, operand_ty.toIntern())) { |
| 11453 | | .anyerror_type => { |
| 11454 | | if (special_prong != .@"else") { |
| 11455 | | return sema.fail( |
| 11456 | | block, |
| 11457 | | src, |
| 11458 | | "else prong required when switching on type 'anyerror'", |
| 11459 | | .{}, |
| 11460 | | ); |
| 11461 | | } |
| 11462 | | else_error_ty = Type.anyerror; |
| 11463 | | }, |
| 11464 | | else => |err_set_ty_index| else_validation: { |
| 11465 | | const error_names = ip.indexToKey(err_set_ty_index).error_set_type.names; |
| 11466 | | var maybe_msg: ?*Module.ErrorMsg = null; |
| 11467 | | errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); |
| 11468 | | |
| 11469 | | for (error_names.get(ip)) |error_name| { |
| 11470 | | if (!seen_errors.contains(error_name) and special_prong != .@"else") { |
| 11471 | | const msg = maybe_msg orelse blk: { |
| 11472 | | maybe_msg = try sema.errMsg( |
| 11473 | | block, |
| 11474 | | src, |
| 11475 | | "switch must handle all possibilities", |
| 11476 | | .{}, |
| 11477 | | ); |
| 11478 | | break :blk maybe_msg.?; |
| 11479 | | }; |
| 11480 | | |
| 11481 | | try sema.errNote( |
| 11482 | | block, |
| 11483 | | src, |
| 11484 | | msg, |
| 11485 | | "unhandled error value: 'error.{}'", |
| 11486 | | .{error_name.fmt(ip)}, |
| 11487 | | ); |
| 11488 | | } |
| 11489 | | } |
| 11490 | | |
| 11491 | | if (maybe_msg) |msg| { |
| 11492 | | maybe_msg = null; |
| 11493 | | try sema.addDeclaredHereNote(msg, operand_ty); |
| 11494 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 11495 | | } |
| 11496 | | |
| 11497 | | if (special_prong == .@"else" and |
| 11498 | | seen_errors.count() == error_names.len) |
| 11499 | | { |
| 11500 | | // In order to enable common patterns for generic code allow simple else bodies |
| 11501 | | // else => unreachable, |
| 11502 | | // else => return, |
| 11503 | | // else => |e| return e, |
| 11504 | | // even if all the possible errors were already handled. |
| 11505 | | const tags = sema.code.instructions.items(.tag); |
| 11506 | | for (special.body) |else_inst| switch (tags[@intFromEnum(else_inst)]) { |
| 11507 | | .dbg_block_begin, |
| 11508 | | .dbg_block_end, |
| 11509 | | .dbg_stmt, |
| 11510 | | .dbg_var_val, |
| 11511 | | .ret_type, |
| 11512 | | .as_node, |
| 11513 | | .ret_node, |
| 11514 | | .@"unreachable", |
| 11515 | | .@"defer", |
| 11516 | | .defer_err_code, |
| 11517 | | .err_union_code, |
| 11518 | | .ret_err_value_code, |
| 11519 | | .restore_err_ret_index, |
| 11520 | | .is_non_err, |
| 11521 | | .ret_is_non_err, |
| 11522 | | .condbr, |
| 11523 | | => {}, |
| 11524 | | else => break, |
| 11525 | | } else break :else_validation; |
| 11526 | | |
| 11527 | | return sema.fail( |
| 11528 | | block, |
| 11529 | | special_prong_src, |
| 11530 | | "unreachable else prong; all cases already handled", |
| 11531 | | .{}, |
| 11532 | | ); |
| 11533 | | } |
| 11534 | | |
| 11535 | | var names: InferredErrorSet.NameMap = .{}; |
| 11536 | | try names.ensureUnusedCapacity(sema.arena, error_names.len); |
| 11537 | | for (error_names.get(ip)) |error_name| { |
| 11538 | | if (seen_errors.contains(error_name)) continue; |
| 11539 | | |
| 11540 | | names.putAssumeCapacityNoClobber(error_name, {}); |
| 11541 | | } |
| 11542 | | // No need to keep the hash map metadata correct; here we |
| 11543 | | // extract the (sorted) keys only. |
| 11544 | | else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 11545 | | }, |
| 11546 | | } |
| 11547 | | }, |
| 11396 | .ErrorSet => else_error_ty = try validateErrSetSwitch( |
| 11397 | sema, |
| 11398 | block, |
| 11399 | &seen_errors, |
| 11400 | &case_vals, |
| 11401 | operand_ty, |
| 11402 | inst_data, |
| 11403 | scalar_cases_len, |
| 11404 | multi_cases_len, |
| 11405 | .{ .body = special.body, .end = special.end, .src = special_prong_src }, |
| 11406 | special_prong == .@"else", |
| 11407 | ), |
| 11548 | 11408 | .Int, .ComptimeInt => { |
| 11549 | 11409 | var extra_index: usize = special.end; |
| 11550 | 11410 | { |
| ... | ... | @@ -11840,114 +11700,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11840 | 11700 | defer merges.deinit(gpa); |
| 11841 | 11701 | |
| 11842 | 11702 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { |
| 11843 | | const resolved_operand_val = try sema.resolveLazyValue(operand_val); |
| 11844 | | var extra_index: usize = special.end; |
| 11845 | | { |
| 11846 | | var scalar_i: usize = 0; |
| 11847 | | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11848 | | extra_index += 1; |
| 11849 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11850 | | extra_index += 1; |
| 11851 | | const body = sema.code.bodySlice(extra_index, info.body_len); |
| 11852 | | extra_index += info.body_len; |
| 11853 | | |
| 11854 | | const item = case_vals.items[scalar_i]; |
| 11855 | | const item_val = sema.resolveConstDefinedValue(&child_block, .unneeded, item, undefined) catch unreachable; |
| 11856 | | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11857 | | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11858 | | return spa.resolveProngComptime( |
| 11859 | | &child_block, |
| 11860 | | .normal, |
| 11861 | | body, |
| 11862 | | info.capture, |
| 11863 | | .{ .scalar_capture = @intCast(scalar_i) }, |
| 11864 | | &.{item}, |
| 11865 | | if (info.is_inline) operand else .none, |
| 11866 | | info.has_tag_capture, |
| 11867 | | merges, |
| 11868 | | ); |
| 11869 | | } |
| 11870 | | } |
| 11871 | | } |
| 11872 | | { |
| 11873 | | var multi_i: usize = 0; |
| 11874 | | var case_val_idx: usize = scalar_cases_len; |
| 11875 | | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11876 | | const items_len = sema.code.extra[extra_index]; |
| 11877 | | extra_index += 1; |
| 11878 | | const ranges_len = sema.code.extra[extra_index]; |
| 11879 | | extra_index += 1; |
| 11880 | | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 11881 | | extra_index += 1 + items_len; |
| 11882 | | const body = sema.code.bodySlice(extra_index + 2 * ranges_len, info.body_len); |
| 11883 | | |
| 11884 | | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11885 | | case_val_idx += items_len; |
| 11886 | | |
| 11887 | | for (items) |item| { |
| 11888 | | // Validation above ensured these will succeed. |
| 11889 | | const item_val = sema.resolveConstDefinedValue(&child_block, .unneeded, item, undefined) catch unreachable; |
| 11890 | | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11891 | | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11892 | | return spa.resolveProngComptime( |
| 11893 | | &child_block, |
| 11894 | | .normal, |
| 11895 | | body, |
| 11896 | | info.capture, |
| 11897 | | .{ .multi_capture = @intCast(multi_i) }, |
| 11898 | | items, |
| 11899 | | if (info.is_inline) operand else .none, |
| 11900 | | info.has_tag_capture, |
| 11901 | | merges, |
| 11902 | | ); |
| 11903 | | } |
| 11904 | | } |
| 11905 | | |
| 11906 | | var range_i: usize = 0; |
| 11907 | | while (range_i < ranges_len) : (range_i += 1) { |
| 11908 | | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11909 | | extra_index += 2; |
| 11910 | | case_val_idx += 2; |
| 11911 | | |
| 11912 | | // Validation above ensured these will succeed. |
| 11913 | | const first_val = sema.resolveConstDefinedValue(&child_block, .unneeded, range_items[0], undefined) catch unreachable; |
| 11914 | | const last_val = sema.resolveConstDefinedValue(&child_block, .unneeded, range_items[1], undefined) catch unreachable; |
| 11915 | | if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and |
| 11916 | | (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty))) |
| 11917 | | { |
| 11918 | | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11919 | | return spa.resolveProngComptime( |
| 11920 | | &child_block, |
| 11921 | | .normal, |
| 11922 | | body, |
| 11923 | | info.capture, |
| 11924 | | .{ .multi_capture = @intCast(multi_i) }, |
| 11925 | | undefined, // case_vals may be undefined for ranges |
| 11926 | | if (info.is_inline) operand else .none, |
| 11927 | | info.has_tag_capture, |
| 11928 | | merges, |
| 11929 | | ); |
| 11930 | | } |
| 11931 | | } |
| 11932 | | |
| 11933 | | extra_index += info.body_len; |
| 11934 | | } |
| 11935 | | } |
| 11936 | | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); |
| 11937 | | if (empty_enum) { |
| 11938 | | return .void_value; |
| 11939 | | } |
| 11940 | | |
| 11941 | | return spa.resolveProngComptime( |
| 11703 | return resolveSwitchComptime( |
| 11704 | sema, |
| 11705 | spa, |
| 11942 | 11706 | &child_block, |
| 11943 | | .special, |
| 11944 | | special.body, |
| 11945 | | special.capture, |
| 11946 | | .special_capture, |
| 11947 | | undefined, // case_vals may be undefined for special prongs |
| 11948 | | if (special.is_inline) operand else .none, |
| 11949 | | special.has_tag_capture, |
| 11950 | | merges, |
| 11707 | operand, |
| 11708 | operand_val, |
| 11709 | operand_ty, |
| 11710 | special, |
| 11711 | case_vals, |
| 11712 | scalar_cases_len, |
| 11713 | multi_cases_len, |
| 11714 | err_set, |
| 11715 | empty_enum, |
| 11951 | 11716 | ); |
| 11952 | 11717 | } |
| 11953 | 11718 | |
| ... | ... | @@ -12593,6 +12358,140 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 12593 | 12358 | return sema.analyzeBlockBody(block, src, &child_block, merges); |
| 12594 | 12359 | } |
| 12595 | 12360 | |
| 12361 | const SpecialProng = struct { |
| 12362 | body: []const Zir.Inst.Index, |
| 12363 | end: usize, |
| 12364 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 12365 | is_inline: bool, |
| 12366 | has_tag_capture: bool, |
| 12367 | }; |
| 12368 | |
| 12369 | fn resolveSwitchComptime( |
| 12370 | sema: *Sema, |
| 12371 | spa: SwitchProngAnalysis, |
| 12372 | child_block: *Block, |
| 12373 | cond_operand: Air.Inst.Ref, |
| 12374 | operand_val: Value, |
| 12375 | operand_ty: Type, |
| 12376 | special: SpecialProng, |
| 12377 | case_vals: std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12378 | scalar_cases_len: u32, |
| 12379 | multi_cases_len: u32, |
| 12380 | err_set: bool, |
| 12381 | empty_enum: bool, |
| 12382 | ) CompileError!Air.Inst.Ref { |
| 12383 | const merges = &child_block.label.?.merges; |
| 12384 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); |
| 12385 | var extra_index: usize = special.end; |
| 12386 | { |
| 12387 | var scalar_i: usize = 0; |
| 12388 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 12389 | extra_index += 1; |
| 12390 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12391 | extra_index += 1; |
| 12392 | const body = sema.code.bodySlice(extra_index, info.body_len); |
| 12393 | extra_index += info.body_len; |
| 12394 | |
| 12395 | const item = case_vals.items[scalar_i]; |
| 12396 | const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item, undefined) catch unreachable; |
| 12397 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 12398 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_operand); |
| 12399 | return spa.resolveProngComptime( |
| 12400 | child_block, |
| 12401 | .normal, |
| 12402 | body, |
| 12403 | info.capture, |
| 12404 | .{ .scalar_capture = @intCast(scalar_i) }, |
| 12405 | &.{item}, |
| 12406 | if (info.is_inline) cond_operand else .none, |
| 12407 | info.has_tag_capture, |
| 12408 | merges, |
| 12409 | ); |
| 12410 | } |
| 12411 | } |
| 12412 | } |
| 12413 | { |
| 12414 | var multi_i: usize = 0; |
| 12415 | var case_val_idx: usize = scalar_cases_len; |
| 12416 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 12417 | const items_len = sema.code.extra[extra_index]; |
| 12418 | extra_index += 1; |
| 12419 | const ranges_len = sema.code.extra[extra_index]; |
| 12420 | extra_index += 1; |
| 12421 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12422 | extra_index += 1 + items_len; |
| 12423 | const body = sema.code.bodySlice(extra_index + 2 * ranges_len, info.body_len); |
| 12424 | |
| 12425 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 12426 | case_val_idx += items_len; |
| 12427 | |
| 12428 | for (items) |item| { |
| 12429 | // Validation above ensured these will succeed. |
| 12430 | const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item, undefined) catch unreachable; |
| 12431 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 12432 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_operand); |
| 12433 | return spa.resolveProngComptime( |
| 12434 | child_block, |
| 12435 | .normal, |
| 12436 | body, |
| 12437 | info.capture, |
| 12438 | .{ .multi_capture = @intCast(multi_i) }, |
| 12439 | items, |
| 12440 | if (info.is_inline) cond_operand else .none, |
| 12441 | info.has_tag_capture, |
| 12442 | merges, |
| 12443 | ); |
| 12444 | } |
| 12445 | } |
| 12446 | |
| 12447 | var range_i: usize = 0; |
| 12448 | while (range_i < ranges_len) : (range_i += 1) { |
| 12449 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 12450 | extra_index += 2; |
| 12451 | case_val_idx += 2; |
| 12452 | |
| 12453 | // Validation above ensured these will succeed. |
| 12454 | const first_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_items[0], undefined) catch unreachable; |
| 12455 | const last_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_items[1], undefined) catch unreachable; |
| 12456 | if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and |
| 12457 | (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty))) |
| 12458 | { |
| 12459 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_operand); |
| 12460 | return spa.resolveProngComptime( |
| 12461 | child_block, |
| 12462 | .normal, |
| 12463 | body, |
| 12464 | info.capture, |
| 12465 | .{ .multi_capture = @intCast(multi_i) }, |
| 12466 | undefined, // case_vals may be undefined for ranges |
| 12467 | if (info.is_inline) cond_operand else .none, |
| 12468 | info.has_tag_capture, |
| 12469 | merges, |
| 12470 | ); |
| 12471 | } |
| 12472 | } |
| 12473 | |
| 12474 | extra_index += info.body_len; |
| 12475 | } |
| 12476 | } |
| 12477 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, special.body, cond_operand); |
| 12478 | if (empty_enum) { |
| 12479 | return .void_value; |
| 12480 | } |
| 12481 | |
| 12482 | return spa.resolveProngComptime( |
| 12483 | child_block, |
| 12484 | .special, |
| 12485 | special.body, |
| 12486 | special.capture, |
| 12487 | .special_capture, |
| 12488 | undefined, // case_vals may be undefined for special prongs |
| 12489 | if (special.is_inline) cond_operand else .none, |
| 12490 | special.has_tag_capture, |
| 12491 | merges, |
| 12492 | ); |
| 12493 | } |
| 12494 | |
| 12596 | 12495 | const RangeSetUnhandledIterator = struct { |
| 12597 | 12496 | mod: *Module, |
| 12598 | 12497 | cur: ?InternPool.Index, |
| ... | ... | @@ -12710,6 +12609,168 @@ fn resolveSwitchItemVal( |
| 12710 | 12609 | return .{ .ref = new_item, .val = val.toIntern() }; |
| 12711 | 12610 | } |
| 12712 | 12611 | |
| 12612 | fn validateErrSetSwitch( |
| 12613 | sema: *Sema, |
| 12614 | block: *Block, |
| 12615 | seen_errors: *SwitchErrorSet, |
| 12616 | case_vals: *std.ArrayListUnmanaged(Air.Inst.Ref), |
| 12617 | operand_ty: Type, |
| 12618 | inst_data: std.meta.FieldType(Zir.Inst.Data, .pl_node), |
| 12619 | scalar_cases_len: u32, |
| 12620 | multi_cases_len: u32, |
| 12621 | else_case: struct { body: []const Zir.Inst.Index, end: usize, src: LazySrcLoc }, |
| 12622 | has_else: bool, |
| 12623 | ) CompileError!?Type { |
| 12624 | const gpa = sema.gpa; |
| 12625 | const mod = sema.mod; |
| 12626 | const ip = &mod.intern_pool; |
| 12627 | |
| 12628 | const src_node_offset = inst_data.src_node; |
| 12629 | const src = inst_data.src(); |
| 12630 | |
| 12631 | var extra_index: usize = else_case.end; |
| 12632 | { |
| 12633 | var scalar_i: u32 = 0; |
| 12634 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 12635 | const item_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| 12636 | extra_index += 1; |
| 12637 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12638 | extra_index += 1 + info.body_len; |
| 12639 | |
| 12640 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 12641 | block, |
| 12642 | seen_errors, |
| 12643 | item_ref, |
| 12644 | operand_ty, |
| 12645 | src_node_offset, |
| 12646 | .{ .scalar = scalar_i }, |
| 12647 | )); |
| 12648 | } |
| 12649 | } |
| 12650 | { |
| 12651 | var multi_i: u32 = 0; |
| 12652 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 12653 | const items_len = sema.code.extra[extra_index]; |
| 12654 | extra_index += 1; |
| 12655 | const ranges_len = sema.code.extra[extra_index]; |
| 12656 | extra_index += 1; |
| 12657 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); |
| 12658 | extra_index += 1; |
| 12659 | const items = sema.code.refSlice(extra_index, items_len); |
| 12660 | extra_index += items_len + info.body_len; |
| 12661 | |
| 12662 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 12663 | for (items, 0..) |item_ref, item_i| { |
| 12664 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 12665 | block, |
| 12666 | seen_errors, |
| 12667 | item_ref, |
| 12668 | operand_ty, |
| 12669 | src_node_offset, |
| 12670 | .{ .multi = .{ .prong = multi_i, .item = @intCast(item_i) } }, |
| 12671 | )); |
| 12672 | } |
| 12673 | |
| 12674 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| 12675 | } |
| 12676 | } |
| 12677 | |
| 12678 | switch (try sema.resolveInferredErrorSetTy(block, src, operand_ty.toIntern())) { |
| 12679 | .anyerror_type => { |
| 12680 | if (!has_else) { |
| 12681 | return sema.fail( |
| 12682 | block, |
| 12683 | src, |
| 12684 | "else prong required when switching on type 'anyerror'", |
| 12685 | .{}, |
| 12686 | ); |
| 12687 | } |
| 12688 | return Type.anyerror; |
| 12689 | }, |
| 12690 | else => |err_set_ty_index| else_validation: { |
| 12691 | const error_names = ip.indexToKey(err_set_ty_index).error_set_type.names; |
| 12692 | var maybe_msg: ?*Module.ErrorMsg = null; |
| 12693 | errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); |
| 12694 | |
| 12695 | for (error_names.get(ip)) |error_name| { |
| 12696 | if (!seen_errors.contains(error_name) and !has_else) { |
| 12697 | const msg = maybe_msg orelse blk: { |
| 12698 | maybe_msg = try sema.errMsg( |
| 12699 | block, |
| 12700 | src, |
| 12701 | "switch must handle all possibilities", |
| 12702 | .{}, |
| 12703 | ); |
| 12704 | break :blk maybe_msg.?; |
| 12705 | }; |
| 12706 | |
| 12707 | try sema.errNote( |
| 12708 | block, |
| 12709 | src, |
| 12710 | msg, |
| 12711 | "unhandled error value: 'error.{}'", |
| 12712 | .{error_name.fmt(ip)}, |
| 12713 | ); |
| 12714 | } |
| 12715 | } |
| 12716 | |
| 12717 | if (maybe_msg) |msg| { |
| 12718 | maybe_msg = null; |
| 12719 | try sema.addDeclaredHereNote(msg, operand_ty); |
| 12720 | return sema.failWithOwnedErrorMsg(block, msg); |
| 12721 | } |
| 12722 | |
| 12723 | if (has_else and seen_errors.count() == error_names.len) { |
| 12724 | // In order to enable common patterns for generic code allow simple else bodies |
| 12725 | // else => unreachable, |
| 12726 | // else => return, |
| 12727 | // else => |e| return e, |
| 12728 | // even if all the possible errors were already handled. |
| 12729 | const tags = sema.code.instructions.items(.tag); |
| 12730 | for (else_case.body) |else_inst| switch (tags[@intFromEnum(else_inst)]) { |
| 12731 | .dbg_block_begin, |
| 12732 | .dbg_block_end, |
| 12733 | .dbg_stmt, |
| 12734 | .dbg_var_val, |
| 12735 | .ret_type, |
| 12736 | .as_node, |
| 12737 | .ret_node, |
| 12738 | .@"unreachable", |
| 12739 | .@"defer", |
| 12740 | .defer_err_code, |
| 12741 | .err_union_code, |
| 12742 | .ret_err_value_code, |
| 12743 | .restore_err_ret_index, |
| 12744 | .is_non_err, |
| 12745 | .ret_is_non_err, |
| 12746 | .condbr, |
| 12747 | => {}, |
| 12748 | else => break, |
| 12749 | } else break :else_validation; |
| 12750 | |
| 12751 | return sema.fail( |
| 12752 | block, |
| 12753 | else_case.src, |
| 12754 | "unreachable else prong; all cases already handled", |
| 12755 | .{}, |
| 12756 | ); |
| 12757 | } |
| 12758 | |
| 12759 | var names: InferredErrorSet.NameMap = .{}; |
| 12760 | try names.ensureUnusedCapacity(sema.arena, error_names.len); |
| 12761 | for (error_names.get(ip)) |error_name| { |
| 12762 | if (seen_errors.contains(error_name)) continue; |
| 12763 | |
| 12764 | names.putAssumeCapacityNoClobber(error_name, {}); |
| 12765 | } |
| 12766 | // No need to keep the hash map metadata correct; here we |
| 12767 | // extract the (sorted) keys only. |
| 12768 | return try mod.errorSetFromUnsortedNames(names.keys()); |
| 12769 | }, |
| 12770 | } |
| 12771 | return null; |
| 12772 | } |
| 12773 | |
| 12713 | 12774 | fn validateSwitchRange( |
| 12714 | 12775 | sema: *Sema, |
| 12715 | 12776 | block: *Block, |