diff --git a/src/Sema.zig b/src/Sema.zig index b60d474e72..2b7596861e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1340,29 +1340,50 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); const ptr = sema.resolveInst(bin_inst.rhs); - // Create a runtime bitcast instruction with exactly the type the pointer wants. const ptr_ty = try Type.ptr(sema.arena, .{ .pointee_type = pointee_ty, .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), }); - try sema.requireRuntimeBlock(block, src); - const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); if (Air.refToIndex(ptr)) |ptr_inst| { if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { const air_datas = sema.air_instructions.items(.data); const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; - if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { - // Add the stored instruction to the set we will use to resolve peer types - // for the inferred allocation. - // This instruction will not make it to codegen; it is only to participate - // in the `stored_inst_list` of the `inferred_alloc`. - const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); - try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); + switch (ptr_val.tag()) { + .inferred_alloc => { + const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; + // Add the stored instruction to the set we will use to resolve peer types + // for the inferred allocation. + // This instruction will not make it to codegen; it is only to participate + // in the `stored_inst_list` of the `inferred_alloc`. + const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); + try inferred_alloc.stored_inst_list.append(sema.arena, operand); + }, + .inferred_alloc_comptime => { + const iac = ptr_val.castTag(.inferred_alloc_comptime).?; + // There will be only one coerce_result_ptr because we are running at comptime. + // The alloc will turn into a Decl. + var anon_decl = try block.startAnonDecl(); + defer anon_decl.deinit(); + iac.data = try anon_decl.finish( + try pointee_ty.copy(anon_decl.arena()), + Value.undef, + ); + return sema.addConstant( + ptr_ty, + try Value.Tag.decl_ref_mut.create(sema.arena, .{ + .decl = iac.data, + .runtime_index = block.runtime_index, + }), + ); + }, + .decl_ref_mut => return sema.addConstant(ptr_ty, ptr_val), + else => {}, } } } - + try sema.requireRuntimeBlock(block, src); + const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); return bitcasted_ptr; } @@ -1996,6 +2017,9 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; const var_decl_src = inst_data.src(); const var_type = try sema.resolveType(block, ty_src, inst_data.operand); + if (block.is_comptime) { + return sema.analyzeComptimeAlloc(block, var_type); + } const ptr_type = try Type.ptr(sema.arena, .{ .pointee_type = var_type, .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), @@ -13418,9 +13442,10 @@ fn analyzeComptimeAlloc( defer anon_decl.deinit(); const decl = try anon_decl.finish( try var_type.copy(anon_decl.arena()), - // AstGen guarantees there will be a store before the first load, so we put a value - // here indicating there is no valid value. - Value.initTag(.unreachable_value), + // There will be stores before the first load, but they may be to sub-elements or + // sub-fields. So we need to initialize with undef to allow the mechanism to expand + // into fields/elements and have those overridden with stored values. + Value.undef, ); try sema.mod.declareDeclDependency(sema.owner_decl, decl); return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ diff --git a/test/behavior.zig b/test/behavior.zig index c9f8bcaf62..4c854fcb73 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -26,6 +26,7 @@ test { _ = @import("behavior/math.zig"); _ = @import("behavior/member_func.zig"); _ = @import("behavior/pointers.zig"); + _ = @import("behavior/slice.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/struct.zig"); _ = @import("behavior/switch.zig"); @@ -150,7 +151,7 @@ test { _ = @import("behavior/shuffle.zig"); _ = @import("behavior/select.zig"); _ = @import("behavior/sizeof_and_typeof_stage1.zig"); - _ = @import("behavior/slice.zig"); + _ = @import("behavior/slice_stage1.zig"); _ = @import("behavior/slice_sentinel_comptime.zig"); _ = @import("behavior/struct_stage1.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 38d0faa25a..168754381a 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -3,336 +3,3 @@ const expect = std.testing.expect; const expectEqualSlices = std.testing.expectEqualSlices; const expectEqual = std.testing.expectEqual; const mem = std.mem; - -const x = @intToPtr([*]i32, 0x1000)[0..0x500]; -const y = x[0x100..]; -test "compile time slice of pointer to hard coded address" { - try expect(@ptrToInt(x) == 0x1000); - try expect(x.len == 0x500); - - try expect(@ptrToInt(y) == 0x1100); - try expect(y.len == 0x400); -} - -test "runtime safety lets us slice from len..len" { - 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 "implicitly cast array of size 0 to slice" { - var msg = [_]u8{}; - try assertLenIsZero(&msg); -} - -fn assertLenIsZero(msg: []const u8) !void { - try expect(msg.len == 0); -} - -test "C pointer" { - var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; - var len: u32 = 10; - var slice = buf[0..len]; - try expectEqualSlices(u8, "kjdhfkjdhf", slice); -} - -test "C pointer slice access" { - var buf: [10]u32 = [1]u32{42} ** 10; - const c_ptr = @ptrCast([*c]const u32, &buf); - - var runtime_zero: usize = 0; - comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); - comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); - - for (c_ptr[0..5]) |*cl| { - try expectEqual(@as(u32, 42), cl.*); - } -} - -fn sliceSum(comptime q: []const u8) i32 { - comptime var result = 0; - inline for (q) |item| { - result += item; - } - return result; -} - -test "comptime slices are disambiguated" { - try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); - try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); -} - -test "slice type with custom alignment" { - 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 "access len index of sentinel-terminated slice" { - const S = struct { - fn doTheTest() !void { - var slice: [:0]const u8 = "hello"; - - try expect(slice.len == 5); - try expect(slice[5] == 0); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "obtaining a null terminated slice" { - // 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; - const ptr2 = buf[0..runtime_len :0]; - // ptr2 is a null-terminated slice - comptime try expect(@TypeOf(ptr2) == [:0]u8); - comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); - var runtime_zero: usize = 0; - comptime try expect(@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 expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); - try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); - try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); - } - }; - - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "@ptrCast slice to pointer" { - const S = struct { - fn doTheTest() !void { - var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; - var slice: []u8 = &array; - var ptr = @ptrCast(*u16, slice); - try expect(ptr.* == 65535); - } - }; - - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "slice syntax resulting in pointer-to-array" { - 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 testSlice0(); - try testSliceOpt(); - try testSliceAlign(); - } - - fn testArray() !void { - var array = [5]u8{ 1, 2, 3, 4, 5 }; - var slice = array[1..3]; - comptime try expect(@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 try expect(@TypeOf(array[1..3]) == *[2]u8); - comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); - comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); - comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); - } - - fn testArray0() !void { - { - var array = [0]u8{}; - var slice = array[0..0]; - comptime try expect(@TypeOf(slice) == *[0]u8); - } - { - var array = [0:0]u8{}; - var slice = array[0..0]; - comptime try expect(@TypeOf(slice) == *[0:0]u8); - try expect(slice[0] == 0); - } - } - - fn testArrayAlign() !void { - var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; - var slice = array[4..5]; - comptime try expect(@TypeOf(slice) == *align(4) [1]u8); - try expect(slice[0] == 5); - comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); - } - - fn testPointer() !void { - var array = [5]u8{ 1, 2, 3, 4, 5 }; - var pointer: [*]u8 = &array; - var slice = pointer[1..3]; - comptime try expect(@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 try expect(@TypeOf(pointer[1..3]) == *[2]u8); - comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); - } - - fn testPointer0() !void { - var pointer: [*]const u0 = &[1]u0{0}; - var slice = pointer[0..1]; - comptime try expect(@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; - var slice = pointer[4..5]; - comptime try expect(@TypeOf(slice) == *align(4) [1]u8); - try expect(slice[0] == 5); - comptime try expect(@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; - var slice = src_slice[1..3]; - comptime try expect(@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 try expect(@TypeOf(slice[1..3]) == *[2]u8); - comptime try expect(@TypeOf(slice[1..]) == [:0]u8); - comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); - } - - fn testSliceOpt() !void { - var array: [2]u8 = [2]u8{ 1, 2 }; - var slice: ?[]u8 = &array; - comptime try expect(@TypeOf(&array, slice) == ?[]u8); - comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); - } - - fn testSlice0() !void { - { - var array = [0]u8{}; - var src_slice: []u8 = &array; - var slice = src_slice[0..0]; - comptime try expect(@TypeOf(slice) == *[0]u8); - } - { - var array = [0:0]u8{}; - var src_slice: [:0]u8 = &array; - var slice = src_slice[0..0]; - comptime try expect(@TypeOf(slice) == *[0]u8); - } - } - - fn testSliceAlign() !void { - var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; - var src_slice: []align(4) u8 = &array; - var slice = src_slice[4..5]; - comptime try expect(@TypeOf(slice) == *align(4) [1]u8); - try expect(slice[0] == 5); - comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); - } - - fn testConcatStrLiterals() !void { - try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); - try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); - } - }; - - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "slice of hardcoded address to pointer" { - const S = struct { - fn doTheTest() !void { - const pointer = @intToPtr([*]u8, 0x04)[0..2]; - comptime try expect(@TypeOf(pointer) == *[2]u8); - const slice: []const u8 = pointer; - try expect(@ptrToInt(slice.ptr) == 4); - try expect(slice.len == 2); - } - }; - - try S.doTheTest(); -} - -test "type coercion of pointer to anon struct literal to pointer to slice" { - const S = struct { - const U = union { - a: u32, - b: bool, - c: []const u8, - }; - - fn doTheTest() !void { - var x1: u8 = 42; - const t1 = &.{ x1, 56, 54 }; - var 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"; - const t2 = &.{ x2, ", ", "world!" }; - // @compileLog(@TypeOf(t2)); - var 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(); - comptime try S.doTheTest(); -} diff --git a/test/behavior/slice_stage1.zig b/test/behavior/slice_stage1.zig new file mode 100644 index 0000000000..a533136a25 --- /dev/null +++ b/test/behavior/slice_stage1.zig @@ -0,0 +1,334 @@ +const std = @import("std"); +const expect = std.testing.expect; +const expectEqualSlices = std.testing.expectEqualSlices; +const expectEqual = std.testing.expectEqual; +const mem = std.mem; + +const x = @intToPtr([*]i32, 0x1000)[0..0x500]; +const y = x[0x100..]; +test "compile time slice of pointer to hard coded address" { + try expect(@ptrToInt(x) == 0x1000); + try expect(x.len == 0x500); + + try expect(@ptrToInt(y) == 0x1100); + try expect(y.len == 0x400); +} + +test "runtime safety lets us slice from len..len" { + 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 "implicitly cast array of size 0 to slice" { + var msg = [_]u8{}; + try assertLenIsZero(&msg); +} + +fn assertLenIsZero(msg: []const u8) !void { + try expect(msg.len == 0); +} + +test "C pointer" { + var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; + var len: u32 = 10; + var slice = buf[0..len]; + try expectEqualSlices(u8, "kjdhfkjdhf", slice); +} + +test "C pointer slice access" { + var buf: [10]u32 = [1]u32{42} ** 10; + const c_ptr = @ptrCast([*c]const u32, &buf); + + var runtime_zero: usize = 0; + comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); + comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); + + for (c_ptr[0..5]) |*cl| { + try expectEqual(@as(u32, 42), cl.*); + } +} + +fn sliceSum(comptime q: []const u8) i32 { + comptime var result = 0; + inline for (q) |item| { + result += item; + } + return result; +} + +test "comptime slices are disambiguated" { + try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); + try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); +} + +test "slice type with custom alignment" { + 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 "access len index of sentinel-terminated slice" { + const S = struct { + fn doTheTest() !void { + var slice: [:0]const u8 = "hello"; + + try expect(slice.len == 5); + try expect(slice[5] == 0); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "obtaining a null terminated slice" { + // 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; + const ptr2 = buf[0..runtime_len :0]; + // ptr2 is a null-terminated slice + comptime try expect(@TypeOf(ptr2) == [:0]u8); + comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); + var runtime_zero: usize = 0; + comptime try expect(@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 expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); + try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); + try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "@ptrCast slice to pointer" { + const S = struct { + fn doTheTest() !void { + var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; + var slice: []u8 = &array; + var ptr = @ptrCast(*u16, slice); + try expect(ptr.* == 65535); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "slice syntax resulting in pointer-to-array" { + 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 testSlice0(); + try testSliceOpt(); + try testSliceAlign(); + } + + fn testArray() !void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[1..3]; + comptime try expect(@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 try expect(@TypeOf(array[1..3]) == *[2]u8); + comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); + comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); + comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); + } + + fn testArray0() !void { + { + var array = [0]u8{}; + var slice = array[0..0]; + comptime try expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var slice = array[0..0]; + comptime try expect(@TypeOf(slice) == *[0:0]u8); + try expect(slice[0] == 0); + } + } + + fn testArrayAlign() !void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[4..5]; + comptime try expect(@TypeOf(slice) == *align(4) [1]u8); + try expect(slice[0] == 5); + comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); + } + + fn testPointer() !void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*]u8 = &array; + var slice = pointer[1..3]; + comptime try expect(@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 try expect(@TypeOf(pointer[1..3]) == *[2]u8); + comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); + } + + fn testPointer0() !void { + var pointer: [*]const u0 = &[1]u0{0}; + var slice = pointer[0..1]; + comptime try expect(@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; + var slice = pointer[4..5]; + comptime try expect(@TypeOf(slice) == *align(4) [1]u8); + try expect(slice[0] == 5); + comptime try expect(@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; + var slice = src_slice[1..3]; + comptime try expect(@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 try expect(@TypeOf(slice[1..3]) == *[2]u8); + comptime try expect(@TypeOf(slice[1..]) == [:0]u8); + comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); + } + + fn testSliceOpt() !void { + var array: [2]u8 = [2]u8{ 1, 2 }; + var slice: ?[]u8 = &array; + comptime try expect(@TypeOf(&array, slice) == ?[]u8); + comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); + } + + fn testSlice0() !void { + { + var array = [0]u8{}; + var src_slice: []u8 = &array; + var slice = src_slice[0..0]; + comptime try expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var src_slice: [:0]u8 = &array; + var slice = src_slice[0..0]; + comptime try expect(@TypeOf(slice) == *[0]u8); + } + } + + fn testSliceAlign() !void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var src_slice: []align(4) u8 = &array; + var slice = src_slice[4..5]; + comptime try expect(@TypeOf(slice) == *align(4) [1]u8); + try expect(slice[0] == 5); + comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); + } + + fn testConcatStrLiterals() !void { + try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); + try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "slice of hardcoded address to pointer" { + const S = struct { + fn doTheTest() !void { + const pointer = @intToPtr([*]u8, 0x04)[0..2]; + comptime try expect(@TypeOf(pointer) == *[2]u8); + const slice: []const u8 = pointer; + try expect(@ptrToInt(slice.ptr) == 4); + try expect(slice.len == 2); + } + }; + + try S.doTheTest(); +} + +test "type coercion of pointer to anon struct literal to pointer to slice" { + const S = struct { + const U = union { + a: u32, + b: bool, + c: []const u8, + }; + + fn doTheTest() !void { + var x1: u8 = 42; + const t1 = &.{ x1, 56, 54 }; + var 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"; + const t2 = &.{ x2, ", ", "world!" }; + // @compileLog(@TypeOf(t2)); + var 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(); + comptime try S.doTheTest(); +}