compiler: provide result type to sentinel expression in slice operation
Resolves: #21867
This commit is contained in:
@@ -920,7 +920,10 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
||||
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
|
||||
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start);
|
||||
const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none;
|
||||
const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
|
||||
const sentinel = if (full.ast.sentinel != 0) s: {
|
||||
const sentinel_ty = try gz.addUnNode(.slice_sentinel_ty, lhs, node);
|
||||
break :s try expr(gz, scope, .{ .rl = .{ .coerced_ty = sentinel_ty } }, full.ast.sentinel);
|
||||
} else .none;
|
||||
try emitDbgStmt(gz, cursor);
|
||||
if (sentinel != .none) {
|
||||
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
|
||||
.slice_end,
|
||||
.slice_sentinel,
|
||||
.slice_length,
|
||||
.slice_sentinel_ty,
|
||||
.import,
|
||||
.switch_block,
|
||||
.switch_block_ref,
|
||||
|
||||
@@ -599,6 +599,10 @@ pub const Inst = struct {
|
||||
/// Returns a pointer to the subslice.
|
||||
/// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceLength`.
|
||||
slice_length,
|
||||
/// Given a value which is a pointer to the LHS of a slice operation, return the sentinel
|
||||
/// type, used as the result type of the slice sentinel (i.e. `s` in `lhs[a..b :s]`).
|
||||
/// Uses the `un_node` field. AST node is the slice syntax. Operand is `lhs`.
|
||||
slice_sentinel_ty,
|
||||
/// Same as `store` except provides a source location.
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
store_node,
|
||||
@@ -1185,6 +1189,7 @@ pub const Inst = struct {
|
||||
.slice_end,
|
||||
.slice_sentinel,
|
||||
.slice_length,
|
||||
.slice_sentinel_ty,
|
||||
.import,
|
||||
.typeof_log2_int_type,
|
||||
.resolve_inferred_alloc,
|
||||
@@ -1472,6 +1477,7 @@ pub const Inst = struct {
|
||||
.slice_end,
|
||||
.slice_sentinel,
|
||||
.slice_length,
|
||||
.slice_sentinel_ty,
|
||||
.import,
|
||||
.typeof_log2_int_type,
|
||||
.switch_block,
|
||||
@@ -1702,6 +1708,7 @@ pub const Inst = struct {
|
||||
.slice_end = .pl_node,
|
||||
.slice_sentinel = .pl_node,
|
||||
.slice_length = .pl_node,
|
||||
.slice_sentinel_ty = .un_node,
|
||||
.store_node = .pl_node,
|
||||
.store_to_inferred_ptr = .pl_node,
|
||||
.str = .str,
|
||||
@@ -4162,6 +4169,7 @@ fn findTrackableInner(
|
||||
.slice_end,
|
||||
.slice_sentinel,
|
||||
.slice_length,
|
||||
.slice_sentinel_ty,
|
||||
.store_node,
|
||||
.store_to_inferred_ptr,
|
||||
.str,
|
||||
|
||||
41
src/Sema.zig
41
src/Sema.zig
@@ -1197,6 +1197,7 @@ fn analyzeBodyInner(
|
||||
.slice_sentinel => try sema.zirSliceSentinel(block, inst),
|
||||
.slice_start => try sema.zirSliceStart(block, inst),
|
||||
.slice_length => try sema.zirSliceLength(block, inst),
|
||||
.slice_sentinel_ty => try sema.zirSliceSentinelTy(block, inst),
|
||||
.str => try sema.zirStr(inst),
|
||||
.switch_block => try sema.zirSwitchBlock(block, inst, false),
|
||||
.switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
|
||||
@@ -10753,6 +10754,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
|
||||
}
|
||||
|
||||
fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
|
||||
|
||||
const src = block.nodeOffset(inst_data.src_node);
|
||||
const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
|
||||
const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node });
|
||||
|
||||
// This is like the logic in `analyzeSlice`; since we've evaluated the LHS as an lvalue, we will
|
||||
// have a double pointer if it was already a pointer.
|
||||
|
||||
const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand));
|
||||
const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) {
|
||||
.pointer => lhs_ptr_ty.childType(zcu),
|
||||
else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}),
|
||||
};
|
||||
|
||||
const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) {
|
||||
.array => lhs_ty.childType(zcu),
|
||||
.pointer => switch (lhs_ty.ptrSize(zcu)) {
|
||||
.many, .c, .slice => lhs_ty.childType(zcu),
|
||||
.one => s: {
|
||||
const lhs_elem_ty = lhs_ty.childType(zcu);
|
||||
break :s switch (lhs_elem_ty.zigTypeTag(zcu)) {
|
||||
.array => lhs_elem_ty.childType(zcu), // array element type
|
||||
else => return sema.fail(block, sentinel_src, "slice of single-item pointer cannot have sentinel", .{}),
|
||||
};
|
||||
},
|
||||
},
|
||||
else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}),
|
||||
};
|
||||
|
||||
return Air.internedToRef(sentinel_ty.toIntern());
|
||||
}
|
||||
|
||||
/// Holds common data used when analyzing or resolving switch prong bodies,
|
||||
/// including setting up captures.
|
||||
const SwitchProngAnalysis = struct {
|
||||
|
||||
@@ -208,6 +208,7 @@ const Writer = struct {
|
||||
.anyframe_type,
|
||||
.bit_not,
|
||||
.bool_not,
|
||||
.slice_sentinel_ty,
|
||||
.negate,
|
||||
.negate_wrap,
|
||||
.load,
|
||||
|
||||
@@ -1037,3 +1037,16 @@ test "peer slices keep abi alignment with empty struct" {
|
||||
comptime assert(@TypeOf(slice) == []const u32);
|
||||
try expect(slice.len == 0);
|
||||
}
|
||||
|
||||
test "sentinel expression in slice operation has result type" {
|
||||
const sentinel = std.math.maxInt(u16);
|
||||
|
||||
const arr: [3]u16 = .{ 1, 2, sentinel };
|
||||
const slice = arr[0..2 :@intCast(sentinel)];
|
||||
|
||||
comptime assert(@TypeOf(slice) == *const [2:sentinel]u16);
|
||||
comptime assert(slice[2] == sentinel);
|
||||
comptime assert(slice.len == 2);
|
||||
comptime assert(slice[0] == 1);
|
||||
comptime assert(slice[1] == 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user