| 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,29 +1340,50 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1340 | const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); | 1340 | const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); |
| 1341 | const ptr = sema.resolveInst(bin_inst.rhs); | 1341 | const ptr = sema.resolveInst(bin_inst.rhs); |
| 1342 | 1342 | ||
| 1343 | // Create a runtime bitcast instruction with exactly the type the pointer wants. | ||
| 1344 | const ptr_ty = try Type.ptr(sema.arena, .{ | 1343 | const ptr_ty = try Type.ptr(sema.arena, .{ |
| 1345 | .pointee_type = pointee_ty, | 1344 | .pointee_type = pointee_ty, |
| 1346 | .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), | 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 | if (Air.refToIndex(ptr)) |ptr_inst| { | 1348 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 1352 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { | 1349 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { |
| 1353 | const air_datas = sema.air_instructions.items(.data); | 1350 | const air_datas = sema.air_instructions.items(.data); |
| 1354 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; | 1351 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 1355 | if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { | 1352 | switch (ptr_val.tag()) { |
| 1356 | // Add the stored instruction to the set we will use to resolve peer types | 1353 | .inferred_alloc => { |
| 1357 | // for the inferred allocation. | 1354 | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; |
| 1358 | // This instruction will not make it to codegen; it is only to participate | 1355 | // Add the stored instruction to the set we will use to resolve peer types |
| 1359 | // in the `stored_inst_list` of the `inferred_alloc`. | 1356 | // for the inferred allocation. |
| 1360 | const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); | 1357 | // This instruction will not make it to codegen; it is only to participate |
| 1361 | try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); | 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 | return bitcasted_ptr; | 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,6 +2017,9 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 1996 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; | 2017 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; |
| 1997 | const var_decl_src = inst_data.src(); | 2018 | const var_decl_src = inst_data.src(); |
| 1998 | const var_type = try sema.resolveType(block, ty_src, inst_data.operand); | 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 | const ptr_type = try Type.ptr(sema.arena, .{ | 2023 | const ptr_type = try Type.ptr(sema.arena, .{ |
| 2000 | .pointee_type = var_type, | 2024 | .pointee_type = var_type, |
| 2001 | .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), | 2025 | .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), |
| ... | @@ -13418,9 +13442,10 @@ fn analyzeComptimeAlloc( | ... | @@ -13418,9 +13442,10 @@ fn analyzeComptimeAlloc( |
| 13418 | defer anon_decl.deinit(); | 13442 | defer anon_decl.deinit(); |
| 13419 | const decl = try anon_decl.finish( | 13443 | const decl = try anon_decl.finish( |
| 13420 | try var_type.copy(anon_decl.arena()), | 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 | 13445 | // There will be stores before the first load, but they may be to sub-elements or |
| 13422 | // here indicating there is no valid value. | 13446 | // sub-fields. So we need to initialize with undef to allow the mechanism to expand |
| 13423 | Value.initTag(.unreachable_value), | 13447 | // into fields/elements and have those overridden with stored values. |
| 13448 | Value.undef, | ||
| 13424 | ); | 13449 | ); |
| 13425 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); | 13450 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 13426 | return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ | 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,6 +26,7 @@ test { |
| 26 | _ = @import("behavior/math.zig"); | 26 | _ = @import("behavior/math.zig"); |
| 27 | _ = @import("behavior/member_func.zig"); | 27 | _ = @import("behavior/member_func.zig"); |
| 28 | _ = @import("behavior/pointers.zig"); | 28 | _ = @import("behavior/pointers.zig"); |
| 29 | _ = @import("behavior/slice.zig"); | ||
| 29 | _ = @import("behavior/sizeof_and_typeof.zig"); | 30 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 30 | _ = @import("behavior/struct.zig"); | 31 | _ = @import("behavior/struct.zig"); |
| 31 | _ = @import("behavior/switch.zig"); | 32 | _ = @import("behavior/switch.zig"); |
| ... | @@ -150,7 +151,7 @@ test { | ... | @@ -150,7 +151,7 @@ test { |
| 150 | _ = @import("behavior/shuffle.zig"); | 151 | _ = @import("behavior/shuffle.zig"); |
| 151 | _ = @import("behavior/select.zig"); | 152 | _ = @import("behavior/select.zig"); |
| 152 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); | 153 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); |
| 153 | _ = @import("behavior/slice.zig"); | 154 | _ = @import("behavior/slice_stage1.zig"); |
| 154 | _ = @import("behavior/slice_sentinel_comptime.zig"); | 155 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 155 | _ = @import("behavior/struct_stage1.zig"); | 156 | _ = @import("behavior/struct_stage1.zig"); |
| 156 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | 157 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
test/behavior/slice.zig-333| ... | @@ -3,336 +3,3 @@ const expect = std.testing.expect; | ... | @@ -3,336 +3,3 @@ const expect = std.testing.expect; |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | 3 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | const mem = std.mem; | 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 | } | ||