1const builtin = @import("builtin");
2const std = @import("std");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6
7test "compile time recursion" {
8 try expect(some_data.len == 21);
9}
10var some_data: [@as(usize, @intCast(fibonacci(7)))]u8 = undefined;
11fn fibonacci(x: i32) i32 {
12 if (x <= 1) return 1;
13 return fibonacci(x - 1) + fibonacci(x - 2);
14}
15
16fn unwrapAndAddOne(blah: ?i32) i32 {
17 return blah.? + 1;
18}
19const should_be_1235 = unwrapAndAddOne(1234);
20test "static add one" {
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23
24 try expect(should_be_1235 == 1235);
25}
26
27test "inlined loop" {
28 comptime var i = 0;
29 comptime var sum = 0;
30 inline while (i <= 5) : (i += 1)
31 sum += i;
32 try expect(sum == 15);
33}
34
35fn gimme1or2(comptime a: bool) i32 {
36 const x: i32 = 1;
37 const y: i32 = 2;
38 comptime var z: i32 = if (a) x else y;
39 _ = &z;
40 return z;
41}
42test "inline variable gets result of const if" {
43 try expect(gimme1or2(true) == 1);
44 try expect(gimme1or2(false) == 2);
45}
46
47test "static function evaluation" {
48 try expect(statically_added_number == 3);
49}
50const statically_added_number = staticAdd(1, 2);
51fn staticAdd(a: i32, b: i32) i32 {
52 return a + b;
53}
54
55test "const expr eval on single expr blocks" {
56 try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
57 comptime assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
58}
59
60fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
61 const literal = 3;
62
63 const result = if (b) b: {
64 break :b literal;
65 } else b: {
66 break :b x;
67 };
68
69 return result;
70}
71
72test "constant expressions" {
73 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
74
75 var array: [array_size]u8 = undefined;
76 _ = &array;
77 try expect(@sizeOf(@TypeOf(array)) == 20);
78}
79const array_size: u8 = 20;
80
81fn max(comptime T: type, a: T, b: T) T {
82 if (T == bool) {
83 return a or b;
84 } else if (a > b) {
85 return a;
86 } else {
87 return b;
88 }
89}
90fn letsTryToCompareBools(a: bool, b: bool) bool {
91 return max(bool, a, b);
92}
93test "inlined block and runtime block phi" {
94 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
95
96 try expect(letsTryToCompareBools(true, true));
97 try expect(letsTryToCompareBools(true, false));
98 try expect(letsTryToCompareBools(false, true));
99 try expect(!letsTryToCompareBools(false, false));
100
101 comptime {
102 try expect(letsTryToCompareBools(true, true));
103 try expect(letsTryToCompareBools(true, false));
104 try expect(letsTryToCompareBools(false, true));
105 try expect(!letsTryToCompareBools(false, false));
106 }
107}
108
109test "eval @setRuntimeSafety at compile-time" {
110 const result = comptime fnWithSetRuntimeSafety();
111 try expect(result == 1234);
112}
113
114fn fnWithSetRuntimeSafety() i32 {
115 @setRuntimeSafety(true);
116 return 1234;
117}
118
119test "compile-time downcast when the bits fit" {
120 comptime {
121 const spartan_count: u16 = 255;
122 const byte = @as(u8, @intCast(spartan_count));
123 try expect(byte == 255);
124 }
125}
126
127test "pointer to type" {
128 comptime {
129 var T: type = i32;
130 try expect(T == i32);
131 const ptr = &T;
132 try expect(@TypeOf(ptr) == *type);
133 ptr.* = f32;
134 try expect(T == f32);
135 try expect(*T == *f32);
136 }
137}
138
139test "a type constructed in a global expression" {
140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
143
144 var l: List = undefined;
145 l.array[0] = 10;
146 l.array[1] = 11;
147 l.array[2] = 12;
148 const ptr = @as([*]u8, @ptrCast(&l.array));
149 try expect(ptr[0] == 10);
150 try expect(ptr[1] == 11);
151 try expect(ptr[2] == 12);
152}
153
154const List = blk: {
155 const T = [10]u8;
156 break :blk struct {
157 array: T,
158 };
159};
160
161test "comptime function with the same args is memoized" {
162 comptime {
163 try expect(MakeType(i32) == MakeType(i32));
164 try expect(MakeType(i32) != MakeType(f64));
165 }
166}
167
168fn MakeType(comptime T: type) type {
169 return struct {
170 field: T,
171 };
172}
173
174test "try to trick eval with runtime if" {
175 try expect(testTryToTrickEvalWithRuntimeIf(true) == 10);
176}
177
178fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
179 comptime var i: usize = 0;
180 inline while (i < 10) : (i += 1) {
181 const result = if (b) false else true;
182 _ = result;
183 }
184 return comptime i;
185}
186
187test "@setEvalBranchQuota" {
188 comptime {
189 // 1001 for the loop and then 1 more for the expect fn call
190 @setEvalBranchQuota(1002);
191 var i = 0;
192 var sum = 0;
193 while (i < 1001) : (i += 1) {
194 sum += i;
195 }
196 try expect(sum == 500500);
197 }
198}
199
200test "constant struct with negation" {
201 try expect(vertices[0].x == @as(f32, -0.6));
202}
203const Vertex = struct {
204 x: f32,
205 y: f32,
206 r: f32,
207 g: f32,
208 b: f32,
209};
210const vertices = [_]Vertex{
211 Vertex{
212 .x = -0.6,
213 .y = -0.4,
214 .r = 1.0,
215 .g = 0.0,
216 .b = 0.0,
217 },
218 Vertex{
219 .x = 0.6,
220 .y = -0.4,
221 .r = 0.0,
222 .g = 1.0,
223 .b = 0.0,
224 },
225 Vertex{
226 .x = 0.0,
227 .y = 0.6,
228 .r = 0.0,
229 .g = 0.0,
230 .b = 1.0,
231 },
232};
233
234test "statically initialized list" {
235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
236
237 try expect(static_point_list[0].x == 1);
238 try expect(static_point_list[0].y == 2);
239 try expect(static_point_list[1].x == 3);
240 try expect(static_point_list[1].y == 4);
241}
242const Point = struct {
243 x: i32,
244 y: i32,
245};
246const static_point_list = [_]Point{
247 makePoint(1, 2),
248 makePoint(3, 4),
249};
250fn makePoint(x: i32, y: i32) Point {
251 return Point{
252 .x = x,
253 .y = y,
254 };
255}
256
257test "statically initialized array literal" {
258 const y: [4]u8 = st_init_arr_lit_x;
259 try expect(y[3] == 4);
260}
261const st_init_arr_lit_x = [_]u8{ 1, 2, 3, 4 };
262
263const CmdFn = struct {
264 name: []const u8,
265 func: fn (i32) i32,
266};
267
268const cmd_fns = [_]CmdFn{
269 CmdFn{
270 .name = "one",
271 .func = one,
272 },
273 CmdFn{
274 .name = "two",
275 .func = two,
276 },
277 CmdFn{
278 .name = "three",
279 .func = three,
280 },
281};
282fn one(value: i32) i32 {
283 return value + 1;
284}
285fn two(value: i32) i32 {
286 return value + 2;
287}
288fn three(value: i32) i32 {
289 return value + 3;
290}
291
292fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
293 var result: i32 = start_value;
294 comptime var i = 0;
295 inline while (i < cmd_fns.len) : (i += 1) {
296 if (cmd_fns[i].name[0] == prefix_char) {
297 result = cmd_fns[i].func(result);
298 }
299 }
300 return result;
301}
302
303test "comptime iterate over fn ptr list" {
304 try expect(performFn('t', 1) == 6);
305 try expect(performFn('o', 0) == 1);
306 try expect(performFn('w', 99) == 99);
307}
308
309test "create global array with for loop" {
310 try expect(global_array[5] == 5 * 5);
311 try expect(global_array[9] == 9 * 9);
312}
313
314const global_array = x: {
315 var result: [10]usize = undefined;
316 for (&result, 0..) |*item, index| {
317 item.* = index * index;
318 }
319 break :x result;
320};
321
322fn generateTable(comptime T: type) [1010]T {
323 var res: [1010]T = undefined;
324 var i: usize = 0;
325 while (i < 1010) : (i += 1) {
326 res[i] = @as(T, @intCast(i));
327 }
328 return res;
329}
330
331fn doesAlotT(comptime T: type, value: usize) T {
332 @setEvalBranchQuota(5000);
333 const table = comptime blk: {
334 break :blk generateTable(T);
335 };
336 return table[value];
337}
338
339test "@setEvalBranchQuota at same scope as generic function call" {
340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341
342 try expect(doesAlotT(u32, 2) == 2);
343}
344
345pub const Info = struct {
346 version: u8,
347};
348
349pub const diamond_info = Info{ .version = 0 };
350
351test "comptime modification of const struct field" {
352 comptime {
353 var res = diamond_info;
354 res.version = 1;
355 try expect(diamond_info.version == 0);
356 try expect(res.version == 1);
357 }
358}
359
360test "refer to the type of a generic function" {
361 const Func = fn (comptime type) void;
362 const f: Func = doNothingWithType;
363 f(i32);
364}
365
366fn doNothingWithType(comptime T: type) void {
367 _ = T;
368}
369
370test "zero extend from u0 to u1" {
371 var zero_u0: u0 = 0;
372 var zero_u1: u1 = zero_u0;
373 _ = .{ &zero_u0, &zero_u1 };
374 try expect(zero_u1 == 0);
375}
376
377test "return 0 from function that has u0 return type" {
378 const S = struct {
379 fn foo_zero() u0 {
380 return 0;
381 }
382 };
383 comptime {
384 if (S.foo_zero() != 0) {
385 @compileError("test failed");
386 }
387 }
388}
389
390test "statically initialized struct" {
391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392
393 st_init_str_foo.x += 1;
394 try expect(st_init_str_foo.x == 14);
395}
396const StInitStrFoo = struct {
397 x: i32,
398 y: bool,
399};
400var st_init_str_foo = StInitStrFoo{
401 .x = 13,
402 .y = true,
403};
404
405test "inline for with same type but different values" {
406 var res: usize = 0;
407 inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
408 var a: T = undefined;
409 _ = &a;
410 res += a.len;
411 }
412 try expect(res == 5);
413}
414
415test "f32 at compile time is lossy" {
416 try expect(@as(f32, 1 << 24) + 1 == 1 << 24);
417}
418
419test "f64 at compile time is lossy" {
420 try expect(@as(f64, 1 << 53) + 1 == 1 << 53);
421}
422
423test {
424 comptime assert(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
425}
426
427fn copyWithPartialInline(s: []u32, b: []u8) void {
428 comptime var i: usize = 0;
429 inline while (i < 4) : (i += 1) {
430 s[i] = 0;
431 s[i] |= @as(u32, b[i * 4 + 0]) << 24;
432 s[i] |= @as(u32, b[i * 4 + 1]) << 16;
433 s[i] |= @as(u32, b[i * 4 + 2]) << 8;
434 s[i] |= @as(u32, b[i * 4 + 3]) << 0;
435 }
436}
437
438test "binary math operator in partially inlined function" {
439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
442
443 var s: [4]u32 = undefined;
444 var b: [16]u8 = undefined;
445
446 for (&b, 0..) |*r, i|
447 r.* = @as(u8, @intCast(i + 1));
448
449 copyWithPartialInline(s[0..], b[0..]);
450 try expect(s[0] == 0x1020304);
451 try expect(s[1] == 0x5060708);
452 try expect(s[2] == 0x90a0b0c);
453 try expect(s[3] == 0xd0e0f10);
454}
455
456test "comptime shl" {
457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
459
460 const a: u128 = 3;
461 const b: u7 = 63;
462 const c: u128 = 3 << 63;
463 try expect((a << b) == c);
464}
465
466test "comptime bitwise operators" {
467 comptime {
468 try expect(3 & 1 == 1);
469 try expect(3 & -1 == 3);
470 try expect(-3 & -1 == -3);
471 try expect(3 | -1 == -1);
472 try expect(-3 | -1 == -1);
473 try expect(3 ^ -1 == -4);
474 try expect(-3 ^ -1 == 2);
475 try expect(~@as(i8, -1) == 0);
476 try expect(~@as(i128, -1) == 0);
477 try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
478 try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
479 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
480 }
481}
482
483test "comptime shlWithOverflow" {
484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
487
488 const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
489 var a = ~@as(u64, 0);
490 _ = &a;
491 const rt_shifted = @shlWithOverflow(a, 16)[0];
492
493 try expect(ct_shifted == rt_shifted);
494}
495
496test "const ptr to variable data changes at runtime" {
497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
499
500 try expect(foo_ref.name[0] == 'a');
501 foo_ref.name = "b";
502 try expect(foo_ref.name[0] == 'b');
503}
504
505const Foo = struct {
506 name: []const u8,
507};
508
509var foo_contents = Foo{ .name = "a" };
510const foo_ref = &foo_contents;
511
512test "runtime 128 bit integer division" {
513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
517
518 var a: u128 = 152313999999999991610955792383;
519 var b: u128 = 10000000000000000000;
520 _ = .{ &a, &b };
521 const c = a / b;
522 try expect(c == 15231399999);
523}
524
525test "@tagName of @typeInfo" {
526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
528
529 const str = @tagName(@typeInfo(u8));
530 try expect(std.mem.eql(u8, str, "int"));
531}
532
533test "static eval list init" {
534 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
536
537 try expect(static_vec3.data[2] == 1.0);
538 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
539}
540const static_vec3 = vec3(0.0, 0.0, 1.0);
541pub const Vec3 = struct {
542 data: [3]f32,
543};
544pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
545 return Vec3{
546 .data = [_]f32{ x, y, z },
547 };
548}
549
550test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
551 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
552
553 var runtime = [1]i32{3};
554 _ = &runtime;
555 comptime var i: usize = 0;
556 inline while (i < 2) : (i += 1) {
557 const result = if (i == 0) [1]i32{2} else runtime;
558 _ = result;
559 }
560 comptime {
561 try expect(i == 2);
562 }
563}
564
565test "ptr to local array argument at comptime" {
566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
567
568 comptime {
569 var bytes: [10]u8 = undefined;
570 modifySomeBytes(bytes[0..]);
571 try expect(bytes[0] == 'a');
572 try expect(bytes[9] == 'b');
573 }
574}
575
576fn modifySomeBytes(bytes: []u8) void {
577 bytes[0] = 'a';
578 bytes[9] = 'b';
579}
580
581test "comparisons 0 <= uint and 0 > uint should be comptime" {
582 testCompTimeUIntComparisons(1234);
583}
584fn testCompTimeUIntComparisons(x: u32) void {
585 if (!(0 <= x)) {
586 @compileError("this condition should be comptime-known");
587 }
588 if (0 > x) {
589 @compileError("this condition should be comptime-known");
590 }
591 if (!(x >= 0)) {
592 @compileError("this condition should be comptime-known");
593 }
594 if (x < 0) {
595 @compileError("this condition should be comptime-known");
596 }
597}
598
599const hi1 = "hi";
600const hi2 = hi1;
601test "const global shares pointer with other same one" {
602 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
603 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
604
605 try assertEqualPtrs(&hi1[0], &hi2[0]);
606 comptime assert(&hi1[0] == &hi2[0]);
607}
608fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void {
609 try expect(ptr1 == ptr2);
610}
611
612// This one is still up for debate in the language specification.
613// Application code should not rely on this behavior until it is solidified.
614// Historically, stage1 had special case code to make this pass for string literals
615// but it did not work if the values are constructed with comptime code, or if
616// arrays of non-u8 elements are used instead.
617// The official language specification might not make this guarantee. However, if
618// it does make this guarantee, it will make it consistently for all types, not
619// only string literals. This is why Zig currently has a string table for
620// string literals, to match legacy stage1 behavior and pass this test, however
621// the end-game once the lang spec issue is settled would be to use a global
622// InternPool for comptime memoized objects, making this behavior consistent
623// across all types.
624test "string literal used as comptime slice is memoized" {
625 const a = "link";
626 const b = "link";
627 comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
628 comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
629}
630
631pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
632 _ = field_name;
633 return struct {
634 pub const Node = struct {};
635 };
636}
637
638test "comptime function with mutable pointer is not memoized" {
639 comptime {
640 var x: i32 = 1;
641 const ptr = &x;
642 increment(ptr);
643 increment(ptr);
644 try expect(x == 3);
645 }
646}
647
648fn increment(value: *i32) void {
649 value.* += 1;
650}
651
652test "const ptr to comptime mutable data is not memoized" {
653 comptime {
654 var foo = SingleFieldStruct{ .x = 1 };
655 try expect(foo.read_x() == 1);
656 foo.x = 2;
657 try expect(foo.read_x() == 2);
658 }
659}
660
661const SingleFieldStruct = struct {
662 x: i32,
663
664 fn read_x(self: *const SingleFieldStruct) i32 {
665 return self.x;
666 }
667};
668
669test "function which returns struct with type field causes implicit comptime" {
670 const ty = wrap(i32).T;
671 try expect(ty == i32);
672}
673
674const Wrapper = struct {
675 T: type,
676};
677
678fn wrap(comptime T: type) Wrapper {
679 return Wrapper{ .T = T };
680}
681
682test "call method with comptime pass-by-non-copying-value self parameter" {
683 const S = struct {
684 a: u8,
685
686 fn b(comptime s: @This()) u8 {
687 return s.a;
688 }
689 };
690
691 const s = S{ .a = 2 };
692 const b = s.b();
693 try expect(b == 2);
694}
695
696test "setting backward branch quota just before a generic fn call" {
697 @setEvalBranchQuota(1001);
698 loopNTimes(1001);
699}
700
701fn loopNTimes(comptime n: usize) void {
702 comptime var i = 0;
703 inline while (i < n) : (i += 1) {}
704}
705
706test "variable inside inline loop that has different types on different iterations" {
707 try testVarInsideInlineLoop(.{ true, @as(u32, 42) });
708}
709
710fn testVarInsideInlineLoop(args: anytype) !void {
711 comptime var i = 0;
712 inline while (i < args.len) : (i += 1) {
713 const x = args[i];
714 if (i == 0) try expect(x);
715 if (i == 1) try expect(x == 42);
716 }
717}
718
719test "array concatenation of function calls" {
720 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
721 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
722 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
723
724 var a = oneItem(3) ++ oneItem(4);
725 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
726}
727
728fn oneItem(x: i32) [1]i32 {
729 return [_]i32{x};
730}
731
732fn scalar(x: u32) u32 {
733 return x;
734}
735
736test "array concatenation peer resolves element types - value" {
737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
738 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
739
740 var a = [2]u3{ 1, 7 };
741 var b = [3]u8{ 200, 225, 255 };
742 _ = .{ &a, &b };
743 const c = a ++ b;
744 comptime assert(@TypeOf(c) == [5]u8);
745 try expect(c[0] == 1);
746 try expect(c[1] == 7);
747 try expect(c[2] == 200);
748 try expect(c[3] == 225);
749 try expect(c[4] == 255);
750}
751
752test "array concatenation peer resolves element types - pointer" {
753 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
754 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
755 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
756
757 var a = [2]u3{ 1, 7 };
758 var b = [3]u8{ 200, 225, 255 };
759 const c = &a ++ &b;
760 comptime assert(@TypeOf(c) == *const [5]u8);
761 try expect(c[0] == 1);
762 try expect(c[1] == 7);
763 try expect(c[2] == 200);
764 try expect(c[3] == 225);
765 try expect(c[4] == 255);
766}
767
768test "array concatenation sets the sentinel - value" {
769 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
770 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
771 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
772 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
773
774 var a = [2]u3{ 1, 7 };
775 var b = [3:69]u8{ 200, 225, 255 };
776 _ = .{ &a, &b };
777 const c = a ++ b;
778 comptime assert(@TypeOf(c) == [5:69]u8);
779 try expect(c[0] == 1);
780 try expect(c[1] == 7);
781 try expect(c[2] == 200);
782 try expect(c[3] == 225);
783 try expect(c[4] == 255);
784 const ptr: [*]const u8 = &c;
785 try expect(ptr[5] == 69);
786}
787
788test "array concatenation sets the sentinel - pointer" {
789 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
790 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
792
793 var a = [2]u3{ 1, 7 };
794 var b = [3:69]u8{ 200, 225, 255 };
795 const c = &a ++ &b;
796 comptime assert(@TypeOf(c) == *const [5:69]u8);
797 try expect(c[0] == 1);
798 try expect(c[1] == 7);
799 try expect(c[2] == 200);
800 try expect(c[3] == 225);
801 try expect(c[4] == 255);
802 const ptr: [*]const u8 = c;
803 try expect(ptr[5] == 69);
804}
805
806test "comptime assign int to optional int" {
807 comptime {
808 var x: ?i32 = null;
809 x = 2;
810 x.? *= 10;
811 try expectEqual(20, x.?);
812 }
813}
814
815test "two comptime calls with array default initialized to undefined" {
816 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
817 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
818
819 const S = struct {
820 const A = struct {
821 c: B = B{},
822
823 pub fn d() void {
824 var f: A = .{};
825 f.e();
826 }
827
828 pub fn e(g: A) void {
829 _ = g;
830 }
831 };
832
833 const B = struct {
834 buffer: [255]u8 = undefined,
835 };
836 };
837
838 comptime {
839 S.A.d();
840 S.A.d();
841 }
842}
843
844test "const type-annotated local initialized with function call has correct type" {
845 const S = struct {
846 fn foo() comptime_int {
847 return 1234;
848 }
849 };
850 const x: u64 = S.foo();
851 try expect(@TypeOf(x) == u64);
852 try expect(x == 1234);
853}
854
855test "comptime pointer load through elem_ptr" {
856 const S = struct {
857 x: usize,
858 };
859
860 comptime {
861 var array: [10]S = undefined;
862 for (&array, 0..) |*elem, i| {
863 elem.* = .{
864 .x = i,
865 };
866 }
867 var ptr: [*]S = @ptrCast(&array);
868 const x = ptr[0].x;
869 assert(x == 0);
870 ptr += 1;
871 assert(ptr[1].x == 2);
872 }
873}
874
875test "debug variable type resolved through indirect zero-bit types" {
876 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
877
878 const T = struct { key: []void };
879 const slice: []const T = &[_]T{};
880 _ = slice;
881}
882
883test "const local with comptime init through array init" {
884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
885
886 const E1 = enum {
887 A,
888 pub fn a() void {}
889 };
890
891 const S = struct {
892 fn declarations(comptime T: type) []const [:0]const u8 {
893 return @typeInfo(T).@"enum".decl_names;
894 }
895 };
896
897 const decls = comptime [_][]const [:0]const u8{
898 S.declarations(E1),
899 };
900
901 comptime assert(decls[0][0][0] == 'a');
902}
903
904test "closure capture type of runtime-known parameter" {
905 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
906
907 const S = struct {
908 fn b(c: anytype) !void {
909 const D = struct { c: @TypeOf(c) };
910 const d: D = .{ .c = c };
911 try expect(d.c == 1234);
912 }
913 };
914 var c: i32 = 1234;
915 _ = &c;
916 try S.b(c);
917}
918
919test "closure capture type of runtime-known var" {
920 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
921
922 var x: u32 = 1234;
923 _ = &x;
924 const S = struct { val: @TypeOf(x + 100) };
925 const s: S = .{ .val = x };
926 try expect(s.val == 1234);
927}
928
929test "comptime break passing through runtime condition converted to runtime break" {
930 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931
932 const S = struct {
933 fn doTheTest() !void {
934 var runtime: u8 = 'b';
935 _ = &runtime;
936 inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
937 bar();
938 if (byte == runtime) {
939 foo(byte);
940 break;
941 }
942 }
943 try expect(ok);
944 try expect(count == 2);
945 }
946 var ok = false;
947 var count: usize = 0;
948
949 fn foo(byte: u8) void {
950 ok = byte == 'b';
951 }
952
953 fn bar() void {
954 count += 1;
955 }
956 };
957
958 try S.doTheTest();
959}
960
961test "comptime break to outer loop passing through runtime condition converted to runtime break" {
962 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
963 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
964
965 const S = struct {
966 fn doTheTest() !void {
967 var runtime: u8 = 'b';
968 _ = &runtime;
969 outer: inline for ([3]u8{ 'A', 'B', 'C' }) |outer_byte| {
970 inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
971 bar(outer_byte);
972 if (byte == runtime) {
973 foo(byte);
974 break :outer;
975 }
976 }
977 }
978 try expect(ok);
979 try expect(count == 2);
980 }
981 var ok = false;
982 var count: usize = 0;
983
984 fn foo(byte: u8) void {
985 ok = byte == 'b';
986 }
987
988 fn bar(byte: u8) void {
989 _ = byte;
990 count += 1;
991 }
992 };
993
994 try S.doTheTest();
995}
996
997test "comptime break operand passing through runtime condition converted to runtime break" {
998 const S = struct {
999 fn doTheTest(runtime: u8) !void {
1000 const result = inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
1001 if (byte == runtime) {
1002 break runtime;
1003 }
1004 } else 'z';
1005 try expect(result == 'b');
1006 }
1007 };
1008
1009 try S.doTheTest('b');
1010 try comptime S.doTheTest('b');
1011}
1012
1013test "comptime break operand passing through runtime switch converted to runtime break" {
1014 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1015
1016 const S = struct {
1017 fn doTheTest(runtime: u8) !void {
1018 const result = inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
1019 switch (runtime) {
1020 byte => break runtime,
1021 else => {},
1022 }
1023 } else 'z';
1024 try expect(result == 'b');
1025 }
1026 };
1027
1028 try S.doTheTest('b');
1029 try comptime S.doTheTest('b');
1030}
1031
1032test "equality of pointers to comptime const" {
1033 const a: i32 = undefined;
1034 comptime assert(&a == &a);
1035}
1036
1037test "storing an array of type in a field" {
1038 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1040 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1041
1042 const S = struct {
1043 fn doTheTest() void {
1044 const foobar = Foobar.foo();
1045 foo(foobar.str[0..10]);
1046 }
1047 const Foobar = struct {
1048 myTypes: [128]type,
1049 str: [1024]u8,
1050
1051 fn foo() @This() {
1052 comptime var foobar: Foobar = undefined;
1053 foobar.str = @splat('a');
1054 return foobar;
1055 }
1056 };
1057
1058 fn foo(arg: anytype) void {
1059 _ = arg;
1060 }
1061 };
1062
1063 S.doTheTest();
1064}
1065
1066test "pass pointer to field of comptime-only type as a runtime parameter" {
1067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1069
1070 const S = struct {
1071 const Mixed = struct {
1072 T: type,
1073 x: i32,
1074 };
1075 const bag: Mixed = .{
1076 .T = bool,
1077 .x = 1234,
1078 };
1079
1080 var ok = false;
1081
1082 fn doTheTest() !void {
1083 foo(&bag.x);
1084 try expect(ok);
1085 }
1086
1087 fn foo(ptr: *const i32) void {
1088 ok = ptr.* == 1234;
1089 }
1090 };
1091 try S.doTheTest();
1092}
1093
1094test "comptime write through extern struct reinterpreted as array" {
1095 comptime {
1096 const S = extern struct {
1097 a: u8,
1098 b: u8,
1099 c: u8,
1100 };
1101 var s: S = undefined;
1102 @as(*[3]u8, @ptrCast(&s))[0] = 1;
1103 @as(*[3]u8, @ptrCast(&s))[1] = 2;
1104 @as(*[3]u8, @ptrCast(&s))[2] = 3;
1105 assert(s.a == 1);
1106 assert(s.b == 2);
1107 assert(s.c == 3);
1108 }
1109}
1110
1111test "continue nested in a conditional in an inline for" {
1112 var x: u32 = 1;
1113 inline for ([_]u8{ 1, 2, 3 }) |_| {
1114 if (1 == 1) {
1115 x = 0;
1116 continue;
1117 }
1118 }
1119 try expect(x == 0);
1120}
1121
1122test "optional pointer represented as a pointer value" {
1123 comptime {
1124 var val: u8 = 15;
1125 const opt_ptr: ?*u8 = &val;
1126
1127 const payload_ptr = &opt_ptr.?;
1128 try expect(payload_ptr.*.* == 15);
1129 }
1130}
1131
1132test "mutate through pointer-like optional at comptime" {
1133 comptime {
1134 var val: u8 = 15;
1135 var opt_ptr: ?*const u8 = &val;
1136
1137 const payload_ptr = &opt_ptr.?;
1138 payload_ptr.* = &@as(u8, 16);
1139 try expect(payload_ptr.*.* == 16);
1140 }
1141}
1142
1143test "repeated value is correctly expanded" {
1144 const S = struct { x: [4]i8 = std.mem.zeroes([4]i8) };
1145 const M = struct { x: [4]S = std.mem.zeroes([4]S) };
1146
1147 comptime {
1148 var res = M{};
1149 for (.{ 1, 2, 3 }) |i| res.x[i].x[i] = i;
1150
1151 try expectEqual(M{ .x = .{
1152 .{ .x = .{ 0, 0, 0, 0 } },
1153 .{ .x = .{ 0, 1, 0, 0 } },
1154 .{ .x = .{ 0, 0, 2, 0 } },
1155 .{ .x = .{ 0, 0, 0, 3 } },
1156 } }, res);
1157 }
1158}
1159
1160test "value in if block is comptime-known" {
1161 const first = blk: {
1162 const s = if (false) "a" else "b";
1163 break :blk "foo" ++ s;
1164 };
1165 const second = blk: {
1166 const S = struct { str: []const u8 };
1167 const s = if (false) S{ .str = "a" } else S{ .str = "b" };
1168 break :blk "foo" ++ s.str;
1169 };
1170 comptime assert(std.mem.eql(u8, first, second));
1171}
1172
1173test "lazy sizeof is resolved in division" {
1174 const A = struct {
1175 a: u32,
1176 };
1177 const a = 2;
1178 try expect(@sizeOf(A) / a == 2);
1179 try expect(@sizeOf(A) - a == 2);
1180}
1181
1182test "lazy sizeof union tag size in compare" {
1183 const A = union(enum) {
1184 a: void,
1185 b: void,
1186 };
1187 try expect(@sizeOf(A) == 1);
1188}
1189
1190test "lazy value is resolved as slice operand" {
1191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1193 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1195 const A = struct { a: u32 };
1196 var a: [512]u64 = undefined;
1197
1198 const ptr1 = a[0..@sizeOf(A)];
1199 const ptr2 = @as([*]u8, @ptrCast(&a))[0..@sizeOf(A)];
1200 try expect(@intFromPtr(ptr1) == @intFromPtr(ptr2));
1201 try expect(ptr1.len == ptr2.len);
1202}
1203
1204test "break from inline loop depends on runtime condition" {
1205 const S = struct {
1206 fn foo(a: u8) bool {
1207 return a == 4;
1208 }
1209 };
1210 const arr = [_]u8{ 1, 2, 3, 4 };
1211 {
1212 const blk = blk: {
1213 inline for (arr) |val| {
1214 if (S.foo(val)) {
1215 break :blk val;
1216 }
1217 }
1218 return error.TestFailed;
1219 };
1220 try expect(blk == 4);
1221 }
1222
1223 {
1224 comptime var i = 0;
1225 const blk = blk: {
1226 inline while (i < arr.len) : (i += 1) {
1227 const val = arr[i];
1228 if (S.foo(val)) {
1229 break :blk val;
1230 }
1231 }
1232 return error.TestFailed;
1233 };
1234 try expect(blk == 4);
1235 }
1236}
1237
1238test "inline for inside a runtime condition" {
1239 var a = false;
1240 _ = &a;
1241 if (a) {
1242 const arr = .{ 1, 2, 3 };
1243 inline for (arr) |val| {
1244 if (val < 3) continue;
1245 try expect(val == 3);
1246 }
1247 }
1248}
1249
1250test "continue in inline for inside a comptime switch" {
1251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1252
1253 const arr = .{ 1, 2, 3 };
1254 var count: u8 = 0;
1255 switch (arr[1]) {
1256 2 => {
1257 inline for (arr) |val| {
1258 if (val == 2) continue;
1259
1260 count += val;
1261 }
1262 },
1263 else => {},
1264 }
1265 try expect(count == 4);
1266}
1267
1268test "length of global array is determinable at comptime" {
1269 const S = struct {
1270 var bytes: [1024]u8 = undefined;
1271
1272 fn foo() !void {
1273 try std.testing.expect(bytes.len == 1024);
1274 }
1275 };
1276 try comptime S.foo();
1277}
1278
1279test "continue nested inline for loop" {
1280 // TODO: https://github.com/ziglang/zig/issues/13175
1281 if (true) return error.SkipZigTest;
1282
1283 var a: u8 = 0;
1284 loop: inline for ([_]u8{ 1, 2 }) |x| {
1285 inline for ([_]u8{1}) |y| {
1286 if (x == y) {
1287 continue :loop;
1288 }
1289 }
1290 a = x;
1291 try expect(x == 2);
1292 }
1293 try expect(a == 2);
1294}
1295
1296test "continue nested inline for loop in named block expr" {
1297 // TODO: https://github.com/ziglang/zig/issues/13175
1298 if (true) return error.SkipZigTest;
1299
1300 var a: u8 = 0;
1301 loop: inline for ([_]u8{ 1, 2 }) |x| {
1302 a = b: {
1303 inline for ([_]u8{1}) |y| {
1304 if (x == y) {
1305 continue :loop;
1306 }
1307 }
1308 break :b x;
1309 };
1310 try expect(x == 2);
1311 }
1312 try expect(a == 2);
1313}
1314
1315test "x and false is comptime-known false" {
1316 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1317
1318 const T = struct {
1319 var x: u32 = 0;
1320
1321 fn foo() bool {
1322 x += 1; // Observable side-effect
1323 return true;
1324 }
1325 };
1326
1327 if (T.foo() and T.foo() and false and T.foo()) {
1328 @compileError("Condition should be comptime-known false");
1329 }
1330 try expect(T.x == 2);
1331
1332 T.x = 0;
1333 if (T.foo() and T.foo() and b: {
1334 _ = T.foo();
1335 break :b false;
1336 } and T.foo()) {
1337 @compileError("Condition should be comptime-known false");
1338 }
1339 try expect(T.x == 3);
1340}
1341
1342test "x or true is comptime-known true" {
1343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1344
1345 const T = struct {
1346 var x: u32 = 0;
1347
1348 fn foo() bool {
1349 x += 1; // Observable side-effect
1350 return false;
1351 }
1352 };
1353
1354 if (!(T.foo() or T.foo() or true or T.foo())) {
1355 @compileError("Condition should be comptime-known false");
1356 }
1357 try expect(T.x == 2);
1358
1359 T.x = 0;
1360 if (!(T.foo() or T.foo() or b: {
1361 _ = T.foo();
1362 break :b true;
1363 } or T.foo())) {
1364 @compileError("Condition should be comptime-known false");
1365 }
1366 try expect(T.x == 3);
1367}
1368
1369test "non-optional and optional array elements concatenated" {
1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1373
1374 const array = [1]u8{'A'} ++ [1]?u8{null};
1375 var index: usize = 0;
1376 _ = &index;
1377 try expect(array[index].? == 'A');
1378}
1379
1380test "inline call in @TypeOf inherits is_inline property" {
1381 const S = struct {
1382 inline fn doNothing() void {}
1383 const T = @TypeOf(doNothing());
1384 };
1385 try expect(S.T == void);
1386}
1387
1388test "comptime function turns function value to function pointer" {
1389 const S = struct {
1390 fn fnPtr(function: anytype) *const @TypeOf(function) {
1391 return &function;
1392 }
1393 fn Nil() u8 {
1394 return 0;
1395 }
1396 const foo = &[_]*const fn () u8{
1397 fnPtr(Nil),
1398 };
1399 };
1400 comptime assert(S.foo[0] == &S.Nil);
1401}
1402
1403test "container level const and var have unique addresses" {
1404 const S = struct {
1405 x: i32,
1406 y: i32,
1407 const c = @This(){ .x = 1, .y = 1 };
1408 var v: @This() = c;
1409 };
1410 var p = &S.c;
1411 _ = &p;
1412 try std.testing.expect(p.x == S.c.x);
1413 S.v.x = 2;
1414 try std.testing.expect(p.x == S.c.x);
1415}
1416
1417test "break from block results in type" {
1418 const S = struct {
1419 fn NewType(comptime T: type) type {
1420 const Padded = blk: {
1421 if (@sizeOf(T) <= @sizeOf(usize)) break :blk void;
1422 break :blk T;
1423 };
1424
1425 return Padded;
1426 }
1427 };
1428 const T = S.NewType(usize);
1429 try expect(T == void);
1430}
1431
1432test "struct in comptime false branch is not evaluated" {
1433 const S = struct {
1434 const comptime_const = 2;
1435 fn some(comptime V: type) type {
1436 return switch (comptime_const) {
1437 3 => struct { a: V.foo },
1438 2 => V,
1439 else => unreachable,
1440 };
1441 }
1442 };
1443 try expect(S.some(u32) == u32);
1444}
1445
1446test "result of nested switch assigned to variable" {
1447 var zds: u32 = 0;
1448 zds = switch (zds) {
1449 0 => switch (zds) {
1450 0...0 => 1234,
1451 1...1 => zds,
1452 2 => zds,
1453 else => return,
1454 },
1455 else => zds,
1456 };
1457 try expect(zds == 1234);
1458}
1459
1460test "inline for loop of functions returning error unions" {
1461 const T1 = struct {
1462 fn v() error{}!usize {
1463 return 1;
1464 }
1465 };
1466 const T2 = struct {
1467 fn v() error{Error}!usize {
1468 return 2;
1469 }
1470 };
1471 var a: usize = 0;
1472 inline for (.{ T1, T2 }) |T| {
1473 a += try T.v();
1474 }
1475 try expect(a == 3);
1476}
1477
1478test "if inside a switch" {
1479 var condition = true;
1480 var wave_type: u32 = 0;
1481 _ = .{ &condition, &wave_type };
1482 const sample: i32 = switch (wave_type) {
1483 0 => if (condition) 2 else 3,
1484 1 => 100,
1485 2 => 200,
1486 3 => 300,
1487 else => unreachable,
1488 };
1489 try expect(sample == 2);
1490}
1491
1492test "function has correct return type when previous return is casted to smaller type" {
1493 const S = struct {
1494 fn foo(b: bool) u16 {
1495 if (b) return @as(u8, 0xFF);
1496 return 0xFFFF;
1497 }
1498 };
1499 try expect(S.foo(true) == 0xFF);
1500}
1501
1502test "early exit in container level const" {
1503 const S = struct {
1504 const value = blk: {
1505 if (true) {
1506 break :blk @as(u32, 1);
1507 }
1508 break :blk @as(u32, 0);
1509 };
1510 };
1511 try expect(S.value == 1);
1512}
1513
1514test "@inComptime" {
1515 const S = struct {
1516 fn inComptime() bool {
1517 return @inComptime();
1518 }
1519 };
1520 try expectEqual(false, @inComptime());
1521 try expectEqual(false, S.inComptime());
1522 try expectEqual(true, comptime S.inComptime());
1523}
1524
1525// comptime partial array assign
1526comptime {
1527 var foo = [3]u8{ 0x55, 0x55, 0x55 };
1528 var bar = [2]u8{ 1, 2 };
1529 _ = .{ &foo, &bar };
1530 foo[0..2].* = bar;
1531 assert(foo[0] == 1);
1532 assert(foo[1] == 2);
1533 assert(foo[2] == 0x55);
1534}
1535
1536test "const with allocation before result is comptime-known" {
1537 const x = blk: {
1538 const y = [1]u32{2};
1539 _ = y;
1540 break :blk [1]u32{42};
1541 };
1542 comptime assert(@TypeOf(x) == [1]u32);
1543 comptime assert(x[0] == 42);
1544}
1545
1546test "const with specified type initialized with typed array is comptime-known" {
1547 const x: [3]u16 = [3]u16{ 1, 2, 3 };
1548 comptime assert(@TypeOf(x) == [3]u16);
1549 comptime assert(x[0] == 1);
1550 comptime assert(x[1] == 2);
1551 comptime assert(x[2] == 3);
1552}
1553
1554test "block with comptime-known result but possible runtime exit is comptime-known" {
1555 var t: bool = true;
1556 _ = &t;
1557
1558 const a: comptime_int = a: {
1559 if (!t) return error.TestFailed;
1560 break :a 123;
1561 };
1562
1563 const b: comptime_int = b: {
1564 if (t) break :b 456;
1565 return error.TestFailed;
1566 };
1567
1568 comptime assert(a == 123);
1569 comptime assert(b == 456);
1570}
1571
1572test "comptime labeled block implicit exit" {
1573 const result = comptime b: {
1574 if (false) break :b 123;
1575 };
1576 comptime assert(result == {});
1577}
1578
1579test "comptime block has intermediate runtime-known values" {
1580 const arr: [2]u8 = .{ 1, 2 };
1581
1582 var idx: usize = undefined;
1583 idx = 0;
1584
1585 comptime {
1586 _ = arr[idx];
1587 }
1588}