authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 20:05:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 20:05:21-07:00
logd5131e91eba9324eda3a2ae47eb2aa4530c87e83
tree62abf5656b3392f738d48f848d3fc64bbc60c19a
parent157f66ec077ad02f08891bec1a426c0ffef98e09

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.

3 files changed, 249 insertions(+), 61 deletions(-)

src/Module.zig+2-2
......@@ -157,8 +157,8 @@ const MonomorphedFuncsContext = struct {
157157 // The generic function Decl is guaranteed to be the first dependency
158158 // of each of its instantiations.
159159 const generic_owner_decl = key.owner_decl.dependencies.keys()[0];
160 const generic_func = generic_owner_decl.val.castTag(.function).?.data;
161 std.hash.autoHash(&hasher, @ptrToInt(generic_func));
160 const generic_func: *const Fn = generic_owner_decl.val.castTag(.function).?.data;
161 std.hash.autoHash(&hasher, generic_func);
162162
163163 // This logic must be kept in sync with the logic in `analyzeCall` that
164164 // computes the hash.
src/type.zig+234-56
......@@ -847,51 +847,105 @@ pub const Type = extern union {
847847 }
848848
849849 pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void {
850 const zig_type_tag = ty.zigTypeTag();
851 std.hash.autoHash(hasher, zig_type_tag);
852 switch (zig_type_tag) {
853 .Type,
854 .Void,
855 .Bool,
856 .NoReturn,
857 .ComptimeFloat,
858 .ComptimeInt,
859 .Undefined,
860 .Null,
861 => {}, // The zig type tag is all that is needed to distinguish.
850 switch (ty.tag()) {
851 .generic_poison => unreachable,
862852
863 .Pointer => {
864 const info = ty.ptrInfo().data;
865 hashWithHasher(info.pointee_type, hasher);
866 hashSentinel(info.sentinel, info.pointee_type, hasher);
867 std.hash.autoHash(hasher, info.@"align");
868 std.hash.autoHash(hasher, info.@"addrspace");
869 std.hash.autoHash(hasher, info.bit_offset);
870 std.hash.autoHash(hasher, info.host_size);
871 std.hash.autoHash(hasher, info.@"allowzero");
872 std.hash.autoHash(hasher, info.mutable);
873 std.hash.autoHash(hasher, info.@"volatile");
874 std.hash.autoHash(hasher, info.size);
853 .usize,
854 .isize,
855 .c_short,
856 .c_ushort,
857 .c_int,
858 .c_uint,
859 .c_long,
860 .c_ulong,
861 .c_longlong,
862 .c_ulonglong,
863 => |ty_tag| {
864 std.hash.autoHash(hasher, std.builtin.TypeId.Int);
865 std.hash.autoHash(hasher, ty_tag);
875866 },
876 .Int => {
877 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
878 if (ty.isNamedInt()) {
879 std.hash.autoHash(hasher, ty.tag());
880 } else {
881 // Remaining cases are arbitrary sized integers.
882 // The target will not be branched upon, because we handled target-dependent cases above.
883 const info = ty.intInfo(@as(Target, undefined));
884 std.hash.autoHash(hasher, info.signedness);
885 std.hash.autoHash(hasher, info.bits);
886 }
867
868 .f16,
869 .f32,
870 .f64,
871 .f80,
872 .f128,
873 .c_longdouble,
874 => |ty_tag| {
875 std.hash.autoHash(hasher, std.builtin.TypeId.Float);
876 std.hash.autoHash(hasher, ty_tag);
887877 },
888 .Array, .Vector => {
889 const elem_ty = ty.elemType();
890 std.hash.autoHash(hasher, ty.arrayLen());
891 hashWithHasher(elem_ty, hasher);
892 hashSentinel(ty.sentinel(), elem_ty, hasher);
878
879 .bool => std.hash.autoHash(hasher, std.builtin.TypeId.Bool),
880 .void => std.hash.autoHash(hasher, std.builtin.TypeId.Void),
881 .type => std.hash.autoHash(hasher, std.builtin.TypeId.Type),
882 .comptime_int => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeInt),
883 .comptime_float => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeFloat),
884 .noreturn => std.hash.autoHash(hasher, std.builtin.TypeId.NoReturn),
885 .@"null" => std.hash.autoHash(hasher, std.builtin.TypeId.Null),
886 .@"undefined" => std.hash.autoHash(hasher, std.builtin.TypeId.Undefined),
887
888 .@"anyopaque" => {
889 std.hash.autoHash(hasher, std.builtin.TypeId.Opaque);
890 std.hash.autoHash(hasher, Tag.@"anyopaque");
893891 },
894 .Fn => {
892
893 .@"anyframe" => {
894 std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame);
895 std.hash.autoHash(hasher, Tag.@"anyframe");
896 },
897
898 .enum_literal => {
899 std.hash.autoHash(hasher, std.builtin.TypeId.EnumLiteral);
900 std.hash.autoHash(hasher, Tag.enum_literal);
901 },
902
903 .u1,
904 .u8,
905 .i8,
906 .u16,
907 .i16,
908 .u32,
909 .i32,
910 .u64,
911 .i64,
912 .u128,
913 .i128,
914 .int_signed,
915 .int_unsigned,
916 => {
917 // Arbitrary sized integers. The target will not be branched upon,
918 // because we handled target-dependent cases above.
919 std.hash.autoHash(hasher, std.builtin.TypeId.Int);
920 const info = ty.intInfo(@as(Target, undefined));
921 std.hash.autoHash(hasher, info.signedness);
922 std.hash.autoHash(hasher, info.bits);
923 },
924
925 .error_set,
926 .error_set_single,
927 .anyerror,
928 .error_set_inferred,
929 .error_set_merged,
930 => {
931 std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet);
932 // TODO implement this after revisiting Type.Eql for error sets
933 },
934
935 .@"opaque" => {
936 std.hash.autoHash(hasher, std.builtin.TypeId.Opaque);
937 const opaque_obj = ty.castTag(.@"opaque").?.data;
938 std.hash.autoHash(hasher, opaque_obj);
939 },
940
941 .fn_noreturn_no_args,
942 .fn_void_no_args,
943 .fn_naked_noreturn_no_args,
944 .fn_ccc_void_no_args,
945 .function,
946 => {
947 std.hash.autoHash(hasher, std.builtin.TypeId.Fn);
948
895949 const fn_info = ty.fnInfo();
896950 hashWithHasher(fn_info.return_type, hasher);
897951 std.hash.autoHash(hasher, fn_info.alignment);
......@@ -906,26 +960,150 @@ pub const Type = extern union {
906960 hashWithHasher(param_ty, hasher);
907961 }
908962 },
909 .Optional => {
963
964 .array,
965 .array_u8_sentinel_0,
966 .array_u8,
967 .array_sentinel,
968 => {
969 std.hash.autoHash(hasher, std.builtin.TypeId.Array);
970
971 const elem_ty = ty.elemType();
972 std.hash.autoHash(hasher, ty.arrayLen());
973 hashWithHasher(elem_ty, hasher);
974 hashSentinel(ty.sentinel(), elem_ty, hasher);
975 },
976
977 .vector => {
978 std.hash.autoHash(hasher, std.builtin.TypeId.Vector);
979
980 const elem_ty = ty.elemType();
981 std.hash.autoHash(hasher, ty.vectorLen());
982 hashWithHasher(elem_ty, hasher);
983 },
984
985 .single_const_pointer_to_comptime_int,
986 .const_slice_u8,
987 .const_slice_u8_sentinel_0,
988 .single_const_pointer,
989 .single_mut_pointer,
990 .many_const_pointer,
991 .many_mut_pointer,
992 .c_const_pointer,
993 .c_mut_pointer,
994 .const_slice,
995 .mut_slice,
996 .pointer,
997 .inferred_alloc_const,
998 .inferred_alloc_mut,
999 .manyptr_u8,
1000 .manyptr_const_u8,
1001 .manyptr_const_u8_sentinel_0,
1002 => {
1003 std.hash.autoHash(hasher, std.builtin.TypeId.Pointer);
1004
1005 const info = ty.ptrInfo().data;
1006 hashWithHasher(info.pointee_type, hasher);
1007 hashSentinel(info.sentinel, info.pointee_type, hasher);
1008 std.hash.autoHash(hasher, info.@"align");
1009 std.hash.autoHash(hasher, info.@"addrspace");
1010 std.hash.autoHash(hasher, info.bit_offset);
1011 std.hash.autoHash(hasher, info.host_size);
1012 std.hash.autoHash(hasher, info.@"allowzero");
1013 std.hash.autoHash(hasher, info.mutable);
1014 std.hash.autoHash(hasher, info.@"volatile");
1015 std.hash.autoHash(hasher, info.size);
1016 },
1017
1018 .optional,
1019 .optional_single_const_pointer,
1020 .optional_single_mut_pointer,
1021 => {
1022 std.hash.autoHash(hasher, std.builtin.TypeId.Optional);
1023
9101024 var buf: Payload.ElemType = undefined;
9111025 hashWithHasher(ty.optionalChild(&buf), hasher);
9121026 },
913 .Float => {
914 std.hash.autoHash(hasher, ty.tag());
1027
1028 .anyerror_void_error_union, .error_union => {
1029 std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion);
1030
1031 const set_ty = ty.errorUnionSet();
1032 hashWithHasher(set_ty, hasher);
1033
1034 const payload_ty = ty.errorUnionPayload();
1035 hashWithHasher(payload_ty, hasher);
9151036 },
916 .Struct,
917 .ErrorUnion,
918 .ErrorSet,
919 .Enum,
920 .Union,
921 .BoundFn,
922 .Opaque,
923 .Frame,
924 .AnyFrame,
925 .EnumLiteral,
926 => {
927 // TODO implement more type hashing
1037
1038 .anyframe_T => {
1039 std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame);
1040 hashWithHasher(ty.childType(), hasher);
1041 },
1042
1043 .empty_struct => {
1044 std.hash.autoHash(hasher, std.builtin.TypeId.Struct);
1045 const namespace: *const Module.Namespace = ty.castTag(.empty_struct).?.data;
1046 std.hash.autoHash(hasher, namespace);
1047 },
1048 .@"struct" => {
1049 const struct_obj: *const Module.Struct = ty.castTag(.@"struct").?.data;
1050 std.hash.autoHash(hasher, struct_obj);
1051 },
1052 .tuple, .empty_struct_literal => {
1053 std.hash.autoHash(hasher, std.builtin.TypeId.Struct);
1054
1055 const tuple = ty.tupleFields();
1056 std.hash.autoHash(hasher, tuple.types.len);
1057
1058 for (tuple.types) |field_ty, i| {
1059 hashWithHasher(field_ty, hasher);
1060 const field_val = tuple.values[i];
1061 if (field_val.tag() == .unreachable_value) continue;
1062 field_val.hash(field_ty, hasher);
1063 }
1064 },
1065
1066 // we can't hash these based on tags because they wouldn't match the expanded version.
1067 .call_options,
1068 .prefetch_options,
1069 .export_options,
1070 .extern_options,
1071 => unreachable, // needed to resolve the type before now
1072
1073 .enum_full, .enum_nonexhaustive => {
1074 const enum_obj: *const Module.EnumFull = ty.cast(Payload.EnumFull).?.data;
1075 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
1076 std.hash.autoHash(hasher, enum_obj);
1077 },
1078 .enum_simple => {
1079 const enum_obj: *const Module.EnumSimple = ty.cast(Payload.EnumSimple).?.data;
1080 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
1081 std.hash.autoHash(hasher, enum_obj);
9281082 },
1083 .enum_numbered => {
1084 const enum_obj: *const Module.EnumNumbered = ty.cast(Payload.EnumNumbered).?.data;
1085 std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
1086 std.hash.autoHash(hasher, enum_obj);
1087 },
1088 // we can't hash these based on tags because they wouldn't match the expanded version.
1089 .atomic_order,
1090 .atomic_rmw_op,
1091 .calling_convention,
1092 .address_space,
1093 .float_mode,
1094 .reduce_op,
1095 => unreachable, // needed to resolve the type before now
1096
1097 .@"union", .union_tagged => {
1098 const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;
1099 std.hash.autoHash(hasher, std.builtin.TypeId.Union);
1100 std.hash.autoHash(hasher, union_obj);
1101 },
1102 // we can't hash these based on tags because they wouldn't match the expanded version.
1103 .type_info => unreachable, // needed to resolve the type before now
1104
1105 .bound_fn => unreachable, // TODO delete from the language
1106 .var_args_param => unreachable, // can be any type
9291107 }
9301108 }
9311109
src/value.zig+13-3
......@@ -2040,9 +2040,19 @@ pub const Value = extern union {
20402040 }
20412041 const fields = ty.structFields().values();
20422042 if (fields.len == 0) return;
2043 const field_values = val.castTag(.@"struct").?.data;
2044 for (field_values) |field_val, i| {
2045 field_val.hash(fields[i].ty, hasher);
2043 switch (val.tag()) {
2044 .empty_struct_value => {
2045 for (fields) |field| {
2046 field.default_val.hash(field.ty, hasher);
2047 }
2048 },
2049 .@"struct" => {
2050 const field_values = val.castTag(.@"struct").?.data;
2051 for (field_values) |field_val, i| {
2052 field_val.hash(fields[i].ty, hasher);
2053 }
2054 },
2055 else => unreachable,
20462056 }
20472057 },
20482058 .Optional => {