mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Zir: simplify '_' prong of 'switch' statements
This commit is contained in:
+19
-69
@@ -7267,11 +7267,7 @@ fn switchExpr(
|
||||
var total_items_len: usize = 0;
|
||||
var total_ranges_len: usize = 0;
|
||||
var else_case_node: Ast.Node.OptionalIndex = .none;
|
||||
var else_src: ?Ast.TokenIndex = null;
|
||||
var under_case_node: Ast.Node.OptionalIndex = .none;
|
||||
var underscore_node: Ast.Node.OptionalIndex = .none;
|
||||
var underscore_src: ?Ast.TokenIndex = null;
|
||||
var under_is_bare = false;
|
||||
for (case_nodes) |case_node| {
|
||||
const case = tree.fullSwitchCase(case_node).?;
|
||||
if (case.payload_token) |payload_token| {
|
||||
@@ -7304,22 +7300,21 @@ fn switchExpr(
|
||||
|
||||
// Check for else prong.
|
||||
if (case.ast.values.len == 0) {
|
||||
const case_src = case.ast.arrow_token - 1;
|
||||
if (else_src) |src| {
|
||||
if (else_case_node.unwrap()) |prev_case_node| {
|
||||
const prev_else_tok = tree.fullSwitchCase(prev_case_node).?.ast.arrow_token - 1;
|
||||
const else_tok = case.ast.arrow_token - 1;
|
||||
return astgen.failTokNotes(
|
||||
case_src,
|
||||
else_tok,
|
||||
"multiple else prongs in switch expression",
|
||||
.{},
|
||||
&.{try astgen.errNoteTok(src, "previous else prong here", .{})},
|
||||
&.{try astgen.errNoteTok(prev_else_tok, "previous else prong here", .{})},
|
||||
);
|
||||
}
|
||||
else_case_node = case_node.toOptional();
|
||||
else_src = case_src;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for '_' prong and ranges.
|
||||
var case_has_underscore = false;
|
||||
var case_has_ranges = false;
|
||||
for (case.ast.values) |val| {
|
||||
switch (tree.nodeTag(val)) {
|
||||
@@ -7329,10 +7324,10 @@ fn switchExpr(
|
||||
},
|
||||
.string_literal => return astgen.failNode(val, "cannot switch on strings", .{}),
|
||||
else => |tag| {
|
||||
total_items_len += 1;
|
||||
if (tag == .identifier and
|
||||
mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_"))
|
||||
{
|
||||
const val_src = tree.nodeMainToken(val);
|
||||
if (is_err_switch) {
|
||||
const case_src = case.ast.arrow_token - 1;
|
||||
return astgen.failTokNotes(
|
||||
@@ -7348,30 +7343,24 @@ fn switchExpr(
|
||||
},
|
||||
);
|
||||
}
|
||||
if (underscore_src) |src| {
|
||||
return astgen.failTokNotes(
|
||||
val_src,
|
||||
if (underscore_node.unwrap()) |prev_src| {
|
||||
return astgen.failNodeNotes(
|
||||
val,
|
||||
"multiple '_' prongs in switch expression",
|
||||
.{},
|
||||
&.{try astgen.errNoteTok(src, "previous '_' prong here", .{})},
|
||||
&.{try astgen.errNoteNode(prev_src, "previous '_' prong here", .{})},
|
||||
);
|
||||
}
|
||||
if (case.inline_token != null) {
|
||||
return astgen.failTok(val_src, "cannot inline '_' prong", .{});
|
||||
return astgen.failNode(val, "cannot inline '_' prong", .{});
|
||||
}
|
||||
under_case_node = case_node.toOptional();
|
||||
underscore_src = val_src;
|
||||
underscore_node = val.toOptional();
|
||||
under_is_bare = case.ast.values.len == 1;
|
||||
case_has_underscore = true;
|
||||
} else {
|
||||
total_items_len += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const case_len = case.ast.values.len - @intFromBool(case_has_underscore);
|
||||
const case_len = case.ast.values.len;
|
||||
if (case_len == 1 and !case_has_ranges) {
|
||||
scalar_cases_len += 1;
|
||||
} else if (case_len >= 1) {
|
||||
@@ -7379,9 +7368,8 @@ fn switchExpr(
|
||||
}
|
||||
}
|
||||
|
||||
const has_else = else_src != null;
|
||||
const has_under = underscore_src != null;
|
||||
if (under_is_bare) assert(has_under); // make sure that the former implies the latter
|
||||
const has_else = else_case_node != .none;
|
||||
const has_under = underscore_node != .none;
|
||||
if (is_err_switch) assert(!has_under); // should have failed by now
|
||||
const any_ranges = total_ranges_len > 0;
|
||||
|
||||
@@ -7430,10 +7418,8 @@ fn switchExpr(
|
||||
|
||||
var non_err_prong_body_start: u32 = undefined;
|
||||
var else_prong_body_start: u32 = undefined;
|
||||
var bare_under_prong_body_start: u32 = undefined;
|
||||
var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined;
|
||||
var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined;
|
||||
var under_extra: u32 = undefined;
|
||||
|
||||
var block_scope = parent_gz.makeSubBlock(scope);
|
||||
// block_scope not used for collecting instructions
|
||||
@@ -7688,7 +7674,6 @@ fn switchExpr(
|
||||
for (case_nodes) |case_node| {
|
||||
const case = tree.fullSwitchCase(case_node).?;
|
||||
|
||||
const case_has_under = case_node.toOptional() == under_case_node;
|
||||
const ranges_len: u32 = if (any_ranges) blk: {
|
||||
var ranges_len: u32 = 0;
|
||||
for (case.ast.values) |value| {
|
||||
@@ -7696,14 +7681,13 @@ fn switchExpr(
|
||||
}
|
||||
break :blk ranges_len;
|
||||
} else 0;
|
||||
const items_len: u32 = @intCast(case.ast.values.len - ranges_len - @intFromBool(case_has_under));
|
||||
const items_len: u32 = @intCast(case.ast.values.len - ranges_len);
|
||||
const is_multi_case = items_len > 1 or ranges_len > 0;
|
||||
|
||||
// item/range bodies in order of occurence
|
||||
var item_i: usize = 0;
|
||||
var range_i: usize = 0;
|
||||
for (case.ast.values) |value| {
|
||||
if (value.toOptional() == underscore_node) continue;
|
||||
const is_range = tree.nodeTag(value) == .switch_range;
|
||||
const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined;
|
||||
const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value};
|
||||
@@ -7722,16 +7706,9 @@ fn switchExpr(
|
||||
const str_index = try astgen.identAsString(ident_token);
|
||||
break :blk .wrap(.{ .error_value = str_index });
|
||||
},
|
||||
.number_literal => {
|
||||
// We don't actually need a final result type for number
|
||||
// literals, they can just be turned into `comptime_int`
|
||||
// or `comptime_float` as usual and then be coerced to
|
||||
// the correct type later during semantic analysis.
|
||||
assert(scratch_scope.instructions_top == GenZir.unstacked_top); // important! we emit into `parent_gz` which `scratch_scope` is stacked on top of
|
||||
const zir_ref = try comptimeExpr(parent_gz, scope, .{ .rl = .none }, item, .switch_item);
|
||||
break :blk .wrap(.{ .number_literal = zir_ref });
|
||||
},
|
||||
else => {
|
||||
else => if (value.toOptional() == underscore_node) {
|
||||
break :blk .wrap(.under);
|
||||
} else {
|
||||
scratch_scope.instructions_top = parent_gz.instructions.items.len;
|
||||
defer scratch_scope.unstack();
|
||||
const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal);
|
||||
@@ -7957,25 +7934,6 @@ fn switchExpr(
|
||||
break :prong_body;
|
||||
}
|
||||
|
||||
if (case_has_under) {
|
||||
// We're either writing under_prong_info or under_index here.
|
||||
if (under_is_bare) {
|
||||
assert(case.ast.values.len == 1); // only `_`
|
||||
const bare_under_info: Zir.Inst.SwitchBlock.ProngInfo.BareUnder = .{
|
||||
.body_len = @intCast(body_len),
|
||||
.capture = capture,
|
||||
.has_tag_capture = has_tag_capture,
|
||||
};
|
||||
under_extra = @bitCast(bare_under_info);
|
||||
bare_under_prong_body_start = body_start;
|
||||
break :prong_body;
|
||||
} else if (is_multi_case) {
|
||||
under_extra = scalar_cases_len + multi_case_index;
|
||||
} else {
|
||||
under_extra = scalar_case_index;
|
||||
}
|
||||
}
|
||||
|
||||
// We allow prongs with error items which are not inside the error set
|
||||
// being switched on if their body is `=> comptime unreachable,`.
|
||||
const is_comptime_unreach = comptime_unreach: {
|
||||
@@ -8003,7 +7961,7 @@ fn switchExpr(
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(scalar_case_index + multi_case_index + @intFromBool(has_else) + @intFromBool(under_is_bare) == case_nodes.len);
|
||||
assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len);
|
||||
assert(multi_items_infos_start + multi_item_offset == bodies_start);
|
||||
|
||||
if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) {
|
||||
@@ -8024,7 +7982,6 @@ fn switchExpr(
|
||||
@intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset
|
||||
@intFromBool(needs_non_err_handling) + // non_err_info
|
||||
@intFromBool(has_else) + // else_info
|
||||
@intFromBool(has_under) + // under_prong_info or under_index
|
||||
payloads.items.len - body_table_end); // item infos and bodies
|
||||
|
||||
// singular pieces of data
|
||||
@@ -8035,7 +7992,6 @@ fn switchExpr(
|
||||
.any_ranges = any_ranges,
|
||||
.has_else = has_else,
|
||||
.has_under = has_under,
|
||||
.under_is_bare = under_is_bare,
|
||||
.has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue,
|
||||
.any_maybe_runtime_capture = any_maybe_runtime_capture,
|
||||
.payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder,
|
||||
@@ -8054,7 +8010,6 @@ fn switchExpr(
|
||||
astgen.extra.appendAssumeCapacity(@bitCast(non_err_info));
|
||||
}
|
||||
if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info));
|
||||
if (has_under) astgen.extra.appendAssumeCapacity(under_extra);
|
||||
|
||||
const extra_payloads_start = astgen.extra.items.len;
|
||||
|
||||
@@ -8070,11 +8025,6 @@ fn switchExpr(
|
||||
const body = payloads.items[else_prong_body_start..][0..else_info.body_len];
|
||||
astgen.extra.appendSliceAssumeCapacity(body);
|
||||
}
|
||||
if (under_is_bare) {
|
||||
const under_prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(under_extra);
|
||||
const body = payloads.items[bare_under_prong_body_start..][0..under_prong_info.body_len];
|
||||
astgen.extra.appendSliceAssumeCapacity(body);
|
||||
}
|
||||
for (0..scalar_cases_len) |scalar_i| {
|
||||
const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]);
|
||||
const item_body_start = payloads.items[scalar_body_table + scalar_i];
|
||||
|
||||
+19
-104
@@ -3303,34 +3303,25 @@ pub const Inst = struct {
|
||||
/// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union.
|
||||
/// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union.
|
||||
/// 5. else_info: ProngInfo.Else, // If has_else is set.
|
||||
/// 6. under_info: ProngInfo.Under, // If has_under is set and
|
||||
/// // under_is_bare is set.
|
||||
/// 7. under_index: u32, // If has_under is set and
|
||||
/// // under_is_bare is *not* set.
|
||||
/// // Index into switch cases.
|
||||
/// 8. scalar_prong_info: ProngInfo, // for every scalar_cases_len
|
||||
/// 9. multi_prong_info: ProngInfo, // for every multi_cases_len
|
||||
/// 10. multi_case_items_len: u32, // for every multi_cases_len
|
||||
/// 11. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len
|
||||
/// 12. scalar_item_info: ItemInfo, // for every scalar_cases_len
|
||||
/// 13. multi_items_info: { // for every multi_cases_len
|
||||
/// 6. scalar_prong_info: ProngInfo, // for every scalar_cases_len
|
||||
/// 7. multi_prong_info: ProngInfo, // for every multi_cases_len
|
||||
/// 8. multi_case_items_len: u32, // for every multi_cases_len
|
||||
/// 9. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len
|
||||
/// 10. scalar_item_info: ItemInfo, // for every scalar_cases_len
|
||||
/// 11. multi_items_info: { // for every multi_cases_len
|
||||
/// item_info: ItemInfo, // for each multi_case_items_len
|
||||
/// range_items_info: { // for each multi_case_ranges_len
|
||||
/// first_info: ItemInfo,
|
||||
/// last_info: ItemInfo,
|
||||
/// }
|
||||
/// }
|
||||
/// 14. non_err_body {
|
||||
/// 12. non_err_body {
|
||||
/// body_inst: Index // for every non_err_info.body_len
|
||||
/// }
|
||||
/// 15. else_body: { // If has_else is set.
|
||||
/// 13. else_body: { // If has_else is set.
|
||||
/// body_inst: Inst.Index, // for every else_info.body_len
|
||||
/// }
|
||||
/// 16. under_body: { // If has_under is set and
|
||||
/// // under_is_bare is set.
|
||||
/// body_inst: Inst.Index, // for every under_info.body_len
|
||||
/// }
|
||||
/// 17. scalar_bodies: { // for every scalar_cases_len
|
||||
/// 14. scalar_bodies: { // for every scalar_cases_len
|
||||
/// prong_body: { // for each body_len in scalar_prong_info
|
||||
/// body_inst: Inst.Index, // for every body_len
|
||||
/// }
|
||||
@@ -3338,7 +3329,7 @@ pub const Inst = struct {
|
||||
/// body_inst: Inst.Index, // for every body_len
|
||||
/// }
|
||||
/// }
|
||||
/// 18. multi_bodies: { // for each multi_items_info
|
||||
/// 15. multi_bodies: { // for each multi_items_info
|
||||
/// prong_body: {
|
||||
/// body_inst: Inst.Index, // for each multi_prong_info.body_len
|
||||
/// }
|
||||
@@ -3363,8 +3354,6 @@ pub const Inst = struct {
|
||||
any_ranges: bool,
|
||||
has_else: bool,
|
||||
has_under: bool,
|
||||
/// Only valid if `has_under` is also set.
|
||||
under_is_bare: bool,
|
||||
/// If true, at least one prong contains a `continue`.
|
||||
/// Only valid if `has_label` is set.
|
||||
has_continue: bool,
|
||||
@@ -3377,7 +3366,7 @@ pub const Inst = struct {
|
||||
// NOTE maybe don't steal any more bits from poor `scalar_cases_len`
|
||||
// and split `Bits` into two parts instead, `raw_operand` surely
|
||||
// wouldn't mind donating a couple of bits for that purpose...
|
||||
pub const ScalarCasesLen = u23;
|
||||
pub const ScalarCasesLen = u24;
|
||||
};
|
||||
|
||||
pub const ProngInfo = packed struct(u32) {
|
||||
@@ -3406,12 +3395,6 @@ pub const Inst = struct {
|
||||
has_tag_capture: bool,
|
||||
is_simple_noreturn: bool,
|
||||
};
|
||||
|
||||
pub const BareUnder = packed struct(u32) {
|
||||
body_len: u29,
|
||||
capture: ProngInfo.Capture,
|
||||
has_tag_capture: bool,
|
||||
};
|
||||
};
|
||||
|
||||
pub const ItemInfo = packed struct(u32) {
|
||||
@@ -3421,23 +3404,23 @@ pub const Inst = struct {
|
||||
pub const Kind = enum(u2) {
|
||||
enum_literal,
|
||||
error_value,
|
||||
number_literal,
|
||||
body_len,
|
||||
under,
|
||||
};
|
||||
|
||||
pub const Unwrapped = union(ItemInfo.Kind) {
|
||||
enum_literal: Zir.NullTerminatedString,
|
||||
error_value: Zir.NullTerminatedString,
|
||||
number_literal: Inst.Ref,
|
||||
body_len: u32,
|
||||
under,
|
||||
};
|
||||
|
||||
pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo {
|
||||
const data_uncasted: u32 = switch (unwrapped) {
|
||||
.enum_literal => |str_index| @intFromEnum(str_index),
|
||||
.error_value => |str_index| @intFromEnum(str_index),
|
||||
.number_literal => |zir_ref| @intFromEnum(zir_ref),
|
||||
.body_len => |body_len| body_len,
|
||||
.under => 0,
|
||||
};
|
||||
return .{ .kind = unwrapped, .data = @intCast(data_uncasted) };
|
||||
}
|
||||
@@ -3446,8 +3429,8 @@ pub const Inst = struct {
|
||||
return switch (item_info.kind) {
|
||||
.enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) },
|
||||
.error_value => .{ .error_value = @enumFromInt(item_info.data) },
|
||||
.number_literal => .{ .number_literal = @enumFromInt(item_info.data) },
|
||||
.body_len => .{ .body_len = item_info.data },
|
||||
.under => .under,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4818,9 +4801,6 @@ fn findTrackableInner(
|
||||
if (zir_switch.else_case) |else_case| {
|
||||
try zir.findTrackableBody(gpa, contents, defers, else_case.body);
|
||||
}
|
||||
if (zir_switch.under_case.resolve()) |under_case| {
|
||||
try zir.findTrackableBody(gpa, contents, defers, under_case.body);
|
||||
}
|
||||
var extra_index = zir_switch.end;
|
||||
var case_it = zir_switch.iterateCases();
|
||||
while (case_it.next()) |case| {
|
||||
@@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB
|
||||
extra_index += 1;
|
||||
break :else_info else_info;
|
||||
} else undefined;
|
||||
const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = if (bits.has_under and bits.under_is_bare) bare_under_info: {
|
||||
const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = @bitCast(zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :bare_under_info bare_under_info;
|
||||
} else undefined;
|
||||
const under_index: u32 = if (bits.has_under and !bits.under_is_bare) under_index: {
|
||||
const under_index = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :under_index under_index;
|
||||
} else undefined;
|
||||
const scalar_cases_len: u32 = bits.scalar_cases_len;
|
||||
const prong_infos: []const Inst.SwitchBlock.ProngInfo =
|
||||
@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
|
||||
.is_simple_noreturn = else_info.is_simple_noreturn,
|
||||
};
|
||||
} else null;
|
||||
const under_case: UnwrappedSwitchBlock.Case.Under = if (bits.has_under) under_case: {
|
||||
if (bits.under_is_bare) {
|
||||
const body = zir.bodySlice(extra_index, bare_under_info.body_len);
|
||||
extra_index += body.len;
|
||||
break :under_case .{ .bare = .{
|
||||
.index = .bare_under,
|
||||
.body = body,
|
||||
.capture = bare_under_info.capture,
|
||||
.has_tag_capture = bare_under_info.has_tag_capture,
|
||||
} };
|
||||
} else {
|
||||
break :under_case .{ .index = under_index };
|
||||
}
|
||||
} else .none;
|
||||
return .{
|
||||
.main_operand = extra.data.raw_operand,
|
||||
.switch_src_node_offset = inst_data.src_node,
|
||||
@@ -5344,7 +5300,7 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB
|
||||
.any_maybe_runtime_capture = bits.any_maybe_runtime_capture,
|
||||
.non_err_case = non_err_case,
|
||||
.else_case = else_case,
|
||||
.under_case = under_case,
|
||||
.has_under = bits.has_under,
|
||||
.prong_infos = prong_infos,
|
||||
.multi_case_items_lens = multi_case_items_lens,
|
||||
.multi_case_ranges_lens = multi_case_ranges_lens,
|
||||
@@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
any_maybe_runtime_capture: bool,
|
||||
non_err_case: ?Case.NonErr,
|
||||
else_case: ?Case.Else,
|
||||
under_case: Case.Under,
|
||||
has_under: bool,
|
||||
// Refer to doc comment and `iterateCases` to access everything below correctly.
|
||||
prong_infos: []const Inst.SwitchBlock.ProngInfo,
|
||||
multi_case_items_lens: []const u32,
|
||||
@@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
item_infos: []const Inst.SwitchBlock.ItemInfo,
|
||||
range_infos: []const [2]Inst.SwitchBlock.ItemInfo,
|
||||
|
||||
pub fn isUnder(case: *const Case) bool {
|
||||
return case.index.is_under;
|
||||
}
|
||||
|
||||
pub const Index = packed struct(u32) {
|
||||
kind: enum(u1) { scalar, multi },
|
||||
is_under: bool,
|
||||
value: u30,
|
||||
value: u31,
|
||||
|
||||
pub const @"else": Case.Index = .{
|
||||
.kind = .scalar,
|
||||
.is_under = false,
|
||||
.value = std.math.maxInt(u30),
|
||||
};
|
||||
|
||||
pub const bare_under: Case.Index = .{
|
||||
.kind = .scalar,
|
||||
.is_under = true,
|
||||
.value = std.math.maxInt(u30),
|
||||
.value = std.math.maxInt(u31),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
is_simple_noreturn: bool,
|
||||
};
|
||||
|
||||
pub const Under = union(enum) {
|
||||
none,
|
||||
bare: Under.Resolved,
|
||||
index: u32,
|
||||
|
||||
pub const Resolved = struct {
|
||||
index: Case.Index,
|
||||
body: []const Inst.Index,
|
||||
capture: Inst.SwitchBlock.ProngInfo.Capture,
|
||||
has_tag_capture: bool,
|
||||
};
|
||||
|
||||
/// If this returns `null` and `under` is not `.none`, you'll have to
|
||||
/// find the under case by iterating all cases and using `isUnder`!
|
||||
pub fn resolve(under: Under) ?Under.Resolved {
|
||||
return switch (under) {
|
||||
.bare => |resolved| resolved,
|
||||
.none, .index => null,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
next_idx: u32,
|
||||
under_idx: ?u32,
|
||||
prong_infos: []const Inst.SwitchBlock.ProngInfo,
|
||||
multi_case_items_lens: []const u32,
|
||||
multi_case_ranges_lens: ?[]const u32,
|
||||
@@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
return if (idx < scalar_cases_len) .{
|
||||
.index = .{
|
||||
.kind = .scalar,
|
||||
.is_under = idx == it.under_idx,
|
||||
.value = @intCast(idx),
|
||||
},
|
||||
.prong_info = it.prong_infos[idx],
|
||||
@@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
} else .{
|
||||
.index = .{
|
||||
.kind = .multi,
|
||||
.is_under = idx == it.under_idx,
|
||||
.value = @intCast(idx - scalar_cases_len),
|
||||
},
|
||||
.prong_info = it.prong_infos[idx],
|
||||
@@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct {
|
||||
pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator {
|
||||
return .{
|
||||
.next_idx = 0,
|
||||
.under_idx = switch (unwrapped.under_case) {
|
||||
.none, .bare => null,
|
||||
.index => |index| index,
|
||||
},
|
||||
.prong_infos = unwrapped.prong_infos,
|
||||
.multi_case_items_lens = unwrapped.multi_case_items_lens,
|
||||
.multi_case_ranges_lens = unwrapped.multi_case_ranges_lens,
|
||||
|
||||
+112
-129
@@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock(
|
||||
const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
|
||||
|
||||
const has_else = zir_switch.else_case != null;
|
||||
const has_under = zir_switch.under_case != .none;
|
||||
const has_under = zir_switch.has_under;
|
||||
|
||||
const else_case = validated_switch.else_case;
|
||||
const under_case = validated_switch.under_case;
|
||||
|
||||
const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: {
|
||||
const val, const ref = if (operand_is_ref)
|
||||
@@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock(
|
||||
// we allow simple noreturn else prongs when switching on error sets!
|
||||
break :find_prong .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline, true };
|
||||
}
|
||||
if (has_under) {
|
||||
break :find_prong .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false, true };
|
||||
}
|
||||
unreachable; // malformed validated switch
|
||||
};
|
||||
|
||||
@@ -11083,10 +11079,9 @@ fn finishSwitchBr(
|
||||
const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
|
||||
|
||||
const has_else = zir_switch.else_case != null;
|
||||
const has_under = zir_switch.under_case != .none;
|
||||
const has_under = zir_switch.has_under;
|
||||
|
||||
const else_case = validated_switch.else_case;
|
||||
const under_case = validated_switch.under_case;
|
||||
|
||||
const scalar_cases_len = zir_switch.scalarCasesLen();
|
||||
const multi_cases_len = zir_switch.multiCasesLen();
|
||||
@@ -11138,20 +11133,15 @@ fn finishSwitchBr(
|
||||
var case_it = zir_switch.iterateCases();
|
||||
var extra_index = zir_switch.end;
|
||||
|
||||
var under_prong: ?struct {
|
||||
index: Zir.UnwrappedSwitchBlock.Case.Index,
|
||||
body: []const Zir.Inst.Index,
|
||||
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
|
||||
has_tag_capture: bool,
|
||||
} = null;
|
||||
|
||||
var cases_len: u32 = 0;
|
||||
while (case_it.next()) |case| {
|
||||
if (case.isUnder()) { // we'll deal with this later
|
||||
extra_index += case.prong_info.body_len;
|
||||
for (case.item_infos) |item_info| {
|
||||
if (item_info.bodyLen()) |body_len| extra_index += body_len;
|
||||
}
|
||||
for (case.range_infos) |range_info| {
|
||||
if (range_info[0].bodyLen()) |body_len| extra_index += body_len;
|
||||
if (range_info[1].bodyLen()) |body_len| extra_index += body_len;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const item_refs = case_vals[case_val_idx..][0..case.item_infos.len];
|
||||
case_val_idx += item_refs.len;
|
||||
const range_refs: []const [2]Air.Inst.Ref =
|
||||
@@ -11171,7 +11161,9 @@ fn finishSwitchBr(
|
||||
|
||||
var emit_bb = false;
|
||||
var any_analyze_body = false;
|
||||
var is_under_prong = false;
|
||||
for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| {
|
||||
if (item_ref == .none) is_under_prong = true;
|
||||
if (item_info.bodyLen()) |body_len| extra_index += body_len;
|
||||
|
||||
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(
|
||||
}
|
||||
}
|
||||
|
||||
if (!prong_info.is_inline) {
|
||||
cases_len += 1;
|
||||
case_block.instructions.clearRetainingCapacity();
|
||||
case_block.error_return_trace_index = child_block.error_return_trace_index;
|
||||
if (prong_info.is_inline) continue; // handled above
|
||||
|
||||
const prong_hint: std.builtin.BranchHint = hint: {
|
||||
if (any_analyze_body) break :hint try sema.analyzeSwitchProng(
|
||||
&case_block,
|
||||
operand,
|
||||
operand_ty,
|
||||
raw_operand_ty,
|
||||
prong_body,
|
||||
block.src(.{ .switch_capture = .{
|
||||
.switch_node_offset = src_node_offset,
|
||||
.case_idx = case.index,
|
||||
} }),
|
||||
prong_info.capture,
|
||||
prong_info.has_tag_capture,
|
||||
.none,
|
||||
.{ .item_refs = item_refs },
|
||||
validated_switch.else_err_ty,
|
||||
switch_inst,
|
||||
zir_switch,
|
||||
);
|
||||
_ = try case_block.addNoOp(.unreach);
|
||||
break :hint .cold; // unreachable branches are cold
|
||||
if (is_under_prong) {
|
||||
under_prong = .{
|
||||
.index = case.index,
|
||||
.body = prong_body,
|
||||
.capture = case.prong_info.capture,
|
||||
.has_tag_capture = case.prong_info.has_tag_capture,
|
||||
};
|
||||
try branch_hints.append(gpa, prong_hint);
|
||||
|
||||
try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len +
|
||||
item_refs.len +
|
||||
2 * range_refs.len +
|
||||
case_block.instructions.items.len);
|
||||
cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{
|
||||
.items_len = @intCast(item_refs.len),
|
||||
.ranges_len = @intCast(range_refs.len),
|
||||
.body_len = @intCast(case_block.instructions.items.len),
|
||||
}));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items));
|
||||
continue;
|
||||
}
|
||||
|
||||
cases_len += 1;
|
||||
case_block.instructions.clearRetainingCapacity();
|
||||
case_block.error_return_trace_index = child_block.error_return_trace_index;
|
||||
|
||||
const prong_hint: std.builtin.BranchHint = hint: {
|
||||
if (any_analyze_body) break :hint try sema.analyzeSwitchProng(
|
||||
&case_block,
|
||||
operand,
|
||||
operand_ty,
|
||||
raw_operand_ty,
|
||||
prong_body,
|
||||
block.src(.{ .switch_capture = .{
|
||||
.switch_node_offset = src_node_offset,
|
||||
.case_idx = case.index,
|
||||
} }),
|
||||
prong_info.capture,
|
||||
prong_info.has_tag_capture,
|
||||
.none,
|
||||
.{ .item_refs = item_refs },
|
||||
validated_switch.else_err_ty,
|
||||
switch_inst,
|
||||
zir_switch,
|
||||
);
|
||||
_ = try case_block.addNoOp(.unreach);
|
||||
break :hint .cold; // unreachable branches are cold
|
||||
};
|
||||
try branch_hints.append(gpa, prong_hint);
|
||||
|
||||
try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len +
|
||||
item_refs.len +
|
||||
2 * range_refs.len +
|
||||
case_block.instructions.items.len);
|
||||
cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{
|
||||
.items_len = @intCast(item_refs.len),
|
||||
.ranges_len = @intCast(range_refs.len),
|
||||
.body_len = @intCast(case_block.instructions.items.len),
|
||||
}));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs));
|
||||
cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items));
|
||||
}
|
||||
|
||||
const catch_all_extra: []const u32 = catch_all_extra: {
|
||||
@@ -11499,7 +11501,7 @@ fn finishSwitchBr(
|
||||
try branch_hints.append(gpa, prong_hint);
|
||||
|
||||
try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len +
|
||||
(validated_switch.seen_enum_fields.len - zir_switch.totalItemsLen()) +
|
||||
(validated_switch.seen_enum_fields.len + 1 - zir_switch.totalItemsLen()) + // +1 because totalItemsLen includes the _
|
||||
case_block.instructions.items.len);
|
||||
const extra_case = cases_extra.addManyAsArrayAssumeCapacity(
|
||||
@typeInfo(Air.SwitchBr.Case).@"struct".fields.len,
|
||||
@@ -11555,7 +11557,7 @@ fn finishSwitchBr(
|
||||
if (analyze_catch_all_body) {
|
||||
const index, const body, const capture, const has_tag_capture = switch (catch_all_case) {
|
||||
.@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture },
|
||||
.under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture },
|
||||
.under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture },
|
||||
.none => unreachable,
|
||||
};
|
||||
break :hint try sema.analyzeSwitchProng(
|
||||
@@ -11734,7 +11736,6 @@ fn fixupSwitchContinues(
|
||||
const ValidatedSwitchBlock = struct {
|
||||
seen_enum_fields: []const ?LazySrcLoc,
|
||||
seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc),
|
||||
seen_sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc),
|
||||
seen_ranges: []const RangeSet.Range,
|
||||
true_src: ?LazySrcLoc,
|
||||
false_src: ?LazySrcLoc,
|
||||
@@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct {
|
||||
|
||||
case_vals: []const Air.Inst.Ref,
|
||||
else_case: Zir.UnwrappedSwitchBlock.Case.Else,
|
||||
under_case: Zir.UnwrappedSwitchBlock.Case.Under.Resolved,
|
||||
else_err_ty: ?Type,
|
||||
|
||||
fn iterateUnhandledItems(
|
||||
@@ -11868,7 +11868,6 @@ fn validateSwitchBlock(
|
||||
const src = block.nodeOffset(src_node_offset);
|
||||
const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
|
||||
const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset });
|
||||
const under_prong_src = block.src(.{ .node_offset_switch_under_prong = src_node_offset });
|
||||
var extra_index = zir_switch.end;
|
||||
|
||||
// We want to map values to our placeholders later on.
|
||||
@@ -11948,33 +11947,7 @@ fn validateSwitchBlock(
|
||||
};
|
||||
|
||||
const has_else = zir_switch.else_case != null;
|
||||
const has_under = zir_switch.under_case != .none;
|
||||
|
||||
// Validate usage of '_' prongs.
|
||||
if (has_under and !operand_ty.isNonexhaustiveEnum(zcu)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(
|
||||
src,
|
||||
"'_' prong only allowed when switching on non-exhaustive enums",
|
||||
.{},
|
||||
);
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.errNote(
|
||||
under_prong_src,
|
||||
msg,
|
||||
"'_' prong here",
|
||||
.{},
|
||||
);
|
||||
try sema.errNote(
|
||||
src,
|
||||
msg,
|
||||
"consider using 'else'",
|
||||
.{},
|
||||
);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
const has_under = zir_switch.has_under;
|
||||
|
||||
var case_vals: std.ArrayList(Air.Inst.Ref) = .empty;
|
||||
try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len);
|
||||
@@ -11991,7 +11964,6 @@ fn validateSwitchBlock(
|
||||
var else_err_ty: ?Type = null;
|
||||
|
||||
const else_case = zir_switch.else_case orelse undefined;
|
||||
var under_case = zir_switch.under_case.resolve() orelse undefined;
|
||||
|
||||
switch (item_ty.zigTypeTag(zcu)) {
|
||||
.@"union" => unreachable,
|
||||
@@ -12020,16 +11992,6 @@ fn validateSwitchBlock(
|
||||
var case_it = zir_switch.iterateCases();
|
||||
while (case_it.next()) |case| {
|
||||
const prong_info = case.prong_info;
|
||||
const is_under = case.isUnder();
|
||||
if (is_under) {
|
||||
assert(!prong_info.is_inline);
|
||||
under_case = .{
|
||||
.index = case.index,
|
||||
.body = sema.code.bodySlice(extra_index, prong_info.body_len),
|
||||
.capture = prong_info.capture,
|
||||
.has_tag_capture = prong_info.has_tag_capture,
|
||||
};
|
||||
}
|
||||
extra_index += prong_info.body_len;
|
||||
for (case.item_infos, 0..) |item_info, item_i| {
|
||||
const item_src = block.src(.{ .switch_case_item = .{
|
||||
@@ -12037,9 +11999,34 @@ fn validateSwitchBlock(
|
||||
.case_idx = case.index,
|
||||
.item_idx = .{ .kind = .single, .value = @intCast(item_i) },
|
||||
} });
|
||||
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);
|
||||
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);
|
||||
if (!is_under) case_vals.appendAssumeCapacity(item.ref);
|
||||
if (item_info.unwrap() == .under) {
|
||||
if (!operand_ty.isNonexhaustiveEnum(zcu)) return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(
|
||||
src,
|
||||
"'_' prong only allowed when switching on non-exhaustive enums",
|
||||
.{},
|
||||
);
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.errNote(
|
||||
item_src,
|
||||
msg,
|
||||
"'_' prong here",
|
||||
.{},
|
||||
);
|
||||
try sema.errNote(
|
||||
src,
|
||||
msg,
|
||||
"consider using 'else'",
|
||||
.{},
|
||||
);
|
||||
break :msg msg;
|
||||
});
|
||||
case_vals.appendAssumeCapacity(.none);
|
||||
} else {
|
||||
const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach);
|
||||
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);
|
||||
case_vals.appendAssumeCapacity(item.ref);
|
||||
}
|
||||
}
|
||||
for (case.range_infos, 0..) |range_info, range_i| {
|
||||
const range_offset: LazySrcLoc.Offset.SwitchItem = .{
|
||||
@@ -12050,10 +12037,10 @@ fn validateSwitchBlock(
|
||||
const range_src = block.src(.{ .switch_case_item = range_offset });
|
||||
const first_src = block.src(.{ .switch_case_item_range_first = range_offset });
|
||||
const last_src = block.src(.{ .switch_case_item_range_last = range_offset });
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
if (!is_under) case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref });
|
||||
case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12285,7 +12272,6 @@ fn validateSwitchBlock(
|
||||
return .{
|
||||
.seen_enum_fields = seen_enum_fields,
|
||||
.seen_errors = seen_errors,
|
||||
.seen_sparse_values = seen_sparse_values,
|
||||
.seen_ranges = range_set.ranges.items,
|
||||
.true_src = true_src,
|
||||
.false_src = false_src,
|
||||
@@ -12293,7 +12279,6 @@ fn validateSwitchBlock(
|
||||
|
||||
.case_vals = case_vals.items,
|
||||
.else_case = else_case,
|
||||
.under_case = under_case,
|
||||
.else_err_ty = else_err_ty,
|
||||
};
|
||||
}
|
||||
@@ -12334,19 +12319,13 @@ fn resolveSwitchBlock(
|
||||
var case_val_idx: usize = 0;
|
||||
var extra_index = zir_switch.end;
|
||||
var case_it = zir_switch.iterateCases();
|
||||
var under_prong: ?struct {
|
||||
index: Zir.UnwrappedSwitchBlock.Case.Index,
|
||||
body: []const Zir.Inst.Index,
|
||||
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
|
||||
has_tag_capture: bool,
|
||||
} = null;
|
||||
while (case_it.next()) |case| {
|
||||
if (case.isUnder()) { // we'll deal with this later
|
||||
extra_index += case.prong_info.body_len;
|
||||
for (case.item_infos) |item_info| {
|
||||
if (item_info.bodyLen()) |body_len| extra_index += body_len;
|
||||
}
|
||||
for (case.range_infos) |range_info| {
|
||||
if (range_info[0].bodyLen()) |body_len| extra_index += body_len;
|
||||
if (range_info[1].bodyLen()) |body_len| extra_index += body_len;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const prong_info = case.prong_info;
|
||||
const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len);
|
||||
extra_index += prong_body.len;
|
||||
@@ -12363,6 +12342,15 @@ fn resolveSwitchBlock(
|
||||
const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]);
|
||||
case_val_idx += 2 * range_refs.len;
|
||||
for (item_refs) |item_ref| {
|
||||
if (item_ref == .none) {
|
||||
under_prong = .{
|
||||
.index = case.index,
|
||||
.body = prong_body,
|
||||
.capture = case.prong_info.capture,
|
||||
.has_tag_capture = case.prong_info.has_tag_capture,
|
||||
};
|
||||
continue;
|
||||
}
|
||||
const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable;
|
||||
if (cond_val.eql(item_val, item_ty, zcu)) {
|
||||
if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);
|
||||
@@ -12421,7 +12409,6 @@ fn resolveSwitchBlock(
|
||||
}
|
||||
|
||||
const else_case = validated_switch.else_case;
|
||||
const under_case = validated_switch.under_case;
|
||||
|
||||
// named-only prong
|
||||
|
||||
@@ -12452,7 +12439,7 @@ fn resolveSwitchBlock(
|
||||
|
||||
const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) {
|
||||
.@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline },
|
||||
.under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false },
|
||||
.under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture, false },
|
||||
.none => unreachable,
|
||||
};
|
||||
if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref);
|
||||
@@ -13169,7 +13156,6 @@ fn resolveSwitchItem(
|
||||
extra_index: usize,
|
||||
switch_inst: Zir.Inst.Index,
|
||||
prong_is_comptime_unreach: bool,
|
||||
prong_is_inline: bool,
|
||||
) CompileError!ResolvedSwitchItemAndExtraIndex {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
@@ -13180,6 +13166,7 @@ fn resolveSwitchItem(
|
||||
|
||||
var end = extra_index;
|
||||
const uncoerced: Air.Inst.Ref, const uncoerced_ty: Type = uncoerced: switch (item_info.unwrap()) {
|
||||
.under => unreachable, // caller must check this before calling us
|
||||
.enum_literal => |str_index| {
|
||||
const zir_str = sema.code.nullTerminatedString(str_index);
|
||||
const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls);
|
||||
@@ -13198,10 +13185,6 @@ fn resolveSwitchItem(
|
||||
} }));
|
||||
break :uncoerced .{ uncoerced, err_set_ty };
|
||||
},
|
||||
.number_literal => |zir_ref| {
|
||||
const uncoerced = try sema.resolveInst(zir_ref);
|
||||
break :uncoerced .{ uncoerced, sema.typeOf(uncoerced) };
|
||||
},
|
||||
.body_len => |body_len| {
|
||||
const body = sema.code.bodySlice(extra_index, body_len);
|
||||
end += body.len;
|
||||
@@ -13231,7 +13214,7 @@ fn resolveSwitchItem(
|
||||
.ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| {
|
||||
break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty);
|
||||
},
|
||||
.missing_error => if (prong_is_comptime_unreach and !prong_is_inline) {
|
||||
.missing_error => if (prong_is_comptime_unreach) {
|
||||
break :item_ref uncoerced;
|
||||
},
|
||||
.from_anyerror => {},
|
||||
|
||||
+1
-41
@@ -1742,27 +1742,6 @@ pub const SrcLoc = struct {
|
||||
} else unreachable;
|
||||
},
|
||||
|
||||
.node_offset_switch_under_prong => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(zcu);
|
||||
const switch_node = node_off.toAbsolute(src_loc.base_node);
|
||||
_, const extra_index = tree.nodeData(switch_node).node_and_extra;
|
||||
const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index);
|
||||
for (case_nodes) |case_node| {
|
||||
const case = tree.fullSwitchCase(case_node).?;
|
||||
for (case.ast.values) |val| {
|
||||
if (tree.nodeTag(val) == .identifier and
|
||||
mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_"))
|
||||
{
|
||||
return tree.tokensToSpan(
|
||||
tree.firstToken(case_node),
|
||||
tree.lastToken(case_node),
|
||||
tree.nodeMainToken(val),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else unreachable;
|
||||
},
|
||||
|
||||
.node_offset_switch_range => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(zcu);
|
||||
const switch_node = node_off.toAbsolute(src_loc.base_node);
|
||||
@@ -2176,7 +2155,6 @@ pub const SrcLoc = struct {
|
||||
|
||||
var multi_i: u32 = 0;
|
||||
var scalar_i: u32 = 0;
|
||||
var underscore_node: Ast.Node.OptionalIndex = .none;
|
||||
const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| {
|
||||
const case = tree.fullSwitchCase(case_node).?;
|
||||
if (case.ast.values.len == 0) {
|
||||
@@ -2185,17 +2163,6 @@ pub const SrcLoc = struct {
|
||||
}
|
||||
continue :case;
|
||||
}
|
||||
if (underscore_node == .none) {
|
||||
for (case.ast.values) |value| {
|
||||
if (tree.nodeTag(value) == .identifier and
|
||||
mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(value)), "_"))
|
||||
{
|
||||
underscore_node = value.toOptional();
|
||||
if (want_case_idx.is_under) break :case case;
|
||||
if (case.ast.values.len == 1) continue :case;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const is_multi = case.ast.values.len != 1 or
|
||||
tree.nodeTag(case.ast.values[0]) == .switch_range;
|
||||
@@ -2220,7 +2187,6 @@ pub const SrcLoc = struct {
|
||||
.switch_case_item_range_last,
|
||||
=> |x| item_idx: {
|
||||
assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else");
|
||||
assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.bare_under);
|
||||
break :item_idx x.item_idx;
|
||||
},
|
||||
.switch_capture, .switch_tag_capture => {
|
||||
@@ -2247,9 +2213,7 @@ pub const SrcLoc = struct {
|
||||
.single => {
|
||||
var item_i: u32 = 0;
|
||||
for (case.ast.values) |item_node| {
|
||||
if (item_node.toOptional() == underscore_node or
|
||||
tree.nodeTag(item_node) == .switch_range)
|
||||
{
|
||||
if (tree.nodeTag(item_node) == .switch_range) {
|
||||
continue;
|
||||
}
|
||||
if (item_i != want_item_idx.value) {
|
||||
@@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct {
|
||||
/// by taking this AST node index offset from the containing base node,
|
||||
/// which points to a switch expression AST node. Next, navigate to the else prong.
|
||||
node_offset_switch_else_prong: Ast.Node.Offset,
|
||||
/// The source location points to the `_` prong of a switch expression, found
|
||||
/// by taking this AST node index offset from the containing base node,
|
||||
/// which points to a switch expression AST node. Next, navigate to the `_` prong.
|
||||
node_offset_switch_under_prong: Ast.Node.Offset,
|
||||
/// The source location points to all the ranges of a switch expression, found
|
||||
/// by taking this AST node index offset from the containing base node,
|
||||
/// which points to a switch expression AST node. Next, navigate to any of the
|
||||
|
||||
+37
-47
@@ -2021,15 +2021,6 @@ const Writer = struct {
|
||||
try stream.writeAll("else => ");
|
||||
try self.writeBracedBody(stream, else_case.body);
|
||||
}
|
||||
if (zir_switch.under_case.resolve()) |under_case| {
|
||||
try stream.writeAll(",\n");
|
||||
try stream.splatByteAll(' ', self.indent);
|
||||
|
||||
try self.writeSwitchCaptures(stream, under_case.capture, under_case.has_tag_capture, inst, &zir_switch);
|
||||
|
||||
try stream.writeAll("_ => ");
|
||||
try self.writeBracedBody(stream, under_case.body);
|
||||
}
|
||||
|
||||
var case_it = zir_switch.iterateCases();
|
||||
while (case_it.next()) |case| {
|
||||
@@ -2043,14 +2034,8 @@ const Writer = struct {
|
||||
const prong_body = self.code.bodySlice(extra_index, prong_info.body_len);
|
||||
extra_index += prong_body.len;
|
||||
|
||||
var first_item: bool = true;
|
||||
if (case.isUnder()) {
|
||||
try stream.writeAll("_");
|
||||
first_item = false;
|
||||
}
|
||||
for (case.item_infos) |item_info| {
|
||||
if (!first_item) try stream.writeAll(", ");
|
||||
first_item = false;
|
||||
for (case.item_infos, 0..) |item_info, i| {
|
||||
if (i > 0) try stream.writeAll(", ");
|
||||
|
||||
switch (item_info.unwrap()) {
|
||||
.enum_literal => |str_index| {
|
||||
@@ -2061,9 +2046,7 @@ const Writer = struct {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.number_literal => |zir_ref| {
|
||||
try self.writeInstRef(stream, zir_ref);
|
||||
},
|
||||
.under => try stream.writeByte('_'),
|
||||
.body_len => |body_len| {
|
||||
const item_body = self.code.bodySlice(extra_index, body_len);
|
||||
extra_index += item_body.len;
|
||||
@@ -2071,33 +2054,40 @@ const Writer = struct {
|
||||
},
|
||||
}
|
||||
}
|
||||
for (case.range_infos) |range_info| {
|
||||
if (!first_item) try stream.writeAll(", ");
|
||||
first_item = false;
|
||||
|
||||
var first_range_item = true;
|
||||
for (&range_info) |item_info| {
|
||||
if (!first_range_item) try stream.writeAll("...");
|
||||
first_range_item = false;
|
||||
|
||||
switch (item_info.unwrap()) {
|
||||
.enum_literal => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\".{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.error_value => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.number_literal => |zir_ref| {
|
||||
try self.writeInstRef(stream, zir_ref);
|
||||
},
|
||||
.body_len => |body_len| {
|
||||
const item_body = self.code.bodySlice(extra_index, body_len);
|
||||
extra_index += item_body.len;
|
||||
try self.writeBracedDecl(stream, item_body);
|
||||
},
|
||||
}
|
||||
for (case.range_infos, 0..) |range_info, i| {
|
||||
if (i > 0 and case.item_infos.len == 0) try stream.writeAll(", ");
|
||||
switch (range_info[0].unwrap()) {
|
||||
.enum_literal => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\".{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.error_value => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.under => unreachable, // '_..._' is not allowed
|
||||
.body_len => |body_len| {
|
||||
const item_body = self.code.bodySlice(extra_index, body_len);
|
||||
extra_index += item_body.len;
|
||||
try self.writeBracedDecl(stream, item_body);
|
||||
},
|
||||
}
|
||||
try stream.writeAll("...");
|
||||
switch (range_info[1].unwrap()) {
|
||||
.enum_literal => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\".{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.error_value => |str_index| {
|
||||
const str = self.code.nullTerminatedString(str_index);
|
||||
try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)});
|
||||
},
|
||||
.under => unreachable, // '_..._' is not allowed
|
||||
.body_len => |body_len| {
|
||||
const item_body = self.code.bodySlice(extra_index, body_len);
|
||||
extra_index += item_body.len;
|
||||
try self.writeBracedDecl(stream, item_body);
|
||||
},
|
||||
}
|
||||
}
|
||||
try stream.writeAll(" => ");
|
||||
|
||||
Reference in New Issue
Block a user