| 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,7 +12998,7 @@ fn fieldVal( |
| 12998 | .Array => { | 12998 | .Array => { |
| 12999 | if (mem.eql(u8, field_name, "len")) { | 12999 | if (mem.eql(u8, field_name, "len")) { |
| 13000 | return sema.addConstant( | 13000 | return sema.addConstant( |
| 13001 | Type.initTag(.comptime_int), | 13001 | Type.comptime_int, |
| 13002 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), | 13002 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), |
| 13003 | ); | 13003 | ); |
| 13004 | } else { | 13004 | } else { |
| ... | @@ -13010,26 +13010,43 @@ fn fieldVal( | ... | @@ -13010,26 +13010,43 @@ fn fieldVal( |
| 13010 | ); | 13010 | ); |
| 13011 | } | 13011 | } |
| 13012 | }, | 13012 | }, |
| 13013 | .Pointer => if (inner_ty.isSlice()) { | 13013 | .Pointer => { |
| 13014 | if (mem.eql(u8, field_name, "ptr")) { | 13014 | const ptr_info = inner_ty.ptrInfo().data; |
| 13015 | const slice = if (is_pointer_to) | 13015 | if (ptr_info.size == .Slice) { |
| 13016 | try sema.analyzeLoad(block, src, object, object_src) | 13016 | if (mem.eql(u8, field_name, "ptr")) { |
| 13017 | else | 13017 | const slice = if (is_pointer_to) |
| 13018 | object; | 13018 | try sema.analyzeLoad(block, src, object, object_src) |
| 13019 | return sema.analyzeSlicePtr(block, src, slice, inner_ty, object_src); | 13019 | else |
| 13020 | } else if (mem.eql(u8, field_name, "len")) { | 13020 | object; |
| 13021 | const slice = if (is_pointer_to) | 13021 | return sema.analyzeSlicePtr(block, src, slice, inner_ty, object_src); |
| 13022 | try sema.analyzeLoad(block, src, object, object_src) | 13022 | } else if (mem.eql(u8, field_name, "len")) { |
| 13023 | else | 13023 | const slice = if (is_pointer_to) |
| 13024 | object; | 13024 | try sema.analyzeLoad(block, src, object, object_src) |
| 13025 | return sema.analyzeSliceLen(block, src, slice); | 13025 | else |
| 13026 | } else { | 13026 | object; |
| 13027 | return sema.fail( | 13027 | return sema.analyzeSliceLen(block, src, slice); |
| 13028 | block, | 13028 | } else { |
| 13029 | field_name_src, | 13029 | return sema.fail( |
| 13030 | "no member named '{s}' in '{}'", | 13030 | block, |
| 13031 | .{ field_name, object_ty }, | 13031 | field_name_src, |
| 13032 | ); | 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 | .Type => { | 13052 | .Type => { |
| ... | @@ -16371,7 +16388,8 @@ fn resolveStructFully( | ... | @@ -16371,7 +16388,8 @@ fn resolveStructFully( |
| 16371 | try resolveStructLayout(sema, block, src, ty); | 16388 | try resolveStructLayout(sema, block, src, ty); |
| 16372 | 16389 | ||
| 16373 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | 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 | switch (struct_obj.status) { | 16393 | switch (struct_obj.status) { |
| 16376 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | 16394 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| 16377 | .fully_resolved_wip, .fully_resolved => return, | 16395 | .fully_resolved_wip, .fully_resolved => return, |
src/type.zig+13-1| ... | @@ -634,7 +634,19 @@ pub const Type = extern union { | ... | @@ -634,7 +634,19 @@ pub const Type = extern union { |
| 634 | for (a_payload.data.values) |a_val, i| { | 634 | for (a_payload.data.values) |a_val, i| { |
| 635 | const ty = a_payload.data.types[i]; | 635 | const ty = a_payload.data.types[i]; |
| 636 | const b_val = b_payload.data.values[i]; | 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 | return true; | 652 | return true; |
test/behavior.zig-1| ... | @@ -163,7 +163,6 @@ test { | ... | @@ -163,7 +163,6 @@ test { |
| 163 | _ = @import("behavior/select.zig"); | 163 | _ = @import("behavior/select.zig"); |
| 164 | _ = @import("behavior/shuffle.zig"); | 164 | _ = @import("behavior/shuffle.zig"); |
| 165 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); | 165 | _ = @import("behavior/sizeof_and_typeof_stage1.zig"); |
| 166 | _ = @import("behavior/slice_stage1.zig"); | ||
| 167 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | 166 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 168 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | 167 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); |
| 169 | _ = @import("behavior/switch_prong_err_enum.zig"); | 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,3 +204,355 @@ test "slice string literal has correct type" { |
| 204 | const array = [_]i32{ 1, 2, 3, 4 }; | 204 | const array = [_]i32{ 1, 2, 3, 4 }; |
| 205 | comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); | 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 | } | ||