| ... | ... | @@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9923 | 9923 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9924 | 9924 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| 9925 | 9925 | |
| 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); |
| 9927 | 9927 | } |
| 9928 | 9928 | |
| 9929 | 9929 | 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 |
| 9940 | 9940 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9941 | 9941 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| 9942 | 9942 | |
| 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); |
| 9944 | 9944 | } |
| 9945 | 9945 | |
| 9946 | 9946 | 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 |
| 9959 | 9959 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9960 | 9960 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| 9961 | 9961 | |
| 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); |
| 9963 | 9963 | } |
| 9964 | 9964 | |
| 9965 | 9965 | 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 |
| 9968 | 9968 | |
| 9969 | 9969 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9970 | 9970 | 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); |
| 9972 | 9980 | } |
| 9973 | 9981 | |
| 9974 | 9982 | fn zirSwitchCapture( |
| ... | ... | @@ -29200,6 +29208,7 @@ fn analyzeSlice( |
| 29200 | 29208 | ptr_src: LazySrcLoc, |
| 29201 | 29209 | start_src: LazySrcLoc, |
| 29202 | 29210 | end_src: LazySrcLoc, |
| 29211 | by_length: bool, |
| 29203 | 29212 | ) CompileError!Air.Inst.Ref { |
| 29204 | 29213 | // Slice expressions can operate on a variable whose type is an array. This requires |
| 29205 | 29214 | // 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( |
| 29274 | 29283 | // we might learn of the length because it is a comptime-known slice value. |
| 29275 | 29284 | var end_is_len = uncasted_end_opt == .none; |
| 29276 | 29285 | 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) { |
| 29278 | 29292 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); |
| 29279 | 29293 | |
| 29280 | 29294 | if (!end_is_len) { |
| ... | ... | @@ -29384,66 +29398,71 @@ fn analyzeSlice( |
| 29384 | 29398 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 29385 | 29399 | |
| 29386 | 29400 | // 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( |
| 29418 | 29406 | 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 | }; |
| 29424 | 29439 | |
| 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 | }); |
| 29433 | 29448 | |
| 29434 | | break :msg msg; |
| 29435 | | }; |
| 29436 | | return sema.failWithOwnedErrorMsg(msg); |
| 29449 | break :msg msg; |
| 29450 | }; |
| 29451 | return sema.failWithOwnedErrorMsg(msg); |
| 29452 | } |
| 29437 | 29453 | } |
| 29438 | 29454 | } |
| 29439 | 29455 | } |
| 29440 | | } |
| 29441 | 29456 | |
| 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 | } |
| 29445 | 29461 | } |
| 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); |
| 29447 | 29466 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); |
| 29448 | 29467 | |
| 29449 | 29468 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; |