| ... | @@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9923 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; | 9923 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9924 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; | 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 | fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,7 +9940,7 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9940 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; | 9940 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9941 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; | 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 | fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,7 +9959,7 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 9959 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; | 9959 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; |
| 9960 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; | 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 | fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,7 +9968,15 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9968 | | 9968 | |
| 9969 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9969 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9970 | const src = inst_data.src(); | 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 | fn zirSwitchCapture( | 9982 | fn zirSwitchCapture( |
| ... | @@ -29200,6 +29208,7 @@ fn analyzeSlice( | ... | @@ -29200,6 +29208,7 @@ fn analyzeSlice( |
| 29200 | ptr_src: LazySrcLoc, | 29208 | ptr_src: LazySrcLoc, |
| 29201 | start_src: LazySrcLoc, | 29209 | start_src: LazySrcLoc, |
| 29202 | end_src: LazySrcLoc, | 29210 | end_src: LazySrcLoc, |
| | 29211 | by_length: bool, |
| 29203 | ) CompileError!Air.Inst.Ref { | 29212 | ) CompileError!Air.Inst.Ref { |
| 29204 | // Slice expressions can operate on a variable whose type is an array. This requires | 29213 | // Slice expressions can operate on a variable whose type is an array. This requires |
| 29205 | // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. | 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,7 +29283,12 @@ fn analyzeSlice( |
| 29274 | // we might learn of the length because it is a comptime-known slice value. | 29283 | // we might learn of the length because it is a comptime-known slice value. |
| 29275 | var end_is_len = uncasted_end_opt == .none; | 29284 | var end_is_len = uncasted_end_opt == .none; |
| 29276 | const end = e: { | 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 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); | 29292 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); |
| 29279 | | 29293 | |
| 29280 | if (!end_is_len) { | 29294 | if (!end_is_len) { |
| ... | @@ -29384,66 +29398,71 @@ fn analyzeSlice( | ... | @@ -29384,66 +29398,71 @@ fn analyzeSlice( |
| 29384 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; | 29398 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 29385 | | 29399 | |
| 29386 | // requirement: start <= end | 29400 | // requirement: start <= end |
| 29387 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { | 29401 | if (!by_length) { |
| 29388 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { | 29402 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29389 | if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { | 29403 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { |
| 29390 | return sema.fail( | 29404 | if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { |
| 29391 | block, | 29405 | return sema.fail( |
| 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( | | |
| 29418 | block, | 29406 | block, |
| 29419 | end_src, | 29407 | start_src, |
| 29420 | "slice end index {d} exceeds bounds of containing decl of type '{}'", | 29408 | "start index {} is larger than end index {}", |
| 29421 | .{ end_int, ty.fmt(sema.mod) }, | 29409 | .{ |
| 29422 | ), | 29410 | start_val.fmtValue(Type.usize, mod), |
| 29423 | }; | 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)) { | 29440 | if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { |
| 29426 | const msg = msg: { | 29441 | const msg = msg: { |
| 29427 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); | 29442 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); |
| 29428 | errdefer msg.destroy(sema.gpa); | 29443 | errdefer msg.destroy(sema.gpa); |
| 29429 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ | 29444 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ |
| 29430 | expected_sentinel.fmtValue(elem_ty, sema.mod), | 29445 | expected_sentinel.fmtValue(elem_ty, sema.mod), |
| 29431 | actual_sentinel.fmtValue(elem_ty, sema.mod), | 29446 | actual_sentinel.fmtValue(elem_ty, sema.mod), |
| 29432 | }); | 29447 | }); |
| 29433 | | 29448 | |
| 29434 | break :msg msg; | 29449 | break :msg msg; |
| 29435 | }; | 29450 | }; |
| 29436 | return sema.failWithOwnedErrorMsg(msg); | 29451 | return sema.failWithOwnedErrorMsg(msg); |
| | 29452 | } |
| 29437 | } | 29453 | } |
| 29438 | } | 29454 | } |
| 29439 | } | 29455 | } |
| 29440 | } | | |
| 29441 | | 29456 | |
| 29442 | if (block.wantSafety() and !block.is_comptime) { | 29457 | if (block.wantSafety() and !block.is_comptime) { |
| 29443 | // requirement: start <= end | 29458 | // requirement: start <= end |
| 29444 | try sema.panicStartLargerThanEnd(block, 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 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); | 29466 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); |
| 29448 | | 29467 | |
| 29449 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; | 29468 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; |