From c7747c42c1e30e4b084645cb44948f1f5be21813 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 2 Sep 2025 10:48:15 +0000 Subject: [PATCH 1/2] Add missing lifetime replacement for generic param decls on `derive(IntoFuture)` impl block --- .../builder_derives/into_future.rs | 4 ++ .../integration/builder/attr_into_future.rs | 51 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/bon-macros/src/builder/builder_gen/builder_derives/into_future.rs b/bon-macros/src/builder/builder_gen/builder_derives/into_future.rs index ecd869ce..aa29ef22 100644 --- a/bon-macros/src/builder/builder_gen/builder_derives/into_future.rs +++ b/bon-macros/src/builder/builder_gen/builder_derives/into_future.rs @@ -163,6 +163,10 @@ impl BuilderGenCtx { original_lifetimes: &original_lifetimes, }; + for decl in &mut new_generics_decl { + replace_lifetimes.visit_generic_param_mut(decl); + } + let mut new_where_clause = where_clause.clone(); if let Some(where_clause) = &mut new_where_clause { diff --git a/bon/tests/integration/builder/attr_into_future.rs b/bon/tests/integration/builder/attr_into_future.rs index 171c0bc1..ed095e62 100644 --- a/bon/tests/integration/builder/attr_into_future.rs +++ b/bon/tests/integration/builder/attr_into_future.rs @@ -151,6 +151,30 @@ mod tests { let &Dummy = assert_send(builder).await; } + + #[tokio::test] + async fn complex_generics() { + struct Dummy; + + #[builder(derive(IntoFuture(Box)))] + async fn sut<'a: 'b, 'b, T: Sync + 'a + 'b, U: Sync + 'a, const N: usize>( + x1: &'a T, + x2: &'b U, + ) -> (&'a T, &'b U, usize) { + async {}.await; + (x1, x2, N) + } + + // Store the dummy struct in local variables to make sure no `'static` + // lifetime promotion happens + let local_x1 = Dummy; + let local_x2 = Dummy; + + let builder = sut::<_, _, 42>().x1(&local_x1).x2(&local_x2); + + let (&Dummy, &Dummy, usize) = assert_send(builder).await; + assert_eq!(usize, 42); + } } mod test_method { @@ -253,5 +277,32 @@ mod tests { let _: &Dummy = assert_send(builder).await; } + + #[tokio::test] + async fn complex_generics() { + struct Dummy; + + #[bon] + impl Dummy { + #[builder(derive(IntoFuture(Box)))] + async fn sut<'a: 'b, 'b, T: Sync + 'a + 'b, U: Sync + 'a, const N: usize>( + x1: &'a T, + x2: &'b U, + ) -> (&'a T, &'b U, usize) { + async {}.await; + (x1, x2, N) + } + } + + // Store the dummy struct in local variables to make sure no `'static` + // lifetime promotion happens + let local_x1 = Dummy; + let local_x2 = Dummy; + + let builder = Dummy::sut().x1(&local_x1).x2(&local_x2); + + let (&Dummy, &Dummy, usize) = assert_send(builder).await; + assert_eq!(usize, 42); + } } } From be64fea9979ef8aee9ca42b0ae3ee52f38dd47a9 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 2 Sep 2025 10:51:31 +0000 Subject: [PATCH 2/2] Fix test --- bon/tests/integration/builder/attr_into_future.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bon/tests/integration/builder/attr_into_future.rs b/bon/tests/integration/builder/attr_into_future.rs index ed095e62..a8b6d1d2 100644 --- a/bon/tests/integration/builder/attr_into_future.rs +++ b/bon/tests/integration/builder/attr_into_future.rs @@ -299,7 +299,7 @@ mod tests { let local_x1 = Dummy; let local_x2 = Dummy; - let builder = Dummy::sut().x1(&local_x1).x2(&local_x2); + let builder = Dummy::sut::<_, _, 42>().x1(&local_x1).x2(&local_x2); let (&Dummy, &Dummy, usize) = assert_send(builder).await; assert_eq!(usize, 42);