aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-04-28 22:27:50 +0300
committerGitHub <noreply@github.com>2022-04-28 22:27:50 +0300
commit091fe78337dc3ca340fdf74ca6c1a58c5e666626 (patch)
tree3f29858b4c6425073e8c14c27d5355ef863f8074
parent3052597a734f87727fa7f1a0e92247f100df3e96 (diff)
parentf8940a05aeb347deb858b848e33f73ef285c3298 (diff)
downloadzig-091fe78337dc3ca340fdf74ca6c1a58c5e666626.tar.gz
zig-091fe78337dc3ca340fdf74ca6c1a58c5e666626.zip
Merge pull request #11541 from Vexu/stage2-slice-field-ptr
Stage2: fix slice field modification at comptime
-rw-r--r--src/Sema.zig131
-rw-r--r--src/TypedValue.zig41
-rw-r--r--src/value.zig12
-rw-r--r--test/behavior/slice.zig11
4 files changed, 151 insertions, 44 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 3fa0353e9d..c9d8f090ae 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -16979,44 +16979,44 @@ fn fieldPtr(
const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
- if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- var anon_decl = try block.startAnonDecl(src);
- defer anon_decl.deinit();
-
- return sema.analyzeDeclRef(try anon_decl.finish(
- try slice_ptr_ty.copy(anon_decl.arena()),
- try val.slicePtr().copy(anon_decl.arena()),
- 0, // default alignment
- ));
- }
- try sema.requireRuntimeBlock(block, src);
-
const result_ty = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = slice_ptr_ty,
.mutable = object_ptr_ty.ptrIsMutable(),
.@"addrspace" = object_ptr_ty.ptrAddressSpace(),
});
- return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
- } else if (mem.eql(u8, field_name, "len")) {
if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- var anon_decl = try block.startAnonDecl(src);
- defer anon_decl.deinit();
-
- return sema.analyzeDeclRef(try anon_decl.finish(
- Type.usize,
- try Value.Tag.int_u64.create(anon_decl.arena(), val.sliceLen(sema.mod)),
- 0, // default alignment
- ));
+ return sema.addConstant(
+ result_ty,
+ try Value.Tag.field_ptr.create(sema.arena, .{
+ .container_ptr = val,
+ .container_ty = inner_ty,
+ .field_index = Value.Payload.Slice.ptr_index,
+ }),
+ );
}
try sema.requireRuntimeBlock(block, src);
+ return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
+ } else if (mem.eql(u8, field_name, "len")) {
const result_ty = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = Type.usize,
.mutable = object_ptr_ty.ptrIsMutable(),
.@"addrspace" = object_ptr_ty.ptrAddressSpace(),
});
+ if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
+ return sema.addConstant(
+ result_ty,
+ try Value.Tag.field_ptr.create(sema.arena, .{
+ .container_ptr = val,
+ .container_ty = inner_ty,
+ .field_index = Value.Payload.Slice.len_index,
+ }),
+ );
+ }
+ try sema.requireRuntimeBlock(block, src);
+
return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
} else {
return sema.fail(
@@ -19297,7 +19297,6 @@ fn beginComptimePtrMutation(
const field_ptr = ptr_val.castTag(.field_ptr).?.data;
var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr);
const field_index = @intCast(u32, field_ptr.field_index);
- const field_ty = parent.ty.structFieldType(field_index);
switch (parent.val.tag()) {
.undef => {
// A struct or union has been initialized to undefined at comptime and now we
@@ -19316,7 +19315,7 @@ fn beginComptimePtrMutation(
return ComptimePtrMutationKit{
.decl_ref_mut = parent.decl_ref_mut,
.val = &fields[field_index],
- .ty = field_ty,
+ .ty = parent.ty.structFieldType(field_index),
};
},
.Union => {
@@ -19331,16 +19330,37 @@ fn beginComptimePtrMutation(
return ComptimePtrMutationKit{
.decl_ref_mut = parent.decl_ref_mut,
.val = &payload.data.val,
- .ty = field_ty,
+ .ty = parent.ty.structFieldType(field_index),
};
},
+ .Pointer => {
+ assert(parent.ty.isSlice());
+ parent.val.* = try Value.Tag.slice.create(arena, .{
+ .ptr = Value.undef,
+ .len = Value.undef,
+ });
+
+ switch (field_index) {
+ Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.slice).?.data.ptr,
+ .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+ },
+ Value.Payload.Slice.len_index => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.slice).?.data.len,
+ .ty = Type.usize,
+ },
+ else => unreachable,
+ }
+ },
else => unreachable,
}
},
.aggregate => return ComptimePtrMutationKit{
.decl_ref_mut = parent.decl_ref_mut,
.val = &parent.val.castTag(.aggregate).?.data[field_index],
- .ty = field_ty,
+ .ty = parent.ty.structFieldType(field_index),
},
.@"union" => {
// We need to set the active field of the union.
@@ -19353,9 +19373,22 @@ fn beginComptimePtrMutation(
return ComptimePtrMutationKit{
.decl_ref_mut = parent.decl_ref_mut,
.val = &payload.val,
- .ty = field_ty,
+ .ty = parent.ty.structFieldType(field_index),
};
},
+ .slice => switch (field_index) {
+ Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.slice).?.data.ptr,
+ .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+ },
+ Value.Payload.Slice.len_index => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.slice).?.data.len,
+ .ty = Type.usize,
+ },
+ else => unreachable,
+ },
else => unreachable,
}
@@ -19555,7 +19588,6 @@ fn beginComptimePtrLoad(
.field_ptr => blk: {
const field_ptr = ptr_val.castTag(.field_ptr).?.data;
const field_index = @intCast(u32, field_ptr.field_index);
- const field_ty = field_ptr.container_ty.structFieldType(field_index);
var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
if (field_ptr.container_ty.hasWellDefinedLayout()) {
@@ -19570,19 +19602,38 @@ fn beginComptimePtrLoad(
deref.ty_without_well_defined_layout = field_ptr.container_ty;
}
- if (deref.pointee) |*tv| {
- const coerce_in_mem_ok =
- (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
- (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
- if (coerce_in_mem_ok) {
- deref.pointee = TypedValue{
- .ty = field_ty,
- .val = tv.val.fieldValue(tv.ty, field_index),
- };
- break :blk deref;
- }
+ const tv = &(deref.pointee orelse {
+ deref.pointee = null;
+ break :blk deref;
+ });
+ const coerce_in_mem_ok =
+ (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
+ (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
+ if (!coerce_in_mem_ok) {
+ deref.pointee = null;
+ break :blk deref;
+ }
+
+ if (field_ptr.container_ty.isSlice()) {
+ const slice_val = tv.val.castTag(.slice).?.data;
+ deref.pointee = switch (field_index) {
+ Value.Payload.Slice.ptr_index => TypedValue{
+ .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
+ .val = slice_val.ptr,
+ },
+ Value.Payload.Slice.len_index => TypedValue{
+ .ty = Type.usize,
+ .val = slice_val.len,
+ },
+ else => unreachable,
+ };
+ } else {
+ const field_ty = field_ptr.container_ty.structFieldType(field_index);
+ deref.pointee = TypedValue{
+ .ty = field_ty,
+ .val = tv.val.fieldValue(tv.ty, field_index),
+ };
}
- deref.pointee = null;
break :blk deref;
},
diff --git a/src/TypedValue.zig b/src/TypedValue.zig
index b0d5d77010..43c26b254e 100644
--- a/src/TypedValue.zig
+++ b/src/TypedValue.zig
@@ -146,7 +146,8 @@ pub fn print(
if (ty.zigTypeTag() == .Struct) {
try writer.writeAll(".{ ");
const struct_fields = ty.structFields();
- const max_len = std.math.min(struct_fields.count(), max_aggregate_items);
+ const len = struct_fields.count();
+ const max_len = std.math.min(len, max_aggregate_items);
const field_names = struct_fields.keys();
const fields = struct_fields.values();
@@ -160,11 +161,15 @@ pub fn print(
.val = vals[i],
}, writer, level - 1, mod);
}
+ if (len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
return writer.writeAll(" }");
} else {
try writer.writeAll(".{ ");
const elem_ty = ty.elemType2();
- const max_len = std.math.min(ty.arrayLen(), max_aggregate_items);
+ const len = ty.arrayLen();
+ const max_len = std.math.min(len, max_aggregate_items);
var i: u32 = 0;
while (i < max_len) : (i += 1) {
@@ -174,6 +179,9 @@ pub fn print(
.val = vals[i],
}, writer, level - 1, mod);
}
+ if (len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
return writer.writeAll(" }");
}
},
@@ -292,10 +300,15 @@ pub fn print(
.ty = ty.elemType2(),
.val = val.castTag(.repeated).?.data,
};
- while (i < max_aggregate_items) : (i += 1) {
+ const len = ty.arrayLen();
+ const max_len = std.math.min(len, max_aggregate_items);
+ while (i < max_len) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
try print(elem_tv, writer, level - 1, mod);
}
+ if (len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
return writer.writeAll(" }");
},
.empty_array_sentinel => {
@@ -309,7 +322,27 @@ pub fn print(
}, writer, level - 1, mod);
return writer.writeAll(" }");
},
- .slice => return writer.writeAll("(slice)"),
+ .slice => {
+ const payload = val.castTag(.slice).?.data;
+ try writer.writeAll(".{ ");
+ const elem_ty = ty.elemType2();
+ const len = payload.len.toUnsignedInt(target);
+ const max_len = std.math.min(len, max_aggregate_items);
+
+ var i: u32 = 0;
+ while (i < max_len) : (i += 1) {
+ if (i != 0) try writer.writeAll(", ");
+ var buf: Value.ElemValueBuffer = undefined;
+ try print(.{
+ .ty = elem_ty,
+ .val = payload.ptr.elemValueBuffer(mod, i, &buf),
+ }, writer, level - 1, mod);
+ }
+ if (len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
+ return writer.writeAll(" }");
+ },
.float_16 => return writer.print("{}", .{val.castTag(.float_16).?.data}),
.float_32 => return writer.print("{}", .{val.castTag(.float_32).?.data}),
.float_64 => return writer.print("{}", .{val.castTag(.float_64).?.data}),
diff --git a/src/value.zig b/src/value.zig
index d2de389de9..adfe4600f8 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -2539,6 +2539,15 @@ pub const Value = extern union {
return 1;
}
},
+ .decl_ref_mut => {
+ const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index;
+ const decl = mod.declPtr(decl_index);
+ if (decl.ty.zigTypeTag() == .Array) {
+ return decl.ty.arrayLen();
+ } else {
+ return 1;
+ }
+ },
else => unreachable,
};
}
@@ -5067,6 +5076,9 @@ pub const Value = extern union {
ptr: Value,
len: Value,
},
+
+ pub const ptr_index = 0;
+ pub const len_index = 1;
};
pub const Ty = struct {
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
index 09d15e3ac5..18c769f27c 100644
--- a/test/behavior/slice.zig
+++ b/test/behavior/slice.zig
@@ -682,3 +682,14 @@ test "slicing slice with sentinel as end index" {
try S.do();
comptime try S.do();
}
+
+test "slice len modification at comptime" {
+ comptime {
+ var buf: [10]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ var items: []u8 = buf[0..0];
+ items.len += 2;
+ try expect(items.len == 2);
+ try expect(items[0] == 0);
+ try expect(items[1] == 1);
+ }
+}