Commit 8afafa717f

dweiller <4678790+dweiller@users.noreply.github.com>
2023-11-09 13:30:53
sema: allow slicing *T with comptime known [0..1]
1 parent 4debd43
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 => {
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();
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]
test/cases/compile_errors/slicing_single-item_pointer.zig
@@ -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