1+ use std:: iter:: once;
2+ use std:: mem:: take;
3+
14use proc_macro2:: { Span , TokenStream } ;
25use proc_macro_error:: emit_error;
36use quote:: { quote, ToTokens } ;
7+ use syn:: punctuated:: { Pair , Punctuated } ;
48use syn:: spanned:: Spanned ;
59use syn:: visit_mut:: VisitMut ;
610use syn:: {
7- parse_quote, parse_quote_spanned, token, visit_mut, FnArg , GenericParam , Ident , Lifetime , Pat ,
8- Receiver , ReturnType , Signature , Type , TypeImplTrait , TypeReference , WhereClause ,
11+ parse_quote, parse_quote_spanned, visit_mut, FnArg , GenericParam , Ident , Lifetime ,
12+ LifetimeParam , Pat , Receiver , ReturnType , Signature , Type , TypeImplTrait , TypeParam ,
13+ TypeParamBound , TypeReference , WherePredicate ,
914} ;
1015
1116use super :: lifetime;
1217
18+ fn type_is_generic ( ty : & Type , param : & TypeParam ) -> bool {
19+ match ty {
20+ Type :: Path ( path) => path. path . is_ident ( & param. ident ) ,
21+ _ => false ,
22+ }
23+ }
24+
1325#[ derive( Default ) ]
1426pub struct CollectArgs {
1527 needs_boxing : bool ,
@@ -99,48 +111,68 @@ impl HookSignature {
99111 ..
100112 } = sig;
101113
102- let hook_lifetime = {
103- let hook_lifetime = Lifetime :: new ( "'hook" , Span :: mixed_site ( ) ) ;
104- generics. params = {
105- let elided_lifetimes = & lifetimes. elided ;
106- let params = & generics. params ;
107-
108- parse_quote ! ( #hook_lifetime, #( #elided_lifetimes, ) * #params)
109- } ;
110-
111- let mut where_clause = generics
112- . where_clause
113- . clone ( )
114- . unwrap_or_else ( || WhereClause {
115- where_token : token:: Where {
116- span : Span :: mixed_site ( ) ,
117- } ,
118- predicates : Default :: default ( ) ,
119- } ) ;
114+ let hook_lifetime = Lifetime :: new ( "'hook" , Span :: mixed_site ( ) ) ;
115+ let mut params: Punctuated < _ , _ > = once ( hook_lifetime. clone ( ) )
116+ . chain ( lifetimes. elided )
117+ . map ( |lifetime| {
118+ GenericParam :: Lifetime ( LifetimeParam {
119+ attrs : vec ! [ ] ,
120+ lifetime,
121+ colon_token : None ,
122+ bounds : Default :: default ( ) ,
123+ } )
124+ } )
125+ . map ( |param| Pair :: new ( param, Some ( Default :: default ( ) ) ) )
126+ . chain ( take ( & mut generics. params ) . into_pairs ( ) )
127+ . collect ( ) ;
120128
121- for elided in lifetimes. elided . iter ( ) {
122- where_clause
123- . predicates
124- . push ( parse_quote ! ( #elided: #hook_lifetime) ) ;
125- }
129+ for type_param in params. iter_mut ( ) . skip ( 1 ) {
130+ match type_param {
131+ GenericParam :: Lifetime ( param) => {
132+ if let Some ( predicate) = generics
133+ . where_clause
134+ . iter_mut ( )
135+ . flat_map ( |c| & mut c. predicates )
136+ . find_map ( |predicate| match predicate {
137+ WherePredicate :: Lifetime ( p) if p. lifetime == param. lifetime => Some ( p) ,
138+ _ => None ,
139+ } )
140+ {
141+ predicate. bounds . push ( hook_lifetime. clone ( ) ) ;
142+ } else {
143+ param. colon_token = Some ( param. colon_token . unwrap_or_default ( ) ) ;
144+ param. bounds . push ( hook_lifetime. clone ( ) ) ;
145+ }
146+ }
126147
127- for explicit in lifetimes. explicit . iter ( ) {
128- where_clause
129- . predicates
130- . push ( parse_quote ! ( #explicit: #hook_lifetime) ) ;
131- }
148+ GenericParam :: Type ( param) => {
149+ if let Some ( predicate) = generics
150+ . where_clause
151+ . iter_mut ( )
152+ . flat_map ( |c| & mut c. predicates )
153+ . find_map ( |predicate| match predicate {
154+ WherePredicate :: Type ( p) if type_is_generic ( & p. bounded_ty , param) => {
155+ Some ( p)
156+ }
157+ _ => None ,
158+ } )
159+ {
160+ predicate
161+ . bounds
162+ . push ( TypeParamBound :: Lifetime ( hook_lifetime. clone ( ) ) ) ;
163+ } else {
164+ param. colon_token = Some ( param. colon_token . unwrap_or_default ( ) ) ;
165+ param
166+ . bounds
167+ . push ( TypeParamBound :: Lifetime ( hook_lifetime. clone ( ) ) ) ;
168+ }
169+ }
132170
133- for type_param in generics. type_params ( ) {
134- let type_param_ident = & type_param. ident ;
135- where_clause
136- . predicates
137- . push ( parse_quote ! ( #type_param_ident: #hook_lifetime) ) ;
171+ GenericParam :: Const ( _) => { }
138172 }
173+ }
139174
140- generics. where_clause = Some ( where_clause) ;
141-
142- hook_lifetime
143- } ;
175+ generics. params = params;
144176
145177 let ( output, output_type) = Self :: rewrite_return_type ( & hook_lifetime, return_type) ;
146178 sig. output = output;
@@ -165,7 +197,15 @@ impl HookSignature {
165197 self . sig
166198 . generics
167199 . lifetimes ( )
168- . map ( |life| parse_quote ! { & #life ( ) } )
200+ . map ( |life| TypeReference {
201+ and_token : Default :: default ( ) ,
202+ lifetime : Some ( life. lifetime . clone ( ) ) ,
203+ mutability : None ,
204+ elem : Box :: new ( Type :: Tuple ( syn:: TypeTuple {
205+ paren_token : Default :: default ( ) ,
206+ elems : Default :: default ( ) ,
207+ } ) ) ,
208+ } )
169209 . collect ( )
170210 }
171211
0 commit comments