const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; const expect = std.testing.expect; const expectEqualSlices = std.testing.expectEqualSlices; const expectEqualStrings = std.testing.expectEqualStrings; const expectEqual = std.testing.expectEqual; const mem = std.mem; // comptime array passed as slice argument comptime { const S = struct { fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize { var i: usize = start_index; while (i < slice.len) : (i += 1) { if (slice[i] == value) return i; } return null; } fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize { return indexOfScalarPos(T, slice, 0, value); } }; const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong }; const list: []const type = &unsigned; const pos = S.indexOfScalar(type, list, c_ulong).?; if (pos != 1) @compileError("bad pos"); } test "slicing" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var array: [20]i32 = undefined; array[5] = 1234; var slice = array[5..10]; try expect(slice.len == 5); const ptr = &slice[0]; try expect(ptr.* == 1234); var slice_rest = array[10..]; _ = &slice_rest; try expect(slice_rest.len == 10); } test "const slice" { comptime { const a = "1234567890"; try expect(a.len == 10); const b = a[1..2]; try expect(b.len == 1); try expect(b[0] == '2'); } } test "comptime slice of undefined pointer of length 0" { const slice1 = @as([*]i32, undefined)[0..0]; try expect(slice1.len == 0); const slice2 = @as([*]i32, undefined)[100..100]; try expect(slice2.len == 0); } test "implicitly cast array of size 0 to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var msg = [_]u8{}; try assertLenIsZero(&msg); } fn assertLenIsZero(msg: []const u8) !void { try expect(msg.len == 0); } test "access len index of sentinel-terminated slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var slice: [:0]const u8 = "hello"; _ = &slice; try expect(slice.len == 5); try expect(slice[5] == 0); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "comptime slice of slice preserves comptime var" { comptime { var buff: [10]u8 = undefined; buff[0..][0..][0] = 1; try expect(buff[0..][0..][0] == 1); } } test "open slice of open slice with sentinel" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var slice: [:0]const u8 = "hello"; _ = &slice; comptime assert(@TypeOf(slice[0..][0.. :0]) == [:0]const u8); try expect(slice[0..][0.. :0].len == 5); try expect(slice[0..][0.. :0][0] == 'h'); try expect(slice[0..][0.. :0][5] == 0); comptime assert(@TypeOf(slice[1..][0.. :0]) == [:0]const u8); try expect(slice[1..][0.. :0].len == 4); try expect(slice[1..][0.. :0][0] == 'e'); try expect(slice[1..][0.. :0][4] == 0); } test "open slice with sentinel of slice with end index" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var slice: [:0]const u8 = "hello"; _ = &slice; comptime assert(@TypeOf(slice[0.. :0][0..5]) == *const [5]u8); try expect(slice[0.. :0][0..5].len == 5); try expect(slice[0.. :0][0..5][0] == 'h'); try expect(slice[0.. :0][0..5][4] == 'o'); comptime assert(@TypeOf(slice[0.. :0][0..5 :0]) == *const [5:0]u8); try expect(slice[0.. :0][0..5 :0].len == 5); try expect(slice[0.. :0][0..5 :0][0] == 'h'); try expect(slice[0.. :0][0..5 :0][5] == 0); } test "slice of type" { comptime { var types_array = [_]type{ i32, f64, type }; for (types_array, 0..) |T, i| { switch (i) { 0 => try expect(T == i32), 1 => try expect(T == f64), 2 => try expect(T == type), else => unreachable, } } for (types_array[0..], 0..) |T, i| { switch (i) { 0 => try expect(T == i32), 1 => try expect(T == f64), 2 => try expect(T == type), else => unreachable, } } } } test "generic malloc free" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO 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 @as([*]T, @ptrCast(&some_mem[0]))[0..n]; } fn memFree(comptime T: type, memory: []T) void { _ = memory; } test "slice of hardcoded address to pointer" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { const pointer = @as([*]u8, @ptrFromInt(0x04))[0..2]; comptime assert(@TypeOf(pointer) == *[2]u8); const slice: []const u8 = pointer; try expect(@intFromPtr(slice.ptr) == 4); try expect(slice.len == 2); } }; try S.doTheTest(); } test "comptime slice of pointer preserves comptime var" { comptime { var buff: [10]u8 = undefined; var a = @as([*]u8, @ptrCast(&buff)); a[0..1][0] = 1; try expect(buff[0..][0..][0] == 1); } } test "comptime pointer cast array and then slice" { const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; const ptrA: [*]const u8 = @as([*]const u8, @ptrCast(&array)); const sliceA: []const u8 = ptrA[0..2]; const ptrB: [*]const u8 = &array; const sliceB: []const u8 = ptrB[0..2]; try expect(sliceA[1] == 2); try expect(sliceB[1] == 2); } test "slicing zero length array" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 "slicing pointer by length" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; const ptr: [*]const u8 = @as([*]const u8, @ptrCast(&array)); const slice = ptr[1..][0..5]; try expect(slice.len == 5); var i: usize = 0; while (i < slice.len) : (i += 1) { try expect(slice[i] == i + 2); } } const x = @as([*]i32, @ptrFromInt(0x1000))[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(@intFromPtr(x) == 0x1000); try expect(x.len == 0x500); try expect(@intFromPtr(y) == 0x1400); try expect(y.len == 0x400); } test "slice string literal has correct type" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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; _ = &runtime_zero; comptime assert(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); const array = [_]i32{ 1, 2, 3, 4 }; comptime assert(@TypeOf(array[runtime_zero..]) == []const i32); } test "result location zero sized array inside struct field implicit cast to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const E = struct { entries: []u32, }; var foo: E = .{ .entries = &[_]u32{} }; _ = &foo; try expect(foo.entries.len == 0); } test "runtime safety lets us slice from len..len" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var an_array = [_]u8{ 1, 2, 3 }; try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); } fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { return a_slice[start..end]; } test "C pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; var len: u32 = 10; _ = &len; const slice = buf[0..len]; try expect(mem.eql(u8, "kjdhfkjdhf", slice)); } test "C pointer slice access" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var buf: [10]u32 = [1]u32{42} ** 10; const c_ptr = @as([*c]const u32, @ptrCast(&buf)); var runtime_zero: usize = 0; _ = &runtime_zero; comptime assert(@TypeOf(c_ptr[runtime_zero..1]) == []const u32); comptime assert(@TypeOf(c_ptr[0..1]) == *const [1]u32); for (c_ptr[0..5]) |*cl| { try expect(@as(u32, 42) == cl.*); } } test "comptime slices are disambiguated" { try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); } fn sliceSum(comptime q: []const u8) i32 { comptime var result = 0; inline for (q) |item| { result += item; } return result; } test "slice type with custom alignment" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const LazilyResolvedType = struct { anything: i32, }; var slice: []align(32) LazilyResolvedType = undefined; var array: [10]LazilyResolvedType align(32) = undefined; slice = &array; slice[1].anything = 42; try expect(array[1].anything == 42); } test "obtaining a null terminated slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // here we have a normal array var buf: [50]u8 = undefined; buf[0] = 'a'; buf[1] = 'b'; buf[2] = 'c'; buf[3] = 0; // now we obtain a null terminated slice: const ptr = buf[0..3 :0]; _ = ptr; var runtime_len: usize = 3; _ = &runtime_len; const ptr2 = buf[0..runtime_len :0]; // ptr2 is a null-terminated slice comptime assert(@TypeOf(ptr2) == [:0]u8); comptime assert(@TypeOf(ptr2[0..2]) == *[2]u8); var runtime_zero: usize = 0; _ = &runtime_zero; comptime assert(@TypeOf(ptr2[runtime_zero..2]) == []u8); } test "empty array to slice" { const S = struct { fn doTheTest() !void { const empty: []align(16) u8 = &[_]u8{}; const align_1: []align(1) u8 = empty; const align_4: []align(4) u8 = empty; const align_16: []align(16) u8 = empty; try expect(1 == @typeInfo(@TypeOf(align_1)).pointer.alignment); try expect(4 == @typeInfo(@TypeOf(align_4)).pointer.alignment); try expect(16 == @typeInfo(@TypeOf(align_16)).pointer.alignment); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "@ptrCast slice to pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; const slice: []align(@alignOf(u16)) u8 = &array; const ptr: *u16 = @ptrCast(slice); try expect(ptr.* == 65535); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "slice multi-pointer without end" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { try testPointer(); try testPointerZ(); } fn testPointer() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; const pointer: [*]u8 = &array; const slice = pointer[1..]; comptime assert(@TypeOf(slice) == [*]u8); try expect(slice[0] == 2); try expect(slice[1] == 3); } fn testPointerZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; const pointer: [*:0]u8 = &array; comptime assert(@TypeOf(pointer[1..]) == [*:0]u8); comptime assert(@TypeOf(pointer[1.. :0]) == [*:0]u8); const slice = pointer[1..]; comptime assert(@TypeOf(slice) == [*:0]u8); try expect(slice[0] == 2); try expect(slice[1] == 3); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "slice syntax resulting in pointer-to-array" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { try testArray(); try testArrayZ(); try testArray0(); try testArrayAlign(); try testPointer(); try testPointerZ(); try testPointer0(); try testPointerAlign(); try testSlice(); try testSliceZ(); try testSliceOpt(); try testSliceAlign(); try testConcatStrLiterals(); try testSliceLength(); try testSliceLengthZ(); try testArrayLength(); try testArrayLengthZ(); try testMultiPointer(); try testMultiPointerLengthZ(); try testSingleItemPointer(); } fn testArray() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; const slice = array[1..3]; comptime assert(@TypeOf(slice) == *[2]u8); try expect(slice[0] == 2); try expect(slice[1] == 3); } fn testArrayZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; comptime assert(@TypeOf(array[1..3]) == *[2]u8); comptime assert(@TypeOf(array[1..5]) == *[4:0]u8); comptime assert(@TypeOf(array[1..]) == *[4:0]u8); comptime assert(@TypeOf(array[1..3 :4]) == *[2:4]u8); } fn testArray0() !void { { var array = [0]u8{}; const slice = array[0..0]; comptime assert(@TypeOf(slice) == *[0]u8); } { var array = [0:0]u8{}; const slice = array[0..0]; comptime assert(@TypeOf(slice) == *[0:0]u8); try expect(slice[0] == 0); } } fn testArrayAlign() !void { var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; const slice = array[4..5]; comptime assert(@TypeOf(slice) == *align(4) [1]u8); try expect(slice[0] == 5); comptime assert(@TypeOf(array[0..2]) == *align(4) [2]u8); } fn testPointer() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var pointer: [*]u8 = &array; const slice = pointer[1..3]; comptime assert(@TypeOf(slice) == *[2]u8); try expect(slice[0] == 2); try expect(slice[1] == 3); } fn testPointerZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var pointer: [*:0]u8 = &array; comptime assert(@TypeOf(pointer[1..3]) == *[2]u8); comptime assert(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); } fn testPointer0() !void { var pointer: [*]const u0 = &[1]u0{0}; const slice = pointer[0..1]; comptime assert(@TypeOf(slice) == *const [1]u0); try expect(slice[0] == 0); } fn testPointerAlign() !void { var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; var pointer: [*]align(4) u8 = &array; const slice = pointer[4..5]; comptime assert(@TypeOf(slice) == *align(4) [1]u8); try expect(slice[0] == 5); comptime assert(@TypeOf(pointer[0..2]) == *align(4) [2]u8); } fn testSlice() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var src_slice: []u8 = &array; const slice = src_slice[1..3]; comptime assert(@TypeOf(slice) == *[2]u8); try expect(slice[0] == 2); try expect(slice[1] == 3); } fn testSliceZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var slice: [:0]u8 = &array; comptime assert(@TypeOf(slice[1..3]) == *[2]u8); comptime assert(@TypeOf(slice[1..3 :4]) == *[2:4]u8); if (@inComptime()) { comptime assert(@TypeOf(slice[1..]) == *[4:0]u8); } else { comptime assert(@TypeOf(slice[1..]) == [:0]u8); } } fn testSliceOpt() !void { var array: [2]u8 = [2]u8{ 1, 2 }; var slice: ?[]u8 = &array; comptime assert(@TypeOf(&array, slice) == ?[]u8); comptime assert(@TypeOf(slice, &array) == ?[]u8); comptime assert(@TypeOf(slice.?[0..2]) == *[2]u8); } fn testSliceAlign() !void { var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; var src_slice: []align(4) u8 = &array; const slice = src_slice[4..5]; comptime assert(@TypeOf(slice) == *align(4) [1]u8); try expect(slice[0] == 5); comptime assert(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); } fn testConcatStrLiterals() !void { try expectEqualSlices(u8, "ab", "a"[0..] ++ "b"[0..]); try expectEqualSlices(u8, "ab", "a"[0.. :0] ++ "b"[0.. :0]); } fn testSliceLength() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var slice: []u8 = &array; comptime assert(@TypeOf(slice[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(slice[1..][0..4]) == *[4]u8); comptime assert(@TypeOf(slice[1..][0..2 :4]) == *[2:4]u8); } fn testSliceLengthZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var slice: [:0]u8 = &array; comptime assert(@TypeOf(slice[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(slice[1..][0..2 :4]) == *[2:4]u8); comptime assert(@TypeOf(slice[1.. :0][0..2]) == *[2]u8); comptime assert(@TypeOf(slice[1.. :0][0..2 :4]) == *[2:4]u8); } fn testArrayLength() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; comptime assert(@TypeOf(array[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(array[1..][0..4]) == *[4]u8); comptime assert(@TypeOf(array[1..][0..2 :4]) == *[2:4]u8); } fn testArrayLengthZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; comptime assert(@TypeOf(array[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(array[1..][0..4]) == *[4:0]u8); comptime assert(@TypeOf(array[1..][0..2 :4]) == *[2:4]u8); comptime assert(@TypeOf(array[1.. :0][0..2]) == *[2]u8); comptime assert(@TypeOf(array[1.. :0][0..4]) == *[4:0]u8); comptime assert(@TypeOf(array[1.. :0][0..2 :4]) == *[2:4]u8); } fn testMultiPointer() !void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var ptr: [*]u8 = &array; comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8); comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8); } fn testMultiPointerLengthZ() !void { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var ptr: [*]u8 = &array; comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8); comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8); var ptr_z: [*:0]u8 = &array; comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8); comptime assert(@TypeOf(ptr_z[1..][0..4]) == *[4]u8); comptime assert(@TypeOf(ptr_z[1..][0..2 :4]) == *[2:4]u8); comptime assert(@TypeOf(ptr_z[1.. :0][0..2]) == *[2]u8); comptime assert(@TypeOf(ptr_z[1.. :0][0..4]) == *[4]u8); comptime assert(@TypeOf(ptr_z[1.. :0][0..2 :4]) == *[2:4]u8); } fn testSingleItemPointer() !void { var value: u8 = 1; var ptr = &value; const slice = ptr[0..1]; comptime assert(@TypeOf(slice) == *[1]u8); try expect(slice[0] == 1); comptime assert(@TypeOf(ptr[0..0]) == *[0]u8); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "slice pointer-to-array null terminated" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; comptime { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var slice: [:0]u8 = &array; try expect(@TypeOf(slice[1..3]) == *[2]u8); try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); try expect(@TypeOf(slice[1..]) == *[4:0]u8); } var array = [5:0]u8{ 1, 2, 3, 4, 5 }; var slice: [:0]u8 = &array; comptime assert(@TypeOf(slice[1..3]) == *[2]u8); comptime assert(@TypeOf(slice[1..3 :4]) == *[2:4]u8); comptime assert(@TypeOf(slice[1..]) == [:0]u8); } test "slice pointer-to-array zero length" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; comptime { { var array = [0]u8{}; var src_slice: []u8 = &array; const slice = src_slice[0..0]; try expect(@TypeOf(slice) == *[0]u8); } { var array = [0:0]u8{}; var src_slice: [:0]u8 = &array; const slice = src_slice[0..0]; try expect(@TypeOf(slice) == *[0:0]u8); } } { var array = [0]u8{}; var src_slice: []u8 = &array; const slice = src_slice[0..0]; comptime assert(@TypeOf(slice) == *[0]u8); } { var array = [0:0]u8{}; var src_slice: [:0]u8 = &array; const slice = src_slice[0..0]; comptime assert(@TypeOf(slice) == *[0]u8); } } test "type coercion of pointer to anon struct literal to pointer to slice" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { const U = union { a: u32, b: bool, c: []const u8, }; fn doTheTest() !void { var x1: u8 = 42; _ = &x1; const t1 = &.{ x1, 56, 54 }; const slice1: []const u8 = t1; try expect(slice1.len == 3); try expect(slice1[0] == 42); try expect(slice1[1] == 56); try expect(slice1[2] == 54); var x2: []const u8 = "hello"; _ = &x2; const t2 = &.{ x2, ", ", "world!" }; // @compileLog(@TypeOf(t2)); const slice2: []const []const u8 = t2; try expect(slice2.len == 3); try expect(mem.eql(u8, slice2[0], "hello")); try expect(mem.eql(u8, slice2[1], ", ")); try expect(mem.eql(u8, slice2[2], "world!")); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "array concat of slices gives ptr to array" { comptime { var a: []const u8 = "aoeu"; var b: []const u8 = "asdf"; _ = .{ &a, &b }; const c = a ++ b; try expect(std.mem.eql(u8, c, "aoeuasdf")); try expect(@TypeOf(c) == *const [8]u8); } } test "array mult of slice gives ptr to array" { comptime { var a: []const u8 = "aoeu"; _ = &a; const c = a ** 2; try expect(std.mem.eql(u8, c, "aoeuaoeu")); try expect(@TypeOf(c) == *const [8]u8); } } test "slice bounds in comptime concatenation" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const bs = comptime blk: { const b = "........1........"; break :blk b[8..9]; }; const str = "" ++ bs; try expect(str.len == 1); try expect(std.mem.eql(u8, str, "1")); const str2 = bs ++ ""; try expect(str2.len == 1); try expect(std.mem.eql(u8, str2, "1")); } test "slice sentinel access at comptime" { { const str0 = &[_:0]u8{ '1', '2', '3' }; const slice0: [:0]const u8 = str0; try expect(slice0.len == 3); try expect(slice0[slice0.len] == 0); } { const str0 = "123"; _ = &str0[0]; const slice0: [:0]const u8 = str0; try expect(slice0.len == 3); try expect(slice0[slice0.len] == 0); } } test "slicing array with sentinel as end index" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn do() !void { var array = [_:0]u8{ 1, 2, 3, 4 }; const slice = array[4..5]; try expect(slice.len == 1); try expect(slice[0] == 0); try expect(@TypeOf(slice) == *[1]u8); } }; try S.do(); try comptime S.do(); } test "slicing slice with sentinel as end index" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn do() !void { var array = [_:0]u8{ 1, 2, 3, 4 }; const src_slice: [:0]u8 = &array; const slice = src_slice[4..5]; try expect(slice.len == 1); try expect(slice[0] == 0); try expect(@TypeOf(slice) == *[1]u8); } }; try S.do(); try comptime S.do(); } test "slice len modification at comptime" { comptime { var buf: [10]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var items: []u8 = buf[0..0]; items.len += 2; try expect(items.len == 2); try expect(items[0] == 0); try expect(items[1] == 1); } } test "slice field ptr const" { const const_slice: []const u8 = "string"; const const_ptr_const_slice = &const_slice; try expectEqual(*const []const u8, @TypeOf(&const_ptr_const_slice.*)); try expectEqual(*const [*]const u8, @TypeOf(&const_ptr_const_slice.ptr)); var var_ptr_const_slice = &const_slice; try expectEqual(*const []const u8, @TypeOf(&var_ptr_const_slice.*)); try expectEqual(*const [*]const u8, @TypeOf(&var_ptr_const_slice.ptr)); } test "slice field ptr var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var var_slice: []const u8 = "string"; var var_ptr_var_slice = &var_slice; try expectEqual(*[]const u8, @TypeOf(&var_ptr_var_slice.*)); try expectEqual(*[*]const u8, @TypeOf(&var_ptr_var_slice.ptr)); const const_ptr_var_slice = &var_slice; try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*)); try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr)); } test "global slice field access" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { var slice: []const u8 = undefined; }; S.slice = "string"; S.slice.ptr += 1; S.slice.len -= 2; try expectEqualStrings("trin", S.slice); } test "slice of void" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var n: usize = 10; _ = &n; var arr: [12]void = undefined; const slice = @as([]void, &arr)[0..n]; try expect(slice.len == n); } test "slice with dereferenced value" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var a: usize = 0; const idx: *usize = &a; _ = blk: { var array = [_]u8{}; break :blk array[idx.*..]; }; const res = blk: { var array = [_]u8{}; break :blk array[idx.*..]; }; try expect(res.len == 0); } test "empty slice ptr is non null" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero { const empty_slice: []u8 = &[_]u8{}; const p: [*]u8 = empty_slice.ptr + 0; const t = @as([*]i8, @ptrCast(p)); try expect(@intFromPtr(t) == @intFromPtr(empty_slice.ptr)); } { const empty_slice: []u8 = &.{}; const p: [*]u8 = empty_slice.ptr + 0; const t = @as([*]i8, @ptrCast(p)); try expect(@intFromPtr(t) == @intFromPtr(empty_slice.ptr)); } } test "slice decays to many pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var buf: [8]u8 = "abcdefg\x00".*; const p: [*:0]const u8 = buf[0..7 :0]; try expectEqualStrings(buf[0..7], std.mem.span(p)); } test "write through pointer to optional slice arg" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn bar(foo: *?[]const u8) !void { foo.* = try baz(); } fn baz() ![]const u8 { return "ok"; } }; var foo: ?[]const u8 = null; try S.bar(&foo); try expectEqualStrings(foo.?, "ok"); } test "modify slice length at comptime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const arr: [2]u8 = .{ 10, 20 }; comptime var s: []const u8 = arr[0..0]; s.len += 1; const a = s; s.len += 1; const b = s; try expectEqualSlices(u8, &.{10}, a); try expectEqualSlices(u8, &.{ 10, 20 }, b); } test "slicing zero length array field of struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: [0]usize, fn foo(self: *@This(), start: usize, end: usize) []usize { return self.a[start..end]; } }; var s: S = undefined; try expect(s.foo(0, 0).len == 0); } test "slicing slices gives correct result" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const foo = "1234"; const bar = foo[0..4]; try expectEqualStrings("1234", bar); try expectEqualStrings("2", bar[1..2]); try expectEqualStrings("3", bar[2..3]); try expectEqualStrings("4", bar[3..4]); try expectEqualStrings("34", bar[2..4]); } test "get address of element of zero-sized slice" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn destroy(_: *void) void {} }; var slice: []void = undefined; S.destroy(&slice[0]); } test "sentinel-terminated 0-length slices" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 }; var index: u8 = 2; _ = &index; const slice = u32s[index..index :2]; const array_ptr = u32s[2..2 :2]; const comptime_known_array_value = u32s[2..2 :2].*; var runtime_array_value = u32s[2..2 :2].*; _ = &runtime_array_value; try expect(slice[0] == 2); try expect(array_ptr[0] == 2); try expect(comptime_known_array_value[0] == 2); try expect(runtime_array_value[0] == 2); } test "peer slices keep abi alignment with empty struct" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var cond: bool = undefined; cond = false; const slice = if (cond) &[1]u32{42} else &.{}; comptime assert(@TypeOf(slice) == []const u32); try expect(slice.len == 0); } test "sentinel expression in slice operation has result type" { const sentinel = std.math.maxInt(u16); const arr: [3]u16 = .{ 1, 2, sentinel }; const slice = arr[0..2 :@intCast(sentinel)]; comptime assert(@TypeOf(slice) == *const [2:sentinel]u16); comptime assert(slice[2] == sentinel); comptime assert(slice.len == 2); comptime assert(slice[0] == 1); comptime assert(slice[1] == 2); } test "conditionally return second argument slice" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn foo(cond: bool, slice: []const u8) []const u8 { if (cond) return slice; return &.{}; } }; try expectEqualStrings("", S.foo(false, "false")); try expectEqualStrings("true", S.foo(true, "true")); }