authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-14 22:16:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-14 22:16:26-07:00
logcacd5366a6707cb030e212ea3cc46052168d4006
tree8e6d5d7c40bb763acd180040af8396d4198cbe92
parent55eea3b045c86c78eb8d9cc862122d260352a631

stage2: LLVM backend: implement `wrap_optional` AIR

and move over some passing tests

11 files changed, 428 insertions(+), 402 deletions(-)

src/codegen/llvm.zig+26-3
...@@ -2341,10 +2341,33 @@ pub const FuncGen = struct {...@@ -2341,10 +2341,33 @@ pub const FuncGen = struct {
2341 }2341 }
23422342
2343 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2343 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2344 if (self.liveness.isUnused(inst))2344 if (self.liveness.isUnused(inst)) return null;
2345 return null;
23462345
2347 return self.todo("implement llvm codegen for 'airWrapOptional'", .{});2346 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2347 const operand_ty = self.air.typeOf(ty_op.operand);
2348 const non_null_bit = self.context.intType(1).constAllOnes();
2349 if (!operand_ty.hasCodeGenBits()) return non_null_bit;
2350 const operand = try self.resolveInst(ty_op.operand);
2351 const optional_ty = self.air.typeOfIndex(inst);
2352 if (optional_ty.isPtrLikeOptional()) return operand;
2353 const llvm_optional_ty = try self.dg.llvmType(optional_ty);
2354 if (isByRef(optional_ty)) {
2355 const optional_ptr = self.buildAlloca(llvm_optional_ty);
2356 const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
2357 var buf: Type.Payload.ElemType = undefined;
2358 const payload_ty = operand_ty.optionalChild(&buf);
2359 var ptr_ty_payload: Type.Payload.ElemType = .{
2360 .base = .{ .tag = .single_mut_pointer },
2361 .data = payload_ty,
2362 };
2363 const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2364 self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
2365 const non_null_ptr = self.builder.buildStructGEP(optional_ptr, 1, "");
2366 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
2367 return optional_ptr;
2368 }
2369 const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
2370 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
2348 }2371 }
23492372
2350 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2373 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
test/behavior.zig+1-1
...@@ -28,6 +28,7 @@ test {...@@ -28,6 +28,7 @@ test {
28 _ = @import("behavior/member_func.zig");28 _ = @import("behavior/member_func.zig");
29 _ = @import("behavior/optional.zig");29 _ = @import("behavior/optional.zig");
30 _ = @import("behavior/pointers.zig");30 _ = @import("behavior/pointers.zig");
31 _ = @import("behavior/pub_enum.zig");
31 _ = @import("behavior/slice.zig");32 _ = @import("behavior/slice.zig");
32 _ = @import("behavior/sizeof_and_typeof.zig");33 _ = @import("behavior/sizeof_and_typeof.zig");
33 _ = @import("behavior/struct.zig");34 _ = @import("behavior/struct.zig");
...@@ -140,7 +141,6 @@ test {...@@ -140,7 +141,6 @@ test {
140 _ = @import("behavior/pointers_stage1.zig");141 _ = @import("behavior/pointers_stage1.zig");
141 _ = @import("behavior/popcount.zig");142 _ = @import("behavior/popcount.zig");
142 _ = @import("behavior/ptrcast.zig");143 _ = @import("behavior/ptrcast.zig");
143 _ = @import("behavior/pub_enum.zig");
144 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");144 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
145 _ = @import("behavior/reflection.zig");145 _ = @import("behavior/reflection.zig");
146 {146 {
test/behavior/basic.zig+35
...@@ -411,3 +411,38 @@ test "use of declaration with same name as primitive" {...@@ -411,3 +411,38 @@ test "use of declaration with same name as primitive" {
411 const c: @"u8" = 300;411 const c: @"u8" = 300;
412 try expect(c == 300);412 try expect(c == 300);
413}413}
414
415fn emptyFn() void {}
416
417test "constant equal function pointers" {
418 const alias = emptyFn;
419 try expect(comptime x: {
420 break :x emptyFn == alias;
421 });
422}
423
424test "multiline string literal is null terminated" {
425 const s1 =
426 \\one
427 \\two)
428 \\three
429 ;
430 const s2 = "one\ntwo)\nthree";
431 try expect(std.cstr.cmp(s1, s2) == 0);
432}
433
434test "self reference through fn ptr field" {
435 const S = struct {
436 const A = struct {
437 f: fn (A) u8,
438 };
439
440 fn foo(a: A) u8 {
441 _ = a;
442 return 12;
443 }
444 };
445 var a: S.A = undefined;
446 a.f = S.foo;
447 try expect(a.f(a) == 12);
448}
test/behavior/eval.zig+151
...@@ -217,3 +217,154 @@ const vertices = [_]Vertex{...@@ -217,3 +217,154 @@ const vertices = [_]Vertex{
217 .b = 1.0,217 .b = 1.0,
218 },218 },
219};219};
220
221test "statically initialized list" {
222 try expect(static_point_list[0].x == 1);
223 try expect(static_point_list[0].y == 2);
224 try expect(static_point_list[1].x == 3);
225 try expect(static_point_list[1].y == 4);
226}
227const Point = struct {
228 x: i32,
229 y: i32,
230};
231const static_point_list = [_]Point{
232 makePoint(1, 2),
233 makePoint(3, 4),
234};
235fn makePoint(x: i32, y: i32) Point {
236 return Point{
237 .x = x,
238 .y = y,
239 };
240}
241
242test "statically initialized array literal" {
243 const y: [4]u8 = st_init_arr_lit_x;
244 try expect(y[3] == 4);
245}
246const st_init_arr_lit_x = [_]u8{ 1, 2, 3, 4 };
247
248const CmdFn = struct {
249 name: []const u8,
250 func: fn (i32) i32,
251};
252
253const cmd_fns = [_]CmdFn{
254 CmdFn{
255 .name = "one",
256 .func = one,
257 },
258 CmdFn{
259 .name = "two",
260 .func = two,
261 },
262 CmdFn{
263 .name = "three",
264 .func = three,
265 },
266};
267fn one(value: i32) i32 {
268 return value + 1;
269}
270fn two(value: i32) i32 {
271 return value + 2;
272}
273fn three(value: i32) i32 {
274 return value + 3;
275}
276
277fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
278 var result: i32 = start_value;
279 comptime var i = 0;
280 inline while (i < cmd_fns.len) : (i += 1) {
281 if (cmd_fns[i].name[0] == prefix_char) {
282 result = cmd_fns[i].func(result);
283 }
284 }
285 return result;
286}
287
288test "comptime iterate over fn ptr list" {
289 try expect(performFn('t', 1) == 6);
290 try expect(performFn('o', 0) == 1);
291 try expect(performFn('w', 99) == 99);
292}
293
294test "create global array with for loop" {
295 try expect(global_array[5] == 5 * 5);
296 try expect(global_array[9] == 9 * 9);
297}
298
299const global_array = x: {
300 var result: [10]usize = undefined;
301 for (result) |*item, index| {
302 item.* = index * index;
303 }
304 break :x result;
305};
306
307fn generateTable(comptime T: type) [1010]T {
308 var res: [1010]T = undefined;
309 var i: usize = 0;
310 while (i < 1010) : (i += 1) {
311 res[i] = @intCast(T, i);
312 }
313 return res;
314}
315
316fn doesAlotT(comptime T: type, value: usize) T {
317 @setEvalBranchQuota(5000);
318 const table = comptime blk: {
319 break :blk generateTable(T);
320 };
321 return table[value];
322}
323
324test "@setEvalBranchQuota at same scope as generic function call" {
325 try expect(doesAlotT(u32, 2) == 2);
326}
327
328pub const Info = struct {
329 version: u8,
330};
331
332pub const diamond_info = Info{ .version = 0 };
333
334test "comptime modification of const struct field" {
335 comptime {
336 var res = diamond_info;
337 res.version = 1;
338 try expect(diamond_info.version == 0);
339 try expect(res.version == 1);
340 }
341}
342
343test "refer to the type of a generic function" {
344 const Func = fn (type) void;
345 const f: Func = doNothingWithType;
346 f(i32);
347}
348
349fn doNothingWithType(comptime T: type) void {
350 _ = T;
351}
352
353test "zero extend from u0 to u1" {
354 var zero_u0: u0 = 0;
355 var zero_u1: u1 = zero_u0;
356 try expect(zero_u1 == 0);
357}
358
359test "return 0 from function that has u0 return type" {
360 const S = struct {
361 fn foo_zero() u0 {
362 return 0;
363 }
364 };
365 comptime {
366 if (S.foo_zero() != 0) {
367 @compileError("test failed");
368 }
369 }
370}
test/behavior/eval_stage1.zig-248
...@@ -2,27 +2,6 @@ const std = @import("std");...@@ -2,27 +2,6 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
44
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" {5test "static eval list init" {
27 try expect(static_vec3.data[2] == 1.0);6 try expect(static_vec3.data[2] == 1.0);
28 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);7 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
...@@ -54,27 +33,6 @@ var st_init_str_foo = StInitStrFoo{...@@ -54,27 +33,6 @@ var st_init_str_foo = StInitStrFoo{
54 .y = true,33 .y = true,
55};34};
5635
57test "statically initialized array literal" {
58 const y: [4]u8 = st_init_arr_lit_x;
59 try expect(y[3] == 4);
60}
61const st_init_arr_lit_x = [_]u8{
62 1,
63 2,
64 3,
65 4,
66};
67
68test "const slice" {
69 comptime {
70 const a = "1234567890";
71 try expect(a.len == 10);
72 const b = a[1..2];
73 try expect(b.len == 1);
74 try expect(b[0] == '2');
75 }
76}
77
78test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {36test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
79 var runtime = [1]i32{3};37 var runtime = [1]i32{3};
80 comptime var i: usize = 0;38 comptime var i: usize = 0;
...@@ -87,52 +45,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio...@@ -87,52 +45,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
87 }45 }
88}46}
8947
90const CmdFn = struct {
91 name: []const u8,
92 func: fn (i32) i32,
93};
94
95const cmd_fns = [_]CmdFn{
96 CmdFn{
97 .name = "one",
98 .func = one,
99 },
100 CmdFn{
101 .name = "two",
102 .func = two,
103 },
104 CmdFn{
105 .name = "three",
106 .func = three,
107 },
108};
109fn one(value: i32) i32 {
110 return value + 1;
111}
112fn two(value: i32) i32 {
113 return value + 2;
114}
115fn three(value: i32) i32 {
116 return value + 3;
117}
118
119fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
120 var result: i32 = start_value;
121 comptime var i = 0;
122 inline while (i < cmd_fns.len) : (i += 1) {
123 if (cmd_fns[i].name[0] == prefix_char) {
124 result = cmd_fns[i].func(result);
125 }
126 }
127 return result;
128}
129
130test "comptime iterate over fn ptr list" {
131 try expect(performFn('t', 1) == 6);
132 try expect(performFn('o', 0) == 1);
133 try expect(performFn('w', 99) == 99);
134}
135
136test "eval @setFloatMode at compile-time" {48test "eval @setFloatMode at compile-time" {
137 const result = comptime fnWithFloatMode();49 const result = comptime fnWithFloatMode();
138 try expect(result == 1234.0);50 try expect(result == 1234.0);
...@@ -204,19 +116,6 @@ const Foo = struct {...@@ -204,19 +116,6 @@ const Foo = struct {
204var foo_contents = Foo{ .name = "a" };116var foo_contents = Foo{ .name = "a" };
205const foo_ref = &foo_contents;117const foo_ref = &foo_contents;
206118
207test "create global array with for loop" {
208 try expect(global_array[5] == 5 * 5);
209 try expect(global_array[9] == 9 * 9);
210}
211
212const global_array = x: {
213 var result: [10]usize = undefined;
214 for (result) |*item, index| {
215 item.* = index * index;
216 }
217 break :x result;
218};
219
220const hi1 = "hi";119const hi1 = "hi";
221const hi2 = hi1;120const hi2 = hi1;
222test "const global shares pointer with other same one" {121test "const global shares pointer with other same one" {
...@@ -262,13 +161,6 @@ test "string literal used as comptime slice is memoized" {...@@ -262,13 +161,6 @@ test "string literal used as comptime slice is memoized" {
262 comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);161 comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
263}162}
264163
265test "comptime slice of undefined pointer of length 0" {
266 const slice1 = @as([*]i32, undefined)[0..0];
267 try expect(slice1.len == 0);
268 const slice2 = @as([*]i32, undefined)[100..100];
269 try expect(slice2.len == 0);
270}
271
272fn copyWithPartialInline(s: []u32, b: []u8) void {164fn copyWithPartialInline(s: []u32, b: []u8) void {
273 comptime var i: usize = 0;165 comptime var i: usize = 0;
274 inline while (i < 4) : (i += 1) {166 inline while (i < 4) : (i += 1) {
...@@ -308,44 +200,6 @@ fn increment(value: *i32) void {...@@ -308,44 +200,6 @@ fn increment(value: *i32) void {
308 value.* += 1;200 value.* += 1;
309}201}
310202
311fn generateTable(comptime T: type) [1010]T {
312 var res: [1010]T = undefined;
313 var i: usize = 0;
314 while (i < 1010) : (i += 1) {
315 res[i] = @intCast(T, i);
316 }
317 return res;
318}
319
320fn doesAlotT(comptime T: type, value: usize) T {
321 @setEvalBranchQuota(5000);
322 const table = comptime blk: {
323 break :blk generateTable(T);
324 };
325 return table[value];
326}
327
328test "@setEvalBranchQuota at same scope as generic function call" {
329 try expect(doesAlotT(u32, 2) == 2);
330}
331
332test "comptime slice of slice preserves comptime var" {
333 comptime {
334 var buff: [10]u8 = undefined;
335 buff[0..][0..][0] = 1;
336 try expect(buff[0..][0..][0] == 1);
337 }
338}
339
340test "comptime slice of pointer preserves comptime var" {
341 comptime {
342 var buff: [10]u8 = undefined;
343 var a = @ptrCast([*]u8, &buff);
344 a[0..1][0] = 1;
345 try expect(buff[0..][0..][0] == 1);
346 }
347}
348
349const SingleFieldStruct = struct {203const SingleFieldStruct = struct {
350 x: i32,204 x: i32,
351205
...@@ -362,15 +216,6 @@ test "const ptr to comptime mutable data is not memoized" {...@@ -362,15 +216,6 @@ test "const ptr to comptime mutable data is not memoized" {
362 }216 }
363}217}
364218
365test "array concat of slices gives slice" {
366 comptime {
367 var a: []const u8 = "aoeu";
368 var b: []const u8 = "asdf";
369 const c = a ++ b;
370 try expect(std.mem.eql(u8, c, "aoeuasdf"));
371 }
372}
373
374test "comptime shlWithOverflow" {219test "comptime shlWithOverflow" {
375 const ct_shifted: u64 = comptime amt: {220 const ct_shifted: u64 = comptime amt: {
376 var amt = @as(u64, 0);221 var amt = @as(u64, 0);
...@@ -401,43 +246,6 @@ test "runtime 128 bit integer division" {...@@ -401,43 +246,6 @@ test "runtime 128 bit integer division" {
401 try expect(c == 15231399999);246 try expect(c == 15231399999);
402}247}
403248
404pub const Info = struct {
405 version: u8,
406};
407
408pub const diamond_info = Info{ .version = 0 };
409
410test "comptime modification of const struct field" {
411 comptime {
412 var res = diamond_info;
413 res.version = 1;
414 try expect(diamond_info.version == 0);
415 try expect(res.version == 1);
416 }
417}
418
419test "slice of type" {
420 comptime {
421 var types_array = [_]type{ i32, f64, type };
422 for (types_array) |T, i| {
423 switch (i) {
424 0 => try expect(T == i32),
425 1 => try expect(T == f64),
426 2 => try expect(T == type),
427 else => unreachable,
428 }
429 }
430 for (types_array[0..]) |T, i| {
431 switch (i) {
432 0 => try expect(T == i32),
433 1 => try expect(T == f64),
434 2 => try expect(T == type),
435 else => unreachable,
436 }
437 }
438 }
439}
440
441const Wrapper = struct {249const Wrapper = struct {
442 T: type,250 T: type,
443};251};
...@@ -502,55 +310,12 @@ test "inline for with same type but different values" {...@@ -502,55 +310,12 @@ test "inline for with same type but different values" {
502 try expect(res == 5);310 try expect(res == 5);
503}311}
504312
505test "refer to the type of a generic function" {
506 const Func = fn (type) void;
507 const f: Func = doNothingWithType;
508 f(i32);
509}
510
511fn doNothingWithType(comptime T: type) void {
512 _ = T;
513}
514
515test "zero extend from u0 to u1" {
516 var zero_u0: u0 = 0;
517 var zero_u1: u1 = zero_u0;
518 try expect(zero_u1 == 0);
519}
520
521test "bit shift a u1" {313test "bit shift a u1" {
522 var x: u1 = 1;314 var x: u1 = 1;
523 var y = x << 0;315 var y = x << 0;
524 try expect(y == 1);316 try expect(y == 1);
525}317}
526318
527test "comptime pointer cast array and then slice" {
528 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
529
530 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
531 const sliceA: []const u8 = ptrA[0..2];
532
533 const ptrB: [*]const u8 = &array;
534 const sliceB: []const u8 = ptrB[0..2];
535
536 try expect(sliceA[1] == 2);
537 try expect(sliceB[1] == 2);
538}
539
540test "slice bounds in comptime concatenation" {
541 const bs = comptime blk: {
542 const b = "........1........";
543 break :blk b[8..9];
544 };
545 const str = "" ++ bs;
546 try expect(str.len == 1);
547 try expect(std.mem.eql(u8, str, "1"));
548
549 const str2 = bs ++ "";
550 try expect(str2.len == 1);
551 try expect(std.mem.eql(u8, str2, "1"));
552}
553
554test "comptime bitwise operators" {319test "comptime bitwise operators" {
555 comptime {320 comptime {
556 try expect(3 & 1 == 1);321 try expect(3 & 1 == 1);
...@@ -602,19 +367,6 @@ test "comptime assign int to optional int" {...@@ -602,19 +367,6 @@ test "comptime assign int to optional int" {
602 }367 }
603}368}
604369
605test "return 0 from function that has u0 return type" {
606 const S = struct {
607 fn foo_zero() u0 {
608 return 0;
609 }
610 };
611 comptime {
612 if (S.foo_zero() != 0) {
613 @compileError("test failed");
614 }
615 }
616}
617
618test "two comptime calls with array default initialized to undefined" {370test "two comptime calls with array default initialized to undefined" {
619 const S = struct {371 const S = struct {
620 const CrossTarget = struct {372 const CrossTarget = struct {
test/behavior/misc.zig+1-47
...@@ -7,13 +7,6 @@ const builtin = @import("builtin");...@@ -7,13 +7,6 @@ const builtin = @import("builtin");
77
8fn emptyFn() void {}8fn emptyFn() void {}
99
10test "constant equal function pointers" {
11 const alias = emptyFn;
12 try expect(comptime x: {
13 break :x emptyFn == alias;
14 });
15}
16
17const addr1 = @ptrCast(*const u8, emptyFn);10const addr1 = @ptrCast(*const u8, emptyFn);
18test "comptime cast fn to ptr" {11test "comptime cast fn to ptr" {
19 const addr2 = @ptrCast(*const u8, emptyFn);12 const addr2 = @ptrCast(*const u8, emptyFn);
...@@ -35,17 +28,7 @@ test "string escapes" {...@@ -35,17 +28,7 @@ test "string escapes" {
35 try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");28 try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");
36}29}
3730
38test "multiline string literal is null terminated" {31test "explicit cast optional pointers" {
39 const s1 =
40 \\one
41 \\two)
42 \\three
43 ;
44 const s2 = "one\ntwo)\nthree";
45 try expect(std.cstr.cmp(s1, s2) == 0);
46}
47
48test "explicit cast maybe pointers" {
49 const a: ?*i32 = undefined;32 const a: ?*i32 = undefined;
50 const b: ?*f32 = @ptrCast(?*f32, a);33 const b: ?*f32 = @ptrCast(?*f32, a);
51 _ = b;34 _ = b;
...@@ -159,22 +142,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {...@@ -159,22 +142,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
159 }142 }
160}143}
161144
162test "self reference through fn ptr field" {
163 const S = struct {
164 const A = struct {
165 f: fn (A) u8,
166 };
167
168 fn foo(a: A) u8 {
169 _ = a;
170 return 12;
171 }
172 };
173 var a: S.A = undefined;
174 a.f = S.foo;
175 try expect(a.f(a) == 12);
176}
177
178test "thread local variable" {145test "thread local variable" {
179 const S = struct {146 const S = struct {
180 threadlocal var t: i32 = 1234;147 threadlocal var t: i32 = 1234;
...@@ -183,19 +150,6 @@ test "thread local variable" {...@@ -183,19 +150,6 @@ test "thread local variable" {
183 try expect(S.t == 1235);150 try expect(S.t == 1235);
184}151}
185152
186test "nested optional field in struct" {
187 const S2 = struct {
188 y: u8,
189 };
190 const S1 = struct {
191 x: ?S2,
192 };
193 var s = S1{
194 .x = S2{ .y = 127 },
195 };
196 try expect(s.x.?.y == 127);
197}
198
199fn maybe(x: bool) anyerror!?u32 {153fn maybe(x: bool) anyerror!?u32 {
200 return switch (x) {154 return switch (x) {
201 true => @as(u32, 42),155 true => @as(u32, 42),
test/behavior/optional.zig+34
...@@ -2,3 +2,37 @@ const std = @import("std");...@@ -2,3 +2,37 @@ const std = @import("std");
2const testing = std.testing;2const testing = std.testing;
3const expect = testing.expect;3const expect = testing.expect;
4const expectEqual = testing.expectEqual;4const expectEqual = testing.expectEqual;
5
6test "passing an optional integer as a parameter" {
7 const S = struct {
8 fn entry() bool {
9 var x: i32 = 1234;
10 return foo(x);
11 }
12
13 fn foo(x: ?i32) bool {
14 return x.? == 1234;
15 }
16 };
17 try expect(S.entry());
18 comptime try expect(S.entry());
19}
20
21test "self-referential struct through a slice of optional" {
22 const S = struct {
23 const Node = struct {
24 children: []?Node,
25 data: ?u8,
26
27 fn new() Node {
28 return Node{
29 .children = undefined,
30 .data = null,
31 };
32 }
33 };
34 };
35
36 var n = S.Node.new();
37 try expect(n.data == null);
38}
test/behavior/optional_stage1.zig-34
...@@ -83,21 +83,6 @@ fn test_cmp_optional_non_optional() !void {...@@ -83,21 +83,6 @@ fn test_cmp_optional_non_optional() !void {
83 };83 };
84}84}
8585
86test "passing an optional integer as a parameter" {
87 const S = struct {
88 fn entry() bool {
89 var x: i32 = 1234;
90 return foo(x);
91 }
92
93 fn foo(x: ?i32) bool {
94 return x.? == 1234;
95 }
96 };
97 try expect(S.entry());
98 comptime try expect(S.entry());
99}
100
101test "unwrap function call with optional pointer return value" {86test "unwrap function call with optional pointer return value" {
102 const S = struct {87 const S = struct {
103 fn entry() !void {88 fn entry() !void {
...@@ -139,25 +124,6 @@ test "nested orelse" {...@@ -139,25 +124,6 @@ test "nested orelse" {
139 comptime try S.entry();124 comptime try S.entry();
140}125}
141126
142test "self-referential struct through a slice of optional" {
143 const S = struct {
144 const Node = struct {
145 children: []?Node,
146 data: ?u8,
147
148 fn new() Node {
149 return Node{
150 .children = undefined,
151 .data = null,
152 };
153 }
154 };
155 };
156
157 var n = S.Node.new();
158 try expect(n.data == null);
159}
160
161test "assigning to an unwrapped optional field in an inline loop" {127test "assigning to an unwrapped optional field in an inline loop" {
162 comptime var maybe_pos_arg: ?comptime_int = null;128 comptime var maybe_pos_arg: ?comptime_int = null;
163 inline for ("ab") |x| {129 inline for ("ab") |x| {
test/behavior/slice_stage1.zig+92
...@@ -20,6 +20,23 @@ test "slicing" {...@@ -20,6 +20,23 @@ test "slicing" {
20 if (slice_rest.len != 10) unreachable;20 if (slice_rest.len != 10) unreachable;
21}21}
2222
23test "const slice" {
24 comptime {
25 const a = "1234567890";
26 try expect(a.len == 10);
27 const b = a[1..2];
28 try expect(b.len == 1);
29 try expect(b[0] == '2');
30 }
31}
32
33test "comptime slice of undefined pointer of length 0" {
34 const slice1 = @as([*]i32, undefined)[0..0];
35 try expect(slice1.len == 0);
36 const slice2 = @as([*]i32, undefined)[100..100];
37 try expect(slice2.len == 0);
38}
39
23test "slicing zero length array" {40test "slicing zero length array" {
24 const s1 = ""[0..];41 const s1 = ""[0..];
25 const s2 = ([_]u32{})[0..];42 const s2 = ([_]u32{})[0..];
...@@ -389,3 +406,78 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {...@@ -389,3 +406,78 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
389 // try S.doTheTest();406 // try S.doTheTest();
390 comptime try S.doTheTest();407 comptime try S.doTheTest();
391}408}
409
410test "comptime slice of slice preserves comptime var" {
411 comptime {
412 var buff: [10]u8 = undefined;
413 buff[0..][0..][0] = 1;
414 try expect(buff[0..][0..][0] == 1);
415 }
416}
417
418test "comptime slice of pointer preserves comptime var" {
419 comptime {
420 var buff: [10]u8 = undefined;
421 var a = @ptrCast([*]u8, &buff);
422 a[0..1][0] = 1;
423 try expect(buff[0..][0..][0] == 1);
424 }
425}
426
427test "array concat of slices gives slice" {
428 comptime {
429 var a: []const u8 = "aoeu";
430 var b: []const u8 = "asdf";
431 const c = a ++ b;
432 try expect(std.mem.eql(u8, c, "aoeuasdf"));
433 }
434}
435
436test "slice of type" {
437 comptime {
438 var types_array = [_]type{ i32, f64, type };
439 for (types_array) |T, i| {
440 switch (i) {
441 0 => try expect(T == i32),
442 1 => try expect(T == f64),
443 2 => try expect(T == type),
444 else => unreachable,
445 }
446 }
447 for (types_array[0..]) |T, i| {
448 switch (i) {
449 0 => try expect(T == i32),
450 1 => try expect(T == f64),
451 2 => try expect(T == type),
452 else => unreachable,
453 }
454 }
455 }
456}
457
458test "comptime pointer cast array and then slice" {
459 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
460
461 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
462 const sliceA: []const u8 = ptrA[0..2];
463
464 const ptrB: [*]const u8 = &array;
465 const sliceB: []const u8 = ptrB[0..2];
466
467 try expect(sliceA[1] == 2);
468 try expect(sliceB[1] == 2);
469}
470
471test "slice bounds in comptime concatenation" {
472 const bs = comptime blk: {
473 const b = "........1........";
474 break :blk b[8..9];
475 };
476 const str = "" ++ bs;
477 try expect(str.len == 1);
478 try expect(std.mem.eql(u8, str, "1"));
479
480 const str2 = bs ++ "";
481 try expect(str2.len == 1);
482 try expect(std.mem.eql(u8, str2, "1"));
483}
test/behavior/while.zig+88
...@@ -111,3 +111,91 @@ test "while copies its payload" {...@@ -111,3 +111,91 @@ test "while copies its payload" {
111 try S.doTheTest();111 try S.doTheTest();
112 comptime try S.doTheTest();112 comptime try S.doTheTest();
113}113}
114
115test "continue and break" {
116 try runContinueAndBreakTest();
117 try expect(continue_and_break_counter == 8);
118}
119var continue_and_break_counter: i32 = 0;
120fn runContinueAndBreakTest() !void {
121 var i: i32 = 0;
122 while (true) {
123 continue_and_break_counter += 2;
124 i += 1;
125 if (i < 4) {
126 continue;
127 }
128 break;
129 }
130 try expect(i == 4);
131}
132
133test "while with optional as condition" {
134 numbers_left = 10;
135 var sum: i32 = 0;
136 while (getNumberOrNull()) |value| {
137 sum += value;
138 }
139 try expect(sum == 45);
140}
141
142test "while with optional as condition with else" {
143 numbers_left = 10;
144 var sum: i32 = 0;
145 var got_else: i32 = 0;
146 while (getNumberOrNull()) |value| {
147 sum += value;
148 try expect(got_else == 0);
149 } else {
150 got_else += 1;
151 }
152 try expect(sum == 45);
153 try expect(got_else == 1);
154}
155
156test "while on bool with else result follow else prong" {
157 const result = while (returnFalse()) {
158 break @as(i32, 10);
159 } else @as(i32, 2);
160 try expect(result == 2);
161}
162
163test "while on bool with else result follow break prong" {
164 const result = while (returnTrue()) {
165 break @as(i32, 10);
166 } else @as(i32, 2);
167 try expect(result == 10);
168}
169
170test "while on optional with else result follow else prong" {
171 const result = while (returnNull()) |value| {
172 break value;
173 } else @as(i32, 2);
174 try expect(result == 2);
175}
176
177test "while on optional with else result follow break prong" {
178 const result = while (returnOptional(10)) |value| {
179 break value;
180 } else @as(i32, 2);
181 try expect(result == 10);
182}
183
184fn returnNull() ?i32 {
185 return null;
186}
187fn returnOptional(x: i32) ?i32 {
188 return x;
189}
190fn returnError() anyerror!i32 {
191 return error.YouWantedAnError;
192}
193fn returnSuccess(x: i32) anyerror!i32 {
194 return x;
195}
196fn returnFalse() bool {
197 return false;
198}
199fn returnTrue() bool {
200 return true;
201}
test/behavior/while_stage1.zig-69
...@@ -1,24 +1,6 @@...@@ -1,24 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
33
4test "continue and break" {
5 try runContinueAndBreakTest();
6 try expect(continue_and_break_counter == 8);
7}
8var continue_and_break_counter: i32 = 0;
9fn runContinueAndBreakTest() !void {
10 var i: i32 = 0;
11 while (true) {
12 continue_and_break_counter += 2;
13 i += 1;
14 if (i < 4) {
15 continue;
16 }
17 break;
18 }
19 try expect(i == 4);
20}
21
22test "return with implicit cast from while loop" {4test "return with implicit cast from while loop" {
23 returnWithImplicitCastFromWhileLoopTest() catch unreachable;5 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
24}6}
...@@ -28,29 +10,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {...@@ -28,29 +10,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
28 }10 }
29}11}
3012
31test "while with optional as condition" {
32 numbers_left = 10;
33 var sum: i32 = 0;
34 while (getNumberOrNull()) |value| {
35 sum += value;
36 }
37 try expect(sum == 45);
38}
39
40test "while with optional as condition with else" {
41 numbers_left = 10;
42 var sum: i32 = 0;
43 var got_else: i32 = 0;
44 while (getNumberOrNull()) |value| {
45 sum += value;
46 try expect(got_else == 0);
47 } else {
48 got_else += 1;
49 }
50 try expect(sum == 45);
51 try expect(got_else == 1);
52}
53
54test "while with error union condition" {13test "while with error union condition" {
55 numbers_left = 10;14 numbers_left = 10;
56 var sum: i32 = 0;15 var sum: i32 = 0;
...@@ -79,20 +38,6 @@ fn getNumberOrNull() ?i32 {...@@ -79,20 +38,6 @@ fn getNumberOrNull() ?i32 {
79 };38 };
80}39}
8140
82test "while on optional with else result follow else prong" {
83 const result = while (returnNull()) |value| {
84 break value;
85 } else @as(i32, 2);
86 try expect(result == 2);
87}
88
89test "while on optional with else result follow break prong" {
90 const result = while (returnOptional(10)) |value| {
91 break value;
92 } else @as(i32, 2);
93 try expect(result == 10);
94}
95
96test "while on error union with else result follow else prong" {41test "while on error union with else result follow else prong" {
97 const result = while (returnError()) |value| {42 const result = while (returnError()) |value| {
98 break value;43 break value;
...@@ -107,20 +52,6 @@ test "while on error union with else result follow break prong" {...@@ -107,20 +52,6 @@ test "while on error union with else result follow break prong" {
107 try expect(result == 10);52 try expect(result == 10);
108}53}
10954
110test "while on bool with else result follow else prong" {
111 const result = while (returnFalse()) {
112 break @as(i32, 10);
113 } else @as(i32, 2);
114 try expect(result == 2);
115}
116
117test "while on bool with else result follow break prong" {
118 const result = while (returnTrue()) {
119 break @as(i32, 10);
120 } else @as(i32, 2);
121 try expect(result == 10);
122}
123
124fn returnNull() ?i32 {55fn returnNull() ?i32 {
125 return null;56 return null;
126}57}