| author | |
| committer | |
| log | ed1268d0e63d3af144a262a1fa41b8e69ab3073b |
| tree | 3f5e99ac159431271bc5c9029b6d8b9f8ee961b2 |
| parent | 8ec4c5cb137d9a93c35df3488408c44056c586b4 |
| signature |
5 files changed, 188 insertions(+), 390 deletions(-)
lib/std/zig/AstGen.zig+19-69| ... | ... | @@ -7267,11 +7267,7 @@ fn switchExpr( |
| 7267 | 7267 | var total_items_len: usize = 0; |
| 7268 | 7268 | var total_ranges_len: usize = 0; |
| 7269 | 7269 | var else_case_node: Ast.Node.OptionalIndex = .none; |
| 7270 | var else_src: ?Ast.TokenIndex = null; | |
| 7271 | var under_case_node: Ast.Node.OptionalIndex = .none; | |
| 7272 | 7270 | var underscore_node: Ast.Node.OptionalIndex = .none; |
| 7273 | var underscore_src: ?Ast.TokenIndex = null; | |
| 7274 | var under_is_bare = false; | |
| 7275 | 7271 | for (case_nodes) |case_node| { |
| 7276 | 7272 | const case = tree.fullSwitchCase(case_node).?; |
| 7277 | 7273 | if (case.payload_token) |payload_token| { |
| ... | ... | @@ -7304,22 +7300,21 @@ fn switchExpr( |
| 7304 | 7300 | |
| 7305 | 7301 | // Check for else prong. |
| 7306 | 7302 | if (case.ast.values.len == 0) { |
| 7307 | const case_src = case.ast.arrow_token - 1; | |
| 7308 | if (else_src) |src| { | |
| 7303 | if (else_case_node.unwrap()) |prev_case_node| { | |
| 7304 | const prev_else_tok = tree.fullSwitchCase(prev_case_node).?.ast.arrow_token - 1; | |
| 7305 | const else_tok = case.ast.arrow_token - 1; | |
| 7309 | 7306 | return astgen.failTokNotes( |
| 7310 | case_src, | |
| 7307 | else_tok, | |
| 7311 | 7308 | "multiple else prongs in switch expression", |
| 7312 | 7309 | .{}, |
| 7313 | &.{try astgen.errNoteTok(src, "previous else prong here", .{})}, | |
| 7310 | &.{try astgen.errNoteTok(prev_else_tok, "previous else prong here", .{})}, | |
| 7314 | 7311 | ); |
| 7315 | 7312 | } |
| 7316 | 7313 | else_case_node = case_node.toOptional(); |
| 7317 | else_src = case_src; | |
| 7318 | 7314 | continue; |
| 7319 | 7315 | } |
| 7320 | 7316 | |
| 7321 | 7317 | // Check for '_' prong and ranges. |
| 7322 | var case_has_underscore = false; | |
| 7323 | 7318 | var case_has_ranges = false; |
| 7324 | 7319 | for (case.ast.values) |val| { |
| 7325 | 7320 | switch (tree.nodeTag(val)) { |
| ... | ... | @@ -7329,10 +7324,10 @@ fn switchExpr( |
| 7329 | 7324 | }, |
| 7330 | 7325 | .string_literal => return astgen.failNode(val, "cannot switch on strings", .{}), |
| 7331 | 7326 | else => |tag| { |
| 7327 | total_items_len += 1; | |
| 7332 | 7328 | if (tag == .identifier and |
| 7333 | 7329 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) |
| 7334 | 7330 | { |
| 7335 | const val_src = tree.nodeMainToken(val); | |
| 7336 | 7331 | if (is_err_switch) { |
| 7337 | 7332 | const case_src = case.ast.arrow_token - 1; |
| 7338 | 7333 | return astgen.failTokNotes( |
| ... | ... | @@ -7348,30 +7343,24 @@ fn switchExpr( |
| 7348 | 7343 | }, |
| 7349 | 7344 | ); |
| 7350 | 7345 | } |
| 7351 | if (underscore_src) |src| { | |
| 7352 | return astgen.failTokNotes( | |
| 7353 | val_src, | |
| 7346 | if (underscore_node.unwrap()) |prev_src| { | |
| 7347 | return astgen.failNodeNotes( | |
| 7348 | val, | |
| 7354 | 7349 | "multiple '_' prongs in switch expression", |
| 7355 | 7350 | .{}, |
| 7356 | &.{try astgen.errNoteTok(src, "previous '_' prong here", .{})}, | |
| 7351 | &.{try astgen.errNoteNode(prev_src, "previous '_' prong here", .{})}, | |
| 7357 | 7352 | ); |
| 7358 | 7353 | } |
| 7359 | 7354 | if (case.inline_token != null) { |
| 7360 | return astgen.failTok(val_src, "cannot inline '_' prong", .{}); | |
| 7355 | return astgen.failNode(val, "cannot inline '_' prong", .{}); | |
| 7361 | 7356 | } |
| 7362 | under_case_node = case_node.toOptional(); | |
| 7363 | underscore_src = val_src; | |
| 7364 | 7357 | underscore_node = val.toOptional(); |
| 7365 | under_is_bare = case.ast.values.len == 1; | |
| 7366 | case_has_underscore = true; | |
| 7367 | } else { | |
| 7368 | total_items_len += 1; | |
| 7369 | 7358 | } |
| 7370 | 7359 | }, |
| 7371 | 7360 | } |
| 7372 | 7361 | } |
| 7373 | 7362 | |
| 7374 | const case_len = case.ast.values.len - @intFromBool(case_has_underscore); | |
| 7363 | const case_len = case.ast.values.len; | |
| 7375 | 7364 | if (case_len == 1 and !case_has_ranges) { |
| 7376 | 7365 | scalar_cases_len += 1; |
| 7377 | 7366 | } else if (case_len >= 1) { |
| ... | ... | @@ -7379,9 +7368,8 @@ fn switchExpr( |
| 7379 | 7368 | } |
| 7380 | 7369 | } |
| 7381 | 7370 | |
| 7382 | const has_else = else_src != null; | |
| 7383 | const has_under = underscore_src != null; | |
| 7384 | if (under_is_bare) assert(has_under); // make sure that the former implies the latter | |
| 7371 | const has_else = else_case_node != .none; | |
| 7372 | const has_under = underscore_node != .none; | |
| 7385 | 7373 | if (is_err_switch) assert(!has_under); // should have failed by now |
| 7386 | 7374 | const any_ranges = total_ranges_len > 0; |
| 7387 | 7375 | |
| ... | ... | @@ -7430,10 +7418,8 @@ fn switchExpr( |
| 7430 | 7418 | |
| 7431 | 7419 | var non_err_prong_body_start: u32 = undefined; |
| 7432 | 7420 | var else_prong_body_start: u32 = undefined; |
| 7433 | var bare_under_prong_body_start: u32 = undefined; | |
| 7434 | 7421 | var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined; |
| 7435 | 7422 | var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined; |
| 7436 | var under_extra: u32 = undefined; | |
| 7437 | 7423 | |
| 7438 | 7424 | var block_scope = parent_gz.makeSubBlock(scope); |
| 7439 | 7425 | // block_scope not used for collecting instructions |
| ... | ... | @@ -7688,7 +7674,6 @@ fn switchExpr( |
| 7688 | 7674 | for (case_nodes) |case_node| { |
| 7689 | 7675 | const case = tree.fullSwitchCase(case_node).?; |
| 7690 | 7676 | |
| 7691 | const case_has_under = case_node.toOptional() == under_case_node; | |
| 7692 | 7677 | const ranges_len: u32 = if (any_ranges) blk: { |
| 7693 | 7678 | var ranges_len: u32 = 0; |
| 7694 | 7679 | for (case.ast.values) |value| { |
| ... | ... | @@ -7696,14 +7681,13 @@ fn switchExpr( |
| 7696 | 7681 | } |
| 7697 | 7682 | break :blk ranges_len; |
| 7698 | 7683 | } else 0; |
| 7699 | const items_len: u32 = @intCast(case.ast.values.len - ranges_len - @intFromBool(case_has_under)); | |
| 7684 | const items_len: u32 = @intCast(case.ast.values.len - ranges_len); | |
| 7700 | 7685 | const is_multi_case = items_len > 1 or ranges_len > 0; |
| 7701 | 7686 | |
| 7702 | 7687 | // item/range bodies in order of occurence |
| 7703 | 7688 | var item_i: usize = 0; |
| 7704 | 7689 | var range_i: usize = 0; |
| 7705 | 7690 | for (case.ast.values) |value| { |
| 7706 | if (value.toOptional() == underscore_node) continue; | |
| 7707 | 7691 | const is_range = tree.nodeTag(value) == .switch_range; |
| 7708 | 7692 | const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined; |
| 7709 | 7693 | const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value}; |
| ... | ... | @@ -7722,16 +7706,9 @@ fn switchExpr( |
| 7722 | 7706 | const str_index = try astgen.identAsString(ident_token); |
| 7723 | 7707 | break :blk .wrap(.{ .error_value = str_index }); |
| 7724 | 7708 | }, |
| 7725 | .number_literal => { | |
| 7726 | // We don't actually need a final result type for number | |
| 7727 | // literals, they can just be turned into `comptime_int` | |
| 7728 | // or `comptime_float` as usual and then be coerced to | |
| 7729 | // the correct type later during semantic analysis. | |
| 7730 | assert(scratch_scope.instructions_top == GenZir.unstacked_top); // important! we emit into `parent_gz` which `scratch_scope` is stacked on top of | |
| 7731 | const zir_ref = try comptimeExpr(parent_gz, scope, .{ .rl = .none }, item, .switch_item); | |
| 7732 | break :blk .wrap(.{ .number_literal = zir_ref }); | |
| 7733 | }, | |
| 7734 | else => { | |
| 7709 | else => if (value.toOptional() == underscore_node) { | |
| 7710 | break :blk .wrap(.under); | |
| 7711 | } else { | |
| 7735 | 7712 | scratch_scope.instructions_top = parent_gz.instructions.items.len; |
| 7736 | 7713 | defer scratch_scope.unstack(); |
| 7737 | 7714 | const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal); |
| ... | ... | @@ -7957,25 +7934,6 @@ fn switchExpr( |
| 7957 | 7934 | break :prong_body; |
| 7958 | 7935 | } |
| 7959 | 7936 | |
| 7960 | if (case_has_under) { | |
| 7961 | // We're either writing under_prong_info or under_index here. | |
| 7962 | if (under_is_bare) { | |
| 7963 | assert(case.ast.values.len == 1); // only `_` | |
| 7964 | const bare_under_info: Zir.Inst.SwitchBlock.ProngInfo.BareUnder = .{ | |
| 7965 | .body_len = @intCast(body_len), | |
| 7966 | .capture = capture, | |
| 7967 | .has_tag_capture = has_tag_capture, | |
| 7968 | }; | |
| 7969 | under_extra = @bitCast(bare_under_info); | |
| 7970 | bare_under_prong_body_start = body_start; | |
| 7971 | break :prong_body; | |
| 7972 | } else if (is_multi_case) { | |
| 7973 | under_extra = scalar_cases_len + multi_case_index; | |
| 7974 | } else { | |
| 7975 | under_extra = scalar_case_index; | |
| 7976 | } | |
| 7977 | } | |
| 7978 | ||
| 7979 | 7937 | // We allow prongs with error items which are not inside the error set |
| 7980 | 7938 | // being switched on if their body is `=> comptime unreachable,`. |
| 7981 | 7939 | const is_comptime_unreach = comptime_unreach: { |
| ... | ... | @@ -8003,7 +7961,7 @@ fn switchExpr( |
| 8003 | 7961 | } |
| 8004 | 7962 | } |
| 8005 | 7963 | } |
| 8006 | assert(scalar_case_index + multi_case_index + @intFromBool(has_else) + @intFromBool(under_is_bare) == case_nodes.len); | |
| 7964 | assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len); | |
| 8007 | 7965 | assert(multi_items_infos_start + multi_item_offset == bodies_start); |
| 8008 | 7966 | |
| 8009 | 7967 | if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) { |
| ... | ... | @@ -8024,7 +7982,6 @@ fn switchExpr( |
| 8024 | 7982 | @intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset |
| 8025 | 7983 | @intFromBool(needs_non_err_handling) + // non_err_info |
| 8026 | 7984 | @intFromBool(has_else) + // else_info |
| 8027 | @intFromBool(has_under) + // under_prong_info or under_index | |
| 8028 | 7985 | payloads.items.len - body_table_end); // item infos and bodies |
| 8029 | 7986 | |
| 8030 | 7987 | // singular pieces of data |
| ... | ... | @@ -8035,7 +7992,6 @@ fn switchExpr( |
| 8035 | 7992 | .any_ranges = any_ranges, |
| 8036 | 7993 | .has_else = has_else, |
| 8037 | 7994 | .has_under = has_under, |
| 8038 | .under_is_bare = under_is_bare, | |
| 8039 | 7995 | .has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue, |
| 8040 | 7996 | .any_maybe_runtime_capture = any_maybe_runtime_capture, |
| 8041 | 7997 | .payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder, |
| ... | ... | @@ -8054,7 +8010,6 @@ fn switchExpr( |
| 8054 | 8010 | astgen.extra.appendAssumeCapacity(@bitCast(non_err_info)); |
| 8055 | 8011 | } |
| 8056 | 8012 | if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info)); |
| 8057 | if (has_under) astgen.extra.appendAssumeCapacity(under_extra); | |
| 8058 | 8013 | |
| 8059 | 8014 | const extra_payloads_start = astgen.extra.items.len; |
| 8060 | 8015 | |
| ... | ... | @@ -8070,11 +8025,6 @@ fn switchExpr( |
| 8070 | 8025 | const body = payloads.items[else_prong_body_start..][0..else_info.body_len]; |
| 8071 | 8026 | astgen.extra.appendSliceAssumeCapacity(body); |
| 8072 | 8027 | } |
| 8073 | if (under_is_bare) { | |
| 8074 | const under_prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(under_extra); | |
| 8075 | const body = payloads.items[bare_under_prong_body_start..][0..under_prong_info.body_len]; | |
| 8076 | astgen.extra.appendSliceAssumeCapacity(body); | |
| 8077 | } | |
| 8078 | 8028 | for (0..scalar_cases_len) |scalar_i| { |
| 8079 | 8029 | const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]); |
| 8080 | 8030 | const item_body_start = payloads.items[scalar_body_table + scalar_i]; |
lib/std/zig/Zir.zig+19-104| ... | ... | @@ -3303,34 +3303,25 @@ pub const Inst = struct { |
| 3303 | 3303 | /// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union. |
| 3304 | 3304 | /// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union. |
| 3305 | 3305 | /// 5. else_info: ProngInfo.Else, // If has_else is set. |
| 3306 | /// 6. under_info: ProngInfo.Under, // If has_under is set and | |
| 3307 | /// // under_is_bare is set. | |
| 3308 | /// 7. under_index: u32, // If has_under is set and | |
| 3309 | /// // under_is_bare is *not* set. | |
| 3310 | /// // Index into switch cases. | |
| 3311 | /// 8. scalar_prong_info: ProngInfo, // for every scalar_cases_len | |
| 3312 | /// 9. multi_prong_info: ProngInfo, // for every multi_cases_len | |
| 3313 | /// 10. multi_case_items_len: u32, // for every multi_cases_len | |
| 3314 | /// 11. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len | |
| 3315 | /// 12. scalar_item_info: ItemInfo, // for every scalar_cases_len | |
| 3316 | /// 13. multi_items_info: { // for every multi_cases_len | |
| 3306 | /// 6. scalar_prong_info: ProngInfo, // for every scalar_cases_len | |
| 3307 | /// 7. multi_prong_info: ProngInfo, // for every multi_cases_len | |
| 3308 | /// 8. multi_case_items_len: u32, // for every multi_cases_len | |
| 3309 | /// 9. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len | |
| 3310 | /// 10. scalar_item_info: ItemInfo, // for every scalar_cases_len | |
| 3311 | /// 11. multi_items_info: { // for every multi_cases_len | |
| 3317 | 3312 | /// item_info: ItemInfo, // for each multi_case_items_len |
| 3318 | 3313 | /// range_items_info: { // for each multi_case_ranges_len |
| 3319 | 3314 | /// first_info: ItemInfo, |
| 3320 | 3315 | /// last_info: ItemInfo, |
| 3321 | 3316 | /// } |
| 3322 | 3317 | /// } |
| 3323 | /// 14. non_err_body { | |
| 3318 | /// 12. non_err_body { | |
| 3324 | 3319 | /// body_inst: Index // for every non_err_info.body_len |
| 3325 | 3320 | /// } |
| 3326 | /// 15. else_body: { // If has_else is set. | |
| 3321 | /// 13. else_body: { // If has_else is set. | |
| 3327 | 3322 | /// body_inst: Inst.Index, // for every else_info.body_len |
| 3328 | 3323 | /// } |
| 3329 | /// 16. under_body: { // If has_under is set and | |
| 3330 | /// // under_is_bare is set. | |
| 3331 | /// body_inst: Inst.Index, // for every under_info.body_len | |
| 3332 | /// } | |
| 3333 | /// 17. scalar_bodies: { // for every scalar_cases_len | |
| 3324 | /// 14. scalar_bodies: { // for every scalar_cases_len | |
| 3334 | 3325 | /// prong_body: { // for each body_len in scalar_prong_info |
| 3335 | 3326 | /// body_inst: Inst.Index, // for every body_len |
| 3336 | 3327 | /// } |
| ... | ... | @@ -3338,7 +3329,7 @@ pub const Inst = struct { |
| 3338 | 3329 | /// body_inst: Inst.Index, // for every body_len |
| 3339 | 3330 | /// } |
| 3340 | 3331 | /// } |
| 3341 | /// 18. multi_bodies: { // for each multi_items_info | |
| 3332 | /// 15. multi_bodies: { // for each multi_items_info | |
| 3342 | 3333 | /// prong_body: { |
| 3343 | 3334 | /// body_inst: Inst.Index, // for each multi_prong_info.body_len |
| 3344 | 3335 | /// } |
| ... | ... | @@ -3363,8 +3354,6 @@ pub const Inst = struct { |
| 3363 | 3354 | any_ranges: bool, |
| 3364 | 3355 | has_else: bool, |
| 3365 | 3356 | has_under: bool, |
| 3366 | /// Only valid if `has_under` is also set. | |
| 3367 | under_is_bare: bool, | |
| 3368 | 3357 | /// If true, at least one prong contains a `continue`. |
| 3369 | 3358 | /// Only valid if `has_label` is set. |
| 3370 | 3359 | has_continue: bool, |
| ... | ... | @@ -3377,7 +3366,7 @@ pub const Inst = struct { |
| 3377 | 3366 | // NOTE maybe don't steal any more bits from poor `scalar_cases_len` |
| 3378 | 3367 | // and split `Bits` into two parts instead, `raw_operand` surely |
| 3379 | 3368 | // wouldn't mind donating a couple of bits for that purpose... |
| 3380 | pub const ScalarCasesLen = u23; | |
| 3369 | pub const ScalarCasesLen = u24; | |
| 3381 | 3370 | }; |
| 3382 | 3371 | |
| 3383 | 3372 | pub const ProngInfo = packed struct(u32) { |
| ... | ... | @@ -3406,12 +3395,6 @@ pub const Inst = struct { |
| 3406 | 3395 | has_tag_capture: bool, |
| 3407 | 3396 | is_simple_noreturn: bool, |
| 3408 | 3397 | }; |
| 3409 | ||
| 3410 | pub const BareUnder = packed struct(u32) { | |
| 3411 | body_len: u29, | |
| 3412 | capture: ProngInfo.Capture, | |
| 3413 | has_tag_capture: bool, | |
| 3414 | }; | |
| 3415 | 3398 | }; |
| 3416 | 3399 | |
| 3417 | 3400 | pub const ItemInfo = packed struct(u32) { |
| ... | ... | @@ -3421,23 +3404,23 @@ pub const Inst = struct { |
| 3421 | 3404 | pub const Kind = enum(u2) { |
| 3422 | 3405 | enum_literal, |
| 3423 | 3406 | error_value, |
| 3424 | number_literal, | |
| 3425 | 3407 | body_len, |
| 3408 | under, | |
| 3426 | 3409 | }; |
| 3427 | 3410 | |
| 3428 | 3411 | pub const Unwrapped = union(ItemInfo.Kind) { |
| 3429 | 3412 | enum_literal: Zir.NullTerminatedString, |
| 3430 | 3413 | error_value: Zir.NullTerminatedString, |
| 3431 | number_literal: Inst.Ref, | |
| 3432 | 3414 | body_len: u32, |
| 3415 | under, | |
| 3433 | 3416 | }; |
| 3434 | 3417 | |
| 3435 | 3418 | pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo { |
| 3436 | 3419 | const data_uncasted: u32 = switch (unwrapped) { |
| 3437 | 3420 | .enum_literal => |str_index| @intFromEnum(str_index), |
| 3438 | 3421 | .error_value => |str_index| @intFromEnum(str_index), |
| 3439 | .number_literal => |zir_ref| @intFromEnum(zir_ref), | |
| 3440 | 3422 | .body_len => |body_len| body_len, |
| 3423 | .under => 0, | |
| 3441 | 3424 | }; |
| 3442 | 3425 | return .{ .kind = unwrapped, .data = @intCast(data_uncasted) }; |
| 3443 | 3426 | } |
| ... | ... | @@ -3446,8 +3429,8 @@ pub const Inst = struct { |
| 3446 | 3429 | return switch (item_info.kind) { |
| 3447 | 3430 | .enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) }, |
| 3448 | 3431 | .error_value => .{ .error_value = @enumFromInt(item_info.data) }, |
| 3449 | .number_literal => .{ .number_literal = @enumFromInt(item_info.data) }, | |
| 3450 | 3432 | .body_len => .{ .body_len = item_info.data }, |
| 3433 | .under => .under, | |
| 3451 | 3434 | }; |
| 3452 | 3435 | } |
| 3453 | 3436 | |
| ... | ... | @@ -4818,9 +4801,6 @@ fn findTrackableInner( |
| 4818 | 4801 | if (zir_switch.else_case) |else_case| { |
| 4819 | 4802 | try zir.findTrackableBody(gpa, contents, defers, else_case.body); |
| 4820 | 4803 | } |
| 4821 | if (zir_switch.under_case.resolve()) |under_case| { | |
| 4822 | try zir.findTrackableBody(gpa, contents, defers, under_case.body); | |
| 4823 | } | |
| 4824 | 4804 | var extra_index = zir_switch.end; |
| 4825 | 4805 | var case_it = zir_switch.iterateCases(); |
| 4826 | 4806 | while (case_it.next()) |case| { |
| ... | ... | @@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5268 | 5248 | extra_index += 1; |
| 5269 | 5249 | break :else_info else_info; |
| 5270 | 5250 | } else undefined; |
| 5271 | const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = if (bits.has_under and bits.under_is_bare) bare_under_info: { | |
| 5272 | const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = @bitCast(zir.extra[extra_index]); | |
| 5273 | extra_index += 1; | |
| 5274 | break :bare_under_info bare_under_info; | |
| 5275 | } else undefined; | |
| 5276 | const under_index: u32 = if (bits.has_under and !bits.under_is_bare) under_index: { | |
| 5277 | const under_index = zir.extra[extra_index]; | |
| 5278 | extra_index += 1; | |
| 5279 | break :under_index under_index; | |
| 5280 | } else undefined; | |
| 5281 | 5251 | const scalar_cases_len: u32 = bits.scalar_cases_len; |
| 5282 | 5252 | const prong_infos: []const Inst.SwitchBlock.ProngInfo = |
| 5283 | 5253 | @ptrCast(zir.extra[extra_index..][0 .. scalar_cases_len + multi_cases_len]); |
| ... | ... | @@ -5320,20 +5290,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5320 | 5290 | .is_simple_noreturn = else_info.is_simple_noreturn, |
| 5321 | 5291 | }; |
| 5322 | 5292 | } else null; |
| 5323 | const under_case: UnwrappedSwitchBlock.Case.Under = if (bits.has_under) under_case: { | |
| 5324 | if (bits.under_is_bare) { | |
| 5325 | const body = zir.bodySlice(extra_index, bare_under_info.body_len); | |
| 5326 | extra_index += body.len; | |
| 5327 | break :under_case .{ .bare = .{ | |
| 5328 | .index = .bare_under, | |
| 5329 | .body = body, | |
| 5330 | .capture = bare_under_info.capture, | |
| 5331 | .has_tag_capture = bare_under_info.has_tag_capture, | |
| 5332 | } }; | |
| 5333 | } else { | |
| 5334 | break :under_case .{ .index = under_index }; | |
| 5335 | } | |
| 5336 | } else .none; | |
| 5337 | 5293 | return .{ |
| 5338 | 5294 | .main_operand = extra.data.raw_operand, |
| 5339 | 5295 | .switch_src_node_offset = inst_data.src_node, |
| ... | ... | @@ -5344,7 +5300,7 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5344 | 5300 | .any_maybe_runtime_capture = bits.any_maybe_runtime_capture, |
| 5345 | 5301 | .non_err_case = non_err_case, |
| 5346 | 5302 | .else_case = else_case, |
| 5347 | .under_case = under_case, | |
| 5303 | .has_under = bits.has_under, | |
| 5348 | 5304 | .prong_infos = prong_infos, |
| 5349 | 5305 | .multi_case_items_lens = multi_case_items_lens, |
| 5350 | 5306 | .multi_case_ranges_lens = multi_case_ranges_lens, |
| ... | ... | @@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct { |
| 5377 | 5333 | any_maybe_runtime_capture: bool, |
| 5378 | 5334 | non_err_case: ?Case.NonErr, |
| 5379 | 5335 | else_case: ?Case.Else, |
| 5380 | under_case: Case.Under, | |
| 5336 | has_under: bool, | |
| 5381 | 5337 | // Refer to doc comment and `iterateCases` to access everything below correctly. |
| 5382 | 5338 | prong_infos: []const Inst.SwitchBlock.ProngInfo, |
| 5383 | 5339 | multi_case_items_lens: []const u32, |
| ... | ... | @@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct { |
| 5411 | 5367 | item_infos: []const Inst.SwitchBlock.ItemInfo, |
| 5412 | 5368 | range_infos: []const [2]Inst.SwitchBlock.ItemInfo, |
| 5413 | 5369 | |
| 5414 | pub fn isUnder(case: *const Case) bool { | |
| 5415 | return case.index.is_under; | |
| 5416 | } | |
| 5417 | ||
| 5418 | 5370 | pub const Index = packed struct(u32) { |
| 5419 | 5371 | kind: enum(u1) { scalar, multi }, |
| 5420 | is_under: bool, | |
| 5421 | value: u30, | |
| 5372 | value: u31, | |
| 5422 | 5373 | |
| 5423 | 5374 | pub const @"else": Case.Index = .{ |
| 5424 | 5375 | .kind = .scalar, |
| 5425 | .is_under = false, | |
| 5426 | .value = std.math.maxInt(u30), | |
| 5427 | }; | |
| 5428 | ||
| 5429 | pub const bare_under: Case.Index = .{ | |
| 5430 | .kind = .scalar, | |
| 5431 | .is_under = true, | |
| 5432 | .value = std.math.maxInt(u30), | |
| 5376 | .value = std.math.maxInt(u31), | |
| 5433 | 5377 | }; |
| 5434 | 5378 | }; |
| 5435 | 5379 | |
| ... | ... | @@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct { |
| 5448 | 5392 | is_simple_noreturn: bool, |
| 5449 | 5393 | }; |
| 5450 | 5394 | |
| 5451 | pub const Under = union(enum) { | |
| 5452 | none, | |
| 5453 | bare: Under.Resolved, | |
| 5454 | index: u32, | |
| 5455 | ||
| 5456 | pub const Resolved = struct { | |
| 5457 | index: Case.Index, | |
| 5458 | body: []const Inst.Index, | |
| 5459 | capture: Inst.SwitchBlock.ProngInfo.Capture, | |
| 5460 | has_tag_capture: bool, | |
| 5461 | }; | |
| 5462 | ||
| 5463 | /// If this returns `null` and `under` is not `.none`, you'll have to | |
| 5464 | /// find the under case by iterating all cases and using `isUnder`! | |
| 5465 | pub fn resolve(under: Under) ?Under.Resolved { | |
| 5466 | return switch (under) { | |
| 5467 | .bare => |resolved| resolved, | |
| 5468 | .none, .index => null, | |
| 5469 | }; | |
| 5470 | } | |
| 5471 | }; | |
| 5472 | ||
| 5473 | 5395 | pub const Iterator = struct { |
| 5474 | 5396 | next_idx: u32, |
| 5475 | under_idx: ?u32, | |
| 5476 | 5397 | prong_infos: []const Inst.SwitchBlock.ProngInfo, |
| 5477 | 5398 | multi_case_items_lens: []const u32, |
| 5478 | 5399 | multi_case_ranges_lens: ?[]const u32, |
| ... | ... | @@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5486 | 5407 | return if (idx < scalar_cases_len) .{ |
| 5487 | 5408 | .index = .{ |
| 5488 | 5409 | .kind = .scalar, |
| 5489 | .is_under = idx == it.under_idx, | |
| 5490 | 5410 | .value = @intCast(idx), |
| 5491 | 5411 | }, |
| 5492 | 5412 | .prong_info = it.prong_infos[idx], |
| ... | ... | @@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5495 | 5415 | } else .{ |
| 5496 | 5416 | .index = .{ |
| 5497 | 5417 | .kind = .multi, |
| 5498 | .is_under = idx == it.under_idx, | |
| 5499 | 5418 | .value = @intCast(idx - scalar_cases_len), |
| 5500 | 5419 | }, |
| 5501 | 5420 | .prong_info = it.prong_infos[idx], |
| ... | ... | @@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5516 | 5435 | pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator { |
| 5517 | 5436 | return .{ |
| 5518 | 5437 | .next_idx = 0, |
| 5519 | .under_idx = switch (unwrapped.under_case) { | |
| 5520 | .none, .bare => null, | |
| 5521 | .index => |index| index, | |
| 5522 | }, | |
| 5523 | 5438 | .prong_infos = unwrapped.prong_infos, |
| 5524 | 5439 | .multi_case_items_lens = unwrapped.multi_case_items_lens, |
| 5525 | 5440 | .multi_case_ranges_lens = unwrapped.multi_case_ranges_lens, |
src/Sema.zig+112-129| ... | ... | @@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock( |
| 10753 | 10753 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 10754 | 10754 | |
| 10755 | 10755 | const has_else = zir_switch.else_case != null; |
| 10756 | const has_under = zir_switch.under_case != .none; | |
| 10756 | const has_under = zir_switch.has_under; | |
| 10757 | 10757 | |
| 10758 | 10758 | const else_case = validated_switch.else_case; |
| 10759 | const under_case = validated_switch.under_case; | |
| 10760 | 10759 | |
| 10761 | 10760 | const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: { |
| 10762 | 10761 | const val, const ref = if (operand_is_ref) |
| ... | ... | @@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock( |
| 10933 | 10932 | // we allow simple noreturn else prongs when switching on error sets! |
| 10934 | 10933 | break :find_prong .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline, true }; |
| 10935 | 10934 | } |
| 10936 | if (has_under) { | |
| 10937 | break :find_prong .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false, true }; | |
| 10938 | } | |
| 10939 | 10935 | unreachable; // malformed validated switch |
| 10940 | 10936 | }; |
| 10941 | 10937 | |
| ... | ... | @@ -11083,10 +11079,9 @@ fn finishSwitchBr( |
| 11083 | 11079 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11084 | 11080 | |
| 11085 | 11081 | const has_else = zir_switch.else_case != null; |
| 11086 | const has_under = zir_switch.under_case != .none; | |
| 11082 | const has_under = zir_switch.has_under; | |
| 11087 | 11083 | |
| 11088 | 11084 | const else_case = validated_switch.else_case; |
| 11089 | const under_case = validated_switch.under_case; | |
| 11090 | 11085 | |
| 11091 | 11086 | const scalar_cases_len = zir_switch.scalarCasesLen(); |
| 11092 | 11087 | const multi_cases_len = zir_switch.multiCasesLen(); |
| ... | ... | @@ -11138,20 +11133,15 @@ fn finishSwitchBr( |
| 11138 | 11133 | var case_it = zir_switch.iterateCases(); |
| 11139 | 11134 | var extra_index = zir_switch.end; |
| 11140 | 11135 | |
| 11136 | var under_prong: ?struct { | |
| 11137 | index: Zir.UnwrappedSwitchBlock.Case.Index, | |
| 11138 | body: []const Zir.Inst.Index, | |
| 11139 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, | |
| 11140 | has_tag_capture: bool, | |
| 11141 | } = null; | |
| 11142 | ||
| 11141 | 11143 | var cases_len: u32 = 0; |
| 11142 | 11144 | while (case_it.next()) |case| { |
| 11143 | if (case.isUnder()) { // we'll deal with this later | |
| 11144 | extra_index += case.prong_info.body_len; | |
| 11145 | for (case.item_infos) |item_info| { | |
| 11146 | if (item_info.bodyLen()) |body_len| extra_index += body_len; | |
| 11147 | } | |
| 11148 | for (case.range_infos) |range_info| { | |
| 11149 | if (range_info[0].bodyLen()) |body_len| extra_index += body_len; | |
| 11150 | if (range_info[1].bodyLen()) |body_len| extra_index += body_len; | |
| 11151 | } | |
| 11152 | continue; | |
| 11153 | } | |
| 11154 | ||
| 11155 | 11145 | const item_refs = case_vals[case_val_idx..][0..case.item_infos.len]; |
| 11156 | 11146 | case_val_idx += item_refs.len; |
| 11157 | 11147 | const range_refs: []const [2]Air.Inst.Ref = |
| ... | ... | @@ -11171,7 +11161,9 @@ fn finishSwitchBr( |
| 11171 | 11161 | |
| 11172 | 11162 | var emit_bb = false; |
| 11173 | 11163 | var any_analyze_body = false; |
| 11164 | var is_under_prong = false; | |
| 11174 | 11165 | for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| { |
| 11166 | if (item_ref == .none) is_under_prong = true; | |
| 11175 | 11167 | if (item_info.bodyLen()) |body_len| extra_index += body_len; |
| 11176 | 11168 | |
| 11177 | 11169 | const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach); |
| ... | ... | @@ -11319,48 +11311,58 @@ fn finishSwitchBr( |
| 11319 | 11311 | } |
| 11320 | 11312 | } |
| 11321 | 11313 | |
| 11322 | if (!prong_info.is_inline) { | |
| 11323 | cases_len += 1; | |
| 11324 | case_block.instructions.clearRetainingCapacity(); | |
| 11325 | case_block.error_return_trace_index = child_block.error_return_trace_index; | |
| 11314 | if (prong_info.is_inline) continue; // handled above | |
| 11326 | 11315 | |
| 11327 | const prong_hint: std.builtin.BranchHint = hint: { | |
| 11328 | if (any_analyze_body) break :hint try sema.analyzeSwitchProng( | |
| 11329 | &case_block, | |
| 11330 | operand, | |
| 11331 | operand_ty, | |
| 11332 | raw_operand_ty, | |
| 11333 | prong_body, | |
| 11334 | block.src(.{ .switch_capture = .{ | |
| 11335 | .switch_node_offset = src_node_offset, | |
| 11336 | .case_idx = case.index, | |
| 11337 | } }), | |
| 11338 | prong_info.capture, | |
| 11339 | prong_info.has_tag_capture, | |
| 11340 | .none, | |
| 11341 | .{ .item_refs = item_refs }, | |
| 11342 | validated_switch.else_err_ty, | |
| 11343 | switch_inst, | |
| 11344 | zir_switch, | |
| 11345 | ); | |
| 11346 | _ = try case_block.addNoOp(.unreach); | |
| 11347 | break :hint .cold; // unreachable branches are cold | |
| 11316 | if (is_under_prong) { | |
| 11317 | under_prong = .{ | |
| 11318 | .index = case.index, | |
| 11319 | .body = prong_body, | |
| 11320 | .capture = case.prong_info.capture, | |
| 11321 | .has_tag_capture = case.prong_info.has_tag_capture, | |
| 11348 | 11322 | }; |
| 11349 | try branch_hints.append(gpa, prong_hint); | |
| 11350 | ||
| 11351 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + | |
| 11352 | item_refs.len + | |
| 11353 | 2 * range_refs.len + | |
| 11354 | case_block.instructions.items.len); | |
| 11355 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ | |
| 11356 | .items_len = @intCast(item_refs.len), | |
| 11357 | .ranges_len = @intCast(range_refs.len), | |
| 11358 | .body_len = @intCast(case_block.instructions.items.len), | |
| 11359 | })); | |
| 11360 | cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs)); | |
| 11361 | cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs)); | |
| 11362 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); | |
| 11323 | continue; | |
| 11363 | 11324 | } |
| 11325 | ||
| 11326 | cases_len += 1; | |
| 11327 | case_block.instructions.clearRetainingCapacity(); | |
| 11328 | case_block.error_return_trace_index = child_block.error_return_trace_index; | |
| 11329 | ||
| 11330 | const prong_hint: std.builtin.BranchHint = hint: { | |
| 11331 | if (any_analyze_body) break :hint try sema.analyzeSwitchProng( | |
| 11332 | &case_block, | |
| 11333 | operand, | |
| 11334 | operand_ty, | |
| 11335 | raw_operand_ty, | |
| 11336 | prong_body, | |
| 11337 | block.src(.{ .switch_capture = .{ | |
| 11338 | .switch_node_offset = src_node_offset, | |
| 11339 | .case_idx = case.index, | |
| 11340 | } }), | |
| 11341 | prong_info.capture, | |
| 11342 | prong_info.has_tag_capture, | |
| 11343 | .none, | |
| 11344 | .{ .item_refs = item_refs }, | |
| 11345 | validated_switch.else_err_ty, | |
| 11346 | switch_inst, | |
| 11347 | zir_switch, | |
| 11348 | ); | |
| 11349 | _ = try case_block.addNoOp(.unreach); | |
| 11350 | break :hint .cold; // unreachable branches are cold | |
| 11351 | }; | |
| 11352 | try branch_hints.append(gpa, prong_hint); | |
| 11353 | ||
| 11354 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + | |
| 11355 | item_refs.len + | |
| 11356 | 2 * range_refs.len + | |
| 11357 | case_block.instructions.items.len); | |
| 11358 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ | |
| 11359 | .items_len = @intCast(item_refs.len), | |
| 11360 | .ranges_len = @intCast(range_refs.len), | |
| 11361 | .body_len = @intCast(case_block.instructions.items.len), | |
| 11362 | })); | |
| 11363 | cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs)); | |
| 11364 | cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs)); | |
| 11365 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); | |
| 11364 | 11366 | } |
| 11365 | 11367 | |
| 11366 | 11368 | const catch_all_extra: []const u32 = catch_all_extra: { |
| ... | ... | @@ -11499,7 +11501,7 @@ fn finishSwitchBr( |
| 11499 | 11501 | try branch_hints.append(gpa, prong_hint); |
| 11500 | 11502 | |
| 11501 | 11503 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + |
| 11502 | (validated_switch.seen_enum_fields.len - zir_switch.totalItemsLen()) + | |
| 11504 | (validated_switch.seen_enum_fields.len + 1 - zir_switch.totalItemsLen()) + // +1 because totalItemsLen includes the _ | |
| 11503 | 11505 | case_block.instructions.items.len); |
| 11504 | 11506 | const extra_case = cases_extra.addManyAsArrayAssumeCapacity( |
| 11505 | 11507 | @typeInfo(Air.SwitchBr.Case).@"struct".fields.len, |
| ... | ... | @@ -11555,7 +11557,7 @@ fn finishSwitchBr( |
| 11555 | 11557 | if (analyze_catch_all_body) { |
| 11556 | 11558 | const index, const body, const capture, const has_tag_capture = switch (catch_all_case) { |
| 11557 | 11559 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture }, |
| 11558 | .under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture }, | |
| 11560 | .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture }, | |
| 11559 | 11561 | .none => unreachable, |
| 11560 | 11562 | }; |
| 11561 | 11563 | break :hint try sema.analyzeSwitchProng( |
| ... | ... | @@ -11734,7 +11736,6 @@ fn fixupSwitchContinues( |
| 11734 | 11736 | const ValidatedSwitchBlock = struct { |
| 11735 | 11737 | seen_enum_fields: []const ?LazySrcLoc, |
| 11736 | 11738 | seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), |
| 11737 | seen_sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc), | |
| 11738 | 11739 | seen_ranges: []const RangeSet.Range, |
| 11739 | 11740 | true_src: ?LazySrcLoc, |
| 11740 | 11741 | false_src: ?LazySrcLoc, |
| ... | ... | @@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct { |
| 11742 | 11743 | |
| 11743 | 11744 | case_vals: []const Air.Inst.Ref, |
| 11744 | 11745 | else_case: Zir.UnwrappedSwitchBlock.Case.Else, |
| 11745 | under_case: Zir.UnwrappedSwitchBlock.Case.Under.Resolved, | |
| 11746 | 11746 | else_err_ty: ?Type, |
| 11747 | 11747 | |
| 11748 | 11748 | fn iterateUnhandledItems( |
| ... | ... | @@ -11868,7 +11868,6 @@ fn validateSwitchBlock( |
| 11868 | 11868 | const src = block.nodeOffset(src_node_offset); |
| 11869 | 11869 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11870 | 11870 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); |
| 11871 | const under_prong_src = block.src(.{ .node_offset_switch_under_prong = src_node_offset }); | |
| 11872 | 11871 | var extra_index = zir_switch.end; |
| 11873 | 11872 | |
| 11874 | 11873 | // We want to map values to our placeholders later on. |
| ... | ... | @@ -11948,33 +11947,7 @@ fn validateSwitchBlock( |
| 11948 | 11947 | }; |
| 11949 | 11948 | |
| 11950 | 11949 | const has_else = zir_switch.else_case != null; |
| 11951 | const has_under = zir_switch.under_case != .none; | |
| 11952 | ||
| 11953 | // Validate usage of '_' prongs. | |
| 11954 | if (has_under and !operand_ty.isNonexhaustiveEnum(zcu)) { | |
| 11955 | const msg = msg: { | |
| 11956 | const msg = try sema.errMsg( | |
| 11957 | src, | |
| 11958 | "'_' prong only allowed when switching on non-exhaustive enums", | |
| 11959 | .{}, | |
| 11960 | ); | |
| 11961 | errdefer msg.destroy(gpa); | |
| 11962 | try sema.errNote( | |
| 11963 | under_prong_src, | |
| 11964 | msg, | |
| 11965 | "'_' prong here", | |
| 11966 | .{}, | |
| 11967 | ); | |
| 11968 | try sema.errNote( | |
| 11969 | src, | |
| 11970 | msg, | |
| 11971 | "consider using 'else'", | |
| 11972 | .{}, | |
| 11973 | ); | |
| 11974 | break :msg msg; | |
| 11975 | }; | |
| 11976 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 11977 | } | |
| 11950 | const has_under = zir_switch.has_under; | |
| 11978 | 11951 | |
| 11979 | 11952 | var case_vals: std.ArrayList(Air.Inst.Ref) = .empty; |
| 11980 | 11953 | try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len); |
| ... | ... | @@ -11991,7 +11964,6 @@ fn validateSwitchBlock( |
| 11991 | 11964 | var else_err_ty: ?Type = null; |
| 11992 | 11965 | |
| 11993 | 11966 | const else_case = zir_switch.else_case orelse undefined; |
| 11994 | var under_case = zir_switch.under_case.resolve() orelse undefined; | |
| 11995 | 11967 | |
| 11996 | 11968 | switch (item_ty.zigTypeTag(zcu)) { |
| 11997 | 11969 | .@"union" => unreachable, |
| ... | ... | @@ -12020,16 +11992,6 @@ fn validateSwitchBlock( |
| 12020 | 11992 | var case_it = zir_switch.iterateCases(); |
| 12021 | 11993 | while (case_it.next()) |case| { |
| 12022 | 11994 | const prong_info = case.prong_info; |
| 12023 | const is_under = case.isUnder(); | |
| 12024 | if (is_under) { | |
| 12025 | assert(!prong_info.is_inline); | |
| 12026 | under_case = .{ | |
| 12027 | .index = case.index, | |
| 12028 | .body = sema.code.bodySlice(extra_index, prong_info.body_len), | |
| 12029 | .capture = prong_info.capture, | |
| 12030 | .has_tag_capture = prong_info.has_tag_capture, | |
| 12031 | }; | |
| 12032 | } | |
| 12033 | 11995 | extra_index += prong_info.body_len; |
| 12034 | 11996 | for (case.item_infos, 0..) |item_info, item_i| { |
| 12035 | 11997 | const item_src = block.src(.{ .switch_case_item = .{ |
| ... | ... | @@ -12037,9 +11999,34 @@ fn validateSwitchBlock( |
| 12037 | 11999 | .case_idx = case.index, |
| 12038 | 12000 | .item_idx = .{ .kind = .single, .value = @intCast(item_i) }, |
| 12039 | 12001 | } }); |
| 12040 | const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | |
| 12041 | try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); | |
| 12042 | if (!is_under) case_vals.appendAssumeCapacity(item.ref); | |
| 12002 | if (item_info.unwrap() == .under) { | |
| 12003 | if (!operand_ty.isNonexhaustiveEnum(zcu)) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 12004 | const msg = try sema.errMsg( | |
| 12005 | src, | |
| 12006 | "'_' prong only allowed when switching on non-exhaustive enums", | |
| 12007 | .{}, | |
| 12008 | ); | |
| 12009 | errdefer msg.destroy(gpa); | |
| 12010 | try sema.errNote( | |
| 12011 | item_src, | |
| 12012 | msg, | |
| 12013 | "'_' prong here", | |
| 12014 | .{}, | |
| 12015 | ); | |
| 12016 | try sema.errNote( | |
| 12017 | src, | |
| 12018 | msg, | |
| 12019 | "consider using 'else'", | |
| 12020 | .{}, | |
| 12021 | ); | |
| 12022 | break :msg msg; | |
| 12023 | }); | |
| 12024 | case_vals.appendAssumeCapacity(.none); | |
| 12025 | } else { | |
| 12026 | const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach); | |
| 12027 | try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); | |
| 12028 | case_vals.appendAssumeCapacity(item.ref); | |
| 12029 | } | |
| 12043 | 12030 | } |
| 12044 | 12031 | for (case.range_infos, 0..) |range_info, range_i| { |
| 12045 | 12032 | const range_offset: LazySrcLoc.Offset.SwitchItem = .{ |
| ... | ... | @@ -12050,10 +12037,10 @@ fn validateSwitchBlock( |
| 12050 | 12037 | const range_src = block.src(.{ .switch_case_item = range_offset }); |
| 12051 | 12038 | const first_src = block.src(.{ .switch_case_item_range_first = range_offset }); |
| 12052 | 12039 | const last_src = block.src(.{ .switch_case_item_range_last = range_offset }); |
| 12053 | const first_item, extra_index = try sema.resolveSwitchItem(block, first_src, item_ty, range_info[0], extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | |
| 12054 | const last_item, extra_index = try sema.resolveSwitchItem(block, last_src, item_ty, range_info[1], extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | |
| 12040 | const first_item, extra_index = try sema.resolveSwitchItem(block, first_src, item_ty, range_info[0], extra_index, switch_inst, prong_info.is_comptime_unreach); | |
| 12041 | const last_item, extra_index = try sema.resolveSwitchItem(block, last_src, item_ty, range_info[1], extra_index, switch_inst, prong_info.is_comptime_unreach); | |
| 12055 | 12042 | try sema.validateSwitchItemOrRange(block, range_src, first_item.val, last_item.val, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); |
| 12056 | if (!is_under) case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref }); | |
| 12043 | case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref }); | |
| 12057 | 12044 | } |
| 12058 | 12045 | } |
| 12059 | 12046 | |
| ... | ... | @@ -12285,7 +12272,6 @@ fn validateSwitchBlock( |
| 12285 | 12272 | return .{ |
| 12286 | 12273 | .seen_enum_fields = seen_enum_fields, |
| 12287 | 12274 | .seen_errors = seen_errors, |
| 12288 | .seen_sparse_values = seen_sparse_values, | |
| 12289 | 12275 | .seen_ranges = range_set.ranges.items, |
| 12290 | 12276 | .true_src = true_src, |
| 12291 | 12277 | .false_src = false_src, |
| ... | ... | @@ -12293,7 +12279,6 @@ fn validateSwitchBlock( |
| 12293 | 12279 | |
| 12294 | 12280 | .case_vals = case_vals.items, |
| 12295 | 12281 | .else_case = else_case, |
| 12296 | .under_case = under_case, | |
| 12297 | 12282 | .else_err_ty = else_err_ty, |
| 12298 | 12283 | }; |
| 12299 | 12284 | } |
| ... | ... | @@ -12334,19 +12319,13 @@ fn resolveSwitchBlock( |
| 12334 | 12319 | var case_val_idx: usize = 0; |
| 12335 | 12320 | var extra_index = zir_switch.end; |
| 12336 | 12321 | var case_it = zir_switch.iterateCases(); |
| 12322 | var under_prong: ?struct { | |
| 12323 | index: Zir.UnwrappedSwitchBlock.Case.Index, | |
| 12324 | body: []const Zir.Inst.Index, | |
| 12325 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, | |
| 12326 | has_tag_capture: bool, | |
| 12327 | } = null; | |
| 12337 | 12328 | while (case_it.next()) |case| { |
| 12338 | if (case.isUnder()) { // we'll deal with this later | |
| 12339 | extra_index += case.prong_info.body_len; | |
| 12340 | for (case.item_infos) |item_info| { | |
| 12341 | if (item_info.bodyLen()) |body_len| extra_index += body_len; | |
| 12342 | } | |
| 12343 | for (case.range_infos) |range_info| { | |
| 12344 | if (range_info[0].bodyLen()) |body_len| extra_index += body_len; | |
| 12345 | if (range_info[1].bodyLen()) |body_len| extra_index += body_len; | |
| 12346 | } | |
| 12347 | continue; | |
| 12348 | } | |
| 12349 | ||
| 12350 | 12329 | const prong_info = case.prong_info; |
| 12351 | 12330 | const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len); |
| 12352 | 12331 | extra_index += prong_body.len; |
| ... | ... | @@ -12363,6 +12342,15 @@ fn resolveSwitchBlock( |
| 12363 | 12342 | const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]); |
| 12364 | 12343 | case_val_idx += 2 * range_refs.len; |
| 12365 | 12344 | for (item_refs) |item_ref| { |
| 12345 | if (item_ref == .none) { | |
| 12346 | under_prong = .{ | |
| 12347 | .index = case.index, | |
| 12348 | .body = prong_body, | |
| 12349 | .capture = case.prong_info.capture, | |
| 12350 | .has_tag_capture = case.prong_info.has_tag_capture, | |
| 12351 | }; | |
| 12352 | continue; | |
| 12353 | } | |
| 12366 | 12354 | const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable; |
| 12367 | 12355 | if (cond_val.eql(item_val, item_ty, zcu)) { |
| 12368 | 12356 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref); |
| ... | ... | @@ -12421,7 +12409,6 @@ fn resolveSwitchBlock( |
| 12421 | 12409 | } |
| 12422 | 12410 | |
| 12423 | 12411 | const else_case = validated_switch.else_case; |
| 12424 | const under_case = validated_switch.under_case; | |
| 12425 | 12412 | |
| 12426 | 12413 | // named-only prong |
| 12427 | 12414 | |
| ... | ... | @@ -12452,7 +12439,7 @@ fn resolveSwitchBlock( |
| 12452 | 12439 | |
| 12453 | 12440 | const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) { |
| 12454 | 12441 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline }, |
| 12455 | .under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false }, | |
| 12442 | .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture, false }, | |
| 12456 | 12443 | .none => unreachable, |
| 12457 | 12444 | }; |
| 12458 | 12445 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref); |
| ... | ... | @@ -13169,7 +13156,6 @@ fn resolveSwitchItem( |
| 13169 | 13156 | extra_index: usize, |
| 13170 | 13157 | switch_inst: Zir.Inst.Index, |
| 13171 | 13158 | prong_is_comptime_unreach: bool, |
| 13172 | prong_is_inline: bool, | |
| 13173 | 13159 | ) CompileError!ResolvedSwitchItemAndExtraIndex { |
| 13174 | 13160 | const pt = sema.pt; |
| 13175 | 13161 | const zcu = pt.zcu; |
| ... | ... | @@ -13180,6 +13166,7 @@ fn resolveSwitchItem( |
| 13180 | 13166 | |
| 13181 | 13167 | var end = extra_index; |
| 13182 | 13168 | const uncoerced: Air.Inst.Ref, const uncoerced_ty: Type = uncoerced: switch (item_info.unwrap()) { |
| 13169 | .under => unreachable, // caller must check this before calling us | |
| 13183 | 13170 | .enum_literal => |str_index| { |
| 13184 | 13171 | const zir_str = sema.code.nullTerminatedString(str_index); |
| 13185 | 13172 | const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls); |
| ... | ... | @@ -13198,10 +13185,6 @@ fn resolveSwitchItem( |
| 13198 | 13185 | } })); |
| 13199 | 13186 | break :uncoerced .{ uncoerced, err_set_ty }; |
| 13200 | 13187 | }, |
| 13201 | .number_literal => |zir_ref| { | |
| 13202 | const uncoerced = try sema.resolveInst(zir_ref); | |
| 13203 | break :uncoerced .{ uncoerced, sema.typeOf(uncoerced) }; | |
| 13204 | }, | |
| 13205 | 13188 | .body_len => |body_len| { |
| 13206 | 13189 | const body = sema.code.bodySlice(extra_index, body_len); |
| 13207 | 13190 | end += body.len; |
| ... | ... | @@ -13231,7 +13214,7 @@ fn resolveSwitchItem( |
| 13231 | 13214 | .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| { |
| 13232 | 13215 | break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty); |
| 13233 | 13216 | }, |
| 13234 | .missing_error => if (prong_is_comptime_unreach and !prong_is_inline) { | |
| 13217 | .missing_error => if (prong_is_comptime_unreach) { | |
| 13235 | 13218 | break :item_ref uncoerced; |
| 13236 | 13219 | }, |
| 13237 | 13220 | .from_anyerror => {}, |
src/Zcu.zig+1-41| ... | ... | @@ -1742,27 +1742,6 @@ pub const SrcLoc = struct { |
| 1742 | 1742 | } else unreachable; |
| 1743 | 1743 | }, |
| 1744 | 1744 | |
| 1745 | .node_offset_switch_under_prong => |node_off| { | |
| 1746 | const tree = try src_loc.file_scope.getTree(zcu); | |
| 1747 | const switch_node = node_off.toAbsolute(src_loc.base_node); | |
| 1748 | _, const extra_index = tree.nodeData(switch_node).node_and_extra; | |
| 1749 | const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); | |
| 1750 | for (case_nodes) |case_node| { | |
| 1751 | const case = tree.fullSwitchCase(case_node).?; | |
| 1752 | for (case.ast.values) |val| { | |
| 1753 | if (tree.nodeTag(val) == .identifier and | |
| 1754 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) | |
| 1755 | { | |
| 1756 | return tree.tokensToSpan( | |
| 1757 | tree.firstToken(case_node), | |
| 1758 | tree.lastToken(case_node), | |
| 1759 | tree.nodeMainToken(val), | |
| 1760 | ); | |
| 1761 | } | |
| 1762 | } | |
| 1763 | } else unreachable; | |
| 1764 | }, | |
| 1765 | ||
| 1766 | 1745 | .node_offset_switch_range => |node_off| { |
| 1767 | 1746 | const tree = try src_loc.file_scope.getTree(zcu); |
| 1768 | 1747 | const switch_node = node_off.toAbsolute(src_loc.base_node); |
| ... | ... | @@ -2176,7 +2155,6 @@ pub const SrcLoc = struct { |
| 2176 | 2155 | |
| 2177 | 2156 | var multi_i: u32 = 0; |
| 2178 | 2157 | var scalar_i: u32 = 0; |
| 2179 | var underscore_node: Ast.Node.OptionalIndex = .none; | |
| 2180 | 2158 | const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| { |
| 2181 | 2159 | const case = tree.fullSwitchCase(case_node).?; |
| 2182 | 2160 | if (case.ast.values.len == 0) { |
| ... | ... | @@ -2185,17 +2163,6 @@ pub const SrcLoc = struct { |
| 2185 | 2163 | } |
| 2186 | 2164 | continue :case; |
| 2187 | 2165 | } |
| 2188 | if (underscore_node == .none) { | |
| 2189 | for (case.ast.values) |value| { | |
| 2190 | if (tree.nodeTag(value) == .identifier and | |
| 2191 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(value)), "_")) | |
| 2192 | { | |
| 2193 | underscore_node = value.toOptional(); | |
| 2194 | if (want_case_idx.is_under) break :case case; | |
| 2195 | if (case.ast.values.len == 1) continue :case; | |
| 2196 | } | |
| 2197 | } | |
| 2198 | } | |
| 2199 | 2166 | |
| 2200 | 2167 | const is_multi = case.ast.values.len != 1 or |
| 2201 | 2168 | tree.nodeTag(case.ast.values[0]) == .switch_range; |
| ... | ... | @@ -2220,7 +2187,6 @@ pub const SrcLoc = struct { |
| 2220 | 2187 | .switch_case_item_range_last, |
| 2221 | 2188 | => |x| item_idx: { |
| 2222 | 2189 | assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else"); |
| 2223 | assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.bare_under); | |
| 2224 | 2190 | break :item_idx x.item_idx; |
| 2225 | 2191 | }, |
| 2226 | 2192 | .switch_capture, .switch_tag_capture => { |
| ... | ... | @@ -2247,9 +2213,7 @@ pub const SrcLoc = struct { |
| 2247 | 2213 | .single => { |
| 2248 | 2214 | var item_i: u32 = 0; |
| 2249 | 2215 | for (case.ast.values) |item_node| { |
| 2250 | if (item_node.toOptional() == underscore_node or | |
| 2251 | tree.nodeTag(item_node) == .switch_range) | |
| 2252 | { | |
| 2216 | if (tree.nodeTag(item_node) == .switch_range) { | |
| 2253 | 2217 | continue; |
| 2254 | 2218 | } |
| 2255 | 2219 | if (item_i != want_item_idx.value) { |
| ... | ... | @@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct { |
| 2456 | 2420 | /// by taking this AST node index offset from the containing base node, |
| 2457 | 2421 | /// which points to a switch expression AST node. Next, navigate to the else prong. |
| 2458 | 2422 | node_offset_switch_else_prong: Ast.Node.Offset, |
| 2459 | /// The source location points to the `_` prong of a switch expression, found | |
| 2460 | /// by taking this AST node index offset from the containing base node, | |
| 2461 | /// which points to a switch expression AST node. Next, navigate to the `_` prong. | |
| 2462 | node_offset_switch_under_prong: Ast.Node.Offset, | |
| 2463 | 2423 | /// The source location points to all the ranges of a switch expression, found |
| 2464 | 2424 | /// by taking this AST node index offset from the containing base node, |
| 2465 | 2425 | /// which points to a switch expression AST node. Next, navigate to any of the |
src/print_zir.zig+37-47| ... | ... | @@ -2021,15 +2021,6 @@ const Writer = struct { |
| 2021 | 2021 | try stream.writeAll("else => "); |
| 2022 | 2022 | try self.writeBracedBody(stream, else_case.body); |
| 2023 | 2023 | } |
| 2024 | if (zir_switch.under_case.resolve()) |under_case| { | |
| 2025 | try stream.writeAll(",\n"); | |
| 2026 | try stream.splatByteAll(' ', self.indent); | |
| 2027 | ||
| 2028 | try self.writeSwitchCaptures(stream, under_case.capture, under_case.has_tag_capture, inst, &zir_switch); | |
| 2029 | ||
| 2030 | try stream.writeAll("_ => "); | |
| 2031 | try self.writeBracedBody(stream, under_case.body); | |
| 2032 | } | |
| 2033 | 2024 | |
| 2034 | 2025 | var case_it = zir_switch.iterateCases(); |
| 2035 | 2026 | while (case_it.next()) |case| { |
| ... | ... | @@ -2043,14 +2034,8 @@ const Writer = struct { |
| 2043 | 2034 | const prong_body = self.code.bodySlice(extra_index, prong_info.body_len); |
| 2044 | 2035 | extra_index += prong_body.len; |
| 2045 | 2036 | |
| 2046 | var first_item: bool = true; | |
| 2047 | if (case.isUnder()) { | |
| 2048 | try stream.writeAll("_"); | |
| 2049 | first_item = false; | |
| 2050 | } | |
| 2051 | for (case.item_infos) |item_info| { | |
| 2052 | if (!first_item) try stream.writeAll(", "); | |
| 2053 | first_item = false; | |
| 2037 | for (case.item_infos, 0..) |item_info, i| { | |
| 2038 | if (i > 0) try stream.writeAll(", "); | |
| 2054 | 2039 | |
| 2055 | 2040 | switch (item_info.unwrap()) { |
| 2056 | 2041 | .enum_literal => |str_index| { |
| ... | ... | @@ -2061,9 +2046,7 @@ const Writer = struct { |
| 2061 | 2046 | const str = self.code.nullTerminatedString(str_index); |
| 2062 | 2047 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); |
| 2063 | 2048 | }, |
| 2064 | .number_literal => |zir_ref| { | |
| 2065 | try self.writeInstRef(stream, zir_ref); | |
| 2066 | }, | |
| 2049 | .under => try stream.writeByte('_'), | |
| 2067 | 2050 | .body_len => |body_len| { |
| 2068 | 2051 | const item_body = self.code.bodySlice(extra_index, body_len); |
| 2069 | 2052 | extra_index += item_body.len; |
| ... | ... | @@ -2071,33 +2054,40 @@ const Writer = struct { |
| 2071 | 2054 | }, |
| 2072 | 2055 | } |
| 2073 | 2056 | } |
| 2074 | for (case.range_infos) |range_info| { | |
| 2075 | if (!first_item) try stream.writeAll(", "); | |
| 2076 | first_item = false; | |
| 2077 | ||
| 2078 | var first_range_item = true; | |
| 2079 | for (&range_info) |item_info| { | |
| 2080 | if (!first_range_item) try stream.writeAll("..."); | |
| 2081 | first_range_item = false; | |
| 2082 | ||
| 2083 | switch (item_info.unwrap()) { | |
| 2084 | .enum_literal => |str_index| { | |
| 2085 | const str = self.code.nullTerminatedString(str_index); | |
| 2086 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); | |
| 2087 | }, | |
| 2088 | .error_value => |str_index| { | |
| 2089 | const str = self.code.nullTerminatedString(str_index); | |
| 2090 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); | |
| 2091 | }, | |
| 2092 | .number_literal => |zir_ref| { | |
| 2093 | try self.writeInstRef(stream, zir_ref); | |
| 2094 | }, | |
| 2095 | .body_len => |body_len| { | |
| 2096 | const item_body = self.code.bodySlice(extra_index, body_len); | |
| 2097 | extra_index += item_body.len; | |
| 2098 | try self.writeBracedDecl(stream, item_body); | |
| 2099 | }, | |
| 2100 | } | |
| 2057 | for (case.range_infos, 0..) |range_info, i| { | |
| 2058 | if (i > 0 and case.item_infos.len == 0) try stream.writeAll(", "); | |
| 2059 | switch (range_info[0].unwrap()) { | |
| 2060 | .enum_literal => |str_index| { | |
| 2061 | const str = self.code.nullTerminatedString(str_index); | |
| 2062 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); | |
| 2063 | }, | |
| 2064 | .error_value => |str_index| { | |
| 2065 | const str = self.code.nullTerminatedString(str_index); | |
| 2066 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); | |
| 2067 | }, | |
| 2068 | .under => unreachable, // '_..._' is not allowed | |
| 2069 | .body_len => |body_len| { | |
| 2070 | const item_body = self.code.bodySlice(extra_index, body_len); | |
| 2071 | extra_index += item_body.len; | |
| 2072 | try self.writeBracedDecl(stream, item_body); | |
| 2073 | }, | |
| 2074 | } | |
| 2075 | try stream.writeAll("..."); | |
| 2076 | switch (range_info[1].unwrap()) { | |
| 2077 | .enum_literal => |str_index| { | |
| 2078 | const str = self.code.nullTerminatedString(str_index); | |
| 2079 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); | |
| 2080 | }, | |
| 2081 | .error_value => |str_index| { | |
| 2082 | const str = self.code.nullTerminatedString(str_index); | |
| 2083 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); | |
| 2084 | }, | |
| 2085 | .under => unreachable, // '_..._' is not allowed | |
| 2086 | .body_len => |body_len| { | |
| 2087 | const item_body = self.code.bodySlice(extra_index, body_len); | |
| 2088 | extra_index += item_body.len; | |
| 2089 | try self.writeBracedDecl(stream, item_body); | |
| 2090 | }, | |
| 2101 | 2091 | } |
| 2102 | 2092 | } |
| 2103 | 2093 | try stream.writeAll(" => "); |