master
1const builtin = @import("builtin");
2const std = @import("std");
3const testing = std.testing;
4const assert = std.debug.assert;
5const expect = testing.expect;
6const expectEqualStrings = std.testing.expectEqualStrings;
7const expectEqual = std.testing.expectEqual;
8
9test "tuple concatenation" {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12
13 const S = struct {
14 fn doTheTest() !void {
15 var a: i32 = 1;
16 var b: i32 = 2;
17 _ = .{ &a, &b };
18 const x = .{a};
19 const y = .{b};
20 const c = x ++ y;
21 try expect(@as(i32, 1) == c[0]);
22 try expect(@as(i32, 2) == c[1]);
23 }
24 };
25 try S.doTheTest();
26 try comptime S.doTheTest();
27}
28
29test "tuple multiplication" {
30 const S = struct {
31 fn doTheTest() !void {
32 {
33 const t = .{} ** 4;
34 try expect(@typeInfo(@TypeOf(t)).@"struct".fields.len == 0);
35 }
36 {
37 const t = .{'a'} ** 4;
38 try expect(@typeInfo(@TypeOf(t)).@"struct".fields.len == 4);
39 inline for (t) |x| try expect(x == 'a');
40 }
41 {
42 const t = .{ 1, 2, 3 } ** 4;
43 try expect(@typeInfo(@TypeOf(t)).@"struct".fields.len == 12);
44 inline for (t, 0..) |x, i| try expect(x == 1 + i % 3);
45 }
46 }
47 };
48 try S.doTheTest();
49 try comptime S.doTheTest();
50}
51
52test "more tuple concatenation" {
53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
56
57 const T = struct {
58 fn consume_tuple(tuple: anytype, len: usize) !void {
59 try expect(tuple.len == len);
60 }
61
62 fn doTheTest() !void {
63 const t1 = .{};
64
65 var rt_var: u8 = 42;
66 const t2 = .{rt_var} ++ .{};
67
68 try expect(t2.len == 1);
69 try expect(t2.@"0" == rt_var);
70 try expect(t2.@"0" == 42);
71 try expect(&t2.@"0" != &rt_var);
72
73 try consume_tuple(t1 ++ t1, 0);
74 try consume_tuple(.{} ++ .{}, 0);
75 try consume_tuple(.{0} ++ .{}, 1);
76 try consume_tuple(.{0} ++ .{1}, 2);
77 try consume_tuple(.{ 0, 1, 2 } ++ .{ u8, 1, noreturn }, 6);
78 try consume_tuple(t2 ++ t1, 1);
79 try consume_tuple(t1 ++ t2, 1);
80 try consume_tuple(t2 ++ t2, 2);
81 try consume_tuple(.{rt_var} ++ .{}, 1);
82 try consume_tuple(.{rt_var} ++ t1, 1);
83 try consume_tuple(.{} ++ .{rt_var}, 1);
84 try consume_tuple(t2 ++ .{void}, 2);
85 try consume_tuple(t2 ++ .{0}, 2);
86 try consume_tuple(.{0} ++ t2, 2);
87 try consume_tuple(.{void} ++ t2, 2);
88 try consume_tuple(.{u8} ++ .{rt_var} ++ .{true}, 3);
89 }
90 };
91
92 try T.doTheTest();
93 try comptime T.doTheTest();
94}
95
96test "pass tuple to comptime var parameter" {
97 const S = struct {
98 fn Foo(comptime args: anytype) !void {
99 try expect(args[0] == 1);
100 }
101
102 fn doTheTest() !void {
103 try Foo(.{1});
104 }
105 };
106 try S.doTheTest();
107 try comptime S.doTheTest();
108}
109
110test "tuple initializer for var" {
111 const S = struct {
112 fn doTheTest() void {
113 const Bytes = struct {
114 id: usize,
115 };
116
117 var tmp = .{
118 .id = @as(usize, 2),
119 .name = Bytes{ .id = 20 },
120 };
121 _ = &tmp;
122 }
123 };
124
125 S.doTheTest();
126 comptime S.doTheTest();
127}
128
129test "array-like initializer for tuple types" {
130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
132
133 const T = @Tuple(&.{ i32, u8 });
134 const S = struct {
135 fn doTheTest() !void {
136 var obj: T = .{ -1234, 128 };
137 _ = &obj;
138 try expect(@as(i32, -1234) == obj[0]);
139 try expect(@as(u8, 128) == obj[1]);
140 }
141 };
142
143 try S.doTheTest();
144 try comptime S.doTheTest();
145}
146
147test "anon struct as the result from a labeled block" {
148 const S = struct {
149 fn doTheTest() !void {
150 const precomputed = comptime blk: {
151 var x: i32 = 1234;
152 _ = &x;
153 break :blk .{
154 .x = x,
155 };
156 };
157 try expect(precomputed.x == 1234);
158 }
159 };
160
161 try S.doTheTest();
162 try comptime S.doTheTest();
163}
164
165test "tuple as the result from a labeled block" {
166 const S = struct {
167 fn doTheTest() !void {
168 const precomputed = comptime blk: {
169 var x: i32 = 1234;
170 _ = &x;
171 break :blk .{x};
172 };
173 try expect(precomputed[0] == 1234);
174 }
175 };
176
177 try S.doTheTest();
178 try comptime S.doTheTest();
179}
180
181test "initializing tuple with explicit type" {
182 const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
183 var a = T{ 0, 0 };
184 _ = &a;
185}
186
187test "initializing anon struct with explicit type" {
188 const T = @TypeOf(.{ .foo = @as(i32, 1), .bar = @as(i32, 2) });
189 var a = T{ .foo = 1, .bar = 2 };
190 _ = &a;
191}
192
193test "fieldParentPtr of tuple" {
194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
195 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
198
199 var x: u32 = 0;
200 _ = &x;
201 const tuple = .{ x, x };
202 try testing.expect(&tuple == @as(@TypeOf(&tuple), @fieldParentPtr("1", &tuple[1])));
203}
204
205test "fieldParentPtr of anon struct" {
206 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
207 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
210
211 var x: u32 = 0;
212 _ = &x;
213 const anon_st = .{ .foo = x, .bar = x };
214 try testing.expect(&anon_st == @as(@TypeOf(&anon_st), @fieldParentPtr("bar", &anon_st.bar)));
215}
216
217test "offsetOf tuple" {
218 var x: u32 = 0;
219 _ = &x;
220 const T = @TypeOf(.{ x, x });
221 try expect(@offsetOf(T, "1") == @sizeOf(u32));
222}
223
224test "offsetOf anon struct" {
225 var x: u32 = 0;
226 _ = &x;
227 const T = @TypeOf(.{ .foo = x, .bar = x });
228 try expect(@offsetOf(T, "bar") == @sizeOf(u32));
229}
230
231test "initializing tuple with mixed comptime-runtime fields" {
232 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
233
234 var x: u32 = 15;
235 _ = &x;
236 const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
237 var a: T = .{ -1234, 5678, x + 1 };
238 _ = &a;
239 try expect(a[2] == 16);
240}
241
242test "initializing anon struct with mixed comptime-runtime fields" {
243 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
244
245 var x: u32 = 15;
246 _ = &x;
247 const T = @TypeOf(.{ .foo = @as(i32, -1234), .bar = x });
248 var a: T = .{ .foo = -1234, .bar = x + 1 };
249 _ = &a;
250 try expect(a.bar == 16);
251}
252
253test "tuple in tuple passed to generic function" {
254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
257
258 const S = struct {
259 fn pair(x: f32, y: f32) std.meta.Tuple(&.{ f32, f32 }) {
260 return .{ x, y };
261 }
262
263 fn foo(x: anytype) !void {
264 try expect(x[0][0] == 1.5);
265 try expect(x[0][1] == 2.5);
266 }
267 };
268 const x = comptime S.pair(1.5, 2.5);
269 try S.foo(.{x});
270}
271
272test "coerce tuple to tuple" {
273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
275 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
276
277 const T = std.meta.Tuple(&.{u8});
278 const S = struct {
279 fn foo(x: T) !void {
280 try expect(x[0] == 123);
281 }
282 };
283 try S.foo(.{123});
284}
285
286test "tuple type with void field" {
287 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
288 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
289 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
290
291 const T = std.meta.Tuple(&[_]type{void});
292 const x = T{{}};
293 try expect(@TypeOf(x[0]) == void);
294}
295
296test "zero sized struct in tuple handled correctly" {
297 const State = struct {
298 const Self = @This();
299 const Inner = struct {};
300
301 data: @Tuple(&.{Inner}),
302
303 pub fn do(this: Self) usize {
304 return @sizeOf(@TypeOf(this));
305 }
306 };
307
308 var s: State = undefined;
309 try expect(s.do() == 0);
310}
311
312test "tuple type with void field and a runtime field" {
313 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
315
316 const T = std.meta.Tuple(&[_]type{ usize, void });
317 var t: T = .{ 5, {} };
318 _ = &t;
319 try expect(t[0] == 5);
320}
321
322test "branching inside tuple literal" {
323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325
326 const S = struct {
327 fn foo(a: anytype) !void {
328 try expect(a[0] == 1234);
329 }
330 };
331 var a = false;
332 _ = &a;
333 try S.foo(.{if (a) @as(u32, 5678) else @as(u32, 1234)});
334}
335
336test "tuple initialized with a runtime known value" {
337 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
338 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
342
343 const E = union(enum) { e: []const u8 };
344 const W = union(enum) { w: E };
345 var e = E{ .e = "test" };
346 _ = &e;
347 const w = .{W{ .w = e }};
348 try expectEqualStrings(w[0].w.e, "test");
349}
350
351test "tuple of struct concatenation and coercion to array" {
352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
353 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
354 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
356
357 const StructWithDefault = struct { value: f32 = 42 };
358 const SomeStruct = struct { array: [4]StructWithDefault };
359
360 const value1 = SomeStruct{ .array = .{StructWithDefault{}} ++ [_]StructWithDefault{.{}} ** 3 };
361 const value2 = SomeStruct{ .array = .{ .{}, .{}, .{}, .{} } };
362
363 try expectEqual(value1, value2);
364}
365
366test "nested runtime conditionals in tuple initializer" {
367 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
370
371 var data: u8 = 0;
372 _ = &data;
373 const x = .{
374 if (data != 0) "" else switch (@as(u1, @truncate(data))) {
375 0 => "up",
376 1 => "down",
377 },
378 };
379 try expectEqualStrings("up", x[0]);
380}
381
382test "sentinel slice in tuple with other fields" {
383 const S = struct {
384 a: u32,
385 b: u32,
386 };
387
388 const Submission = union(enum) {
389 open: struct { *S, [:0]const u8, u32 },
390 };
391
392 _ = Submission;
393}
394
395test "sentinel slice in tuple" {
396 const S = struct { [:0]const u8 };
397
398 _ = S;
399}
400
401test "tuple pointer is indexable" {
402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
405
406 const S = struct { u32, bool };
407
408 const x: S = .{ 123, true };
409 comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness
410 try expectEqual(@as(u32, 123), (&x)[0]);
411 try expectEqual(true, (&x)[1]);
412
413 var y: S = .{ 123, true };
414 comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness
415 try expectEqual(@as(u32, 123), (&y)[0]);
416 try expectEqual(true, (&y)[1]);
417
418 (&y)[0] = 100;
419 (&y)[1] = false;
420 try expectEqual(@as(u32, 100), (&y)[0]);
421 try expectEqual(false, (&y)[1]);
422}
423
424test "coerce anon tuple to tuple" {
425 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
426 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
427
428 var x: u8 = 1;
429 var y: u16 = 2;
430 _ = .{ &x, &y };
431 const t = .{ x, y };
432 const s: struct { u8, u16 } = t;
433 try expectEqual(x, s[0]);
434 try expectEqual(y, s[1]);
435}
436
437test "empty tuple type" {
438 const S = @Tuple(&.{});
439
440 const s: S = .{};
441 try expect(s.len == 0);
442}
443
444test "tuple with comptime fields with non empty initializer" {
445 const a: struct { comptime comptime_int = 0 } = .{0};
446 _ = a;
447}
448
449test "anon tuple field referencing comptime var isn't comptime" {
450 comptime var a: u8 = 0;
451 const tuple = .{&a};
452 // field isn't comptime but tuple is still comptime-known
453 comptime assert(@TypeOf(tuple) == struct { *u8 });
454 a = 1;
455 comptime assert(tuple[0].* == 1);
456}
457
458test "tuple with runtime value coerced into a slice with a sentinel" {
459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
461 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
462 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
463
464 const S = struct {
465 fn f(a: [:null]const ?u8) !void {
466 try expect(a[0] == 42);
467 }
468 };
469
470 const c: u8 = 42;
471 try S.f(&[_:null]?u8{c});
472 try S.f(&.{c});
473
474 var v: u8 = 42;
475 _ = &v;
476 try S.f(&[_:null]?u8{v});
477 try S.f(&.{v});
478}
479
480test "tuple implicitly coerced to optional/error union struct/union" {
481 const SomeUnion = union(enum) {
482 variant: u8,
483 };
484 const SomeStruct = struct {
485 struct_field: u8,
486 };
487 const OptEnum = struct {
488 opt_union: ?SomeUnion,
489 };
490 const ErrEnum = struct {
491 err_union: anyerror!SomeUnion,
492 };
493 const OptStruct = struct {
494 opt_struct: ?SomeStruct,
495 };
496 const ErrStruct = struct {
497 err_struct: anyerror!SomeStruct,
498 };
499
500 try expect((OptEnum{
501 .opt_union = .{
502 .variant = 1,
503 },
504 }).opt_union.?.variant == 1);
505
506 try expect(((ErrEnum{
507 .err_union = .{
508 .variant = 1,
509 },
510 }).err_union catch unreachable).variant == 1);
511
512 try expect((OptStruct{
513 .opt_struct = .{
514 .struct_field = 1,
515 },
516 }).opt_struct.?.struct_field == 1);
517
518 try expect(((ErrStruct{
519 .err_struct = .{
520 .struct_field = 1,
521 },
522 }).err_struct catch unreachable).struct_field == 1);
523}
524
525test "comptime fields in tuple can be initialized" {
526 const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
527 var a: T = .{ 0, 0 };
528 _ = &a;
529}
530
531test "empty struct in tuple" {
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
534 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
535
536 const T = struct { struct {} };
537 const info = @typeInfo(T);
538 try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
539 try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
540 try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"struct");
541}
542
543test "empty union in tuple" {
544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
545 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
547
548 const T = struct { union {} };
549 const info = @typeInfo(T);
550 try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
551 try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
552 try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
553}
554
555test "field pointer of underaligned tuple" {
556 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
557
558 const S = struct {
559 fn doTheTest() !void {
560 const T = struct { u8, u32 };
561 var val: T align(2) = .{ 1, 2 };
562
563 comptime assert(@TypeOf(&val[0]) == *u8); // `u8` field pointer isn't overaligned
564 comptime assert(@TypeOf(&val[1]) == *align(2) u32); // `u32` field pointer is correctly underaligned
565
566 try expect(val[0] == 1);
567 try expect(val[1] == 2);
568 }
569 };
570 try S.doTheTest();
571 try comptime S.doTheTest();
572}
573
574test "OPV tuple fields aren't comptime" {
575 const T = struct { void };
576 const t_info = @typeInfo(T);
577 try expect(!t_info.@"struct".fields[0].is_comptime);
578
579 const T2 = @Tuple(&.{void});
580 const t2_info = @typeInfo(T2);
581 try expect(!t2_info.@"struct".fields[0].is_comptime);
582}
583
584test "array of tuples that end with a zero-bit field followed by padding" {
585 const S = struct {
586 var foo: [2]struct { u32, u8, void } = .{ .{ 1, 2, {} }, .{ 3, 4, {} } };
587 };
588 try expect(S.foo[0][0] == 1);
589 try expect(S.foo[0][1] == 2);
590 try expect(S.foo[0][2] == {});
591 try expect(S.foo[1][0] == 3);
592 try expect(S.foo[1][1] == 4);
593 try expect(S.foo[1][2] == {});
594}