diff --git a/Cargo.lock b/Cargo.lock
index 82c7c143ffa..333ea6fc91a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1764,9 +1764,9 @@ dependencies = [
 
 [[package]]
 name = "ungrammar"
-version = "1.14.1"
+version = "1.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dbe67c0c0f5ded8e404578a9ab1009ffdb6ee219779329aefc0cb4fe7f44891"
+checksum = "5334230a6ae9ca52bc811c968c0ae12f1750c0698ed52ea68dabab7ce5a80972"
 
 [[package]]
 name = "unicase"
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index e633646c3b6..c4e4f010ffb 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -27,6 +27,10 @@ pub(super) fn expr_path(p: &mut Parser) {
     path(p, Mode::Expr)
 }
 
+pub(crate) fn type_path_for_qualifier(p: &mut Parser, qual: CompletedMarker) {
+    path_for_qualifier(p, Mode::Type, qual)
+}
+
 #[derive(Clone, Copy, Eq, PartialEq)]
 enum Mode {
     Use,
@@ -37,7 +41,11 @@ enum Mode {
 fn path(p: &mut Parser, mode: Mode) {
     let path = p.start();
     path_segment(p, mode, true);
-    let mut qual = path.complete(p, PATH);
+    let qual = path.complete(p, PATH);
+    path_for_qualifier(p, mode, qual)
+}
+
+fn path_for_qualifier(p: &mut Parser, mode: Mode, mut qual: CompletedMarker) {
     loop {
         let use_tree = matches!(p.nth(2), T![*] | T!['{']);
         if p.at(T![::]) && !use_tree {
diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs
index ed2322e52cb..175def8d5c7 100644
--- a/crates/parser/src/grammar/type_args.rs
+++ b/crates/parser/src/grammar/type_args.rs
@@ -65,17 +65,51 @@ fn generic_arg(p: &mut Parser) {
             m.complete(p, LIFETIME_ARG);
         }
         // test associated_type_bounds
-        // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
-        IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => {
+        // fn print_all<T: Iterator<Item, Item::Item, Item: Display, Item<'a> = Item>>(printables: T) {}
+        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => {
+            let path_ty = p.start();
+            let path = p.start();
+            let path_seg = p.start();
             name_ref(p);
-            type_params::bounds(p);
-            m.complete(p, ASSOC_TYPE_ARG);
-        }
-        IDENT if p.nth(1) == T![=] => {
-            name_ref(p);
-            p.bump_any();
-            types::type_(p);
-            m.complete(p, ASSOC_TYPE_ARG);
+            if p.current() == T![<] {
+                opt_generic_arg_list(p, false);
+            }
+            match p.current() {
+                // NameRef<...> =
+                T![=] => {
+                    p.bump_any();
+                    types::type_(p);
+
+                    path_seg.abandon(p);
+                    path.abandon(p);
+                    path_ty.abandon(p);
+                    m.complete(p, ASSOC_TYPE_ARG);
+                }
+                T![:] if p.nth(1) == T![:] => {
+                    // NameRef::, this is a path type
+                    path_seg.complete(p, PATH_SEGMENT);
+                    let qual = path.complete(p, PATH);
+                    paths::type_path_for_qualifier(p, qual);
+                    path_ty.complete(p, PATH_TYPE);
+                    m.complete(p, TYPE_ARG);
+                }
+                // NameRef<...>:
+                T![:] => {
+                    type_params::bounds(p);
+
+                    path_seg.abandon(p);
+                    path.abandon(p);
+                    path_ty.abandon(p);
+                    m.complete(p, ASSOC_TYPE_ARG);
+                }
+                // NameRef, this is a single segment path type
+                _ => {
+                    path_seg.complete(p, PATH_SEGMENT);
+                    path.complete(p, PATH);
+                    path_ty.complete(p, PATH_TYPE);
+                    m.complete(p, TYPE_ARG);
+                }
+            }
         }
         T!['{'] => {
             expressions::block_expr(p);
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index b040bf61f48..287160a19fb 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -107,6 +107,7 @@ pub struct AssocTypeArg {
 impl ast::TypeBoundsOwner for AssocTypeArg {}
 impl AssocTypeArg {
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
@@ -125,6 +126,15 @@ impl ConstArg {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericParamList {
+    pub(crate) syntax: SyntaxNode,
+}
+impl GenericParamList {
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct TypeBoundList {
     pub(crate) syntax: SyntaxNode,
 }
@@ -454,15 +464,6 @@ impl Abi {
     pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericParamList {
-    pub(crate) syntax: SyntaxNode,
-}
-impl GenericParamList {
-    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
-    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct WhereClause {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1584,6 +1585,17 @@ impl AstNode for ConstArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for GenericParamList {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for TypeBoundList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -1892,17 +1904,6 @@ impl AstNode for Abi {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for GenericParamList {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
 impl AstNode for WhereClause {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3680,6 +3681,11 @@ impl std::fmt::Display for ConstArg {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for GenericParamList {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for TypeBoundList {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -3820,11 +3826,6 @@ impl std::fmt::Display for Abi {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for GenericParamList {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for WhereClause {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
index 3870ec1353d..605e4213f47 100644
--- a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
@@ -1,55 +1,95 @@
-SOURCE_FILE@0..59
-  FN@0..58
+SOURCE_FILE@0..94
+  FN@0..93
     FN_KW@0..2 "fn"
     WHITESPACE@2..3 " "
     NAME@3..12
       IDENT@3..12 "print_all"
-    GENERIC_PARAM_LIST@12..40
+    GENERIC_PARAM_LIST@12..75
       L_ANGLE@12..13 "<"
-      TYPE_PARAM@13..39
+      TYPE_PARAM@13..74
         NAME@13..14
           IDENT@13..14 "T"
         COLON@14..15 ":"
         WHITESPACE@15..16 " "
-        TYPE_BOUND_LIST@16..39
-          TYPE_BOUND@16..39
-            PATH_TYPE@16..39
-              PATH@16..39
-                PATH_SEGMENT@16..39
+        TYPE_BOUND_LIST@16..74
+          TYPE_BOUND@16..74
+            PATH_TYPE@16..74
+              PATH@16..74
+                PATH_SEGMENT@16..74
                   NAME_REF@16..24
                     IDENT@16..24 "Iterator"
-                  GENERIC_ARG_LIST@24..39
+                  GENERIC_ARG_LIST@24..74
                     L_ANGLE@24..25 "<"
-                    ASSOC_TYPE_ARG@25..38
-                      NAME_REF@25..29
-                        IDENT@25..29 "Item"
-                      COLON@29..30 ":"
-                      WHITESPACE@30..31 " "
-                      TYPE_BOUND_LIST@31..38
-                        TYPE_BOUND@31..38
-                          PATH_TYPE@31..38
-                            PATH@31..38
-                              PATH_SEGMENT@31..38
-                                NAME_REF@31..38
-                                  IDENT@31..38 "Display"
-                    R_ANGLE@38..39 ">"
-      R_ANGLE@39..40 ">"
-    PARAM_LIST@40..55
-      L_PAREN@40..41 "("
-      PARAM@41..54
-        IDENT_PAT@41..51
-          NAME@41..51
-            IDENT@41..51 "printables"
-        COLON@51..52 ":"
-        WHITESPACE@52..53 " "
-        PATH_TYPE@53..54
-          PATH@53..54
-            PATH_SEGMENT@53..54
-              NAME_REF@53..54
-                IDENT@53..54 "T"
-      R_PAREN@54..55 ")"
-    WHITESPACE@55..56 " "
-    BLOCK_EXPR@56..58
-      L_CURLY@56..57 "{"
-      R_CURLY@57..58 "}"
-  WHITESPACE@58..59 "\n"
+                    TYPE_ARG@25..29
+                      PATH_TYPE@25..29
+                        PATH@25..29
+                          PATH_SEGMENT@25..29
+                            NAME_REF@25..29
+                              IDENT@25..29 "Item"
+                    COMMA@29..30 ","
+                    WHITESPACE@30..31 " "
+                    TYPE_ARG@31..41
+                      PATH_TYPE@31..41
+                        PATH@31..41
+                          PATH@31..35
+                            PATH_SEGMENT@31..35
+                              NAME_REF@31..35
+                                IDENT@31..35 "Item"
+                          COLON2@35..37 "::"
+                          PATH_SEGMENT@37..41
+                            NAME_REF@37..41
+                              IDENT@37..41 "Item"
+                    COMMA@41..42 ","
+                    WHITESPACE@42..43 " "
+                    ASSOC_TYPE_ARG@43..56
+                      NAME_REF@43..47
+                        IDENT@43..47 "Item"
+                      COLON@47..48 ":"
+                      WHITESPACE@48..49 " "
+                      TYPE_BOUND_LIST@49..56
+                        TYPE_BOUND@49..56
+                          PATH_TYPE@49..56
+                            PATH@49..56
+                              PATH_SEGMENT@49..56
+                                NAME_REF@49..56
+                                  IDENT@49..56 "Display"
+                    COMMA@56..57 ","
+                    WHITESPACE@57..58 " "
+                    ASSOC_TYPE_ARG@58..73
+                      NAME_REF@58..62
+                        IDENT@58..62 "Item"
+                      GENERIC_ARG_LIST@62..66
+                        L_ANGLE@62..63 "<"
+                        LIFETIME_ARG@63..65
+                          LIFETIME@63..65
+                            LIFETIME_IDENT@63..65 "'a"
+                        R_ANGLE@65..66 ">"
+                      WHITESPACE@66..67 " "
+                      EQ@67..68 "="
+                      WHITESPACE@68..69 " "
+                      PATH_TYPE@69..73
+                        PATH@69..73
+                          PATH_SEGMENT@69..73
+                            NAME_REF@69..73
+                              IDENT@69..73 "Item"
+                    R_ANGLE@73..74 ">"
+      R_ANGLE@74..75 ">"
+    PARAM_LIST@75..90
+      L_PAREN@75..76 "("
+      PARAM@76..89
+        IDENT_PAT@76..86
+          NAME@76..86
+            IDENT@76..86 "printables"
+        COLON@86..87 ":"
+        WHITESPACE@87..88 " "
+        PATH_TYPE@88..89
+          PATH@88..89
+            PATH_SEGMENT@88..89
+              NAME_REF@88..89
+                IDENT@88..89 "T"
+      R_PAREN@89..90 ")"
+    WHITESPACE@90..91 " "
+    BLOCK_EXPR@91..93
+      L_CURLY@91..92 "{"
+      R_CURLY@92..93 "}"
+  WHITESPACE@93..94 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs
index eb21a657b90..d7a19dbb392 100644
--- a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs
+++ b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs
@@ -1 +1 @@
-fn print_all<T: Iterator<Item: Display>>(printables: T) {}
+fn print_all<T: Iterator<Item, Item::Item, Item: Display, Item<'a> = Item>>(printables: T) {}