Repository: dtolnay/syn
Pull request #1326 (2023-01-23 23:28:07)

Parse generic associated type bindings in generic arguments
As in `I: StreamingIterator<Item<'a> = T>`.


Patch:
diff --git a/src/gen/clone.rs b/src/gen/clone.rs
index 2c36e8d5..04a304df 100644
--- a/src/gen/clone.rs
+++ b/src/gen/clone.rs
@@ -41,6 +41,30 @@ impl Clone for Arm {
 }
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
+impl Clone for AssocConst {
+    fn clone(&self) -> Self {
+        AssocConst {
+            ident: self.ident.clone(),
+            generics: self.generics.clone(),
+            eq_token: self.eq_token.clone(),
+            value: self.value.clone(),
+        }
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
+impl Clone for AssocType {
+    fn clone(&self) -> Self {
+        AssocType {
+            ident: self.ident.clone(),
+            generics: self.generics.clone(),
+            eq_token: self.eq_token.clone(),
+            ty: self.ty.clone(),
+        }
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Copy for AttrStyle {}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
@@ -82,17 +106,6 @@ impl Clone for BinOp {
         *self
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
-impl Clone for Binding {
-    fn clone(&self) -> Self {
-        Binding {
-            ident: self.ident.clone(),
-            eq_token: self.eq_token.clone(),
-            ty: self.ty.clone(),
-        }
-    }
-}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Clone for Block {
@@ -136,6 +149,7 @@ impl Clone for Constraint {
     fn clone(&self) -> Self {
         Constraint {
             ident: self.ident.clone(),
+            generics: self.generics.clone(),
             colon_token: self.colon_token.clone(),
             bounds: self.bounds.clone(),
         }
@@ -908,7 +922,8 @@ impl Clone for GenericArgument {
             GenericArgument::Lifetime(v0) => GenericArgument::Lifetime(v0.clone()),
             GenericArgument::Type(v0) => GenericArgument::Type(v0.clone()),
             GenericArgument::Const(v0) => GenericArgument::Const(v0.clone()),
-            GenericArgument::Binding(v0) => GenericArgument::Binding(v0.clone()),
+            GenericArgument::AssocType(v0) => GenericArgument::AssocType(v0.clone()),
+            GenericArgument::AssocConst(v0) => GenericArgument::AssocConst(v0.clone()),
             GenericArgument::Constraint(v0) => GenericArgument::Constraint(v0.clone()),
         }
     }
diff --git a/src/gen/debug.rs b/src/gen/debug.rs
index 6e117bbf..c1733c33 100644
--- a/src/gen/debug.rs
+++ b/src/gen/debug.rs
@@ -41,6 +41,30 @@ impl Debug for Arm {
 }
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Debug for AssocConst {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let mut formatter = formatter.debug_struct("AssocConst");
+        formatter.field("ident", &self.ident);
+        formatter.field("generics", &self.generics);
+        formatter.field("eq_token", &self.eq_token);
+        formatter.field("value", &self.value);
+        formatter.finish()
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Debug for AssocType {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let mut formatter = formatter.debug_struct("AssocType");
+        formatter.field("ident", &self.ident);
+        formatter.field("generics", &self.generics);
+        formatter.field("eq_token", &self.eq_token);
+        formatter.field("ty", &self.ty);
+        formatter.finish()
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for AttrStyle {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -224,17 +248,6 @@ impl Debug for BinOp {
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Debug for Binding {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        let mut formatter = formatter.debug_struct("Binding");
-        formatter.field("ident", &self.ident);
-        formatter.field("eq_token", &self.eq_token);
-        formatter.field("ty", &self.ty);
-        formatter.finish()
-    }
-}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for Block {
@@ -278,6 +291,7 @@ impl Debug for Constraint {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let mut formatter = formatter.debug_struct("Constraint");
         formatter.field("ident", &self.ident);
+        formatter.field("generics", &self.generics);
         formatter.field("colon_token", &self.colon_token);
         formatter.field("bounds", &self.bounds);
         formatter.finish()
@@ -1270,8 +1284,13 @@ impl Debug for GenericArgument {
                 formatter.field(v0);
                 formatter.finish()
             }
-            GenericArgument::Binding(v0) => {
-                let mut formatter = formatter.debug_tuple("Binding");
+            GenericArgument::AssocType(v0) => {
+                let mut formatter = formatter.debug_tuple("AssocType");
+                formatter.field(v0);
+                formatter.finish()
+            }
+            GenericArgument::AssocConst(v0) => {
+                let mut formatter = formatter.debug_tuple("AssocConst");
                 formatter.field(v0);
                 formatter.finish()
             }
diff --git a/src/gen/eq.rs b/src/gen/eq.rs
index 7d9b05d4..b6a81c43 100644
--- a/src/gen/eq.rs
+++ b/src/gen/eq.rs
@@ -37,6 +37,28 @@ impl PartialEq for Arm {
 }
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Eq for AssocConst {}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl PartialEq for AssocConst {
+    fn eq(&self, other: &Self) -> bool {
+        self.ident == other.ident && self.generics == other.generics
+            && self.value == other.value
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Eq for AssocType {}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl PartialEq for AssocType {
+    fn eq(&self, other: &Self) -> bool {
+        self.ident == other.ident && self.generics == other.generics
+            && self.ty == other.ty
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for AttrStyle {}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
@@ -109,16 +131,6 @@ impl PartialEq for BinOp {
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Eq for Binding {}
-#[cfg(any(feature = "derive", feature = "full"))]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl PartialEq for Binding {
-    fn eq(&self, other: &Self) -> bool {
-        self.ident == other.ident && self.ty == other.ty
-    }
-}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for Block {}
@@ -157,7 +169,8 @@ impl Eq for Constraint {}
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl PartialEq for Constraint {
     fn eq(&self, other: &Self) -> bool {
-        self.ident == other.ident && self.bounds == other.bounds
+        self.ident == other.ident && self.generics == other.generics
+            && self.bounds == other.bounds
     }
 }
 #[cfg(feature = "derive")]
@@ -881,7 +894,10 @@ impl PartialEq for GenericArgument {
             (GenericArgument::Const(self0), GenericArgument::Const(other0)) => {
                 self0 == other0
             }
-            (GenericArgument::Binding(self0), GenericArgument::Binding(other0)) => {
+            (GenericArgument::AssocType(self0), GenericArgument::AssocType(other0)) => {
+                self0 == other0
+            }
+            (GenericArgument::AssocConst(self0), GenericArgument::AssocConst(other0)) => {
                 self0 == other0
             }
             (GenericArgument::Constraint(self0), GenericArgument::Constraint(other0)) => {
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index b29ceac4..6429b124 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -43,6 +43,14 @@ pub trait Fold {
         fold_arm(self, i)
     }
     #[cfg(any(feature = "derive", feature = "full"))]
+    fn fold_assoc_const(&mut self, i: AssocConst) -> AssocConst {
+        fold_assoc_const(self, i)
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn fold_assoc_type(&mut self, i: AssocType) -> AssocType {
+        fold_assoc_type(self, i)
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
     fn fold_attr_style(&mut self, i: AttrStyle) -> AttrStyle {
         fold_attr_style(self, i)
     }
@@ -58,10 +66,6 @@ pub trait Fold {
     fn fold_bin_op(&mut self, i: BinOp) -> BinOp {
         fold_bin_op(self, i)
     }
-    #[cfg(any(feature = "derive", feature = "full"))]
-    fn fold_binding(&mut self, i: Binding) -> Binding {
-        fold_binding(self, i)
-    }
     #[cfg(feature = "full")]
     fn fold_block(&mut self, i: Block) -> Block {
         fold_block(self, i)
@@ -791,6 +795,30 @@ where
     }
 }
 #[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_assoc_const<F>(f: &mut F, node: AssocConst) -> AssocConst
+where
+    F: Fold + ?Sized,
+{
+    AssocConst {
+        ident: f.fold_ident(node.ident),
+        generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)),
+        eq_token: Token![=](tokens_helper(f, &node.eq_token.spans)),
+        value: f.fold_expr(node.value),
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_assoc_type<F>(f: &mut F, node: AssocType) -> AssocType
+where
+    F: Fold + ?Sized,
+{
+    AssocType {
+        ident: f.fold_ident(node.ident),
+        generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)),
+        eq_token: Token![=](tokens_helper(f, &node.eq_token.spans)),
+        ty: f.fold_type(node.ty),
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
 pub fn fold_attr_style<F>(f: &mut F, node: AttrStyle) -> AttrStyle
 where
     F: Fold + ?Sized,
@@ -921,17 +949,6 @@ where
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-pub fn fold_binding<F>(f: &mut F, node: Binding) -> Binding
-where
-    F: Fold + ?Sized,
-{
-    Binding {
-        ident: f.fold_ident(node.ident),
-        eq_token: Token![=](tokens_helper(f, &node.eq_token.spans)),
-        ty: f.fold_type(node.ty),
-    }
-}
 #[cfg(feature = "full")]
 pub fn fold_block<F>(f: &mut F, node: Block) -> Block
 where
@@ -976,6 +993,7 @@ where
 {
     Constraint {
         ident: f.fold_ident(node.ident),
+        generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)),
         colon_token: Token![:](tokens_helper(f, &node.colon_token.spans)),
         bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
     }
@@ -1753,8 +1771,11 @@ where
         GenericArgument::Const(_binding_0) => {
             GenericArgument::Const(f.fold_expr(_binding_0))
         }
-        GenericArgument::Binding(_binding_0) => {
-            GenericArgument::Binding(f.fold_binding(_binding_0))
+        GenericArgument::AssocType(_binding_0) => {
+            GenericArgument::AssocType(f.fold_assoc_type(_binding_0))
+        }
+        GenericArgument::AssocConst(_binding_0) => {
+            GenericArgument::AssocConst(f.fold_assoc_const(_binding_0))
         }
         GenericArgument::Constraint(_binding_0) => {
             GenericArgument::Constraint(f.fold_constraint(_binding_0))
diff --git a/src/gen/hash.rs b/src/gen/hash.rs
index de914931..5165ccf4 100644
--- a/src/gen/hash.rs
+++ b/src/gen/hash.rs
@@ -42,6 +42,30 @@ impl Hash for Arm {
 }
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Hash for AssocConst {
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        self.ident.hash(state);
+        self.generics.hash(state);
+        self.value.hash(state);
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Hash for AssocType {
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        self.ident.hash(state);
+        self.generics.hash(state);
+        self.ty.hash(state);
+    }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for AttrStyle {
     fn hash<H>(&self, state: &mut H)
     where
@@ -175,17 +199,6 @@ impl Hash for BinOp {
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Hash for Binding {
-    fn hash<H>(&self, state: &mut H)
-    where
-        H: Hasher,
-    {
-        self.ident.hash(state);
-        self.ty.hash(state);
-    }
-}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for Block {
@@ -228,6 +241,7 @@ impl Hash for Constraint {
         H: Hasher,
     {
         self.ident.hash(state);
+        self.generics.hash(state);
         self.bounds.hash(state);
     }
 }
@@ -1186,14 +1200,18 @@ impl Hash for GenericArgument {
                 state.write_u8(2u8);
                 v0.hash(state);
             }
-            GenericArgument::Binding(v0) => {
+            GenericArgument::AssocType(v0) => {
                 state.write_u8(3u8);
                 v0.hash(state);
             }
-            GenericArgument::Constraint(v0) => {
+            GenericArgument::AssocConst(v0) => {
                 state.write_u8(4u8);
                 v0.hash(state);
             }
+            GenericArgument::Constraint(v0) => {
+                state.write_u8(5u8);
+                v0.hash(state);
+            }
         }
     }
 }
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index bfcc9af0..5af2ce35 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -45,6 +45,14 @@ pub trait Visit<'ast> {
         visit_arm(self, i);
     }
     #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_assoc_const(&mut self, i: &'ast AssocConst) {
+        visit_assoc_const(self, i);
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_assoc_type(&mut self, i: &'ast AssocType) {
+        visit_assoc_type(self, i);
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_attr_style(&mut self, i: &'ast AttrStyle) {
         visit_attr_style(self, i);
     }
@@ -60,10 +68,6 @@ pub trait Visit<'ast> {
     fn visit_bin_op(&mut self, i: &'ast BinOp) {
         visit_bin_op(self, i);
     }
-    #[cfg(any(feature = "derive", feature = "full"))]
-    fn visit_binding(&mut self, i: &'ast Binding) {
-        visit_binding(self, i);
-    }
     #[cfg(feature = "full")]
     fn visit_block(&mut self, i: &'ast Block) {
         visit_block(self, i);
@@ -796,6 +800,30 @@ where
     }
 }
 #[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_assoc_const<'ast, V>(v: &mut V, node: &'ast AssocConst)
+where
+    V: Visit<'ast> + ?Sized,
+{
+    v.visit_ident(&node.ident);
+    if let Some(it) = &node.generics {
+        v.visit_angle_bracketed_generic_arguments(it);
+    }
+    tokens_helper(v, &node.eq_token.spans);
+    v.visit_expr(&node.value);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_assoc_type<'ast, V>(v: &mut V, node: &'ast AssocType)
+where
+    V: Visit<'ast> + ?Sized,
+{
+    v.visit_ident(&node.ident);
+    if let Some(it) = &node.generics {
+        v.visit_angle_bracketed_generic_arguments(it);
+    }
+    tokens_helper(v, &node.eq_token.spans);
+    v.visit_type(&node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_attr_style<'ast, V>(v: &mut V, node: &'ast AttrStyle)
 where
     V: Visit<'ast> + ?Sized,
@@ -923,15 +951,6 @@ where
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-pub fn visit_binding<'ast, V>(v: &mut V, node: &'ast Binding)
-where
-    V: Visit<'ast> + ?Sized,
-{
-    v.visit_ident(&node.ident);
-    tokens_helper(v, &node.eq_token.spans);
-    v.visit_type(&node.ty);
-}
 #[cfg(feature = "full")]
 pub fn visit_block<'ast, V>(v: &mut V, node: &'ast Block)
 where
@@ -983,6 +1002,9 @@ where
     V: Visit<'ast> + ?Sized,
 {
     v.visit_ident(&node.ident);
+    if let Some(it) = &node.generics {
+        v.visit_angle_bracketed_generic_arguments(it);
+    }
     tokens_helper(v, &node.colon_token.spans);
     for el in Punctuated::pairs(&node.bounds) {
         let (it, p) = el.into_tuple();
@@ -1949,8 +1971,11 @@ where
         GenericArgument::Const(_binding_0) => {
             v.visit_expr(_binding_0);
         }
-        GenericArgument::Binding(_binding_0) => {
-            v.visit_binding(_binding_0);
+        GenericArgument::AssocType(_binding_0) => {
+            v.visit_assoc_type(_binding_0);
+        }
+        GenericArgument::AssocConst(_binding_0) => {
+            v.visit_assoc_const(_binding_0);
         }
         GenericArgument::Constraint(_binding_0) => {
             v.visit_constraint(_binding_0);
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index a001c286..fbeb49cf 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -46,6 +46,14 @@ pub trait VisitMut {
         visit_arm_mut(self, i);
     }
     #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_assoc_const_mut(&mut self, i: &mut AssocConst) {
+        visit_assoc_const_mut(self, i);
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_assoc_type_mut(&mut self, i: &mut AssocType) {
+        visit_assoc_type_mut(self, i);
+    }
+    #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_attr_style_mut(&mut self, i: &mut AttrStyle) {
         visit_attr_style_mut(self, i);
     }
@@ -61,10 +69,6 @@ pub trait VisitMut {
     fn visit_bin_op_mut(&mut self, i: &mut BinOp) {
         visit_bin_op_mut(self, i);
     }
-    #[cfg(any(feature = "derive", feature = "full"))]
-    fn visit_binding_mut(&mut self, i: &mut Binding) {
-        visit_binding_mut(self, i);
-    }
     #[cfg(feature = "full")]
     fn visit_block_mut(&mut self, i: &mut Block) {
         visit_block_mut(self, i);
@@ -797,6 +801,30 @@ where
     }
 }
 #[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_assoc_const_mut<V>(v: &mut V, node: &mut AssocConst)
+where
+    V: VisitMut + ?Sized,
+{
+    v.visit_ident_mut(&mut node.ident);
+    if let Some(it) = &mut node.generics {
+        v.visit_angle_bracketed_generic_arguments_mut(it);
+    }
+    tokens_helper(v, &mut node.eq_token.spans);
+    v.visit_expr_mut(&mut node.value);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_assoc_type_mut<V>(v: &mut V, node: &mut AssocType)
+where
+    V: VisitMut + ?Sized,
+{
+    v.visit_ident_mut(&mut node.ident);
+    if let Some(it) = &mut node.generics {
+        v.visit_angle_bracketed_generic_arguments_mut(it);
+    }
+    tokens_helper(v, &mut node.eq_token.spans);
+    v.visit_type_mut(&mut node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_attr_style_mut<V>(v: &mut V, node: &mut AttrStyle)
 where
     V: VisitMut + ?Sized,
@@ -924,15 +952,6 @@ where
         }
     }
 }
-#[cfg(any(feature = "derive", feature = "full"))]
-pub fn visit_binding_mut<V>(v: &mut V, node: &mut Binding)
-where
-    V: VisitMut + ?Sized,
-{
-    v.visit_ident_mut(&mut node.ident);
-    tokens_helper(v, &mut node.eq_token.spans);
-    v.visit_type_mut(&mut node.ty);
-}
 #[cfg(feature = "full")]
 pub fn visit_block_mut<V>(v: &mut V, node: &mut Block)
 where
@@ -984,6 +1003,9 @@ where
     V: VisitMut + ?Sized,
 {
     v.visit_ident_mut(&mut node.ident);
+    if let Some(it) = &mut node.generics {
+        v.visit_angle_bracketed_generic_arguments_mut(it);
+    }
     tokens_helper(v, &mut node.colon_token.spans);
     for el in Punctuated::pairs_mut(&mut node.bounds) {
         let (it, p) = el.into_tuple();
@@ -1950,8 +1972,11 @@ where
         GenericArgument::Const(_binding_0) => {
             v.visit_expr_mut(_binding_0);
         }
-        GenericArgument::Binding(_binding_0) => {
-            v.visit_binding_mut(_binding_0);
+        GenericArgument::AssocType(_binding_0) => {
+            v.visit_assoc_type_mut(_binding_0);
+        }
+        GenericArgument::AssocConst(_binding_0) => {
+            v.visit_assoc_const_mut(_binding_0);
         }
         GenericArgument::Constraint(_binding_0) => {
             v.visit_constraint_mut(_binding_0);
diff --git a/src/lib.rs b/src/lib.rs
index 56332592..ffa8d972 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -454,7 +454,7 @@ pub use crate::pat::{
 mod path;
 #[cfg(any(feature = "full", feature = "derive"))]
 pub use crate::path::{
-    AngleBracketedGenericArguments, Binding, Constraint, GenericArgument,
+    AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
     ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
 };
 
diff --git a/src/path.rs b/src/path.rs
index d2c019bb..e1c0e553 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -103,7 +103,10 @@ ast_enum! {
         Const(Expr),
         /// A binding (equality constraint) on an associated type: the `Item =
         /// u8` in `Iterator<Item = u8>`.
-        Binding(Binding),
+        AssocType(AssocType),
+        /// An equality constraint on an associated constant: the `PANIC =
+        /// false` in `Trait<PANIC = false>`.
+        AssocConst(AssocConst),
         /// An associated type bound: `Iterator<Item: Display>`.
         Constraint(Constraint),
     }
@@ -122,20 +125,35 @@ ast_struct! {
 }
 
 ast_struct! {
-    /// A binding (equality constraint) on an associated type: `Item = u8`.
+    /// A binding (equality constraint) on an associated type: the `Item = u8`
+    /// in `Iterator<Item = u8>`.
     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
-    pub struct Binding {
+    pub struct AssocType {
         pub ident: Ident,
+        pub generics: Option<AngleBracketedGenericArguments>,
         pub eq_token: Token![=],
         pub ty: Type,
     }
 }
 
+ast_struct! {
+    /// An equality constraint on an associated constant: the `PANIC = false` in
+    /// `Trait<PANIC = false>`.
+    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
+    pub struct AssocConst {
+        pub ident: Ident,
+        pub generics: Option<AngleBracketedGenericArguments>,
+        pub eq_token: Token![=],
+        pub value: Expr,
+    }
+}
+
 ast_struct! {
     /// An associated type bound: `Iterator<Item: Display>`.
     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
     pub struct Constraint {
         pub ident: Ident,
+        pub generics: Option<AngleBracketedGenericArguments>,
         pub colon_token: Token![:],
         pub bounds: Punctuated<TypeParamBound, Token![+]>,
     }
@@ -202,79 +220,80 @@ pub mod parsing {
                 return Ok(GenericArgument::Lifetime(input.parse()?));
             }
 
-            if input.peek(Ident) && input.peek2(Token![=]) {
-                let ident: Ident = input.parse()?;
-                let eq_token: Token![=] = input.parse()?;
-
-                let ty = if input.peek(Lit) {
-                    let begin = input.fork();
-                    input.parse::<Lit>()?;
-                    Type::Verbatim(verbatim::between(begin, input))
-                } else if input.peek(token::Brace) {
-                    let begin = input.fork();
-
-                    #[cfg(feature = "full")]
-                    input.parse::<ExprBlock>()?;
-
-                    #[cfg(not(feature = "full"))]
-                    {
-                        let content;
-                        braced!(content in input);
-                        content.parse::<Expr>()?;
-                    }
-
-                    Type::Verbatim(verbatim::between(begin, input))
-                } else {
-                    input.parse()?
-                };
-
-                return Ok(GenericArgument::Binding(Binding {
-                    ident,
-                    eq_token,
-                    ty,
-                }));
-            }
-
-            #[cfg(feature = "full")]
-            if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
-                return Ok(GenericArgument::Constraint(input.parse()?));
-            }
-
             if input.peek(Lit) || input.peek(token::Brace) {
                 return const_argument(input).map(GenericArgument::Const);
             }
 
-            #[cfg(feature = "full")]
-            let begin = input.fork();
-
-            let argument: Type = input.parse()?;
-
-            #[cfg(feature = "full")]
-            if match &argument {
-                Type::Path(argument)
-                    if argument.qself.is_none()
-                        && argument.path.leading_colon.is_none()
-                        && argument.path.segments.len() == 1 =>
+            let mut argument: Type = input.parse()?;
+
+            match argument {
+                Type::Path(mut ty)
+                    if ty.qself.is_none()
+                        && ty.path.leading_colon.is_none()
+                        && ty.path.segments.len() == 1
+                        && match &ty.path.segments[0].arguments {
+                            PathArguments::None | PathArguments::AngleBracketed(_) => true,
+                            PathArguments::Parenthesized(_) => false,
+                        } =>
                 {
-                    match argument.path.segments[0].arguments {
-                        PathArguments::AngleBracketed(_) => true,
-                        _ => false,
+                    if let Some(eq_token) = input.parse::<Option<Token![=]>>()? {
+                        let segment = ty.path.segments.pop().unwrap().into_value();
+                        let ident = segment.ident;
+                        let generics = match segment.arguments {
+                            PathArguments::None => None,
+                            PathArguments::AngleBracketed(arguments) => Some(arguments),
+                            PathArguments::Parenthesized(_) => unreachable!(),
+                        };
+                        return if input.peek(Lit) || input.peek(token::Brace) {
+                            Ok(GenericArgument::AssocConst(AssocConst {
+                                ident,
+                                generics,
+                                eq_token,
+                                value: const_argument(input)?,
+                            }))
+                        } else {
+                            Ok(GenericArgument::AssocType(AssocType {
+                                ident,
+                                generics,
+                                eq_token,
+                                ty: input.parse()?,
+                            }))
+                        };
+                    }
+
+                    #[cfg(feature = "full")]
+                    if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
+                        let segment = ty.path.segments.pop().unwrap().into_value();
+                        return Ok(GenericArgument::Constraint(Constraint {
+                            ident: segment.ident,
+                            generics: match segment.arguments {
+                                PathArguments::None => None,
+                                PathArguments::AngleBracketed(arguments) => Some(arguments),
+                                PathArguments::Parenthesized(_) => unreachable!(),
+                            },
+                            colon_token,
+                            bounds: {
+                                let mut bounds = Punctuated::new();
+                                loop {
+                                    if input.peek(Token![,]) || input.peek(Token![>]) {
+                                        break;
+                                    }
+                                    let value: TypeParamBound = input.parse()?;
+                                    bounds.push_value(value);
+                                    if !input.peek(Token![+]) {
+                                        break;
+                                    }
+                                    let punct: Token![+] = input.parse()?;
+                                    bounds.push_punct(punct);
+                                }
+                                bounds
+                            },
+                        }));
                     }
+
+                    argument = Type::Path(ty);
                 }
-                _ => false,
-            } && if input.peek(Token![=]) {
-                input.parse::<Token![=]>()?;
-                input.parse::<Type>()?;
-                true
-            } else if input.peek(Token![:]) {
-                input.parse::<Token![:]>()?;
-                input.call(constraint_bounds)?;
-                true
-            } else {
-                false
-            } {
-                let verbatim = verbatim::between(begin, input);
-                return Ok(GenericArgument::Type(Type::Verbatim(verbatim)));
+                _ => {}
             }
 
             Ok(GenericArgument::Type(argument))
@@ -410,47 +429,6 @@ pub mod parsing {
         }
     }
 
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
-    impl Parse for Binding {
-        fn parse(input: ParseStream) -> Result<Self> {
-            Ok(Binding {
-                ident: input.parse()?,
-                eq_token: input.parse()?,
-                ty: input.parse()?,
-            })
-        }
-    }
-
-    #[cfg(feature = "full")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
-    impl Parse for Constraint {
-        fn parse(input: ParseStream) -> Result<Self> {
-            Ok(Constraint {
-                ident: input.parse()?,
-                colon_token: input.parse()?,
-                bounds: constraint_bounds(input)?,
-            })
-        }
-    }
-
-    #[cfg(feature = "full")]
-    fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
-        let mut bounds = Punctuated::new();
-        loop {
-            if input.peek(Token![,]) || input.peek(Token![>]) {
-                break;
-            }
-            let value = input.parse()?;
-            bounds.push_value(value);
-            if !input.peek(Token![+]) {
-                break;
-            }
-            let punct = input.parse()?;
-            bounds.push_punct(punct);
-        }
-        Ok(bounds)
-    }
-
     impl Path {
         /// Parse a `Path` containing no path arguments on any of its segments.
         ///
@@ -702,23 +680,21 @@ pub(crate) mod printing {
             match self {
                 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
                 GenericArgument::Type(ty) => ty.to_tokens(tokens),
-                GenericArgument::Const(e) => match e {
-                    Expr::Lit(_) => e.to_tokens(tokens),
+                GenericArgument::Const(expr) => match expr {
+                    Expr::Lit(_) => expr.to_tokens(tokens),
 
-                    // NOTE: We should probably support parsing blocks with only
-                    // expressions in them without the full feature for const
-                    // generics.
                     #[cfg(feature = "full")]
-                    Expr::Block(_) => e.to_tokens(tokens),
+                    Expr::Block(_) => expr.to_tokens(tokens),
 
                     // ERROR CORRECTION: Add braces to make sure that the
                     // generated code is valid.
                     _ => token::Brace::default().surround(tokens, |tokens| {
-                        e.to_tokens(tokens);
+                        expr.to_tokens(tokens);
                     }),
                 },
-                GenericArgument::Binding(tb) => tb.to_tokens(tokens),
-                GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
+                GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
+                GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
+                GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
             }
         }
     }
@@ -740,7 +716,8 @@ pub(crate) mod printing {
                     }
                     GenericArgument::Type(_)
                     | GenericArgument::Const(_)
-                    | GenericArgument::Binding(_)
+                    | GenericArgument::AssocType(_)
+                    | GenericArgument::AssocConst(_)
                     | GenericArgument::Constraint(_) => {}
                 }
             }
@@ -748,7 +725,8 @@ pub(crate) mod printing {
                 match param.value() {
                     GenericArgument::Type(_)
                     | GenericArgument::Const(_)
-                    | GenericArgument::Binding(_)
+                    | GenericArgument::AssocType(_)
+                    | GenericArgument::AssocConst(_)
                     | GenericArgument::Constraint(_) => {
                         if !trailing_or_empty {
                             <Token![,]>::default().to_tokens(tokens);
@@ -765,18 +743,30 @@ pub(crate) mod printing {
     }
 
     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
-    impl ToTokens for Binding {
+    impl ToTokens for AssocType {
         fn to_tokens(&self, tokens: &mut TokenStream) {
             self.ident.to_tokens(tokens);
+            self.generics.to_tokens(tokens);
             self.eq_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
 
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
+    impl ToTokens for AssocConst {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            self.ident.to_tokens(tokens);
+            self.generics.to_tokens(tokens);
+            self.eq_token.to_tokens(tokens);
+            self.value.to_tokens(tokens);
+        }
+    }
+
     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
     impl ToTokens for Constraint {
         fn to_tokens(&self, tokens: &mut TokenStream) {
             self.ident.to_tokens(tokens);
+            self.generics.to_tokens(tokens);
             self.colon_token.to_tokens(tokens);
             self.bounds.to_tokens(tokens);
         }
diff --git a/syn.json b/syn.json
index 2e66e617..8048df6b 100644
--- a/syn.json
+++ b/syn.json
@@ -95,6 +95,56 @@
         }
       }
     },
+    {
+      "ident": "AssocConst",
+      "features": {
+        "any": [
+          "derive",
+          "full"
+        ]
+      },
+      "fields": {
+        "ident": {
+          "proc_macro2": "Ident"
+        },
+        "generics": {
+          "option": {
+            "syn": "AngleBracketedGenericArguments"
+          }
+        },
+        "eq_token": {
+          "token": "Eq"
+        },
+        "value": {
+          "syn": "Expr"
+        }
+      }
+    },
+    {
+      "ident": "AssocType",
+      "features": {
+        "any": [
+          "derive",
+          "full"
+        ]
+      },
+      "fields": {
+        "ident": {
+          "proc_macro2": "Ident"
+        },
+        "generics": {
+          "option": {
+            "syn": "AngleBracketedGenericArguments"
+          }
+        },
+        "eq_token": {
+          "token": "Eq"
+        },
+        "ty": {
+          "syn": "Type"
+        }
+      }
+    },
     {
       "ident": "AttrStyle",
       "features": {
@@ -317,26 +367,6 @@
         ]
       }
     },
-    {
-      "ident": "Binding",
-      "features": {
-        "any": [
-          "derive",
-          "full"
-        ]
-      },
-      "fields": {
-        "ident": {
-          "proc_macro2": "Ident"
-        },
-        "eq_token": {
-          "token": "Eq"
-        },
-        "ty": {
-          "syn": "Type"
-        }
-      }
-    },
     {
       "ident": "Block",
       "features": {
@@ -433,6 +463,11 @@
         "ident": {
           "proc_macro2": "Ident"
         },
+        "generics": {
+          "option": {
+            "syn": "AngleBracketedGenericArguments"
+          }
+        },
         "colon_token": {
           "token": "Colon"
         },
@@ -2249,9 +2284,14 @@
             "syn": "Expr"
           }
         ],
-        "Binding": [
+        "AssocType": [
+          {
+            "syn": "AssocType"
+          }
+        ],
+        "AssocConst": [
           {
-            "syn": "Binding"
+            "syn": "AssocConst"
           }
         ],
         "Constraint": [


Test patch:
diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs
index 2e6286b4..65cd926b 100644
--- a/tests/debug/gen.rs
+++ b/tests/debug/gen.rs
@@ -88,6 +88,56 @@ impl Debug for Lite<syn::Arm> {
         formatter.finish()
     }
 }
+impl Debug for Lite<syn::AssocConst> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let _val = &self.value;
+        let mut formatter = formatter.debug_struct("AssocConst");
+        formatter.field("ident", Lite(&_val.ident));
+        if let Some(val) = &_val.generics {
+            #[derive(RefCast)]
+            #[repr(transparent)]
+            struct Print(syn::AngleBracketedGenericArguments);
+            impl Debug for Print {
+                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                    formatter.write_str("Some")?;
+                    let _val = &self.0;
+                    formatter.write_str("(")?;
+                    Debug::fmt(Lite(_val), formatter)?;
+                    formatter.write_str(")")?;
+                    Ok(())
+                }
+            }
+            formatter.field("generics", Print::ref_cast(val));
+        }
+        formatter.field("value", Lite(&_val.value));
+        formatter.finish()
+    }
+}
+impl Debug for Lite<syn::AssocType> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let _val = &self.value;
+        let mut formatter = formatter.debug_struct("AssocType");
+        formatter.field("ident", Lite(&_val.ident));
+        if let Some(val) = &_val.generics {
+            #[derive(RefCast)]
+            #[repr(transparent)]
+            struct Print(syn::AngleBracketedGenericArguments);
+            impl Debug for Print {
+                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                    formatter.write_str("Some")?;
+                    let _val = &self.0;
+                    formatter.write_str("(")?;
+                    Debug::fmt(Lite(_val), formatter)?;
+                    formatter.write_str(")")?;
+                    Ok(())
+                }
+            }
+            formatter.field("generics", Print::ref_cast(val));
+        }
+        formatter.field("ty", Lite(&_val.ty));
+        formatter.finish()
+    }
+}
 impl Debug for Lite<syn::AttrStyle> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;
@@ -255,15 +305,6 @@ impl Debug for Lite<syn::BinOp> {
         }
     }
 }
-impl Debug for Lite<syn::Binding> {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        let _val = &self.value;
-        let mut formatter = formatter.debug_struct("Binding");
-        formatter.field("ident", Lite(&_val.ident));
-        formatter.field("ty", Lite(&_val.ty));
-        formatter.finish()
-    }
-}
 impl Debug for Lite<syn::Block> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;
@@ -329,6 +370,22 @@ impl Debug for Lite<syn::Constraint> {
         let _val = &self.value;
         let mut formatter = formatter.debug_struct("Constraint");
         formatter.field("ident", Lite(&_val.ident));
+        if let Some(val) = &_val.generics {
+            #[derive(RefCast)]
+            #[repr(transparent)]
+            struct Print(syn::AngleBracketedGenericArguments);
+            impl Debug for Print {
+                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                    formatter.write_str("Some")?;
+                    let _val = &self.0;
+                    formatter.write_str("(")?;
+                    Debug::fmt(Lite(_val), formatter)?;
+                    formatter.write_str(")")?;
+                    Ok(())
+                }
+            }
+            formatter.field("generics", Print::ref_cast(val));
+        }
         if !_val.bounds.is_empty() {
             formatter.field("bounds", Lite(&_val.bounds));
         }
@@ -2305,8 +2362,15 @@ impl Debug for Lite<syn::GenericArgument> {
                 formatter.write_str(")")?;
                 Ok(())
             }
-            syn::GenericArgument::Binding(_val) => {
-                formatter.write_str("Binding")?;
+            syn::GenericArgument::AssocType(_val) => {
+                formatter.write_str("AssocType")?;
+                formatter.write_str("(")?;
+                Debug::fmt(Lite(_val), formatter)?;
+                formatter.write_str(")")?;
+                Ok(())
+            }
+            syn::GenericArgument::AssocConst(_val) => {
+                formatter.write_str("AssocConst")?;
                 formatter.write_str("(")?;
                 Debug::fmt(Lite(_val), formatter)?;
                 formatter.write_str(")")?;