From 8afafa717f5c036595a3a781c63b6be7b478c025 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:30:53 +1100 Subject: [PATCH] sema: allow slicing *T with comptime known [0..1] --- src/Sema.zig | 76 ++++++++++++++++++- test/behavior/slice.zig | 12 +++ .../slice_of_single-item_pointer_bounds.zig | 41 ++++++++++ .../slicing_single-item_pointer.zig | 10 --- 4 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig delete mode 100644 test/cases/compile_errors/slicing_single-item_pointer.zig diff --git a/src/Sema.zig b/src/Sema.zig index 941c91fcd0..14092eb6f1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -32572,14 +32572,86 @@ fn analyzeSlice( .Pointer => switch (ptr_ptr_child_ty.ptrSize(mod)) { .One => { const double_child_ty = ptr_ptr_child_ty.childType(mod); + ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); if (double_child_ty.zigTypeTag(mod) == .Array) { ptr_sentinel = double_child_ty.sentinel(mod); - ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); slice_ty = ptr_ptr_child_ty; array_ty = double_child_ty; elem_ty = double_child_ty.childType(mod); } else { - return sema.fail(block, src, "slice of single-item pointer", .{}); + const bounds_error_message = "slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1]"; + if (uncasted_end_opt == .none) { + return sema.fail(block, src, bounds_error_message, .{}); + } + const start_value = try sema.resolveConstDefinedValue( + block, + start_src, + uncasted_start, + .{ .needed_comptime_reason = bounds_error_message }, + ); + + const end_value = try sema.resolveConstDefinedValue( + block, + end_src, + uncasted_end_opt, + .{ .needed_comptime_reason = bounds_error_message }, + ); + + if (try sema.compareScalar(start_value, .neq, end_value, Type.comptime_int)) { + if (try sema.compareScalar(start_value, .neq, InternPool.Index.zero.toValue(), Type.comptime_int)) { + const err_msg = try sema.errMsg(block, start_src, bounds_error_message, .{}); + try sema.errNote( + block, + start_src, + err_msg, + "expected '{}', found '{}'", + .{ + Value.zero_comptime_int.fmtValue(Type.comptime_int, mod), + start_value.fmtValue(Type.comptime_int, mod), + }, + ); + return sema.failWithOwnedErrorMsg(block, err_msg); + } else if (try sema.compareScalar(end_value, .neq, InternPool.Index.one.toValue(), Type.comptime_int)) { + const err_msg = try sema.errMsg(block, end_src, bounds_error_message, .{}); + try sema.errNote( + block, + end_src, + err_msg, + "expected '{}', found '{}'", + .{ + Value.one_comptime_int.fmtValue(Type.comptime_int, mod), + end_value.fmtValue(Type.comptime_int, mod), + }, + ); + return sema.failWithOwnedErrorMsg(block, err_msg); + } + } else { + if (try sema.compareScalar(end_value, .gt, InternPool.Index.one.toValue(), Type.comptime_int)) { + return sema.fail( + block, + end_src, + "end index {} out of bounds for slice of single-item pointer", + .{end_value.fmtValue(Type.comptime_int, mod)}, + ); + } + } + + array_ty = try mod.arrayType(.{ + .len = 1, + .child = double_child_ty.toIntern(), + }); + const ptr_info = ptr_ptr_child_ty.ptrInfo(mod); + slice_ty = try mod.ptrType(.{ + .child = array_ty.toIntern(), + .flags = .{ + .alignment = ptr_info.flags.alignment, + .is_const = ptr_info.flags.is_const, + .is_allowzero = ptr_info.flags.is_allowzero, + .is_volatile = ptr_info.flags.is_volatile, + .address_space = ptr_info.flags.address_space, + }, + }); + elem_ty = double_child_ty; } }, .Many, .C => { diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 2ff8debfb6..d6b54fd1f3 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -416,6 +416,7 @@ test "slice syntax resulting in pointer-to-array" { try testArrayLengthZ(); try testMultiPointer(); try testMultiPointerLengthZ(); + try testSingleItemPointer(); } fn testArray() !void { @@ -591,6 +592,17 @@ test "slice syntax resulting in pointer-to-array" { try comptime expect(@TypeOf(ptr_z[1.. :0][0..4]) == *[4]u8); try comptime expect(@TypeOf(ptr_z[1.. :0][0..2 :4]) == *[2:4]u8); } + + fn testSingleItemPointer() !void { + var value: u8 = 1; + var ptr = &value; + + const slice = ptr[0..1]; + try comptime expect(@TypeOf(slice) == *[1]u8); + try expect(slice[0] == 1); + + try comptime expect(@TypeOf(ptr[0..0]) == *[0]u8); + } }; try S.doTheTest(); diff --git a/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig b/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig new file mode 100644 index 0000000000..17c031f12b --- /dev/null +++ b/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig @@ -0,0 +1,41 @@ +const value: u8 = 1; +const ptr = &value; + +comptime { + _ = ptr[0..]; +} + +comptime { + _ = ptr[1..2]; +} + +comptime { + _ = ptr[0..2]; +} + +comptime { + _ = ptr[2..2]; +} + +export fn entry1() void { + var start: usize = 0; + _ = ptr[start..2]; +} + +export fn entry2() void { + var end: usize = 0; + _ = ptr[0..end]; +} + +// error +// +// :5:12: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :9:13: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :9:13: note: expected '0', found '1' +// :13:16: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :13:16: note: expected '1', found '2' +// :17:16: error: end index 2 out of bounds for slice of single-item pointer +// :22:13: error: unable to resolve comptime value +// :22:13: note: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :27:16: error: unable to resolve comptime value +// :27:16: note: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] diff --git a/test/cases/compile_errors/slicing_single-item_pointer.zig b/test/cases/compile_errors/slicing_single-item_pointer.zig deleted file mode 100644 index 6b3021e5e0..0000000000 --- a/test/cases/compile_errors/slicing_single-item_pointer.zig +++ /dev/null @@ -1,10 +0,0 @@ -export fn entry(ptr: *i32) void { - const slice = ptr[0..2]; - _ = slice; -} - -// error -// backend=stage2 -// target=native -// -// :2:22: error: slice of single-item pointer