@@ -17,11 +17,24 @@ decl_derive!(
1717 [ GenericTypeVisitable ] => customizable_type_visitable_derive
1818) ;
1919
20- struct LiftedTy {
20+ struct TransformedTy {
2121 ty : syn:: Type ,
2222 generic_parameter_bounds : Vec < syn:: Ident > ,
2323}
2424
25+ enum TypeParameterPath {
26+ Interner ,
27+ GenericParameter ( syn:: Ident ) ,
28+ }
29+
30+ enum TypeParameterTransform {
31+ Continue ,
32+ Stop ,
33+ }
34+
35+ type TypeParameterVisitor =
36+ fn ( TypeParameterPath , & mut syn:: TypePath , & mut Vec < syn:: Ident > ) -> TypeParameterTransform ;
37+
2538fn has_ignore_attr ( attrs : & [ Attribute ] , name : & ' static str , meta : & ' static str ) -> bool {
2639 let mut ignored = false ;
2740 attrs. iter ( ) . for_each ( |attr| {
@@ -91,6 +104,9 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
91104
92105 s. add_where_predicate ( parse_quote ! { I : Interner } ) ;
93106 s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
107+ let generic_parameters =
108+ s. ast ( ) . generics . type_params ( ) . map ( |ty| ty. ident . clone ( ) ) . collect :: < Vec < _ > > ( ) ;
109+ let mut generic_parameter_bounds = vec ! [ ] ;
94110 s. bind_with ( |_| synstructure:: BindStyle :: Move ) ;
95111 let body_try_fold = s. each_variant ( |vi| {
96112 let bindings = vi. bindings ( ) ;
@@ -101,6 +117,12 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
101117 if has_ignore_attr ( & bind. ast ( ) . attrs , "type_foldable" , "identity" ) {
102118 bind. to_token_stream ( )
103119 } else {
120+ for param in
121+ type_foldable_generic_parameters ( bind. ast ( ) . ty . clone ( ) , & generic_parameters)
122+ {
123+ push_unique ( & mut generic_parameter_bounds, param) ;
124+ }
125+
104126 quote ! {
105127 :: rustc_type_ir:: TypeFoldable :: try_fold_with( #bind, __folder) ?
106128 }
@@ -129,6 +151,9 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
129151 // to generate code for them.
130152 s. filter ( |bi| !has_ignore_attr ( & bi. ast ( ) . attrs , "type_foldable" , "identity" ) ) ;
131153 s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
154+ for param in generic_parameter_bounds {
155+ s. add_where_predicate ( parse_quote ! { #param: :: rustc_type_ir:: TypeFoldable <I > } ) ;
156+ }
132157 s. bound_impl (
133158 quote ! ( :: rustc_type_ir:: TypeFoldable <I >) ,
134159 quote ! {
@@ -149,6 +174,19 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
149174 )
150175}
151176
177+ fn type_foldable_generic_parameters (
178+ ty : syn:: Type ,
179+ generic_parameters : & [ syn:: Ident ] ,
180+ ) -> Vec < syn:: Ident > {
181+ transform_type_parameters ( ty, generic_parameters, |path, _, generic_parameter_bounds| {
182+ if let TypeParameterPath :: GenericParameter ( param) = path {
183+ push_unique ( generic_parameter_bounds, param) ;
184+ }
185+ TypeParameterTransform :: Continue
186+ } )
187+ . generic_parameter_bounds
188+ }
189+
152190/// `Lift_Generic` is specialised for structs/enums parameterised by an interner
153191/// `I: Interner`. It derives `Lift<J>` by rewriting interner associated types
154192/// from `I::Assoc` to `J::Assoc`. The required associated type lift bounds are
@@ -251,40 +289,75 @@ fn is_type_phantom(ty: &syn::Type) -> bool {
251289 get_first_path_segment ( ty) . is_some_and ( |segment| segment. ident == "PhantomData" )
252290}
253291
254- fn lift ( mut ty : syn:: Type , generic_parameters : & [ syn:: Ident ] ) -> LiftedTy {
255- struct ItoJ < ' a > {
292+ fn lift ( ty : syn:: Type , generic_parameters : & [ syn:: Ident ] ) -> TransformedTy {
293+ transform_type_parameters ( ty, generic_parameters, |path, ty, generic_parameter_bounds| {
294+ match path {
295+ TypeParameterPath :: Interner => {
296+ * ty. path . segments . first_mut ( ) . unwrap ( ) = parse_quote ! { J } ;
297+ TypeParameterTransform :: Continue
298+ }
299+ TypeParameterPath :: GenericParameter ( param) => {
300+ push_unique ( generic_parameter_bounds, param. clone ( ) ) ;
301+ * ty = parse_quote ! { <#param as :: rustc_type_ir:: lift:: Lift <J >>:: Lifted } ;
302+ TypeParameterTransform :: Stop
303+ }
304+ }
305+ } )
306+ }
307+
308+ fn transform_type_parameters (
309+ mut ty : syn:: Type ,
310+ generic_parameters : & [ syn:: Ident ] ,
311+ visit : TypeParameterVisitor ,
312+ ) -> TransformedTy {
313+ struct TypeParameterTransformer < ' a > {
256314 generic_parameters : & ' a [ syn:: Ident ] ,
257315 generic_parameter_bounds : Vec < syn:: Ident > ,
316+ visit : TypeParameterVisitor ,
258317 }
259318
260- impl VisitMut for ItoJ < ' _ > {
319+ impl VisitMut for TypeParameterTransformer < ' _ > {
261320 fn visit_type_path_mut ( & mut self , i : & mut syn:: TypePath ) {
262- if i. qself . is_none ( ) {
321+ let path = if i. qself . is_none ( ) {
263322 let segments_len = i. path . segments . len ( ) ;
264- if let Some ( first) = i. path . segments . first_mut ( ) {
265- // Turn paths from `I` into `J`
323+ i. path . segments . first ( ) . and_then ( |first| {
266324 if first. ident == "I" {
267- * first = parse_quote ! { J } ;
325+ Some ( TypeParameterPath :: Interner )
268326 } else if segments_len == 1
269327 && matches ! ( first. arguments, syn:: PathArguments :: None )
270328 && self . generic_parameters . iter ( ) . any ( |param| first. ident == * param)
271329 {
272- let ident = first. ident . clone ( ) ;
273- if !self . generic_parameter_bounds . iter ( ) . any ( |param| * param == ident) {
274- self . generic_parameter_bounds . push ( ident. clone ( ) ) ;
275- }
276-
277- * i = parse_quote ! { <#ident as :: rustc_type_ir:: lift:: Lift <J >>:: Lifted } ;
278- return ;
330+ Some ( TypeParameterPath :: GenericParameter ( first. ident . clone ( ) ) )
331+ } else {
332+ None
279333 }
334+ } )
335+ } else {
336+ None
337+ } ;
338+
339+ if let Some ( path) = path {
340+ if let TypeParameterTransform :: Stop =
341+ ( self . visit ) ( path, i, & mut self . generic_parameter_bounds )
342+ {
343+ return ;
280344 }
281345 }
346+
282347 syn:: visit_mut:: visit_type_path_mut ( self , i) ;
283348 }
284349 }
285- let mut visitor = ItoJ { generic_parameters, generic_parameter_bounds : Vec :: new ( ) } ;
350+
351+ let mut visitor =
352+ TypeParameterTransformer { generic_parameters, generic_parameter_bounds : vec ! [ ] , visit } ;
286353 visitor. visit_type_mut ( & mut ty) ;
287- LiftedTy { ty, generic_parameter_bounds : visitor. generic_parameter_bounds }
354+ TransformedTy { ty, generic_parameter_bounds : visitor. generic_parameter_bounds }
355+ }
356+
357+ fn push_unique ( params : & mut Vec < syn:: Ident > , param : syn:: Ident ) {
358+ if !params. iter ( ) . any ( |prev| * prev == param) {
359+ params. push ( param) ;
360+ }
288361}
289362
290363#[ cfg( not( feature = "nightly" ) ) ]
0 commit comments