diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-02-28 20:05:21 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-28 20:05:21 -0700 |
| commit | d5131e91eba9324eda3a2ae47eb2aa4530c87e83 (patch) | |
| tree | 62abf5656b3392f738d48f848d3fc64bbc60c19a /src | |
| parent | 157f66ec077ad02f08891bec1a426c0ffef98e09 (diff) | |
| download | zig-d5131e91eba9324eda3a2ae47eb2aa4530c87e83.tar.gz zig-d5131e91eba9324eda3a2ae47eb2aa4530c87e83.zip | |
Sema: complete the Type.hash function
Similar to how Type.eql was reworked in the previous commit, this commit
reworks Type.hash to check all the different kinds of tags that a Type
can be represented with. It also completes the implementation for all
types except error sets, which need to have Type.eql enhanced as well.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 4 | ||||
| -rw-r--r-- | src/type.zig | 290 | ||||
| -rw-r--r-- | src/value.zig | 16 |
3 files changed, 249 insertions, 61 deletions
diff --git a/src/Module.zig b/src/Module.zig index 8fed3138e7..847e78f1f2 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -157,8 +157,8 @@ const MonomorphedFuncsContext = struct { // The generic function Decl is guaranteed to be the first dependency // of each of its instantiations. const generic_owner_decl = key.owner_decl.dependencies.keys()[0]; - const generic_func = generic_owner_decl.val.castTag(.function).?.data; - std.hash.autoHash(&hasher, @ptrToInt(generic_func)); + const generic_func: *const Fn = generic_owner_decl.val.castTag(.function).?.data; + std.hash.autoHash(&hasher, generic_func); // This logic must be kept in sync with the logic in `analyzeCall` that // computes the hash. diff --git a/src/type.zig b/src/type.zig index 1c8e1bfa50..dbb5eb4ba3 100644 --- a/src/type.zig +++ b/src/type.zig @@ -847,51 +847,105 @@ pub const Type = extern union { } pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void { - const zig_type_tag = ty.zigTypeTag(); - std.hash.autoHash(hasher, zig_type_tag); - switch (zig_type_tag) { - .Type, - .Void, - .Bool, - .NoReturn, - .ComptimeFloat, - .ComptimeInt, - .Undefined, - .Null, - => {}, // The zig type tag is all that is needed to distinguish. + switch (ty.tag()) { + .generic_poison => unreachable, - .Pointer => { - const info = ty.ptrInfo().data; - hashWithHasher(info.pointee_type, hasher); - hashSentinel(info.sentinel, info.pointee_type, hasher); - std.hash.autoHash(hasher, info.@"align"); - std.hash.autoHash(hasher, info.@"addrspace"); - std.hash.autoHash(hasher, info.bit_offset); - std.hash.autoHash(hasher, info.host_size); - std.hash.autoHash(hasher, info.@"allowzero"); - std.hash.autoHash(hasher, info.mutable); - std.hash.autoHash(hasher, info.@"volatile"); - std.hash.autoHash(hasher, info.size); + .usize, + .isize, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + => |ty_tag| { + std.hash.autoHash(hasher, std.builtin.TypeId.Int); + std.hash.autoHash(hasher, ty_tag); }, - .Int => { - // Detect that e.g. u64 != usize, even if the bits match on a particular target. - if (ty.isNamedInt()) { - std.hash.autoHash(hasher, ty.tag()); - } else { - // Remaining cases are arbitrary sized integers. - // The target will not be branched upon, because we handled target-dependent cases above. - const info = ty.intInfo(@as(Target, undefined)); - std.hash.autoHash(hasher, info.signedness); - std.hash.autoHash(hasher, info.bits); - } + + .f16, + .f32, + .f64, + .f80, + .f128, + .c_longdouble, + => |ty_tag| { + std.hash.autoHash(hasher, std.builtin.TypeId.Float); + std.hash.autoHash(hasher, ty_tag); }, - .Array, .Vector => { - const elem_ty = ty.elemType(); - std.hash.autoHash(hasher, ty.arrayLen()); - hashWithHasher(elem_ty, hasher); - hashSentinel(ty.sentinel(), elem_ty, hasher); + + .bool => std.hash.autoHash(hasher, std.builtin.TypeId.Bool), + .void => std.hash.autoHash(hasher, std.builtin.TypeId.Void), + .type => std.hash.autoHash(hasher, std.builtin.TypeId.Type), + .comptime_int => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeInt), + .comptime_float => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeFloat), + .noreturn => std.hash.autoHash(hasher, std.builtin.TypeId.NoReturn), + .@"null" => std.hash.autoHash(hasher, std.builtin.TypeId.Null), + .@"undefined" => std.hash.autoHash(hasher, std.builtin.TypeId.Undefined), + + .@"anyopaque" => { + std.hash.autoHash(hasher, std.builtin.TypeId.Opaque); + std.hash.autoHash(hasher, Tag.@"anyopaque"); }, - .Fn => { + + .@"anyframe" => { + std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); + std.hash.autoHash(hasher, Tag.@"anyframe"); + }, + + .enum_literal => { + std.hash.autoHash(hasher, std.builtin.TypeId.EnumLiteral); + std.hash.autoHash(hasher, Tag.enum_literal); + }, + + .u1, + .u8, + .i8, + .u16, + .i16, + .u32, + .i32, + .u64, + .i64, + .u128, + .i128, + .int_signed, + .int_unsigned, + => { + // Arbitrary sized integers. The target will not be branched upon, + // because we handled target-dependent cases above. + std.hash.autoHash(hasher, std.builtin.TypeId.Int); + const info = ty.intInfo(@as(Target, undefined)); + std.hash.autoHash(hasher, info.signedness); + std.hash.autoHash(hasher, info.bits); + }, + + .error_set, + .error_set_single, + .anyerror, + .error_set_inferred, + .error_set_merged, + => { + std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); + // TODO implement this after revisiting Type.Eql for error sets + }, + + .@"opaque" => { + std.hash.autoHash(hasher, std.builtin.TypeId.Opaque); + const opaque_obj = ty.castTag(.@"opaque").?.data; + std.hash.autoHash(hasher, opaque_obj); + }, + + .fn_noreturn_no_args, + .fn_void_no_args, + .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, + .function, + => { + std.hash.autoHash(hasher, std.builtin.TypeId.Fn); + const fn_info = ty.fnInfo(); hashWithHasher(fn_info.return_type, hasher); std.hash.autoHash(hasher, fn_info.alignment); @@ -906,26 +960,150 @@ pub const Type = extern union { hashWithHasher(param_ty, hasher); } }, - .Optional => { + + .array, + .array_u8_sentinel_0, + .array_u8, + .array_sentinel, + => { + std.hash.autoHash(hasher, std.builtin.TypeId.Array); + + const elem_ty = ty.elemType(); + std.hash.autoHash(hasher, ty.arrayLen()); + hashWithHasher(elem_ty, hasher); + hashSentinel(ty.sentinel(), elem_ty, hasher); + }, + + .vector => { + std.hash.autoHash(hasher, std.builtin.TypeId.Vector); + + const elem_ty = ty.elemType(); + std.hash.autoHash(hasher, ty.vectorLen()); + hashWithHasher(elem_ty, hasher); + }, + + .single_const_pointer_to_comptime_int, + .const_slice_u8, + .const_slice_u8_sentinel_0, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .pointer, + .inferred_alloc_const, + .inferred_alloc_mut, + .manyptr_u8, + .manyptr_const_u8, + .manyptr_const_u8_sentinel_0, + => { + std.hash.autoHash(hasher, std.builtin.TypeId.Pointer); + + const info = ty.ptrInfo().data; + hashWithHasher(info.pointee_type, hasher); + hashSentinel(info.sentinel, info.pointee_type, hasher); + std.hash.autoHash(hasher, info.@"align"); + std.hash.autoHash(hasher, info.@"addrspace"); + std.hash.autoHash(hasher, info.bit_offset); + std.hash.autoHash(hasher, info.host_size); + std.hash.autoHash(hasher, info.@"allowzero"); + std.hash.autoHash(hasher, info.mutable); + std.hash.autoHash(hasher, info.@"volatile"); + std.hash.autoHash(hasher, info.size); + }, + + .optional, + .optional_single_const_pointer, + .optional_single_mut_pointer, + => { + std.hash.autoHash(hasher, std.builtin.TypeId.Optional); + var buf: Payload.ElemType = undefined; hashWithHasher(ty.optionalChild(&buf), hasher); }, - .Float => { - std.hash.autoHash(hasher, ty.tag()); + + .anyerror_void_error_union, .error_union => { + std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion); + + const set_ty = ty.errorUnionSet(); + hashWithHasher(set_ty, hasher); + + const payload_ty = ty.errorUnionPayload(); + hashWithHasher(payload_ty, hasher); }, - .Struct, - .ErrorUnion, - .ErrorSet, - .Enum, - .Union, - .BoundFn, - .Opaque, - .Frame, - .AnyFrame, - .EnumLiteral, - => { - // TODO implement more type hashing + + .anyframe_T => { + std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); + hashWithHasher(ty.childType(), hasher); + }, + + .empty_struct => { + std.hash.autoHash(hasher, std.builtin.TypeId.Struct); + const namespace: *const Module.Namespace = ty.castTag(.empty_struct).?.data; + std.hash.autoHash(hasher, namespace); + }, + .@"struct" => { + const struct_obj: *const Module.Struct = ty.castTag(.@"struct").?.data; + std.hash.autoHash(hasher, struct_obj); + }, + .tuple, .empty_struct_literal => { + std.hash.autoHash(hasher, std.builtin.TypeId.Struct); + + const tuple = ty.tupleFields(); + std.hash.autoHash(hasher, tuple.types.len); + + for (tuple.types) |field_ty, i| { + hashWithHasher(field_ty, hasher); + const field_val = tuple.values[i]; + if (field_val.tag() == .unreachable_value) continue; + field_val.hash(field_ty, hasher); + } + }, + + // we can't hash these based on tags because they wouldn't match the expanded version. + .call_options, + .prefetch_options, + .export_options, + .extern_options, + => unreachable, // needed to resolve the type before now + + .enum_full, .enum_nonexhaustive => { + const enum_obj: *const Module.EnumFull = ty.cast(Payload.EnumFull).?.data; + std.hash.autoHash(hasher, std.builtin.TypeId.Enum); + std.hash.autoHash(hasher, enum_obj); + }, + .enum_simple => { + const enum_obj: *const Module.EnumSimple = ty.cast(Payload.EnumSimple).?.data; + std.hash.autoHash(hasher, std.builtin.TypeId.Enum); + std.hash.autoHash(hasher, enum_obj); }, + .enum_numbered => { + const enum_obj: *const Module.EnumNumbered = ty.cast(Payload.EnumNumbered).?.data; + std.hash.autoHash(hasher, std.builtin.TypeId.Enum); + std.hash.autoHash(hasher, enum_obj); + }, + // we can't hash these based on tags because they wouldn't match the expanded version. + .atomic_order, + .atomic_rmw_op, + .calling_convention, + .address_space, + .float_mode, + .reduce_op, + => unreachable, // needed to resolve the type before now + + .@"union", .union_tagged => { + const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data; + std.hash.autoHash(hasher, std.builtin.TypeId.Union); + std.hash.autoHash(hasher, union_obj); + }, + // we can't hash these based on tags because they wouldn't match the expanded version. + .type_info => unreachable, // needed to resolve the type before now + + .bound_fn => unreachable, // TODO delete from the language + .var_args_param => unreachable, // can be any type } } diff --git a/src/value.zig b/src/value.zig index 51f678aaaa..a740a35b79 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2040,9 +2040,19 @@ pub const Value = extern union { } const fields = ty.structFields().values(); if (fields.len == 0) return; - const field_values = val.castTag(.@"struct").?.data; - for (field_values) |field_val, i| { - field_val.hash(fields[i].ty, hasher); + switch (val.tag()) { + .empty_struct_value => { + for (fields) |field| { + field.default_val.hash(field.ty, hasher); + } + }, + .@"struct" => { + const field_values = val.castTag(.@"struct").?.data; + for (field_values) |field_val, i| { + field_val.hash(fields[i].ty, hasher); + } + }, + else => unreachable, } }, .Optional => { |
