@@ -6,16 +6,35 @@ use proc_macro2::Span;
66use quote:: quote;
77use syn:: punctuated:: Punctuated ;
88use syn:: visit:: Visit ;
9- use syn:: GenericParam ;
10- use syn:: { BoundLifetimes , Ident , LifetimeParam } ;
9+ use syn:: visit_mut :: VisitMut ;
10+ use syn:: { BoundLifetimes , GenericParam , Ident , LifetimeParam } ;
1111use syn:: { Lifetime , Type } ;
1212
1313pub ( crate ) trait TypeExt {
14+ /// Check if the type includes macro invocations.
15+ ///
16+ /// Proc-macros cannot expand macros and peek into them, so if macro is involved sometimes special handling is required.
17+ fn has_macro ( & self ) -> bool ;
18+
1419 /// Get the list of unbound lifetimes referenced by the type.
1520 fn unbound_lifetimes ( & self ) -> BTreeSet < & Lifetime > ;
1621}
1722
1823impl TypeExt for Type {
24+ fn has_macro ( & self ) -> bool {
25+ struct HasMacro ( bool ) ;
26+
27+ impl < ' ast > Visit < ' ast > for HasMacro {
28+ fn visit_macro ( & mut self , _: & ' ast syn:: Macro ) {
29+ self . 0 = true ;
30+ }
31+ }
32+
33+ let mut visitor = HasMacro ( false ) ;
34+ visitor. visit_type ( self ) ;
35+ visitor. 0
36+ }
37+
1938 fn unbound_lifetimes ( & self ) -> BTreeSet < & Lifetime > {
2039 struct LifetimeVisitor < ' a > {
2140 bound : BTreeSet < & ' a Lifetime > ,
@@ -117,14 +136,62 @@ impl Binder<Type> {
117136 return self . value . clone ( ) ;
118137 }
119138
120- let bound = self . for_bound_4 ( ) ;
121- let bound_lt = bound. lifetimes . iter ( ) ;
122- let ty = & self . value ;
123- return syn:: Type :: Verbatim ( quote ! (
124- <:: pin_init:: __internal:: ForLtImpl <
125- dyn #bound :: pin_init:: __internal:: WithLt4 <#( #bound_lt, ) * Of = #ty>
126- > as :: pin_init:: __internal:: ForLt4 >:: Of <#lifetime, #lifetime, #lifetime, #lifetime>
127- ) ) ;
139+ // If the type has macro, we cannot peek into it. Use some different approach to replace
140+ // the type using GAT.
141+ if self . value . has_macro ( ) {
142+ let bound = self . for_bound_4 ( ) ;
143+ let bound_lt = bound. lifetimes . iter ( ) ;
144+ let ty = & self . value ;
145+ return syn:: Type :: Verbatim ( quote ! (
146+ <:: pin_init:: __internal:: ForLtImpl <
147+ dyn #bound :: pin_init:: __internal:: WithLt4 <#( #bound_lt, ) * Of = #ty>
148+ > as :: pin_init:: __internal:: ForLt4 >:: Of <#lifetime, #lifetime, #lifetime, #lifetime>
149+ ) ) ;
150+ }
151+
152+ struct LifetimeReplacer < ' a > {
153+ to_replace : BTreeSet < & ' a Lifetime > ,
154+ replacement : & ' a Lifetime ,
155+ }
156+
157+ impl VisitMut for LifetimeReplacer < ' _ > {
158+ fn visit_lifetime_mut ( & mut self , lt : & mut syn:: Lifetime ) {
159+ if self . to_replace . contains ( lt) {
160+ * lt = self . replacement . clone ( ) ;
161+ }
162+ }
163+
164+ fn visit_trait_bound_mut ( & mut self , bound : & mut syn:: TraitBound ) {
165+ // In case the type includes a lifetime binder, e.g. `dyn for<'a> Foo`,
166+ // temporarily remove them from to_replace if they're.
167+
168+ let mut removed = Vec :: new ( ) ;
169+ if let Some ( bound_lt) = & bound. lifetimes {
170+ for lt in & bound_lt. lifetimes {
171+ let GenericParam :: Lifetime ( lt) = lt else {
172+ continue ;
173+ } ;
174+ if let Some ( lt) = self . to_replace . take ( & lt. lifetime ) {
175+ removed. push ( lt) ;
176+ }
177+ }
178+ }
179+
180+ self . visit_path_mut ( & mut bound. path ) ;
181+
182+ for lt in removed {
183+ self . to_replace . insert ( lt) ;
184+ }
185+ }
186+ }
187+
188+ let mut ret = self . value . clone ( ) ;
189+ LifetimeReplacer {
190+ to_replace : self . bound . iter ( ) . collect ( ) ,
191+ replacement : lifetime,
192+ }
193+ . visit_type_mut ( & mut ret) ;
194+ ret
128195 }
129196}
130197
0 commit comments