@@ -38,95 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
38
38
attrs
39
39
}
40
40
41
+ pub ( crate ) fn hash_stable_derive ( s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
42
+ hash_stable_derive_with_mode ( s, HashStableMode :: Normal )
43
+ }
44
+
41
45
pub ( crate ) fn hash_stable_generic_derive (
42
- mut s : synstructure:: Structure < ' _ > ,
46
+ s : synstructure:: Structure < ' _ > ,
43
47
) -> proc_macro2:: TokenStream {
44
- let generic: syn:: GenericParam = parse_quote ! ( __CTX) ;
45
- s. add_bounds ( synstructure:: AddBounds :: Generics ) ;
46
- s. add_impl_generic ( generic) ;
47
- s. add_where_predicate ( parse_quote ! { __CTX: crate :: HashStableContext } ) ;
48
+ hash_stable_derive_with_mode ( s, HashStableMode :: Generic )
49
+ }
48
50
49
- let discriminant = hash_stable_discriminant ( & mut s) ;
50
- let body = hash_stable_body ( & mut s) ;
51
+ pub ( crate ) fn hash_stable_no_context_derive (
52
+ s : synstructure:: Structure < ' _ > ,
53
+ ) -> proc_macro2:: TokenStream {
54
+ hash_stable_derive_with_mode ( s, HashStableMode :: NoContext )
55
+ }
51
56
52
- s. bound_impl (
53
- quote ! ( :: rustc_data_structures:: stable_hasher:: HashStable <__CTX>) ,
54
- quote ! {
55
- #[ inline]
56
- fn hash_stable(
57
- & self ,
58
- __hcx: & mut __CTX,
59
- __hasher: & mut :: rustc_data_structures:: stable_hasher:: StableHasher ) {
60
- #discriminant
61
- match * self { #body }
62
- }
63
- } ,
64
- )
57
+ enum HashStableMode {
58
+ // Use the query-system aware stable hashing context.
59
+ Normal ,
60
+ // Emit a generic implementation that uses a crate-local `StableHashingContext`
61
+ // trait, when the crate is upstream of `rustc_middle`.
62
+ Generic ,
63
+ // Emit a hash-stable implementation that takes no context,
64
+ // and emits per-field where clauses for (almost-)perfect derives.
65
+ NoContext ,
65
66
}
66
67
67
- pub ( crate ) fn hash_stable_no_context_derive (
68
+ fn hash_stable_derive_with_mode (
68
69
mut s : synstructure:: Structure < ' _ > ,
70
+ mode : HashStableMode ,
69
71
) -> proc_macro2:: TokenStream {
70
- let generic: syn:: GenericParam = parse_quote ! ( __CTX) ;
71
- s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
72
- s. add_impl_generic ( generic) ;
73
- let body = s. each ( |bi| {
74
- let attrs = parse_attributes ( bi. ast ( ) ) ;
75
- if attrs. ignore {
76
- quote ! { }
77
- } else if let Some ( project) = attrs. project {
78
- quote ! {
79
- ( & #bi. #project) . hash_stable( __hcx, __hasher) ;
80
- }
81
- } else {
82
- quote ! {
83
- #bi. hash_stable( __hcx, __hasher) ;
84
- }
85
- }
86
- } ) ;
87
-
88
- let discriminant = match s. ast ( ) . data {
89
- syn:: Data :: Enum ( _) => quote ! {
90
- :: std:: mem:: discriminant( self ) . hash_stable( __hcx, __hasher) ;
91
- } ,
92
- syn:: Data :: Struct ( _) => quote ! { } ,
93
- syn:: Data :: Union ( _) => panic ! ( "cannot derive on union" ) ,
72
+ let generic: syn:: GenericParam = match mode {
73
+ HashStableMode :: Normal => parse_quote ! ( ' __ctx) ,
74
+ HashStableMode :: Generic | HashStableMode :: NoContext => parse_quote ! ( __CTX) ,
94
75
} ;
95
76
96
- s . bound_impl (
97
- quote ! ( :: rustc_data_structures :: stable_hasher :: HashStable <__CTX> ) ,
98
- quote ! {
99
- # [ inline ]
100
- fn hash_stable (
101
- & self ,
102
- __hcx : & mut __CTX ,
103
- __hasher : & mut :: rustc_data_structures :: stable_hasher :: StableHasher ) {
104
- #discriminant
105
- match * self { #body }
106
- }
107
- } ,
108
- )
109
- }
77
+ // no_context impl is able to derive by-field, which is closer to a perfect derive.
78
+ s . add_bounds ( match mode {
79
+ HashStableMode :: Normal | HashStableMode :: Generic => synstructure :: AddBounds :: Generics ,
80
+ HashStableMode :: NoContext => synstructure :: AddBounds :: Fields ,
81
+ } ) ;
82
+
83
+ // For generic impl, add `where __CTX: HashStableContext`.
84
+ match mode {
85
+ HashStableMode :: Normal => { }
86
+ HashStableMode :: Generic => {
87
+ s . add_where_predicate ( parse_quote ! { __CTX : crate :: HashStableContext } ) ;
88
+ }
89
+ HashStableMode :: NoContext => { }
90
+ }
110
91
111
- pub ( crate ) fn hash_stable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
112
- let generic: syn:: GenericParam = parse_quote ! ( ' __ctx) ;
113
- s. add_bounds ( synstructure:: AddBounds :: Generics ) ;
114
92
s. add_impl_generic ( generic) ;
115
93
116
94
let discriminant = hash_stable_discriminant ( & mut s) ;
117
95
let body = hash_stable_body ( & mut s) ;
118
96
97
+ let context: syn:: Type = match mode {
98
+ HashStableMode :: Normal => {
99
+ parse_quote ! ( :: rustc_query_system:: ich:: StableHashingContext <' __ctx>)
100
+ }
101
+ HashStableMode :: Generic | HashStableMode :: NoContext => parse_quote ! ( __CTX) ,
102
+ } ;
103
+
119
104
s. bound_impl (
120
105
quote ! (
121
106
:: rustc_data_structures:: stable_hasher:: HashStable <
122
- :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
107
+ #context
123
108
>
124
109
) ,
125
110
quote ! {
126
111
#[ inline]
127
112
fn hash_stable(
128
113
& self ,
129
- __hcx: & mut :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
114
+ __hcx: & mut #context ,
130
115
__hasher: & mut :: rustc_data_structures:: stable_hasher:: StableHasher ) {
131
116
#discriminant
132
117
match * self { #body }
0 commit comments