authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-02 17:32:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-02 17:32:21-07:00
loge4b325c1952f25d447bf106966ae598482f93c17
tree4362f28061a325f8f8485ff2cfa7b14b7def9017
parent358c43939c1f5236eec9e022e7d45f1741234948
parent072744f1ac8f4f58a80dc6ca0e15bd4ecbb4abfb

Merge branch 'splat'


5 files changed, 157 insertions(+), 149 deletions(-)

doc/langref.html.in+4-9
......@@ -5474,19 +5474,14 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
54745474 {#header_close#}
54755475
54765476 {#header_open|@splat#}
5477 <pre>{#syntax#}@splat(scalar: anytype) anytype{#endsyntax#}</pre>
5477 <pre>{#syntax#}@splat(element: anytype) anytype{#endsyntax#}</pre>
54785478 <p>
54795479 Produces an array or vector where each element is the value
5480 {#syntax#}scalar{#endsyntax#}. The return type and thus the length of the
5481 vector is inferred.
5480 {#syntax#}element{#endsyntax#}. The return type, including the number of
5481 elements, is inferred.
54825482 </p>
54835483 {#code|test_splat_builtin.zig#}
5484
5485 <p>
5486 {#syntax#}scalar{#endsyntax#} must be an {#link|integer|Integers#}, {#link|bool|Primitive Types#},
5487 {#link|float|Floats#}, or {#link|pointer|Pointers#}.
5488 </p>
5489 {#see_also|Vectors|@shuffle#}
5484 {#see_also|Vectors|Arrays|@shuffle#}
54905485 {#header_close#}
54915486
54925487 {#header_open|@reduce#}
test/behavior.zig+1
......@@ -78,6 +78,7 @@ test {
7878 _ = @import("behavior/sizeof_and_typeof.zig");
7979 _ = @import("behavior/slice.zig");
8080 _ = @import("behavior/slice_sentinel_comptime.zig");
81 _ = @import("behavior/splat.zig");
8182 _ = @import("behavior/src.zig");
8283 _ = @import("behavior/string_literals.zig");
8384 _ = @import("behavior/struct.zig");
test/behavior/array.zig-101
......@@ -326,26 +326,6 @@ test "set global var array via slice embedded in struct" {
326326 try expect(s_array[2].b == 3);
327327}
328328
329test "read/write through global variable array of struct fields initialized via splat" {
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
332
333 const S = struct {
334 fn doTheTest() !void {
335 try expect(storage[0].term == 1);
336 storage[0] = MyStruct{ .term = 123 };
337 try expect(storage[0].term == 123);
338 }
339
340 pub const MyStruct = struct {
341 term: usize,
342 };
343
344 var storage: [1]MyStruct = @splat(.{ .term = 1 });
345 };
346 try S.doTheTest();
347}
348
349329test "implicit cast single-item pointer" {
350330 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
351331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -988,74 +968,6 @@ test "runtime index of array of zero-bit values" {
988968 try std.testing.expect(result.value == {});
989969}
990970
991test "@splat array" {
992 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
993 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
994 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
995
996 const S = struct {
997 fn doTheTest(comptime T: type, x: T) !void {
998 const arr: [10]T = @splat(x);
999 for (arr) |elem| {
1000 try expectEqual(x, elem);
1001 }
1002 }
1003 };
1004
1005 try S.doTheTest(u32, 123);
1006 try comptime S.doTheTest(u32, 123);
1007
1008 const Foo = struct { x: u8 };
1009 try S.doTheTest(Foo, .{ .x = 10 });
1010 try comptime S.doTheTest(Foo, .{ .x = 10 });
1011}
1012
1013test "@splat array with sentinel" {
1014 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1015 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1016 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1017
1018 const S = struct {
1019 fn doTheTest(comptime T: type, x: T, comptime s: T) !void {
1020 const arr: [10:s]T = @splat(x);
1021 for (arr) |elem| {
1022 try expectEqual(x, elem);
1023 }
1024 const ptr: [*]const T = &arr;
1025 try expectEqual(s, ptr[10]); // sentinel correct
1026 }
1027 };
1028
1029 try S.doTheTest(u32, 100, 42);
1030 try comptime S.doTheTest(u32, 100, 42);
1031
1032 try S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null);
1033 try comptime S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null);
1034}
1035
1036test "@splat zero-length array" {
1037 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1038 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1040
1041 const S = struct {
1042 fn doTheTest(comptime T: type, comptime s: T) !void {
1043 var runtime_undef: T = undefined;
1044 runtime_undef = undefined;
1045 // The array should be comptime-known despite the `@splat` operand being runtime-known.
1046 const arr: [0:s]T = @splat(runtime_undef);
1047 const ptr: [*]const T = &arr;
1048 comptime assert(ptr[0] == s);
1049 }
1050 };
1051
1052 try S.doTheTest(u32, 42);
1053 try comptime S.doTheTest(u32, 42);
1054
1055 try S.doTheTest(?*anyopaque, null);
1056 try comptime S.doTheTest(?*anyopaque, null);
1057}
1058
1059971test "initialize slice with reference to empty array initializer" {
1060972 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1061973
......@@ -1116,19 +1028,6 @@ test "sentinel of runtime-known array initialization is populated" {
11161028 try expect(elems[1] == 123);
11171029}
11181030
1119test "splat with an error union or optional result type" {
1120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1121
1122 const S = struct {
1123 fn doTest(T: type) !?T {
1124 return @splat(1);
1125 }
1126 };
1127
1128 _ = try S.doTest(@Vector(4, u32));
1129 _ = try S.doTest([4]u32);
1130}
1131
11321031test "resist alias of explicit copy of array passed as arg" {
11331032 const S = struct {
11341033 const Thing = [1]u32;
test/behavior/splat.zig created+152
......@@ -0,0 +1,152 @@
1const builtin = @import("builtin");
2
3const std = @import("std");
4const expect = std.testing.expect;
5const assert = std.debug.assert;
6
7test "@splat array" {
8 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11
12 const Foo = struct { x: u8 };
13 const S = struct {
14 fn testInt(x: u32) !void {
15 const arr: [10]u32 = @splat(x);
16 for (arr) |elem| {
17 try expect(x == elem);
18 }
19 }
20
21 fn testStruct(x: Foo) !void {
22 const arr: [10]Foo = @splat(x);
23 for (arr) |elem| {
24 try expect(x.x == elem.x);
25 }
26 }
27 };
28
29 try S.testInt(123);
30 try comptime S.testInt(123);
31
32 try S.testStruct(.{ .x = 10 });
33 try comptime S.testStruct(.{ .x = 10 });
34}
35
36test "@splat array with sentinel" {
37 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40
41 const S = struct {
42 fn doTheTest(comptime T: type, x: T, comptime s: T) !void {
43 const arr: [10:s]T = @splat(x);
44 for (arr) |elem| {
45 try expect(x == elem);
46 }
47 const ptr: [*]const T = &arr;
48 try expect(s == ptr[10]); // sentinel correct
49 }
50 };
51
52 try S.doTheTest(u32, 100, 42);
53 try comptime S.doTheTest(u32, 100, 42);
54
55 try S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null);
56 try comptime S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null);
57}
58
59test "@splat zero-length array" {
60 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
62 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
63
64 const S = struct {
65 fn doTheTest(comptime T: type, comptime s: T) !void {
66 var runtime_undef: T = undefined;
67 runtime_undef = undefined;
68 // The array should be comptime-known despite the `@splat` operand being runtime-known.
69 const arr: [0:s]T = @splat(runtime_undef);
70 const ptr: [*]const T = &arr;
71 comptime assert(ptr[0] == s);
72 }
73 };
74
75 try S.doTheTest(u32, 42);
76 try comptime S.doTheTest(u32, 42);
77
78 try S.doTheTest(?*anyopaque, null);
79 try comptime S.doTheTest(?*anyopaque, null);
80}
81
82test "splat with an error union or optional result type" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
84
85 const S = struct {
86 fn doTest(T: type) !?T {
87 return @splat(1);
88 }
89 };
90
91 _ = try S.doTest(@Vector(4, u32));
92 _ = try S.doTest([4]u32);
93}
94
95test "read/write through global variable array of struct fields initialized via splat" {
96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98
99 const S = struct {
100 fn doTheTest() !void {
101 try expect(storage[0].term == 1);
102 storage[0] = MyStruct{ .term = 123 };
103 try expect(storage[0].term == 123);
104 }
105
106 pub const MyStruct = struct {
107 term: usize,
108 };
109
110 var storage: [1]MyStruct = @splat(.{ .term = 1 });
111 };
112 try S.doTheTest();
113}
114
115test "vector @splat" {
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
120 const S = struct {
121 fn testForT(comptime N: comptime_int, v: anytype) !void {
122 const T = @TypeOf(v);
123 var vec: @Vector(N, T) = @splat(v);
124 _ = &vec;
125 const as_array = @as([N]T, vec);
126 for (as_array) |elem| try expect(v == elem);
127 }
128 fn doTheTest() !void {
129 // Splats with multiple-of-8 bit types that fill a 128bit vector.
130 try testForT(16, @as(u8, 0xEE));
131 try testForT(8, @as(u16, 0xBEEF));
132 try testForT(4, @as(u32, 0xDEADBEEF));
133 try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF));
134
135 try testForT(8, @as(f16, 3.1415));
136 try testForT(4, @as(f32, 3.1415));
137 try testForT(2, @as(f64, 3.1415));
138
139 // Same but fill more than 128 bits.
140 try testForT(16 * 2, @as(u8, 0xEE));
141 try testForT(8 * 2, @as(u16, 0xBEEF));
142 try testForT(4 * 2, @as(u32, 0xDEADBEEF));
143 try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF));
144
145 try testForT(8 * 2, @as(f16, 3.1415));
146 try testForT(4 * 2, @as(f32, 3.1415));
147 try testForT(2 * 2, @as(f64, 3.1415));
148 }
149 };
150 try S.doTheTest();
151 try comptime S.doTheTest();
152}
test/behavior/vector.zig-39
......@@ -374,45 +374,6 @@ test "vector casts of sizes not divisible by 8" {
374374 try comptime S.doTheTest();
375375}
376376
377test "vector @splat" {
378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
382 const S = struct {
383 fn testForT(comptime N: comptime_int, v: anytype) !void {
384 const T = @TypeOf(v);
385 var vec: @Vector(N, T) = @splat(v);
386 _ = &vec;
387 const as_array = @as([N]T, vec);
388 for (as_array) |elem| try expect(v == elem);
389 }
390 fn doTheTest() !void {
391 // Splats with multiple-of-8 bit types that fill a 128bit vector.
392 try testForT(16, @as(u8, 0xEE));
393 try testForT(8, @as(u16, 0xBEEF));
394 try testForT(4, @as(u32, 0xDEADBEEF));
395 try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF));
396
397 try testForT(8, @as(f16, 3.1415));
398 try testForT(4, @as(f32, 3.1415));
399 try testForT(2, @as(f64, 3.1415));
400
401 // Same but fill more than 128 bits.
402 try testForT(16 * 2, @as(u8, 0xEE));
403 try testForT(8 * 2, @as(u16, 0xBEEF));
404 try testForT(4 * 2, @as(u32, 0xDEADBEEF));
405 try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF));
406
407 try testForT(8 * 2, @as(f16, 3.1415));
408 try testForT(4 * 2, @as(f32, 3.1415));
409 try testForT(2 * 2, @as(f64, 3.1415));
410 }
411 };
412 try S.doTheTest();
413 try comptime S.doTheTest();
414}
415
416377test "load vector elements via comptime index" {
417378 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
418379 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO