authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-04-30 15:00:28+10:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-05-07 15:55:20+10:00
loge58a0c5e9e9a6eab7f5efdc60b0f3d5b9c106786
tree11a6030bb17f34008a947e36e9ac899987e01c44
parenta62b5d84d834757682be9b5a0606ff8168c1d594

sema: implement slice_length ZIR instruction


1 files changed, 76 insertions(+), 57 deletions(-)

src/Sema.zig+76-57
......@@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
99239923 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
99249924 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
99259925
9926 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src);
9926 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false);
99279927}
99289928
99299929fn 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
99409940 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
99419941 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
99429942
9943 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src);
9943 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false);
99449944}
99459945
99469946fn 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
99599959 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
99609960 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
99619961
9962 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src);
9962 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false);
99639963}
99649964
99659965fn 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
99689968
99699969 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
99709970 const src = inst_data.src();
9971 return sema.fail(block, src, "TODO: implement .slice_length", .{});
9971 const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
9972 const array_ptr = try sema.resolveInst(extra.lhs);
9973 const start = try sema.resolveInst(extra.start);
9974 const len = try sema.resolveInst(extra.len);
9975 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
9976 const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset };
9977 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
9978
9979 return sema.analyzeSlice(block, src, array_ptr, start, len, .none, .unneeded, ptr_src, start_src, end_src, true);
99729980}
99739981
99749982fn zirSwitchCapture(
......@@ -29200,6 +29208,7 @@ fn analyzeSlice(
2920029208 ptr_src: LazySrcLoc,
2920129209 start_src: LazySrcLoc,
2920229210 end_src: LazySrcLoc,
29211 by_length: bool,
2920329212) CompileError!Air.Inst.Ref {
2920429213 // Slice expressions can operate on a variable whose type is an array. This requires
2920529214 // 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(
2927429283 // we might learn of the length because it is a comptime-known slice value.
2927529284 var end_is_len = uncasted_end_opt == .none;
2927629285 const end = e: {
29277 if (array_ty.zigTypeTag() == .Array) {
29286 if (by_length and !end_is_len) {
29287 const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
29288 const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
29289 const end = try sema.coerce(block, Type.usize, uncasted_end, end_src);
29290 break :e end;
29291 } else if (array_ty.zigTypeTag() == .Array) {
2927829292 const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen());
2927929293
2928029294 if (!end_is_len) {
......@@ -29384,66 +29398,71 @@ fn analyzeSlice(
2938429398 const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
2938529399
2938629400 // requirement: start <= end
29387 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
29388 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
29389 if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
29390 return sema.fail(
29391 block,
29392 start_src,
29393 "start index {} is larger than end index {}",
29394 .{
29395 start_val.fmtValue(Type.usize, mod),
29396 end_val.fmtValue(Type.usize, mod),
29397 },
29398 );
29399 }
29400 if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
29401 const expected_sentinel = sentinel orelse break :sentinel_check;
29402 const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
29403 const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
29404 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
29405
29406 const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
29407 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
29408 const actual_sentinel = switch (res) {
29409 .runtime_load => break :sentinel_check,
29410 .val => |v| v,
29411 .needed_well_defined => |ty| return sema.fail(
29412 block,
29413 src,
29414 "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
29415 .{ty.fmt(sema.mod)},
29416 ),
29417 .out_of_bounds => |ty| return sema.fail(
29401 if (!by_length) {
29402 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
29403 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
29404 if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
29405 return sema.fail(
2941829406 block,
29419 end_src,
29420 "slice end index {d} exceeds bounds of containing decl of type '{}'",
29421 .{ end_int, ty.fmt(sema.mod) },
29422 ),
29423 };
29407 start_src,
29408 "start index {} is larger than end index {}",
29409 .{
29410 start_val.fmtValue(Type.usize, mod),
29411 end_val.fmtValue(Type.usize, mod),
29412 },
29413 );
29414 }
29415 if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
29416 const expected_sentinel = sentinel orelse break :sentinel_check;
29417 const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
29418 const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
29419 const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
29420
29421 const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
29422 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
29423 const actual_sentinel = switch (res) {
29424 .runtime_load => break :sentinel_check,
29425 .val => |v| v,
29426 .needed_well_defined => |ty| return sema.fail(
29427 block,
29428 src,
29429 "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
29430 .{ty.fmt(sema.mod)},
29431 ),
29432 .out_of_bounds => |ty| return sema.fail(
29433 block,
29434 end_src,
29435 "slice end index {d} exceeds bounds of containing decl of type '{}'",
29436 .{ end_int, ty.fmt(sema.mod) },
29437 ),
29438 };
2942429439
29425 if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
29426 const msg = msg: {
29427 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
29428 errdefer msg.destroy(sema.gpa);
29429 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
29430 expected_sentinel.fmtValue(elem_ty, sema.mod),
29431 actual_sentinel.fmtValue(elem_ty, sema.mod),
29432 });
29440 if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
29441 const msg = msg: {
29442 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
29443 errdefer msg.destroy(sema.gpa);
29444 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
29445 expected_sentinel.fmtValue(elem_ty, sema.mod),
29446 actual_sentinel.fmtValue(elem_ty, sema.mod),
29447 });
2943329448
29434 break :msg msg;
29435 };
29436 return sema.failWithOwnedErrorMsg(msg);
29449 break :msg msg;
29450 };
29451 return sema.failWithOwnedErrorMsg(msg);
29452 }
2943729453 }
2943829454 }
2943929455 }
29440 }
2944129456
29442 if (block.wantSafety() and !block.is_comptime) {
29443 // requirement: start <= end
29444 try sema.panicStartLargerThanEnd(block, start, end);
29457 if (block.wantSafety() and !block.is_comptime) {
29458 // requirement: start <= end
29459 try sema.panicStartLargerThanEnd(block, start, end);
29460 }
2944529461 }
29446 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
29462 const new_len = if (by_length)
29463 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
29464 else
29465 try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
2944729466 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
2944829467
2944929468 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;