diff --git a/src/Sema.zig b/src/Sema.zig index 94b5a7f1d14bf64f6591b4180bd391d6aa3d94fc..a3dccf1d7d189d18d58ab246ddf42f08ff0f78a5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2503,6 +2503,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com try sema.requireRuntimeBlock(block, src); try sema.resolveTypeLayout(block, ty_src, final_elem_ty); + const final_ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = final_elem_ty, + .mutable = var_is_mut, + .@"align" = inferred_alloc.data.alignment, + .@"addrspace" = target_util.defaultAddressSpace(target, .local), + }); + if (var_is_mut) { try sema.validateVarType(block, ty_src, final_elem_ty, false); } else ct: { @@ -2534,8 +2541,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct; if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct; - const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty; - const new_decl = d: { var anon_decl = try block.startAnonDecl(src); defer anon_decl.deinit(); @@ -2551,17 +2556,15 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com // block so that codegen does not see it. block.instructions.shrinkRetainingCapacity(block.instructions.items.len - 3); sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl); - air_datas[ptr_inst].ty_pl.ty = bitcast_ty_ref; + // Would be nice if we could just assign `bitcast_ty_ref` to + // `air_datas[ptr_inst].ty_pl.ty`, wouldn't it? Alas, that is almost correct, + // except that the pointer is mutable and we need to make it constant here. + air_datas[ptr_inst].ty_pl.ty = try sema.addType(final_ptr_ty); return; } // Change it to a normal alloc. - const final_ptr_ty = try Type.ptr(sema.arena, .{ - .pointee_type = final_elem_ty, - .@"align" = inferred_alloc.data.alignment, - .@"addrspace" = target_util.defaultAddressSpace(target, .local), - }); sema.air_instructions.set(ptr_inst, .{ .tag = .alloc, .data = .{ .ty = final_ptr_ty }, @@ -15609,12 +15612,16 @@ fn analyzeSlice( var slice_ty = ptr_ptr_ty; var ptr_or_slice = ptr_ptr; var elem_ty = ptr_ptr_child_ty.childType(); + var ptr_sentinel: ?Value = null; switch (ptr_ptr_child_ty.zigTypeTag()) { - .Array => {}, + .Array => { + ptr_sentinel = ptr_ptr_child_ty.sentinel(); + }, .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { .One => { const double_child_ty = ptr_ptr_child_ty.childType(); if (double_child_ty.zigTypeTag() == .Array) { + ptr_sentinel = double_child_ty.sentinel(); ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); slice_ty = ptr_ptr_child_ty; array_ty = double_child_ty; @@ -15624,12 +15631,14 @@ fn analyzeSlice( } }, .Many, .C => { + ptr_sentinel = ptr_ptr_child_ty.sentinel(); ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); slice_ty = ptr_ptr_child_ty; array_ty = ptr_ptr_child_ty; elem_ty = ptr_ptr_child_ty.childType(); }, .Slice => { + ptr_sentinel = ptr_ptr_child_ty.sentinel(); ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); slice_ty = ptr_ptr_child_ty; array_ty = ptr_ptr_child_ty; @@ -15647,29 +15656,67 @@ fn analyzeSlice( const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); const new_ptr = try analyzePtrArithmetic(sema, block, src, ptr, start, .ptr_add, ptr_src, start_src); + // true if and only if the end index of the slice, implicitly or explicitly, equals + // the length of the underlying object being sliced. we might learn the length of the + // underlying object because it is an array (which has the length in the type), or + // we might learn of the length because it is a comptime-known slice value. + var end_is_len = uncasted_end_opt == .none; const end = e: { - if (uncasted_end_opt != .none) { - break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); - } - if (array_ty.zigTypeTag() == .Array) { - break :e try sema.addConstant( - Type.usize, - try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()), - ); + const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); + + if (!end_is_len) { + const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + if (try sema.resolveMaybeUndefVal(block, end_src, end)) |end_val| { + if (end_val.eql(len_val, Type.usize)) { + end_is_len = true; + } + } + break :e end; + } + + break :e try sema.addConstant(Type.usize, len_val); } else if (slice_ty.isSlice()) { + if (!end_is_len) { + const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { + if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { + var int_payload: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = slice_val.sliceLen(), + }; + const slice_len_val = Value.initPayload(&int_payload.base); + if (end_val.eql(slice_len_val, Type.usize)) { + end_is_len = true; + } + } + } + break :e end; + } break :e try sema.analyzeSliceLen(block, src, ptr_or_slice); } + if (!end_is_len) { + break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + } return sema.fail(block, end_src, "slice of pointer must include end value", .{}); }; - const slice_sentinel = if (sentinel_opt != .none) blk: { - const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src); - break :blk try sema.resolveConstValue(block, sentinel_src, casted); - } else null; + const sentinel = s: { + if (sentinel_opt != .none) { + const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src); + break :s try sema.resolveConstValue(block, sentinel_src, casted); + } + // If we are slicing to the end of something that is sentinel-terminated + // then the resulting slice type is also sentinel-terminated. + if (end_is_len) { + if (ptr_sentinel) |sent| { + break :s sent; + } + } + break :s null; + }; const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src); - const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; @@ -15678,11 +15725,6 @@ fn analyzeSlice( if (opt_new_len_val) |new_len_val| { const new_len_int = new_len_val.toUnsignedInt(); - const sentinel = if (array_ty.zigTypeTag() == .Array and new_len_int == array_ty.arrayLen()) - array_ty.sentinel() - else - slice_sentinel; - const return_ty = try Type.ptr(sema.arena, .{ .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty), .sentinel = null, @@ -15713,7 +15755,7 @@ fn analyzeSlice( const return_ty = try Type.ptr(sema.arena, .{ .pointee_type = elem_ty, - .sentinel = slice_sentinel, + .sentinel = sentinel, .@"align" = new_ptr_ty_info.@"align", .@"addrspace" = new_ptr_ty_info.@"addrspace", .mutable = new_ptr_ty_info.mutable, diff --git a/src/type.zig b/src/type.zig index 5632629bff726070df6b0846b7f9ed03418a0b4c..272d09a921ca7efa9bc7234b0aed0d40c7b63cc0 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3042,6 +3042,9 @@ pub const Type = extern union { .array_u8, .manyptr_u8, .manyptr_const_u8, + .const_slice_u8, + .const_slice, + .mut_slice, => return null, .pointer => return self.castTag(.pointer).?.data.sentinel, diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 0b01139800bc63d79e89391776877fb4c1a15e28..d4e8284751d663a6743ad5cabb9d27955be5d397 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -192,3 +192,15 @@ test "compile time slice of pointer to hard coded address" { try expect(@ptrToInt(y) == 0x1400); try expect(y.len == 0x400); } + +test "slice string literal has correct type" { + comptime { + try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); + const array = [_]i32{ 1, 2, 3, 4 }; + try expect(@TypeOf(array[0..]) == *const [4]i32); + } + var runtime_zero: usize = 0; + comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); + const array = [_]i32{ 1, 2, 3, 4 }; + comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); +} diff --git a/test/behavior/slice_stage1.zig b/test/behavior/slice_stage1.zig index 3df7a75e108d51ca0edcfb21f7bb2ea128a96bc7..cb7c0f5223d840a55657362bc24d70f22aaa91e6 100644 --- a/test/behavior/slice_stage1.zig +++ b/test/behavior/slice_stage1.zig @@ -4,18 +4,6 @@ const expectEqualSlices = std.testing.expectEqualSlices; const expectEqual = std.testing.expectEqual; const mem = std.mem; -test "slice string literal has correct type" { - comptime { - try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); - const array = [_]i32{ 1, 2, 3, 4 }; - try expect(@TypeOf(array[0..]) == *const [4]i32); - } - var runtime_zero: usize = 0; - comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); - const array = [_]i32{ 1, 2, 3, 4 }; - comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); -} - test "result location zero sized array inside struct field implicit cast to slice" { const E = struct { entries: []u32,