@@ -7652,11 +7652,12 @@ fn switchExpr(
7652
7652
var scalar_cases_len: u32 = 0;
7653
7653
var multi_cases_len: u32 = 0;
7654
7654
var inline_cases_len: u32 = 0;
7655
- var special_prong: Zir.SpecialProng = .none;
7656
- var special_node: Ast.Node.OptionalIndex = .none;
7655
+ var else_case_node: Ast.Node.OptionalIndex = .none;
7657
7656
var else_src: ?Ast.TokenIndex = null;
7658
- var underscore_src: ? Ast.TokenIndex = null ;
7657
+ var underscore_case_node: Ast.Node.OptionalIndex = .none ;
7659
7658
var underscore_node: Ast.Node.OptionalIndex = .none;
7659
+ var underscore_src: ?Ast.TokenIndex = null;
7660
+ var underscore_additional_items: Zir.SpecialProngs.AdditionalItems = .none;
7660
7661
for (case_nodes) |case_node| {
7661
7662
const case = tree.fullSwitchCase(case_node).?;
7662
7663
if (case.payload_token) |payload_token| {
@@ -7677,6 +7678,7 @@ fn switchExpr(
7677
7678
any_non_inline_capture = true;
7678
7679
}
7679
7680
}
7681
+
7680
7682
// Check for else prong.
7681
7683
if (case.ast.values.len == 0) {
7682
7684
const case_src = case.ast.arrow_token - 1;
@@ -7693,40 +7695,21 @@ fn switchExpr(
7693
7695
),
7694
7696
},
7695
7697
);
7696
- } else if (underscore_src) |some_underscore| {
7697
- return astgen.failNodeNotes(
7698
- node,
7699
- "else and '_' prong in switch expression",
7700
- .{},
7701
- &[_]u32{
7702
- try astgen.errNoteTok(
7703
- case_src,
7704
- "else prong here",
7705
- .{},
7706
- ),
7707
- try astgen.errNoteTok(
7708
- some_underscore,
7709
- "'_' prong here",
7710
- .{},
7711
- ),
7712
- },
7713
- );
7714
7698
}
7715
- special_node = case_node.toOptional();
7716
- special_prong = .@"else";
7699
+ else_case_node = case_node.toOptional();
7717
7700
else_src = case_src;
7718
7701
continue;
7719
7702
}
7720
7703
7721
7704
// Check for '_' prong.
7722
- var found_underscore = false;
7705
+ var case_has_underscore = false;
7723
7706
for (case.ast.values) |val| {
7724
7707
switch (tree.nodeTag(val)) {
7725
7708
.identifier => if (mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) {
7726
- const case_src = case.ast.arrow_token - 1 ;
7709
+ const val_src = tree.nodeMainToken(val) ;
7727
7710
if (underscore_src) |src| {
7728
7711
return astgen.failTokNotes(
7729
- case_src ,
7712
+ val_src ,
7730
7713
"multiple '_' prongs in switch expression",
7731
7714
.{},
7732
7715
&[_]u32{
@@ -7737,39 +7720,26 @@ fn switchExpr(
7737
7720
),
7738
7721
},
7739
7722
);
7740
- } else if (else_src) |some_else| {
7741
- return astgen.failNodeNotes(
7742
- node,
7743
- "else and '_' prong in switch expression",
7744
- .{},
7745
- &[_]u32{
7746
- try astgen.errNoteTok(
7747
- some_else,
7748
- "else prong here",
7749
- .{},
7750
- ),
7751
- try astgen.errNoteTok(
7752
- case_src,
7753
- "'_' prong here",
7754
- .{},
7755
- ),
7756
- },
7757
- );
7758
7723
}
7759
7724
if (case.inline_token != null) {
7760
- return astgen.failTok(case_src , "cannot inline '_' prong", .{});
7725
+ return astgen.failTok(val_src , "cannot inline '_' prong", .{});
7761
7726
}
7762
- special_node = case_node.toOptional();
7763
- special_prong = if (case.ast.values.len == 1) .under else .absorbing_under;
7764
- underscore_src = case_src;
7727
+ underscore_case_node = case_node.toOptional();
7728
+ underscore_src = val_src;
7765
7729
underscore_node = val.toOptional();
7766
- found_underscore = true;
7730
+ underscore_additional_items = switch (case.ast.values.len) {
7731
+ 0 => unreachable,
7732
+ 1 => .none,
7733
+ 2 => .one,
7734
+ else => .many,
7735
+ };
7736
+ case_has_underscore = true;
7767
7737
},
7768
7738
.string_literal => return astgen.failNode(val, "cannot switch on strings", .{}),
7769
7739
else => {},
7770
7740
}
7771
7741
}
7772
- if (found_underscore ) continue;
7742
+ if (case_has_underscore ) continue;
7773
7743
7774
7744
if (case.ast.values.len == 1 and tree.nodeTag(case.ast.values[0]) != .switch_range) {
7775
7745
scalar_cases_len += 1;
@@ -7781,6 +7751,14 @@ fn switchExpr(
7781
7751
}
7782
7752
}
7783
7753
7754
+ const special_prongs: Zir.SpecialProngs = .init(
7755
+ else_src != null,
7756
+ underscore_src != null,
7757
+ underscore_additional_items,
7758
+ );
7759
+ const has_else = special_prongs.hasElse();
7760
+ const has_under = special_prongs.hasUnder();
7761
+
7784
7762
const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none };
7785
7763
7786
7764
astgen.advanceSourceCursorToNode(operand_node);
@@ -7801,7 +7779,9 @@ fn switchExpr(
7801
7779
const payloads = &astgen.scratch;
7802
7780
const scratch_top = astgen.scratch.items.len;
7803
7781
const case_table_start = scratch_top;
7804
- const scalar_case_table = case_table_start + @intFromBool(special_prong != .none);
7782
+ const else_case_index = if (has_else) case_table_start else undefined;
7783
+ const under_case_index = if (has_under) case_table_start + @intFromBool(has_else) else undefined;
7784
+ const scalar_case_table = case_table_start + @intFromBool(has_else) + @intFromBool(has_under);
7805
7785
const multi_case_table = scalar_case_table + scalar_cases_len;
7806
7786
const case_table_end = multi_case_table + multi_cases_len;
7807
7787
try astgen.scratch.resize(gpa, case_table_end);
@@ -7933,9 +7913,19 @@ fn switchExpr(
7933
7913
7934
7914
const header_index: u32 = @intCast(payloads.items.len);
7935
7915
const body_len_index = if (is_multi_case) blk: {
7936
- if (case_node.toOptional() == special_node) {
7937
- assert(special_prong == .absorbing_under);
7938
- payloads.items[case_table_start] = header_index;
7916
+ if (case_node.toOptional() == underscore_case_node) {
7917
+ payloads.items[under_case_index] = header_index;
7918
+ if (special_prongs.hasOneAdditionalItem()) {
7919
+ try payloads.resize(gpa, header_index + 2); // item, body_len
7920
+ const maybe_item_node = case.ast.values[0];
7921
+ const item_node = if (maybe_item_node.toOptional() == underscore_node)
7922
+ case.ast.values[1]
7923
+ else
7924
+ maybe_item_node;
7925
+ const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node, .switch_item);
7926
+ payloads.items[header_index] = @intFromEnum(item_inst);
7927
+ break :blk header_index + 1;
7928
+ }
7939
7929
} else {
7940
7930
payloads.items[multi_case_table + multi_case_index] = header_index;
7941
7931
multi_case_index += 1;
@@ -7975,9 +7965,13 @@ fn switchExpr(
7975
7965
payloads.items[header_index] = items_len;
7976
7966
payloads.items[header_index + 1] = ranges_len;
7977
7967
break :blk header_index + 2;
7978
- } else if (case_node.toOptional() == special_node) blk: {
7979
- assert(special_prong != .absorbing_under);
7980
- payloads.items[case_table_start] = header_index;
7968
+ } else if (case_node.toOptional() == else_case_node) blk: {
7969
+ payloads.items[else_case_index] = header_index;
7970
+ try payloads.resize(gpa, header_index + 1); // body_len
7971
+ break :blk header_index;
7972
+ } else if (case_node.toOptional() == underscore_case_node) blk: {
7973
+ assert(!special_prongs.hasAdditionalItems());
7974
+ payloads.items[under_case_index] = header_index;
7981
7975
try payloads.resize(gpa, header_index + 1); // body_len
7982
7976
break :blk header_index;
7983
7977
} else blk: {
@@ -8038,7 +8032,7 @@ fn switchExpr(
8038
8032
.operand = raw_operand,
8039
8033
.bits = Zir.Inst.SwitchBlock.Bits{
8040
8034
.has_multi_cases = multi_cases_len != 0,
8041
- .special_prong = special_prong ,
8035
+ .special_prongs = special_prongs ,
8042
8036
.any_has_tag_capture = any_has_tag_capture,
8043
8037
.any_non_inline_capture = any_non_inline_capture,
8044
8038
.has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue,
@@ -8057,29 +8051,40 @@ fn switchExpr(
8057
8051
const zir_datas = astgen.instructions.items(.data);
8058
8052
zir_datas[@intFromEnum(switch_block)].pl_node.payload_index = payload_index;
8059
8053
8060
- var normal_case_table_start = case_table_start;
8061
- if (special_prong != .none) {
8062
- normal_case_table_start += 1;
8063
-
8064
- const start_index = payloads.items[case_table_start];
8054
+ if (has_else) {
8055
+ const start_index = payloads.items[else_case_index];
8056
+ var end_index = start_index + 1;
8057
+ const prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(payloads.items[start_index]);
8058
+ end_index += prong_info.body_len;
8059
+ astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]);
8060
+ }
8061
+ if (has_under) {
8062
+ const start_index = payloads.items[under_case_index];
8065
8063
var body_len_index = start_index;
8066
8064
var end_index = start_index;
8067
- if (special_prong == .absorbing_under) {
8068
- body_len_index += 2;
8069
- const items_len = payloads.items[start_index];
8070
- const ranges_len = payloads.items[start_index + 1];
8071
- end_index += 3 + items_len + 2 * ranges_len;
8072
- } else {
8073
- end_index += 1;
8065
+ switch (underscore_additional_items) {
8066
+ .none => {
8067
+ end_index += 1;
8068
+ },
8069
+ .one => {
8070
+ body_len_index += 1;
8071
+ end_index += 2;
8072
+ },
8073
+ .many => {
8074
+ body_len_index += 2;
8075
+ const items_len = payloads.items[start_index];
8076
+ const ranges_len = payloads.items[start_index + 1];
8077
+ end_index += 3 + items_len + 2 * ranges_len;
8078
+ },
8074
8079
}
8075
8080
const prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(payloads.items[body_len_index]);
8076
8081
end_index += prong_info.body_len;
8077
8082
astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]);
8078
8083
}
8079
- for (payloads.items[normal_case_table_start ..case_table_end], 0..) |start_index, i| {
8084
+ for (payloads.items[scalar_case_table ..case_table_end], 0..) |start_index, i| {
8080
8085
var body_len_index = start_index;
8081
8086
var end_index = start_index;
8082
- const table_index = normal_case_table_start + i;
8087
+ const table_index = scalar_case_table + i;
8083
8088
if (table_index < multi_case_table) {
8084
8089
body_len_index += 1;
8085
8090
end_index += 2;
0 commit comments