| author | |
| committer | |
| log | 95fbce2b958395a367a82ce33170edd93e686173 |
| tree | dae1e68036754591c53b71571d5b12b3b2f33539 |
| parent | 64f7231f86d4b8a155f48087b3f173d8e41b620c |
fieldVal handles pointer to pointer to array. This can happen for
example, if a pointer to an array is used as the condition expression of
a for loop.
resolveStructFully handles tuples (by doing nothing).
fixed Type comparison for tuples to handle comptime fields properly.5 files changed, 405 insertions(+), 371 deletions(-)
src/Sema.zig+40-22| ... | ... | @@ -12998,7 +12998,7 @@ fn fieldVal( |
| 12998 | 12998 | .Array => { |
| 12999 | 12999 | if (mem.eql(u8, field_name, "len")) { |
| 13000 | 13000 | return sema.addConstant( |
| 13001 | Type.initTag(.comptime_int), | |
| 13001 | Type.comptime_int, | |
| 13002 | 13002 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), |
| 13003 | 13003 | ); |
| 13004 | 13004 | } else { |
| ... | ... | @@ -13010,26 +13010,43 @@ fn fieldVal( |
| 13010 | 13010 | ); |
| 13011 | 13011 | } |
| 13012 | 13012 | }, |
| 13013 | .Pointer => if (inner_ty.isSlice()) { | |
| 13014 | if (mem.eql(u8, field_name, "ptr")) { | |
| 13015 | const slice = if (is_pointer_to) | |
| 13016 | try sema.analyzeLoad(block, src, object, object_src) | |
| 13017 | else | |
| 13018 | object; | |
| 13019 | return sema.analyzeSlicePtr(block, src, slice, inner_ty, object_src); | |
| 13020 | } else if (mem.eql(u8, field_name, "len")) { | |
| 13021 | const slice = if (is_pointer_to) | |
| 13022 | try sema.analyzeLoad(block, src, object, object_src) | |
| 13023 | else | |
| 13024 | object; | |
| 13025 | return sema.analyzeSliceLen(block, src, slice); | |
| 13026 | } else { | |
| 13027 | return sema.fail( | |
| 13028 | block, | |
| 13029 | field_name_src, | |
| 13030 | "no member named '{s}' in '{}'", | |
| 13031 | .{ field_name, object_ty }, | |
| 13032 | ); | |
| 13013 | .Pointer => { | |
| 13014 | const ptr_info = inner_ty.ptrInfo().data; | |
| 13015 | if (ptr_info.size == .Slice) { | |
| 13016 | if (mem.eql(u8, field_name, "ptr")) { | |
| 13017 | const slice = if (is_pointer_to) | |
| 13018 | try sema.analyzeLoad(block, src, object, object_src) | |
| 13019 | else | |
| 13020 | object; | |
| 13021 | return sema.analyzeSlicePtr(block, src, slice, inner_ty, object_src); | |
| 13022 | } else if (mem.eql(u8, field_name, "len")) { | |
| 13023 | const slice = if (is_pointer_to) | |
| 13024 | try sema.analyzeLoad(block, src, object, object_src) | |
| 13025 | else | |
| 13026 | object; | |
| 13027 | return sema.analyzeSliceLen(block, src, slice); | |
| 13028 | } else { | |
| 13029 | return sema.fail( | |
| 13030 | block, | |
| 13031 | field_name_src, | |
| 13032 | "no member named '{s}' in '{}'", | |
| 13033 | .{ field_name, object_ty }, | |
| 13034 | ); | |
| 13035 | } | |
| 13036 | } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { | |
| 13037 | if (mem.eql(u8, field_name, "len")) { | |
| 13038 | return sema.addConstant( | |
| 13039 | Type.comptime_int, | |
| 13040 | try Value.Tag.int_u64.create(arena, ptr_info.pointee_type.arrayLen()), | |
| 13041 | ); | |
| 13042 | } else { | |
| 13043 | return sema.fail( | |
| 13044 | block, | |
| 13045 | field_name_src, | |
| 13046 | "no member named '{s}' in '{}'", | |
| 13047 | .{ field_name, ptr_info.pointee_type }, | |
| 13048 | ); | |
| 13049 | } | |
| 13033 | 13050 | } |
| 13034 | 13051 | }, |
| 13035 | 13052 | .Type => { |
| ... | ... | @@ -16371,7 +16388,8 @@ fn resolveStructFully( |
| 16371 | 16388 | try resolveStructLayout(sema, block, src, ty); |
| 16372 | 16389 | |
| 16373 | 16390 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 16374 | const struct_obj = resolved_ty.castTag(.@"struct").?.data; | |
| 16391 | const payload = resolved_ty.castTag(.@"struct") orelse return; | |
| 16392 | const struct_obj = payload.data; | |
| 16375 | 16393 | switch (struct_obj.status) { |
| 16376 | 16394 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| 16377 | 16395 | .fully_resolved_wip, .fully_resolved => return, |
src/type.zig+13-1| ... | ... | @@ -634,7 +634,19 @@ pub const Type = extern union { |
| 634 | 634 | for (a_payload.data.values) |a_val, i| { |
| 635 | 635 | const ty = a_payload.data.types[i]; |
| 636 | 636 | const b_val = b_payload.data.values[i]; |
| 637 | if (!Value.eql(a_val, b_val, ty)) return false; | |
| 637 | if (a_val.tag() == .unreachable_value) { | |
| 638 | if (b_val.tag() == .unreachable_value) { | |
| 639 | continue; | |
| 640 | } else { | |
| 641 | return false; | |
| 642 | } | |
| 643 | } else { | |
| 644 | if (b_val.tag() == .unreachable_value) { | |
| 645 | return false; | |
| 646 | } else { | |
| 647 | if (!Value.eql(a_val, b_val, ty)) return false; | |
| 648 | } | |
| 649 | } | |
| 638 | 650 | } |
| 639 | 651 | |
| 640 | 652 | return true; |
test/behavior.zig-1| ... | ... | @@ -163,7 +163,6 @@ test { |
| 163 | 163 | _ = @import("behavior/select.zig"); |
| 164 | 164 | _ = @import("behavior/shuffle.zig"); |
| 165 | 165 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); |
| 166 | _ = @import("behavior/slice_stage1.zig"); | |
| 167 | 166 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 168 | 167 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); |
| 169 | 168 | _ = @import("behavior/switch_prong_err_enum.zig"); |
test/behavior/slice.zig+352| ... | ... | @@ -204,3 +204,355 @@ test "slice string literal has correct type" { |
| 204 | 204 | const array = [_]i32{ 1, 2, 3, 4 }; |
| 205 | 205 | comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); |
| 206 | 206 | } |
| 207 | ||
| 208 | test "result location zero sized array inside struct field implicit cast to slice" { | |
| 209 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 210 | ||
| 211 | const E = struct { | |
| 212 | entries: []u32, | |
| 213 | }; | |
| 214 | var foo = E{ .entries = &[_]u32{} }; | |
| 215 | try expect(foo.entries.len == 0); | |
| 216 | } | |
| 217 | ||
| 218 | test "runtime safety lets us slice from len..len" { | |
| 219 | var an_array = [_]u8{ 1, 2, 3 }; | |
| 220 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | |
| 221 | } | |
| 222 | ||
| 223 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | |
| 224 | return a_slice[start..end]; | |
| 225 | } | |
| 226 | ||
| 227 | test "C pointer" { | |
| 228 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | |
| 229 | var len: u32 = 10; | |
| 230 | var slice = buf[0..len]; | |
| 231 | try expect(mem.eql(u8, "kjdhfkjdhf", slice)); | |
| 232 | } | |
| 233 | ||
| 234 | test "C pointer slice access" { | |
| 235 | var buf: [10]u32 = [1]u32{42} ** 10; | |
| 236 | const c_ptr = @ptrCast([*c]const u32, &buf); | |
| 237 | ||
| 238 | var runtime_zero: usize = 0; | |
| 239 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | |
| 240 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | |
| 241 | ||
| 242 | for (c_ptr[0..5]) |*cl| { | |
| 243 | try expect(@as(u32, 42) == cl.*); | |
| 244 | } | |
| 245 | } | |
| 246 | ||
| 247 | test "comptime slices are disambiguated" { | |
| 248 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 249 | ||
| 250 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | |
| 251 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | |
| 252 | } | |
| 253 | ||
| 254 | fn sliceSum(comptime q: []const u8) i32 { | |
| 255 | comptime var result = 0; | |
| 256 | inline for (q) |item| { | |
| 257 | result += item; | |
| 258 | } | |
| 259 | return result; | |
| 260 | } | |
| 261 | ||
| 262 | test "slice type with custom alignment" { | |
| 263 | const LazilyResolvedType = struct { | |
| 264 | anything: i32, | |
| 265 | }; | |
| 266 | var slice: []align(32) LazilyResolvedType = undefined; | |
| 267 | var array: [10]LazilyResolvedType align(32) = undefined; | |
| 268 | slice = &array; | |
| 269 | slice[1].anything = 42; | |
| 270 | try expect(array[1].anything == 42); | |
| 271 | } | |
| 272 | ||
| 273 | test "obtaining a null terminated slice" { | |
| 274 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 275 | ||
| 276 | // here we have a normal array | |
| 277 | var buf: [50]u8 = undefined; | |
| 278 | ||
| 279 | buf[0] = 'a'; | |
| 280 | buf[1] = 'b'; | |
| 281 | buf[2] = 'c'; | |
| 282 | buf[3] = 0; | |
| 283 | ||
| 284 | // now we obtain a null terminated slice: | |
| 285 | const ptr = buf[0..3 :0]; | |
| 286 | _ = ptr; | |
| 287 | ||
| 288 | var runtime_len: usize = 3; | |
| 289 | const ptr2 = buf[0..runtime_len :0]; | |
| 290 | // ptr2 is a null-terminated slice | |
| 291 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | |
| 292 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | |
| 293 | var runtime_zero: usize = 0; | |
| 294 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | |
| 295 | } | |
| 296 | ||
| 297 | test "empty array to slice" { | |
| 298 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 299 | ||
| 300 | const S = struct { | |
| 301 | fn doTheTest() !void { | |
| 302 | const empty: []align(16) u8 = &[_]u8{}; | |
| 303 | const align_1: []align(1) u8 = empty; | |
| 304 | const align_4: []align(4) u8 = empty; | |
| 305 | const align_16: []align(16) u8 = empty; | |
| 306 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | |
| 307 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | |
| 308 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | |
| 309 | } | |
| 310 | }; | |
| 311 | ||
| 312 | try S.doTheTest(); | |
| 313 | comptime try S.doTheTest(); | |
| 314 | } | |
| 315 | ||
| 316 | test "@ptrCast slice to pointer" { | |
| 317 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 318 | ||
| 319 | const S = struct { | |
| 320 | fn doTheTest() !void { | |
| 321 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | |
| 322 | var slice: []u8 = &array; | |
| 323 | var ptr = @ptrCast(*u16, slice); | |
| 324 | try expect(ptr.* == 65535); | |
| 325 | } | |
| 326 | }; | |
| 327 | ||
| 328 | try S.doTheTest(); | |
| 329 | comptime try S.doTheTest(); | |
| 330 | } | |
| 331 | ||
| 332 | test "slice syntax resulting in pointer-to-array" { | |
| 333 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 334 | ||
| 335 | const S = struct { | |
| 336 | fn doTheTest() !void { | |
| 337 | try testArray(); | |
| 338 | try testArrayZ(); | |
| 339 | try testArray0(); | |
| 340 | try testArrayAlign(); | |
| 341 | try testPointer(); | |
| 342 | try testPointerZ(); | |
| 343 | try testPointer0(); | |
| 344 | try testPointerAlign(); | |
| 345 | try testSlice(); | |
| 346 | try testSliceZ(); | |
| 347 | try testSlice0(); | |
| 348 | try testSliceOpt(); | |
| 349 | try testSliceAlign(); | |
| 350 | } | |
| 351 | ||
| 352 | fn testArray() !void { | |
| 353 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 354 | var slice = array[1..3]; | |
| 355 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 356 | try expect(slice[0] == 2); | |
| 357 | try expect(slice[1] == 3); | |
| 358 | } | |
| 359 | ||
| 360 | fn testArrayZ() !void { | |
| 361 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 362 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | |
| 363 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | |
| 364 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | |
| 365 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | |
| 366 | } | |
| 367 | ||
| 368 | fn testArray0() !void { | |
| 369 | { | |
| 370 | var array = [0]u8{}; | |
| 371 | var slice = array[0..0]; | |
| 372 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 373 | } | |
| 374 | { | |
| 375 | var array = [0:0]u8{}; | |
| 376 | var slice = array[0..0]; | |
| 377 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | |
| 378 | try expect(slice[0] == 0); | |
| 379 | } | |
| 380 | } | |
| 381 | ||
| 382 | fn testArrayAlign() !void { | |
| 383 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 384 | var slice = array[4..5]; | |
| 385 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 386 | try expect(slice[0] == 5); | |
| 387 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | |
| 388 | } | |
| 389 | ||
| 390 | fn testPointer() !void { | |
| 391 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 392 | var pointer: [*]u8 = &array; | |
| 393 | var slice = pointer[1..3]; | |
| 394 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 395 | try expect(slice[0] == 2); | |
| 396 | try expect(slice[1] == 3); | |
| 397 | } | |
| 398 | ||
| 399 | fn testPointerZ() !void { | |
| 400 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 401 | var pointer: [*:0]u8 = &array; | |
| 402 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | |
| 403 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | |
| 404 | } | |
| 405 | ||
| 406 | fn testPointer0() !void { | |
| 407 | var pointer: [*]const u0 = &[1]u0{0}; | |
| 408 | var slice = pointer[0..1]; | |
| 409 | comptime try expect(@TypeOf(slice) == *const [1]u0); | |
| 410 | try expect(slice[0] == 0); | |
| 411 | } | |
| 412 | ||
| 413 | fn testPointerAlign() !void { | |
| 414 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 415 | var pointer: [*]align(4) u8 = &array; | |
| 416 | var slice = pointer[4..5]; | |
| 417 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 418 | try expect(slice[0] == 5); | |
| 419 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | |
| 420 | } | |
| 421 | ||
| 422 | fn testSlice() !void { | |
| 423 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 424 | var src_slice: []u8 = &array; | |
| 425 | var slice = src_slice[1..3]; | |
| 426 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 427 | try expect(slice[0] == 2); | |
| 428 | try expect(slice[1] == 3); | |
| 429 | } | |
| 430 | ||
| 431 | fn testSliceZ() !void { | |
| 432 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 433 | var slice: [:0]u8 = &array; | |
| 434 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | |
| 435 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | |
| 436 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | |
| 437 | } | |
| 438 | ||
| 439 | fn testSliceOpt() !void { | |
| 440 | var array: [2]u8 = [2]u8{ 1, 2 }; | |
| 441 | var slice: ?[]u8 = &array; | |
| 442 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | |
| 443 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | |
| 444 | } | |
| 445 | ||
| 446 | fn testSlice0() !void { | |
| 447 | { | |
| 448 | var array = [0]u8{}; | |
| 449 | var src_slice: []u8 = &array; | |
| 450 | var slice = src_slice[0..0]; | |
| 451 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 452 | } | |
| 453 | { | |
| 454 | var array = [0:0]u8{}; | |
| 455 | var src_slice: [:0]u8 = &array; | |
| 456 | var slice = src_slice[0..0]; | |
| 457 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 458 | } | |
| 459 | } | |
| 460 | ||
| 461 | fn testSliceAlign() !void { | |
| 462 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 463 | var src_slice: []align(4) u8 = &array; | |
| 464 | var slice = src_slice[4..5]; | |
| 465 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 466 | try expect(slice[0] == 5); | |
| 467 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | |
| 468 | } | |
| 469 | ||
| 470 | fn testConcatStrLiterals() !void { | |
| 471 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | |
| 472 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | |
| 473 | } | |
| 474 | }; | |
| 475 | ||
| 476 | try S.doTheTest(); | |
| 477 | comptime try S.doTheTest(); | |
| 478 | } | |
| 479 | ||
| 480 | test "type coercion of pointer to anon struct literal to pointer to slice" { | |
| 481 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 482 | ||
| 483 | const S = struct { | |
| 484 | const U = union { | |
| 485 | a: u32, | |
| 486 | b: bool, | |
| 487 | c: []const u8, | |
| 488 | }; | |
| 489 | ||
| 490 | fn doTheTest() !void { | |
| 491 | var x1: u8 = 42; | |
| 492 | const t1 = &.{ x1, 56, 54 }; | |
| 493 | var slice1: []const u8 = t1; | |
| 494 | try expect(slice1.len == 3); | |
| 495 | try expect(slice1[0] == 42); | |
| 496 | try expect(slice1[1] == 56); | |
| 497 | try expect(slice1[2] == 54); | |
| 498 | ||
| 499 | var x2: []const u8 = "hello"; | |
| 500 | const t2 = &.{ x2, ", ", "world!" }; | |
| 501 | // @compileLog(@TypeOf(t2)); | |
| 502 | var slice2: []const []const u8 = t2; | |
| 503 | try expect(slice2.len == 3); | |
| 504 | try expect(mem.eql(u8, slice2[0], "hello")); | |
| 505 | try expect(mem.eql(u8, slice2[1], ", ")); | |
| 506 | try expect(mem.eql(u8, slice2[2], "world!")); | |
| 507 | } | |
| 508 | }; | |
| 509 | // try S.doTheTest(); | |
| 510 | comptime try S.doTheTest(); | |
| 511 | } | |
| 512 | ||
| 513 | test "array concat of slices gives slice" { | |
| 514 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 515 | ||
| 516 | comptime { | |
| 517 | var a: []const u8 = "aoeu"; | |
| 518 | var b: []const u8 = "asdf"; | |
| 519 | const c = a ++ b; | |
| 520 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | test "slice bounds in comptime concatenation" { | |
| 525 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 526 | ||
| 527 | const bs = comptime blk: { | |
| 528 | const b = "........1........"; | |
| 529 | break :blk b[8..9]; | |
| 530 | }; | |
| 531 | const str = "" ++ bs; | |
| 532 | try expect(str.len == 1); | |
| 533 | try expect(std.mem.eql(u8, str, "1")); | |
| 534 | ||
| 535 | const str2 = bs ++ ""; | |
| 536 | try expect(str2.len == 1); | |
| 537 | try expect(std.mem.eql(u8, str2, "1")); | |
| 538 | } | |
| 539 | ||
| 540 | test "slice sentinel access at comptime" { | |
| 541 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 542 | ||
| 543 | { | |
| 544 | const str0 = &[_:0]u8{ '1', '2', '3' }; | |
| 545 | const slice0: [:0]const u8 = str0; | |
| 546 | ||
| 547 | try expect(slice0.len == 3); | |
| 548 | try expect(slice0[slice0.len] == 0); | |
| 549 | } | |
| 550 | { | |
| 551 | const str0 = "123"; | |
| 552 | _ = &str0[0]; | |
| 553 | const slice0: [:0]const u8 = str0; | |
| 554 | ||
| 555 | try expect(slice0.len == 3); | |
| 556 | try expect(slice0[slice0.len] == 0); | |
| 557 | } | |
| 558 | } |
test/behavior/slice_stage1.zig deleted-347| ... | ... | @@ -1,347 +0,0 @@ |
| 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 | test "result location zero sized array inside struct field implicit cast to slice" { | |
| 8 | const E = struct { | |
| 9 | entries: []u32, | |
| 10 | }; | |
| 11 | var foo = E{ .entries = &[_]u32{} }; | |
| 12 | try expect(foo.entries.len == 0); | |
| 13 | } | |
| 14 | ||
| 15 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | |
| 16 | const y = x[0x100..]; | |
| 17 | test "compile time slice of pointer to hard coded address" { | |
| 18 | try expect(@ptrToInt(x) == 0x1000); | |
| 19 | try expect(x.len == 0x500); | |
| 20 | ||
| 21 | try expect(@ptrToInt(y) == 0x1100); | |
| 22 | try expect(y.len == 0x400); | |
| 23 | } | |
| 24 | ||
| 25 | test "runtime safety lets us slice from len..len" { | |
| 26 | var an_array = [_]u8{ 1, 2, 3 }; | |
| 27 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | |
| 28 | } | |
| 29 | ||
| 30 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | |
| 31 | return a_slice[start..end]; | |
| 32 | } | |
| 33 | ||
| 34 | test "C pointer" { | |
| 35 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | |
| 36 | var len: u32 = 10; | |
| 37 | var slice = buf[0..len]; | |
| 38 | try expectEqualSlices(u8, "kjdhfkjdhf", slice); | |
| 39 | } | |
| 40 | ||
| 41 | test "C pointer slice access" { | |
| 42 | var buf: [10]u32 = [1]u32{42} ** 10; | |
| 43 | const c_ptr = @ptrCast([*c]const u32, &buf); | |
| 44 | ||
| 45 | var runtime_zero: usize = 0; | |
| 46 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | |
| 47 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | |
| 48 | ||
| 49 | for (c_ptr[0..5]) |*cl| { | |
| 50 | try expectEqual(@as(u32, 42), cl.*); | |
| 51 | } | |
| 52 | } | |
| 53 | ||
| 54 | fn sliceSum(comptime q: []const u8) i32 { | |
| 55 | comptime var result = 0; | |
| 56 | inline for (q) |item| { | |
| 57 | result += item; | |
| 58 | } | |
| 59 | return result; | |
| 60 | } | |
| 61 | ||
| 62 | test "comptime slices are disambiguated" { | |
| 63 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | |
| 64 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | |
| 65 | } | |
| 66 | ||
| 67 | test "slice type with custom alignment" { | |
| 68 | const LazilyResolvedType = struct { | |
| 69 | anything: i32, | |
| 70 | }; | |
| 71 | var slice: []align(32) LazilyResolvedType = undefined; | |
| 72 | var array: [10]LazilyResolvedType align(32) = undefined; | |
| 73 | slice = &array; | |
| 74 | slice[1].anything = 42; | |
| 75 | try expect(array[1].anything == 42); | |
| 76 | } | |
| 77 | ||
| 78 | test "obtaining a null terminated slice" { | |
| 79 | // here we have a normal array | |
| 80 | var buf: [50]u8 = undefined; | |
| 81 | ||
| 82 | buf[0] = 'a'; | |
| 83 | buf[1] = 'b'; | |
| 84 | buf[2] = 'c'; | |
| 85 | buf[3] = 0; | |
| 86 | ||
| 87 | // now we obtain a null terminated slice: | |
| 88 | const ptr = buf[0..3 :0]; | |
| 89 | _ = ptr; | |
| 90 | ||
| 91 | var runtime_len: usize = 3; | |
| 92 | const ptr2 = buf[0..runtime_len :0]; | |
| 93 | // ptr2 is a null-terminated slice | |
| 94 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | |
| 95 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | |
| 96 | var runtime_zero: usize = 0; | |
| 97 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | |
| 98 | } | |
| 99 | ||
| 100 | test "empty array to slice" { | |
| 101 | const S = struct { | |
| 102 | fn doTheTest() !void { | |
| 103 | const empty: []align(16) u8 = &[_]u8{}; | |
| 104 | const align_1: []align(1) u8 = empty; | |
| 105 | const align_4: []align(4) u8 = empty; | |
| 106 | const align_16: []align(16) u8 = empty; | |
| 107 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | |
| 108 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | |
| 109 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | |
| 110 | } | |
| 111 | }; | |
| 112 | ||
| 113 | try S.doTheTest(); | |
| 114 | comptime try S.doTheTest(); | |
| 115 | } | |
| 116 | ||
| 117 | test "@ptrCast slice to pointer" { | |
| 118 | const S = struct { | |
| 119 | fn doTheTest() !void { | |
| 120 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | |
| 121 | var slice: []u8 = &array; | |
| 122 | var ptr = @ptrCast(*u16, slice); | |
| 123 | try expect(ptr.* == 65535); | |
| 124 | } | |
| 125 | }; | |
| 126 | ||
| 127 | try S.doTheTest(); | |
| 128 | comptime try S.doTheTest(); | |
| 129 | } | |
| 130 | ||
| 131 | test "slice syntax resulting in pointer-to-array" { | |
| 132 | const S = struct { | |
| 133 | fn doTheTest() !void { | |
| 134 | try testArray(); | |
| 135 | try testArrayZ(); | |
| 136 | try testArray0(); | |
| 137 | try testArrayAlign(); | |
| 138 | try testPointer(); | |
| 139 | try testPointerZ(); | |
| 140 | try testPointer0(); | |
| 141 | try testPointerAlign(); | |
| 142 | try testSlice(); | |
| 143 | try testSliceZ(); | |
| 144 | try testSlice0(); | |
| 145 | try testSliceOpt(); | |
| 146 | try testSliceAlign(); | |
| 147 | } | |
| 148 | ||
| 149 | fn testArray() !void { | |
| 150 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 151 | var slice = array[1..3]; | |
| 152 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 153 | try expect(slice[0] == 2); | |
| 154 | try expect(slice[1] == 3); | |
| 155 | } | |
| 156 | ||
| 157 | fn testArrayZ() !void { | |
| 158 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 159 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | |
| 160 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | |
| 161 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | |
| 162 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | |
| 163 | } | |
| 164 | ||
| 165 | fn testArray0() !void { | |
| 166 | { | |
| 167 | var array = [0]u8{}; | |
| 168 | var slice = array[0..0]; | |
| 169 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 170 | } | |
| 171 | { | |
| 172 | var array = [0:0]u8{}; | |
| 173 | var slice = array[0..0]; | |
| 174 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | |
| 175 | try expect(slice[0] == 0); | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | fn testArrayAlign() !void { | |
| 180 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 181 | var slice = array[4..5]; | |
| 182 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 183 | try expect(slice[0] == 5); | |
| 184 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | |
| 185 | } | |
| 186 | ||
| 187 | fn testPointer() !void { | |
| 188 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 189 | var pointer: [*]u8 = &array; | |
| 190 | var slice = pointer[1..3]; | |
| 191 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 192 | try expect(slice[0] == 2); | |
| 193 | try expect(slice[1] == 3); | |
| 194 | } | |
| 195 | ||
| 196 | fn testPointerZ() !void { | |
| 197 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 198 | var pointer: [*:0]u8 = &array; | |
| 199 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | |
| 200 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | |
| 201 | } | |
| 202 | ||
| 203 | fn testPointer0() !void { | |
| 204 | var pointer: [*]const u0 = &[1]u0{0}; | |
| 205 | var slice = pointer[0..1]; | |
| 206 | comptime try expect(@TypeOf(slice) == *const [1]u0); | |
| 207 | try expect(slice[0] == 0); | |
| 208 | } | |
| 209 | ||
| 210 | fn testPointerAlign() !void { | |
| 211 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 212 | var pointer: [*]align(4) u8 = &array; | |
| 213 | var slice = pointer[4..5]; | |
| 214 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 215 | try expect(slice[0] == 5); | |
| 216 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | |
| 217 | } | |
| 218 | ||
| 219 | fn testSlice() !void { | |
| 220 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 221 | var src_slice: []u8 = &array; | |
| 222 | var slice = src_slice[1..3]; | |
| 223 | comptime try expect(@TypeOf(slice) == *[2]u8); | |
| 224 | try expect(slice[0] == 2); | |
| 225 | try expect(slice[1] == 3); | |
| 226 | } | |
| 227 | ||
| 228 | fn testSliceZ() !void { | |
| 229 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | |
| 230 | var slice: [:0]u8 = &array; | |
| 231 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | |
| 232 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | |
| 233 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | |
| 234 | } | |
| 235 | ||
| 236 | fn testSliceOpt() !void { | |
| 237 | var array: [2]u8 = [2]u8{ 1, 2 }; | |
| 238 | var slice: ?[]u8 = &array; | |
| 239 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | |
| 240 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | |
| 241 | } | |
| 242 | ||
| 243 | fn testSlice0() !void { | |
| 244 | { | |
| 245 | var array = [0]u8{}; | |
| 246 | var src_slice: []u8 = &array; | |
| 247 | var slice = src_slice[0..0]; | |
| 248 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 249 | } | |
| 250 | { | |
| 251 | var array = [0:0]u8{}; | |
| 252 | var src_slice: [:0]u8 = &array; | |
| 253 | var slice = src_slice[0..0]; | |
| 254 | comptime try expect(@TypeOf(slice) == *[0]u8); | |
| 255 | } | |
| 256 | } | |
| 257 | ||
| 258 | fn testSliceAlign() !void { | |
| 259 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | |
| 260 | var src_slice: []align(4) u8 = &array; | |
| 261 | var slice = src_slice[4..5]; | |
| 262 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | |
| 263 | try expect(slice[0] == 5); | |
| 264 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | |
| 265 | } | |
| 266 | ||
| 267 | fn testConcatStrLiterals() !void { | |
| 268 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | |
| 269 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | |
| 270 | } | |
| 271 | }; | |
| 272 | ||
| 273 | try S.doTheTest(); | |
| 274 | comptime try S.doTheTest(); | |
| 275 | } | |
| 276 | ||
| 277 | test "type coercion of pointer to anon struct literal to pointer to slice" { | |
| 278 | const S = struct { | |
| 279 | const U = union { | |
| 280 | a: u32, | |
| 281 | b: bool, | |
| 282 | c: []const u8, | |
| 283 | }; | |
| 284 | ||
| 285 | fn doTheTest() !void { | |
| 286 | var x1: u8 = 42; | |
| 287 | const t1 = &.{ x1, 56, 54 }; | |
| 288 | var slice1: []const u8 = t1; | |
| 289 | try expect(slice1.len == 3); | |
| 290 | try expect(slice1[0] == 42); | |
| 291 | try expect(slice1[1] == 56); | |
| 292 | try expect(slice1[2] == 54); | |
| 293 | ||
| 294 | var x2: []const u8 = "hello"; | |
| 295 | const t2 = &.{ x2, ", ", "world!" }; | |
| 296 | // @compileLog(@TypeOf(t2)); | |
| 297 | var slice2: []const []const u8 = t2; | |
| 298 | try expect(slice2.len == 3); | |
| 299 | try expect(mem.eql(u8, slice2[0], "hello")); | |
| 300 | try expect(mem.eql(u8, slice2[1], ", ")); | |
| 301 | try expect(mem.eql(u8, slice2[2], "world!")); | |
| 302 | } | |
| 303 | }; | |
| 304 | // try S.doTheTest(); | |
| 305 | comptime try S.doTheTest(); | |
| 306 | } | |
| 307 | ||
| 308 | test "array concat of slices gives slice" { | |
| 309 | comptime { | |
| 310 | var a: []const u8 = "aoeu"; | |
| 311 | var b: []const u8 = "asdf"; | |
| 312 | const c = a ++ b; | |
| 313 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | |
| 314 | } | |
| 315 | } | |
| 316 | ||
| 317 | test "slice bounds in comptime concatenation" { | |
| 318 | const bs = comptime blk: { | |
| 319 | const b = "........1........"; | |
| 320 | break :blk b[8..9]; | |
| 321 | }; | |
| 322 | const str = "" ++ bs; | |
| 323 | try expect(str.len == 1); | |
| 324 | try expect(std.mem.eql(u8, str, "1")); | |
| 325 | ||
| 326 | const str2 = bs ++ ""; | |
| 327 | try expect(str2.len == 1); | |
| 328 | try expect(std.mem.eql(u8, str2, "1")); | |
| 329 | } | |
| 330 | ||
| 331 | test "slice sentinel access at comptime" { | |
| 332 | { | |
| 333 | const str0 = &[_:0]u8{ '1', '2', '3' }; | |
| 334 | const slice0: [:0]const u8 = str0; | |
| 335 | ||
| 336 | try expect(slice0.len == 3); | |
| 337 | try expect(slice0[slice0.len] == 0); | |
| 338 | } | |
| 339 | { | |
| 340 | const str0 = "123"; | |
| 341 | _ = &str0[0]; | |
| 342 | const slice0: [:0]const u8 = str0; | |
| 343 | ||
| 344 | try expect(slice0.len == 3); | |
| 345 | try expect(slice0[slice0.len] == 0); | |
| 346 | } | |
| 347 | } |