authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-28 17:45:33+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-28 17:45:33+03:00
log095d51164f53ee7f23aae9dbe08270eacf61d97b
tree6b281707a59612dce18c9584b413635efd3874eb
parent6f4343b61afe36a709e713735947561a2b76bce8

Sema: fix slice field modification at comptime


3 files changed, 114 insertions(+), 40 deletions(-)

src/Sema.zig+91-40
......@@ -16979,44 +16979,44 @@ fn fieldPtr(
1697916979 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
1698016980 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
1698116981
16982 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
16983 var anon_decl = try block.startAnonDecl(src);
16984 defer anon_decl.deinit();
16985
16986 return sema.analyzeDeclRef(try anon_decl.finish(
16987 try slice_ptr_ty.copy(anon_decl.arena()),
16988 try val.slicePtr().copy(anon_decl.arena()),
16989 0, // default alignment
16990 ));
16991 }
16992 try sema.requireRuntimeBlock(block, src);
16993
1699416982 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
1699516983 .pointee_type = slice_ptr_ty,
1699616984 .mutable = object_ptr_ty.ptrIsMutable(),
1699716985 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
1699816986 });
1699916987
17000 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
17001 } else if (mem.eql(u8, field_name, "len")) {
1700216988 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
17003 var anon_decl = try block.startAnonDecl(src);
17004 defer anon_decl.deinit();
17005
17006 return sema.analyzeDeclRef(try anon_decl.finish(
17007 Type.usize,
17008 try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen(sema.mod)),
17009 0, // default alignment
17010 ));
16989 return sema.addConstant(
16990 result_ty,
16991 try Value.Tag.field_ptr.create(sema.arena, .{
16992 .container_ptr = val,
16993 .container_ty = inner_ty,
16994 .field_index = Value.Payload.Slice.ptr_index,
16995 }),
16996 );
1701116997 }
1701216998 try sema.requireRuntimeBlock(block, src);
1701316999
17000 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
17001 } else if (mem.eql(u8, field_name, "len")) {
1701417002 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
1701517003 .pointee_type = Type.usize,
1701617004 .mutable = object_ptr_ty.ptrIsMutable(),
1701717005 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
1701817006 });
1701917007
17008 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
17009 return sema.addConstant(
17010 result_ty,
17011 try Value.Tag.field_ptr.create(sema.arena, .{
17012 .container_ptr = val,
17013 .container_ty = inner_ty,
17014 .field_index = Value.Payload.Slice.len_index,
17015 }),
17016 );
17017 }
17018 try sema.requireRuntimeBlock(block, src);
17019
1702017020 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
1702117021 } else {
1702217022 return sema.fail(
......@@ -19297,7 +19297,6 @@ fn beginComptimePtrMutation(
1929719297 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1929819298 var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr);
1929919299 const field_index = @intCast(u32, field_ptr.field_index);
19300 const field_ty = parent.ty.structFieldType(field_index);
1930119300 switch (parent.val.tag()) {
1930219301 .undef => {
1930319302 // A struct or union has been initialized to undefined at comptime and now we
......@@ -19316,7 +19315,7 @@ fn beginComptimePtrMutation(
1931619315 return ComptimePtrMutationKit{
1931719316 .decl_ref_mut = parent.decl_ref_mut,
1931819317 .val = &fields[field_index],
19319 .ty = field_ty,
19318 .ty = parent.ty.structFieldType(field_index),
1932019319 };
1932119320 },
1932219321 .Union => {
......@@ -19331,16 +19330,37 @@ fn beginComptimePtrMutation(
1933119330 return ComptimePtrMutationKit{
1933219331 .decl_ref_mut = parent.decl_ref_mut,
1933319332 .val = &payload.data.val,
19334 .ty = field_ty,
19333 .ty = parent.ty.structFieldType(field_index),
1933519334 };
1933619335 },
19336 .Pointer => {
19337 assert(parent.ty.isSlice());
19338 parent.val.* = try Value.Tag.slice.create(arena, .{
19339 .ptr = Value.undef,
19340 .len = Value.undef,
19341 });
19342
19343 switch (field_index) {
19344 Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{
19345 .decl_ref_mut = parent.decl_ref_mut,
19346 .val = &parent.val.castTag(.slice).?.data.ptr,
19347 .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
19348 },
19349 Value.Payload.Slice.len_index => return ComptimePtrMutationKit{
19350 .decl_ref_mut = parent.decl_ref_mut,
19351 .val = &parent.val.castTag(.slice).?.data.len,
19352 .ty = Type.usize,
19353 },
19354 else => unreachable,
19355 }
19356 },
1933719357 else => unreachable,
1933819358 }
1933919359 },
1934019360 .aggregate => return ComptimePtrMutationKit{
1934119361 .decl_ref_mut = parent.decl_ref_mut,
1934219362 .val = &parent.val.castTag(.aggregate).?.data[field_index],
19343 .ty = field_ty,
19363 .ty = parent.ty.structFieldType(field_index),
1934419364 },
1934519365 .@"union" => {
1934619366 // We need to set the active field of the union.
......@@ -19353,9 +19373,22 @@ fn beginComptimePtrMutation(
1935319373 return ComptimePtrMutationKit{
1935419374 .decl_ref_mut = parent.decl_ref_mut,
1935519375 .val = &payload.val,
19356 .ty = field_ty,
19376 .ty = parent.ty.structFieldType(field_index),
1935719377 };
1935819378 },
19379 .slice => switch (field_index) {
19380 Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{
19381 .decl_ref_mut = parent.decl_ref_mut,
19382 .val = &parent.val.castTag(.slice).?.data.ptr,
19383 .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
19384 },
19385 Value.Payload.Slice.len_index => return ComptimePtrMutationKit{
19386 .decl_ref_mut = parent.decl_ref_mut,
19387 .val = &parent.val.castTag(.slice).?.data.len,
19388 .ty = Type.usize,
19389 },
19390 else => unreachable,
19391 },
1935919392
1936019393 else => unreachable,
1936119394 }
......@@ -19555,7 +19588,6 @@ fn beginComptimePtrLoad(
1955519588 .field_ptr => blk: {
1955619589 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1955719590 const field_index = @intCast(u32, field_ptr.field_index);
19558 const field_ty = field_ptr.container_ty.structFieldType(field_index);
1955919591 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
1956019592
1956119593 if (field_ptr.container_ty.hasWellDefinedLayout()) {
......@@ -19570,19 +19602,38 @@ fn beginComptimePtrLoad(
1957019602 deref.ty_without_well_defined_layout = field_ptr.container_ty;
1957119603 }
1957219604
19573 if (deref.pointee) |*tv| {
19574 const coerce_in_mem_ok =
19575 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
19576 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
19577 if (coerce_in_mem_ok) {
19578 deref.pointee = TypedValue{
19579 .ty = field_ty,
19580 .val = tv.val.fieldValue(tv.ty, field_index),
19581 };
19582 break :blk deref;
19583 }
19605 const tv = &(deref.pointee orelse {
19606 deref.pointee = null;
19607 break :blk deref;
19608 });
19609 const coerce_in_mem_ok =
19610 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
19611 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
19612 if (!coerce_in_mem_ok) {
19613 deref.pointee = null;
19614 break :blk deref;
19615 }
19616
19617 if (field_ptr.container_ty.isSlice()) {
19618 const slice_val = tv.val.castTag(.slice).?.data;
19619 deref.pointee = switch (field_index) {
19620 Value.Payload.Slice.ptr_index => TypedValue{
19621 .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
19622 .val = slice_val.ptr,
19623 },
19624 Value.Payload.Slice.len_index => TypedValue{
19625 .ty = Type.usize,
19626 .val = slice_val.len,
19627 },
19628 else => unreachable,
19629 };
19630 } else {
19631 const field_ty = field_ptr.container_ty.structFieldType(field_index);
19632 deref.pointee = TypedValue{
19633 .ty = field_ty,
19634 .val = tv.val.fieldValue(tv.ty, field_index),
19635 };
1958419636 }
19585 deref.pointee = null;
1958619637 break :blk deref;
1958719638 },
1958819639
src/value.zig+12
......@@ -2542,6 +2542,15 @@ pub const Value = extern union {
25422542 return 1;
25432543 }
25442544 },
2545 .decl_ref_mut => {
2546 const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index;
2547 const decl = mod.declPtr(decl_index);
2548 if (decl.ty.zigTypeTag() == .Array) {
2549 return decl.ty.arrayLen();
2550 } else {
2551 return 1;
2552 }
2553 },
25452554 else => unreachable,
25462555 };
25472556 }
......@@ -5116,6 +5125,9 @@ pub const Value = extern union {
51165125 ptr: Value,
51175126 len: Value,
51185127 },
5128
5129 pub const ptr_index = 0;
5130 pub const len_index = 1;
51195131 };
51205132
51215133 pub const Ty = struct {
test/behavior/slice.zig+11
......@@ -682,3 +682,14 @@ test "slicing slice with sentinel as end index" {
682682 try S.do();
683683 comptime try S.do();
684684}
685
686test "slice len modification at comptime" {
687 comptime {
688 var buf: [10]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
689 var items: []u8 = buf[0..0];
690 items.len += 2;
691 try expect(items.len == 2);
692 try expect(items[0] == 0);
693 try expect(items[1] == 1);
694 }
695}