diff options
| author | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2022-03-08 20:44:58 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-03-10 14:20:16 -0700 |
| commit | 569870ca41e73c64d8dc9f1eccfef3529caf2266 (patch) | |
| tree | 8a4ec47628cacc1723efbff01ba36ebc147a86ad /src/type.zig | |
| parent | 0b82c02945c69e2e0465b5a4d9de471ea3c76d50 (diff) | |
| download | zig-569870ca41e73c64d8dc9f1eccfef3529caf2266.tar.gz zig-569870ca41e73c64d8dc9f1eccfef3529caf2266.zip | |
stage2: error_set_merged type equality
This implements type equality for error sets. This is done
through element-wise error set comparison.
Inferred error sets are always distinct types and other error sets are
always sorted. See #11022.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/src/type.zig b/src/type.zig index b0ff9e59e9..9126f1213b 100644 --- a/src/type.zig +++ b/src/type.zig @@ -564,27 +564,30 @@ pub const Type = extern union { => { if (b.zigTypeTag() != .ErrorSet) return false; - // TODO: revisit the language specification for how to evaluate equality - // for error set types. - - if (a.tag() == .anyerror and b.tag() == .anyerror) { - return true; + // inferred error sets are only equal if both are inferred + // and they originate from the exact same function. + if (a.castTag(.error_set_inferred)) |a_pl| { + if (b.castTag(.error_set_inferred)) |b_pl| { + return a_pl.data.func == b_pl.data.func; + } + return false; } - - if (a.tag() == .error_set and b.tag() == .error_set) { - return a.castTag(.error_set).?.data.owner_decl == b.castTag(.error_set).?.data.owner_decl; + if (b.tag() == .error_set_inferred) return false; + + // anyerror matches exactly. + const a_is_any = a.isAnyError(); + const b_is_any = b.isAnyError(); + if (a_is_any or b_is_any) return a_is_any and b_is_any; + + // two resolved sets match if their error set names match. + const a_set = a.errorSetNames(); + const b_set = b.errorSetNames(); + if (a_set.len != b_set.len) return false; + for (b_set) |b_val| { + if (!a.errorSetHasField(b_val)) return false; } - if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) { - return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data; - } - - if (a.tag() == .error_set_single and b.tag() == .error_set_single) { - const a_data = a.castTag(.error_set_single).?.data; - const b_data = b.castTag(.error_set_single).?.data; - return std.mem.eql(u8, a_data, b_data); - } - return false; + return true; }, .@"opaque" => { @@ -961,12 +964,30 @@ pub const Type = extern union { .error_set, .error_set_single, - .anyerror, - .error_set_inferred, .error_set_merged, => { + // all are treated like an "error set" for hashing + std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); + std.hash.autoHash(hasher, Tag.error_set); + + const names = ty.errorSetNames(); + std.hash.autoHash(hasher, names.len); + assert(std.sort.isSorted([]const u8, names, u8, std.mem.lessThan)); + for (names) |name| hasher.update(name); + }, + + .anyerror => { + // anyerror is distinct from other error sets std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); - // TODO implement this after revisiting Type.Eql for error sets + std.hash.autoHash(hasher, Tag.anyerror); + }, + + .error_set_inferred => { + // inferred error sets are compared using their data pointer + const data = ty.castTag(.error_set_inferred).?.data.func; + std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); + std.hash.autoHash(hasher, Tag.error_set_inferred); + std.hash.autoHash(hasher, data); }, .@"opaque" => { @@ -4365,6 +4386,9 @@ pub const Type = extern union { try names.put(arena, name, {}); } + // names must be sorted + Module.ErrorSet.sortNames(&names); + return try Tag.error_set_merged.create(arena, names); } |
