| ... | ... | @@ -847,51 +847,105 @@ pub const Type = extern union { |
| 847 | 847 | } |
| 848 | 848 | |
| 849 | 849 | 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, |
| 862 | 852 | |
| 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); |
| 875 | 866 | }, |
| 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); |
| 887 | 877 | }, |
| 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"); |
| 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 | 949 | const fn_info = ty.fnInfo(); |
| 896 | 950 | hashWithHasher(fn_info.return_type, hasher); |
| 897 | 951 | std.hash.autoHash(hasher, fn_info.alignment); |
| ... | ... | @@ -906,26 +960,150 @@ pub const Type = extern union { |
| 906 | 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 | 1024 | var buf: Payload.ElemType = undefined; |
| 911 | 1025 | hashWithHasher(ty.optionalChild(&buf), hasher); |
| 912 | 1026 | }, |
| 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); |
| 915 | 1036 | }, |
| 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); |
| 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 | |