1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4const assert = std.debug.assert;
5
6const E1 = enum(u8) {
7 a,
8 b,
9 c,
10 d,
11 const expected = .{
12 .val = @as(E1, .b),
13 .int = @as(@typeInfo(E1).@"enum".tag_type, 1),
14 };
15};
16const E2 = enum(i20) {
17 x,
18 y,
19 z = -5,
20 const expected = .{
21 .val = @as(E2, .z),
22 .int = @as(@typeInfo(E2).@"enum".tag_type, -5),
23 };
24};
25const E3 = enum(i32) {
26 _,
27 const zero: E3 = @bitCast(@as(i32, 0));
28 const expected = .{
29 .val = @as(E3, .zero),
30 .int = @as(@typeInfo(E3).@"enum".tag_type, 0),
31 };
32};
33const E4 = enum(i200) {
34 min = -(1 << 199),
35 const expected = .{
36 .val = @as(E4, .min),
37 .int = @as(@typeInfo(E4).@"enum".tag_type, -(1 << 199)),
38 };
39};
40const E5 = enum(u0) {
41 a,
42 const expected = .{
43 .val = @as(E5, .a),
44 .int = @as(@typeInfo(E5).@"enum".tag_type, 0),
45 };
46};
47
48test "@backingInt with enums" {
49 const static = struct {
50 fn doTheTest(v1: E1, v2: E2, v3: E3, v4: E4, v5: E5) !void {
51 const b1 = @backingInt(v1);
52 comptime assert(@TypeOf(b1) == @typeInfo(E1).@"enum".tag_type);
53 try expect(b1 == E1.expected.int);
54
55 const b2 = @backingInt(v2);
56 comptime assert(@TypeOf(b2) == @typeInfo(E2).@"enum".tag_type);
57 try expect(b2 == E2.expected.int);
58
59 const b3 = @backingInt(v3);
60 comptime assert(@TypeOf(b3) == @typeInfo(E3).@"enum".tag_type);
61 try expect(b3 == E3.expected.int);
62
63 const b4 = @backingInt(v4);
64 comptime assert(@TypeOf(b4) == @typeInfo(E4).@"enum".tag_type);
65 try expect(b4 == E4.expected.int);
66
67 const b5 = @backingInt(v5);
68 comptime assert(@TypeOf(b5) == @typeInfo(E5).@"enum".tag_type);
69 try expect(b5 == E5.expected.int);
70 }
71 };
72 try static.doTheTest(E1.expected.val, E2.expected.val, E3.expected.val, E4.expected.val, E5.expected.val);
73 try comptime static.doTheTest(E1.expected.val, E2.expected.val, E3.expected.val, E4.expected.val, E5.expected.val);
74}
75
76test "@fromBackingInt with enums" {
77 const static = struct {
78 fn doTheTest(
79 b1: @typeInfo(E1).@"enum".tag_type,
80 b2: @typeInfo(E2).@"enum".tag_type,
81 b3: @typeInfo(E3).@"enum".tag_type,
82 b4: @typeInfo(E4).@"enum".tag_type,
83 b5: @typeInfo(E5).@"enum".tag_type,
84 ) !void {
85 const v1: E1 = @fromBackingInt(b1);
86 try expect(v1 == E1.expected.val);
87
88 const v2: E2 = @fromBackingInt(b2);
89 try expect(v2 == E2.expected.val);
90
91 const v3: E3 = @fromBackingInt(b3);
92 try expect(v3 == E3.expected.val);
93
94 const v4: E4 = @fromBackingInt(b4);
95 try expect(v4 == E4.expected.val);
96
97 const v5: E5 = @fromBackingInt(b5);
98 try expect(v5 == E5.expected.val);
99 }
100 };
101 try static.doTheTest(E1.expected.int, E2.expected.int, E3.expected.int, E4.expected.int, E5.expected.int);
102 try comptime static.doTheTest(E1.expected.int, E2.expected.int, E3.expected.int, E4.expected.int, E5.expected.int);
103}
104
105const T1 = union(E1) {
106 a: u8,
107 b: []const u16,
108 c: []const u8,
109 d: i32,
110 const expected = .{
111 .val = @unionInit(T1, @tagName(E1.expected.val), &.{ 1, 2, 3 }),
112 .int = E1.expected.int,
113 };
114};
115const T2 = union(E2) {
116 x,
117 y: i32,
118 z,
119 const expected = .{
120 .val = @unionInit(T2, @tagName(E2.expected.val), {}),
121 .int = E2.expected.int,
122 };
123};
124const T4 = union(E4) {
125 min: f32,
126 const expected = .{
127 .val = @unionInit(T4, @tagName(E4.expected.val), 0.123),
128 .int = E4.expected.int,
129 };
130};
131const T5 = union(E5) {
132 a: u0,
133 const expected = .{
134 .val = @unionInit(T5, @tagName(E5.expected.val), 0),
135 .int = E5.expected.int,
136 };
137};
138
139test "@backingInt with tagged unions" {
140 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
141
142 const static = struct {
143 fn doTheTest(v1: T1, v2: T2, v4: T4, v5: T5) !void {
144 const b1 = @backingInt(v1);
145 comptime assert(@TypeOf(b1) == @typeInfo(@typeInfo(T1).@"union".tag_type.?).@"enum".tag_type);
146 try expect(b1 == E1.expected.int);
147
148 const b2 = @backingInt(v2);
149 comptime assert(@TypeOf(b2) == @typeInfo(@typeInfo(T2).@"union".tag_type.?).@"enum".tag_type);
150 try expect(b2 == E2.expected.int);
151
152 const b4 = @backingInt(v4);
153 comptime assert(@TypeOf(b4) == @typeInfo(@typeInfo(T4).@"union".tag_type.?).@"enum".tag_type);
154 try expect(b4 == E4.expected.int);
155
156 const b5 = @backingInt(v5);
157 comptime assert(@TypeOf(b5) == @typeInfo(@typeInfo(T5).@"union".tag_type.?).@"enum".tag_type);
158 try expect(b5 == E5.expected.int);
159 }
160 };
161 try static.doTheTest(T1.expected.val, T2.expected.val, T4.expected.val, T5.expected.val);
162 try comptime static.doTheTest(T1.expected.val, T2.expected.val, T4.expected.val, T5.expected.val);
163}
164
165const S1 = packed struct(u8) {
166 a: u4,
167 b: i4,
168 const expected = .{
169 .val = @as(S1, .{ .a = 0b1000, .b = 0b0010 }),
170 .int = @as(@typeInfo(S1).@"struct".backing_integer.?, 0b0010_1000),
171 };
172};
173const S2 = packed struct(i20) {
174 a: u10,
175 b: enum(i10) { x, y, z },
176 const expected = .{
177 .val = @as(S2, .{ .a = 0b0011001100, .b = .z }),
178 .int = @as(@typeInfo(S2).@"struct".backing_integer.?, 0b0000000010_0011001100),
179 };
180};
181const S3 = packed struct(i32) {
182 a: packed struct(u12) {
183 x: u8,
184 y: i4,
185 },
186 b: packed union(i20) {
187 x: i20,
188 y: enum(u20) { u, v },
189 },
190 const expected = .{
191 .val = @as(S3, .{ .a = .{ .x = 0b10010001, .y = 0b0110 }, .b = .{ .y = .v } }),
192 .int = @as(@typeInfo(S3).@"struct".backing_integer.?, 0b00000000000000000001_0110_10010001),
193 };
194};
195const S4 = packed struct(i200) {
196 a: u200,
197 const expected = .{
198 .val = @as(S4, .{ .a = (1 << 199) + 10 }),
199 .int = @as(@typeInfo(S4).@"struct".backing_integer.?, @bitCast(@as(u200, (1 << 199) + 10))),
200 };
201};
202const S5 = packed struct(u0) {
203 a: u0,
204 const expected = .{
205 .val = @as(S5, .{ .a = 0 }),
206 .int = @as(@typeInfo(S5).@"struct".backing_integer.?, 0),
207 };
208};
209
210test "@backingInt with packed structs" {
211 const static = struct {
212 fn doTheTest(v1: S1, v2: S2, v3: S3, v4: S4, v5: S5) !void {
213 const b1 = @backingInt(v1);
214 comptime assert(@TypeOf(b1) == @typeInfo(S1).@"struct".backing_integer.?);
215 try expect(b1 == S1.expected.int);
216
217 const b2 = @backingInt(v2);
218 comptime assert(@TypeOf(b2) == @typeInfo(S2).@"struct".backing_integer.?);
219 try expect(b2 == S2.expected.int);
220
221 const b3 = @backingInt(v3);
222 comptime assert(@TypeOf(b3) == @typeInfo(S3).@"struct".backing_integer.?);
223 try expect(b3 == S3.expected.int);
224
225 const b4 = @backingInt(v4);
226 comptime assert(@TypeOf(b4) == @typeInfo(S4).@"struct".backing_integer.?);
227 try expect(b4 == S4.expected.int);
228
229 const b5 = @backingInt(v5);
230 comptime assert(@TypeOf(b5) == @typeInfo(S5).@"struct".backing_integer.?);
231 try expect(b5 == S5.expected.int);
232 }
233 };
234 try static.doTheTest(S1.expected.val, S2.expected.val, S3.expected.val, S4.expected.val, S5.expected.val);
235 try comptime static.doTheTest(S1.expected.val, S2.expected.val, S3.expected.val, S4.expected.val, S5.expected.val);
236}
237
238test "@fromBackingInt with packed structs" {
239 const static = struct {
240 fn doTheTest(
241 b1: @typeInfo(S1).@"struct".backing_integer.?,
242 b2: @typeInfo(S2).@"struct".backing_integer.?,
243 b3: @typeInfo(S3).@"struct".backing_integer.?,
244 b4: @typeInfo(S4).@"struct".backing_integer.?,
245 b5: @typeInfo(S5).@"struct".backing_integer.?,
246 ) !void {
247 const v1: S1 = @fromBackingInt(b1);
248 try expect(v1 == S1.expected.val);
249
250 const v2: S2 = @fromBackingInt(b2);
251 try expect(v2 == S2.expected.val);
252
253 const v3: S3 = @fromBackingInt(b3);
254 try expect(v3 == S3.expected.val);
255
256 // https://codeberg.org/ziglang/zig/issues/35982
257 if (builtin.zig_backend != .stage2_x86_64) {
258 const v4: S4 = @fromBackingInt(b4);
259 try expect(v4 == S4.expected.val);
260 }
261
262 const v5: S5 = @fromBackingInt(b5);
263 try expect(v5 == S5.expected.val);
264 }
265 };
266 try static.doTheTest(S1.expected.int, S2.expected.int, S3.expected.int, S4.expected.int, S5.expected.int);
267 try comptime static.doTheTest(S1.expected.int, S2.expected.int, S3.expected.int, S4.expected.int, S5.expected.int);
268}
269
270const U1 = packed union(u8) {
271 a: u8,
272 b: i8,
273 const expected = .{
274 .val = @as(U1, .{ .b = -123 }),
275 .int = @as(@typeInfo(U1).@"union".backing_integer.?, @bitCast(@as(i8, -123))),
276 };
277};
278const U2 = packed union(i20) {
279 a: u20,
280 b: enum(i20) { x, y, z },
281 const expected = .{
282 .val = @as(U2, .{ .b = .z }),
283 .int = @as(@typeInfo(U2).@"union".backing_integer.?, 0b00000000000000000000000000000010),
284 };
285};
286const U3 = packed union(i32) {
287 a: packed struct(u32) {
288 x: u18,
289 y: i14,
290 },
291 b: packed union(u32) {
292 x: i32,
293 y: enum(u32) { u, v },
294 },
295 const expected = .{
296 .val = @as(U3, .{ .b = .{ .y = .v } }),
297 .int = @as(@typeInfo(U3).@"union".backing_integer.?, 0b00000000000000000000000000000001),
298 };
299};
300const U4 = packed union(i200) {
301 a: u200,
302 const expected = .{
303 .val = @as(U4, .{ .a = (1 << 199) + 10 }),
304 .int = @as(@typeInfo(U4).@"union".backing_integer.?, @bitCast(@as(u200, (1 << 199) + 10))),
305 };
306};
307const U5 = packed union(u0) {
308 a: u0,
309 const expected = .{
310 .val = @as(U5, .{ .a = 0 }),
311 .int = @as(@typeInfo(U5).@"union".backing_integer.?, 0),
312 };
313};
314
315test "@backingInt with packed unions" {
316 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
317
318 const static = struct {
319 fn doTheTest(v1: U1, v2: U2, v3: U3, v4: U4, v5: U5) !void {
320 const b1 = @backingInt(v1);
321 comptime assert(@TypeOf(b1) == @typeInfo(U1).@"union".backing_integer.?);
322 try expect(b1 == U1.expected.int);
323
324 const b2 = @backingInt(v2);
325 comptime assert(@TypeOf(b2) == @typeInfo(U2).@"union".backing_integer.?);
326 try expect(b2 == U2.expected.int);
327
328 const b3 = @backingInt(v3);
329 comptime assert(@TypeOf(b3) == @typeInfo(U3).@"union".backing_integer.?);
330 try expect(b3 == U3.expected.int);
331
332 const b4 = @backingInt(v4);
333 comptime assert(@TypeOf(b4) == @typeInfo(U4).@"union".backing_integer.?);
334 try expect(b4 == U4.expected.int);
335
336 const b5 = @backingInt(v5);
337 comptime assert(@TypeOf(b5) == @typeInfo(U5).@"union".backing_integer.?);
338 try expect(b5 == U5.expected.int);
339 }
340 };
341 try static.doTheTest(U1.expected.val, U2.expected.val, U3.expected.val, U4.expected.val, U5.expected.val);
342 try comptime static.doTheTest(U1.expected.val, U2.expected.val, U3.expected.val, U4.expected.val, U5.expected.val);
343}
344
345test "@fromBackingInt with packed unions" {
346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
347
348 const static = struct {
349 fn doTheTest(
350 b1: @typeInfo(U1).@"union".backing_integer.?,
351 b2: @typeInfo(U2).@"union".backing_integer.?,
352 b3: @typeInfo(U3).@"union".backing_integer.?,
353 b4: @typeInfo(U4).@"union".backing_integer.?,
354 b5: @typeInfo(U5).@"union".backing_integer.?,
355 ) !void {
356 const v1: U1 = @fromBackingInt(b1);
357 try expect(v1 == U1.expected.val);
358
359 const v2: U2 = @fromBackingInt(b2);
360 try expect(v2 == U2.expected.val);
361
362 const v3: U3 = @fromBackingInt(b3);
363 try expect(v3 == U3.expected.val);
364
365 // https://codeberg.org/ziglang/zig/issues/35982
366 if (builtin.zig_backend != .stage2_x86_64) {
367 const v4: U4 = @fromBackingInt(b4);
368 try expect(v4 == U4.expected.val);
369 }
370
371 const v5: U5 = @fromBackingInt(b5);
372 try expect(v5 == U5.expected.val);
373 }
374 };
375 try static.doTheTest(U1.expected.int, U2.expected.int, U3.expected.int, U4.expected.int, U5.expected.int);
376 try comptime static.doTheTest(U1.expected.int, U2.expected.int, U3.expected.int, U4.expected.int, U5.expected.int);
377}
378
379test "@fromBackingInt provides result type to its argument" {
380 const E = enum(u32) { a, b, c };
381 const static = struct {
382 fn doTheTest(x: u8) !void {
383 const e: E = @fromBackingInt(x);
384 try expect(e == .b);
385 try expect(@backingInt(e) == x);
386 }
387 };
388 try static.doTheTest(1);
389 try comptime static.doTheTest(1);
390}