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}