@@ -38,51 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
3838 attrs
3939}
4040
41+ pub ( crate ) fn hash_stable_derive ( s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
42+ hash_stable_derive_with_mode ( s, HashStableMode :: Normal )
43+ }
44+
4145pub ( crate ) fn hash_stable_generic_derive (
42- mut s : synstructure:: Structure < ' _ > ,
46+ s : synstructure:: Structure < ' _ > ,
4347) -> 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+ }
4850
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+ }
5156
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 ,
6566}
6667
67- pub ( crate ) fn hash_stable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
68- let generic: syn:: GenericParam = parse_quote ! ( ' __ctx) ;
69- s. add_bounds ( synstructure:: AddBounds :: Generics ) ;
68+ fn hash_stable_derive_with_mode (
69+ mut s : synstructure:: Structure < ' _ > ,
70+ mode : HashStableMode ,
71+ ) -> proc_macro2:: TokenStream {
72+ let generic: syn:: GenericParam = match mode {
73+ HashStableMode :: Normal => parse_quote ! ( ' __ctx) ,
74+ HashStableMode :: Generic | HashStableMode :: NoContext => parse_quote ! ( __CTX) ,
75+ } ;
76+
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+ }
91+
7092 s. add_impl_generic ( generic) ;
7193
7294 let discriminant = hash_stable_discriminant ( & mut s) ;
7395 let body = hash_stable_body ( & mut s) ;
7496
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+
75104 s. bound_impl (
76105 quote ! (
77106 :: rustc_data_structures:: stable_hasher:: HashStable <
78- :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
107+ #context
79108 >
80109 ) ,
81110 quote ! {
82111 #[ inline]
83112 fn hash_stable(
84113 & self ,
85- __hcx: & mut :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
114+ __hcx: & mut #context ,
86115 __hasher: & mut :: rustc_data_structures:: stable_hasher:: StableHasher ) {
87116 #discriminant
88117 match * self { #body }
0 commit comments