Repository: rust-lang/rustfmt (rust)

Issue:
`feature(non_lifetime_binder)` syntax gets removed
the following code:
```rust
#![feature(non_lifetime_binders)]
#![allow(incomplete_features)]

trait Other<U: ?Sized> {}

trait Trait<U> 
where
    for<T> U: Other<T> {}
```
when formatted is:
```rust
#![feature(non_lifetime_binders)]
#![allow(incomplete_features)]

trait Other<U: ?Sized> {}

trait Trait<U>
where
    U: Other<T>,
{
}
```

Pull request:
Support non-lifetime binders
Makes it so we stop yeeting non-lifetime binders into the void. Rustfmt already generally supports formatting `ast::GenericParam` anyways, so this just is piggybacking on that formatting.

Fixes #5721

Patch:
diff --git a/src/closures.rs b/src/closures.rs
index c95e9a97..cf128752 100644
--- a/src/closures.rs
+++ b/src/closures.rs
@@ -12,7 +12,7 @@ use crate::overflow::OverflowableItem;
 use crate::rewrite::{Rewrite, RewriteContext};
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
-use crate::types::rewrite_lifetime_param;
+use crate::types::rewrite_bound_params;
 use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
 
 // This module is pretty messy because of the rules around closures and blocks:
@@ -246,7 +246,7 @@ fn rewrite_closure_fn_decl(
             "for<> ".to_owned()
         }
         ast::ClosureBinder::For { generic_params, .. } => {
-            let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?;
+            let lifetime_str = rewrite_bound_params(context, shape, generic_params)?;
             format!("for<{lifetime_str}> ")
         }
         ast::ClosureBinder::NotPresent => "".to_owned(),
diff --git a/src/types.rs b/src/types.rs
index 18a08f17..bb236a38 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -426,10 +426,10 @@ impl Rewrite for ast::WherePredicate {
             }) => {
                 let type_str = bounded_ty.rewrite(context, shape)?;
                 let colon = type_bound_colon(context).trim_end();
-                let lhs = if let Some(lifetime_str) =
-                    rewrite_lifetime_param(context, shape, bound_generic_params)
+                let lhs = if let Some(binder_str) =
+                    rewrite_bound_params(context, shape, bound_generic_params)
                 {
-                    format!("for<{}> {}{}", lifetime_str, type_str, colon)
+                    format!("for<{}> {}{}", binder_str, type_str, colon)
                 } else {
                     format!("{}{}", type_str, colon)
                 };
@@ -657,8 +657,7 @@ impl Rewrite for ast::GenericParam {
 
 impl Rewrite for ast::PolyTraitRef {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        if let Some(lifetime_str) =
-            rewrite_lifetime_param(context, shape, &self.bound_generic_params)
+        if let Some(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params)
         {
             // 6 is "for<> ".len()
             let extra_offset = lifetime_str.len() + 6;
@@ -881,8 +880,7 @@ fn rewrite_bare_fn(
 
     let mut result = String::with_capacity(128);
 
-    if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
-    {
+    if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &bare_fn.generic_params) {
         result.push_str("for<");
         // 6 = "for<> ".len(), 4 = "for<".
         // This doesn't work out so nicely for multiline situation with lots of
@@ -1122,16 +1120,15 @@ pub(crate) fn can_be_overflowed_type(
     }
 }
 
-/// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
-pub(crate) fn rewrite_lifetime_param(
+/// Returns `None` if there is no `GenericParam` in the list
+pub(crate) fn rewrite_bound_params(
     context: &RewriteContext<'_>,
     shape: Shape,
     generic_params: &[ast::GenericParam],
 ) -> Option<String> {
     let result = generic_params
         .iter()
-        .filter(|p| matches!(p.kind, ast::GenericParamKind::Lifetime))
-        .map(|lt| lt.rewrite(context, shape))
+        .map(|param| param.rewrite(context, shape))
         .collect::<Option<Vec<_>>>()?
         .join(", ");
     if result.is_empty() {


Test patch:
diff --git a/tests/source/issue_5721.rs b/tests/source/issue_5721.rs
new file mode 100644
index 00000000..e5ae9612
--- /dev/null
+++ b/tests/source/issue_5721.rs
@@ -0,0 +1,8 @@
+#![feature(non_lifetime_binders)]
+#![allow(incomplete_features)]
+
+trait Other<U: ?Sized> {}
+
+trait Trait<U> 
+where
+    for<T> U: Other<T> {}
diff --git a/tests/source/non-lifetime-binders.rs b/tests/source/non-lifetime-binders.rs
new file mode 100644
index 00000000..c26393c8
--- /dev/null
+++ b/tests/source/non-lifetime-binders.rs
@@ -0,0 +1,10 @@
+fn main() where for<'a, T: Sized + 'a, const C: usize> [&'a T; C]: Sized { 
+    let x = for<T> 
+    || {};
+
+    let y: dyn 
+    for<T> Into<T>;
+    
+    let z: for<T> 
+    fn(T);
+}
diff --git a/tests/target/issue_5721.rs b/tests/target/issue_5721.rs
new file mode 100644
index 00000000..d073b09c
--- /dev/null
+++ b/tests/target/issue_5721.rs
@@ -0,0 +1,10 @@
+#![feature(non_lifetime_binders)]
+#![allow(incomplete_features)]
+
+trait Other<U: ?Sized> {}
+
+trait Trait<U>
+where
+    for<T> U: Other<T>,
+{
+}
diff --git a/tests/target/non-lifetime-binders.rs b/tests/target/non-lifetime-binders.rs
new file mode 100644
index 00000000..ca6941a0
--- /dev/null
+++ b/tests/target/non-lifetime-binders.rs
@@ -0,0 +1,10 @@
+fn main()
+where
+    for<'a, T: Sized + 'a, const C: usize> [&'a T; C]: Sized,
+{
+    let x = for<T> || {};
+
+    let y: dyn for<T> Into<T>;
+
+    let z: for<T> fn(T);
+}