@@ -25,6 +25,32 @@ impl<'a> GenericSettersCtx<'a> {
2525 } )
2626 . collect ( ) ;
2727
28+ // Check for interdependent type parameters in generic bounds
29+ for param in generics. iter ( ) {
30+ if let syn:: GenericParam :: Type ( type_param) = param {
31+ let params_in_bounds =
32+ find_type_params_in_bounds ( & type_param. bounds , & type_param_idents) ;
33+ if params_in_bounds. len ( ) > 1
34+ || ( params_in_bounds. len ( ) == 1 && params_in_bounds[ 0 ] != & type_param. ident )
35+ {
36+ let params_str = params_in_bounds
37+ . iter ( )
38+ . map ( |p| format ! ( "`{p}`" ) )
39+ . collect :: < Vec < _ > > ( )
40+ . join ( ", " ) ;
41+ bail ! (
42+ & type_param. bounds,
43+ "generic conversion methods cannot be generated for interdependent type parameters; \
44+ the bounds on generic parameter `{}` reference other type parameters: {}\n \
45+ \n \
46+ Consider removing `generics(setters(...))` or restructuring your types to avoid interdependencies",
47+ type_param. ident,
48+ params_str
49+ ) ;
50+ }
51+ }
52+ }
53+
2854 // Check for interdependent type parameters in where clauses
2955 if let Some ( where_clause) = & self . base . generics . where_clause {
3056 for predicate in & where_clause. predicates {
@@ -253,6 +279,47 @@ impl<'a> GenericSettersCtx<'a> {
253279 }
254280}
255281
282+ fn find_type_params_in_bounds < ' b > (
283+ bounds : & syn:: punctuated:: Punctuated < syn:: TypeParamBound , syn:: token:: Plus > ,
284+ type_params : & ' b [ & ' b syn:: Ident ] ,
285+ ) -> Vec < & ' b syn:: Ident > {
286+ use syn:: visit:: Visit ;
287+
288+ struct TypeParamFinder < ' a > {
289+ type_params : & ' a [ & ' a syn:: Ident ] ,
290+ found : std:: collections:: HashSet < & ' a syn:: Ident > ,
291+ }
292+
293+ impl < ' ast > Visit < ' ast > for TypeParamFinder < ' _ > {
294+ fn visit_path ( & mut self , path : & ' ast syn:: Path ) {
295+ // Check if this path is one of our type parameters
296+ for & param in self . type_params {
297+ if path. is_ident ( param) {
298+ self . found . insert ( param) ;
299+ }
300+ }
301+ // Continue visiting nested paths
302+ syn:: visit:: visit_path ( self , path) ;
303+ }
304+ }
305+
306+ let mut finder = TypeParamFinder {
307+ type_params,
308+ found : std:: collections:: HashSet :: new ( ) ,
309+ } ;
310+
311+ for bound in bounds {
312+ finder. visit_type_param_bound ( bound) ;
313+ }
314+
315+ // Preserve the original order of type parameters for deterministic output
316+ type_params
317+ . iter ( )
318+ . filter ( |param| finder. found . contains ( * param) )
319+ . copied ( )
320+ . collect ( )
321+ }
322+
256323fn find_type_params_in_predicate < ' b > (
257324 predicate : & syn:: WherePredicate ,
258325 type_params : & ' b [ & ' b syn:: Ident ] ,
0 commit comments