authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-05-22 17:32:38+02:00
committergravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-07-24 17:48:10+02:00
loge48779fe1f6127d50008277fb8662566769975da
tree55a346d4c59937c493b5ca9efa02220cdf9d53ce
parentd3056114f6f17bb4723cccfa4dd578ddafb909a9

Sema: improve invalid switch type compile errors

Makes them more similar to other existing compile errors.

3 files changed, 139 insertions(+), 47 deletions(-)

src/Sema.zig+36-22
......@@ -11186,14 +11186,8 @@ fn validateSwitchBlock(
1118611186 operand_ty.assertHasLayout(zcu);
1118711187 const union_obj = ip.loadUnionType(operand_ty.toIntern());
1118811188 switch (union_obj.tag_usage) {
11189 .tagged => {
11190 break :item_ty .fromInterned(union_obj.enum_tag_type);
11191 },
11192 .none => {
11193 if (union_obj.layout == .@"packed") {
11194 break :item_ty operand_ty;
11195 }
11196 },
11189 .tagged => break :item_ty .fromInterned(union_obj.enum_tag_type),
11190 .none => if (union_obj.layout == .@"packed") break :item_ty operand_ty,
1119711191 .safety => {},
1119811192 }
1119911193 return sema.failWithOwnedErrorMsg(block, msg: {
......@@ -11208,27 +11202,47 @@ fn validateSwitchBlock(
1120811202
1120911203 .@"struct" => {
1121011204 operand_ty.assertHasLayout(zcu);
11211 const layout = operand_ty.containerLayout(zcu);
11212 if (layout == .@"packed") {
11213 break :item_ty operand_ty;
11214 }
11205 if (operand_ty.containerLayout(zcu) == .@"packed") break :item_ty operand_ty;
1121511206 return sema.failWithOwnedErrorMsg(block, msg: {
11216 const msg = try sema.errMsg(operand_src, "switch on struct with {t} layout", .{layout});
11207 const msg = try sema.errMsg(operand_src, "switch on non-packed struct", .{});
1121711208 errdefer msg.destroy(sema.gpa);
11218 if (operand_ty.srcLocOrNull(zcu)) |struct_src| {
11219 try sema.errNote(struct_src, msg, "consider 'packed struct' here", .{});
11220 }
11209 try sema.addDeclaredHereNote(msg, operand_ty);
1122111210 break :msg msg;
1122211211 });
1122311212 },
1122411213
11225 .pointer => {
11226 if (!operand_ty.isSlice(zcu)) {
11227 break :item_ty operand_ty;
11228 }
11229 },
11214 .pointer => if (!operand_ty.isSlice(zcu)) break :item_ty operand_ty,
1123011215
11231 else => {},
11216 .optional => return sema.failWithOwnedErrorMsg(block, msg: {
11217 const msg = try sema.errMsg(operand_src, "switch on optional type '{f}'", .{
11218 operand_ty.fmt(pt),
11219 });
11220 errdefer msg.destroy(gpa);
11221 try sema.errNote(operand_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
11222 break :msg msg;
11223 }),
11224
11225 .error_union => return sema.failWithOwnedErrorMsg(block, msg: {
11226 const msg = try sema.errMsg(operand_src, "switch on error union type '{f}'", .{
11227 operand_ty.fmt(pt),
11228 });
11229 errdefer msg.destroy(gpa);
11230 try sema.errNote(operand_src, msg, "consider using 'try', 'catch', or 'if'", .{});
11231 break :msg msg;
11232 }),
11233
11234 .noreturn,
11235 .float,
11236 .comptime_float,
11237 .array,
11238 .vector,
11239 .undefined,
11240 .null,
11241 .@"opaque",
11242 .frame,
11243 .@"anyframe",
11244 .spirv,
11245 => {},
1123211246 }
1123311247 return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)});
1123411248 };
test/cases/compile_errors/switch_on_invalid_type.zig created+103
......@@ -0,0 +1,103 @@
1const AutoUnion = union { a: u8 };
2export fn entry1() void {
3 switch (@as(AutoUnion, .{ .a = 123 })) {
4 else => {},
5 }
6}
7
8const ExternUnion = union { a: u8 };
9export fn entry2() void {
10 switch (@as(ExternUnion, .{ .a = 123 })) {
11 else => {},
12 }
13}
14
15const AutoStruct = struct { a: u8 };
16export fn entry3() void {
17 switch (@as(AutoStruct, .{ .a = 123 })) {
18 else => {},
19 }
20}
21
22const ExternStruct = extern struct { a: u8 };
23export fn entry4() void {
24 switch (@as(ExternStruct, .{ .a = 123 })) {
25 else => {},
26 }
27}
28
29export fn entry5() void {
30 switch (@as([]const u16, &.{ 1, 2, 3 })) {
31 else => {},
32 }
33}
34
35export fn entry6() void {
36 switch (@as([3]u16, .{ 1, 2, 3 })) {
37 else => {},
38 }
39}
40
41export fn entry7() void {
42 switch (@as(@Vector(3, u16), .{ 1, 2, 3 })) {
43 else => {},
44 }
45}
46
47export fn entry8() void {
48 switch (@as(?u16, 123)) {
49 else => {},
50 }
51}
52
53export fn entry9() void {
54 switch (@as(anyerror!u16, 123)) {
55 else => {},
56 }
57}
58
59export fn entry10() void {
60 switch (@as(f32, 123)) {
61 else => {},
62 }
63}
64
65export fn entry11() void {
66 switch (@as(comptime_float, 123)) {
67 else => {},
68 }
69}
70
71export fn entry12() void {
72 switch (undefined) {
73 else => {},
74 }
75}
76
77export fn entry13() void {
78 switch (null) {
79 else => {},
80 }
81}
82
83// error
84//
85// :3:13: error: switch on union with no attached enum
86// :1:19: note: consider 'union(enum)' here
87// :10:13: error: switch on union with no attached enum
88// :8:21: note: consider 'union(enum)' here
89// :17:13: error: switch on non-packed struct
90// :15:20: note: struct declared here
91// :24:13: error: switch on non-packed struct
92// :22:29: note: struct declared here
93// :30:13: error: switch on type '[]const u16'
94// :36:13: error: switch on type '[3]u16'
95// :42:13: error: switch on type '@Vector(3, u16)'
96// :48:13: error: switch on optional type '?u16'
97// :48:13: note: consider using '.?', 'orelse', or 'if'
98// :54:13: error: switch on error union type 'anyerror!u16'
99// :54:13: note: consider using 'try', 'catch', or 'if'
100// :60:13: error: switch on type 'f32'
101// :66:13: error: switch on type 'comptime_float'
102// :72:13: error: switch on type '@TypeOf(undefined)'
103// :78:13: error: switch on type '@TypeOf(null)'
test/cases/compile_errors/switch_on_non_packed_struct.zig deleted-25
......@@ -1,25 +0,0 @@
1const Auto = struct {
2 a: u8,
3};
4export fn entry1(a: u8) void {
5 const s: Auto = .{ .a = a };
6 switch (s) {
7 else => {},
8 }
9}
10
11const Extern = extern struct {
12 a: u8,
13};
14export fn entry2(s: Extern) void {
15 switch (s) {
16 else => {},
17 }
18}
19
20// error
21//
22// :6:13: error: switch on struct with auto layout
23// :1:14: note: consider 'packed struct' here
24// :15:13: error: switch on struct with extern layout
25// :11:23: note: consider 'packed struct' here