| author | |
| committer | |
| log | 0f38558435a0f73c4c025b5641bd8e531f063e0c |
| tree | 439d2571f3c7bf3bdb4b532cccfe3c5eff38ce62 |
| parent | 456f3c026b3d6fb289f42e442b202e0be152c9d3 |
| signature |
Resolves: #218675 files changed, 68 insertions(+), 1 deletions(-)
lib/std/zig/AstGen.zig+5-1| ... | @@ -920,7 +920,10 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -920,7 +920,10 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 920 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); | 920 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); |
| 921 | const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start); | 921 | const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start); |
| 922 | const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none; | 922 | const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none; |
| 923 | const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none; | 923 | const sentinel = if (full.ast.sentinel != 0) s: { |
| 924 | const sentinel_ty = try gz.addUnNode(.slice_sentinel_ty, lhs, node); | ||
| 925 | break :s try expr(gz, scope, .{ .rl = .{ .coerced_ty = sentinel_ty } }, full.ast.sentinel); | ||
| 926 | } else .none; | ||
| 924 | try emitDbgStmt(gz, cursor); | 927 | try emitDbgStmt(gz, cursor); |
| 925 | if (sentinel != .none) { | 928 | if (sentinel != .none) { |
| 926 | const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ | 929 | const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ |
| ... | @@ -2855,6 +2858,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2855,6 +2858,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2855 | .slice_end, | 2858 | .slice_end, |
| 2856 | .slice_sentinel, | 2859 | .slice_sentinel, |
| 2857 | .slice_length, | 2860 | .slice_length, |
| 2861 | .slice_sentinel_ty, | ||
| 2858 | .import, | 2862 | .import, |
| 2859 | .switch_block, | 2863 | .switch_block, |
| 2860 | .switch_block_ref, | 2864 | .switch_block_ref, |
lib/std/zig/Zir.zig+8| ... | @@ -599,6 +599,10 @@ pub const Inst = struct { | ... | @@ -599,6 +599,10 @@ pub const Inst = struct { |
| 599 | /// Returns a pointer to the subslice. | 599 | /// Returns a pointer to the subslice. |
| 600 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceLength`. | 600 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceLength`. |
| 601 | slice_length, | 601 | slice_length, |
| 602 | /// Given a value which is a pointer to the LHS of a slice operation, return the sentinel | ||
| 603 | /// type, used as the result type of the slice sentinel (i.e. `s` in `lhs[a..b :s]`). | ||
| 604 | /// Uses the `un_node` field. AST node is the slice syntax. Operand is `lhs`. | ||
| 605 | slice_sentinel_ty, | ||
| 602 | /// Same as `store` except provides a source location. | 606 | /// Same as `store` except provides a source location. |
| 603 | /// Uses the `pl_node` union field. Payload is `Bin`. | 607 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 604 | store_node, | 608 | store_node, |
| ... | @@ -1185,6 +1189,7 @@ pub const Inst = struct { | ... | @@ -1185,6 +1189,7 @@ pub const Inst = struct { |
| 1185 | .slice_end, | 1189 | .slice_end, |
| 1186 | .slice_sentinel, | 1190 | .slice_sentinel, |
| 1187 | .slice_length, | 1191 | .slice_length, |
| 1192 | .slice_sentinel_ty, | ||
| 1188 | .import, | 1193 | .import, |
| 1189 | .typeof_log2_int_type, | 1194 | .typeof_log2_int_type, |
| 1190 | .resolve_inferred_alloc, | 1195 | .resolve_inferred_alloc, |
| ... | @@ -1472,6 +1477,7 @@ pub const Inst = struct { | ... | @@ -1472,6 +1477,7 @@ pub const Inst = struct { |
| 1472 | .slice_end, | 1477 | .slice_end, |
| 1473 | .slice_sentinel, | 1478 | .slice_sentinel, |
| 1474 | .slice_length, | 1479 | .slice_length, |
| 1480 | .slice_sentinel_ty, | ||
| 1475 | .import, | 1481 | .import, |
| 1476 | .typeof_log2_int_type, | 1482 | .typeof_log2_int_type, |
| 1477 | .switch_block, | 1483 | .switch_block, |
| ... | @@ -1702,6 +1708,7 @@ pub const Inst = struct { | ... | @@ -1702,6 +1708,7 @@ pub const Inst = struct { |
| 1702 | .slice_end = .pl_node, | 1708 | .slice_end = .pl_node, |
| 1703 | .slice_sentinel = .pl_node, | 1709 | .slice_sentinel = .pl_node, |
| 1704 | .slice_length = .pl_node, | 1710 | .slice_length = .pl_node, |
| 1711 | .slice_sentinel_ty = .un_node, | ||
| 1705 | .store_node = .pl_node, | 1712 | .store_node = .pl_node, |
| 1706 | .store_to_inferred_ptr = .pl_node, | 1713 | .store_to_inferred_ptr = .pl_node, |
| 1707 | .str = .str, | 1714 | .str = .str, |
| ... | @@ -4162,6 +4169,7 @@ fn findTrackableInner( | ... | @@ -4162,6 +4169,7 @@ fn findTrackableInner( |
| 4162 | .slice_end, | 4169 | .slice_end, |
| 4163 | .slice_sentinel, | 4170 | .slice_sentinel, |
| 4164 | .slice_length, | 4171 | .slice_length, |
| 4172 | .slice_sentinel_ty, | ||
| 4165 | .store_node, | 4173 | .store_node, |
| 4166 | .store_to_inferred_ptr, | 4174 | .store_to_inferred_ptr, |
| 4167 | .str, | 4175 | .str, |
src/Sema.zig+41| ... | @@ -1197,6 +1197,7 @@ fn analyzeBodyInner( | ... | @@ -1197,6 +1197,7 @@ fn analyzeBodyInner( |
| 1197 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | 1197 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), |
| 1198 | .slice_start => try sema.zirSliceStart(block, inst), | 1198 | .slice_start => try sema.zirSliceStart(block, inst), |
| 1199 | .slice_length => try sema.zirSliceLength(block, inst), | 1199 | .slice_length => try sema.zirSliceLength(block, inst), |
| 1200 | .slice_sentinel_ty => try sema.zirSliceSentinelTy(block, inst), | ||
| 1200 | .str => try sema.zirStr(inst), | 1201 | .str => try sema.zirStr(inst), |
| 1201 | .switch_block => try sema.zirSwitchBlock(block, inst, false), | 1202 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1202 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), | 1203 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| ... | @@ -10753,6 +10754,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10753,6 +10754,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10753 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); | 10754 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); |
| 10754 | } | 10755 | } |
| 10755 | 10756 | ||
| 10757 | fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 10758 | const tracy = trace(@src()); | ||
| 10759 | defer tracy.end(); | ||
| 10760 | |||
| 10761 | const pt = sema.pt; | ||
| 10762 | const zcu = pt.zcu; | ||
| 10763 | |||
| 10764 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; | ||
| 10765 | |||
| 10766 | const src = block.nodeOffset(inst_data.src_node); | ||
| 10767 | const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node }); | ||
| 10768 | const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node }); | ||
| 10769 | |||
| 10770 | // This is like the logic in `analyzeSlice`; since we've evaluated the LHS as an lvalue, we will | ||
| 10771 | // have a double pointer if it was already a pointer. | ||
| 10772 | |||
| 10773 | const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand)); | ||
| 10774 | const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) { | ||
| 10775 | .pointer => lhs_ptr_ty.childType(zcu), | ||
| 10776 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}), | ||
| 10777 | }; | ||
| 10778 | |||
| 10779 | const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) { | ||
| 10780 | .array => lhs_ty.childType(zcu), | ||
| 10781 | .pointer => switch (lhs_ty.ptrSize(zcu)) { | ||
| 10782 | .many, .c, .slice => lhs_ty.childType(zcu), | ||
| 10783 | .one => s: { | ||
| 10784 | const lhs_elem_ty = lhs_ty.childType(zcu); | ||
| 10785 | break :s switch (lhs_elem_ty.zigTypeTag(zcu)) { | ||
| 10786 | .array => lhs_elem_ty.childType(zcu), // array element type | ||
| 10787 | else => return sema.fail(block, sentinel_src, "slice of single-item pointer cannot have sentinel", .{}), | ||
| 10788 | }; | ||
| 10789 | }, | ||
| 10790 | }, | ||
| 10791 | else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}), | ||
| 10792 | }; | ||
| 10793 | |||
| 10794 | return Air.internedToRef(sentinel_ty.toIntern()); | ||
| 10795 | } | ||
| 10796 | |||
| 10756 | /// Holds common data used when analyzing or resolving switch prong bodies, | 10797 | /// Holds common data used when analyzing or resolving switch prong bodies, |
| 10757 | /// including setting up captures. | 10798 | /// including setting up captures. |
| 10758 | const SwitchProngAnalysis = struct { | 10799 | const SwitchProngAnalysis = struct { |
src/print_zir.zig+1| ... | @@ -208,6 +208,7 @@ const Writer = struct { | ... | @@ -208,6 +208,7 @@ const Writer = struct { |
| 208 | .anyframe_type, | 208 | .anyframe_type, |
| 209 | .bit_not, | 209 | .bit_not, |
| 210 | .bool_not, | 210 | .bool_not, |
| 211 | .slice_sentinel_ty, | ||
| 211 | .negate, | 212 | .negate, |
| 212 | .negate_wrap, | 213 | .negate_wrap, |
| 213 | .load, | 214 | .load, |
test/behavior/slice.zig+13| ... | @@ -1037,3 +1037,16 @@ test "peer slices keep abi alignment with empty struct" { | ... | @@ -1037,3 +1037,16 @@ test "peer slices keep abi alignment with empty struct" { |
| 1037 | comptime assert(@TypeOf(slice) == []const u32); | 1037 | comptime assert(@TypeOf(slice) == []const u32); |
| 1038 | try expect(slice.len == 0); | 1038 | try expect(slice.len == 0); |
| 1039 | } | 1039 | } |
| 1040 | |||
| 1041 | test "sentinel expression in slice operation has result type" { | ||
| 1042 | const sentinel = std.math.maxInt(u16); | ||
| 1043 | |||
| 1044 | const arr: [3]u16 = .{ 1, 2, sentinel }; | ||
| 1045 | const slice = arr[0..2 :@intCast(sentinel)]; | ||
| 1046 | |||
| 1047 | comptime assert(@TypeOf(slice) == *const [2:sentinel]u16); | ||
| 1048 | comptime assert(slice[2] == sentinel); | ||
| 1049 | comptime assert(slice.len == 2); | ||
| 1050 | comptime assert(slice[0] == 1); | ||
| 1051 | comptime assert(slice[1] == 2); | ||
| 1052 | } |