authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-21 15:23:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-22 13:24:27-05:00
logd5e21a4f1a2920ef7bbe3c54feab1a3b5119bf77
tree01d6459250665626691593e3a52f774f30e98c81
parent994e191643f60fa2c6d6e79377340f8fad1d711b

std: remove meta.trait

In general, I don't like the idea of std.meta.trait, and so I am providing some guidance by deleting the entire namespace from the standard library and compiler codebase. My main criticism is that it's overcomplicated machinery that bloats compile times and is ultimately unnecessary given the existence of Zig's strong type system and reference traces. Users who want this can create a third party package that provides this functionality. closes #18051

23 files changed, 380 insertions(+), 965 deletions(-)

CMakeLists.txt-1
......@@ -290,7 +290,6 @@ set(ZIG_STAGE2_SOURCES
290290 "${CMAKE_SOURCE_DIR}/lib/std/mem/Allocator.zig"
291291 "${CMAKE_SOURCE_DIR}/lib/std/meta.zig"
292292 "${CMAKE_SOURCE_DIR}/lib/std/meta/trailer_flags.zig"
293 "${CMAKE_SOURCE_DIR}/lib/std/meta/trait.zig"
294293 "${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig"
295294 "${CMAKE_SOURCE_DIR}/lib/std/os.zig"
296295 "${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
lib/std/array_hash_map.zig+8-10
......@@ -4,8 +4,6 @@ const assert = debug.assert;
44const testing = std.testing;
55const math = std.math;
66const mem = std.mem;
7const meta = std.meta;
8const trait = meta.trait;
97const autoHash = std.hash.autoHash;
108const Wyhash = std.hash.Wyhash;
119const Allocator = mem.Allocator;
......@@ -2341,13 +2339,13 @@ test "reIndex" {
23412339test "auto store_hash" {
23422340 const HasCheapEql = AutoArrayHashMap(i32, i32);
23432341 const HasExpensiveEql = AutoArrayHashMap([32]i32, i32);
2344 try testing.expect(meta.fieldInfo(HasCheapEql.Data, .hash).type == void);
2345 try testing.expect(meta.fieldInfo(HasExpensiveEql.Data, .hash).type != void);
2342 try testing.expect(std.meta.fieldInfo(HasCheapEql.Data, .hash).type == void);
2343 try testing.expect(std.meta.fieldInfo(HasExpensiveEql.Data, .hash).type != void);
23462344
23472345 const HasCheapEqlUn = AutoArrayHashMapUnmanaged(i32, i32);
23482346 const HasExpensiveEqlUn = AutoArrayHashMapUnmanaged([32]i32, i32);
2349 try testing.expect(meta.fieldInfo(HasCheapEqlUn.Data, .hash).type == void);
2350 try testing.expect(meta.fieldInfo(HasExpensiveEqlUn.Data, .hash).type != void);
2347 try testing.expect(std.meta.fieldInfo(HasCheapEqlUn.Data, .hash).type == void);
2348 try testing.expect(std.meta.fieldInfo(HasExpensiveEqlUn.Data, .hash).type != void);
23512349}
23522350
23532351test "sort" {
......@@ -2434,12 +2432,12 @@ pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K)
24342432 return struct {
24352433 fn hash(ctx: Context, key: K) u32 {
24362434 _ = ctx;
2437 if (comptime trait.hasUniqueRepresentation(K)) {
2438 return @as(u32, @truncate(Wyhash.hash(0, std.mem.asBytes(&key))));
2435 if (std.meta.hasUniqueRepresentation(K)) {
2436 return @truncate(Wyhash.hash(0, std.mem.asBytes(&key)));
24392437 } else {
24402438 var hasher = Wyhash.init(0);
24412439 autoHash(&hasher, key);
2442 return @as(u32, @truncate(hasher.final()));
2440 return @truncate(hasher.final());
24432441 }
24442442 }
24452443 }.hash;
......@@ -2450,7 +2448,7 @@ pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K
24502448 fn eql(ctx: Context, a: K, b: K, b_index: usize) bool {
24512449 _ = b_index;
24522450 _ = ctx;
2453 return meta.eql(a, b);
2451 return std.meta.eql(a, b);
24542452 }
24552453 }.eql;
24562454}
lib/std/atomic/Atomic.zig+130-138
......@@ -153,163 +153,155 @@ pub fn Atomic(comptime T: type) type {
153153 return @atomicRmw(T, &self.value, op, value, ordering);
154154 }
155155
156 fn exportWhen(comptime condition: bool, comptime functions: type) type {
157 return if (condition) functions else struct {};
156 pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: Ordering) T {
157 return self.rmw(.Add, value, ordering);
158158 }
159159
160 pub usingnamespace exportWhen(std.meta.trait.isNumber(T), struct {
161 pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: Ordering) T {
162 return self.rmw(.Add, value, ordering);
163 }
164
165 pub inline fn fetchSub(self: *Self, value: T, comptime ordering: Ordering) T {
166 return self.rmw(.Sub, value, ordering);
167 }
160 pub inline fn fetchSub(self: *Self, value: T, comptime ordering: Ordering) T {
161 return self.rmw(.Sub, value, ordering);
162 }
168163
169 pub inline fn fetchMin(self: *Self, value: T, comptime ordering: Ordering) T {
170 return self.rmw(.Min, value, ordering);
171 }
164 pub inline fn fetchMin(self: *Self, value: T, comptime ordering: Ordering) T {
165 return self.rmw(.Min, value, ordering);
166 }
172167
173 pub inline fn fetchMax(self: *Self, value: T, comptime ordering: Ordering) T {
174 return self.rmw(.Max, value, ordering);
175 }
176 });
168 pub inline fn fetchMax(self: *Self, value: T, comptime ordering: Ordering) T {
169 return self.rmw(.Max, value, ordering);
170 }
177171
178 pub usingnamespace exportWhen(std.meta.trait.isIntegral(T), struct {
179 pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: Ordering) T {
180 return self.rmw(.And, value, ordering);
181 }
172 pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: Ordering) T {
173 return self.rmw(.And, value, ordering);
174 }
182175
183 pub inline fn fetchNand(self: *Self, value: T, comptime ordering: Ordering) T {
184 return self.rmw(.Nand, value, ordering);
185 }
176 pub inline fn fetchNand(self: *Self, value: T, comptime ordering: Ordering) T {
177 return self.rmw(.Nand, value, ordering);
178 }
186179
187 pub inline fn fetchOr(self: *Self, value: T, comptime ordering: Ordering) T {
188 return self.rmw(.Or, value, ordering);
189 }
180 pub inline fn fetchOr(self: *Self, value: T, comptime ordering: Ordering) T {
181 return self.rmw(.Or, value, ordering);
182 }
190183
191 pub inline fn fetchXor(self: *Self, value: T, comptime ordering: Ordering) T {
192 return self.rmw(.Xor, value, ordering);
193 }
184 pub inline fn fetchXor(self: *Self, value: T, comptime ordering: Ordering) T {
185 return self.rmw(.Xor, value, ordering);
186 }
194187
195 const Bit = std.math.Log2Int(T);
196 const BitRmwOp = enum {
197 Set,
198 Reset,
199 Toggle,
200 };
188 const Bit = std.math.Log2Int(T);
189 const BitRmwOp = enum {
190 Set,
191 Reset,
192 Toggle,
193 };
201194
202 pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
203 return bitRmw(self, .Set, bit, ordering);
204 }
195 pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
196 return bitRmw(self, .Set, bit, ordering);
197 }
205198
206 pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
207 return bitRmw(self, .Reset, bit, ordering);
208 }
199 pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
200 return bitRmw(self, .Reset, bit, ordering);
201 }
209202
210 pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
211 return bitRmw(self, .Toggle, bit, ordering);
212 }
203 pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
204 return bitRmw(self, .Toggle, bit, ordering);
205 }
213206
214 inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
215 // x86 supports dedicated bitwise instructions
216 if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {
217 // TODO: this causes std lib test failures when enabled
218 if (false) {
219 return x86BitRmw(self, op, bit, ordering);
220 }
207 inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
208 // x86 supports dedicated bitwise instructions
209 if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {
210 // TODO: this causes std lib test failures when enabled
211 if (false) {
212 return x86BitRmw(self, op, bit, ordering);
221213 }
214 }
222215
223 const mask = @as(T, 1) << bit;
224 const value = switch (op) {
225 .Set => self.fetchOr(mask, ordering),
226 .Reset => self.fetchAnd(~mask, ordering),
227 .Toggle => self.fetchXor(mask, ordering),
228 };
216 const mask = @as(T, 1) << bit;
217 const value = switch (op) {
218 .Set => self.fetchOr(mask, ordering),
219 .Reset => self.fetchAnd(~mask, ordering),
220 .Toggle => self.fetchXor(mask, ordering),
221 };
229222
230 return @intFromBool(value & mask != 0);
231 }
223 return @intFromBool(value & mask != 0);
224 }
232225
233 inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
234 const old_bit: u8 = switch (@sizeOf(T)) {
235 2 => switch (op) {
236 .Set => asm volatile ("lock btsw %[bit], %[ptr]"
237 // LLVM doesn't support u1 flag register return values
238 : [result] "={@ccc}" (-> u8),
239 : [ptr] "*m" (&self.value),
240 [bit] "X" (@as(T, bit)),
241 : "cc", "memory"
242 ),
243 .Reset => asm volatile ("lock btrw %[bit], %[ptr]"
244 // LLVM doesn't support u1 flag register return values
245 : [result] "={@ccc}" (-> u8),
246 : [ptr] "*m" (&self.value),
247 [bit] "X" (@as(T, bit)),
248 : "cc", "memory"
249 ),
250 .Toggle => asm volatile ("lock btcw %[bit], %[ptr]"
251 // LLVM doesn't support u1 flag register return values
252 : [result] "={@ccc}" (-> u8),
253 : [ptr] "*m" (&self.value),
254 [bit] "X" (@as(T, bit)),
255 : "cc", "memory"
256 ),
257 },
258 4 => switch (op) {
259 .Set => asm volatile ("lock btsl %[bit], %[ptr]"
260 // LLVM doesn't support u1 flag register return values
261 : [result] "={@ccc}" (-> u8),
262 : [ptr] "*m" (&self.value),
263 [bit] "X" (@as(T, bit)),
264 : "cc", "memory"
265 ),
266 .Reset => asm volatile ("lock btrl %[bit], %[ptr]"
267 // LLVM doesn't support u1 flag register return values
268 : [result] "={@ccc}" (-> u8),
269 : [ptr] "*m" (&self.value),
270 [bit] "X" (@as(T, bit)),
271 : "cc", "memory"
272 ),
273 .Toggle => asm volatile ("lock btcl %[bit], %[ptr]"
274 // LLVM doesn't support u1 flag register return values
275 : [result] "={@ccc}" (-> u8),
276 : [ptr] "*m" (&self.value),
277 [bit] "X" (@as(T, bit)),
278 : "cc", "memory"
279 ),
280 },
281 8 => switch (op) {
282 .Set => asm volatile ("lock btsq %[bit], %[ptr]"
283 // LLVM doesn't support u1 flag register return values
284 : [result] "={@ccc}" (-> u8),
285 : [ptr] "*m" (&self.value),
286 [bit] "X" (@as(T, bit)),
287 : "cc", "memory"
288 ),
289 .Reset => asm volatile ("lock btrq %[bit], %[ptr]"
290 // LLVM doesn't support u1 flag register return values
291 : [result] "={@ccc}" (-> u8),
292 : [ptr] "*m" (&self.value),
293 [bit] "X" (@as(T, bit)),
294 : "cc", "memory"
295 ),
296 .Toggle => asm volatile ("lock btcq %[bit], %[ptr]"
297 // LLVM doesn't support u1 flag register return values
298 : [result] "={@ccc}" (-> u8),
299 : [ptr] "*m" (&self.value),
300 [bit] "X" (@as(T, bit)),
301 : "cc", "memory"
302 ),
303 },
304 else => @compileError("Invalid atomic type " ++ @typeName(T)),
305 };
226 inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
227 const old_bit: u8 = switch (@sizeOf(T)) {
228 2 => switch (op) {
229 .Set => asm volatile ("lock btsw %[bit], %[ptr]"
230 // LLVM doesn't support u1 flag register return values
231 : [result] "={@ccc}" (-> u8),
232 : [ptr] "*m" (&self.value),
233 [bit] "X" (@as(T, bit)),
234 : "cc", "memory"
235 ),
236 .Reset => asm volatile ("lock btrw %[bit], %[ptr]"
237 // LLVM doesn't support u1 flag register return values
238 : [result] "={@ccc}" (-> u8),
239 : [ptr] "*m" (&self.value),
240 [bit] "X" (@as(T, bit)),
241 : "cc", "memory"
242 ),
243 .Toggle => asm volatile ("lock btcw %[bit], %[ptr]"
244 // LLVM doesn't support u1 flag register return values
245 : [result] "={@ccc}" (-> u8),
246 : [ptr] "*m" (&self.value),
247 [bit] "X" (@as(T, bit)),
248 : "cc", "memory"
249 ),
250 },
251 4 => switch (op) {
252 .Set => asm volatile ("lock btsl %[bit], %[ptr]"
253 // LLVM doesn't support u1 flag register return values
254 : [result] "={@ccc}" (-> u8),
255 : [ptr] "*m" (&self.value),
256 [bit] "X" (@as(T, bit)),
257 : "cc", "memory"
258 ),
259 .Reset => asm volatile ("lock btrl %[bit], %[ptr]"
260 // LLVM doesn't support u1 flag register return values
261 : [result] "={@ccc}" (-> u8),
262 : [ptr] "*m" (&self.value),
263 [bit] "X" (@as(T, bit)),
264 : "cc", "memory"
265 ),
266 .Toggle => asm volatile ("lock btcl %[bit], %[ptr]"
267 // LLVM doesn't support u1 flag register return values
268 : [result] "={@ccc}" (-> u8),
269 : [ptr] "*m" (&self.value),
270 [bit] "X" (@as(T, bit)),
271 : "cc", "memory"
272 ),
273 },
274 8 => switch (op) {
275 .Set => asm volatile ("lock btsq %[bit], %[ptr]"
276 // LLVM doesn't support u1 flag register return values
277 : [result] "={@ccc}" (-> u8),
278 : [ptr] "*m" (&self.value),
279 [bit] "X" (@as(T, bit)),
280 : "cc", "memory"
281 ),
282 .Reset => asm volatile ("lock btrq %[bit], %[ptr]"
283 // LLVM doesn't support u1 flag register return values
284 : [result] "={@ccc}" (-> u8),
285 : [ptr] "*m" (&self.value),
286 [bit] "X" (@as(T, bit)),
287 : "cc", "memory"
288 ),
289 .Toggle => asm volatile ("lock btcq %[bit], %[ptr]"
290 // LLVM doesn't support u1 flag register return values
291 : [result] "={@ccc}" (-> u8),
292 : [ptr] "*m" (&self.value),
293 [bit] "X" (@as(T, bit)),
294 : "cc", "memory"
295 ),
296 },
297 else => @compileError("Invalid atomic type " ++ @typeName(T)),
298 };
306299
307 // TODO: emit appropriate tsan fence if compiling with tsan
308 _ = ordering;
300 // TODO: emit appropriate tsan fence if compiling with tsan
301 _ = ordering;
309302
310 return @as(u1, @intCast(old_bit));
311 }
312 });
303 return @intCast(old_bit);
304 }
313305 };
314306}
315307
lib/std/enums.zig+1-1
......@@ -201,7 +201,7 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E {
201201 if (V == E) break :blk value;
202202 const name: ?[]const u8 = switch (@typeInfo(V)) {
203203 .EnumLiteral, .Enum => @tagName(value),
204 .Pointer => if (std.meta.trait.isZigString(V)) value else null,
204 .Pointer => value,
205205 else => null,
206206 };
207207 if (name) |n| {
lib/std/fmt.zig+6-9
......@@ -478,7 +478,7 @@ pub fn formatType(
478478 return formatAddress(value, options, writer);
479479 }
480480
481 if (comptime std.meta.trait.hasFn("format")(T)) {
481 if (std.meta.hasFn(T, "format")) {
482482 return try value.format(actual_fmt, options, writer);
483483 }
484484
......@@ -611,15 +611,12 @@ pub fn formatType(
611611 else => {},
612612 }
613613 }
614 if (comptime std.meta.trait.isZigString(info.child)) {
615 for (value, 0..) |item, i| {
616 comptime checkTextFmt(actual_fmt);
617 if (i != 0) try formatBuf(", ", options, writer);
618 try formatBuf(item, options, writer);
619 }
620 return;
614 for (value, 0..) |item, i| {
615 comptime checkTextFmt(actual_fmt);
616 if (i != 0) try formatBuf(", ", options, writer);
617 try formatBuf(item, options, writer);
621618 }
622 invalidFmtError(fmt, value);
619 return;
623620 },
624621 .Enum, .Union, .Struct => {
625622 return formatType(value.*, actual_fmt, options, writer, max_depth);
lib/std/hash/auto_hash.zig+16-23
......@@ -1,7 +1,6 @@
11const std = @import("std");
22const assert = std.debug.assert;
33const mem = std.mem;
4const meta = std.meta;
54
65/// Describes how pointer types should be hashed.
76pub const HashStrategy = enum {
......@@ -69,7 +68,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
6968 else => @TypeOf(hasher),
7069 };
7170
72 if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) {
71 if (strat == .Shallow and std.meta.hasUniqueRepresentation(Key)) {
7372 @call(.always_inline, Hasher.update, .{ hasher, mem.asBytes(&key) });
7473 return;
7574 }
......@@ -97,7 +96,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
9796 .signedness = .unsigned,
9897 } }), @bitCast(key)), strat),
9998 .unsigned => {
100 if (comptime meta.trait.hasUniqueRepresentation(Key)) {
99 if (std.meta.hasUniqueRepresentation(Key)) {
101100 @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) });
102101 } else {
103102 // Take only the part containing the key value, the remaining
......@@ -120,7 +119,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
120119 .Array => hashArray(hasher, key, strat),
121120
122121 .Vector => |info| {
123 if (comptime meta.trait.hasUniqueRepresentation(Key)) {
122 if (std.meta.hasUniqueRepresentation(Key)) {
124123 hasher.update(mem.asBytes(&key));
125124 } else {
126125 comptime var i = 0;
......@@ -140,7 +139,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
140139
141140 .Union => |info| {
142141 if (info.tag_type) |tag_type| {
143 const tag = meta.activeTag(key);
142 const tag = std.meta.activeTag(key);
144143 hash(hasher, tag, strat);
145144 inline for (info.fields) |field| {
146145 if (@field(tag_type, field.name) == tag) {
......@@ -166,27 +165,21 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
166165 }
167166}
168167
169fn typeContainsSlice(comptime K: type) bool {
170 comptime {
171 if (meta.trait.isSlice(K)) {
172 return true;
173 }
174 if (meta.trait.is(.Struct)(K)) {
175 inline for (@typeInfo(K).Struct.fields) |field| {
176 if (typeContainsSlice(field.type)) {
177 return true;
178 }
179 }
180 }
181 if (meta.trait.is(.Union)(K)) {
182 inline for (@typeInfo(K).Union.fields) |field| {
168inline fn typeContainsSlice(comptime K: type) bool {
169 return switch (@typeInfo(K)) {
170 .Pointer => |info| info.size == .Slice,
171
172 inline .Struct, .Union => |info| {
173 inline for (info.fields) |field| {
183174 if (typeContainsSlice(field.type)) {
184175 return true;
185176 }
186177 }
187 }
188 return false;
189 }
178 return false;
179 },
180
181 else => false,
182 };
190183}
191184
192185/// Provides generic hashing for any eligible type.
......@@ -236,7 +229,7 @@ fn testHashDeepRecursive(key: anytype) u64 {
236229
237230test "typeContainsSlice" {
238231 comptime {
239 try testing.expect(!typeContainsSlice(meta.Tag(std.builtin.Type)));
232 try testing.expect(!typeContainsSlice(std.meta.Tag(std.builtin.Type)));
240233
241234 try testing.expect(typeContainsSlice([]const u8));
242235 try testing.expect(!typeContainsSlice(u8));
lib/std/hash/xxhash.zig-24
......@@ -185,8 +185,6 @@ pub const XxHash64 = struct {
185185 }
186186
187187 pub fn update(self: *XxHash64, input: anytype) void {
188 validateType(@TypeOf(input));
189
190188 if (input.len < 32 - self.buf_len) {
191189 @memcpy(self.buf[self.buf_len..][0..input.len], input);
192190 self.buf_len += input.len;
......@@ -232,8 +230,6 @@ pub const XxHash64 = struct {
232230 };
233231
234232 pub fn hash(seed: u64, input: anytype) u64 {
235 validateType(@TypeOf(input));
236
237233 if (input.len < 32) {
238234 return finalize(seed +% prime_5, 0, input);
239235 } else {
......@@ -315,8 +311,6 @@ pub const XxHash32 = struct {
315311 }
316312
317313 pub fn update(self: *XxHash32, input: []const u8) void {
318 validateType(@TypeOf(input));
319
320314 if (input.len < 16 - self.buf_len) {
321315 @memcpy(self.buf[self.buf_len..][0..input.len], input);
322316 self.buf_len += input.len;
......@@ -416,8 +410,6 @@ pub const XxHash32 = struct {
416410 }
417411
418412 pub fn hash(seed: u32, input: anytype) u32 {
419 validateType(@TypeOf(input));
420
421413 if (input.len < 16) {
422414 return finalize(seed +% prime_5, 0, input);
423415 } else {
......@@ -587,8 +579,6 @@ pub const XxHash3 = struct {
587579 // Public API - Oneshot
588580
589581 pub fn hash(seed: u64, input: anytype) u64 {
590 validateType(@TypeOf(input));
591
592582 const secret = &default_secret;
593583 if (input.len > 240) return hashLong(seed, input);
594584 if (input.len > 128) return hash240(seed, input, secret);
......@@ -709,8 +699,6 @@ pub const XxHash3 = struct {
709699 }
710700
711701 pub fn update(self: *XxHash3, input: anytype) void {
712 validateType(@TypeOf(input));
713
714702 self.total_len += input.len;
715703 std.debug.assert(self.buffered <= self.buffer.len);
716704
......@@ -783,18 +771,6 @@ pub const XxHash3 = struct {
783771
784772const verify = @import("verify.zig");
785773
786fn validateType(comptime T: type) void {
787 comptime {
788 if (!((std.meta.trait.isSlice(T) or
789 std.meta.trait.is(.Array)(T) or
790 std.meta.trait.isPtrTo(.Array)(T)) and
791 std.meta.Elem(T) == u8))
792 {
793 @compileError("expect a slice, array or pointer to array of u8, got " ++ @typeName(T));
794 }
795 }
796}
797
798774fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) !void {
799775 try expectEqual(expected, H.hash(seed, input));
800776
lib/std/hash_map.zig+2-4
......@@ -4,8 +4,6 @@ const assert = std.debug.assert;
44const autoHash = std.hash.autoHash;
55const math = std.math;
66const mem = std.mem;
7const meta = std.meta;
8const trait = meta.trait;
97const Allocator = mem.Allocator;
108const Wyhash = std.hash.Wyhash;
119
......@@ -24,7 +22,7 @@ pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K)
2422 return struct {
2523 fn hash(ctx: Context, key: K) u64 {
2624 _ = ctx;
27 if (comptime trait.hasUniqueRepresentation(K)) {
25 if (std.meta.hasUniqueRepresentation(K)) {
2826 return Wyhash.hash(0, std.mem.asBytes(&key));
2927 } else {
3028 var hasher = Wyhash.init(0);
......@@ -39,7 +37,7 @@ pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K
3937 return struct {
4038 fn eql(ctx: Context, a: K, b: K) bool {
4139 _ = ctx;
42 return meta.eql(a, b);
40 return std.meta.eql(a, b);
4341 }
4442 }.eql;
4543}
lib/std/io/bit_reader.zig-3
......@@ -2,7 +2,6 @@ const std = @import("../std.zig");
22const io = std.io;
33const assert = std.debug.assert;
44const testing = std.testing;
5const trait = std.meta.trait;
65const meta = std.meta;
76const math = std.math;
87
......@@ -43,8 +42,6 @@ pub fn BitReader(comptime endian: std.builtin.Endian, comptime ReaderType: type)
4342 /// containing them in the least significant end. The number of bits successfully
4443 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
4544 pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
46 comptime assert(trait.isUnsignedInt(U));
47
4845 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
4946 // related to shifting and casting.
5047 const u_bit_count = @bitSizeOf(U);
lib/std/io/bit_writer.zig+1-3
......@@ -2,8 +2,6 @@ const std = @import("../std.zig");
22const io = std.io;
33const testing = std.testing;
44const assert = std.debug.assert;
5const trait = std.meta.trait;
6const meta = std.meta;
75const math = std.math;
86
97/// Creates a stream which allows for writing bit fields to another stream
......@@ -35,7 +33,7 @@ pub fn BitWriter(comptime endian: std.builtin.Endian, comptime WriterType: type)
3533 if (bits == 0) return;
3634
3735 const U = @TypeOf(value);
38 comptime assert(trait.isUnsignedInt(U));
36 comptime assert(@typeInfo(U).Int.signedness == .unsigned);
3937
4038 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
4139 // related to shifting and casting.
lib/std/io/test.zig-2
......@@ -1,7 +1,5 @@
11const std = @import("std");
22const io = std.io;
3const meta = std.meta;
4const trait = std.trait;
53const DefaultPrng = std.rand.DefaultPrng;
64const expect = std.testing.expect;
75const expectEqual = std.testing.expectEqual;
lib/std/json/static.zig+6-6
......@@ -247,7 +247,7 @@ pub fn innerParse(
247247 }
248248 },
249249 .Enum => {
250 if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
250 if (std.meta.hasFn(T, "jsonParse")) {
251251 return T.jsonParse(allocator, source, options);
252252 }
253253
......@@ -260,7 +260,7 @@ pub fn innerParse(
260260 return sliceToEnum(T, slice);
261261 },
262262 .Union => |unionInfo| {
263 if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
263 if (std.meta.hasFn(T, "jsonParse")) {
264264 return T.jsonParse(allocator, source, options);
265265 }
266266
......@@ -318,7 +318,7 @@ pub fn innerParse(
318318 return r;
319319 }
320320
321 if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
321 if (std.meta.hasFn(T, "jsonParse")) {
322322 return T.jsonParse(allocator, source, options);
323323 }
324324
......@@ -581,7 +581,7 @@ pub fn innerParseFromValue(
581581 }
582582 },
583583 .Enum => {
584 if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
584 if (std.meta.hasFn(T, "jsonParseFromValue")) {
585585 return T.jsonParseFromValue(allocator, source, options);
586586 }
587587
......@@ -593,7 +593,7 @@ pub fn innerParseFromValue(
593593 }
594594 },
595595 .Union => |unionInfo| {
596 if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
596 if (std.meta.hasFn(T, "jsonParseFromValue")) {
597597 return T.jsonParseFromValue(allocator, source, options);
598598 }
599599
......@@ -635,7 +635,7 @@ pub fn innerParseFromValue(
635635 return r;
636636 }
637637
638 if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
638 if (std.meta.hasFn(T, "jsonParseFromValue")) {
639639 return T.jsonParseFromValue(allocator, source, options);
640640 }
641641
lib/std/json/stringify.zig+3-3
......@@ -451,14 +451,14 @@ pub fn WriteStream(
451451 }
452452 },
453453 .Enum, .EnumLiteral => {
454 if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
454 if (std.meta.hasFn(T, "jsonStringify")) {
455455 return value.jsonStringify(self);
456456 }
457457
458458 return self.stringValue(@tagName(value));
459459 },
460460 .Union => {
461 if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
461 if (std.meta.hasFn(T, "jsonStringify")) {
462462 return value.jsonStringify(self);
463463 }
464464
......@@ -487,7 +487,7 @@ pub fn WriteStream(
487487 }
488488 },
489489 .Struct => |S| {
490 if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
490 if (std.meta.hasFn(T, "jsonStringify")) {
491491 return value.jsonStringify(self);
492492 }
493493
lib/std/math.zig+1-1
......@@ -801,7 +801,7 @@ fn testDivFloor() !void {
801801/// zero.
802802pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T {
803803 @setRuntimeSafety(false);
804 if ((comptime std.meta.trait.isNumber(T)) and denominator == 0) return error.DivisionByZero;
804 if (denominator == 0) return error.DivisionByZero;
805805 const info = @typeInfo(T);
806806 switch (info) {
807807 .ComptimeFloat, .Float => return @ceil(numerator / denominator),
lib/std/mem.zig+14-46
......@@ -4,8 +4,6 @@ const debug = std.debug;
44const assert = debug.assert;
55const math = std.math;
66const mem = @This();
7const meta = std.meta;
8const trait = meta.trait;
97const testing = std.testing;
108const Endian = std.builtin.Endian;
119const native_endian = builtin.cpu.arch.endian();
......@@ -736,7 +734,7 @@ test "span" {
736734}
737735
738736/// Helper for the return type of sliceTo()
739fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
737fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type {
740738 switch (@typeInfo(T)) {
741739 .Optional => |optional_info| {
742740 return ?SliceTo(optional_info.child, end);
......@@ -796,7 +794,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
796794/// resulting slice is also sentinel terminated.
797795/// Pointer properties such as mutability and alignment are preserved.
798796/// C pointers are assumed to be non-null.
799pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
797pub fn sliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
800798 if (@typeInfo(@TypeOf(ptr)) == .Optional) {
801799 const non_null = ptr orelse return null;
802800 return sliceTo(non_null, end);
......@@ -852,7 +850,7 @@ test "sliceTo" {
852850}
853851
854852/// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len
855fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
853fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
856854 switch (@typeInfo(@TypeOf(ptr))) {
857855 .Pointer => |ptr_info| switch (ptr_info.size) {
858856 .One => switch (@typeInfo(ptr_info.child)) {
......@@ -1319,7 +1317,7 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us
13191317 if (needle.len > haystack.len) return null;
13201318 if (needle.len == 0) return haystack.len;
13211319
1322 if (!meta.trait.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
1320 if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
13231321 return lastIndexOfLinear(T, haystack, needle);
13241322
13251323 const haystack_bytes = sliceAsBytes(haystack);
......@@ -1350,7 +1348,7 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
13501348 return indexOfScalarPos(T, haystack, start_index, needle[0]);
13511349 }
13521350
1353 if (!meta.trait.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
1351 if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
13541352 return indexOfPosLinear(T, haystack, start_index, needle);
13551353
13561354 const haystack_bytes = sliceAsBytes(haystack);
......@@ -3368,13 +3366,7 @@ fn ReverseIterator(comptime T: type) type {
33683366
33693367/// Iterates over a slice in reverse.
33703368pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {
3371 const T = @TypeOf(slice);
3372 if (comptime trait.isPtrTo(.Array)(T)) {
3373 return .{ .ptr = slice, .index = slice.len };
3374 } else {
3375 comptime assert(trait.isSlice(T));
3376 return .{ .ptr = slice.ptr, .index = slice.len };
3377 }
3369 return .{ .ptr = slice.ptr, .index = slice.len };
33783370}
33793371
33803372test "reverseIterator" {
......@@ -3394,7 +3386,7 @@ test "reverseIterator" {
33943386 try testing.expectEqual(@as(?i32, null), it.next());
33953387
33963388 it = reverseIterator(slice);
3397 try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
3389 try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
33983390 try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
33993391 try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
34003392 try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
......@@ -3414,7 +3406,7 @@ test "reverseIterator" {
34143406 try testing.expectEqual(@as(?i32, null), it.next());
34153407
34163408 it = reverseIterator(ptr_to_array);
3417 try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
3409 try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
34183410 try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
34193411 try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
34203412 try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
......@@ -3730,11 +3722,7 @@ fn CopyPtrAttrs(
37303722}
37313723
37323724fn AsBytesReturnType(comptime P: type) type {
3733 if (!trait.isSingleItemPtr(P))
3734 @compileError("expected single item pointer, passed " ++ @typeName(P));
3735
3736 const size = @sizeOf(meta.Child(P));
3737
3725 const size = @sizeOf(std.meta.Child(P));
37383726 return CopyPtrAttrs(P, .One, [size]u8);
37393727}
37403728
......@@ -3818,21 +3806,13 @@ test "toBytes" {
38183806}
38193807
38203808fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
3821 const size = @as(usize, @sizeOf(T));
3822
3823 if (comptime !trait.is(.Pointer)(B) or
3824 (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))
3825 {
3826 @compileError(std.fmt.comptimePrint("expected *[{}]u8, passed " ++ @typeName(B), .{size}));
3827 }
3828
38293809 return CopyPtrAttrs(B, .One, T);
38303810}
38313811
38323812/// Given a pointer to an array of bytes, returns a pointer to a value of the specified type
38333813/// backed by those bytes, preserving pointer attributes.
38343814pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
3835 return @as(BytesAsValueReturnType(T, @TypeOf(bytes)), @ptrCast(bytes));
3815 return @ptrCast(bytes);
38363816}
38373817
38383818test "bytesAsValue" {
......@@ -3872,7 +3852,7 @@ test "bytesAsValue" {
38723852 .big => "\xA1\xDE\xEF\xBE",
38733853 };
38743854 const inst2 = bytesAsValue(S, inst_bytes);
3875 try testing.expect(meta.eql(inst, inst2.*));
3855 try testing.expect(std.meta.eql(inst, inst2.*));
38763856}
38773857
38783858test "bytesAsValue preserves pointer attributes" {
......@@ -3905,14 +3885,6 @@ test "bytesToValue" {
39053885}
39063886
39073887fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
3908 if (!(trait.isSlice(bytesType) or trait.isPtrTo(.Array)(bytesType)) or meta.Elem(bytesType) != u8) {
3909 @compileError("expected []u8 or *[_]u8, passed " ++ @typeName(bytesType));
3910 }
3911
3912 if (trait.isPtrTo(.Array)(bytesType) and @typeInfo(meta.Child(bytesType)).Array.len % @sizeOf(T) != 0) {
3913 @compileError("number of bytes in " ++ @typeName(bytesType) ++ " is not divisible by size of " ++ @typeName(T));
3914 }
3915
39163888 return CopyPtrAttrs(bytesType, .Slice, T);
39173889}
39183890
......@@ -4000,10 +3972,6 @@ test "bytesAsSlice preserves pointer attributes" {
40003972}
40013973
40023974fn SliceAsBytesReturnType(comptime Slice: type) type {
4003 if (!trait.isSlice(Slice) and !trait.isPtrTo(.Array)(Slice)) {
4004 @compileError("expected []T or *[_]T, passed " ++ @typeName(Slice));
4005 }
4006
40073975 return CopyPtrAttrs(Slice, .Slice, u8);
40083976}
40093977
......@@ -4012,15 +3980,15 @@ pub fn sliceAsBytes(slice: anytype) SliceAsBytesReturnType(@TypeOf(slice)) {
40123980 const Slice = @TypeOf(slice);
40133981
40143982 // a slice of zero-bit values always occupies zero bytes
4015 if (@sizeOf(meta.Elem(Slice)) == 0) return &[0]u8{};
3983 if (@sizeOf(std.meta.Elem(Slice)) == 0) return &[0]u8{};
40163984
40173985 // let's not give an undefined pointer to @ptrCast
40183986 // it may be equal to zero and fail a null check
4019 if (slice.len == 0 and comptime meta.sentinel(Slice) == null) return &[0]u8{};
3987 if (slice.len == 0 and std.meta.sentinel(Slice) == null) return &[0]u8{};
40203988
40213989 const cast_target = CopyPtrAttrs(Slice, .Many, u8);
40223990
4023 return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
3991 return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(std.meta.Elem(Slice))];
40243992}
40253993
40263994test "sliceAsBytes" {
lib/std/meta.zig+124-5
......@@ -5,7 +5,6 @@ const math = std.math;
55const testing = std.testing;
66const root = @import("root");
77
8pub const trait = @import("meta/trait.zig");
98pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags;
109
1110const Type = std.builtin.Type;
......@@ -135,7 +134,8 @@ test "std.meta.Elem" {
135134/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
136135/// or `null` if there is not one.
137136/// Types which cannot possibly have a sentinel will be a compile error.
138pub fn sentinel(comptime T: type) ?Elem(T) {
137/// Result is always comptime-known.
138pub inline fn sentinel(comptime T: type) ?Elem(T) {
139139 switch (@typeInfo(T)) {
140140 .Array => |info| {
141141 const sentinel_ptr = info.sentinel orelse return null;
......@@ -162,7 +162,7 @@ pub fn sentinel(comptime T: type) ?Elem(T) {
162162 @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
163163}
164164
165test "std.meta.sentinel" {
165test sentinel {
166166 try testSentinel();
167167 try comptime testSentinel();
168168}
......@@ -712,8 +712,6 @@ test "std.meta.activeTag" {
712712const TagPayloadType = TagPayload;
713713
714714pub fn TagPayloadByName(comptime U: type, comptime tag_name: []const u8) type {
715 comptime debug.assert(trait.is(.Union)(U));
716
717715 const info = @typeInfo(U).Union;
718716
719717 inline for (info.fields) |field_info| {
......@@ -1117,3 +1115,124 @@ test "isError" {
11171115 try std.testing.expect(isError(math.divTrunc(u8, 5, 0)));
11181116 try std.testing.expect(!isError(math.divTrunc(u8, 5, 5)));
11191117}
1118
1119/// Returns true if a type has a namespace and the namespace contains `name`;
1120/// `false` otherwise. Result is always comptime-known.
1121pub inline fn hasFn(comptime T: type, comptime name: []const u8) bool {
1122 switch (@typeInfo(T)) {
1123 .Struct, .Union, .Enum, .Opaque => {},
1124 else => return false,
1125 }
1126 if (!@hasDecl(T, name))
1127 return false;
1128
1129 return @typeInfo(@TypeOf(@field(T, name))) == .Fn;
1130}
1131
1132/// True if every value of the type `T` has a unique bit pattern representing it.
1133/// In other words, `T` has no unused bits and no padding.
1134/// Result is always comptime-known.
1135pub inline fn hasUniqueRepresentation(comptime T: type) bool {
1136 return switch (@typeInfo(T)) {
1137 else => false, // TODO can we know if it's true for some of these types ?
1138
1139 .AnyFrame,
1140 .Enum,
1141 .ErrorSet,
1142 .Fn,
1143 => true,
1144
1145 .Bool => false,
1146
1147 .Int => |info| @sizeOf(T) * 8 == info.bits,
1148
1149 .Pointer => |info| info.size != .Slice,
1150
1151 .Array => |info| hasUniqueRepresentation(info.child),
1152
1153 .Struct => |info| {
1154 var sum_size = @as(usize, 0);
1155
1156 inline for (info.fields) |field| {
1157 if (!hasUniqueRepresentation(field.type)) return false;
1158 sum_size += @sizeOf(field.type);
1159 }
1160
1161 return @sizeOf(T) == sum_size;
1162 },
1163
1164 .Vector => |info| hasUniqueRepresentation(info.child) and
1165 @sizeOf(T) == @sizeOf(info.child) * info.len,
1166 };
1167}
1168
1169test "hasUniqueRepresentation" {
1170 const TestStruct1 = struct {
1171 a: u32,
1172 b: u32,
1173 };
1174
1175 try testing.expect(hasUniqueRepresentation(TestStruct1));
1176
1177 const TestStruct2 = struct {
1178 a: u32,
1179 b: u16,
1180 };
1181
1182 try testing.expect(!hasUniqueRepresentation(TestStruct2));
1183
1184 const TestStruct3 = struct {
1185 a: u32,
1186 b: u32,
1187 };
1188
1189 try testing.expect(hasUniqueRepresentation(TestStruct3));
1190
1191 const TestStruct4 = struct { a: []const u8 };
1192
1193 try testing.expect(!hasUniqueRepresentation(TestStruct4));
1194
1195 const TestStruct5 = struct { a: TestStruct4 };
1196
1197 try testing.expect(!hasUniqueRepresentation(TestStruct5));
1198
1199 const TestUnion1 = packed union {
1200 a: u32,
1201 b: u16,
1202 };
1203
1204 try testing.expect(!hasUniqueRepresentation(TestUnion1));
1205
1206 const TestUnion2 = extern union {
1207 a: u32,
1208 b: u16,
1209 };
1210
1211 try testing.expect(!hasUniqueRepresentation(TestUnion2));
1212
1213 const TestUnion3 = union {
1214 a: u32,
1215 b: u16,
1216 };
1217
1218 try testing.expect(!hasUniqueRepresentation(TestUnion3));
1219
1220 const TestUnion4 = union(enum) {
1221 a: u32,
1222 b: u16,
1223 };
1224
1225 try testing.expect(!hasUniqueRepresentation(TestUnion4));
1226
1227 inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
1228 try testing.expect(hasUniqueRepresentation(T));
1229 }
1230 inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
1231 try testing.expect(!hasUniqueRepresentation(T));
1232 }
1233
1234 try testing.expect(!hasUniqueRepresentation([]u8));
1235 try testing.expect(!hasUniqueRepresentation([]const u8));
1236
1237 try testing.expect(hasUniqueRepresentation(@Vector(4, u16)));
1238}
lib/std/meta/trait.zig deleted-652
......@@ -1,652 +0,0 @@
1const std = @import("../std.zig");
2const mem = std.mem;
3const debug = std.debug;
4const testing = std.testing;
5
6const meta = @import("../meta.zig");
7
8pub const TraitFn = fn (type) bool;
9
10pub fn multiTrait(comptime traits: anytype) TraitFn {
11 const Closure = struct {
12 pub fn trait(comptime T: type) bool {
13 inline for (traits) |t|
14 if (!t(T)) return false;
15 return true;
16 }
17 };
18 return Closure.trait;
19}
20
21test "multiTrait" {
22 const Vector2 = struct {
23 const MyType = @This();
24
25 x: u8,
26 y: u8,
27
28 pub fn add(self: MyType, other: MyType) MyType {
29 return MyType{
30 .x = self.x + other.x,
31 .y = self.y + other.y,
32 };
33 }
34 };
35
36 const isVector = multiTrait(.{
37 hasFn("add"),
38 hasField("x"),
39 hasField("y"),
40 });
41 try testing.expect(isVector(Vector2));
42 try testing.expect(!isVector(u8));
43}
44
45pub fn hasFn(comptime name: []const u8) TraitFn {
46 const Closure = struct {
47 pub fn trait(comptime T: type) bool {
48 if (!comptime isContainer(T)) return false;
49 if (!comptime @hasDecl(T, name)) return false;
50 const DeclType = @TypeOf(@field(T, name));
51 return @typeInfo(DeclType) == .Fn;
52 }
53 };
54 return Closure.trait;
55}
56
57test "hasFn" {
58 const TestStruct = struct {
59 pub fn useless() void {}
60 };
61
62 try testing.expect(hasFn("useless")(TestStruct));
63 try testing.expect(!hasFn("append")(TestStruct));
64 try testing.expect(!hasFn("useless")(u8));
65}
66
67pub fn hasField(comptime name: []const u8) TraitFn {
68 const Closure = struct {
69 pub fn trait(comptime T: type) bool {
70 const fields = switch (@typeInfo(T)) {
71 .Struct => |s| s.fields,
72 .Union => |u| u.fields,
73 .Enum => |e| e.fields,
74 else => return false,
75 };
76
77 inline for (fields) |field| {
78 if (mem.eql(u8, field.name, name)) return true;
79 }
80
81 return false;
82 }
83 };
84 return Closure.trait;
85}
86
87test "hasField" {
88 const TestStruct = struct {
89 value: u32,
90 };
91
92 try testing.expect(hasField("value")(TestStruct));
93 try testing.expect(!hasField("value")(*TestStruct));
94 try testing.expect(!hasField("x")(TestStruct));
95 try testing.expect(!hasField("x")(**TestStruct));
96 try testing.expect(!hasField("value")(u8));
97}
98
99pub fn is(comptime id: std.builtin.TypeId) TraitFn {
100 const Closure = struct {
101 pub fn trait(comptime T: type) bool {
102 return id == @typeInfo(T);
103 }
104 };
105 return Closure.trait;
106}
107
108test "is" {
109 try testing.expect(is(.Int)(u8));
110 try testing.expect(!is(.Int)(f32));
111 try testing.expect(is(.Pointer)(*u8));
112 try testing.expect(is(.Void)(void));
113 try testing.expect(!is(.Optional)(anyerror));
114}
115
116pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn {
117 const Closure = struct {
118 pub fn trait(comptime T: type) bool {
119 if (!comptime isSingleItemPtr(T)) return false;
120 return id == @typeInfo(meta.Child(T));
121 }
122 };
123 return Closure.trait;
124}
125
126test "isPtrTo" {
127 try testing.expect(!isPtrTo(.Struct)(struct {}));
128 try testing.expect(isPtrTo(.Struct)(*struct {}));
129 try testing.expect(!isPtrTo(.Struct)(**struct {}));
130}
131
132pub fn isSliceOf(comptime id: std.builtin.TypeId) TraitFn {
133 const Closure = struct {
134 pub fn trait(comptime T: type) bool {
135 if (!comptime isSlice(T)) return false;
136 return id == @typeInfo(meta.Child(T));
137 }
138 };
139 return Closure.trait;
140}
141
142test "isSliceOf" {
143 try testing.expect(!isSliceOf(.Struct)(struct {}));
144 try testing.expect(isSliceOf(.Struct)([]struct {}));
145 try testing.expect(!isSliceOf(.Struct)([][]struct {}));
146}
147
148///////////Strait trait Fns
149
150//@TODO:
151// Somewhat limited since we can't apply this logic to normal variables, fields, or
152// Fns yet. Should be isExternType?
153pub fn isExtern(comptime T: type) bool {
154 return switch (@typeInfo(T)) {
155 .Struct => |s| s.layout == .Extern,
156 .Union => |u| u.layout == .Extern,
157 else => false,
158 };
159}
160
161test "isExtern" {
162 const TestExStruct = extern struct {};
163 const TestStruct = struct {};
164
165 try testing.expect(isExtern(TestExStruct));
166 try testing.expect(!isExtern(TestStruct));
167 try testing.expect(!isExtern(u8));
168}
169
170pub fn isPacked(comptime T: type) bool {
171 return switch (@typeInfo(T)) {
172 .Struct => |s| s.layout == .Packed,
173 .Union => |u| u.layout == .Packed,
174 else => false,
175 };
176}
177
178test "isPacked" {
179 const TestPStruct = packed struct {};
180 const TestStruct = struct {};
181
182 try testing.expect(isPacked(TestPStruct));
183 try testing.expect(!isPacked(TestStruct));
184 try testing.expect(!isPacked(u8));
185}
186
187pub fn isUnsignedInt(comptime T: type) bool {
188 return switch (@typeInfo(T)) {
189 .Int => |i| i.signedness == .unsigned,
190 else => false,
191 };
192}
193
194test "isUnsignedInt" {
195 try testing.expect(isUnsignedInt(u32) == true);
196 try testing.expect(isUnsignedInt(comptime_int) == false);
197 try testing.expect(isUnsignedInt(i64) == false);
198 try testing.expect(isUnsignedInt(f64) == false);
199}
200
201pub fn isSignedInt(comptime T: type) bool {
202 return switch (@typeInfo(T)) {
203 .ComptimeInt => true,
204 .Int => |i| i.signedness == .signed,
205 else => false,
206 };
207}
208
209test "isSignedInt" {
210 try testing.expect(isSignedInt(u32) == false);
211 try testing.expect(isSignedInt(comptime_int) == true);
212 try testing.expect(isSignedInt(i64) == true);
213 try testing.expect(isSignedInt(f64) == false);
214}
215
216pub fn isSingleItemPtr(comptime T: type) bool {
217 if (comptime is(.Pointer)(T)) {
218 return @typeInfo(T).Pointer.size == .One;
219 }
220 return false;
221}
222
223test "isSingleItemPtr" {
224 const array = [_]u8{0} ** 10;
225 try comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
226 try comptime testing.expect(!isSingleItemPtr(@TypeOf(array)));
227 var runtime_zero: usize = 0;
228 _ = &runtime_zero;
229 try testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1])));
230}
231
232pub fn isManyItemPtr(comptime T: type) bool {
233 if (comptime is(.Pointer)(T)) {
234 return @typeInfo(T).Pointer.size == .Many;
235 }
236 return false;
237}
238
239test "isManyItemPtr" {
240 const array = [_]u8{0} ** 10;
241 const mip = @as([*]const u8, @ptrCast(&array[0]));
242 try testing.expect(isManyItemPtr(@TypeOf(mip)));
243 try testing.expect(!isManyItemPtr(@TypeOf(array)));
244 try testing.expect(!isManyItemPtr(@TypeOf(array[0..1])));
245}
246
247pub fn isSlice(comptime T: type) bool {
248 if (comptime is(.Pointer)(T)) {
249 return @typeInfo(T).Pointer.size == .Slice;
250 }
251 return false;
252}
253
254test "isSlice" {
255 const array = [_]u8{0} ** 10;
256 var runtime_zero: usize = 0;
257 _ = &runtime_zero;
258 try testing.expect(isSlice(@TypeOf(array[runtime_zero..])));
259 try testing.expect(!isSlice(@TypeOf(array)));
260 try testing.expect(!isSlice(@TypeOf(&array[0])));
261}
262
263pub fn isIndexable(comptime T: type) bool {
264 if (comptime is(.Pointer)(T)) {
265 if (@typeInfo(T).Pointer.size == .One) {
266 return (comptime is(.Array)(meta.Child(T)));
267 }
268 return true;
269 }
270 return comptime is(.Array)(T) or is(.Vector)(T) or isTuple(T);
271}
272
273test "isIndexable" {
274 const array = [_]u8{0} ** 10;
275 const slice = @as([]const u8, &array);
276 const vector: @Vector(2, u32) = [_]u32{0} ** 2;
277 const tuple = .{ 1, 2, 3 };
278
279 try testing.expect(isIndexable(@TypeOf(array)));
280 try testing.expect(isIndexable(@TypeOf(&array)));
281 try testing.expect(isIndexable(@TypeOf(slice)));
282 try testing.expect(!isIndexable(meta.Child(@TypeOf(slice))));
283 try testing.expect(isIndexable(@TypeOf(vector)));
284 try testing.expect(isIndexable(@TypeOf(tuple)));
285}
286
287pub fn isNumber(comptime T: type) bool {
288 return switch (@typeInfo(T)) {
289 .Int, .Float, .ComptimeInt, .ComptimeFloat => true,
290 else => false,
291 };
292}
293
294test "isNumber" {
295 const NotANumber = struct {
296 number: u8,
297 };
298
299 try testing.expect(isNumber(u32));
300 try testing.expect(isNumber(f32));
301 try testing.expect(isNumber(u64));
302 try testing.expect(isNumber(@TypeOf(102)));
303 try testing.expect(isNumber(@TypeOf(102.123)));
304 try testing.expect(!isNumber([]u8));
305 try testing.expect(!isNumber(NotANumber));
306}
307
308pub fn isIntegral(comptime T: type) bool {
309 return switch (@typeInfo(T)) {
310 .Int, .ComptimeInt => true,
311 else => false,
312 };
313}
314
315test "isIntegral" {
316 try testing.expect(isIntegral(u32));
317 try testing.expect(!isIntegral(f32));
318 try testing.expect(isIntegral(@TypeOf(102)));
319 try testing.expect(!isIntegral(@TypeOf(102.123)));
320 try testing.expect(!isIntegral(*u8));
321 try testing.expect(!isIntegral([]u8));
322}
323
324pub fn isFloat(comptime T: type) bool {
325 return switch (@typeInfo(T)) {
326 .Float, .ComptimeFloat => true,
327 else => false,
328 };
329}
330
331test "isFloat" {
332 try testing.expect(!isFloat(u32));
333 try testing.expect(isFloat(f32));
334 try testing.expect(!isFloat(@TypeOf(102)));
335 try testing.expect(isFloat(@TypeOf(102.123)));
336 try testing.expect(!isFloat(*f64));
337 try testing.expect(!isFloat([]f32));
338}
339
340pub fn isConstPtr(comptime T: type) bool {
341 if (!comptime is(.Pointer)(T)) return false;
342 return @typeInfo(T).Pointer.is_const;
343}
344
345test "isConstPtr" {
346 var t: u8 = 0;
347 t = t;
348 const c: u8 = 0;
349 try testing.expect(isConstPtr(*const @TypeOf(t)));
350 try testing.expect(isConstPtr(@TypeOf(&c)));
351 try testing.expect(!isConstPtr(*@TypeOf(t)));
352 try testing.expect(!isConstPtr(@TypeOf(6)));
353}
354
355pub fn isContainer(comptime T: type) bool {
356 return switch (@typeInfo(T)) {
357 .Struct, .Union, .Enum, .Opaque => true,
358 else => false,
359 };
360}
361
362test "isContainer" {
363 const TestStruct = struct {};
364 const TestUnion = union {
365 a: void,
366 };
367 const TestEnum = enum {
368 A,
369 B,
370 };
371 const TestOpaque = opaque {};
372
373 try testing.expect(isContainer(TestStruct));
374 try testing.expect(isContainer(TestUnion));
375 try testing.expect(isContainer(TestEnum));
376 try testing.expect(isContainer(TestOpaque));
377 try testing.expect(!isContainer(u8));
378}
379
380pub fn isTuple(comptime T: type) bool {
381 return is(.Struct)(T) and @typeInfo(T).Struct.is_tuple;
382}
383
384test "isTuple" {
385 const t1 = struct {};
386 const t2 = .{ .a = 0 };
387 const t3 = .{ 1, 2, 3 };
388 try testing.expect(!isTuple(t1));
389 try testing.expect(!isTuple(@TypeOf(t2)));
390 try testing.expect(isTuple(@TypeOf(t3)));
391}
392
393/// Returns true if the passed type will coerce to []const u8.
394/// Any of the following are considered strings:
395/// ```
396/// []const u8, [:S]const u8, *const [N]u8, *const [N:S]u8,
397/// []u8, [:S]u8, *[:S]u8, *[N:S]u8.
398/// ```
399/// These types are not considered strings:
400/// ```
401/// u8, [N]u8, [*]const u8, [*:0]const u8,
402/// [*]const [N]u8, []const u16, []const i8,
403/// *const u8, ?[]const u8, ?*const [N]u8.
404/// ```
405pub fn isZigString(comptime T: type) bool {
406 return comptime blk: {
407 // Only pointer types can be strings, no optionals
408 const info = @typeInfo(T);
409 if (info != .Pointer) break :blk false;
410
411 const ptr = &info.Pointer;
412 // Check for CV qualifiers that would prevent coerction to []const u8
413 if (ptr.is_volatile or ptr.is_allowzero) break :blk false;
414
415 // If it's already a slice, simple check.
416 if (ptr.size == .Slice) {
417 break :blk ptr.child == u8;
418 }
419
420 // Otherwise check if it's an array type that coerces to slice.
421 if (ptr.size == .One) {
422 const child = @typeInfo(ptr.child);
423 if (child == .Array) {
424 const arr = &child.Array;
425 break :blk arr.child == u8;
426 }
427 }
428
429 break :blk false;
430 };
431}
432
433test "isZigString" {
434 try testing.expect(isZigString([]const u8));
435 try testing.expect(isZigString([]u8));
436 try testing.expect(isZigString([:0]const u8));
437 try testing.expect(isZigString([:0]u8));
438 try testing.expect(isZigString([:5]const u8));
439 try testing.expect(isZigString([:5]u8));
440 try testing.expect(isZigString(*const [0]u8));
441 try testing.expect(isZigString(*[0]u8));
442 try testing.expect(isZigString(*const [0:0]u8));
443 try testing.expect(isZigString(*[0:0]u8));
444 try testing.expect(isZigString(*const [0:5]u8));
445 try testing.expect(isZigString(*[0:5]u8));
446 try testing.expect(isZigString(*const [10]u8));
447 try testing.expect(isZigString(*[10]u8));
448 try testing.expect(isZigString(*const [10:0]u8));
449 try testing.expect(isZigString(*[10:0]u8));
450 try testing.expect(isZigString(*const [10:5]u8));
451 try testing.expect(isZigString(*[10:5]u8));
452
453 try testing.expect(!isZigString(u8));
454 try testing.expect(!isZigString([4]u8));
455 try testing.expect(!isZigString([4:0]u8));
456 try testing.expect(!isZigString([*]const u8));
457 try testing.expect(!isZigString([*]const [4]u8));
458 try testing.expect(!isZigString([*c]const u8));
459 try testing.expect(!isZigString([*c]const [4]u8));
460 try testing.expect(!isZigString([*:0]const u8));
461 try testing.expect(!isZigString([*:0]const u8));
462 try testing.expect(!isZigString(*[]const u8));
463 try testing.expect(!isZigString(?[]const u8));
464 try testing.expect(!isZigString(?*const [4]u8));
465 try testing.expect(!isZigString([]allowzero u8));
466 try testing.expect(!isZigString([]volatile u8));
467 try testing.expect(!isZigString(*allowzero [4]u8));
468 try testing.expect(!isZigString(*volatile [4]u8));
469}
470
471pub fn hasDecls(comptime T: type, comptime names: anytype) bool {
472 inline for (names) |name| {
473 if (!@hasDecl(T, name))
474 return false;
475 }
476 return true;
477}
478
479test "hasDecls" {
480 const TestStruct1 = struct {};
481 const TestStruct2 = struct {
482 pub var a: u32 = undefined;
483 pub var b: u32 = undefined;
484 c: bool,
485 pub fn useless() void {}
486 };
487
488 const tuple = .{ "a", "b", "c" };
489
490 try testing.expect(!hasDecls(TestStruct1, .{"a"}));
491 try testing.expect(hasDecls(TestStruct2, .{ "a", "b" }));
492 try testing.expect(hasDecls(TestStruct2, .{ "a", "b", "useless" }));
493 try testing.expect(!hasDecls(TestStruct2, .{ "a", "b", "c" }));
494 try testing.expect(!hasDecls(TestStruct2, tuple));
495}
496
497pub fn hasFields(comptime T: type, comptime names: anytype) bool {
498 inline for (names) |name| {
499 if (!@hasField(T, name))
500 return false;
501 }
502 return true;
503}
504
505test "hasFields" {
506 const TestStruct1 = struct {};
507 const TestStruct2 = struct {
508 a: u32,
509 b: u32,
510 c: bool,
511 pub fn useless() void {}
512 };
513
514 const tuple = .{ "a", "b", "c" };
515
516 try testing.expect(!hasFields(TestStruct1, .{"a"}));
517 try testing.expect(hasFields(TestStruct2, .{ "a", "b" }));
518 try testing.expect(hasFields(TestStruct2, .{ "a", "b", "c" }));
519 try testing.expect(hasFields(TestStruct2, tuple));
520 try testing.expect(!hasFields(TestStruct2, .{ "a", "b", "useless" }));
521}
522
523pub fn hasFunctions(comptime T: type, comptime names: anytype) bool {
524 inline for (names) |name| {
525 if (!hasFn(name)(T))
526 return false;
527 }
528 return true;
529}
530
531test "hasFunctions" {
532 const TestStruct1 = struct {};
533 const TestStruct2 = struct {
534 pub fn a() void {}
535 fn b() void {}
536 };
537
538 const tuple = .{ "a", "b", "c" };
539
540 try testing.expect(!hasFunctions(TestStruct1, .{"a"}));
541 try testing.expect(hasFunctions(TestStruct2, .{ "a", "b" }));
542 try testing.expect(!hasFunctions(TestStruct2, .{ "a", "b", "c" }));
543 try testing.expect(!hasFunctions(TestStruct2, tuple));
544}
545
546/// True if every value of the type `T` has a unique bit pattern representing it.
547/// In other words, `T` has no unused bits and no padding.
548pub fn hasUniqueRepresentation(comptime T: type) bool {
549 switch (@typeInfo(T)) {
550 else => return false, // TODO can we know if it's true for some of these types ?
551
552 .AnyFrame,
553 .Enum,
554 .ErrorSet,
555 .Fn,
556 => return true,
557
558 .Bool => return false,
559
560 .Int => |info| return @sizeOf(T) * 8 == info.bits,
561
562 .Pointer => |info| return info.size != .Slice,
563
564 .Array => |info| return comptime hasUniqueRepresentation(info.child),
565
566 .Struct => |info| {
567 var sum_size = @as(usize, 0);
568
569 inline for (info.fields) |field| {
570 const FieldType = field.type;
571 if (comptime !hasUniqueRepresentation(FieldType)) return false;
572 sum_size += @sizeOf(FieldType);
573 }
574
575 return @sizeOf(T) == sum_size;
576 },
577
578 .Vector => |info| return comptime hasUniqueRepresentation(info.child) and
579 @sizeOf(T) == @sizeOf(info.child) * info.len,
580 }
581}
582
583test "hasUniqueRepresentation" {
584 const TestStruct1 = struct {
585 a: u32,
586 b: u32,
587 };
588
589 try testing.expect(hasUniqueRepresentation(TestStruct1));
590
591 const TestStruct2 = struct {
592 a: u32,
593 b: u16,
594 };
595
596 try testing.expect(!hasUniqueRepresentation(TestStruct2));
597
598 const TestStruct3 = struct {
599 a: u32,
600 b: u32,
601 };
602
603 try testing.expect(hasUniqueRepresentation(TestStruct3));
604
605 const TestStruct4 = struct { a: []const u8 };
606
607 try testing.expect(!hasUniqueRepresentation(TestStruct4));
608
609 const TestStruct5 = struct { a: TestStruct4 };
610
611 try testing.expect(!hasUniqueRepresentation(TestStruct5));
612
613 const TestUnion1 = packed union {
614 a: u32,
615 b: u16,
616 };
617
618 try testing.expect(!hasUniqueRepresentation(TestUnion1));
619
620 const TestUnion2 = extern union {
621 a: u32,
622 b: u16,
623 };
624
625 try testing.expect(!hasUniqueRepresentation(TestUnion2));
626
627 const TestUnion3 = union {
628 a: u32,
629 b: u16,
630 };
631
632 try testing.expect(!hasUniqueRepresentation(TestUnion3));
633
634 const TestUnion4 = union(enum) {
635 a: u32,
636 b: u16,
637 };
638
639 try testing.expect(!hasUniqueRepresentation(TestUnion4));
640
641 inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
642 try testing.expect(hasUniqueRepresentation(T));
643 }
644 inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
645 try testing.expect(!hasUniqueRepresentation(T));
646 }
647
648 try testing.expect(!hasUniqueRepresentation([]u8));
649 try testing.expect(!hasUniqueRepresentation([]const u8));
650
651 try testing.expect(hasUniqueRepresentation(@Vector(4, u16)));
652}
lib/std/rand.zig+20-22
......@@ -3,8 +3,6 @@
33//! use `std.crypto.random`.
44//! Be sure to use a CSPRNG when required, otherwise using a normal PRNG will
55//! be faster and use substantially less stack space.
6//!
7//! TODO(tiehuis): Benchmark these against other reference implementations.
86
97const std = @import("std.zig");
108const builtin = @import("builtin");
......@@ -383,34 +381,34 @@ pub const Random = struct {
383381 /// This is useful for selecting an item from a slice where weights are not equal.
384382 /// `T` must be a numeric type capable of holding the sum of `proportions`.
385383 pub fn weightedIndex(r: std.rand.Random, comptime T: type, proportions: []const T) usize {
386 // This implementation works by summing the proportions and picking a random
387 // point in [0, sum). We then loop over the proportions, accumulating
388 // until our accumulator is greater than the random point.
389
390 var sum: T = 0;
391 for (proportions) |v| {
392 sum += v;
393 }
384 // This implementation works by summing the proportions and picking a
385 // random point in [0, sum). We then loop over the proportions,
386 // accumulating until our accumulator is greater than the random point.
387
388 const sum = s: {
389 var sum: T = 0;
390 for (proportions) |v| sum += v;
391 break :s sum;
392 };
394393
395 const point = if (comptime std.meta.trait.isSignedInt(T))
396 r.intRangeLessThan(T, 0, sum)
397 else if (comptime std.meta.trait.isUnsignedInt(T))
398 r.uintLessThan(T, sum)
399 else if (comptime std.meta.trait.isFloat(T))
394 const point = switch (@typeInfo(T)) {
395 .Int => |int_info| switch (int_info.signedness) {
396 .signed => r.intRangeLessThan(T, 0, sum),
397 .unsigned => r.uintLessThan(T, sum),
398 },
400399 // take care that imprecision doesn't lead to a value slightly greater than sum
401 @min(r.float(T) * sum, sum - std.math.floatEps(T))
402 else
403 @compileError("weightedIndex does not support proportions of type " ++ @typeName(T));
400 .Float => @min(r.float(T) * sum, sum - std.math.floatEps(T)),
401 else => @compileError("weightedIndex does not support proportions of type " ++
402 @typeName(T)),
403 };
404404
405 std.debug.assert(point < sum);
405 assert(point < sum);
406406
407407 var accumulator: T = 0;
408408 for (proportions, 0..) |p, index| {
409409 accumulator += p;
410410 if (point < accumulator) return index;
411 }
412
413 unreachable;
411 } else unreachable;
414412 }
415413
416414 /// Returns the smallest of `Index` and `usize`.
lib/std/target.zig-2
......@@ -823,7 +823,6 @@ pub const Target = struct {
823823
824824 /// Returns true if any specified feature is enabled.
825825 pub fn featureSetHasAny(set: Set, features: anytype) bool {
826 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
827826 inline for (features) |feature| {
828827 if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
829828 }
......@@ -832,7 +831,6 @@ pub const Target = struct {
832831
833832 /// Returns true if every specified feature is enabled.
834833 pub fn featureSetHasAll(set: Set, features: anytype) bool {
835 comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
836834 inline for (features) |feature| {
837835 if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
838836 }
src/link/Wasm/Object.zig+4-5
......@@ -838,11 +838,10 @@ fn ElementType(comptime ptr: type) type {
838838/// signedness of the given type `T`.
839839/// Asserts `T` is an integer.
840840fn readLeb(comptime T: type, reader: anytype) !T {
841 if (comptime std.meta.trait.isSignedInt(T)) {
842 return try leb.readILEB128(T, reader);
843 } else {
844 return try leb.readULEB128(T, reader);
845 }
841 return switch (@typeInfo(T).Int.signedness) {
842 .signed => try leb.readILEB128(T, reader),
843 .unsigned => try leb.readULEB128(T, reader),
844 };
846845}
847846
848847/// Reads an enum type from the given reader.
src/translate_c.zig+4-1
......@@ -4567,7 +4567,10 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
45674567}
45684568
45694569fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
4570 const fmt_s = if (comptime meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}";
4570 const fmt_s = switch (@typeInfo(@TypeOf(num))) {
4571 .Int, .ComptimeInt => "{d}",
4572 else => "{s}",
4573 };
45714574 const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num});
45724575 if (num_kind == .float)
45734576 return Tag.float_literal.create(c.arena, str)
test/behavior/vector.zig+10-2
......@@ -542,7 +542,11 @@ test "vector division operators" {
542542
543543 const S = struct {
544544 fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
545 if (!comptime std.meta.trait.isSignedInt(T)) {
545 const is_signed_int = switch (@typeInfo(T)) {
546 .Int => |info| info.signedness == .signed,
547 else => false,
548 };
549 if (!is_signed_int) {
546550 const d0 = x / y;
547551 for (@as([4]T, d0), 0..) |v, i| {
548552 try expect(x[i] / y[i] == v);
......@@ -563,7 +567,11 @@ test "vector division operators" {
563567 }
564568
565569 fn doTheTestMod(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
566 if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {
570 const is_signed_int = switch (@typeInfo(T)) {
571 .Int => |info| info.signedness == .signed,
572 else => false,
573 };
574 if (!is_signed_int and @typeInfo(T) != .Float) {
567575 const r0 = x % y;
568576 for (@as([4]T, r0), 0..) |v, i| {
569577 try expect(x[i] % y[i] == v);
test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig+30-2
......@@ -5,10 +5,38 @@ pub export fn entry() void {
55 _ = sliceAsBytes(ohnoes);
66 _ = &ohnoes;
77}
8fn sliceAsBytes(slice: anytype) std.meta.trait.isPtrTo(.Array)(@TypeOf(slice)) {}
8fn sliceAsBytes(slice: anytype) isPtrTo(.Array)(@TypeOf(slice)) {}
9
10pub const TraitFn = fn (type) bool;
11
12pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn {
13 const Closure = struct {
14 pub fn trait(comptime T: type) bool {
15 if (!comptime isSingleItemPtr(T)) return false;
16 return id == @typeInfo(std.meta.Child(T));
17 }
18 };
19 return Closure.trait;
20}
21
22pub fn isSingleItemPtr(comptime T: type) bool {
23 if (comptime is(.Pointer)(T)) {
24 return @typeInfo(T).Pointer.size == .One;
25 }
26 return false;
27}
28
29pub fn is(comptime id: std.builtin.TypeId) TraitFn {
30 const Closure = struct {
31 pub fn trait(comptime T: type) bool {
32 return id == @typeInfo(T);
33 }
34 };
35 return Closure.trait;
36}
937
1038// error
1139// backend=llvm
1240// target=native
1341//
14// :8:63: error: expected type 'type', found 'bool'
42// :8:48: error: expected type 'type', found 'bool'