diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index b765792a07..3d1d491675 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -181,18 +181,25 @@ fn typeContainsSlice(comptime K: type) bool { } } } + if (meta.trait.is(.Union)(K)) { + inline for (@typeInfo(K).Union.fields) |field| { + if (typeContainsSlice(field.field_type)) { + return true; + } + } + } return false; } } /// Provides generic hashing for any eligible type. /// Only hashes `key` itself, pointers are not followed. -/// Slices and structs containing slices are rejected to avoid ambiguity on the -/// user's intention. +/// Slices as well as unions and structs containing slices are rejected to avoid +/// ambiguity on the user's intention. pub fn autoHash(hasher: anytype, key: anytype) void { const Key = @TypeOf(key); if (comptime typeContainsSlice(Key)) { - @compileError("std.auto_hash.autoHash does not allow slices or structs containing slices here (" ++ @typeName(Key) ++ + @compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++ ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); } diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index 1c2f2df513..180e0b8664 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -530,10 +530,53 @@ test "std.meta.trait.hasUniqueRepresentation" { testing.expect(hasUniqueRepresentation(TestStruct3)); + const TestStruct4 = struct { + a: []const u8 + }; + + testing.expect(!hasUniqueRepresentation(TestStruct4)); + + const TestStruct5 = struct { + a: TestStruct4 + }; + + testing.expect(!hasUniqueRepresentation(TestStruct5)); + + const TestUnion1 = packed union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion1)); + + const TestUnion2 = extern union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion2)); + + const TestUnion3 = union { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion3)); + + const TestUnion4 = union(enum) { + a: u32, + b: u16, + }; + + testing.expect(!hasUniqueRepresentation(TestUnion4)); + inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| { testing.expect(hasUniqueRepresentation(T)); } inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| { testing.expect(!hasUniqueRepresentation(T)); } + + testing.expect(!hasUniqueRepresentation([]u8)); + testing.expect(!hasUniqueRepresentation([]const u8)); }