| ... | @@ -11212,16 +11212,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r | ... | @@ -11212,16 +11212,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11212 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); | 11212 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 11213 | defer case_vals.deinit(gpa); | 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 | const special_prong = extra.data.bits.specialProng(); | 11215 | const special_prong = extra.data.bits.specialProng(); |
| 11224 | const special: Special = switch (special_prong) { | 11216 | const special: SpecialProng = switch (special_prong) { |
| 11225 | .none => .{ | 11217 | .none => .{ |
| 11226 | .body = &.{}, | 11218 | .body = &.{}, |
| 11227 | .end = header_extra_index, | 11219 | .end = header_extra_index, |
| ... | @@ -11401,150 +11393,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r | ... | @@ -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 => { | 11396 | .ErrorSet => else_error_ty = try validateErrSetSwitch( |
| 11405 | var extra_index: usize = special.end; | 11397 | sema, |
| 11406 | { | 11398 | block, |
| 11407 | var scalar_i: u32 = 0; | 11399 | &seen_errors, |
| 11408 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11400 | &case_vals, |
| 11409 | const item_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | 11401 | operand_ty, |
| 11410 | extra_index += 1; | 11402 | inst_data, |
| 11411 | const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[extra_index]); | 11403 | scalar_cases_len, |
| 11412 | extra_index += 1 + info.body_len; | 11404 | multi_cases_len, |
| 11413 | | 11405 | .{ .body = special.body, .end = special.end, .src = special_prong_src }, |
| 11414 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( | 11406 | special_prong == .@"else", |
| 11415 | block, | 11407 | ), |
| 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 | }, | | |
| 11548 | .Int, .ComptimeInt => { | 11408 | .Int, .ComptimeInt => { |
| 11549 | var extra_index: usize = special.end; | 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,114 +11700,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 11840 | defer merges.deinit(gpa); | 11700 | defer merges.deinit(gpa); |
| 11841 | | 11701 | |
| 11842 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { | 11702 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { |
| 11843 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); | 11703 | return resolveSwitchComptime( |
| 11844 | var extra_index: usize = special.end; | 11704 | sema, |
| 11845 | { | 11705 | spa, |
| 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( | | |
| 11942 | &child_block, | 11706 | &child_block, |
| 11943 | .special, | 11707 | operand, |
| 11944 | special.body, | 11708 | operand_val, |
| 11945 | special.capture, | 11709 | operand_ty, |
| 11946 | .special_capture, | 11710 | special, |
| 11947 | undefined, // case_vals may be undefined for special prongs | 11711 | case_vals, |
| 11948 | if (special.is_inline) operand else .none, | 11712 | scalar_cases_len, |
| 11949 | special.has_tag_capture, | 11713 | multi_cases_len, |
| 11950 | merges, | 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,6 +12358,140 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r |
| 12593 | return sema.analyzeBlockBody(block, src, &child_block, merges); | 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 | const RangeSetUnhandledIterator = struct { | 12495 | const RangeSetUnhandledIterator = struct { |
| 12597 | mod: *Module, | 12496 | mod: *Module, |
| 12598 | cur: ?InternPool.Index, | 12497 | cur: ?InternPool.Index, |
| ... | @@ -12710,6 +12609,168 @@ fn resolveSwitchItemVal( | ... | @@ -12710,6 +12609,168 @@ fn resolveSwitchItemVal( |
| 12710 | return .{ .ref = new_item, .val = val.toIntern() }; | 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 | fn validateSwitchRange( | 12774 | fn validateSwitchRange( |
| 12714 | sema: *Sema, | 12775 | sema: *Sema, |
| 12715 | block: *Block, | 12776 | block: *Block, |