authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-07 11:07:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-07 11:08:08-07:00
log259f3458a162120288eb80dea4e55cd4ed9cf4c5
treebe93f1e502b55b3d831d2cb1f267810d083df3c0
parent5789036b86bcc95b2e017ed7330aaf7ccbfa3d5f

Sema: implement alloc_inferred_comptime


4 files changed, 726 insertions(+), 718 deletions(-)

src/Sema.zig+7-3
......@@ -139,7 +139,7 @@ pub fn analyzeBody(
139139 .alloc => try sema.zirAlloc(block, inst),
140140 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
141141 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
142 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
142 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst),
143143 .alloc_mut => try sema.zirAllocMut(block, inst),
144144 .alloc_comptime => try sema.zirAllocComptime(block, inst),
145145 .anyframe_type => try sema.zirAnyframeType(block, inst),
......@@ -1384,10 +1384,14 @@ fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
13841384 return sema.analyzeComptimeAlloc(block, var_type);
13851385}
13861386
1387fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1387fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
13881388 const src_node = sema.code.instructions.items(.data)[inst].node;
13891389 const src: LazySrcLoc = .{ .node_offset = src_node };
1390 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocInferredComptime", .{});
1390 sema.src = src;
1391 return sema.addConstant(
1392 Type.initTag(.inferred_alloc_mut),
1393 try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined),
1394 );
13911395}
13921396
13931397fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior.zig+2-1
......@@ -5,6 +5,7 @@ test {
55 _ = @import("behavior/bool.zig");
66 _ = @import("behavior/basic.zig");
77 _ = @import("behavior/generics.zig");
8 _ = @import("behavior/eval.zig");
89
910 if (!builtin.zig_is_stage2) {
1011 // Tests that only pass for stage1.
......@@ -88,7 +89,7 @@ test {
8889 _ = @import("behavior/enum.zig");
8990 _ = @import("behavior/enum_with_members.zig");
9091 _ = @import("behavior/error.zig");
91 _ = @import("behavior/eval.zig");
92 _ = @import("behavior/eval_stage1.zig");
9293 _ = @import("behavior/field_parent_ptr.zig");
9394 _ = @import("behavior/floatop.zig");
9495 _ = @import("behavior/fn.zig");
test/behavior/eval.zig-714
......@@ -63,146 +63,12 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
6363 return result;
6464}
6565
66test "statically initialized list" {
67 try expect(static_point_list[0].x == 1);
68 try expect(static_point_list[0].y == 2);
69 try expect(static_point_list[1].x == 3);
70 try expect(static_point_list[1].y == 4);
71}
72const Point = struct {
73 x: i32,
74 y: i32,
75};
76const static_point_list = [_]Point{
77 makePoint(1, 2),
78 makePoint(3, 4),
79};
80fn makePoint(x: i32, y: i32) Point {
81 return Point{
82 .x = x,
83 .y = y,
84 };
85}
86
87test "static eval list init" {
88 try expect(static_vec3.data[2] == 1.0);
89 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
90}
91const static_vec3 = vec3(0.0, 0.0, 1.0);
92pub const Vec3 = struct {
93 data: [3]f32,
94};
95pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
96 return Vec3{
97 .data = [_]f32{
98 x,
99 y,
100 z,
101 },
102 };
103}
104
10566test "constant expressions" {
10667 var array: [array_size]u8 = undefined;
10768 try expect(@sizeOf(@TypeOf(array)) == 20);
10869}
10970const array_size: u8 = 20;
11071
111test "constant struct with negation" {
112 try expect(vertices[0].x == -0.6);
113}
114const Vertex = struct {
115 x: f32,
116 y: f32,
117 r: f32,
118 g: f32,
119 b: f32,
120};
121const vertices = [_]Vertex{
122 Vertex{
123 .x = -0.6,
124 .y = -0.4,
125 .r = 1.0,
126 .g = 0.0,
127 .b = 0.0,
128 },
129 Vertex{
130 .x = 0.6,
131 .y = -0.4,
132 .r = 0.0,
133 .g = 1.0,
134 .b = 0.0,
135 },
136 Vertex{
137 .x = 0.0,
138 .y = 0.6,
139 .r = 0.0,
140 .g = 0.0,
141 .b = 1.0,
142 },
143};
144
145test "statically initialized struct" {
146 st_init_str_foo.x += 1;
147 try expect(st_init_str_foo.x == 14);
148}
149const StInitStrFoo = struct {
150 x: i32,
151 y: bool,
152};
153var st_init_str_foo = StInitStrFoo{
154 .x = 13,
155 .y = true,
156};
157
158test "statically initalized array literal" {
159 const y: [4]u8 = st_init_arr_lit_x;
160 try expect(y[3] == 4);
161}
162const st_init_arr_lit_x = [_]u8{
163 1,
164 2,
165 3,
166 4,
167};
168
169test "const slice" {
170 comptime {
171 const a = "1234567890";
172 try expect(a.len == 10);
173 const b = a[1..2];
174 try expect(b.len == 1);
175 try expect(b[0] == '2');
176 }
177}
178
179test "try to trick eval with runtime if" {
180 try expect(testTryToTrickEvalWithRuntimeIf(true) == 10);
181}
182
183fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
184 comptime var i: usize = 0;
185 inline while (i < 10) : (i += 1) {
186 const result = if (b) false else true;
187 _ = result;
188 }
189 comptime {
190 return i;
191 }
192}
193
194test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
195 var runtime = [1]i32{3};
196 comptime var i: usize = 0;
197 inline while (i < 2) : (i += 1) {
198 const result = if (i == 0) [1]i32{2} else runtime;
199 _ = result;
200 }
201 comptime {
202 try expect(i == 2);
203 }
204}
205
20672fn max(comptime T: type, a: T, b: T) T {
20773 if (T == bool) {
20874 return a or b;
......@@ -229,52 +95,6 @@ test "inlined block and runtime block phi" {
22995 }
23096}
23197
232const CmdFn = struct {
233 name: []const u8,
234 func: fn (i32) i32,
235};
236
237const cmd_fns = [_]CmdFn{
238 CmdFn{
239 .name = "one",
240 .func = one,
241 },
242 CmdFn{
243 .name = "two",
244 .func = two,
245 },
246 CmdFn{
247 .name = "three",
248 .func = three,
249 },
250};
251fn one(value: i32) i32 {
252 return value + 1;
253}
254fn two(value: i32) i32 {
255 return value + 2;
256}
257fn three(value: i32) i32 {
258 return value + 3;
259}
260
261fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
262 var result: i32 = start_value;
263 comptime var i = 0;
264 inline while (i < cmd_fns.len) : (i += 1) {
265 if (cmd_fns[i].name[0] == prefix_char) {
266 result = cmd_fns[i].func(result);
267 }
268 }
269 return result;
270}
271
272test "comptime iterate over fn ptr list" {
273 try expect(performFn('t', 1) == 6);
274 try expect(performFn('o', 0) == 1);
275 try expect(performFn('w', 99) == 99);
276}
277
27898test "eval @setRuntimeSafety at compile-time" {
27999 const result = comptime fnWithSetRuntimeSafety();
280100 try expect(result == 1234);
......@@ -285,90 +105,6 @@ fn fnWithSetRuntimeSafety() i32 {
285105 return 1234;
286106}
287107
288test "eval @setFloatMode at compile-time" {
289 const result = comptime fnWithFloatMode();
290 try expect(result == 1234.0);
291}
292
293fn fnWithFloatMode() f32 {
294 @setFloatMode(std.builtin.FloatMode.Strict);
295 return 1234.0;
296}
297
298const SimpleStruct = struct {
299 field: i32,
300
301 fn method(self: *const SimpleStruct) i32 {
302 return self.field + 3;
303 }
304};
305
306var simple_struct = SimpleStruct{ .field = 1234 };
307
308const bound_fn = simple_struct.method;
309
310test "call method on bound fn referring to var instance" {
311 try expect(bound_fn() == 1237);
312}
313
314test "ptr to local array argument at comptime" {
315 comptime {
316 var bytes: [10]u8 = undefined;
317 modifySomeBytes(bytes[0..]);
318 try expect(bytes[0] == 'a');
319 try expect(bytes[9] == 'b');
320 }
321}
322
323fn modifySomeBytes(bytes: []u8) void {
324 bytes[0] = 'a';
325 bytes[9] = 'b';
326}
327
328test "comparisons 0 <= uint and 0 > uint should be comptime" {
329 testCompTimeUIntComparisons(1234);
330}
331fn testCompTimeUIntComparisons(x: u32) void {
332 if (!(0 <= x)) {
333 @compileError("this condition should be comptime known");
334 }
335 if (0 > x) {
336 @compileError("this condition should be comptime known");
337 }
338 if (!(x >= 0)) {
339 @compileError("this condition should be comptime known");
340 }
341 if (x < 0) {
342 @compileError("this condition should be comptime known");
343 }
344}
345
346test "const ptr to variable data changes at runtime" {
347 try expect(foo_ref.name[0] == 'a');
348 foo_ref.name = "b";
349 try expect(foo_ref.name[0] == 'b');
350}
351
352const Foo = struct {
353 name: []const u8,
354};
355
356var foo_contents = Foo{ .name = "a" };
357const foo_ref = &foo_contents;
358
359test "create global array with for loop" {
360 try expect(global_array[5] == 5 * 5);
361 try expect(global_array[9] == 9 * 9);
362}
363
364const global_array = x: {
365 var result: [10]usize = undefined;
366 for (result) |*item, index| {
367 item.* = index * index;
368 }
369 break :x result;
370};
371
372108test "compile-time downcast when the bits fit" {
373109 comptime {
374110 const spartan_count: u16 = 255;
......@@ -377,231 +113,6 @@ test "compile-time downcast when the bits fit" {
377113 }
378114}
379115
380const hi1 = "hi";
381const hi2 = hi1;
382test "const global shares pointer with other same one" {
383 try assertEqualPtrs(&hi1[0], &hi2[0]);
384 comptime try expect(&hi1[0] == &hi2[0]);
385}
386fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void {
387 try expect(ptr1 == ptr2);
388}
389
390test "@setEvalBranchQuota" {
391 comptime {
392 // 1001 for the loop and then 1 more for the expect fn call
393 @setEvalBranchQuota(1002);
394 var i = 0;
395 var sum = 0;
396 while (i < 1001) : (i += 1) {
397 sum += i;
398 }
399 try expect(sum == 500500);
400 }
401}
402
403test "float literal at compile time not lossy" {
404 try expect(16777216.0 + 1.0 == 16777217.0);
405 try expect(9007199254740992.0 + 1.0 == 9007199254740993.0);
406}
407
408test "f32 at compile time is lossy" {
409 try expect(@as(f32, 1 << 24) + 1 == 1 << 24);
410}
411
412test "f64 at compile time is lossy" {
413 try expect(@as(f64, 1 << 53) + 1 == 1 << 53);
414}
415
416test "f128 at compile time is lossy" {
417 try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
418}
419
420test {
421 comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
422}
423
424pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
425 _ = field_name;
426 return struct {
427 pub const Node = struct {};
428 };
429}
430
431test "string literal used as comptime slice is memoized" {
432 const a = "link";
433 const b = "link";
434 comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
435 comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
436}
437
438test "comptime slice of undefined pointer of length 0" {
439 const slice1 = @as([*]i32, undefined)[0..0];
440 try expect(slice1.len == 0);
441 const slice2 = @as([*]i32, undefined)[100..100];
442 try expect(slice2.len == 0);
443}
444
445fn copyWithPartialInline(s: []u32, b: []u8) void {
446 comptime var i: usize = 0;
447 inline while (i < 4) : (i += 1) {
448 s[i] = 0;
449 s[i] |= @as(u32, b[i * 4 + 0]) << 24;
450 s[i] |= @as(u32, b[i * 4 + 1]) << 16;
451 s[i] |= @as(u32, b[i * 4 + 2]) << 8;
452 s[i] |= @as(u32, b[i * 4 + 3]) << 0;
453 }
454}
455
456test "binary math operator in partially inlined function" {
457 var s: [4]u32 = undefined;
458 var b: [16]u8 = undefined;
459
460 for (b) |*r, i|
461 r.* = @intCast(u8, i + 1);
462
463 copyWithPartialInline(s[0..], b[0..]);
464 try expect(s[0] == 0x1020304);
465 try expect(s[1] == 0x5060708);
466 try expect(s[2] == 0x90a0b0c);
467 try expect(s[3] == 0xd0e0f10);
468}
469
470test "comptime function with the same args is memoized" {
471 comptime {
472 try expect(MakeType(i32) == MakeType(i32));
473 try expect(MakeType(i32) != MakeType(f64));
474 }
475}
476
477fn MakeType(comptime T: type) type {
478 return struct {
479 field: T,
480 };
481}
482
483test "comptime function with mutable pointer is not memoized" {
484 comptime {
485 var x: i32 = 1;
486 const ptr = &x;
487 increment(ptr);
488 increment(ptr);
489 try expect(x == 3);
490 }
491}
492
493fn increment(value: *i32) void {
494 value.* += 1;
495}
496
497fn generateTable(comptime T: type) [1010]T {
498 var res: [1010]T = undefined;
499 var i: usize = 0;
500 while (i < 1010) : (i += 1) {
501 res[i] = @intCast(T, i);
502 }
503 return res;
504}
505
506fn doesAlotT(comptime T: type, value: usize) T {
507 @setEvalBranchQuota(5000);
508 const table = comptime blk: {
509 break :blk generateTable(T);
510 };
511 return table[value];
512}
513
514test "@setEvalBranchQuota at same scope as generic function call" {
515 try expect(doesAlotT(u32, 2) == 2);
516}
517
518test "comptime slice of slice preserves comptime var" {
519 comptime {
520 var buff: [10]u8 = undefined;
521 buff[0..][0..][0] = 1;
522 try expect(buff[0..][0..][0] == 1);
523 }
524}
525
526test "comptime slice of pointer preserves comptime var" {
527 comptime {
528 var buff: [10]u8 = undefined;
529 var a = @ptrCast([*]u8, &buff);
530 a[0..1][0] = 1;
531 try expect(buff[0..][0..][0] == 1);
532 }
533}
534
535const SingleFieldStruct = struct {
536 x: i32,
537
538 fn read_x(self: *const SingleFieldStruct) i32 {
539 return self.x;
540 }
541};
542test "const ptr to comptime mutable data is not memoized" {
543 comptime {
544 var foo = SingleFieldStruct{ .x = 1 };
545 try expect(foo.read_x() == 1);
546 foo.x = 2;
547 try expect(foo.read_x() == 2);
548 }
549}
550
551test "array concat of slices gives slice" {
552 comptime {
553 var a: []const u8 = "aoeu";
554 var b: []const u8 = "asdf";
555 const c = a ++ b;
556 try expect(std.mem.eql(u8, c, "aoeuasdf"));
557 }
558}
559
560test "comptime shlWithOverflow" {
561 const ct_shifted: u64 = comptime amt: {
562 var amt = @as(u64, 0);
563 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
564 break :amt amt;
565 };
566
567 const rt_shifted: u64 = amt: {
568 var amt = @as(u64, 0);
569 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
570 break :amt amt;
571 };
572
573 try expect(ct_shifted == rt_shifted);
574}
575
576test "comptime shl" {
577 var a: u128 = 3;
578 var b: u7 = 63;
579 var c: u128 = 3 << 63;
580 try expectEqual(a << b, c);
581}
582
583test "runtime 128 bit integer division" {
584 var a: u128 = 152313999999999991610955792383;
585 var b: u128 = 10000000000000000000;
586 var c = a / b;
587 try expect(c == 15231399999);
588}
589
590pub const Info = struct {
591 version: u8,
592};
593
594pub const diamond_info = Info{ .version = 0 };
595
596test "comptime modification of const struct field" {
597 comptime {
598 var res = diamond_info;
599 res.version = 1;
600 try expect(diamond_info.version == 0);
601 try expect(res.version == 1);
602 }
603}
604
605116test "pointer to type" {
606117 comptime {
607118 var T: type = i32;
......@@ -614,233 +125,8 @@ test "pointer to type" {
614125 }
615126}
616127
617test "slice of type" {
618 comptime {
619 var types_array = [_]type{ i32, f64, type };
620 for (types_array) |T, i| {
621 switch (i) {
622 0 => try expect(T == i32),
623 1 => try expect(T == f64),
624 2 => try expect(T == type),
625 else => unreachable,
626 }
627 }
628 for (types_array[0..]) |T, i| {
629 switch (i) {
630 0 => try expect(T == i32),
631 1 => try expect(T == f64),
632 2 => try expect(T == type),
633 else => unreachable,
634 }
635 }
636 }
637}
638
639const Wrapper = struct {
640 T: type,
641};
642
643fn wrap(comptime T: type) Wrapper {
644 return Wrapper{ .T = T };
645}
646
647test "function which returns struct with type field causes implicit comptime" {
648 const ty = wrap(i32).T;
649 try expect(ty == i32);
650}
651
652test "call method with comptime pass-by-non-copying-value self parameter" {
653 const S = struct {
654 a: u8,
655
656 fn b(comptime s: @This()) u8 {
657 return s.a;
658 }
659 };
660
661 const s = S{ .a = 2 };
662 var b = s.b();
663 try expect(b == 2);
664}
665
666test "@tagName of @typeInfo" {
667 const str = @tagName(@typeInfo(u8));
668 try expect(std.mem.eql(u8, str, "Int"));
669}
670
671test "setting backward branch quota just before a generic fn call" {
672 @setEvalBranchQuota(1001);
673 loopNTimes(1001);
674}
675
676fn loopNTimes(comptime n: usize) void {
677 comptime var i = 0;
678 inline while (i < n) : (i += 1) {}
679}
680
681test "variable inside inline loop that has different types on different iterations" {
682 try testVarInsideInlineLoop(.{ true, @as(u32, 42) });
683}
684
685fn testVarInsideInlineLoop(args: anytype) !void {
686 comptime var i = 0;
687 inline while (i < args.len) : (i += 1) {
688 const x = args[i];
689 if (i == 0) try expect(x);
690 if (i == 1) try expect(x == 42);
691 }
692}
693
694test "inline for with same type but different values" {
695 var res: usize = 0;
696 inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
697 var a: T = undefined;
698 res += a.len;
699 }
700 try expect(res == 5);
701}
702
703test "refer to the type of a generic function" {
704 const Func = fn (type) void;
705 const f: Func = doNothingWithType;
706 f(i32);
707}
708
709fn doNothingWithType(comptime T: type) void {
710 _ = T;
711}
712
713test "zero extend from u0 to u1" {
714 var zero_u0: u0 = 0;
715 var zero_u1: u1 = zero_u0;
716 try expect(zero_u1 == 0);
717}
718
719test "bit shift a u1" {
720 var x: u1 = 1;
721 var y = x << 0;
722 try expect(y == 1);
723}
724
725test "comptime pointer cast array and then slice" {
726 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
727
728 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
729 const sliceA: []const u8 = ptrA[0..2];
730
731 const ptrB: [*]const u8 = &array;
732 const sliceB: []const u8 = ptrB[0..2];
733
734 try expect(sliceA[1] == 2);
735 try expect(sliceB[1] == 2);
736}
737
738test "slice bounds in comptime concatenation" {
739 const bs = comptime blk: {
740 const b = "........1........";
741 break :blk b[8..9];
742 };
743 const str = "" ++ bs;
744 try expect(str.len == 1);
745 try expect(std.mem.eql(u8, str, "1"));
746
747 const str2 = bs ++ "";
748 try expect(str2.len == 1);
749 try expect(std.mem.eql(u8, str2, "1"));
750}
751
752test "comptime bitwise operators" {
753 comptime {
754 try expect(3 & 1 == 1);
755 try expect(3 & -1 == 3);
756 try expect(-3 & -1 == -3);
757 try expect(3 | -1 == -1);
758 try expect(-3 | -1 == -1);
759 try expect(3 ^ -1 == -4);
760 try expect(-3 ^ -1 == 2);
761 try expect(~@as(i8, -1) == 0);
762 try expect(~@as(i128, -1) == 0);
763 try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
764 try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
765 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
766 }
767}
768
769test "*align(1) u16 is the same as *align(1:0:2) u16" {
770 comptime {
771 try expect(*align(1:0:2) u16 == *align(1) u16);
772 try expect(*align(2:0:2) u16 == *u16);
773 }
774}
775
776test "array concatenation forces comptime" {
777 var a = oneItem(3) ++ oneItem(4);
778 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
779}
780
781test "array multiplication forces comptime" {
782 var a = oneItem(3) ** scalar(2);
783 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
784}
785
786fn oneItem(x: i32) [1]i32 {
787 return [_]i32{x};
788}
789
790fn scalar(x: u32) u32 {
791 return x;
792}
793
794128test "no undeclared identifier error in unanalyzed branches" {
795129 if (false) {
796130 lol_this_doesnt_exist = nonsense;
797131 }
798132}
799
800test "comptime assign int to optional int" {
801 comptime {
802 var x: ?i32 = null;
803 x = 2;
804 x.? *= 10;
805 try expectEqual(20, x.?);
806 }
807}
808
809test "return 0 from function that has u0 return type" {
810 const S = struct {
811 fn foo_zero() u0 {
812 return 0;
813 }
814 };
815 comptime {
816 if (S.foo_zero() != 0) {
817 @compileError("test failed");
818 }
819 }
820}
821
822test "two comptime calls with array default initialized to undefined" {
823 const S = struct {
824 const CrossTarget = struct {
825 dynamic_linker: DynamicLinker = DynamicLinker{},
826
827 pub fn parse() void {
828 var result: CrossTarget = .{};
829 result.getCpuArch();
830 }
831
832 pub fn getCpuArch(self: CrossTarget) void {
833 _ = self;
834 }
835 };
836
837 const DynamicLinker = struct {
838 buffer: [255]u8 = undefined,
839 };
840 };
841
842 comptime {
843 S.CrossTarget.parse();
844 S.CrossTarget.parse();
845 }
846}
test/behavior/eval_stage1.zig created+717
......@@ -0,0 +1,717 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4
5test "statically initialized list" {
6 try expect(static_point_list[0].x == 1);
7 try expect(static_point_list[0].y == 2);
8 try expect(static_point_list[1].x == 3);
9 try expect(static_point_list[1].y == 4);
10}
11const Point = struct {
12 x: i32,
13 y: i32,
14};
15const static_point_list = [_]Point{
16 makePoint(1, 2),
17 makePoint(3, 4),
18};
19fn makePoint(x: i32, y: i32) Point {
20 return Point{
21 .x = x,
22 .y = y,
23 };
24}
25
26test "static eval list init" {
27 try expect(static_vec3.data[2] == 1.0);
28 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
29}
30const static_vec3 = vec3(0.0, 0.0, 1.0);
31pub const Vec3 = struct {
32 data: [3]f32,
33};
34pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
35 return Vec3{
36 .data = [_]f32{
37 x,
38 y,
39 z,
40 },
41 };
42}
43
44test "constant struct with negation" {
45 try expect(vertices[0].x == -0.6);
46}
47const Vertex = struct {
48 x: f32,
49 y: f32,
50 r: f32,
51 g: f32,
52 b: f32,
53};
54const vertices = [_]Vertex{
55 Vertex{
56 .x = -0.6,
57 .y = -0.4,
58 .r = 1.0,
59 .g = 0.0,
60 .b = 0.0,
61 },
62 Vertex{
63 .x = 0.6,
64 .y = -0.4,
65 .r = 0.0,
66 .g = 1.0,
67 .b = 0.0,
68 },
69 Vertex{
70 .x = 0.0,
71 .y = 0.6,
72 .r = 0.0,
73 .g = 0.0,
74 .b = 1.0,
75 },
76};
77
78test "statically initialized struct" {
79 st_init_str_foo.x += 1;
80 try expect(st_init_str_foo.x == 14);
81}
82const StInitStrFoo = struct {
83 x: i32,
84 y: bool,
85};
86var st_init_str_foo = StInitStrFoo{
87 .x = 13,
88 .y = true,
89};
90
91test "statically initalized array literal" {
92 const y: [4]u8 = st_init_arr_lit_x;
93 try expect(y[3] == 4);
94}
95const st_init_arr_lit_x = [_]u8{
96 1,
97 2,
98 3,
99 4,
100};
101
102test "const slice" {
103 comptime {
104 const a = "1234567890";
105 try expect(a.len == 10);
106 const b = a[1..2];
107 try expect(b.len == 1);
108 try expect(b[0] == '2');
109 }
110}
111
112test "try to trick eval with runtime if" {
113 try expect(testTryToTrickEvalWithRuntimeIf(true) == 10);
114}
115
116fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
117 comptime var i: usize = 0;
118 inline while (i < 10) : (i += 1) {
119 const result = if (b) false else true;
120 _ = result;
121 }
122 comptime {
123 return i;
124 }
125}
126
127test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
128 var runtime = [1]i32{3};
129 comptime var i: usize = 0;
130 inline while (i < 2) : (i += 1) {
131 const result = if (i == 0) [1]i32{2} else runtime;
132 _ = result;
133 }
134 comptime {
135 try expect(i == 2);
136 }
137}
138
139const CmdFn = struct {
140 name: []const u8,
141 func: fn (i32) i32,
142};
143
144const cmd_fns = [_]CmdFn{
145 CmdFn{
146 .name = "one",
147 .func = one,
148 },
149 CmdFn{
150 .name = "two",
151 .func = two,
152 },
153 CmdFn{
154 .name = "three",
155 .func = three,
156 },
157};
158fn one(value: i32) i32 {
159 return value + 1;
160}
161fn two(value: i32) i32 {
162 return value + 2;
163}
164fn three(value: i32) i32 {
165 return value + 3;
166}
167
168fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
169 var result: i32 = start_value;
170 comptime var i = 0;
171 inline while (i < cmd_fns.len) : (i += 1) {
172 if (cmd_fns[i].name[0] == prefix_char) {
173 result = cmd_fns[i].func(result);
174 }
175 }
176 return result;
177}
178
179test "comptime iterate over fn ptr list" {
180 try expect(performFn('t', 1) == 6);
181 try expect(performFn('o', 0) == 1);
182 try expect(performFn('w', 99) == 99);
183}
184
185test "eval @setFloatMode at compile-time" {
186 const result = comptime fnWithFloatMode();
187 try expect(result == 1234.0);
188}
189
190fn fnWithFloatMode() f32 {
191 @setFloatMode(std.builtin.FloatMode.Strict);
192 return 1234.0;
193}
194
195const SimpleStruct = struct {
196 field: i32,
197
198 fn method(self: *const SimpleStruct) i32 {
199 return self.field + 3;
200 }
201};
202
203var simple_struct = SimpleStruct{ .field = 1234 };
204
205const bound_fn = simple_struct.method;
206
207test "call method on bound fn referring to var instance" {
208 try expect(bound_fn() == 1237);
209}
210
211test "ptr to local array argument at comptime" {
212 comptime {
213 var bytes: [10]u8 = undefined;
214 modifySomeBytes(bytes[0..]);
215 try expect(bytes[0] == 'a');
216 try expect(bytes[9] == 'b');
217 }
218}
219
220fn modifySomeBytes(bytes: []u8) void {
221 bytes[0] = 'a';
222 bytes[9] = 'b';
223}
224
225test "comparisons 0 <= uint and 0 > uint should be comptime" {
226 testCompTimeUIntComparisons(1234);
227}
228fn testCompTimeUIntComparisons(x: u32) void {
229 if (!(0 <= x)) {
230 @compileError("this condition should be comptime known");
231 }
232 if (0 > x) {
233 @compileError("this condition should be comptime known");
234 }
235 if (!(x >= 0)) {
236 @compileError("this condition should be comptime known");
237 }
238 if (x < 0) {
239 @compileError("this condition should be comptime known");
240 }
241}
242
243test "const ptr to variable data changes at runtime" {
244 try expect(foo_ref.name[0] == 'a');
245 foo_ref.name = "b";
246 try expect(foo_ref.name[0] == 'b');
247}
248
249const Foo = struct {
250 name: []const u8,
251};
252
253var foo_contents = Foo{ .name = "a" };
254const foo_ref = &foo_contents;
255
256test "create global array with for loop" {
257 try expect(global_array[5] == 5 * 5);
258 try expect(global_array[9] == 9 * 9);
259}
260
261const global_array = x: {
262 var result: [10]usize = undefined;
263 for (result) |*item, index| {
264 item.* = index * index;
265 }
266 break :x result;
267};
268
269const hi1 = "hi";
270const hi2 = hi1;
271test "const global shares pointer with other same one" {
272 try assertEqualPtrs(&hi1[0], &hi2[0]);
273 comptime try expect(&hi1[0] == &hi2[0]);
274}
275fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void {
276 try expect(ptr1 == ptr2);
277}
278
279test "@setEvalBranchQuota" {
280 comptime {
281 // 1001 for the loop and then 1 more for the expect fn call
282 @setEvalBranchQuota(1002);
283 var i = 0;
284 var sum = 0;
285 while (i < 1001) : (i += 1) {
286 sum += i;
287 }
288 try expect(sum == 500500);
289 }
290}
291
292test "float literal at compile time not lossy" {
293 try expect(16777216.0 + 1.0 == 16777217.0);
294 try expect(9007199254740992.0 + 1.0 == 9007199254740993.0);
295}
296
297test "f32 at compile time is lossy" {
298 try expect(@as(f32, 1 << 24) + 1 == 1 << 24);
299}
300
301test "f64 at compile time is lossy" {
302 try expect(@as(f64, 1 << 53) + 1 == 1 << 53);
303}
304
305test "f128 at compile time is lossy" {
306 try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
307}
308
309test {
310 comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
311}
312
313pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
314 _ = field_name;
315 return struct {
316 pub const Node = struct {};
317 };
318}
319
320test "string literal used as comptime slice is memoized" {
321 const a = "link";
322 const b = "link";
323 comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
324 comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
325}
326
327test "comptime slice of undefined pointer of length 0" {
328 const slice1 = @as([*]i32, undefined)[0..0];
329 try expect(slice1.len == 0);
330 const slice2 = @as([*]i32, undefined)[100..100];
331 try expect(slice2.len == 0);
332}
333
334fn copyWithPartialInline(s: []u32, b: []u8) void {
335 comptime var i: usize = 0;
336 inline while (i < 4) : (i += 1) {
337 s[i] = 0;
338 s[i] |= @as(u32, b[i * 4 + 0]) << 24;
339 s[i] |= @as(u32, b[i * 4 + 1]) << 16;
340 s[i] |= @as(u32, b[i * 4 + 2]) << 8;
341 s[i] |= @as(u32, b[i * 4 + 3]) << 0;
342 }
343}
344
345test "binary math operator in partially inlined function" {
346 var s: [4]u32 = undefined;
347 var b: [16]u8 = undefined;
348
349 for (b) |*r, i|
350 r.* = @intCast(u8, i + 1);
351
352 copyWithPartialInline(s[0..], b[0..]);
353 try expect(s[0] == 0x1020304);
354 try expect(s[1] == 0x5060708);
355 try expect(s[2] == 0x90a0b0c);
356 try expect(s[3] == 0xd0e0f10);
357}
358
359test "comptime function with the same args is memoized" {
360 comptime {
361 try expect(MakeType(i32) == MakeType(i32));
362 try expect(MakeType(i32) != MakeType(f64));
363 }
364}
365
366fn MakeType(comptime T: type) type {
367 return struct {
368 field: T,
369 };
370}
371
372test "comptime function with mutable pointer is not memoized" {
373 comptime {
374 var x: i32 = 1;
375 const ptr = &x;
376 increment(ptr);
377 increment(ptr);
378 try expect(x == 3);
379 }
380}
381
382fn increment(value: *i32) void {
383 value.* += 1;
384}
385
386fn generateTable(comptime T: type) [1010]T {
387 var res: [1010]T = undefined;
388 var i: usize = 0;
389 while (i < 1010) : (i += 1) {
390 res[i] = @intCast(T, i);
391 }
392 return res;
393}
394
395fn doesAlotT(comptime T: type, value: usize) T {
396 @setEvalBranchQuota(5000);
397 const table = comptime blk: {
398 break :blk generateTable(T);
399 };
400 return table[value];
401}
402
403test "@setEvalBranchQuota at same scope as generic function call" {
404 try expect(doesAlotT(u32, 2) == 2);
405}
406
407test "comptime slice of slice preserves comptime var" {
408 comptime {
409 var buff: [10]u8 = undefined;
410 buff[0..][0..][0] = 1;
411 try expect(buff[0..][0..][0] == 1);
412 }
413}
414
415test "comptime slice of pointer preserves comptime var" {
416 comptime {
417 var buff: [10]u8 = undefined;
418 var a = @ptrCast([*]u8, &buff);
419 a[0..1][0] = 1;
420 try expect(buff[0..][0..][0] == 1);
421 }
422}
423
424const SingleFieldStruct = struct {
425 x: i32,
426
427 fn read_x(self: *const SingleFieldStruct) i32 {
428 return self.x;
429 }
430};
431test "const ptr to comptime mutable data is not memoized" {
432 comptime {
433 var foo = SingleFieldStruct{ .x = 1 };
434 try expect(foo.read_x() == 1);
435 foo.x = 2;
436 try expect(foo.read_x() == 2);
437 }
438}
439
440test "array concat of slices gives slice" {
441 comptime {
442 var a: []const u8 = "aoeu";
443 var b: []const u8 = "asdf";
444 const c = a ++ b;
445 try expect(std.mem.eql(u8, c, "aoeuasdf"));
446 }
447}
448
449test "comptime shlWithOverflow" {
450 const ct_shifted: u64 = comptime amt: {
451 var amt = @as(u64, 0);
452 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
453 break :amt amt;
454 };
455
456 const rt_shifted: u64 = amt: {
457 var amt = @as(u64, 0);
458 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
459 break :amt amt;
460 };
461
462 try expect(ct_shifted == rt_shifted);
463}
464
465test "comptime shl" {
466 var a: u128 = 3;
467 var b: u7 = 63;
468 var c: u128 = 3 << 63;
469 try expectEqual(a << b, c);
470}
471
472test "runtime 128 bit integer division" {
473 var a: u128 = 152313999999999991610955792383;
474 var b: u128 = 10000000000000000000;
475 var c = a / b;
476 try expect(c == 15231399999);
477}
478
479pub const Info = struct {
480 version: u8,
481};
482
483pub const diamond_info = Info{ .version = 0 };
484
485test "comptime modification of const struct field" {
486 comptime {
487 var res = diamond_info;
488 res.version = 1;
489 try expect(diamond_info.version == 0);
490 try expect(res.version == 1);
491 }
492}
493
494test "slice of type" {
495 comptime {
496 var types_array = [_]type{ i32, f64, type };
497 for (types_array) |T, i| {
498 switch (i) {
499 0 => try expect(T == i32),
500 1 => try expect(T == f64),
501 2 => try expect(T == type),
502 else => unreachable,
503 }
504 }
505 for (types_array[0..]) |T, i| {
506 switch (i) {
507 0 => try expect(T == i32),
508 1 => try expect(T == f64),
509 2 => try expect(T == type),
510 else => unreachable,
511 }
512 }
513 }
514}
515
516const Wrapper = struct {
517 T: type,
518};
519
520fn wrap(comptime T: type) Wrapper {
521 return Wrapper{ .T = T };
522}
523
524test "function which returns struct with type field causes implicit comptime" {
525 const ty = wrap(i32).T;
526 try expect(ty == i32);
527}
528
529test "call method with comptime pass-by-non-copying-value self parameter" {
530 const S = struct {
531 a: u8,
532
533 fn b(comptime s: @This()) u8 {
534 return s.a;
535 }
536 };
537
538 const s = S{ .a = 2 };
539 var b = s.b();
540 try expect(b == 2);
541}
542
543test "@tagName of @typeInfo" {
544 const str = @tagName(@typeInfo(u8));
545 try expect(std.mem.eql(u8, str, "Int"));
546}
547
548test "setting backward branch quota just before a generic fn call" {
549 @setEvalBranchQuota(1001);
550 loopNTimes(1001);
551}
552
553fn loopNTimes(comptime n: usize) void {
554 comptime var i = 0;
555 inline while (i < n) : (i += 1) {}
556}
557
558test "variable inside inline loop that has different types on different iterations" {
559 try testVarInsideInlineLoop(.{ true, @as(u32, 42) });
560}
561
562fn testVarInsideInlineLoop(args: anytype) !void {
563 comptime var i = 0;
564 inline while (i < args.len) : (i += 1) {
565 const x = args[i];
566 if (i == 0) try expect(x);
567 if (i == 1) try expect(x == 42);
568 }
569}
570
571test "inline for with same type but different values" {
572 var res: usize = 0;
573 inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
574 var a: T = undefined;
575 res += a.len;
576 }
577 try expect(res == 5);
578}
579
580test "refer to the type of a generic function" {
581 const Func = fn (type) void;
582 const f: Func = doNothingWithType;
583 f(i32);
584}
585
586fn doNothingWithType(comptime T: type) void {
587 _ = T;
588}
589
590test "zero extend from u0 to u1" {
591 var zero_u0: u0 = 0;
592 var zero_u1: u1 = zero_u0;
593 try expect(zero_u1 == 0);
594}
595
596test "bit shift a u1" {
597 var x: u1 = 1;
598 var y = x << 0;
599 try expect(y == 1);
600}
601
602test "comptime pointer cast array and then slice" {
603 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
604
605 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
606 const sliceA: []const u8 = ptrA[0..2];
607
608 const ptrB: [*]const u8 = &array;
609 const sliceB: []const u8 = ptrB[0..2];
610
611 try expect(sliceA[1] == 2);
612 try expect(sliceB[1] == 2);
613}
614
615test "slice bounds in comptime concatenation" {
616 const bs = comptime blk: {
617 const b = "........1........";
618 break :blk b[8..9];
619 };
620 const str = "" ++ bs;
621 try expect(str.len == 1);
622 try expect(std.mem.eql(u8, str, "1"));
623
624 const str2 = bs ++ "";
625 try expect(str2.len == 1);
626 try expect(std.mem.eql(u8, str2, "1"));
627}
628
629test "comptime bitwise operators" {
630 comptime {
631 try expect(3 & 1 == 1);
632 try expect(3 & -1 == 3);
633 try expect(-3 & -1 == -3);
634 try expect(3 | -1 == -1);
635 try expect(-3 | -1 == -1);
636 try expect(3 ^ -1 == -4);
637 try expect(-3 ^ -1 == 2);
638 try expect(~@as(i8, -1) == 0);
639 try expect(~@as(i128, -1) == 0);
640 try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
641 try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
642 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
643 }
644}
645
646test "*align(1) u16 is the same as *align(1:0:2) u16" {
647 comptime {
648 try expect(*align(1:0:2) u16 == *align(1) u16);
649 try expect(*align(2:0:2) u16 == *u16);
650 }
651}
652
653test "array concatenation forces comptime" {
654 var a = oneItem(3) ++ oneItem(4);
655 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
656}
657
658test "array multiplication forces comptime" {
659 var a = oneItem(3) ** scalar(2);
660 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
661}
662
663fn oneItem(x: i32) [1]i32 {
664 return [_]i32{x};
665}
666
667fn scalar(x: u32) u32 {
668 return x;
669}
670
671test "comptime assign int to optional int" {
672 comptime {
673 var x: ?i32 = null;
674 x = 2;
675 x.? *= 10;
676 try expectEqual(20, x.?);
677 }
678}
679
680test "return 0 from function that has u0 return type" {
681 const S = struct {
682 fn foo_zero() u0 {
683 return 0;
684 }
685 };
686 comptime {
687 if (S.foo_zero() != 0) {
688 @compileError("test failed");
689 }
690 }
691}
692
693test "two comptime calls with array default initialized to undefined" {
694 const S = struct {
695 const CrossTarget = struct {
696 dynamic_linker: DynamicLinker = DynamicLinker{},
697
698 pub fn parse() void {
699 var result: CrossTarget = .{};
700 result.getCpuArch();
701 }
702
703 pub fn getCpuArch(self: CrossTarget) void {
704 _ = self;
705 }
706 };
707
708 const DynamicLinker = struct {
709 buffer: [255]u8 = undefined,
710 };
711 };
712
713 comptime {
714 S.CrossTarget.parse();
715 S.CrossTarget.parse();
716 }
717}