Parse `for<'a> [const]`

And also refactor parsing of HRTB.
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 4e87774..7990a64 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -960,37 +960,28 @@
         impl_trait_lower_fn: ImplTraitLowerFn<'_>,
     ) -> TypeBound {
         match node.kind() {
-            ast::TypeBoundKind::PathType(path_type) => {
-                let m = match node.question_mark_token() {
-                    Some(_) => TraitBoundModifier::Maybe,
-                    None => TraitBoundModifier::None,
-                };
-                self.lower_path_type(&path_type, impl_trait_lower_fn)
-                    .map(|p| {
-                        TypeBound::Path(self.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
-                    })
-                    .unwrap_or(TypeBound::Error)
-            }
-            ast::TypeBoundKind::ForType(for_type) => {
-                let lt_refs = match for_type.generic_param_list() {
+            ast::TypeBoundKind::PathType(binder, path_type) => {
+                let binder = match binder.and_then(|it| it.generic_param_list()) {
                     Some(gpl) => gpl
                         .lifetime_params()
                         .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
                         .collect(),
                     None => ThinVec::default(),
                 };
-                let path = for_type.ty().and_then(|ty| match &ty {
-                    ast::Type::PathType(path_type) => {
-                        self.lower_path_type(path_type, impl_trait_lower_fn).map(|p| (p, ty))
-                    }
-                    _ => None,
-                });
-                match path {
-                    Some((p, ty)) => {
-                        TypeBound::ForLifetime(lt_refs, self.alloc_path(p, AstPtr::new(&ty)))
-                    }
-                    None => TypeBound::Error,
-                }
+                let m = match node.question_mark_token() {
+                    Some(_) => TraitBoundModifier::Maybe,
+                    None => TraitBoundModifier::None,
+                };
+                self.lower_path_type(&path_type, impl_trait_lower_fn)
+                    .map(|p| {
+                        let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
+                        if binder.is_empty() {
+                            TypeBound::Path(path, m)
+                        } else {
+                            TypeBound::ForLifetime(binder, path)
+                        }
+                    })
+                    .unwrap_or(TypeBound::Error)
             }
             ast::TypeBoundKind::Use(gal) => TypeBound::Use(
                 gal.use_bound_generic_args()
diff --git a/crates/hir-def/src/expr_store/lower/generics.rs b/crates/hir-def/src/expr_store/lower/generics.rs
index 02a1d27..c570df4 100644
--- a/crates/hir-def/src/expr_store/lower/generics.rs
+++ b/crates/hir-def/src/expr_store/lower/generics.rs
@@ -180,17 +180,18 @@
                 continue;
             };
 
-            let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
-                // Higher-Ranked Trait Bounds
-                param_list
-                    .lifetime_params()
-                    .map(|lifetime_param| {
-                        lifetime_param
-                            .lifetime()
-                            .map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
-                    })
-                    .collect()
-            });
+            let lifetimes: Option<Box<_>> =
+                pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| {
+                    // Higher-Ranked Trait Bounds
+                    param_list
+                        .lifetime_params()
+                        .map(|lifetime_param| {
+                            lifetime_param
+                                .lifetime()
+                                .map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
+                        })
+                        .collect()
+                });
             for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
                 self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target);
             }
diff --git a/crates/ide/src/inlay_hints/lifetime.rs b/crates/ide/src/inlay_hints/lifetime.rs
index 0069452..49fec0a 100644
--- a/crates/ide/src/inlay_hints/lifetime.rs
+++ b/crates/ide/src/inlay_hints/lifetime.rs
@@ -77,17 +77,18 @@
         return None;
     }
 
-    let parent_for_type = func
+    let parent_for_binder = func
         .syntax()
         .ancestors()
         .skip(1)
         .take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
-        .find_map(ast::ForType::cast);
+        .find_map(ast::ForType::cast)
+        .and_then(|it| it.for_binder());
 
     let param_list = func.param_list()?;
-    let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
+    let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
     let ret_type = func.ret_type();
