| ... | @@ -847,51 +847,105 @@ pub const Type = extern union { | ... | @@ -847,51 +847,105 @@ pub const Type = extern union { |
| 847 | } | 847 | } |
| 848 | | 848 | |
| 849 | pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void { | 849 | pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void { |
| 850 | const zig_type_tag = ty.zigTypeTag(); | 850 | switch (ty.tag()) { |
| 851 | std.hash.autoHash(hasher, zig_type_tag); | 851 | .generic_poison => unreachable, |
| 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. | | |
| 862 | | 852 | |
| 863 | .Pointer => { | 853 | .usize, |
| 864 | const info = ty.ptrInfo().data; | 854 | .isize, |
| 865 | hashWithHasher(info.pointee_type, hasher); | 855 | .c_short, |
| 866 | hashSentinel(info.sentinel, info.pointee_type, hasher); | 856 | .c_ushort, |
| 867 | std.hash.autoHash(hasher, info.@"align"); | 857 | .c_int, |
| 868 | std.hash.autoHash(hasher, info.@"addrspace"); | 858 | .c_uint, |
| 869 | std.hash.autoHash(hasher, info.bit_offset); | 859 | .c_long, |
| 870 | std.hash.autoHash(hasher, info.host_size); | 860 | .c_ulong, |
| 871 | std.hash.autoHash(hasher, info.@"allowzero"); | 861 | .c_longlong, |
| 872 | std.hash.autoHash(hasher, info.mutable); | 862 | .c_ulonglong, |
| 873 | std.hash.autoHash(hasher, info.@"volatile"); | 863 | => |ty_tag| { |
| 874 | std.hash.autoHash(hasher, info.size); | 864 | std.hash.autoHash(hasher, std.builtin.TypeId.Int); |
| | 865 | std.hash.autoHash(hasher, ty_tag); |
| 875 | }, | 866 | }, |
| 876 | .Int => { | 867 | |
| 877 | // Detect that e.g. u64 != usize, even if the bits match on a particular target. | 868 | .f16, |
| 878 | if (ty.isNamedInt()) { | 869 | .f32, |
| 879 | std.hash.autoHash(hasher, ty.tag()); | 870 | .f64, |
| 880 | } else { | 871 | .f80, |
| 881 | // Remaining cases are arbitrary sized integers. | 872 | .f128, |
| 882 | // The target will not be branched upon, because we handled target-dependent cases above. | 873 | .c_longdouble, |
| 883 | const info = ty.intInfo(@as(Target, undefined)); | 874 | => |ty_tag| { |
| 884 | std.hash.autoHash(hasher, info.signedness); | 875 | std.hash.autoHash(hasher, std.builtin.TypeId.Float); |
| 885 | std.hash.autoHash(hasher, info.bits); | 876 | std.hash.autoHash(hasher, ty_tag); |
| 886 | } | | |
| 887 | }, | 877 | }, |
| 888 | .Array, .Vector => { | 878 | |
| 889 | const elem_ty = ty.elemType(); | 879 | .bool => std.hash.autoHash(hasher, std.builtin.TypeId.Bool), |
| 890 | std.hash.autoHash(hasher, ty.arrayLen()); | 880 | .void => std.hash.autoHash(hasher, std.builtin.TypeId.Void), |
| 891 | hashWithHasher(elem_ty, hasher); | 881 | .type => std.hash.autoHash(hasher, std.builtin.TypeId.Type), |
| 892 | hashSentinel(ty.sentinel(), elem_ty, hasher); | 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"); |
| 893 | }, | 891 | }, |
| 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 | |
| 895 | const fn_info = ty.fnInfo(); | 949 | const fn_info = ty.fnInfo(); |
| 896 | hashWithHasher(fn_info.return_type, hasher); | 950 | hashWithHasher(fn_info.return_type, hasher); |
| 897 | std.hash.autoHash(hasher, fn_info.alignment); | 951 | std.hash.autoHash(hasher, fn_info.alignment); |
| ... | @@ -906,26 +960,150 @@ pub const Type = extern union { | ... | @@ -906,26 +960,150 @@ pub const Type = extern union { |
| 906 | hashWithHasher(param_ty, hasher); | 960 | hashWithHasher(param_ty, hasher); |
| 907 | } | 961 | } |
| 908 | }, | 962 | }, |
| 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 | |
| 910 | var buf: Payload.ElemType = undefined; | 1024 | var buf: Payload.ElemType = undefined; |
| 911 | hashWithHasher(ty.optionalChild(&buf), hasher); | 1025 | hashWithHasher(ty.optionalChild(&buf), hasher); |
| 912 | }, | 1026 | }, |
| 913 | .Float => { | 1027 | |
| 914 | std.hash.autoHash(hasher, ty.tag()); | 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); |
| 915 | }, | 1036 | }, |
| 916 | .Struct, | 1037 | |
| 917 | .ErrorUnion, | 1038 | .anyframe_T => { |
| 918 | .ErrorSet, | 1039 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); |
| 919 | .Enum, | 1040 | hashWithHasher(ty.childType(), hasher); |
| 920 | .Union, | 1041 | }, |
| 921 | .BoundFn, | 1042 | |
| 922 | .Opaque, | 1043 | .empty_struct => { |
| 923 | .Frame, | 1044 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); |
| 924 | .AnyFrame, | 1045 | const namespace: *const Module.Namespace = ty.castTag(.empty_struct).?.data; |
| 925 | .EnumLiteral, | 1046 | std.hash.autoHash(hasher, namespace); |
| 926 | => { | 1047 | }, |
| 927 | // TODO implement more type hashing | 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); |
| 928 | }, | 1082 | }, |
| | 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 |
| 929 | } | 1107 | } |
| 930 | } | 1108 | } |
| 931 | | 1109 | |