authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-28 22:27:50+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-28 22:27:50+03:00
log091fe78337dc3ca340fdf74ca6c1a58c5e666626
tree3f29858b4c6425073e8c14c27d5355ef863f8074
parent3052597a734f87727fa7f1a0e92247f100df3e96
parentf8940a05aeb347deb858b848e33f73ef285c3298
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11541 from Vexu/stage2-slice-field-ptr

Stage2: fix slice field modification at comptime

4 files changed, 151 insertions(+), 44 deletions(-)

src/Sema.zig+91-40
...@@ -16979,44 +16979,44 @@ fn fieldPtr(...@@ -16979,44 +16979,44 @@ fn fieldPtr(
16979 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);16979 const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
16980 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);16980 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
16994 const result_ty = try Type.ptr(sema.arena, sema.mod, .{16982 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
16995 .pointee_type = slice_ptr_ty,16983 .pointee_type = slice_ptr_ty,
16996 .mutable = object_ptr_ty.ptrIsMutable(),16984 .mutable = object_ptr_ty.ptrIsMutable(),
16997 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),16985 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
16998 });16986 });
1699916987
17000 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
17001 } else if (mem.eql(u8, field_name, "len")) {
17002 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {16988 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
17003 var anon_decl = try block.startAnonDecl(src);16989 return sema.addConstant(
17004 defer anon_decl.deinit();16990 result_ty,
1700516991 try Value.Tag.field_ptr.create(sema.arena, .{
17006 return sema.analyzeDeclRef(try anon_decl.finish(16992 .container_ptr = val,
17007 Type.usize,16993 .container_ty = inner_ty,
17008 try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen(sema.mod)),16994 .field_index = Value.Payload.Slice.ptr_index,
17009 0, // default alignment16995 }),
17010 ));16996 );
17011 }16997 }
17012 try sema.requireRuntimeBlock(block, src);16998 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")) {
17014 const result_ty = try Type.ptr(sema.arena, sema.mod, .{17002 const result_ty = try Type.ptr(sema.arena, sema.mod, .{
17015 .pointee_type = Type.usize,17003 .pointee_type = Type.usize,
17016 .mutable = object_ptr_ty.ptrIsMutable(),17004 .mutable = object_ptr_ty.ptrIsMutable(),
17017 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),17005 .@"addrspace" = object_ptr_ty.ptrAddressSpace(),
17018 });17006 });
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
17020 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);17020 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
17021 } else {17021 } else {
17022 return sema.fail(17022 return sema.fail(
...@@ -19297,7 +19297,6 @@ fn beginComptimePtrMutation(...@@ -19297,7 +19297,6 @@ fn beginComptimePtrMutation(
19297 const field_ptr = ptr_val.castTag(.field_ptr).?.data;19297 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
19298 var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr);19298 var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr);
19299 const field_index = @intCast(u32, field_ptr.field_index);19299 const field_index = @intCast(u32, field_ptr.field_index);
19300 const field_ty = parent.ty.structFieldType(field_index);
19301 switch (parent.val.tag()) {19300 switch (parent.val.tag()) {
19302 .undef => {19301 .undef => {
19303 // A struct or union has been initialized to undefined at comptime and now we19302 // A struct or union has been initialized to undefined at comptime and now we
...@@ -19316,7 +19315,7 @@ fn beginComptimePtrMutation(...@@ -19316,7 +19315,7 @@ fn beginComptimePtrMutation(
19316 return ComptimePtrMutationKit{19315 return ComptimePtrMutationKit{
19317 .decl_ref_mut = parent.decl_ref_mut,19316 .decl_ref_mut = parent.decl_ref_mut,
19318 .val = &fields[field_index],19317 .val = &fields[field_index],
19319 .ty = field_ty,19318 .ty = parent.ty.structFieldType(field_index),
19320 };19319 };
19321 },19320 },
19322 .Union => {19321 .Union => {
...@@ -19331,16 +19330,37 @@ fn beginComptimePtrMutation(...@@ -19331,16 +19330,37 @@ fn beginComptimePtrMutation(
19331 return ComptimePtrMutationKit{19330 return ComptimePtrMutationKit{
19332 .decl_ref_mut = parent.decl_ref_mut,19331 .decl_ref_mut = parent.decl_ref_mut,
19333 .val = &payload.data.val,19332 .val = &payload.data.val,
19334 .ty = field_ty,19333 .ty = parent.ty.structFieldType(field_index),
19335 };19334 };
19336 },19335 },
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 },
19337 else => unreachable,19357 else => unreachable,
19338 }19358 }
19339 },19359 },
19340 .aggregate => return ComptimePtrMutationKit{19360 .aggregate => return ComptimePtrMutationKit{
19341 .decl_ref_mut = parent.decl_ref_mut,19361 .decl_ref_mut = parent.decl_ref_mut,
19342 .val = &parent.val.castTag(.aggregate).?.data[field_index],19362 .val = &parent.val.castTag(.aggregate).?.data[field_index],
19343 .ty = field_ty,19363 .ty = parent.ty.structFieldType(field_index),
19344 },19364 },
19345 .@"union" => {19365 .@"union" => {
19346 // We need to set the active field of the union.19366 // We need to set the active field of the union.
...@@ -19353,9 +19373,22 @@ fn beginComptimePtrMutation(...@@ -19353,9 +19373,22 @@ fn beginComptimePtrMutation(
19353 return ComptimePtrMutationKit{19373 return ComptimePtrMutationKit{
19354 .decl_ref_mut = parent.decl_ref_mut,19374 .decl_ref_mut = parent.decl_ref_mut,
19355 .val = &payload.val,19375 .val = &payload.val,
19356 .ty = field_ty,19376 .ty = parent.ty.structFieldType(field_index),
19357 };19377 };
19358 },19378 },
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
19360 else => unreachable,19393 else => unreachable,
19361 }19394 }
...@@ -19555,7 +19588,6 @@ fn beginComptimePtrLoad(...@@ -19555,7 +19588,6 @@ fn beginComptimePtrLoad(
19555 .field_ptr => blk: {19588 .field_ptr => blk: {
19556 const field_ptr = ptr_val.castTag(.field_ptr).?.data;19589 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
19557 const field_index = @intCast(u32, field_ptr.field_index);19590 const field_index = @intCast(u32, field_ptr.field_index);
19558 const field_ty = field_ptr.container_ty.structFieldType(field_index);
19559 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);19591 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
1956019592
19561 if (field_ptr.container_ty.hasWellDefinedLayout()) {19593 if (field_ptr.container_ty.hasWellDefinedLayout()) {
...@@ -19570,19 +19602,38 @@ fn beginComptimePtrLoad(...@@ -19570,19 +19602,38 @@ fn beginComptimePtrLoad(
19570 deref.ty_without_well_defined_layout = field_ptr.container_ty;19602 deref.ty_without_well_defined_layout = field_ptr.container_ty;
19571 }19603 }
1957219604
19573 if (deref.pointee) |*tv| {19605 const tv = &(deref.pointee orelse {
19574 const coerce_in_mem_ok =19606 deref.pointee = null;
19575 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or19607 break :blk deref;
19576 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;19608 });
19577 if (coerce_in_mem_ok) {19609 const coerce_in_mem_ok =
19578 deref.pointee = TypedValue{19610 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
19579 .ty = field_ty,19611 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
19580 .val = tv.val.fieldValue(tv.ty, field_index),19612 if (!coerce_in_mem_ok) {
19581 };19613 deref.pointee = null;
19582 break :blk deref;19614 break :blk deref;
19583 }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 };
19584 }19636 }
19585 deref.pointee = null;
19586 break :blk deref;19637 break :blk deref;
19587 },19638 },
1958819639
src/TypedValue.zig+37-4
...@@ -146,7 +146,8 @@ pub fn print(...@@ -146,7 +146,8 @@ pub fn print(
146 if (ty.zigTypeTag() == .Struct) {146 if (ty.zigTypeTag() == .Struct) {
147 try writer.writeAll(".{ ");147 try writer.writeAll(".{ ");
148 const struct_fields = ty.structFields();148 const struct_fields = ty.structFields();
149 const max_len = std.math.min(struct_fields.count(), max_aggregate_items);149 const len = struct_fields.count();
150 const max_len = std.math.min(len, max_aggregate_items);
150151
151 const field_names = struct_fields.keys();152 const field_names = struct_fields.keys();
152 const fields = struct_fields.values();153 const fields = struct_fields.values();
...@@ -160,11 +161,15 @@ pub fn print(...@@ -160,11 +161,15 @@ pub fn print(
160 .val = vals[i],161 .val = vals[i],
161 }, writer, level - 1, mod);162 }, writer, level - 1, mod);
162 }163 }
164 if (len > max_aggregate_items) {
165 try writer.writeAll(", ...");
166 }
163 return writer.writeAll(" }");167 return writer.writeAll(" }");
164 } else {168 } else {
165 try writer.writeAll(".{ ");169 try writer.writeAll(".{ ");
166 const elem_ty = ty.elemType2();170 const elem_ty = ty.elemType2();
167 const max_len = std.math.min(ty.arrayLen(), max_aggregate_items);171 const len = ty.arrayLen();
172 const max_len = std.math.min(len, max_aggregate_items);
168173
169 var i: u32 = 0;174 var i: u32 = 0;
170 while (i < max_len) : (i += 1) {175 while (i < max_len) : (i += 1) {
...@@ -174,6 +179,9 @@ pub fn print(...@@ -174,6 +179,9 @@ pub fn print(
174 .val = vals[i],179 .val = vals[i],
175 }, writer, level - 1, mod);180 }, writer, level - 1, mod);
176 }181 }
182 if (len > max_aggregate_items) {
183 try writer.writeAll(", ...");
184 }
177 return writer.writeAll(" }");185 return writer.writeAll(" }");
178 }186 }
179 },187 },
...@@ -292,10 +300,15 @@ pub fn print(...@@ -292,10 +300,15 @@ pub fn print(
292 .ty = ty.elemType2(),300 .ty = ty.elemType2(),
293 .val = val.castTag(.repeated).?.data,301 .val = val.castTag(.repeated).?.data,
294 };302 };
295 while (i < max_aggregate_items) : (i += 1) {303 const len = ty.arrayLen();
304 const max_len = std.math.min(len, max_aggregate_items);
305 while (i < max_len) : (i += 1) {
296 if (i != 0) try writer.writeAll(", ");306 if (i != 0) try writer.writeAll(", ");
297 try print(elem_tv, writer, level - 1, mod);307 try print(elem_tv, writer, level - 1, mod);
298 }308 }
309 if (len > max_aggregate_items) {
310 try writer.writeAll(", ...");
311 }
299 return writer.writeAll(" }");312 return writer.writeAll(" }");
300 },313 },
301 .empty_array_sentinel => {314 .empty_array_sentinel => {
...@@ -309,7 +322,27 @@ pub fn print(...@@ -309,7 +322,27 @@ pub fn print(
309 }, writer, level - 1, mod);322 }, writer, level - 1, mod);
310 return writer.writeAll(" }");323 return writer.writeAll(" }");
311 },324 },
312 .slice => return writer.writeAll("(slice)"),325 .slice => {
326 const payload = val.castTag(.slice).?.data;
327 try writer.writeAll(".{ ");
328 const elem_ty = ty.elemType2();
329 const len = payload.len.toUnsignedInt(target);
330 const max_len = std.math.min(len, max_aggregate_items);
331
332 var i: u32 = 0;
333 while (i < max_len) : (i += 1) {
334 if (i != 0) try writer.writeAll(", ");
335 var buf: Value.ElemValueBuffer = undefined;
336 try print(.{
337 .ty = elem_ty,
338 .val = payload.ptr.elemValueBuffer(mod, i, &buf),
339 }, writer, level - 1, mod);
340 }
341 if (len > max_aggregate_items) {
342 try writer.writeAll(", ...");
343 }
344 return writer.writeAll(" }");
345 },
313 .float_16 => return writer.print("{}", .{val.castTag(.float_16).?.data}),346 .float_16 => return writer.print("{}", .{val.castTag(.float_16).?.data}),
314 .float_32 => return writer.print("{}", .{val.castTag(.float_32).?.data}),347 .float_32 => return writer.print("{}", .{val.castTag(.float_32).?.data}),
315 .float_64 => return writer.print("{}", .{val.castTag(.float_64).?.data}),348 .float_64 => return writer.print("{}", .{val.castTag(.float_64).?.data}),
src/value.zig+12
...@@ -2539,6 +2539,15 @@ pub const Value = extern union {...@@ -2539,6 +2539,15 @@ pub const Value = extern union {
2539 return 1;2539 return 1;
2540 }2540 }
2541 },2541 },
2542 .decl_ref_mut => {
2543 const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index;
2544 const decl = mod.declPtr(decl_index);
2545 if (decl.ty.zigTypeTag() == .Array) {
2546 return decl.ty.arrayLen();
2547 } else {
2548 return 1;
2549 }
2550 },
2542 else => unreachable,2551 else => unreachable,
2543 };2552 };
2544 }2553 }
...@@ -5067,6 +5076,9 @@ pub const Value = extern union {...@@ -5067,6 +5076,9 @@ pub const Value = extern union {
5067 ptr: Value,5076 ptr: Value,
5068 len: Value,5077 len: Value,
5069 },5078 },
5079
5080 pub const ptr_index = 0;
5081 pub const len_index = 1;
5070 };5082 };
50715083
5072 pub const Ty = struct {5084 pub const Ty = struct {
test/behavior/slice.zig+11
...@@ -682,3 +682,14 @@ test "slicing slice with sentinel as end index" {...@@ -682,3 +682,14 @@ test "slicing slice with sentinel as end index" {
682 try S.do();682 try S.do();
683 comptime try S.do();683 comptime try S.do();
684}684}
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}