Skip to content

Commit

Permalink
sema: allow slicing *T with comptime known [0..1]
Browse files Browse the repository at this point in the history
  • Loading branch information
dweiller authored and andrewrk committed Jan 15, 2024
1 parent 4debd43 commit 8afafa7
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 12 deletions.
76 changes: 74 additions & 2 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
12 changes: 12 additions & 0 deletions test/behavior/slice.zig
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ test "slice syntax resulting in pointer-to-array" {
try testArrayLengthZ();
try testMultiPointer();
try testMultiPointerLengthZ();
try testSingleItemPointer();
}

fn testArray() !void {
Expand Down Expand Up @@ -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();
Expand Down
41 changes: 41 additions & 0 deletions test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig
Original file line number Diff line number Diff line change
@@ -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]
10 changes: 0 additions & 10 deletions test/cases/compile_errors/slicing_single-item_pointer.zig

This file was deleted.

0 comments on commit 8afafa7

Please sign in to comment.