Commit e58a0c5e9e
Changed files (1)
src
src/Sema.zig
@@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false);
}
fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9940,7 +9940,7 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false);
}
fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9959,7 +9959,7 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false);
}
fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9968,7 +9968,15 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
- return sema.fail(block, src, "TODO: implement .slice_length", .{});
+ const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
+ const array_ptr = try sema.resolveInst(extra.lhs);
+ const start = try sema.resolveInst(extra.start);
+ const len = try sema.resolveInst(extra.len);
+ const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
+ const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset };
+ const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
+
+ return sema.analyzeSlice(block, src, array_ptr, start, len, .none, .unneeded, ptr_src, start_src, end_src, true);
}
fn zirSwitchCapture(
@@ -29200,6 +29208,7 @@ fn analyzeSlice(
ptr_src: LazySrcLoc,
start_src: LazySrcLoc,
end_src: LazySrcLoc,
+ by_length: bool,
) CompileError!Air.Inst.Ref {
// Slice expressions can operate on a variable whose type is an array. This requires
// the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.
@@ -29274,7 +29283,12 @@ fn analyzeSlice(
// 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 (array_ty.zigTypeTag() == .Array) {
+ if (by_length and !end_is_len) {
+ const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
+ const end = try sema.coerce(block, Type.usize, uncasted_end, end_src);
+ break :e end;
+ } else if (array_ty.zigTypeTag() == .Array) {
const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen());
if (!end_is_len) {
@@ -29384,66 +29398,71 @@ fn analyzeSlice(
const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
// requirement: start <= end
- if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
- if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
- if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
- return sema.fail(
- block,
- start_src,
- "start index {} is larger than end index {}",
- .{
- start_val.fmtValue(Type.usize, mod),
- end_val.fmtValue(Type.usize, mod),
- },
- );
- }
- if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
- const expected_sentinel = sentinel orelse break :sentinel_check;
- const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
- const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
- const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
-
- const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
- const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
- const actual_sentinel = switch (res) {
- .runtime_load => break :sentinel_check,
- .val => |v| v,
- .needed_well_defined => |ty| return sema.fail(
- block,
- src,
- "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
- .{ty.fmt(sema.mod)},
- ),
- .out_of_bounds => |ty| return sema.fail(
+ if (!by_length) {
+ if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
+ if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
+ if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
+ return sema.fail(
block,
- end_src,
- "slice end index {d} exceeds bounds of containing decl of type '{}'",
- .{ end_int, ty.fmt(sema.mod) },
- ),
- };
+ start_src,
+ "start index {} is larger than end index {}",
+ .{
+ start_val.fmtValue(Type.usize, mod),
+ end_val.fmtValue(Type.usize, mod),
+ },
+ );
+ }
+ if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
+ const expected_sentinel = sentinel orelse break :sentinel_check;
+ const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
+ const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
+ const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
+
+ const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
+ const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
+ const actual_sentinel = switch (res) {
+ .runtime_load => break :sentinel_check,
+ .val => |v| v,
+ .needed_well_defined => |ty| return sema.fail(
+ block,
+ src,
+ "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
+ .{ty.fmt(sema.mod)},
+ ),
+ .out_of_bounds => |ty| return sema.fail(
+ block,
+ end_src,
+ "slice end index {d} exceeds bounds of containing decl of type '{}'",
+ .{ end_int, ty.fmt(sema.mod) },
+ ),
+ };
- if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
- expected_sentinel.fmtValue(elem_ty, sema.mod),
- actual_sentinel.fmtValue(elem_ty, sema.mod),
- });
+ if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
+ expected_sentinel.fmtValue(elem_ty, sema.mod),
+ actual_sentinel.fmtValue(elem_ty, sema.mod),
+ });
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
}
}
}
- }
- if (block.wantSafety() and !block.is_comptime) {
- // requirement: start <= end
- try sema.panicStartLargerThanEnd(block, start, end);
+ if (block.wantSafety() and !block.is_comptime) {
+ // requirement: start <= end
+ try sema.panicStartLargerThanEnd(block, start, end);
+ }
}
- const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
+ const new_len = if (by_length)
+ try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
+ else
+ try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;