diff --git a/test/behavior.zig b/test/behavior.zig index 4c854fcb73..dac07e89fb 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -25,6 +25,7 @@ test { _ = @import("behavior/if.zig"); _ = @import("behavior/math.zig"); _ = @import("behavior/member_func.zig"); + _ = @import("behavior/optional.zig"); _ = @import("behavior/pointers.zig"); _ = @import("behavior/slice.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); @@ -135,7 +136,7 @@ test { _ = @import("behavior/muladd.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/null.zig"); - _ = @import("behavior/optional.zig"); + _ = @import("behavior/optional_stage1.zig"); _ = @import("behavior/pointers_stage1.zig"); _ = @import("behavior/popcount.zig"); _ = @import("behavior/ptrcast.zig"); diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 63a3ad9eb6..33e4c6fd8d 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const mem = std.mem; const expect = std.testing.expect; @@ -192,6 +193,14 @@ fn testMemcpyMemset() !void { const OpaqueA = opaque {}; const OpaqueB = opaque {}; +test "opaque types" { + try expect(*OpaqueA != *OpaqueB); + if (!builtin.zig_is_stage2) { + try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); + try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); + } +} + test "variable is allowed to be a pointer to an opaque type" { var x: i32 = 1234; _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); @@ -200,3 +209,205 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { var a = ptr; return a; } + +const global_a: i32 = 1234; +const global_b: *const i32 = &global_a; +const global_c: *const f32 = @ptrCast(*const f32, global_b); +test "compile time global reinterpret" { + const d = @ptrCast(*const i32, global_c); + try expect(d.* == 1234); +} + +test "cast undefined" { + const array: [100]u8 = undefined; + const slice = @as([]const u8, &array); + testCastUndefined(slice); +} +fn testCastUndefined(x: []const u8) void { + _ = x; +} + +test "implicit cast after unreachable" { + try expect(outer() == 1234); +} +fn inner() i32 { + return 1234; +} +fn outer() i64 { + return inner(); +} + +test "take address of parameter" { + try testTakeAddressOfParameter(12.34); +} +fn testTakeAddressOfParameter(f: f32) !void { + const f_ptr = &f; + try expect(f_ptr.* == 12.34); +} + +test "pointer to void return type" { + testPointerToVoidReturnType() catch unreachable; +} +fn testPointerToVoidReturnType() anyerror!void { + const a = testPointerToVoidReturnType2(); + return a.*; +} +const test_pointer_to_void_return_type_x = void{}; +fn testPointerToVoidReturnType2() *const void { + return &test_pointer_to_void_return_type_x; +} + +test "array 2D const double ptr" { + const rect_2d_vertexes = [_][1]f32{ + [_]f32{1.0}, + [_]f32{2.0}, + }; + try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); +} + +fn testArray2DConstDoublePtr(ptr: *const f32) !void { + const ptr2 = @ptrCast([*]const f32, ptr); + try expect(ptr2[0] == 1.0); + try expect(ptr2[1] == 2.0); +} + +test "double implicit cast in same expression" { + var x = @as(i32, @as(u16, nine())); + try expect(x == 9); +} +fn nine() u8 { + return 9; +} + +test "comptime if inside runtime while which unconditionally breaks" { + testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); + comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); +} +fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { + while (cond) { + if (false) {} + break; + } +} + +test "implicit comptime while" { + while (false) { + @compileError("bad"); + } +} + +fn fnThatClosesOverLocalConst() type { + const c = 1; + return struct { + fn g() i32 { + return c; + } + }; +} + +test "function closes over local const" { + const x = fnThatClosesOverLocalConst().g(); + try expect(x == 1); +} + +test "volatile load and store" { + var number: i32 = 1234; + const ptr = @as(*volatile i32, &number); + ptr.* += 1; + try expect(ptr.* == 1235); +} + +test "struct inside function" { + try testStructInFn(); + comptime try testStructInFn(); +} + +fn testStructInFn() !void { + const BlockKind = u32; + + const Block = struct { + kind: BlockKind, + }; + + var block = Block{ .kind = 1234 }; + + block.kind += 1; + + try expect(block.kind == 1235); +} + +test "fn call returning scalar optional in equality expression" { + try expect(getNull() == null); +} + +fn getNull() ?*i32 { + return null; +} + +var global_foo: *i32 = undefined; + +test "global variable assignment with optional unwrapping with var initialized to undefined" { + const S = struct { + var data: i32 = 1234; + fn foo() ?*i32 { + return &data; + } + }; + global_foo = S.foo() orelse { + @panic("bad"); + }; + try expect(global_foo.* == 1234); +} + +test "peer result location with typed parent, runtime condition, comptime prongs" { + const S = struct { + fn doTheTest(arg: i32) i32 { + const st = Structy{ + .bleh = if (arg == 1) 1 else 1, + }; + + if (st.bleh == 1) + return 1234; + return 0; + } + + const Structy = struct { + bleh: i32, + }; + }; + try expect(S.doTheTest(0) == 1234); + try expect(S.doTheTest(1) == 1234); +} + +fn ZA() type { + return struct { + b: B(), + + const Self = @This(); + + fn B() type { + return struct { + const Self = @This(); + }; + } + }; +} +test "non-ambiguous reference of shadowed decls" { + try expect(ZA().B().Self != ZA().Self); +} + +test "use of declaration with same name as primitive" { + const S = struct { + const @"u8" = u16; + const alias = @"u8"; + }; + const a: S.u8 = 300; + try expect(a == 300); + + const b: S.alias = 300; + try expect(b == 300); + + const @"u8" = u16; + const c: @"u8" = 300; + try expect(c == 300); +} diff --git a/test/behavior/misc.zig b/test/behavior/misc.zig index b6b8e730c9..1b8f6ef4a2 100644 --- a/test/behavior/misc.zig +++ b/test/behavior/misc.zig @@ -5,6 +5,8 @@ const expectEqualStrings = std.testing.expectEqualStrings; const mem = std.mem; const builtin = @import("builtin"); +fn emptyFn() void {} + test "constant equal function pointers" { const alias = emptyFn; try expect(comptime x: { @@ -12,7 +14,16 @@ test "constant equal function pointers" { }); } -fn emptyFn() void {} +const addr1 = @ptrCast(*const u8, emptyFn); +test "comptime cast fn to ptr" { + const addr2 = @ptrCast(*const u8, emptyFn); + comptime try expect(addr1 == addr2); +} + +test "equality compare fn ptrs" { + var a = emptyFn; + try expect(a == a); +} test "string escapes" { try expectEqualStrings("\"", "\x22"); @@ -34,51 +45,12 @@ test "multiline string literal is null terminated" { try expect(std.cstr.cmp(s1, s2) == 0); } -const global_a: i32 = 1234; -const global_b: *const i32 = &global_a; -const global_c: *const f32 = @ptrCast(*const f32, global_b); -test "compile time global reinterpret" { - const d = @ptrCast(*const i32, global_c); - try expect(d.* == 1234); -} - test "explicit cast maybe pointers" { const a: ?*i32 = undefined; const b: ?*f32 = @ptrCast(?*f32, a); _ = b; } -test "generic malloc free" { - const a = memAlloc(u8, 10) catch unreachable; - memFree(u8, a); -} -var some_mem: [100]u8 = undefined; -fn memAlloc(comptime T: type, n: usize) anyerror![]T { - return @ptrCast([*]T, &some_mem[0])[0..n]; -} -fn memFree(comptime T: type, memory: []T) void { - _ = memory; -} - -test "cast undefined" { - const array: [100]u8 = undefined; - const slice = @as([]const u8, &array); - testCastUndefined(slice); -} -fn testCastUndefined(x: []const u8) void { - _ = x; -} - -test "implicit cast after unreachable" { - try expect(outer() == 1234); -} -fn inner() i32 { - return 1234; -} -fn outer() i64 { - return inner(); -} - test "constant enum initialization with differing sizes" { try test3_1(test3_foo); try test3_2(test3_bar); @@ -117,14 +89,6 @@ fn test3_2(f: Test3Foo) !void { } } -test "take address of parameter" { - try testTakeAddressOfParameter(12.34); -} -fn testTakeAddressOfParameter(f: f32) !void { - const f_ptr = &f; - try expect(f_ptr.* == 12.34); -} - test "pointer comparison" { const a = @as([]const u8, "a"); const b = &a; @@ -153,40 +117,6 @@ test "string concatenation" { try expect(b[len] == 0); } -test "pointer to void return type" { - testPointerToVoidReturnType() catch unreachable; -} -fn testPointerToVoidReturnType() anyerror!void { - const a = testPointerToVoidReturnType2(); - return a.*; -} -const test_pointer_to_void_return_type_x = void{}; -fn testPointerToVoidReturnType2() *const void { - return &test_pointer_to_void_return_type_x; -} - -test "array 2D const double ptr" { - const rect_2d_vertexes = [_][1]f32{ - [_]f32{1.0}, - [_]f32{2.0}, - }; - try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); -} - -fn testArray2DConstDoublePtr(ptr: *const f32) !void { - const ptr2 = @ptrCast([*]const f32, ptr); - try expect(ptr2[0] == 1.0); - try expect(ptr2[1] == 2.0); -} - -test "double implicit cast in same expression" { - var x = @as(i32, @as(u16, nine())); - try expect(x == 9); -} -fn nine() u8 { - return 9; -} - test "global variable initialized to global variable array element" { try expect(global_ptr == &gdt[0]); } @@ -206,45 +136,6 @@ export fn writeToVRam() void { vram[0] = 'X'; } -const OpaqueA = opaque {}; -const OpaqueB = opaque {}; -test "opaque types" { - try expect(*OpaqueA != *OpaqueB); - try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); - try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); -} - -test "comptime if inside runtime while which unconditionally breaks" { - testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); - comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); -} -fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { - while (cond) { - if (false) {} - break; - } -} - -test "implicit comptime while" { - while (false) { - @compileError("bad"); - } -} - -fn fnThatClosesOverLocalConst() type { - const c = 1; - return struct { - fn g() i32 { - return c; - } - }; -} - -test "function closes over local const" { - const x = fnThatClosesOverLocalConst().g(); - try expect(x == 1); -} - const PackedStruct = packed struct { a: u8, b: u8, @@ -268,26 +159,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { } } -test "slicing zero length array" { - const s1 = ""[0..]; - const s2 = ([_]u32{})[0..]; - try expect(s1.len == 0); - try expect(s2.len == 0); - try expect(mem.eql(u8, s1, "")); - try expect(mem.eql(u32, s2, &[_]u32{})); -} - -const addr1 = @ptrCast(*const u8, emptyFn); -test "comptime cast fn to ptr" { - const addr2 = @ptrCast(*const u8, emptyFn); - comptime try expect(addr1 == addr2); -} - -test "equality compare fn ptrs" { - var a = emptyFn; - try expect(a == a); -} - test "self reference through fn ptr field" { const S = struct { const A = struct { @@ -304,52 +175,6 @@ test "self reference through fn ptr field" { try expect(a.f(a) == 12); } -test "volatile load and store" { - var number: i32 = 1234; - const ptr = @as(*volatile i32, &number); - ptr.* += 1; - try expect(ptr.* == 1235); -} - -test "slice string literal has correct type" { - comptime { - try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); - const array = [_]i32{ 1, 2, 3, 4 }; - try expect(@TypeOf(array[0..]) == *const [4]i32); - } - var runtime_zero: usize = 0; - comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); - const array = [_]i32{ 1, 2, 3, 4 }; - comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); -} - -test "struct inside function" { - try testStructInFn(); - comptime try testStructInFn(); -} - -fn testStructInFn() !void { - const BlockKind = u32; - - const Block = struct { - kind: BlockKind, - }; - - var block = Block{ .kind = 1234 }; - - block.kind += 1; - - try expect(block.kind == 1235); -} - -test "fn call returning scalar optional in equality expression" { - try expect(getNull() == null); -} - -fn getNull() ?*i32 { - return null; -} - test "thread local variable" { const S = struct { threadlocal var t: i32 = 1234; @@ -358,49 +183,6 @@ test "thread local variable" { try expect(S.t == 1235); } -test "result location zero sized array inside struct field implicit cast to slice" { - const E = struct { - entries: []u32, - }; - var foo = E{ .entries = &[_]u32{} }; - try expect(foo.entries.len == 0); -} - -var global_foo: *i32 = undefined; - -test "global variable assignment with optional unwrapping with var initialized to undefined" { - const S = struct { - var data: i32 = 1234; - fn foo() ?*i32 { - return &data; - } - }; - global_foo = S.foo() orelse { - @panic("bad"); - }; - try expect(global_foo.* == 1234); -} - -test "peer result location with typed parent, runtime condition, comptime prongs" { - const S = struct { - fn doTheTest(arg: i32) i32 { - const st = Structy{ - .bleh = if (arg == 1) 1 else 1, - }; - - if (st.bleh == 1) - return 1234; - return 0; - } - - const Structy = struct { - bleh: i32, - }; - }; - try expect(S.doTheTest(0) == 1234); - try expect(S.doTheTest(1) == 1234); -} - test "nested optional field in struct" { const S2 = struct { y: u8, @@ -462,36 +244,3 @@ test "lazy typeInfo value as generic parameter" { }; S.foo(@typeInfo(@TypeOf(.{}))); } - -fn ZA() type { - return struct { - b: B(), - - const Self = @This(); - - fn B() type { - return struct { - const Self = @This(); - }; - } - }; -} -test "non-ambiguous reference of shadowed decls" { - try expect(ZA().B().Self != ZA().Self); -} - -test "use of declaration with same name as primitive" { - const S = struct { - const @"u8" = u16; - const alias = @"u8"; - }; - const a: S.u8 = 300; - try expect(a == 300); - - const b: S.alias = 300; - try expect(b == 300); - - const @"u8" = u16; - const c: @"u8" = 300; - try expect(c == 300); -} diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 2943915869..e2bf15627f 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -2,270 +2,3 @@ const std = @import("std"); const testing = std.testing; const expect = testing.expect; const expectEqual = testing.expectEqual; - -pub const EmptyStruct = struct {}; - -test "optional pointer to size zero struct" { - var e = EmptyStruct{}; - var o: ?*EmptyStruct = &e; - try expect(o != null); -} - -test "equality compare nullable pointers" { - try testNullPtrsEql(); - comptime try testNullPtrsEql(); -} - -fn testNullPtrsEql() !void { - var number: i32 = 1234; - - var x: ?*i32 = null; - var y: ?*i32 = null; - try expect(x == y); - y = &number; - try expect(x != y); - try expect(x != &number); - try expect(&number != x); - x = &number; - try expect(x == y); - try expect(x == &number); - try expect(&number == x); -} - -test "address of unwrap optional" { - const S = struct { - const Foo = struct { - a: i32, - }; - - var global: ?Foo = null; - - pub fn getFoo() anyerror!*Foo { - return &global.?; - } - }; - S.global = S.Foo{ .a = 1234 }; - const foo = S.getFoo() catch unreachable; - try expect(foo.a == 1234); -} - -test "equality compare optional with non-optional" { - try test_cmp_optional_non_optional(); - comptime try test_cmp_optional_non_optional(); -} - -fn test_cmp_optional_non_optional() !void { - var ten: i32 = 10; - var opt_ten: ?i32 = 10; - var five: i32 = 5; - var int_n: ?i32 = null; - - try expect(int_n != ten); - try expect(opt_ten == ten); - try expect(opt_ten != five); - - // test evaluation is always lexical - // ensure that the optional isn't always computed before the non-optional - var mutable_state: i32 = 0; - _ = blk1: { - mutable_state += 1; - break :blk1 @as(?f64, 10.0); - } != blk2: { - try expect(mutable_state == 1); - break :blk2 @as(f64, 5.0); - }; - _ = blk1: { - mutable_state += 1; - break :blk1 @as(f64, 10.0); - } != blk2: { - try expect(mutable_state == 2); - break :blk2 @as(?f64, 5.0); - }; -} - -test "passing an optional integer as a parameter" { - const S = struct { - fn entry() bool { - var x: i32 = 1234; - return foo(x); - } - - fn foo(x: ?i32) bool { - return x.? == 1234; - } - }; - try expect(S.entry()); - comptime try expect(S.entry()); -} - -test "unwrap function call with optional pointer return value" { - const S = struct { - fn entry() !void { - try expect(foo().?.* == 1234); - try expect(bar() == null); - } - const global: i32 = 1234; - fn foo() ?*const i32 { - return &global; - } - fn bar() ?*i32 { - return null; - } - }; - try S.entry(); - comptime try S.entry(); -} - -test "nested orelse" { - const S = struct { - fn entry() !void { - try expect(func() == null); - } - fn maybe() ?Foo { - return null; - } - fn func() ?Foo { - const x = maybe() orelse - maybe() orelse - return null; - _ = x; - unreachable; - } - const Foo = struct { - field: i32, - }; - }; - try S.entry(); - comptime try S.entry(); -} - -test "self-referential struct through a slice of optional" { - const S = struct { - const Node = struct { - children: []?Node, - data: ?u8, - - fn new() Node { - return Node{ - .children = undefined, - .data = null, - }; - } - }; - }; - - var n = S.Node.new(); - try expect(n.data == null); -} - -test "assigning to an unwrapped optional field in an inline loop" { - comptime var maybe_pos_arg: ?comptime_int = null; - inline for ("ab") |x| { - _ = x; - maybe_pos_arg = 0; - if (maybe_pos_arg.? != 0) { - @compileError("bad"); - } - maybe_pos_arg.? = 10; - } -} - -test "coerce an anon struct literal to optional struct" { - const S = struct { - const Struct = struct { - field: u32, - }; - fn doTheTest() !void { - var maybe_dims: ?Struct = null; - maybe_dims = .{ .field = 1 }; - try expect(maybe_dims.?.field == 1); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "optional with void type" { - const Foo = struct { - x: ?void, - }; - var x = Foo{ .x = null }; - try expect(x.x == null); -} - -test "0-bit child type coerced to optional return ptr result location" { - const S = struct { - fn doTheTest() !void { - var y = Foo{}; - var z = y.thing(); - try expect(z != null); - } - - const Foo = struct { - pub const Bar = struct { - field: *Foo, - }; - - pub fn thing(self: *Foo) ?Bar { - return Bar{ .field = self }; - } - }; - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "0-bit child type coerced to optional" { - const S = struct { - fn doTheTest() !void { - var it: Foo = .{ - .list = undefined, - }; - try expect(it.foo() != null); - } - - const Empty = struct {}; - const Foo = struct { - list: [10]Empty, - - fn foo(self: *Foo) ?*Empty { - const data = &self.list[0]; - return data; - } - }; - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "array of optional unaligned types" { - const Enum = enum { one, two, three }; - - const SomeUnion = union(enum) { - Num: Enum, - Other: u32, - }; - - const values = [_]?SomeUnion{ - SomeUnion{ .Num = .one }, - SomeUnion{ .Num = .two }, - SomeUnion{ .Num = .three }, - SomeUnion{ .Num = .one }, - SomeUnion{ .Num = .two }, - SomeUnion{ .Num = .three }, - }; - - // The index must be a runtime value - var i: usize = 0; - try expectEqual(Enum.one, values[i].?.Num); - i += 1; - try expectEqual(Enum.two, values[i].?.Num); - i += 1; - try expectEqual(Enum.three, values[i].?.Num); - i += 1; - try expectEqual(Enum.one, values[i].?.Num); - i += 1; - try expectEqual(Enum.two, values[i].?.Num); - i += 1; - try expectEqual(Enum.three, values[i].?.Num); -} diff --git a/test/behavior/optional_stage1.zig b/test/behavior/optional_stage1.zig new file mode 100644 index 0000000000..9448f501f4 --- /dev/null +++ b/test/behavior/optional_stage1.zig @@ -0,0 +1,284 @@ +const std = @import("std"); +const testing = std.testing; +const expect = testing.expect; +const expectEqual = testing.expectEqual; + +pub const EmptyStruct = struct {}; + +test "optional pointer to size zero struct" { + var e = EmptyStruct{}; + var o: ?*EmptyStruct = &e; + try expect(o != null); +} + +test "equality compare nullable pointers" { + try testNullPtrsEql(); + comptime try testNullPtrsEql(); +} + +fn testNullPtrsEql() !void { + var number: i32 = 1234; + + var x: ?*i32 = null; + var y: ?*i32 = null; + try expect(x == y); + y = &number; + try expect(x != y); + try expect(x != &number); + try expect(&number != x); + x = &number; + try expect(x == y); + try expect(x == &number); + try expect(&number == x); +} + +test "address of unwrap optional" { + const S = struct { + const Foo = struct { + a: i32, + }; + + var global: ?Foo = null; + + pub fn getFoo() anyerror!*Foo { + return &global.?; + } + }; + S.global = S.Foo{ .a = 1234 }; + const foo = S.getFoo() catch unreachable; + try expect(foo.a == 1234); +} + +test "equality compare optional with non-optional" { + try test_cmp_optional_non_optional(); + comptime try test_cmp_optional_non_optional(); +} + +fn test_cmp_optional_non_optional() !void { + var ten: i32 = 10; + var opt_ten: ?i32 = 10; + var five: i32 = 5; + var int_n: ?i32 = null; + + try expect(int_n != ten); + try expect(opt_ten == ten); + try expect(opt_ten != five); + + // test evaluation is always lexical + // ensure that the optional isn't always computed before the non-optional + var mutable_state: i32 = 0; + _ = blk1: { + mutable_state += 1; + break :blk1 @as(?f64, 10.0); + } != blk2: { + try expect(mutable_state == 1); + break :blk2 @as(f64, 5.0); + }; + _ = blk1: { + mutable_state += 1; + break :blk1 @as(f64, 10.0); + } != blk2: { + try expect(mutable_state == 2); + break :blk2 @as(?f64, 5.0); + }; +} + +test "passing an optional integer as a parameter" { + const S = struct { + fn entry() bool { + var x: i32 = 1234; + return foo(x); + } + + fn foo(x: ?i32) bool { + return x.? == 1234; + } + }; + try expect(S.entry()); + comptime try expect(S.entry()); +} + +test "unwrap function call with optional pointer return value" { + const S = struct { + fn entry() !void { + try expect(foo().?.* == 1234); + try expect(bar() == null); + } + const global: i32 = 1234; + fn foo() ?*const i32 { + return &global; + } + fn bar() ?*i32 { + return null; + } + }; + try S.entry(); + comptime try S.entry(); +} + +test "nested orelse" { + const S = struct { + fn entry() !void { + try expect(func() == null); + } + fn maybe() ?Foo { + return null; + } + fn func() ?Foo { + const x = maybe() orelse + maybe() orelse + return null; + _ = x; + unreachable; + } + const Foo = struct { + field: i32, + }; + }; + try S.entry(); + comptime try S.entry(); +} + +test "self-referential struct through a slice of optional" { + const S = struct { + const Node = struct { + children: []?Node, + data: ?u8, + + fn new() Node { + return Node{ + .children = undefined, + .data = null, + }; + } + }; + }; + + var n = S.Node.new(); + try expect(n.data == null); +} + +test "assigning to an unwrapped optional field in an inline loop" { + comptime var maybe_pos_arg: ?comptime_int = null; + inline for ("ab") |x| { + _ = x; + maybe_pos_arg = 0; + if (maybe_pos_arg.? != 0) { + @compileError("bad"); + } + maybe_pos_arg.? = 10; + } +} + +test "coerce an anon struct literal to optional struct" { + const S = struct { + const Struct = struct { + field: u32, + }; + fn doTheTest() !void { + var maybe_dims: ?Struct = null; + maybe_dims = .{ .field = 1 }; + try expect(maybe_dims.?.field == 1); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "optional with void type" { + const Foo = struct { + x: ?void, + }; + var x = Foo{ .x = null }; + try expect(x.x == null); +} + +test "0-bit child type coerced to optional return ptr result location" { + const S = struct { + fn doTheTest() !void { + var y = Foo{}; + var z = y.thing(); + try expect(z != null); + } + + const Foo = struct { + pub const Bar = struct { + field: *Foo, + }; + + pub fn thing(self: *Foo) ?Bar { + return Bar{ .field = self }; + } + }; + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "0-bit child type coerced to optional" { + const S = struct { + fn doTheTest() !void { + var it: Foo = .{ + .list = undefined, + }; + try expect(it.foo() != null); + } + + const Empty = struct {}; + const Foo = struct { + list: [10]Empty, + + fn foo(self: *Foo) ?*Empty { + const data = &self.list[0]; + return data; + } + }; + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "array of optional unaligned types" { + const Enum = enum { one, two, three }; + + const SomeUnion = union(enum) { + Num: Enum, + Other: u32, + }; + + const values = [_]?SomeUnion{ + SomeUnion{ .Num = .one }, + SomeUnion{ .Num = .two }, + SomeUnion{ .Num = .three }, + SomeUnion{ .Num = .one }, + SomeUnion{ .Num = .two }, + SomeUnion{ .Num = .three }, + }; + + // The index must be a runtime value + var i: usize = 0; + try expectEqual(Enum.one, values[i].?.Num); + i += 1; + try expectEqual(Enum.two, values[i].?.Num); + i += 1; + try expectEqual(Enum.three, values[i].?.Num); + i += 1; + try expectEqual(Enum.one, values[i].?.Num); + i += 1; + try expectEqual(Enum.two, values[i].?.Num); + i += 1; + try expectEqual(Enum.three, values[i].?.Num); +} + +test "nested optional field in struct" { + const S2 = struct { + y: u8, + }; + const S1 = struct { + x: ?S2, + }; + var s = S1{ + .x = S2{ .y = 127 }, + }; + try expect(s.x.?.y == 127); +} diff --git a/test/behavior/slice_stage1.zig b/test/behavior/slice_stage1.zig index 89adbfaea1..dbc59823ec 100644 --- a/test/behavior/slice_stage1.zig +++ b/test/behavior/slice_stage1.zig @@ -20,6 +20,47 @@ test "slicing" { if (slice_rest.len != 10) unreachable; } +test "slicing zero length array" { + const s1 = ""[0..]; + const s2 = ([_]u32{})[0..]; + try expect(s1.len == 0); + try expect(s2.len == 0); + try expect(mem.eql(u8, s1, "")); + try expect(mem.eql(u32, s2, &[_]u32{})); +} + +test "slice string literal has correct type" { + comptime { + try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); + const array = [_]i32{ 1, 2, 3, 4 }; + try expect(@TypeOf(array[0..]) == *const [4]i32); + } + var runtime_zero: usize = 0; + comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); + const array = [_]i32{ 1, 2, 3, 4 }; + comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); +} + +test "generic malloc free" { + const a = memAlloc(u8, 10) catch unreachable; + memFree(u8, a); +} +var some_mem: [100]u8 = undefined; +fn memAlloc(comptime T: type, n: usize) anyerror![]T { + return @ptrCast([*]T, &some_mem[0])[0..n]; +} +fn memFree(comptime T: type, memory: []T) void { + _ = memory; +} + +test "result location zero sized array inside struct field implicit cast to slice" { + const E = struct { + entries: []u32, + }; + var foo = E{ .entries = &[_]u32{} }; + try expect(foo.entries.len == 0); +} + const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" {