| author | |
| committer | |
| log | e851d89113a57064c38ed85722edc7f686d0c11a |
| tree | 959a2858d2fe1e72356b888c9e67b1866b81b41c |
| parent | 2a701a92c403dda47a61848a38998b474442d805 |
This is progress towards being able to use `builtin.cpu.arch` instead of
the `stage2_arch` workaround. The next blocker is comptime `elemVal`.4 files changed, 375 insertions(+), 348 deletions(-)
src/Sema.zig+39-14| ... | ... | @@ -1340,29 +1340,50 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1340 | 1340 | const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); |
| 1341 | 1341 | const ptr = sema.resolveInst(bin_inst.rhs); |
| 1342 | 1342 | |
| 1343 | // Create a runtime bitcast instruction with exactly the type the pointer wants. | |
| 1344 | 1343 | const ptr_ty = try Type.ptr(sema.arena, .{ |
| 1345 | 1344 | .pointee_type = pointee_ty, |
| 1346 | 1345 | .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), |
| 1347 | 1346 | }); |
| 1348 | try sema.requireRuntimeBlock(block, src); | |
| 1349 | const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); | |
| 1350 | 1347 | |
| 1351 | 1348 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 1352 | 1349 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { |
| 1353 | 1350 | const air_datas = sema.air_instructions.items(.data); |
| 1354 | 1351 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 1355 | if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { | |
| 1356 | // Add the stored instruction to the set we will use to resolve peer types | |
| 1357 | // for the inferred allocation. | |
| 1358 | // This instruction will not make it to codegen; it is only to participate | |
| 1359 | // in the `stored_inst_list` of the `inferred_alloc`. | |
| 1360 | const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); | |
| 1361 | try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); | |
| 1352 | switch (ptr_val.tag()) { | |
| 1353 | .inferred_alloc => { | |
| 1354 | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; | |
| 1355 | // Add the stored instruction to the set we will use to resolve peer types | |
| 1356 | // for the inferred allocation. | |
| 1357 | // This instruction will not make it to codegen; it is only to participate | |
| 1358 | // in the `stored_inst_list` of the `inferred_alloc`. | |
| 1359 | const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); | |
| 1360 | try inferred_alloc.stored_inst_list.append(sema.arena, operand); | |
| 1361 | }, | |
| 1362 | .inferred_alloc_comptime => { | |
| 1363 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | |
| 1364 | // There will be only one coerce_result_ptr because we are running at comptime. | |
| 1365 | // The alloc will turn into a Decl. | |
| 1366 | var anon_decl = try block.startAnonDecl(); | |
| 1367 | defer anon_decl.deinit(); | |
| 1368 | iac.data = try anon_decl.finish( | |
| 1369 | try pointee_ty.copy(anon_decl.arena()), | |
| 1370 | Value.undef, | |
| 1371 | ); | |
| 1372 | return sema.addConstant( | |
| 1373 | ptr_ty, | |
| 1374 | try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 1375 | .decl = iac.data, | |
| 1376 | .runtime_index = block.runtime_index, | |
| 1377 | }), | |
| 1378 | ); | |
| 1379 | }, | |
| 1380 | .decl_ref_mut => return sema.addConstant(ptr_ty, ptr_val), | |
| 1381 | else => {}, | |
| 1362 | 1382 | } |
| 1363 | 1383 | } |
| 1364 | 1384 | } |
| 1365 | ||
| 1385 | try sema.requireRuntimeBlock(block, src); | |
| 1386 | const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); | |
| 1366 | 1387 | return bitcasted_ptr; |
| 1367 | 1388 | } |
| 1368 | 1389 | |
| ... | ... | @@ -1996,6 +2017,9 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 1996 | 2017 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; |
| 1997 | 2018 | const var_decl_src = inst_data.src(); |
| 1998 | 2019 | const var_type = try sema.resolveType(block, ty_src, inst_data.operand); |
| 2020 | if (block.is_comptime) { | |
| 2021 | return sema.analyzeComptimeAlloc(block, var_type); | |
| 2022 | } | |
| 1999 | 2023 | const ptr_type = try Type.ptr(sema.arena, .{ |
| 2000 | 2024 | .pointee_type = var_type, |
| 2001 | 2025 | .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), |
| ... | ... | @@ -13418,9 +13442,10 @@ fn analyzeComptimeAlloc( |
| 13418 | 13442 | defer anon_decl.deinit(); |
| 13419 | 13443 | const decl = try anon_decl.finish( |
| 13420 | 13444 | try var_type.copy(anon_decl.arena()), |
| 13421 | // AstGen guarantees there will be a store before the first load, so we put a value | |
| 13422 | // here indicating there is no valid value. | |
| 13423 | Value.initTag(.unreachable_value), | |
| 13445 | // There will be stores before the first load, but they may be to sub-elements or | |
| 13446 | // sub-fields. So we need to initialize with undef to allow the mechanism to expand | |
| 13447 | // into fields/elements and have those overridden with stored values. | |
| 13448 | Value.undef, | |
| 13424 | 13449 | ); |
| 13425 | 13450 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 13426 | 13451 | return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ |
test/behavior.zig+2-1| ... | ... | @@ -26,6 +26,7 @@ test { |
| 26 | 26 | _ = @import("behavior/math.zig"); |
| 27 | 27 | _ = @import("behavior/member_func.zig"); |
| 28 | 28 | _ = @import("behavior/pointers.zig"); |
| 29 | _ = @import("behavior/slice.zig"); | |
| 29 | 30 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 30 | 31 | _ = @import("behavior/struct.zig"); |
| 31 | 32 | _ = @import("behavior/switch.zig"); |
| ... | ... | @@ -150,7 +151,7 @@ test { |
| 150 | 151 | _ = @import("behavior/shuffle.zig"); |
| 151 | 152 | _ = @import("behavior/select.zig"); |
| 152 | 153 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); |
| 153 | _ = @import("behavior/slice.zig"); | |
| 154 | _ = @import("behavior/slice_stage1.zig"); | |
| 154 | 155 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 155 | 156 | _ = @import("behavior/struct_stage1.zig"); |
| 156 | 157 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
test/behavior/slice.zig-333| ... | ... | @@ -3,336 +3,3 @@ const expect = std.testing.expect; |
| 3 | 3 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | const mem = std.mem; |
| 6 | ||
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | |
| 8 | const y = x[0x100..]; | |
| 9 | test "compile time slice of pointer to hard coded address" { | |
| 10 | try expect(@ptrToInt(x) == 0x1000); | |
| 11 | try expect(x.len == 0x500); | |
| 12 | ||
| 13 | try expect(@ptrToInt(y) == 0x1100); | |
| 14 | try expect(y.len == 0x400); | |
| 15 | } | |
| 16 | ||
| 17 | test "runtime safety lets us slice from len..len" { | |
| 18 | var an_array = [_]u8{ | |
| 19 | 1, | |
| 20 | 2, | |
| 21 | 3, | |
| 22 | }; | |
| 23 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | |
| 24 | } | |
| 25 | ||
| 26 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | |
| 27 | return a_slice[start..end]; | |
| 28 | } | |
| 29 | ||
| 30 | test "implicitly cast array of size 0 to slice" { | |
| 31 | var msg = [_]u8{}; | |
| 32 | try assertLenIsZero(&msg); | |
| 33 | } | |
| 34 | ||
| 35 | fn assertLenIsZero(msg: []const u8) !void { | |
| 36 | try expect(msg.len == 0); | |
| 37 | } | |
| 38 | ||
| 39 | test "C pointer" { | |
| 40 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | |
| 41 | var len: u32 = 10; | |
| 42 | var slice = buf[0..len]; | |
| 43 | try expectEqualSlices(u8, "kjdhfkjdhf", slice); | |
| 44 | } | |
| 45 | ||
| 46 | test "C pointer slice access" { | |
| 47 | var buf: [10]u32 = [1]u32{42} ** 10; | |
| 48 | const c_ptr = @ptrCast([*c]const u32, &buf); | |
| 49 | ||
| 50 | var runtime_zero: usize = 0; | |
| 51 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | |
| 52 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | |
| 53 | ||
| 54 | for (c_ptr[0..5]) |*cl| { | |
| 55 | try expectEqual(@as(u32, 42), cl.*); | |
| 56 | } | |
| 57 | } | |
| 58 | ||
| 59 | fn sliceSum(comptime q: []const u8) i32 { | |
| 60 | comptime var result = 0; | |
| 61 | inline for (q) |item| { | |
| 62 | result += item; | |
| 63 | } | |
| 64 | return result; | |
| 65 | } | |
| 66 | ||
| 67 | test "comptime slices are disambiguated" { | |
| 68 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | |
| 69 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | |
| 70 | } | |
| 71 | ||
| 72 | test "slice type with custom alignment" { | |
| 73 | const LazilyResolvedType = struct { | |
| 74 | anything: i32, | |
| 75 | }; | |
| 76 | var slice: []align(32) LazilyResolvedType = undefined; | |
| 77 | var array: [10]LazilyResolvedType align(32) = undefined; | |
| 78 | slice = &array; | |
| 79 | slice[1].anything = 42; | |
| 80 | try expect(array[1].anything == 42); | |
| 81 | } | |
| 82 | ||
| 83 | test "access len index of sentinel-terminated slice" { | |
| 84 | const S = struct { | |
| 85 | fn doTheTest() !void { | |
| 86 | var slice: [:0]const u8 = "hello"; | |
| 87 | ||
| 88 | try expect(slice.len == 5); | |
| 89 | try expect(slice[5] == 0); | |
| 90 | } | |
| 91 | }; | |
| 92 | try S.doTheTest(); | |
| 93 | comptime try S.doTheTest(); | |
| 94 | } | |
| 95 | ||
| 96 | test "obtaining a null terminated slice" { | |
| 97 | // here we have a normal array | |
| 98 | var buf: [50]u8 = undefined; | |
| 99 | ||
| 100 | buf[0] = 'a'; | |
| 101 | buf[1] = 'b'; | |
| 102 | buf[2] = 'c'; | |
| 103 | buf[3] = 0; | |
| 104 | ||
| 105 | // now we obtain a null terminated slice: | |
| 106 | const ptr = buf[0..3 :0]; | |
| 107 | _ = ptr; | |
| 108 | ||
| 109 | var runtime_len: usize = 3; | |
| 110 | const ptr2 = buf[0..runtime_len :0]; | |
| 111 | // ptr2 is a null-terminated slice | |
| 112 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | |
| 113 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | |
| 114 | var runtime_zero: usize = 0; | |
| 115 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | |
| 116 | } | |
| 117 | ||
| 118 | test "empty array to slice" { | |
| 119 | const S = struct { | |
| 120 | fn doTheTest() !void { | |
| 121 | const empty: []align(16) u8 = &[_]u8{}; | |
| 122 | const align_1: []align(1) u8 = empty; | |
| 123 | const align_4: []align(4) u8 = empty; | |
| 124 | const align_16: []align(16) u8 = empty; | |
| 125 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | |
| 126 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | |
| 127 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | |
| 128 | } | |
| 129 | }; | |
| 130 | ||
| 131 | try S.doTheTest(); | |
| 132 | comptime try S.doTheTest(); | |
| 133 | } | |
| 134 | ||
| 135 | test "@ptrCast slice to pointer" { | |
| 136 | const S = struct { | |
| 137 | fn doTheTest() !void { | |
| 138 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | |
| 139 | var slice: []u8 = &array; | |
| 140 | var ptr = @ptrCast(*u16, slice); | |
| 141 | try expect(ptr.* == 65535); | |
| 142 | } | |
| 143 | }; | |
| 144 | ||
| 145 | try S.doTheTest(); | |
| 146 | comptime try S.doTheTest(); | |
| 147 | } | |
| 148 | ||
| 149 | test "slice syntax resulting in pointer-to-array" { | |
| 150 | const S = struct { | |
| 151 | fn doTheTest() !void { | |
| 152 | try testArray(); | |
| 153 | try testArrayZ(); | |
| 154 | try testArray0(); | |
| 155 | try testArrayAlign(); | |
| 156 | try testPointer(); | |
| 157 | try testPointerZ(); | |
| 158 | try testPointer0(); | |
| 159 | try testPointerAlign(); | |
| 160 | try testSlice(); | |
| 161 | try testSliceZ(); | |
| 162 | try testSlice0(); | |
| 163 | try testSliceOpt(); | |
| 164 | try testSliceAlign(); | |
| 165 | } | |
| 166 | ||
| 167 | fn testArray() !void { | |
| 168 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 169 | var slice = array[1..3]; | |
| 170 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 171 | try expect(slice[0] == 2); | |
| 172 | try expect(slice[1] == 3); | |
| 173 | } | |
| 174 | ||
| 175 | fn testArrayZ() !void { | |
| 176 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 177 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | |
| 178 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | |
| 179 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | |
| 180 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | |
| 181 | } | |
| 182 | ||
| 183 | fn testArray0() !void { | |
| 184 | { | |
| 185 | var array = [0]u8{}; | |
| 186 | var slice = array[0..0]; | |
| 187 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 188 | } | |
| 189 | { | |
| 190 | var array = [0:0]u8{}; | |
| 191 | var slice = array[0..0]; | |
| 192 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | |
| 193 | try expect(slice[0] == 0); | |
| 194 | } | |
| 195 | } | |
| 196 | ||
| 197 | fn testArrayAlign() !void { | |
| 198 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 199 | var slice = array[4..5]; | |
| 200 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 201 | try expect(slice[0] == 5); | |
| 202 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | |
| 203 | } | |
| 204 | ||
| 205 | fn testPointer() !void { | |
| 206 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 207 | var pointer: [*]u8 = &array; | |
| 208 | var slice = pointer[1..3]; | |
| 209 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 210 | try expect(slice[0] == 2); | |
| 211 | try expect(slice[1] == 3); | |
| 212 | } | |
| 213 | ||
| 214 | fn testPointerZ() !void { | |
| 215 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 216 | var pointer: [*:0]u8 = &array; | |
| 217 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | |
| 218 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | |
| 219 | } | |
| 220 | ||
| 221 | fn testPointer0() !void { | |
| 222 | var pointer: [*]const u0 = &[1]u0{0}; | |
| 223 | var slice = pointer[0..1]; | |
| 224 | comptime try expect(@TypeOf(slice) == *const [1]u0); | |
| 225 | try expect(slice[0] == 0); | |
| 226 | } | |
| 227 | ||
| 228 | fn testPointerAlign() !void { | |
| 229 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 230 | var pointer: [*]align(4) u8 = &array; | |
| 231 | var slice = pointer[4..5]; | |
| 232 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 233 | try expect(slice[0] == 5); | |
| 234 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | |
| 235 | } | |
| 236 | ||
| 237 | fn testSlice() !void { | |
| 238 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 239 | var src_slice: []u8 = &array; | |
| 240 | var slice = src_slice[1..3]; | |
| 241 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 242 | try expect(slice[0] == 2); | |
| 243 | try expect(slice[1] == 3); | |
| 244 | } | |
| 245 | ||
| 246 | fn testSliceZ() !void { | |
| 247 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 248 | var slice: [:0]u8 = &array; | |
| 249 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | |
| 250 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | |
| 251 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | |
| 252 | } | |
| 253 | ||
| 254 | fn testSliceOpt() !void { | |
| 255 | var array: [2]u8 = [2]u8{ 1, 2 }; | |
| 256 | var slice: ?[]u8 = &array; | |
| 257 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | |
| 258 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | |
| 259 | } | |
| 260 | ||
| 261 | fn testSlice0() !void { | |
| 262 | { | |
| 263 | var array = [0]u8{}; | |
| 264 | var src_slice: []u8 = &array; | |
| 265 | var slice = src_slice[0..0]; | |
| 266 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 267 | } | |
| 268 | { | |
| 269 | var array = [0:0]u8{}; | |
| 270 | var src_slice: [:0]u8 = &array; | |
| 271 | var slice = src_slice[0..0]; | |
| 272 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 273 | } | |
| 274 | } | |
| 275 | ||
| 276 | fn testSliceAlign() !void { | |
| 277 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 278 | var src_slice: []align(4) u8 = &array; | |
| 279 | var slice = src_slice[4..5]; | |
| 280 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 281 | try expect(slice[0] == 5); | |
| 282 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | |
| 283 | } | |
| 284 | ||
| 285 | fn testConcatStrLiterals() !void { | |
| 286 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | |
| 287 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | |
| 288 | } | |
| 289 | }; | |
| 290 | ||
| 291 | try S.doTheTest(); | |
| 292 | comptime try S.doTheTest(); | |
| 293 | } | |
| 294 | ||
| 295 | test "slice of hardcoded address to pointer" { | |
| 296 | const S = struct { | |
| 297 | fn doTheTest() !void { | |
| 298 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | |
| 299 | comptime try expect(@TypeOf(pointer) == *[2]u8); | |
| 300 | const slice: []const u8 = pointer; | |
| 301 | try expect(@ptrToInt(slice.ptr) == 4); | |
| 302 | try expect(slice.len == 2); | |
| 303 | } | |
| 304 | }; | |
| 305 | ||
| 306 | try S.doTheTest(); | |
| 307 | } | |
| 308 | ||
| 309 | test "type coercion of pointer to anon struct literal to pointer to slice" { | |
| 310 | const S = struct { | |
| 311 | const U = union { | |
| 312 | a: u32, | |
| 313 | b: bool, | |
| 314 | c: []const u8, | |
| 315 | }; | |
| 316 | ||
| 317 | fn doTheTest() !void { | |
| 318 | var x1: u8 = 42; | |
| 319 | const t1 = &.{ x1, 56, 54 }; | |
| 320 | var slice1: []const u8 = t1; | |
| 321 | try expect(slice1.len == 3); | |
| 322 | try expect(slice1[0] == 42); | |
| 323 | try expect(slice1[1] == 56); | |
| 324 | try expect(slice1[2] == 54); | |
| 325 | ||
| 326 | var x2: []const u8 = "hello"; | |
| 327 | const t2 = &.{ x2, ", ", "world!" }; | |
| 328 | // @compileLog(@TypeOf(t2)); | |
| 329 | var slice2: []const []const u8 = t2; | |
| 330 | try expect(slice2.len == 3); | |
| 331 | try expect(mem.eql(u8, slice2[0], "hello")); | |
| 332 | try expect(mem.eql(u8, slice2[1], ", ")); | |
| 333 | try expect(mem.eql(u8, slice2[2], "world!")); | |
| 334 | } | |
| 335 | }; | |
| 336 | // try S.doTheTest(); | |
| 337 | comptime try S.doTheTest(); | |
| 338 | } |
test/behavior/slice_stage1.zig created+334| ... | ... | @@ -0,0 +1,334 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | |
| 4 | const expectEqual = std.testing.expectEqual; | |
| 5 | const mem = std.mem; | |
| 6 | ||
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | |
| 8 | const y = x[0x100..]; | |
| 9 | test "compile time slice of pointer to hard coded address" { | |
| 10 | try expect(@ptrToInt(x) == 0x1000); | |
| 11 | try expect(x.len == 0x500); | |
| 12 | ||
| 13 | try expect(@ptrToInt(y) == 0x1100); | |
| 14 | try expect(y.len == 0x400); | |
| 15 | } | |
| 16 | ||
| 17 | test "runtime safety lets us slice from len..len" { | |
| 18 | var an_array = [_]u8{ 1, 2, 3 }; | |
| 19 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | |
| 20 | } | |
| 21 | ||
| 22 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | |
| 23 | return a_slice[start..end]; | |
| 24 | } | |
| 25 | ||
| 26 | test "implicitly cast array of size 0 to slice" { | |
| 27 | var msg = [_]u8{}; | |
| 28 | try assertLenIsZero(&msg); | |
| 29 | } | |
| 30 | ||
| 31 | fn assertLenIsZero(msg: []const u8) !void { | |
| 32 | try expect(msg.len == 0); | |
| 33 | } | |
| 34 | ||
| 35 | test "C pointer" { | |
| 36 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | |
| 37 | var len: u32 = 10; | |
| 38 | var slice = buf[0..len]; | |
| 39 | try expectEqualSlices(u8, "kjdhfkjdhf", slice); | |
| 40 | } | |
| 41 | ||
| 42 | test "C pointer slice access" { | |
| 43 | var buf: [10]u32 = [1]u32{42} ** 10; | |
| 44 | const c_ptr = @ptrCast([*c]const u32, &buf); | |
| 45 | ||
| 46 | var runtime_zero: usize = 0; | |
| 47 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | |
| 48 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | |
| 49 | ||
| 50 | for (c_ptr[0..5]) |*cl| { | |
| 51 | try expectEqual(@as(u32, 42), cl.*); | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | fn sliceSum(comptime q: []const u8) i32 { | |
| 56 | comptime var result = 0; | |
| 57 | inline for (q) |item| { | |
| 58 | result += item; | |
| 59 | } | |
| 60 | return result; | |
| 61 | } | |
| 62 | ||
| 63 | test "comptime slices are disambiguated" { | |
| 64 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | |
| 65 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | |
| 66 | } | |
| 67 | ||
| 68 | test "slice type with custom alignment" { | |
| 69 | const LazilyResolvedType = struct { | |
| 70 | anything: i32, | |
| 71 | }; | |
| 72 | var slice: []align(32) LazilyResolvedType = undefined; | |
| 73 | var array: [10]LazilyResolvedType align(32) = undefined; | |
| 74 | slice = &array; | |
| 75 | slice[1].anything = 42; | |
| 76 | try expect(array[1].anything == 42); | |
| 77 | } | |
| 78 | ||
| 79 | test "access len index of sentinel-terminated slice" { | |
| 80 | const S = struct { | |
| 81 | fn doTheTest() !void { | |
| 82 | var slice: [:0]const u8 = "hello"; | |
| 83 | ||
| 84 | try expect(slice.len == 5); | |
| 85 | try expect(slice[5] == 0); | |
| 86 | } | |
| 87 | }; | |
| 88 | try S.doTheTest(); | |
| 89 | comptime try S.doTheTest(); | |
| 90 | } | |
| 91 | ||
| 92 | test "obtaining a null terminated slice" { | |
| 93 | // here we have a normal array | |
| 94 | var buf: [50]u8 = undefined; | |
| 95 | ||
| 96 | buf[0] = 'a'; | |
| 97 | buf[1] = 'b'; | |
| 98 | buf[2] = 'c'; | |
| 99 | buf[3] = 0; | |
| 100 | ||
| 101 | // now we obtain a null terminated slice: | |
| 102 | const ptr = buf[0..3 :0]; | |
| 103 | _ = ptr; | |
| 104 | ||
| 105 | var runtime_len: usize = 3; | |
| 106 | const ptr2 = buf[0..runtime_len :0]; | |
| 107 | // ptr2 is a null-terminated slice | |
| 108 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | |
| 109 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | |
| 110 | var runtime_zero: usize = 0; | |
| 111 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | |
| 112 | } | |
| 113 | ||
| 114 | test "empty array to slice" { | |
| 115 | const S = struct { | |
| 116 | fn doTheTest() !void { | |
| 117 | const empty: []align(16) u8 = &[_]u8{}; | |
| 118 | const align_1: []align(1) u8 = empty; | |
| 119 | const align_4: []align(4) u8 = empty; | |
| 120 | const align_16: []align(16) u8 = empty; | |
| 121 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | |
| 122 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | |
| 123 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | |
| 124 | } | |
| 125 | }; | |
| 126 | ||
| 127 | try S.doTheTest(); | |
| 128 | comptime try S.doTheTest(); | |
| 129 | } | |
| 130 | ||
| 131 | test "@ptrCast slice to pointer" { | |
| 132 | const S = struct { | |
| 133 | fn doTheTest() !void { | |
| 134 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | |
| 135 | var slice: []u8 = &array; | |
| 136 | var ptr = @ptrCast(*u16, slice); | |
| 137 | try expect(ptr.* == 65535); | |
| 138 | } | |
| 139 | }; | |
| 140 | ||
| 141 | try S.doTheTest(); | |
| 142 | comptime try S.doTheTest(); | |
| 143 | } | |
| 144 | ||
| 145 | test "slice syntax resulting in pointer-to-array" { | |
| 146 | const S = struct { | |
| 147 | fn doTheTest() !void { | |
| 148 | try testArray(); | |
| 149 | try testArrayZ(); | |
| 150 | try testArray0(); | |
| 151 | try testArrayAlign(); | |
| 152 | try testPointer(); | |
| 153 | try testPointerZ(); | |
| 154 | try testPointer0(); | |
| 155 | try testPointerAlign(); | |
| 156 | try testSlice(); | |
| 157 | try testSliceZ(); | |
| 158 | try testSlice0(); | |
| 159 | try testSliceOpt(); | |
| 160 | try testSliceAlign(); | |
| 161 | } | |
| 162 | ||
| 163 | fn testArray() !void { | |
| 164 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 165 | var slice = array[1..3]; | |
| 166 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 167 | try expect(slice[0] == 2); | |
| 168 | try expect(slice[1] == 3); | |
| 169 | } | |
| 170 | ||
| 171 | fn testArrayZ() !void { | |
| 172 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 173 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | |
| 174 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | |
| 175 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | |
| 176 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | |
| 177 | } | |
| 178 | ||
| 179 | fn testArray0() !void { | |
| 180 | { | |
| 181 | var array = [0]u8{}; | |
| 182 | var slice = array[0..0]; | |
| 183 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 184 | } | |
| 185 | { | |
| 186 | var array = [0:0]u8{}; | |
| 187 | var slice = array[0..0]; | |
| 188 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | |
| 189 | try expect(slice[0] == 0); | |
| 190 | } | |
| 191 | } | |
| 192 | ||
| 193 | fn testArrayAlign() !void { | |
| 194 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 195 | var slice = array[4..5]; | |
| 196 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 197 | try expect(slice[0] == 5); | |
| 198 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | |
| 199 | } | |
| 200 | ||
| 201 | fn testPointer() !void { | |
| 202 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 203 | var pointer: [*]u8 = &array; | |
| 204 | var slice = pointer[1..3]; | |
| 205 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 206 | try expect(slice[0] == 2); | |
| 207 | try expect(slice[1] == 3); | |
| 208 | } | |
| 209 | ||
| 210 | fn testPointerZ() !void { | |
| 211 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 212 | var pointer: [*:0]u8 = &array; | |
| 213 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | |
| 214 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | |
| 215 | } | |
| 216 | ||
| 217 | fn testPointer0() !void { | |
| 218 | var pointer: [*]const u0 = &[1]u0{0}; | |
| 219 | var slice = pointer[0..1]; | |
| 220 | comptime try expect(@TypeOf(slice) == *const [1]u0); | |
| 221 | try expect(slice[0] == 0); | |
| 222 | } | |
| 223 | ||
| 224 | fn testPointerAlign() !void { | |
| 225 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 226 | var pointer: [*]align(4) u8 = &array; | |
| 227 | var slice = pointer[4..5]; | |
| 228 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 229 | try expect(slice[0] == 5); | |
| 230 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | |
| 231 | } | |
| 232 | ||
| 233 | fn testSlice() !void { | |
| 234 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 235 | var src_slice: []u8 = &array; | |
| 236 | var slice = src_slice[1..3]; | |
| 237 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 238 | try expect(slice[0] == 2); | |
| 239 | try expect(slice[1] == 3); | |
| 240 | } | |
| 241 | ||
| 242 | fn testSliceZ() !void { | |
| 243 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 244 | var slice: [:0]u8 = &array; | |
| 245 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | |
| 246 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | |
| 247 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | |
| 248 | } | |
| 249 | ||
| 250 | fn testSliceOpt() !void { | |
| 251 | var array: [2]u8 = [2]u8{ 1, 2 }; | |
| 252 | var slice: ?[]u8 = &array; | |
| 253 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | |
| 254 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | |
| 255 | } | |
| 256 | ||
| 257 | fn testSlice0() !void { | |
| 258 | { | |
| 259 | var array = [0]u8{}; | |
| 260 | var src_slice: []u8 = &array; | |
| 261 | var slice = src_slice[0..0]; | |
| 262 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 263 | } | |
| 264 | { | |
| 265 | var array = [0:0]u8{}; | |
| 266 | var src_slice: [:0]u8 = &array; | |
| 267 | var slice = src_slice[0..0]; | |
| 268 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 269 | } | |
| 270 | } | |
| 271 | ||
| 272 | fn testSliceAlign() !void { | |
| 273 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 274 | var src_slice: []align(4) u8 = &array; | |
| 275 | var slice = src_slice[4..5]; | |
| 276 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 277 | try expect(slice[0] == 5); | |
| 278 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | |
| 279 | } | |
| 280 | ||
| 281 | fn testConcatStrLiterals() !void { | |
| 282 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | |
| 283 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | |
| 284 | } | |
| 285 | }; | |
| 286 | ||
| 287 | try S.doTheTest(); | |
| 288 | comptime try S.doTheTest(); | |
| 289 | } | |
| 290 | ||
| 291 | test "slice of hardcoded address to pointer" { | |
| 292 | const S = struct { | |
| 293 | fn doTheTest() !void { | |
| 294 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | |
| 295 | comptime try expect(@TypeOf(pointer) == *[2]u8); | |
| 296 | const slice: []const u8 = pointer; | |
| 297 | try expect(@ptrToInt(slice.ptr) == 4); | |
| 298 | try expect(slice.len == 2); | |
| 299 | } | |
| 300 | }; | |
| 301 | ||
| 302 | try S.doTheTest(); | |
| 303 | } | |
| 304 | ||
| 305 | test "type coercion of pointer to anon struct literal to pointer to slice" { | |
| 306 | const S = struct { | |
| 307 | const U = union { | |
| 308 | a: u32, | |
| 309 | b: bool, | |
| 310 | c: []const u8, | |
| 311 | }; | |
| 312 | ||
| 313 | fn doTheTest() !void { | |
| 314 | var x1: u8 = 42; | |
| 315 | const t1 = &.{ x1, 56, 54 }; | |
| 316 | var slice1: []const u8 = t1; | |
| 317 | try expect(slice1.len == 3); | |
| 318 | try expect(slice1[0] == 42); | |
| 319 | try expect(slice1[1] == 56); | |
| 320 | try expect(slice1[2] == 54); | |
| 321 | ||
| 322 | var x2: []const u8 = "hello"; | |
| 323 | const t2 = &.{ x2, ", ", "world!" }; | |
| 324 | // @compileLog(@TypeOf(t2)); | |
| 325 | var slice2: []const []const u8 = t2; | |
| 326 | try expect(slice2.len == 3); | |
| 327 | try expect(mem.eql(u8, slice2[0], "hello")); | |
| 328 | try expect(mem.eql(u8, slice2[1], ", ")); | |
| 329 | try expect(mem.eql(u8, slice2[2], "world!")); | |
| 330 | } | |
| 331 | }; | |
| 332 | // try S.doTheTest(); | |
| 333 | comptime try S.doTheTest(); | |
| 334 | } |