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