-    let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
+    let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
     hints_(
         acc,
         ctx,
@@ -143,15 +144,16 @@
 
     // FIXME: Support general path types
     let (param_list, ret_type) = func.path().as_ref().and_then(path_as_fn)?;
-    let parent_for_type = func
+    let parent_for_binder = func
         .syntax()
         .ancestors()
         .skip(1)
         .take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
-        .find_map(ast::ForType::cast);
+        .find_map(ast::ForType::cast)
+        .and_then(|it| it.for_binder());
 
-    let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
-    let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
+    let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
+    let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
     hints_(
         acc,
         ctx,
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index 7665656..ed8a91c 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -572,9 +572,7 @@
     // test closure_binder
     // fn main() { for<'a> || (); }
     if p.at(T![for]) {
-        let b = p.start();
         types::for_binder(p);
-        b.complete(p, CLOSURE_BINDER);
     }
     // test const_closure
     // fn main() { let cl = const || _ = 0; }
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs
index 55c5dc4..cb1b59f 100644
--- a/crates/parser/src/grammar/generic_params.rs
+++ b/crates/parser/src/grammar/generic_params.rs
@@ -13,7 +13,7 @@
 
 // test_err generic_param_list_recover
 // fn f<T: Clone,, U:, V>() {}
-fn generic_param_list(p: &mut Parser<'_>) {
+pub(super) fn generic_param_list(p: &mut Parser<'_>) {
     assert!(p.at(T![<]));
     let m = p.start();
     delimited(
@@ -147,7 +147,15 @@
     let has_paren = p.eat(T!['(']);
     match p.current() {
         LIFETIME_IDENT => lifetime(p),
-        T![for] => types::for_type(p, false),
+        // test for_binder_bound
+        // fn foo<T: for<'a> [const] async Trait>() {}
+        T![for] => {
+            types::for_binder(p);
+            if path_type_bound(p).is_err() {
+                m.abandon(p);
+                return false;
+            }
+        }
         // test precise_capturing
         // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
 
@@ -180,44 +188,8 @@
             p.bump_any();
             types::for_type(p, false)
         }
-        current => {
-            match current {
-                T![?] => p.bump_any(),
-                T![~] => {
-                    p.bump_any();
-                    p.expect(T![const]);
-                }
-                T!['['] => {
-                    p.bump_any();
-                    p.expect(T![const]);
-                    p.expect(T![']']);
-                }
-                // test const_trait_bound
-                // const fn foo(_: impl const Trait) {}
-                T![const] => {
-                    p.bump_any();
-                }
-                // test async_trait_bound
-                // fn async_foo(_: impl async Fn(&i32)) {}
-                T![async] => {
-                    p.bump_any();
-                }
-                _ => (),
-            }
-            if paths::is_use_path_start(p) {
-                types::path_type_bounds(p, false);
-                // test_err type_bounds_macro_call_recovery
-                // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
-                if p.at(T![!]) {
-                    let m = p.start();
-                    p.bump(T![!]);
-                    p.error("unexpected `!` in type path, macro calls are not allowed here");
-                    if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
-                        items::token_tree(p);
-                    }
-                    m.complete(p, ERROR);
-                }
-            } else {
+        _ => {
+            if path_type_bound(p).is_err() {
                 m.abandon(p);
                 return false;
             }
@@ -231,6 +203,43 @@
     true
 }
 
+fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> {
+    if p.eat(T![~]) {
+        p.expect(T![const]);
+    } else if p.eat(T!['[']) {
+        // test maybe_const_trait_bound
+        // const fn foo(_: impl [const] Trait) {}
+        p.expect(T![const]);
+        p.expect(T![']']);
+    } else {
+        // test const_trait_bound
+        // const fn foo(_: impl const Trait) {}
+        p.eat(T![const]);
+    }
+    // test async_trait_bound
+    // fn async_foo(_: impl async Fn(&i32)) {}
+    p.eat(T![async]);
+    p.eat(T![?]);
+
+    if paths::is_use_path_start(p) {
+        types::path_type_bounds(p, false);
+        // test_err type_bounds_macro_call_recovery
+        // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
+        if p.at(T![!]) {
+            let m = p.start();
+            p.bump(T![!]);
+            p.error("unexpected `!` in type path, macro calls are not allowed here");
+            if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
+                items::token_tree(p);
+            }
+            m.complete(p, ERROR);
+        }
+        Ok(())
+    } else {
+        Err(())
+    }
+}
+
 // test where_clause
 // fn foo()
 // where
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 908440b..a7e97c5 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -249,13 +249,14 @@
 }
 
 pub(super) fn for_binder(p: &mut Parser<'_>) {
-    assert!(p.at(T![for]));
+    let m = p.start();
     p.bump(T![for]);
     if p.at(T![<]) {
-        generic_params::opt_generic_param_list(p);
+        generic_params::generic_param_list(p);
     } else {
         p.error("expected `<`");
     }
+    m.complete(p, FOR_BINDER);
 }
 
 // test for_type
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 12a13ca..3a8041d 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -185,7 +185,6 @@
     BREAK_EXPR,
     CALL_EXPR,
     CAST_EXPR,
-    CLOSURE_BINDER,
     CLOSURE_EXPR,
     CONST,
     CONST_ARG,
@@ -203,6 +202,7 @@
     FN_PTR_TYPE,
     FORMAT_ARGS_ARG,
     FORMAT_ARGS_EXPR,
+    FOR_BINDER,
     FOR_EXPR,
     FOR_TYPE,
     GENERIC_ARG_LIST,
@@ -358,7 +358,6 @@
             | BREAK_EXPR
             | CALL_EXPR
             | CAST_EXPR
-            | CLOSURE_BINDER
             | CLOSURE_EXPR
             | CONST
             | CONST_ARG
@@ -376,6 +375,7 @@
             | FN_PTR_TYPE
             | FORMAT_ARGS_ARG
             | FORMAT_ARGS_EXPR
+            | FOR_BINDER
             | FOR_EXPR
             | FOR_TYPE
             | GENERIC_ARG_LIST
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index cef7b0e..c642e1a 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -253,6 +253,10 @@
         run_and_expect_no_errors("test_data/parser/inline/ok/fn_pointer_unnamed_arg.rs");
     }
     #[test]
+    fn for_binder_bound() {
+        run_and_expect_no_errors("test_data/parser/inline/ok/for_binder_bound.rs");
+    }
+    #[test]
     fn for_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/for_expr.rs"); }
     #[test]
     fn for_range_from() {
@@ -402,6 +406,10 @@
     #[test]
     fn match_guard() { run_and_expect_no_errors("test_data/parser/inline/ok/match_guard.rs"); }
     #[test]
+    fn maybe_const_trait_bound() {
+        run_and_expect_no_errors("test_data/parser/inline/ok/maybe_const_trait_bound.rs");
+    }
+    #[test]
     fn metas() { run_and_expect_no_errors("test_data/parser/inline/ok/metas.rs"); }
     #[test]
     fn method_call_expr() {
diff --git a/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/crates/parser/test_data/parser/err/0024_many_type_parens.rast
index 025c12e..2fd1725 100644
--- a/crates/parser/test_data/parser/err/0024_many_type_parens.rast
+++ b/crates/parser/test_data/parser/err/0024_many_type_parens.rast
@@ -37,7 +37,7 @@
           WHITESPACE " "
           TYPE_BOUND
             L_PAREN "("
-            FOR_TYPE
+            FOR_BINDER
               FOR_KW "for"
               GENERIC_PARAM_LIST
                 L_ANGLE "<"
@@ -45,18 +45,18 @@
                   LIFETIME
                     LIFETIME_IDENT "'a"
                 R_ANGLE ">"
-              WHITESPACE " "
-              PATH_TYPE
-                PATH
-                  PATH_SEGMENT
-                    NAME_REF
-                      IDENT "Trait"
-                    GENERIC_ARG_LIST
-                      L_ANGLE "<"
-                      LIFETIME_ARG
-                        LIFETIME
-                          LIFETIME_IDENT "'a"
-                      R_ANGLE ">"
+            WHITESPACE " "
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Trait"
+                  GENERIC_ARG_LIST
+                    L_ANGLE "<"
+                    LIFETIME_ARG
+                      LIFETIME
+                        LIFETIME_IDENT "'a"
+                    R_ANGLE ">"
             R_PAREN ")"
       R_ANGLE ">"
     PARAM_LIST
@@ -124,7 +124,7 @@
               WHITESPACE " "
               TYPE_BOUND
                 L_PAREN "("
-                FOR_TYPE
+                FOR_BINDER
                   FOR_KW "for"
                   GENERIC_PARAM_LIST
                     L_ANGLE "<"
@@ -132,18 +132,18 @@
                       LIFETIME
                         LIFETIME_IDENT "'a"
                     R_ANGLE ">"
-                  WHITESPACE " "
-                  PATH_TYPE
-                    PATH
-                      PATH_SEGMENT
-                        NAME_REF
-                          IDENT "Trait"
-                        GENERIC_ARG_LIST
-                          L_ANGLE "<"
-                          LIFETIME_ARG
-                            LIFETIME
-                              LIFETIME_IDENT "'a"
-                          R_ANGLE ">"
+                WHITESPACE " "
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Trait"
+                      GENERIC_ARG_LIST
+                        L_ANGLE "<"
+                        LIFETIME_ARG
+                          LIFETIME
+                            LIFETIME_IDENT "'a"
+                        R_ANGLE ">"
                 R_PAREN ")"
         ERROR
           R_ANGLE ">"
@@ -186,7 +186,7 @@
               TUPLE_EXPR
                 L_PAREN "("
                 CLOSURE_EXPR
-                  CLOSURE_BINDER
+                  FOR_BINDER
                     FOR_KW "for"
                     GENERIC_PARAM_LIST
                       L_ANGLE "<"
@@ -243,13 +243,14 @@
                           PAREN_TYPE
                             L_PAREN "("
                             FOR_TYPE
-                              FOR_KW "for"
-                              GENERIC_PARAM_LIST
-                                L_ANGLE "<"
-                                LIFETIME_PARAM
-                                  LIFETIME
-                                    LIFETIME_IDENT "'a"
-                                R_ANGLE ">"
+                              FOR_BINDER
+                                FOR_KW "for"
+                                GENERIC_PARAM_LIST
+                                  L_ANGLE "<"
+                                  LIFETIME_PARAM
+                                    LIFETIME
+                                      LIFETIME_IDENT "'a"
+                                  R_ANGLE ">"
                               WHITESPACE " "
                               PATH_TYPE
                                 PATH
diff --git a/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast b/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
index 674c8d5..3768a55 100644
--- a/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
+++ b/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
@@ -12,13 +12,14 @@
       WHERE_KW "where"
       WHITESPACE " "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
     WHITESPACE "\n"
     BLOCK_EXPR
       STMT_LIST
diff --git a/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast b/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
index cb4fb16..9c4ee6f 100644
--- a/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
+++ b/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
@@ -8,13 +8,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       REF_TYPE
         AMP "&"
@@ -37,13 +38,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       TUPLE_TYPE
         L_PAREN "("
@@ -70,13 +72,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       SLICE_TYPE
         L_BRACK "["
@@ -97,22 +100,24 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
-      WHITESPACE " "
-      FOR_TYPE
+      FOR_BINDER
         FOR_KW "for"
         GENERIC_PARAM_LIST
           L_ANGLE "<"
           LIFETIME_PARAM
             LIFETIME
-              LIFETIME_IDENT "'b"
+              LIFETIME_IDENT "'a"
           R_ANGLE ">"
+      WHITESPACE " "
+      FOR_TYPE
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'b"
+            R_ANGLE ">"
         WHITESPACE " "
         FN_PTR_TYPE
           FN_KW "fn"
@@ -164,31 +169,34 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
-        WHITESPACE " "
-        FOR_TYPE
+        FOR_BINDER
           FOR_KW "for"
           GENERIC_PARAM_LIST
             L_ANGLE "<"
             LIFETIME_PARAM
               LIFETIME
-                LIFETIME_IDENT "'b"
+                LIFETIME_IDENT "'a"
             R_ANGLE ">"
-          WHITESPACE " "
-          FOR_TYPE
+        WHITESPACE " "
+        FOR_TYPE
+          FOR_BINDER
             FOR_KW "for"
             GENERIC_PARAM_LIST
               L_ANGLE "<"
               LIFETIME_PARAM
                 LIFETIME
-                  LIFETIME_IDENT "'c"
+                  LIFETIME_IDENT "'b"
               R_ANGLE ">"
+          WHITESPACE " "
+          FOR_TYPE
+            FOR_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'c"
+                R_ANGLE ">"
             WHITESPACE " "
             FN_PTR_TYPE
               FN_KW "fn"
diff --git a/crates/parser/test_data/parser/inline/ok/closure_binder.rast b/crates/parser/test_data/parser/inline/ok/closure_binder.rast
index c04dbe1..c96ccf7 100644
--- a/crates/parser/test_data/parser/inline/ok/closure_binder.rast
+++ b/crates/parser/test_data/parser/inline/ok/closure_binder.rast
@@ -14,7 +14,7 @@
         WHITESPACE " "
         EXPR_STMT
           CLOSURE_EXPR
-            CLOSURE_BINDER
+            FOR_BINDER
               FOR_KW "for"
               GENERIC_PARAM_LIST
                 L_ANGLE "<"
diff --git a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
index dcc66dc..6578809 100644
--- a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
+++ b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
@@ -103,7 +103,7 @@
       WHITESPACE " "
       TYPE_BOUND_LIST
         TYPE_BOUND
-          FOR_TYPE
+          FOR_BINDER
             FOR_KW "for"
             GENERIC_PARAM_LIST
               L_ANGLE "<"
@@ -111,12 +111,12 @@
                 LIFETIME
                   LIFETIME_IDENT "'a"
               R_ANGLE ">"
-            WHITESPACE " "
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Path"
+          WHITESPACE " "
+          PATH_TYPE
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "Path"
     SEMICOLON ";"
   WHITESPACE "\n"
   TYPE_ALIAS
diff --git a/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast b/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast
new file mode 100644
index 0000000..17dbbf3
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/for_binder_bound.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    GENERIC_PARAM_LIST
+      L_ANGLE "<"
+      TYPE_PARAM
+        NAME
+          IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            FOR_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'a"
+                R_ANGLE ">"
+            WHITESPACE " "
+            L_BRACK "["
+            CONST_KW "const"
+            R_BRACK "]"
+            WHITESPACE " "
+            ASYNC_KW "async"
+            WHITESPACE " "
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Trait"
+      R_ANGLE ">"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs b/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs
new file mode 100644
index 0000000..427cf55
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs
@@ -0,0 +1 @@
+fn foo<T: for<'a> [const] async Trait>() {}
diff --git a/crates/parser/test_data/parser/inline/ok/for_type.rast b/crates/parser/test_data/parser/inline/ok/for_type.rast
index 7600457..5862305 100644
--- a/crates/parser/test_data/parser/inline/ok/for_type.rast
+++ b/crates/parser/test_data/parser/inline/ok/for_type.rast
@@ -8,13 +8,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       FN_PTR_TYPE
         FN_KW "fn"
@@ -39,13 +40,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       FN_PTR_TYPE
         UNSAFE_KW "unsafe"
@@ -86,13 +88,14 @@
     EQ "="
     WHITESPACE " "
     FOR_TYPE
-      FOR_KW "for"
-      GENERIC_PARAM_LIST
-        L_ANGLE "<"
-        LIFETIME_PARAM
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        R_ANGLE ">"
+      FOR_BINDER
+        FOR_KW "for"
+        GENERIC_PARAM_LIST
+          L_ANGLE "<"
+          LIFETIME_PARAM
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          R_ANGLE ">"
       WHITESPACE " "
       PATH_TYPE
         PATH
diff --git a/crates/parser/test_data/parser/inline/ok/lambda_expr.rast b/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
index ea401d2..bf24a57 100644
--- a/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
+++ b/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
@@ -202,7 +202,7 @@
         WHITESPACE "\n    "
         EXPR_STMT
           CLOSURE_EXPR
-            CLOSURE_BINDER
+            FOR_BINDER
               FOR_KW "for"
               GENERIC_PARAM_LIST
                 L_ANGLE "<"
@@ -223,7 +223,7 @@
         WHITESPACE "\n    "
         EXPR_STMT
           CLOSURE_EXPR
-            CLOSURE_BINDER
+            FOR_BINDER
               FOR_KW "for"
               GENERIC_PARAM_LIST
                 L_ANGLE "<"
diff --git a/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast b/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast
new file mode 100644
index 0000000..8d12f81
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+  FN
+    CONST_KW "const"
+    WHITESPACE " "
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      PARAM
+        WILDCARD_PAT
+          UNDERSCORE "_"
+        COLON ":"
+        WHITESPACE " "
+        IMPL_TRAIT_TYPE
+          IMPL_KW "impl"
+          WHITESPACE " "
+          TYPE_BOUND_LIST
+            TYPE_BOUND
+              L_BRACK "["
+              CONST_KW "const"
+              R_BRACK "]"
+              WHITESPACE " "
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "Trait"
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs b/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs
new file mode 100644
index 0000000..e1da920
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/maybe_const_trait_bound.rs
@@ -0,0 +1 @@
+const fn foo(_: impl [const] Trait) {}
diff --git a/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast b/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
index 30a2842..6afa061 100644
--- a/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
+++ b/crates/parser/test_data/parser/inline/ok/no_dyn_trait_leading_for.rast
@@ -11,13 +11,14 @@
       TYPE_BOUND_LIST
         TYPE_BOUND
           FOR_TYPE
-            FOR_KW "for"
-            GENERIC_PARAM_LIST
-              L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'a"
-              R_ANGLE ">"
+            FOR_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'a"
+                R_ANGLE ">"
             WHITESPACE " "
             PATH_TYPE
               PATH
diff --git a/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast b/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
index 56e2d10..cb29615 100644
--- a/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
+++ b/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast
@@ -29,10 +29,11 @@
           TYPE_BOUND
             QUESTION "?"
             FOR_TYPE
-              FOR_KW "for"
-              GENERIC_PARAM_LIST
-                L_ANGLE "<"
-                R_ANGLE ">"
+              FOR_BINDER
+                FOR_KW "for"
+                GENERIC_PARAM_LIST
+                  L_ANGLE "<"
+                  R_ANGLE ">"
               WHITESPACE " "
               PATH_TYPE
                 PATH
diff --git a/crates/parser/test_data/parser/inline/ok/where_pred_for.rast b/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
index 0cc365e..b10b953 100644
--- a/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
+++ b/crates/parser/test_data/parser/inline/ok/where_pred_for.rast
@@ -18,13 +18,14 @@
       WHERE_KW "where"
       WHITESPACE "\n   "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         PATH_TYPE
           PATH
diff --git a/crates/parser/test_data/parser/ok/0032_where_for.rast b/crates/parser/test_data/parser/ok/0032_where_for.rast
index 86f6af9..dcaf58f 100644
--- a/crates/parser/test_data/parser/ok/0032_where_for.rast
+++ b/crates/parser/test_data/parser/ok/0032_where_for.rast
@@ -36,7 +36,7 @@
           PLUS "+"
           WHITESPACE " "
           TYPE_BOUND
-            FOR_TYPE
+            FOR_BINDER
               FOR_KW "for"
               GENERIC_PARAM_LIST
                 L_ANGLE "<"
@@ -44,18 +44,18 @@
                   LIFETIME
                     LIFETIME_IDENT "'de"
                 R_ANGLE ">"
-              WHITESPACE " "
-              PATH_TYPE
-                PATH
-                  PATH_SEGMENT
-                    NAME_REF
-                      IDENT "Deserialize"
-                    GENERIC_ARG_LIST
-                      L_ANGLE "<"
-                      LIFETIME_ARG
-                        LIFETIME
-                          LIFETIME_IDENT "'de"
-                      R_ANGLE ">"
+            WHITESPACE " "
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Deserialize"
+                  GENERIC_ARG_LIST
+                    L_ANGLE "<"
+                    LIFETIME_ARG
+                      LIFETIME
+                        LIFETIME_IDENT "'de"
+                    R_ANGLE ">"
           WHITESPACE " "
           PLUS "+"
           WHITESPACE " "
diff --git a/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
index 8bf1090..5cef4df 100644
--- a/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
+++ b/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
@@ -18,13 +18,14 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         PATH_TYPE
           PATH
@@ -81,13 +82,14 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         REF_TYPE
           AMP "&"
@@ -135,13 +137,14 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         PAREN_TYPE
           L_PAREN "("
@@ -206,13 +209,14 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         SLICE_TYPE
           L_BRACK "["
@@ -276,13 +280,14 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
+        FOR_BINDER
+          FOR_KW "for"
+          GENERIC_PARAM_LIST
+            L_ANGLE "<"
+            LIFETIME_PARAM
+              LIFETIME
+                LIFETIME_IDENT "'a"
+            R_ANGLE ">"
         WHITESPACE " "
         PATH_TYPE
           PATH
@@ -349,22 +354,24 @@
       WHERE_KW "where"
       WHITESPACE "\n    "
       WHERE_PRED
-        FOR_KW "for"
-        GENERIC_PARAM_LIST
-          L_ANGLE "<"
-          LIFETIME_PARAM
-            LIFETIME
-              LIFETIME_IDENT "'a"
-          R_ANGLE ">"
-        WHITESPACE " "
-        FOR_TYPE
+        FOR_BINDER
           FOR_KW "for"
           GENERIC_PARAM_LIST
             L_ANGLE "<"
             LIFETIME_PARAM
               LIFETIME
-                LIFETIME_IDENT "'b"
+                LIFETIME_IDENT "'a"
             R_ANGLE ">"
+        WHITESPACE " "
+        FOR_TYPE
+          FOR_BINDER
+            FOR_KW "for"
+            GENERIC_PARAM_LIST
+              L_ANGLE "<"
+              LIFETIME_PARAM
+                LIFETIME
+                  LIFETIME_IDENT "'b"
+              R_ANGLE ">"
           WHITESPACE " "
           FN_PTR_TYPE
             FN_KW "fn"
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 4cbc88c..6d8a360 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -101,7 +101,7 @@
   'where' predicates:(WherePred (',' WherePred)* ','?)
 
 WherePred =
-  ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList?
+  ForBinder? (Lifetime | Type) ':' TypeBoundList?
 
 
 //*************************//
@@ -534,10 +534,10 @@
   Attr* Expr '.' NameRef
 
 ClosureExpr =
-  Attr* ClosureBinder? 'const'? 'static'? 'async'? 'gen'? 'move'?  ParamList RetType?
+  Attr* ForBinder? 'const'? 'static'? 'async'? 'gen'? 'move'?  ParamList RetType?
   body:Expr
 
-ClosureBinder =
+ForBinder =
   'for' GenericParamList
 
 IfExpr =
@@ -658,7 +658,7 @@
   'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
 
 ForType =
-  'for' GenericParamList Type
+  ForBinder Type
 
 ImplTraitType =
   'impl' TypeBoundList
@@ -671,7 +671,7 @@
 
 TypeBound =
   Lifetime
-| ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type
+| ForBinder? ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type
 | 'use' UseBoundGenericArgs
 
 UseBoundGenericArgs =
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index d787fd0..a9aeeed 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -393,8 +393,7 @@
     let pred = predicates.next().unwrap();
     let mut bounds = pred.type_bound_list().unwrap().bounds();
 
-    assert!(pred.for_token().is_none());
-    assert!(pred.generic_param_list().is_none());
+    assert!(pred.for_binder().is_none());
     assert_eq!("T", pred.ty().unwrap().syntax().text().to_string());
     assert_bound("Clone", bounds.next());
     assert_bound("Copy", bounds.next());
@@ -432,8 +431,10 @@
     let pred = predicates.next().unwrap();
     let mut bounds = pred.type_bound_list().unwrap().bounds();
 
-    assert!(pred.for_token().is_some());
-    assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string());
+    assert_eq!(
+        "<'a>",
+        pred.for_binder().unwrap().generic_param_list().unwrap().syntax().text().to_string()
+    );
     assert_eq!("F", pred.ty().unwrap().syntax().text().to_string());
     assert_bound("Fn(&'a str)", bounds.next());
 }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 2b86246..ceb2866 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -377,22 +377,13 @@
     #[inline]
     pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 }
-pub struct ClosureBinder {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ClosureBinder {
-    #[inline]
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
-    #[inline]
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
-}
 pub struct ClosureExpr {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::HasAttrs for ClosureExpr {}
 impl ClosureExpr {
     #[inline]
-    pub fn closure_binder(&self) -> Option<ClosureBinder> { support::child(&self.syntax) }
+    pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
     #[inline]
     pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
     #[inline]
@@ -615,6 +606,15 @@
     #[inline]
     pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
+pub struct ForBinder {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ForBinder {
+    #[inline]
+    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    #[inline]
+    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+}
 pub struct ForExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -632,11 +632,9 @@
 }
 impl ForType {
     #[inline]
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
     #[inline]
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    #[inline]
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 }
 pub struct FormatArgsArg {
     pub(crate) syntax: SyntaxNode,
@@ -1766,6 +1764,8 @@
 }
 impl TypeBound {
     #[inline]
+    pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
+    #[inline]
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
     #[inline]
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
@@ -1938,13 +1938,11 @@
 impl ast::HasTypeBounds for WherePred {}
 impl WherePred {
     #[inline]
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+    pub fn for_binder(&self) -> Option<ForBinder> { support::child(&self.syntax) }
     #[inline]
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
     #[inline]
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
-    #[inline]
-    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 }
 pub struct WhileExpr {
     pub(crate) syntax: SyntaxNode,
@@ -3239,42 +3237,6 @@
         f.debug_struct("CastExpr").field("syntax", &self.syntax).finish()
     }
 }
-impl AstNode for ClosureBinder {
-    #[inline]
-    fn kind() -> SyntaxKind
-    where
-        Self: Sized,
-    {
-        CLOSURE_BINDER
-    }
-    #[inline]
-    fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_BINDER }
-    #[inline]
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    #[inline]
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
-impl hash::Hash for ClosureBinder {
-    fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
-}
-impl Eq for ClosureBinder {}
-impl PartialEq for ClosureBinder {
-    fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
-}
-impl Clone for ClosureBinder {
-    fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
-}
-impl fmt::Debug for ClosureBinder {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("ClosureBinder").field("syntax", &self.syntax).finish()
-    }
-}
 impl AstNode for ClosureExpr {
     #[inline]
     fn kind() -> SyntaxKind
@@ -3815,6 +3777,42 @@
         f.debug_struct("FnPtrType").field("syntax", &self.syntax).finish()
     }
 }
+impl AstNode for ForBinder {
+    #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FOR_BINDER
+    }
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_BINDER }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl hash::Hash for ForBinder {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
+}
+impl Eq for ForBinder {}
+impl PartialEq for ForBinder {
+    fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
+}
+impl Clone for ForBinder {
+    fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
+}
+impl fmt::Debug for ForBinder {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ForBinder").field("syntax", &self.syntax).finish()
+    }
+}
 impl AstNode for ForExpr {
     #[inline]
     fn kind() -> SyntaxKind
@@ -10146,11 +10144,6 @@
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for ClosureBinder {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for ClosureExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -10226,6 +10219,11 @@
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for ForBinder {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for ForExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index f5530c5..62a7d4d 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -805,9 +805,7 @@
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum TypeBoundKind {
     /// Trait
-    PathType(ast::PathType),
-    /// for<'a> ...
-    ForType(ast::ForType),
+    PathType(Option<ast::ForBinder>, ast::PathType),
     /// use
     Use(ast::UseBoundGenericArgs),
     /// 'a
@@ -817,9 +815,7 @@
 impl ast::TypeBound {
     pub fn kind(&self) -> TypeBoundKind {
         if let Some(path_type) = support::children(self.syntax()).next() {
-            TypeBoundKind::PathType(path_type)
-        } else if let Some(for_type) = support::children(self.syntax()).next() {
-            TypeBoundKind::ForType(for_type)
+            TypeBoundKind::PathType(self.for_binder(), path_type)
         } else if let Some(args) = self.use_bound_generic_args() {
             TypeBoundKind::Use(args)
         } else if let Some(lifetime) = self.lifetime() {