master
  1const builtin = @import("builtin");
  2const std = @import("std");
  3const testing = std.testing;
  4const assert = std.debug.assert;
  5const expect = testing.expect;
  6const expectEqual = testing.expectEqual;
  7const expectEqualStrings = std.testing.expectEqualStrings;
  8
  9test "passing an optional integer as a parameter" {
 10    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 11    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 12
 13    const S = struct {
 14        fn entry() bool {
 15            const x: i32 = 1234;
 16            return foo(x);
 17        }
 18
 19        fn foo(x: ?i32) bool {
 20            return x.? == 1234;
 21        }
 22    };
 23    try expect(S.entry());
 24    comptime assert(S.entry());
 25}
 26
 27pub const EmptyStruct = struct {};
 28
 29test "optional pointer to size zero struct" {
 30    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 31    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 32
 33    var e = EmptyStruct{};
 34    const o: ?*EmptyStruct = &e;
 35    try expect(o != null);
 36}
 37
 38test "equality compare optional pointers" {
 39    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 40
 41    try testNullPtrsEql();
 42    try comptime testNullPtrsEql();
 43}
 44
 45fn testNullPtrsEql() !void {
 46    var number: i32 = 1234;
 47
 48    var x: ?*i32 = null;
 49    var y: ?*i32 = null;
 50    try expect(x == y);
 51    y = &number;
 52    try expect(x != y);
 53    try expect(x != &number);
 54    try expect(&number != x);
 55    x = &number;
 56    try expect(x == y);
 57    try expect(x == &number);
 58    try expect(&number == x);
 59}
 60
 61test "optional with zero-bit type" {
 62    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 63    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 64
 65    const S = struct {
 66        fn doTheTest(comptime ZeroBit: type, comptime zero_bit: ZeroBit) !void {
 67            const WithRuntime = struct {
 68                zero_bit: ZeroBit,
 69                runtime: u1,
 70            };
 71            var with_runtime: WithRuntime = undefined;
 72            with_runtime = .{ .zero_bit = zero_bit, .runtime = 0 };
 73
 74            const Opt = struct { opt: ?ZeroBit };
 75            var opt: Opt = .{ .opt = null };
 76            try expect(opt.opt == null);
 77            try expect(opt.opt != zero_bit);
 78            try expect(opt.opt != with_runtime.zero_bit);
 79            opt.opt = zero_bit;
 80            try expect(opt.opt != null);
 81            try expect(opt.opt == zero_bit);
 82            try expect(opt.opt == with_runtime.zero_bit);
 83            opt = .{ .opt = zero_bit };
 84            try expect(opt.opt != null);
 85            try expect(opt.opt == zero_bit);
 86            try expect(opt.opt == with_runtime.zero_bit);
 87            opt.opt = with_runtime.zero_bit;
 88            try expect(opt.opt != null);
 89            try expect(opt.opt == zero_bit);
 90            try expect(opt.opt == with_runtime.zero_bit);
 91            opt = .{ .opt = with_runtime.zero_bit };
 92            try expect(opt.opt != null);
 93            try expect(opt.opt == zero_bit);
 94            try expect(opt.opt == with_runtime.zero_bit);
 95
 96            var two: ?struct { ZeroBit, ZeroBit } = undefined;
 97            two = .{ with_runtime.zero_bit, with_runtime.zero_bit };
 98            try expect(two != null);
 99            try expect(two.?[0] == zero_bit);
100            try expect(two.?[0] == with_runtime.zero_bit);
101            try expect(two.?[1] == zero_bit);
102            try expect(two.?[1] == with_runtime.zero_bit);
103        }
104    };
105
106    try S.doTheTest(void, {});
107    try comptime S.doTheTest(void, {});
108    try S.doTheTest(enum { only }, .only);
109    try comptime S.doTheTest(enum { only }, .only);
110}
111
112test "address of unwrap optional" {
113    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
116    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
117
118    const S = struct {
119        const Foo = struct {
120            a: i32,
121        };
122
123        var global: ?Foo = null;
124
125        pub fn getFoo() anyerror!*Foo {
126            return &global.?;
127        }
128    };
129    S.global = S.Foo{ .a = 1234 };
130    const foo = S.getFoo() catch unreachable;
131    try expect(foo.a == 1234);
132}
133
134test "nested optional field in struct" {
135    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137
138    const S2 = struct {
139        y: u8,
140    };
141    const S1 = struct {
142        x: ?S2,
143    };
144    var s = S1{
145        .x = S2{ .y = 127 },
146    };
147    _ = &s;
148    try expect(s.x.?.y == 127);
149}
150
151test "equality compare optionals and non-optionals" {
152    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
153    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
154    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
155
156    const S = struct {
157        fn doTheTest() !void {
158            var five: isize = 5;
159            var ten: isize = 10;
160            var opt_null: ?isize = null;
161            var opt_ten: ?isize = 10;
162            _ = .{ &five, &ten, &opt_null, &opt_ten };
163            try expect(opt_null != five);
164            try expect(opt_null != ten);
165            try expect(opt_ten != five);
166            try expect(opt_ten == ten);
167
168            var opt_int: ?isize = null;
169            try expect(opt_int != five);
170            try expect(opt_int != ten);
171            try expect(opt_int == opt_null);
172            try expect(opt_int != opt_ten);
173
174            opt_int = 10;
175            try expect(opt_int != five);
176            try expect(opt_int == ten);
177            try expect(opt_int != opt_null);
178            try expect(opt_int == opt_ten);
179
180            opt_int = five;
181            try expect(opt_int == five);
182            try expect(opt_int != ten);
183            try expect(opt_int != opt_null);
184            try expect(opt_int != opt_ten);
185
186            // test evaluation is always lexical
187            // ensure that the optional isn't always computed before the non-optional
188            var mutable_state: i32 = 0;
189            _ = blk1: {
190                mutable_state += 1;
191                break :blk1 @as(?f64, 10.0);
192            } != blk2: {
193                try expect(mutable_state == 1);
194                break :blk2 @as(f64, 5.0);
195            };
196            _ = blk1: {
197                mutable_state += 1;
198                break :blk1 @as(f64, 10.0);
199            } != blk2: {
200                try expect(mutable_state == 2);
201                break :blk2 @as(?f64, 5.0);
202            };
203        }
204    };
205
206    try S.doTheTest();
207    try comptime S.doTheTest();
208}
209
210test "compare optionals with modified payloads" {
211    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
212
213    var lhs: ?bool = false;
214    const lhs_payload = &lhs.?;
215    var rhs: ?bool = true;
216    const rhs_payload = &rhs.?;
217    try expect(lhs != rhs and !(lhs == rhs));
218
219    lhs = null;
220    lhs_payload.* = false;
221    rhs = false;
222    try expect(lhs != rhs and !(lhs == rhs));
223
224    lhs = true;
225    rhs = null;
226    rhs_payload.* = true;
227    try expect(lhs != rhs and !(lhs == rhs));
228
229    lhs = null;
230    lhs_payload.* = false;
231    rhs = null;
232    rhs_payload.* = true;
233    try expect(lhs == rhs and !(lhs != rhs));
234}
235
236test "unwrap function call with optional pointer return value" {
237    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
239    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
240
241    const S = struct {
242        fn entry() !void {
243            try expect(foo().?.* == 1234);
244            try expect(bar() == null);
245        }
246        const global: i32 = 1234;
247        fn foo() ?*const i32 {
248            return &global;
249        }
250        fn bar() ?*i32 {
251            return null;
252        }
253    };
254    try S.entry();
255    try comptime S.entry();
256}
257
258test "nested orelse" {
259    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
260    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
261
262    const S = struct {
263        fn entry() !void {
264            try expect(func() == null);
265        }
266        fn maybe() ?Foo {
267            return null;
268        }
269        fn func() ?Foo {
270            const x = maybe() orelse
271                maybe() orelse
272                return null;
273            _ = x;
274            unreachable;
275        }
276        const Foo = struct {
277            field: i32,
278        };
279    };
280    try S.entry();
281    try comptime S.entry();
282}
283
284test "self-referential struct through a slice of optional" {
285    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
286    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
287    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
288
289    const S = struct {
290        const Node = struct {
291            children: []?Node,
292            data: ?u8,
293
294            fn new() Node {
295                return Node{
296                    .children = undefined,
297                    .data = null,
298                };
299            }
300        };
301    };
302
303    const n = S.Node.new();
304    try expect(n.data == null);
305}
306
307test "assigning to an unwrapped optional field in an inline loop" {
308    comptime var maybe_pos_arg: ?comptime_int = null;
309    inline for ("ab") |x| {
310        _ = x;
311        maybe_pos_arg = 0;
312        if (maybe_pos_arg.? != 0) {
313            @compileError("bad");
314        }
315        maybe_pos_arg.? = 10;
316    }
317}
318
319test "coerce an anon struct literal to optional struct" {
320    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
321    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
323
324    const S = struct {
325        const Struct = struct {
326            field: u32,
327        };
328        fn doTheTest() !void {
329            var maybe_dims: ?Struct = null;
330            maybe_dims = .{ .field = 1 };
331            try expect(maybe_dims.?.field == 1);
332        }
333    };
334    try S.doTheTest();
335    try comptime S.doTheTest();
336}
337
338test "0-bit child type coerced to optional return ptr result location" {
339    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341
342    const S = struct {
343        fn doTheTest() !void {
344            var y = Foo{};
345            const z = y.thing();
346            try expect(z != null);
347        }
348
349        const Foo = struct {
350            pub const Bar = struct {
351                field: *Foo,
352            };
353
354            pub fn thing(self: *Foo) ?Bar {
355                return Bar{ .field = self };
356            }
357        };
358    };
359    try S.doTheTest();
360    try comptime S.doTheTest();
361}
362
363test "0-bit child type coerced to optional" {
364    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
365    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
366    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
367
368    const S = struct {
369        fn doTheTest() !void {
370            var it: Foo = .{
371                .list = undefined,
372            };
373            try expect(it.foo() != null);
374        }
375
376        const Empty = struct {};
377        const Foo = struct {
378            list: [10]Empty,
379
380            fn foo(self: *Foo) ?*Empty {
381                const data = &self.list[0];
382                return data;
383            }
384        };
385    };
386    try S.doTheTest();
387    try comptime S.doTheTest();
388}
389
390test "array of optional unaligned types" {
391    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
392    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
393    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
394
395    const Enum = enum { one, two, three };
396
397    const SomeUnion = union(enum) {
398        Num: Enum,
399        Other: u32,
400    };
401
402    const values = [_]?SomeUnion{
403        SomeUnion{ .Num = .one },
404        SomeUnion{ .Num = .two },
405        SomeUnion{ .Num = .three },
406        SomeUnion{ .Num = .one },
407        SomeUnion{ .Num = .two },
408        SomeUnion{ .Num = .three },
409    };
410
411    // The index must be a runtime value
412    var i: usize = 0;
413    try expect(Enum.one == values[i].?.Num);
414    i += 1;
415    try expect(Enum.two == values[i].?.Num);
416    i += 1;
417    try expect(Enum.three == values[i].?.Num);
418    i += 1;
419    try expect(Enum.one == values[i].?.Num);
420    i += 1;
421    try expect(Enum.two == values[i].?.Num);
422    i += 1;
423    try expect(Enum.three == values[i].?.Num);
424}
425
426test "optional pointer to zero bit optional payload" {
427    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
428    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
430    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
431
432    const B = struct {
433        fn foo(_: *@This()) void {}
434    };
435    const A = struct {
436        b: ?B = .{},
437    };
438    var a: A = .{};
439    var a_ptr = &a;
440    if (a_ptr.b) |*some| {
441        some.foo();
442    }
443}
444
445test "optional pointer to zero bit error union payload" {
446    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
448    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
449    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
450
451    const B = struct {
452        fn foo(_: *@This()) void {}
453    };
454    const A = struct {
455        b: anyerror!B = .{},
456    };
457    var a: A = .{};
458    var a_ptr = &a;
459    if (a_ptr.b) |*some| {
460        some.foo();
461    } else |_| {}
462}
463
464const NoReturn = struct {
465    var a: u32 = undefined;
466    fn someData() bool {
467        a -= 1;
468        return a == 0;
469    }
470    fn loop() ?noreturn {
471        while (true) {
472            if (someData()) return null;
473        }
474    }
475    fn testOrelse() u32 {
476        loop() orelse return 123;
477        @compileError("bad");
478    }
479};
480
481test "optional of noreturn used with if" {
482    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
483
484    NoReturn.a = 64;
485    if (NoReturn.loop()) |_| {
486        @compileError("bad");
487    } else {
488        try expect(true);
489    }
490}
491
492test "optional of noreturn used with orelse" {
493    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
494
495    NoReturn.a = 64;
496    const val = NoReturn.testOrelse();
497    try expect(val == 123);
498}
499
500test "mutable optional of noreturn" {
501    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502
503    var a: ?noreturn = null;
504    if (a) |*ptr| {
505        _ = ptr;
506        @compileError("bad");
507    } else {
508        // this is what we expect to hit
509        return;
510    }
511    @compileError("bad");
512}
513
514test "orelse on C pointer" {
515    // TODO https://github.com/ziglang/zig/issues/6597
516    const foo: [*c]const u8 = "hey";
517    const d = foo orelse @compileError("bad");
518    try expectEqual([*c]const u8, @TypeOf(d));
519}
520
521test "alignment of wrapping an optional payload" {
522    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
523    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
524    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
525    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
526    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
527
528    const S = struct {
529        const I = extern struct { x: i128 };
530
531        fn foo() ?I {
532            var i: I = .{ .x = 1234 };
533            _ = &i;
534            return i;
535        }
536    };
537    try expect(S.foo().?.x == 1234);
538}
539
540test "Optional slice size is optimized" {
541    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
542    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
543    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
544
545    try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
546    var a: ?[]const u8 = null;
547    try expect(a == null);
548    a = "hello";
549    try expectEqualStrings(a.?, "hello");
550}
551
552test "Optional slice passed to function" {
553    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
554    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
555    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
556    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
557
558    const S = struct {
559        fn foo(a: ?[]const u8) !void {
560            try std.testing.expectEqualStrings(a.?, "foo");
561        }
562        fn bar(a: ?[]allowzero const u8) !void {
563            try std.testing.expectEqualStrings(@ptrCast(a.?), "bar");
564        }
565    };
566    try S.foo("foo");
567    try S.bar("bar");
568}
569
570test "peer type resolution in nested if expressions" {
571    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
572
573    const Thing = struct { n: i32 };
574    var a = false;
575    var b = false;
576    _ = .{ &a, &b };
577
578    const result1 = if (a)
579        Thing{ .n = 1 }
580    else
581        null;
582    try expect(result1 == null);
583    try expect(@TypeOf(result1) == ?Thing);
584
585    const result2 = if (a)
586        Thing{ .n = 0 }
587    else if (b)
588        Thing{ .n = 1 }
589    else
590        null;
591    try expect(result2 == null);
592    try expect(@TypeOf(result2) == ?Thing);
593}
594
595test "cast slice to const slice nested in error union and optional" {
596    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
597    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
598    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
599    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
600
601    const S = struct {
602        fn inner() !?[]u8 {
603            return error.Foo;
604        }
605        fn outer() !?[]const u8 {
606            return inner();
607        }
608    };
609    try std.testing.expectError(error.Foo, S.outer());
610}
611
612test "variable of optional of noreturn" {
613    var null_opv: ?noreturn = null;
614    _ = &null_opv;
615    try std.testing.expectEqual(@as(?noreturn, null), null_opv);
616}
617
618test "copied optional doesn't alias source" {
619    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
621    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
622    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
623
624    var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
625
626    const x = opt_x.?;
627    opt_x.?[0] = 15.0;
628
629    try expect(x[0] == 0.0);
630}
631
632test "result location initialization of optional with OPV payload" {
633    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
634    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
635    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
636    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
637    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
638
639    const S = struct {
640        x: u0,
641    };
642
643    const a: ?S = .{ .x = 0 };
644    comptime assert(a.?.x == 0);
645
646    comptime {
647        var b: ?S = .{ .x = 0 };
648        _ = &b;
649        assert(b.?.x == 0);
650    }
651
652    var c: ?S = .{ .x = 0 };
653    _ = &c;
654    try expectEqual(0, (c orelse return error.TestFailed).x);
655}
656
657test "global comptime only optional" {
658    const S = struct {
659        const @"null": ?*type = null;
660        const @"void": ?*const type = &void;
661    };
662    comptime {
663        assert(S.null == null);
664        assert(S.void.?.* == void);
665    }
666}