Skip to content

Commit 60cff3d

Browse files
FnControlOptionTechatrix
authored andcommitted
Resolve type of labeled switch from break statements
1 parent 9fe30b1 commit 60cff3d

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/analysis.zig

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,7 @@ const FindBreaks = struct {
18271827
try context.break_operands.append(context.allocator, operand.unwrap() orelse return);
18281828
} else if (context.label) |label| {
18291829
if (opt_label_token.unwrap()) |label_token| {
1830-
if (std.mem.eql(u8, label, tree.tokenSlice(label_token))) {
1830+
if (std.mem.eql(u8, label, offsets.identifierTokenToNameSlice(tree, label_token))) {
18311831
try context.break_operands.append(context.allocator, operand.unwrap() orelse return);
18321832
}
18331833
}
@@ -2497,6 +2497,25 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) error
24972497
const switch_node = tree.switchFull(node);
24982498

24992499
var either: std.ArrayList(Type.TypeWithDescriptor) = .empty;
2500+
2501+
if (switch_node.label_token) |label_token| {
2502+
var context: FindBreaks = .{
2503+
.label = offsets.identifierTokenToNameSlice(tree, label_token),
2504+
.allow_unlabeled = false,
2505+
.allocator = analyser.gpa,
2506+
};
2507+
defer context.deinit();
2508+
try context.findBreakOperands(tree, node);
2509+
for (context.break_operands.items) |operand| {
2510+
if (try analyser.resolveTypeOfNodeInternal(.of(operand, handle))) |operand_type| {
2511+
try either.append(analyser.arena, .{
2512+
.type = operand_type,
2513+
.descriptor = "break",
2514+
});
2515+
}
2516+
}
2517+
}
2518+
25002519
for (switch_node.ast.cases) |case| {
25012520
const switch_case = tree.fullSwitchCase(case).?;
25022521
var descriptor: std.ArrayList(u8) = .empty;
@@ -2547,7 +2566,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) error
25472566
return else_type;
25482567

25492568
var context: FindBreaks = .{
2550-
.label = if (loop.label_token) |token| tree.tokenSlice(token) else null,
2569+
.label = if (loop.label_token) |token| offsets.identifierTokenToNameSlice(tree, token) else null,
25512570
.allow_unlabeled = true,
25522571
.allocator = analyser.gpa,
25532572
};

tests/analysis/switch.zig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
const A = struct {
2+
alpha: u32,
3+
};
4+
5+
const B = struct {
6+
beta: u32,
7+
};
8+
19
const Enum = enum {
210
foo,
311
bar,
@@ -115,3 +123,19 @@ const switch_null_inline = switch (null) {
115123
// ^ (@TypeOf(null))() TODO this should be `unknown`
116124
// ^ (unknown)()
117125
};
126+
127+
// zig fmt: off
128+
const labeled_switch = blk: switch (some_u8) {
129+
// ^^^^^^^^^^^^^^ (u8)()
130+
'x' => |a| break :blk a,
131+
'y' => |a| break :blk a,
132+
else => |a| break :blk a,
133+
};
134+
135+
const labeled_switch_2 = blk: switch (undefined) {
136+
// ^^^^^^^^^^^^^^^^ (either type)()
137+
1 => break :blk A{},
138+
2 => B{},
139+
else => unreachable,
140+
};
141+
// zig fmt: on

0 commit comments

Comments
 (0)