mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
Sema: fix slice field modification at comptime
This commit is contained in:
parent
6f4343b61a
commit
095d51164f
131
src/Sema.zig
131
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;
|
||||
},
|
||||
|
||||
|
@ -2542,6 +2542,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,
|
||||
};
|
||||
}
|
||||
@ -5116,6 +5125,9 @@ pub const Value = extern union {
|
||||
ptr: Value,
|
||||
len: Value,
|
||||
},
|
||||
|
||||
pub const ptr_index = 0;
|
||||
pub const len_index = 1;
|
||||
};
|
||||
|
||||
pub const Ty = struct {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user