diff --git a/src/Sema.zig b/src/Sema.zig index 8abcbd47ed..f341ae727d 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/value.zig b/src/value.zig index bb7b742290..7cd19c5d25 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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 { 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); + } +}