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

Stage2: fix slice field modification at comptime
This commit is contained in:
Veikka Tuominen 2022-04-28 22:27:50 +03:00 committed by GitHub
commit 091fe78337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 44 deletions

View File

@ -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;
},

View File

@ -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}),

View File

@ -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 {

View File

@ -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);
}
}