authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-11 13:16:25+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-11 14:37:27+00:00
loged1268d0e63d3af144a262a1fa41b8e69ab3073b
tree3f5e99ac159431271bc5c9029b6d8b9f8ee961b2
parent8ec4c5cb137d9a93c35df3488408c44056c586b4
signaturelock-open Commit is signed but in an unrecognized format.

Zir: simplify '_' prong of 'switch' statements


5 files changed, 188 insertions(+), 390 deletions(-)

lib/std/zig/AstGen.zig+19-69
...@@ -7267,11 +7267,7 @@ fn switchExpr(...@@ -7267,11 +7267,7 @@ fn switchExpr(
7267 var total_items_len: usize = 0;7267 var total_items_len: usize = 0;
7268 var total_ranges_len: usize = 0;7268 var total_ranges_len: usize = 0;
7269 var else_case_node: Ast.Node.OptionalIndex = .none;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 var underscore_node: Ast.Node.OptionalIndex = .none;7270 var underscore_node: Ast.Node.OptionalIndex = .none;
7273 var underscore_src: ?Ast.TokenIndex = null;
7274 var under_is_bare = false;
7275 for (case_nodes) |case_node| {7271 for (case_nodes) |case_node| {
7276 const case = tree.fullSwitchCase(case_node).?;7272 const case = tree.fullSwitchCase(case_node).?;
7277 if (case.payload_token) |payload_token| {7273 if (case.payload_token) |payload_token| {
...@@ -7304,22 +7300,21 @@ fn switchExpr(...@@ -7304,22 +7300,21 @@ fn switchExpr(
73047300
7305 // Check for else prong.7301 // Check for else prong.
7306 if (case.ast.values.len == 0) {7302 if (case.ast.values.len == 0) {
7307 const case_src = case.ast.arrow_token - 1;7303 if (else_case_node.unwrap()) |prev_case_node| {
7308 if (else_src) |src| {7304 const prev_else_tok = tree.fullSwitchCase(prev_case_node).?.ast.arrow_token - 1;
7305 const else_tok = case.ast.arrow_token - 1;
7309 return astgen.failTokNotes(7306 return astgen.failTokNotes(
7310 case_src,7307 else_tok,
7311 "multiple else prongs in switch expression",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 else_case_node = case_node.toOptional();7313 else_case_node = case_node.toOptional();
7317 else_src = case_src;
7318 continue;7314 continue;
7319 }7315 }
73207316
7321 // Check for '_' prong and ranges.7317 // Check for '_' prong and ranges.
7322 var case_has_underscore = false;
7323 var case_has_ranges = false;7318 var case_has_ranges = false;
7324 for (case.ast.values) |val| {7319 for (case.ast.values) |val| {
7325 switch (tree.nodeTag(val)) {7320 switch (tree.nodeTag(val)) {
...@@ -7329,10 +7324,10 @@ fn switchExpr(...@@ -7329,10 +7324,10 @@ fn switchExpr(
7329 },7324 },
7330 .string_literal => return astgen.failNode(val, "cannot switch on strings", .{}),7325 .string_literal => return astgen.failNode(val, "cannot switch on strings", .{}),
7331 else => |tag| {7326 else => |tag| {
7327 total_items_len += 1;
7332 if (tag == .identifier and7328 if (tag == .identifier and
7333 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_"))7329 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_"))
7334 {7330 {
7335 const val_src = tree.nodeMainToken(val);
7336 if (is_err_switch) {7331 if (is_err_switch) {
7337 const case_src = case.ast.arrow_token - 1;7332 const case_src = case.ast.arrow_token - 1;
7338 return astgen.failTokNotes(7333 return astgen.failTokNotes(
...@@ -7348,30 +7343,24 @@ fn switchExpr(...@@ -7348,30 +7343,24 @@ fn switchExpr(
7348 },7343 },
7349 );7344 );
7350 }7345 }
7351 if (underscore_src) |src| {7346 if (underscore_node.unwrap()) |prev_src| {
7352 return astgen.failTokNotes(7347 return astgen.failNodeNotes(
7353 val_src,7348 val,
7354 "multiple '_' prongs in switch expression",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 if (case.inline_token != null) {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 underscore_node = val.toOptional();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 }
73737362
7374 const case_len = case.ast.values.len - @intFromBool(case_has_underscore);7363 const case_len = case.ast.values.len;
7375 if (case_len == 1 and !case_has_ranges) {7364 if (case_len == 1 and !case_has_ranges) {
7376 scalar_cases_len += 1;7365 scalar_cases_len += 1;
7377 } else if (case_len >= 1) {7366 } else if (case_len >= 1) {
...@@ -7379,9 +7368,8 @@ fn switchExpr(...@@ -7379,9 +7368,8 @@ fn switchExpr(
7379 }7368 }
7380 }7369 }
73817370
7382 const has_else = else_src != null;7371 const has_else = else_case_node != .none;
7383 const has_under = underscore_src != null;7372 const has_under = underscore_node != .none;
7384 if (under_is_bare) assert(has_under); // make sure that the former implies the latter
7385 if (is_err_switch) assert(!has_under); // should have failed by now7373 if (is_err_switch) assert(!has_under); // should have failed by now
7386 const any_ranges = total_ranges_len > 0;7374 const any_ranges = total_ranges_len > 0;
73877375
...@@ -7430,10 +7418,8 @@ fn switchExpr(...@@ -7430,10 +7418,8 @@ fn switchExpr(
74307418
7431 var non_err_prong_body_start: u32 = undefined;7419 var non_err_prong_body_start: u32 = undefined;
7432 var else_prong_body_start: u32 = undefined;7420 var else_prong_body_start: u32 = undefined;
7433 var bare_under_prong_body_start: u32 = undefined;
7434 var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined;7421 var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined;
7435 var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined;7422 var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined;
7436 var under_extra: u32 = undefined;
74377423
7438 var block_scope = parent_gz.makeSubBlock(scope);7424 var block_scope = parent_gz.makeSubBlock(scope);
7439 // block_scope not used for collecting instructions7425 // block_scope not used for collecting instructions
...@@ -7688,7 +7674,6 @@ fn switchExpr(...@@ -7688,7 +7674,6 @@ fn switchExpr(
7688 for (case_nodes) |case_node| {7674 for (case_nodes) |case_node| {
7689 const case = tree.fullSwitchCase(case_node).?;7675 const case = tree.fullSwitchCase(case_node).?;
76907676
7691 const case_has_under = case_node.toOptional() == under_case_node;
7692 const ranges_len: u32 = if (any_ranges) blk: {7677 const ranges_len: u32 = if (any_ranges) blk: {
7693 var ranges_len: u32 = 0;7678 var ranges_len: u32 = 0;
7694 for (case.ast.values) |value| {7679 for (case.ast.values) |value| {
...@@ -7696,14 +7681,13 @@ fn switchExpr(...@@ -7696,14 +7681,13 @@ fn switchExpr(
7696 }7681 }
7697 break :blk ranges_len;7682 break :blk ranges_len;
7698 } else 0;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 const is_multi_case = items_len > 1 or ranges_len > 0;7685 const is_multi_case = items_len > 1 or ranges_len > 0;
77017686
7702 // item/range bodies in order of occurence7687 // item/range bodies in order of occurence
7703 var item_i: usize = 0;7688 var item_i: usize = 0;
7704 var range_i: usize = 0;7689 var range_i: usize = 0;
7705 for (case.ast.values) |value| {7690 for (case.ast.values) |value| {
7706 if (value.toOptional() == underscore_node) continue;
7707 const is_range = tree.nodeTag(value) == .switch_range;7691 const is_range = tree.nodeTag(value) == .switch_range;
7708 const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined;7692 const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined;
7709 const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value};7693 const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value};
...@@ -7722,16 +7706,9 @@ fn switchExpr(...@@ -7722,16 +7706,9 @@ fn switchExpr(
7722 const str_index = try astgen.identAsString(ident_token);7706 const str_index = try astgen.identAsString(ident_token);
7723 break :blk .wrap(.{ .error_value = str_index });7707 break :blk .wrap(.{ .error_value = str_index });
7724 },7708 },
7725 .number_literal => {7709 else => if (value.toOptional() == underscore_node) {
7726 // We don't actually need a final result type for number7710 break :blk .wrap(.under);
7727 // literals, they can just be turned into `comptime_int`7711 } else {
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 => {
7735 scratch_scope.instructions_top = parent_gz.instructions.items.len;7712 scratch_scope.instructions_top = parent_gz.instructions.items.len;
7736 defer scratch_scope.unstack();7713 defer scratch_scope.unstack();
7737 const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal);7714 const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal);
...@@ -7957,25 +7934,6 @@ fn switchExpr(...@@ -7957,25 +7934,6 @@ fn switchExpr(
7957 break :prong_body;7934 break :prong_body;
7958 }7935 }
79597936
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 // We allow prongs with error items which are not inside the error set7937 // We allow prongs with error items which are not inside the error set
7980 // being switched on if their body is `=> comptime unreachable,`.7938 // being switched on if their body is `=> comptime unreachable,`.
7981 const is_comptime_unreach = comptime_unreach: {7939 const is_comptime_unreach = comptime_unreach: {
...@@ -8003,7 +7961,7 @@ fn switchExpr(...@@ -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 assert(multi_items_infos_start + multi_item_offset == bodies_start);7965 assert(multi_items_infos_start + multi_item_offset == bodies_start);
80087966
8009 if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) {7967 if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) {
...@@ -8024,7 +7982,6 @@ fn switchExpr(...@@ -8024,7 +7982,6 @@ fn switchExpr(
8024 @intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset7982 @intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset
8025 @intFromBool(needs_non_err_handling) + // non_err_info7983 @intFromBool(needs_non_err_handling) + // non_err_info
8026 @intFromBool(has_else) + // else_info7984 @intFromBool(has_else) + // else_info
8027 @intFromBool(has_under) + // under_prong_info or under_index
8028 payloads.items.len - body_table_end); // item infos and bodies7985 payloads.items.len - body_table_end); // item infos and bodies
80297986
8030 // singular pieces of data7987 // singular pieces of data
...@@ -8035,7 +7992,6 @@ fn switchExpr(...@@ -8035,7 +7992,6 @@ fn switchExpr(
8035 .any_ranges = any_ranges,7992 .any_ranges = any_ranges,
8036 .has_else = has_else,7993 .has_else = has_else,
8037 .has_under = has_under,7994 .has_under = has_under,
8038 .under_is_bare = under_is_bare,
8039 .has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue,7995 .has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue,
8040 .any_maybe_runtime_capture = any_maybe_runtime_capture,7996 .any_maybe_runtime_capture = any_maybe_runtime_capture,
8041 .payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder,7997 .payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder,
...@@ -8054,7 +8010,6 @@ fn switchExpr(...@@ -8054,7 +8010,6 @@ fn switchExpr(
8054 astgen.extra.appendAssumeCapacity(@bitCast(non_err_info));8010 astgen.extra.appendAssumeCapacity(@bitCast(non_err_info));
8055 }8011 }
8056 if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info));8012 if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info));
8057 if (has_under) astgen.extra.appendAssumeCapacity(under_extra);
80588013
8059 const extra_payloads_start = astgen.extra.items.len;8014 const extra_payloads_start = astgen.extra.items.len;
80608015
...@@ -8070,11 +8025,6 @@ fn switchExpr(...@@ -8070,11 +8025,6 @@ fn switchExpr(
8070 const body = payloads.items[else_prong_body_start..][0..else_info.body_len];8025 const body = payloads.items[else_prong_body_start..][0..else_info.body_len];
8071 astgen.extra.appendSliceAssumeCapacity(body);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 for (0..scalar_cases_len) |scalar_i| {8028 for (0..scalar_cases_len) |scalar_i| {
8079 const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]);8029 const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]);
8080 const item_body_start = payloads.items[scalar_body_table + scalar_i];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,34 +3303,25 @@ pub const Inst = struct {
3303 /// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union.3303 /// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union.
3304 /// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union.3304 /// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union.
3305 /// 5. else_info: ProngInfo.Else, // If has_else is set.3305 /// 5. else_info: ProngInfo.Else, // If has_else is set.
3306 /// 6. under_info: ProngInfo.Under, // If has_under is set and3306 /// 6. scalar_prong_info: ProngInfo, // for every scalar_cases_len
3307 /// // under_is_bare is set.3307 /// 7. multi_prong_info: ProngInfo, // for every multi_cases_len
3308 /// 7. under_index: u32, // If has_under is set and3308 /// 8. multi_case_items_len: u32, // for every multi_cases_len
3309 /// // under_is_bare is *not* set.3309 /// 9. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len
3310 /// // Index into switch cases.3310 /// 10. scalar_item_info: ItemInfo, // for every scalar_cases_len
3311 /// 8. scalar_prong_info: ProngInfo, // for every scalar_cases_len3311 /// 11. multi_items_info: { // for every multi_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
3317 /// item_info: ItemInfo, // for each multi_case_items_len3312 /// item_info: ItemInfo, // for each multi_case_items_len
3318 /// range_items_info: { // for each multi_case_ranges_len3313 /// range_items_info: { // for each multi_case_ranges_len
3319 /// first_info: ItemInfo,3314 /// first_info: ItemInfo,
3320 /// last_info: ItemInfo,3315 /// last_info: ItemInfo,
3321 /// }3316 /// }
3322 /// }3317 /// }
3323 /// 14. non_err_body {3318 /// 12. non_err_body {
3324 /// body_inst: Index // for every non_err_info.body_len3319 /// 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 /// body_inst: Inst.Index, // for every else_info.body_len3322 /// body_inst: Inst.Index, // for every else_info.body_len
3328 /// }3323 /// }
3329 /// 16. under_body: { // If has_under is set and3324 /// 14. scalar_bodies: { // for every scalar_cases_len
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
3334 /// prong_body: { // for each body_len in scalar_prong_info3325 /// prong_body: { // for each body_len in scalar_prong_info
3335 /// body_inst: Inst.Index, // for every body_len3326 /// body_inst: Inst.Index, // for every body_len
3336 /// }3327 /// }
...@@ -3338,7 +3329,7 @@ pub const Inst = struct {...@@ -3338,7 +3329,7 @@ pub const Inst = struct {
3338 /// body_inst: Inst.Index, // for every body_len3329 /// body_inst: Inst.Index, // for every body_len
3339 /// }3330 /// }
3340 /// }3331 /// }
3341 /// 18. multi_bodies: { // for each multi_items_info3332 /// 15. multi_bodies: { // for each multi_items_info
3342 /// prong_body: {3333 /// prong_body: {
3343 /// body_inst: Inst.Index, // for each multi_prong_info.body_len3334 /// body_inst: Inst.Index, // for each multi_prong_info.body_len
3344 /// }3335 /// }
...@@ -3363,8 +3354,6 @@ pub const Inst = struct {...@@ -3363,8 +3354,6 @@ pub const Inst = struct {
3363 any_ranges: bool,3354 any_ranges: bool,
3364 has_else: bool,3355 has_else: bool,
3365 has_under: bool,3356 has_under: bool,
3366 /// Only valid if `has_under` is also set.
3367 under_is_bare: bool,
3368 /// If true, at least one prong contains a `continue`.3357 /// If true, at least one prong contains a `continue`.
3369 /// Only valid if `has_label` is set.3358 /// Only valid if `has_label` is set.
3370 has_continue: bool,3359 has_continue: bool,
...@@ -3377,7 +3366,7 @@ pub const Inst = struct {...@@ -3377,7 +3366,7 @@ pub const Inst = struct {
3377 // NOTE maybe don't steal any more bits from poor `scalar_cases_len`3366 // NOTE maybe don't steal any more bits from poor `scalar_cases_len`
3378 // and split `Bits` into two parts instead, `raw_operand` surely3367 // and split `Bits` into two parts instead, `raw_operand` surely
3379 // wouldn't mind donating a couple of bits for that purpose...3368 // wouldn't mind donating a couple of bits for that purpose...
3380 pub const ScalarCasesLen = u23;3369 pub const ScalarCasesLen = u24;
3381 };3370 };
33823371
3383 pub const ProngInfo = packed struct(u32) {3372 pub const ProngInfo = packed struct(u32) {
...@@ -3406,12 +3395,6 @@ pub const Inst = struct {...@@ -3406,12 +3395,6 @@ pub const Inst = struct {
3406 has_tag_capture: bool,3395 has_tag_capture: bool,
3407 is_simple_noreturn: bool,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 };
34163399
3417 pub const ItemInfo = packed struct(u32) {3400 pub const ItemInfo = packed struct(u32) {
...@@ -3421,23 +3404,23 @@ pub const Inst = struct {...@@ -3421,23 +3404,23 @@ pub const Inst = struct {
3421 pub const Kind = enum(u2) {3404 pub const Kind = enum(u2) {
3422 enum_literal,3405 enum_literal,
3423 error_value,3406 error_value,
3424 number_literal,
3425 body_len,3407 body_len,
3408 under,
3426 };3409 };
34273410
3428 pub const Unwrapped = union(ItemInfo.Kind) {3411 pub const Unwrapped = union(ItemInfo.Kind) {
3429 enum_literal: Zir.NullTerminatedString,3412 enum_literal: Zir.NullTerminatedString,
3430 error_value: Zir.NullTerminatedString,3413 error_value: Zir.NullTerminatedString,
3431 number_literal: Inst.Ref,
3432 body_len: u32,3414 body_len: u32,
3415 under,
3433 };3416 };
34343417
3435 pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo {3418 pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo {
3436 const data_uncasted: u32 = switch (unwrapped) {3419 const data_uncasted: u32 = switch (unwrapped) {
3437 .enum_literal => |str_index| @intFromEnum(str_index),3420 .enum_literal => |str_index| @intFromEnum(str_index),
3438 .error_value => |str_index| @intFromEnum(str_index),3421 .error_value => |str_index| @intFromEnum(str_index),
3439 .number_literal => |zir_ref| @intFromEnum(zir_ref),
3440 .body_len => |body_len| body_len,3422 .body_len => |body_len| body_len,
3423 .under => 0,
3441 };3424 };
3442 return .{ .kind = unwrapped, .data = @intCast(data_uncasted) };3425 return .{ .kind = unwrapped, .data = @intCast(data_uncasted) };
3443 }3426 }
...@@ -3446,8 +3429,8 @@ pub const Inst = struct {...@@ -3446,8 +3429,8 @@ pub const Inst = struct {
3446 return switch (item_info.kind) {3429 return switch (item_info.kind) {
3447 .enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) },3430 .enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) },
3448 .error_value => .{ .error_value = @enumFromInt(item_info.data) },3431 .error_value => .{ .error_value = @enumFromInt(item_info.data) },
3449 .number_literal => .{ .number_literal = @enumFromInt(item_info.data) },
3450 .body_len => .{ .body_len = item_info.data },3432 .body_len => .{ .body_len = item_info.data },
3433 .under => .under,
3451 };3434 };
3452 }3435 }
34533436
...@@ -4818,9 +4801,6 @@ fn findTrackableInner(...@@ -4818,9 +4801,6 @@ fn findTrackableInner(
4818 if (zir_switch.else_case) |else_case| {4801 if (zir_switch.else_case) |else_case| {
4819 try zir.findTrackableBody(gpa, contents, defers, else_case.body);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 var extra_index = zir_switch.end;4804 var extra_index = zir_switch.end;
4825 var case_it = zir_switch.iterateCases();4805 var case_it = zir_switch.iterateCases();
4826 while (case_it.next()) |case| {4806 while (case_it.next()) |case| {
...@@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB...@@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB
5268 extra_index += 1;5248 extra_index += 1;
5269 break :else_info else_info;5249 break :else_info else_info;
5270 } else undefined;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 const scalar_cases_len: u32 = bits.scalar_cases_len;5251 const scalar_cases_len: u32 = bits.scalar_cases_len;
5282 const prong_infos: []const Inst.SwitchBlock.ProngInfo =5252 const prong_infos: []const Inst.SwitchBlock.ProngInfo =
5283 @ptrCast(zir.extra[extra_index..][0 .. scalar_cases_len + multi_cases_len]);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,20 +5290,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB
5320 .is_simple_noreturn = else_info.is_simple_noreturn,5290 .is_simple_noreturn = else_info.is_simple_noreturn,
5321 };5291 };
5322 } else null;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 return .{5293 return .{
5338 .main_operand = extra.data.raw_operand,5294 .main_operand = extra.data.raw_operand,
5339 .switch_src_node_offset = inst_data.src_node,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,7 +5300,7 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB
5344 .any_maybe_runtime_capture = bits.any_maybe_runtime_capture,5300 .any_maybe_runtime_capture = bits.any_maybe_runtime_capture,
5345 .non_err_case = non_err_case,5301 .non_err_case = non_err_case,
5346 .else_case = else_case,5302 .else_case = else_case,
5347 .under_case = under_case,5303 .has_under = bits.has_under,
5348 .prong_infos = prong_infos,5304 .prong_infos = prong_infos,
5349 .multi_case_items_lens = multi_case_items_lens,5305 .multi_case_items_lens = multi_case_items_lens,
5350 .multi_case_ranges_lens = multi_case_ranges_lens,5306 .multi_case_ranges_lens = multi_case_ranges_lens,
...@@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct {
5377 any_maybe_runtime_capture: bool,5333 any_maybe_runtime_capture: bool,
5378 non_err_case: ?Case.NonErr,5334 non_err_case: ?Case.NonErr,
5379 else_case: ?Case.Else,5335 else_case: ?Case.Else,
5380 under_case: Case.Under,5336 has_under: bool,
5381 // Refer to doc comment and `iterateCases` to access everything below correctly.5337 // Refer to doc comment and `iterateCases` to access everything below correctly.
5382 prong_infos: []const Inst.SwitchBlock.ProngInfo,5338 prong_infos: []const Inst.SwitchBlock.ProngInfo,
5383 multi_case_items_lens: []const u32,5339 multi_case_items_lens: []const u32,
...@@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct {
5411 item_infos: []const Inst.SwitchBlock.ItemInfo,5367 item_infos: []const Inst.SwitchBlock.ItemInfo,
5412 range_infos: []const [2]Inst.SwitchBlock.ItemInfo,5368 range_infos: []const [2]Inst.SwitchBlock.ItemInfo,
54135369
5414 pub fn isUnder(case: *const Case) bool {
5415 return case.index.is_under;
5416 }
5417
5418 pub const Index = packed struct(u32) {5370 pub const Index = packed struct(u32) {
5419 kind: enum(u1) { scalar, multi },5371 kind: enum(u1) { scalar, multi },
5420 is_under: bool,5372 value: u31,
5421 value: u30,
54225373
5423 pub const @"else": Case.Index = .{5374 pub const @"else": Case.Index = .{
5424 .kind = .scalar,5375 .kind = .scalar,
5425 .is_under = false,5376 .value = std.math.maxInt(u31),
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),
5433 };5377 };
5434 };5378 };
54355379
...@@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct {
5448 is_simple_noreturn: bool,5392 is_simple_noreturn: bool,
5449 };5393 };
54505394
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 pub const Iterator = struct {5395 pub const Iterator = struct {
5474 next_idx: u32,5396 next_idx: u32,
5475 under_idx: ?u32,
5476 prong_infos: []const Inst.SwitchBlock.ProngInfo,5397 prong_infos: []const Inst.SwitchBlock.ProngInfo,
5477 multi_case_items_lens: []const u32,5398 multi_case_items_lens: []const u32,
5478 multi_case_ranges_lens: ?[]const u32,5399 multi_case_ranges_lens: ?[]const u32,
...@@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct {
5486 return if (idx < scalar_cases_len) .{5407 return if (idx < scalar_cases_len) .{
5487 .index = .{5408 .index = .{
5488 .kind = .scalar,5409 .kind = .scalar,
5489 .is_under = idx == it.under_idx,
5490 .value = @intCast(idx),5410 .value = @intCast(idx),
5491 },5411 },
5492 .prong_info = it.prong_infos[idx],5412 .prong_info = it.prong_infos[idx],
...@@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct {
5495 } else .{5415 } else .{
5496 .index = .{5416 .index = .{
5497 .kind = .multi,5417 .kind = .multi,
5498 .is_under = idx == it.under_idx,
5499 .value = @intCast(idx - scalar_cases_len),5418 .value = @intCast(idx - scalar_cases_len),
5500 },5419 },
5501 .prong_info = it.prong_infos[idx],5420 .prong_info = it.prong_infos[idx],
...@@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct {...@@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct {
5516 pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator {5435 pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator {
5517 return .{5436 return .{
5518 .next_idx = 0,5437 .next_idx = 0,
5519 .under_idx = switch (unwrapped.under_case) {
5520 .none, .bare => null,
5521 .index => |index| index,
5522 },
5523 .prong_infos = unwrapped.prong_infos,5438 .prong_infos = unwrapped.prong_infos,
5524 .multi_case_items_lens = unwrapped.multi_case_items_lens,5439 .multi_case_items_lens = unwrapped.multi_case_items_lens,
5525 .multi_case_ranges_lens = unwrapped.multi_case_ranges_lens,5440 .multi_case_ranges_lens = unwrapped.multi_case_ranges_lens,
src/Sema.zig+112-129
...@@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock(...@@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock(
10753 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });10753 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
1075410754
10755 const has_else = zir_switch.else_case != null;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;
1075710757
10758 const else_case = validated_switch.else_case;10758 const else_case = validated_switch.else_case;
10759 const under_case = validated_switch.under_case;
1076010759
10761 const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: {10760 const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: {
10762 const val, const ref = if (operand_is_ref)10761 const val, const ref = if (operand_is_ref)
...@@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock(...@@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock(
10933 // we allow simple noreturn else prongs when switching on error sets!10932 // we allow simple noreturn else prongs when switching on error sets!
10934 break :find_prong .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline, true };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 unreachable; // malformed validated switch10935 unreachable; // malformed validated switch
10940 };10936 };
1094110937
...@@ -11083,10 +11079,9 @@ fn finishSwitchBr(...@@ -11083,10 +11079,9 @@ fn finishSwitchBr(
11083 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });11079 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
1108411080
11085 const has_else = zir_switch.else_case != null;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;
1108711083
11088 const else_case = validated_switch.else_case;11084 const else_case = validated_switch.else_case;
11089 const under_case = validated_switch.under_case;
1109011085
11091 const scalar_cases_len = zir_switch.scalarCasesLen();11086 const scalar_cases_len = zir_switch.scalarCasesLen();
11092 const multi_cases_len = zir_switch.multiCasesLen();11087 const multi_cases_len = zir_switch.multiCasesLen();
...@@ -11138,20 +11133,15 @@ fn finishSwitchBr(...@@ -11138,20 +11133,15 @@ fn finishSwitchBr(
11138 var case_it = zir_switch.iterateCases();11133 var case_it = zir_switch.iterateCases();
11139 var extra_index = zir_switch.end;11134 var extra_index = zir_switch.end;
1114011135
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 var cases_len: u32 = 0;11143 var cases_len: u32 = 0;
11142 while (case_it.next()) |case| {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 const item_refs = case_vals[case_val_idx..][0..case.item_infos.len];11145 const item_refs = case_vals[case_val_idx..][0..case.item_infos.len];
11156 case_val_idx += item_refs.len;11146 case_val_idx += item_refs.len;
11157 const range_refs: []const [2]Air.Inst.Ref =11147 const range_refs: []const [2]Air.Inst.Ref =
...@@ -11171,7 +11161,9 @@ fn finishSwitchBr(...@@ -11171,7 +11161,9 @@ fn finishSwitchBr(
1117111161
11172 var emit_bb = false;11162 var emit_bb = false;
11173 var any_analyze_body = false;11163 var any_analyze_body = false;
11164 var is_under_prong = false;
11174 for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| {11165 for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| {
11166 if (item_ref == .none) is_under_prong = true;
11175 if (item_info.bodyLen()) |body_len| extra_index += body_len;11167 if (item_info.bodyLen()) |body_len| extra_index += body_len;
1117611168
11177 const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach);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,48 +11311,58 @@ fn finishSwitchBr(
11319 }11311 }
11320 }11312 }
1132111313
11322 if (!prong_info.is_inline) {11314 if (prong_info.is_inline) continue; // handled above
11323 cases_len += 1;
11324 case_block.instructions.clearRetainingCapacity();
11325 case_block.error_return_trace_index = child_block.error_return_trace_index;
1132611315
11327 const prong_hint: std.builtin.BranchHint = hint: {11316 if (is_under_prong) {
11328 if (any_analyze_body) break :hint try sema.analyzeSwitchProng(11317 under_prong = .{
11329 &case_block,11318 .index = case.index,
11330 operand,11319 .body = prong_body,
11331 operand_ty,11320 .capture = case.prong_info.capture,
11332 raw_operand_ty,11321 .has_tag_capture = case.prong_info.has_tag_capture,
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
11348 };11322 };
11349 try branch_hints.append(gpa, prong_hint);11323 continue;
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));
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 }
1136511367
11366 const catch_all_extra: []const u32 = catch_all_extra: {11368 const catch_all_extra: []const u32 = catch_all_extra: {
...@@ -11499,7 +11501,7 @@ fn finishSwitchBr(...@@ -11499,7 +11501,7 @@ fn finishSwitchBr(
11499 try branch_hints.append(gpa, prong_hint);11501 try branch_hints.append(gpa, prong_hint);
1150011502
11501 try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len +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 case_block.instructions.items.len);11505 case_block.instructions.items.len);
11504 const extra_case = cases_extra.addManyAsArrayAssumeCapacity(11506 const extra_case = cases_extra.addManyAsArrayAssumeCapacity(
11505 @typeInfo(Air.SwitchBr.Case).@"struct".fields.len,11507 @typeInfo(Air.SwitchBr.Case).@"struct".fields.len,
...@@ -11555,7 +11557,7 @@ fn finishSwitchBr(...@@ -11555,7 +11557,7 @@ fn finishSwitchBr(
11555 if (analyze_catch_all_body) {11557 if (analyze_catch_all_body) {
11556 const index, const body, const capture, const has_tag_capture = switch (catch_all_case) {11558 const index, const body, const capture, const has_tag_capture = switch (catch_all_case) {
11557 .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture },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 .none => unreachable,11561 .none => unreachable,
11560 };11562 };
11561 break :hint try sema.analyzeSwitchProng(11563 break :hint try sema.analyzeSwitchProng(
...@@ -11734,7 +11736,6 @@ fn fixupSwitchContinues(...@@ -11734,7 +11736,6 @@ fn fixupSwitchContinues(
11734const ValidatedSwitchBlock = struct {11736const ValidatedSwitchBlock = struct {
11735 seen_enum_fields: []const ?LazySrcLoc,11737 seen_enum_fields: []const ?LazySrcLoc,
11736 seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc),11738 seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc),
11737 seen_sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc),
11738 seen_ranges: []const RangeSet.Range,11739 seen_ranges: []const RangeSet.Range,
11739 true_src: ?LazySrcLoc,11740 true_src: ?LazySrcLoc,
11740 false_src: ?LazySrcLoc,11741 false_src: ?LazySrcLoc,
...@@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct {...@@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct {
1174211743
11743 case_vals: []const Air.Inst.Ref,11744 case_vals: []const Air.Inst.Ref,
11744 else_case: Zir.UnwrappedSwitchBlock.Case.Else,11745 else_case: Zir.UnwrappedSwitchBlock.Case.Else,
11745 under_case: Zir.UnwrappedSwitchBlock.Case.Under.Resolved,
11746 else_err_ty: ?Type,11746 else_err_ty: ?Type,
1174711747
11748 fn iterateUnhandledItems(11748 fn iterateUnhandledItems(
...@@ -11868,7 +11868,6 @@ fn validateSwitchBlock(...@@ -11868,7 +11868,6 @@ fn validateSwitchBlock(
11868 const src = block.nodeOffset(src_node_offset);11868 const src = block.nodeOffset(src_node_offset);
11869 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });11869 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
11870 const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset });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 var extra_index = zir_switch.end;11871 var extra_index = zir_switch.end;
1187311872
11874 // We want to map values to our placeholders later on.11873 // We want to map values to our placeholders later on.
...@@ -11948,33 +11947,7 @@ fn validateSwitchBlock(...@@ -11948,33 +11947,7 @@ fn validateSwitchBlock(
11948 };11947 };
1194911948
11950 const has_else = zir_switch.else_case != null;11949 const has_else = zir_switch.else_case != null;
11951 const has_under = zir_switch.under_case != .none;11950 const has_under = zir_switch.has_under;
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 }
1197811951
11979 var case_vals: std.ArrayList(Air.Inst.Ref) = .empty;11952 var case_vals: std.ArrayList(Air.Inst.Ref) = .empty;
11980 try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len);11953 try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len);
...@@ -11991,7 +11964,6 @@ fn validateSwitchBlock(...@@ -11991,7 +11964,6 @@ fn validateSwitchBlock(
11991 var else_err_ty: ?Type = null;11964 var else_err_ty: ?Type = null;
1199211965
11993 const else_case = zir_switch.else_case orelse undefined;11966 const else_case = zir_switch.else_case orelse undefined;
11994 var under_case = zir_switch.under_case.resolve() orelse undefined;
1199511967
11996 switch (item_ty.zigTypeTag(zcu)) {11968 switch (item_ty.zigTypeTag(zcu)) {
11997 .@"union" => unreachable,11969 .@"union" => unreachable,
...@@ -12020,16 +11992,6 @@ fn validateSwitchBlock(...@@ -12020,16 +11992,6 @@ fn validateSwitchBlock(
12020 var case_it = zir_switch.iterateCases();11992 var case_it = zir_switch.iterateCases();
12021 while (case_it.next()) |case| {11993 while (case_it.next()) |case| {
12022 const prong_info = case.prong_info;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 extra_index += prong_info.body_len;11995 extra_index += prong_info.body_len;
12034 for (case.item_infos, 0..) |item_info, item_i| {11996 for (case.item_infos, 0..) |item_info, item_i| {
12035 const item_src = block.src(.{ .switch_case_item = .{11997 const item_src = block.src(.{ .switch_case_item = .{
...@@ -12037,9 +11999,34 @@ fn validateSwitchBlock(...@@ -12037,9 +11999,34 @@ fn validateSwitchBlock(
12037 .case_idx = case.index,11999 .case_idx = case.index,
12038 .item_idx = .{ .kind = .single, .value = @intCast(item_i) },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);12002 if (item_info.unwrap() == .under) {
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);12003 if (!operand_ty.isNonexhaustiveEnum(zcu)) return sema.failWithOwnedErrorMsg(block, msg: {
12042 if (!is_under) case_vals.appendAssumeCapacity(item.ref);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 for (case.range_infos, 0..) |range_info, range_i| {12031 for (case.range_infos, 0..) |range_info, range_i| {
12045 const range_offset: LazySrcLoc.Offset.SwitchItem = .{12032 const range_offset: LazySrcLoc.Offset.SwitchItem = .{
...@@ -12050,10 +12037,10 @@ fn validateSwitchBlock(...@@ -12050,10 +12037,10 @@ fn validateSwitchBlock(
12050 const range_src = block.src(.{ .switch_case_item = range_offset });12037 const range_src = block.src(.{ .switch_case_item = range_offset });
12051 const first_src = block.src(.{ .switch_case_item_range_first = range_offset });12038 const first_src = block.src(.{ .switch_case_item_range_first = range_offset });
12052 const last_src = block.src(.{ .switch_case_item_range_last = range_offset });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);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);
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);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 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);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 }
1205912046
...@@ -12285,7 +12272,6 @@ fn validateSwitchBlock(...@@ -12285,7 +12272,6 @@ fn validateSwitchBlock(
12285 return .{12272 return .{
12286 .seen_enum_fields = seen_enum_fields,12273 .seen_enum_fields = seen_enum_fields,
12287 .seen_errors = seen_errors,12274 .seen_errors = seen_errors,
12288 .seen_sparse_values = seen_sparse_values,
12289 .seen_ranges = range_set.ranges.items,12275 .seen_ranges = range_set.ranges.items,
12290 .true_src = true_src,12276 .true_src = true_src,
12291 .false_src = false_src,12277 .false_src = false_src,
...@@ -12293,7 +12279,6 @@ fn validateSwitchBlock(...@@ -12293,7 +12279,6 @@ fn validateSwitchBlock(
1229312279
12294 .case_vals = case_vals.items,12280 .case_vals = case_vals.items,
12295 .else_case = else_case,12281 .else_case = else_case,
12296 .under_case = under_case,
12297 .else_err_ty = else_err_ty,12282 .else_err_ty = else_err_ty,
12298 };12283 };
12299}12284}
...@@ -12334,19 +12319,13 @@ fn resolveSwitchBlock(...@@ -12334,19 +12319,13 @@ fn resolveSwitchBlock(
12334 var case_val_idx: usize = 0;12319 var case_val_idx: usize = 0;
12335 var extra_index = zir_switch.end;12320 var extra_index = zir_switch.end;
12336 var case_it = zir_switch.iterateCases();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 while (case_it.next()) |case| {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 const prong_info = case.prong_info;12329 const prong_info = case.prong_info;
12351 const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len);12330 const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len);
12352 extra_index += prong_body.len;12331 extra_index += prong_body.len;
...@@ -12363,6 +12342,15 @@ fn resolveSwitchBlock(...@@ -12363,6 +12342,15 @@ fn resolveSwitchBlock(
12363 const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]);12342 const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]);
12364 case_val_idx += 2 * range_refs.len;12343 case_val_idx += 2 * range_refs.len;
12365 for (item_refs) |item_ref| {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 const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable;12354 const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable;
12367 if (cond_val.eql(item_val, item_ty, zcu)) {12355 if (cond_val.eql(item_val, item_ty, zcu)) {
12368 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);12356 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);
...@@ -12421,7 +12409,6 @@ fn resolveSwitchBlock(...@@ -12421,7 +12409,6 @@ fn resolveSwitchBlock(
12421 }12409 }
1242212410
12423 const else_case = validated_switch.else_case;12411 const else_case = validated_switch.else_case;
12424 const under_case = validated_switch.under_case;
1242512412
12426 // named-only prong12413 // named-only prong
1242712414
...@@ -12452,7 +12439,7 @@ fn resolveSwitchBlock(...@@ -12452,7 +12439,7 @@ fn resolveSwitchBlock(
1245212439
12453 const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) {12440 const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) {
12454 .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline },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 .none => unreachable,12443 .none => unreachable,
12457 };12444 };
12458 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref);12445 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref);
...@@ -13169,7 +13156,6 @@ fn resolveSwitchItem(...@@ -13169,7 +13156,6 @@ fn resolveSwitchItem(
13169 extra_index: usize,13156 extra_index: usize,
13170 switch_inst: Zir.Inst.Index,13157 switch_inst: Zir.Inst.Index,
13171 prong_is_comptime_unreach: bool,13158 prong_is_comptime_unreach: bool,
13172 prong_is_inline: bool,
13173) CompileError!ResolvedSwitchItemAndExtraIndex {13159) CompileError!ResolvedSwitchItemAndExtraIndex {
13174 const pt = sema.pt;13160 const pt = sema.pt;
13175 const zcu = pt.zcu;13161 const zcu = pt.zcu;
...@@ -13180,6 +13166,7 @@ fn resolveSwitchItem(...@@ -13180,6 +13166,7 @@ fn resolveSwitchItem(
1318013166
13181 var end = extra_index;13167 var end = extra_index;
13182 const uncoerced: Air.Inst.Ref, const uncoerced_ty: Type = uncoerced: switch (item_info.unwrap()) {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 .enum_literal => |str_index| {13170 .enum_literal => |str_index| {
13184 const zir_str = sema.code.nullTerminatedString(str_index);13171 const zir_str = sema.code.nullTerminatedString(str_index);
13185 const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls);13172 const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls);
...@@ -13198,10 +13185,6 @@ fn resolveSwitchItem(...@@ -13198,10 +13185,6 @@ fn resolveSwitchItem(
13198 } }));13185 } }));
13199 break :uncoerced .{ uncoerced, err_set_ty };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 .body_len => |body_len| {13188 .body_len => |body_len| {
13206 const body = sema.code.bodySlice(extra_index, body_len);13189 const body = sema.code.bodySlice(extra_index, body_len);
13207 end += body.len;13190 end += body.len;
...@@ -13231,7 +13214,7 @@ fn resolveSwitchItem(...@@ -13231,7 +13214,7 @@ fn resolveSwitchItem(
13231 .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| {13214 .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| {
13232 break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty);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 break :item_ref uncoerced;13218 break :item_ref uncoerced;
13236 },13219 },
13237 .from_anyerror => {},13220 .from_anyerror => {},
src/Zcu.zig+1-41
...@@ -1742,27 +1742,6 @@ pub const SrcLoc = struct {...@@ -1742,27 +1742,6 @@ pub const SrcLoc = struct {
1742 } else unreachable;1742 } else unreachable;
1743 },1743 },
17441744
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 .node_offset_switch_range => |node_off| {1745 .node_offset_switch_range => |node_off| {
1767 const tree = try src_loc.file_scope.getTree(zcu);1746 const tree = try src_loc.file_scope.getTree(zcu);
1768 const switch_node = node_off.toAbsolute(src_loc.base_node);1747 const switch_node = node_off.toAbsolute(src_loc.base_node);
...@@ -2176,7 +2155,6 @@ pub const SrcLoc = struct {...@@ -2176,7 +2155,6 @@ pub const SrcLoc = struct {
21762155
2177 var multi_i: u32 = 0;2156 var multi_i: u32 = 0;
2178 var scalar_i: u32 = 0;2157 var scalar_i: u32 = 0;
2179 var underscore_node: Ast.Node.OptionalIndex = .none;
2180 const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| {2158 const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| {
2181 const case = tree.fullSwitchCase(case_node).?;2159 const case = tree.fullSwitchCase(case_node).?;
2182 if (case.ast.values.len == 0) {2160 if (case.ast.values.len == 0) {
...@@ -2185,17 +2163,6 @@ pub const SrcLoc = struct {...@@ -2185,17 +2163,6 @@ pub const SrcLoc = struct {
2185 }2163 }
2186 continue :case;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 }
21992166
2200 const is_multi = case.ast.values.len != 1 or2167 const is_multi = case.ast.values.len != 1 or
2201 tree.nodeTag(case.ast.values[0]) == .switch_range;2168 tree.nodeTag(case.ast.values[0]) == .switch_range;
...@@ -2220,7 +2187,6 @@ pub const SrcLoc = struct {...@@ -2220,7 +2187,6 @@ pub const SrcLoc = struct {
2220 .switch_case_item_range_last,2187 .switch_case_item_range_last,
2221 => |x| item_idx: {2188 => |x| item_idx: {
2222 assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else");2189 assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else");
2223 assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.bare_under);
2224 break :item_idx x.item_idx;2190 break :item_idx x.item_idx;
2225 },2191 },
2226 .switch_capture, .switch_tag_capture => {2192 .switch_capture, .switch_tag_capture => {
...@@ -2247,9 +2213,7 @@ pub const SrcLoc = struct {...@@ -2247,9 +2213,7 @@ pub const SrcLoc = struct {
2247 .single => {2213 .single => {
2248 var item_i: u32 = 0;2214 var item_i: u32 = 0;
2249 for (case.ast.values) |item_node| {2215 for (case.ast.values) |item_node| {
2250 if (item_node.toOptional() == underscore_node or2216 if (tree.nodeTag(item_node) == .switch_range) {
2251 tree.nodeTag(item_node) == .switch_range)
2252 {
2253 continue;2217 continue;
2254 }2218 }
2255 if (item_i != want_item_idx.value) {2219 if (item_i != want_item_idx.value) {
...@@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct {...@@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct {
2456 /// by taking this AST node index offset from the containing base node,2420 /// by taking this AST node index offset from the containing base node,
2457 /// which points to a switch expression AST node. Next, navigate to the else prong.2421 /// which points to a switch expression AST node. Next, navigate to the else prong.
2458 node_offset_switch_else_prong: Ast.Node.Offset,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 /// The source location points to all the ranges of a switch expression, found2423 /// The source location points to all the ranges of a switch expression, found
2464 /// by taking this AST node index offset from the containing base node,2424 /// by taking this AST node index offset from the containing base node,
2465 /// which points to a switch expression AST node. Next, navigate to any of the2425 /// 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,15 +2021,6 @@ const Writer = struct {
2021 try stream.writeAll("else => ");2021 try stream.writeAll("else => ");
2022 try self.writeBracedBody(stream, else_case.body);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 }
20332024
2034 var case_it = zir_switch.iterateCases();2025 var case_it = zir_switch.iterateCases();
2035 while (case_it.next()) |case| {2026 while (case_it.next()) |case| {
...@@ -2043,14 +2034,8 @@ const Writer = struct {...@@ -2043,14 +2034,8 @@ const Writer = struct {
2043 const prong_body = self.code.bodySlice(extra_index, prong_info.body_len);2034 const prong_body = self.code.bodySlice(extra_index, prong_info.body_len);
2044 extra_index += prong_body.len;2035 extra_index += prong_body.len;
20452036
2046 var first_item: bool = true;2037 for (case.item_infos, 0..) |item_info, i| {
2047 if (case.isUnder()) {2038 if (i > 0) try stream.writeAll(", ");
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;
20542039
2055 switch (item_info.unwrap()) {2040 switch (item_info.unwrap()) {
2056 .enum_literal => |str_index| {2041 .enum_literal => |str_index| {
...@@ -2061,9 +2046,7 @@ const Writer = struct {...@@ -2061,9 +2046,7 @@ const Writer = struct {
2061 const str = self.code.nullTerminatedString(str_index);2046 const str = self.code.nullTerminatedString(str_index);
2062 try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});2047 try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
2063 },2048 },
2064 .number_literal => |zir_ref| {2049 .under => try stream.writeByte('_'),
2065 try self.writeInstRef(stream, zir_ref);
2066 },
2067 .body_len => |body_len| {2050 .body_len => |body_len| {
2068 const item_body = self.code.bodySlice(extra_index, body_len);2051 const item_body = self.code.bodySlice(extra_index, body_len);
2069 extra_index += item_body.len;2052 extra_index += item_body.len;
...@@ -2071,33 +2054,40 @@ const Writer = struct {...@@ -2071,33 +2054,40 @@ const Writer = struct {
2071 },2054 },
2072 }2055 }
2073 }2056 }
2074 for (case.range_infos) |range_info| {2057 for (case.range_infos, 0..) |range_info, i| {
2075 if (!first_item) try stream.writeAll(", ");2058 if (i > 0 and case.item_infos.len == 0) try stream.writeAll(", ");
2076 first_item = false;2059 switch (range_info[0].unwrap()) {
20772060 .enum_literal => |str_index| {
2078 var first_range_item = true;2061 const str = self.code.nullTerminatedString(str_index);
2079 for (&range_info) |item_info| {2062 try stream.print("\".{f}\"", .{std.zig.fmtString(str)});
2080 if (!first_range_item) try stream.writeAll("...");2063 },
2081 first_range_item = false;2064 .error_value => |str_index| {
20822065 const str = self.code.nullTerminatedString(str_index);
2083 switch (item_info.unwrap()) {2066 try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
2084 .enum_literal => |str_index| {2067 },
2085 const str = self.code.nullTerminatedString(str_index);2068 .under => unreachable, // '_..._' is not allowed
2086 try stream.print("\".{f}\"", .{std.zig.fmtString(str)});2069 .body_len => |body_len| {
2087 },2070 const item_body = self.code.bodySlice(extra_index, body_len);
2088 .error_value => |str_index| {2071 extra_index += item_body.len;
2089 const str = self.code.nullTerminatedString(str_index);2072 try self.writeBracedDecl(stream, item_body);
2090 try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});2073 },
2091 },2074 }
2092 .number_literal => |zir_ref| {2075 try stream.writeAll("...");
2093 try self.writeInstRef(stream, zir_ref);2076 switch (range_info[1].unwrap()) {
2094 },2077 .enum_literal => |str_index| {
2095 .body_len => |body_len| {2078 const str = self.code.nullTerminatedString(str_index);
2096 const item_body = self.code.bodySlice(extra_index, body_len);2079 try stream.print("\".{f}\"", .{std.zig.fmtString(str)});
2097 extra_index += item_body.len;2080 },
2098 try self.writeBracedDecl(stream, item_body);2081 .error_value => |str_index| {
2099 },2082 const str = self.code.nullTerminatedString(str_index);
2100 }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 try stream.writeAll(" => ");2093 try stream.writeAll(" => ");