Skip to content

Commit 2753eba

Browse files
committed
Sema: allow indexing tuple and vector pointers
Resolves: #13852 Resolves: #14705
1 parent c16d4ab commit 2753eba

File tree

5 files changed

+92
-6
lines changed

5 files changed

+92
-6
lines changed

src/Sema.zig

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9957,7 +9957,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
99579957
indexable_ty.fmt(sema.mod),
99589958
});
99599959
errdefer msg.destroy(sema.gpa);
9960-
if (indexable_ty.zigTypeTag() == .Array) {
9960+
if (indexable_ty.isIndexable()) {
99619961
try sema.errNote(block, src, msg, "consider using '&' here", .{});
99629962
}
99639963
break :msg msg;
@@ -24979,8 +24979,19 @@ fn elemPtrOneLayerOnly(
2497924979
return block.addPtrElemPtr(indexable, elem_index, result_ty);
2498024980
},
2498124981
.One => {
24982-
assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by checkIndexable
24983-
return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
24982+
const child_ty = indexable_ty.childType();
24983+
switch (child_ty.zigTypeTag()) {
24984+
.Array, .Vector => {
24985+
return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
24986+
},
24987+
.Struct => {
24988+
assert(child_ty.isTuple());
24989+
const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
24990+
const index = @intCast(u32, index_val.toUnsignedInt(target));
24991+
return sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
24992+
},
24993+
else => unreachable, // Guaranteed by checkIndexable
24994+
}
2498424995
},
2498524996
}
2498624997
}
@@ -25026,7 +25037,6 @@ fn elemVal(
2502625037
return block.addBinOp(.ptr_elem_val, indexable, elem_index);
2502725038
},
2502825039
.One => {
25029-
assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by checkIndexable
2503025040
const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
2503125041
return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
2503225042
},

src/type.zig

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5329,7 +5329,11 @@ pub const Type = extern union {
53295329
.Array, .Vector => true,
53305330
.Pointer => switch (ty.ptrSize()) {
53315331
.Slice, .Many, .C => true,
5332-
.One => ty.elemType().zigTypeTag() == .Array,
5332+
.One => switch (ty.elemType().zigTypeTag()) {
5333+
.Array, .Vector => true,
5334+
.Struct => ty.elemType().isTuple(),
5335+
else => false,
5336+
},
53335337
},
53345338
.Struct => ty.isTuple(),
53355339
else => false,
@@ -5342,7 +5346,11 @@ pub const Type = extern union {
53425346
.Pointer => switch (ty.ptrSize()) {
53435347
.Many, .C => false,
53445348
.Slice => true,
5345-
.One => ty.elemType().zigTypeTag() == .Array,
5349+
.One => switch (ty.elemType().zigTypeTag()) {
5350+
.Array, .Vector => true,
5351+
.Struct => ty.elemType().isTuple(),
5352+
else => false,
5353+
},
53465354
},
53475355
.Struct => ty.isTuple(),
53485356
else => false,

test/behavior/for.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,19 @@ test "inline for with counter as the comptime-known" {
463463

464464
try expect(S.ok == 2);
465465
}
466+
467+
test "inline for on tuple pointer" {
468+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
469+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
471+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
472+
473+
const S = struct { u32, u32, u32 };
474+
var s: S = .{ 100, 200, 300 };
475+
476+
inline for (&s, 0..) |*x, i| {
477+
x.* = i;
478+
}
479+
480+
try expectEqual(S{ 0, 1, 2 }, s);
481+
}

test/behavior/tuple.zig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const builtin = @import("builtin");
22
const std = @import("std");
33
const testing = std.testing;
4+
const assert = std.debug.assert;
45
const expect = testing.expect;
56
const expectEqualStrings = std.testing.expectEqualStrings;
67
const expectEqual = std.testing.expectEqual;
@@ -428,3 +429,27 @@ test "sentinel slice in tuple" {
428429

429430
_ = S;
430431
}
432+
433+
test "tuple pointer is indexable" {
434+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
435+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
438+
439+
const S = struct { u32, bool };
440+
441+
const x: S = .{ 123, true };
442+
comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness
443+
try expectEqual(@as(u32, 123), (&x)[0]);
444+
try expectEqual(true, (&x)[1]);
445+
446+
var y: S = .{ 123, true };
447+
comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness
448+
try expectEqual(@as(u32, 123), (&y)[0]);
449+
try expectEqual(true, (&y)[1]);
450+
451+
(&y)[0] = 100;
452+
(&y)[1] = false;
453+
try expectEqual(@as(u32, 100), (&y)[0]);
454+
try expectEqual(false, (&y)[1]);
455+
}

test/behavior/vector.zig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const std = @import("std");
22
const builtin = @import("builtin");
33
const mem = std.mem;
44
const math = std.math;
5+
const assert = std.debug.assert;
56
const expect = std.testing.expect;
67
const expectEqual = std.testing.expectEqual;
78

@@ -1330,3 +1331,29 @@ test "addition of vectors represented as strings" {
13301331
const bar: V = @typeName(u32).*;
13311332
try expectEqual(V{ 219, 162, 161 }, foo + bar);
13321333
}
1334+
1335+
test "vector pointer is indexable" {
1336+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1337+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1338+
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1339+
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1340+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1341+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
1342+
1343+
const V = @Vector(2, u32);
1344+
1345+
const x: V = .{ 123, 456 };
1346+
comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness
1347+
try expectEqual(@as(u32, 123), (&x)[0]);
1348+
try expectEqual(@as(u32, 456), (&x)[1]);
1349+
1350+
var y: V = .{ 123, 456 };
1351+
comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness
1352+
try expectEqual(@as(u32, 123), (&y)[0]);
1353+
try expectEqual(@as(u32, 456), (&y)[1]);
1354+
1355+
(&y)[0] = 100;
1356+
(&y)[1] = 200;
1357+
try expectEqual(@as(u32, 100), (&y)[0]);
1358+
try expectEqual(@as(u32, 200), (&y)[1]);
1359+
}

0 commit comments

Comments
 (0)