Repository: dtolnay/syn
Pull request #1321 (2023-01-23 07:19:11)

Delete MethodTurbofish in favor of AngleBracketedGenericArguments
Following #1320, these are practically equivalent pieces of syntax.


Patch:
diff --git a/src/expr.rs b/src/expr.rs
index ad8909f7..7d32e4d5 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -526,7 +526,7 @@ ast_struct! {
         pub receiver: Box<Expr>,
         pub dot_token: Token![.],
         pub method: Ident,
-        pub turbofish: Option<MethodTurbofish>,
+        pub turbofish: Option<AngleBracketedGenericArguments>,
         pub paren_token: token::Paren,
         pub args: Punctuated<Expr, Token![,]>,
     }
@@ -858,19 +858,6 @@ impl IdentFragment for Index {
     }
 }
 
-#[cfg(feature = "full")]
-ast_struct! {
-    /// The `::<>` explicit type parameters passed to a method call:
-    /// `parse::<u64>()`.
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
-    pub struct MethodTurbofish {
-        pub colon2_token: Token![::],
-        pub lt_token: Token![<],
-        pub args: Punctuated<GenericArgument, Token![,]>,
-        pub gt_token: Token![>],
-    }
-}
-
 #[cfg(feature = "full")]
 ast_struct! {
     /// A field-value pair in a struct literal.
@@ -1473,7 +1460,7 @@ pub(crate) mod parsing {
 
                 let member: Member = input.parse()?;
                 let turbofish = if member.is_named() && input.peek(Token![::]) {
-                    Some(input.parse::<MethodTurbofish>()?)
+                    Some(AngleBracketedGenericArguments::parse_turbofish(input)?)
                 } else {
                     None
                 };
@@ -1946,34 +1933,6 @@ pub(crate) mod parsing {
         })
     }
 
-    #[cfg(feature = "full")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
-    impl Parse for MethodTurbofish {
-        fn parse(input: ParseStream) -> Result<Self> {
-            Ok(MethodTurbofish {
-                colon2_token: input.parse()?,
-                lt_token: input.parse()?,
-                args: {
-                    let mut args = Punctuated::new();
-                    loop {
-                        if input.peek(Token![>]) {
-                            break;
-                        }
-                        let value: GenericArgument = input.parse()?;
-                        args.push_value(value);
-                        if input.peek(Token![>]) {
-                            break;
-                        }
-                        let punct = input.parse()?;
-                        args.push_punct(punct);
-                    }
-                    args
-                },
-                gt_token: input.parse()?,
-            })
-        }
-    }
-
     #[cfg(feature = "full")]
     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
     impl Parse for ExprLet {
@@ -2855,17 +2814,6 @@ pub(crate) mod printing {
         }
     }
 
-    #[cfg(feature = "full")]
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
-    impl ToTokens for MethodTurbofish {
-        fn to_tokens(&self, tokens: &mut TokenStream) {
-            self.colon2_token.to_tokens(tokens);
-            self.lt_token.to_tokens(tokens);
-            self.args.to_tokens(tokens);
-            self.gt_token.to_tokens(tokens);
-        }
-    }
-
     #[cfg(feature = "full")]
     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
     impl ToTokens for ExprTuple {
diff --git a/src/gen/clone.rs b/src/gen/clone.rs
index cf7f3a41..06ab49c6 100644
--- a/src/gen/clone.rs
+++ b/src/gen/clone.rs
@@ -1418,18 +1418,6 @@ impl Clone for MetaNameValue {
         }
     }
 }
-#[cfg(feature = "full")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
-impl Clone for MethodTurbofish {
-    fn clone(&self) -> Self {
-        MethodTurbofish {
-            colon2_token: self.colon2_token.clone(),
-            lt_token: self.lt_token.clone(),
-            args: self.args.clone(),
-            gt_token: self.gt_token.clone(),
-        }
-    }
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Clone for ParenthesizedGenericArguments {
diff --git a/src/gen/debug.rs b/src/gen/debug.rs
index da7b45e1..bde6a00f 100644
--- a/src/gen/debug.rs
+++ b/src/gen/debug.rs
@@ -1952,18 +1952,6 @@ impl Debug for MetaNameValue {
         formatter.finish()
     }
 }
-#[cfg(feature = "full")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Debug for MethodTurbofish {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        let mut formatter = formatter.debug_struct("MethodTurbofish");
-        formatter.field("colon2_token", &self.colon2_token);
-        formatter.field("lt_token", &self.lt_token);
-        formatter.field("args", &self.args);
-        formatter.field("gt_token", &self.gt_token);
-        formatter.finish()
-    }
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for ParenthesizedGenericArguments {
diff --git a/src/gen/eq.rs b/src/gen/eq.rs
index 384988c2..3787ebd8 100644
--- a/src/gen/eq.rs
+++ b/src/gen/eq.rs
@@ -1341,16 +1341,6 @@ impl PartialEq for MetaNameValue {
         self.path == other.path && self.value == other.value
     }
 }
-#[cfg(feature = "full")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Eq for MethodTurbofish {}
-#[cfg(feature = "full")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl PartialEq for MethodTurbofish {
-    fn eq(&self, other: &Self) -> bool {
-        self.args == other.args
-    }
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for ParenthesizedGenericArguments {}
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 953d5461..e013219a 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -484,10 +484,6 @@ pub trait Fold {
     fn fold_meta_name_value(&mut self, i: MetaNameValue) -> MetaNameValue {
         fold_meta_name_value(self, i)
     }
-    #[cfg(feature = "full")]
-    fn fold_method_turbofish(&mut self, i: MethodTurbofish) -> MethodTurbofish {
-        fold_method_turbofish(self, i)
-    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn fold_parenthesized_generic_arguments(
         &mut self,
@@ -1407,7 +1403,8 @@ where
         receiver: Box::new(f.fold_expr(*node.receiver)),
         dot_token: Token![.](tokens_helper(f, &node.dot_token.spans)),
         method: f.fold_ident(node.method),
-        turbofish: (node.turbofish).map(|it| f.fold_method_turbofish(it)),
+        turbofish: (node.turbofish)
+            .map(|it| f.fold_angle_bracketed_generic_arguments(it)),
         paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
         args: FoldHelper::lift(node.args, |it| f.fold_expr(it)),
     }
@@ -2392,18 +2389,6 @@ where
         value: f.fold_expr(node.value),
     }
 }
-#[cfg(feature = "full")]
-pub fn fold_method_turbofish<F>(f: &mut F, node: MethodTurbofish) -> MethodTurbofish
-where
-    F: Fold + ?Sized,
-{
-    MethodTurbofish {
-        colon2_token: Token![::](tokens_helper(f, &node.colon2_token.spans)),
-        lt_token: Token![<](tokens_helper(f, &node.lt_token.spans)),
-        args: FoldHelper::lift(node.args, |it| f.fold_generic_argument(it)),
-        gt_token: Token![>](tokens_helper(f, &node.gt_token.spans)),
-    }
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn fold_parenthesized_generic_arguments<F>(
     f: &mut F,
diff --git a/src/gen/hash.rs b/src/gen/hash.rs
index 2a4cc3b1..e6a08963 100644
--- a/src/gen/hash.rs
+++ b/src/gen/hash.rs
@@ -1799,16 +1799,6 @@ impl Hash for MetaNameValue {
         self.value.hash(state);
     }
 }
-#[cfg(feature = "full")]
-#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
-impl Hash for MethodTurbofish {
-    fn hash<H>(&self, state: &mut H)
-    where
-        H: Hasher,
-    {
-        self.args.hash(state);
-    }
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for ParenthesizedGenericArguments {
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index 5d6fa296..56492b09 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -486,10 +486,6 @@ pub trait Visit<'ast> {
     fn visit_meta_name_value(&mut self, i: &'ast MetaNameValue) {
         visit_meta_name_value(self, i);
     }
-    #[cfg(feature = "full")]
-    fn visit_method_turbofish(&mut self, i: &'ast MethodTurbofish) {
-        visit_method_turbofish(self, i);
-    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_parenthesized_generic_arguments(
         &mut self,
@@ -1537,7 +1533,7 @@ where
     tokens_helper(v, &node.dot_token.spans);
     v.visit_ident(&node.method);
     if let Some(it) = &node.turbofish {
-        v.visit_method_turbofish(it);
+        v.visit_angle_bracketed_generic_arguments(it);
     }
     tokens_helper(v, &node.paren_token.span);
     for el in Punctuated::pairs(&node.args) {
@@ -2662,22 +2658,6 @@ where
     tokens_helper(v, &node.eq_token.spans);
     v.visit_expr(&node.value);
 }
-#[cfg(feature = "full")]
-pub fn visit_method_turbofish<'ast, V>(v: &mut V, node: &'ast MethodTurbofish)
-where
-    V: Visit<'ast> + ?Sized,
-{
-    tokens_helper(v, &node.colon2_token.spans);
-    tokens_helper(v, &node.lt_token.spans);
-    for el in Punctuated::pairs(&node.args) {
-        let (it, p) = el.into_tuple();
-        v.visit_generic_argument(it);
-        if let Some(p) = p {
-            tokens_helper(v, &p.spans);
-        }
-    }
-    tokens_helper(v, &node.gt_token.spans);
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_parenthesized_generic_arguments<'ast, V>(
     v: &mut V,
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index e9453b99..75685f57 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -487,10 +487,6 @@ pub trait VisitMut {
     fn visit_meta_name_value_mut(&mut self, i: &mut MetaNameValue) {
         visit_meta_name_value_mut(self, i);
     }
-    #[cfg(feature = "full")]
-    fn visit_method_turbofish_mut(&mut self, i: &mut MethodTurbofish) {
-        visit_method_turbofish_mut(self, i);
-    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_parenthesized_generic_arguments_mut(
         &mut self,
@@ -1538,7 +1534,7 @@ where
     tokens_helper(v, &mut node.dot_token.spans);
     v.visit_ident_mut(&mut node.method);
     if let Some(it) = &mut node.turbofish {
-        v.visit_method_turbofish_mut(it);
+        v.visit_angle_bracketed_generic_arguments_mut(it);
     }
     tokens_helper(v, &mut node.paren_token.span);
     for el in Punctuated::pairs_mut(&mut node.args) {
@@ -2665,22 +2661,6 @@ where
     tokens_helper(v, &mut node.eq_token.spans);
     v.visit_expr_mut(&mut node.value);
 }
-#[cfg(feature = "full")]
-pub fn visit_method_turbofish_mut<V>(v: &mut V, node: &mut MethodTurbofish)
-where
-    V: VisitMut + ?Sized,
-{
-    tokens_helper(v, &mut node.colon2_token.spans);
-    tokens_helper(v, &mut node.lt_token.spans);
-    for el in Punctuated::pairs_mut(&mut node.args) {
-        let (it, p) = el.into_tuple();
-        v.visit_generic_argument_mut(it);
-        if let Some(p) = p {
-            tokens_helper(v, &mut p.spans);
-        }
-    }
-    tokens_helper(v, &mut node.gt_token.spans);
-}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_parenthesized_generic_arguments_mut<V>(
     v: &mut V,
diff --git a/src/lib.rs b/src/lib.rs
index 617500ac..9ca8e520 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -345,7 +345,7 @@ pub use crate::error::{Error, Result};
 #[cfg(any(feature = "full", feature = "derive"))]
 mod expr;
 #[cfg(feature = "full")]
-pub use crate::expr::{Arm, FieldValue, Label, MethodTurbofish, RangeLimits};
+pub use crate::expr::{Arm, FieldValue, Label, RangeLimits};
 #[cfg(any(feature = "full", feature = "derive"))]
 pub use crate::expr::{
     Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock,
diff --git a/src/path.rs b/src/path.rs
index 369af385..9a53fb5b 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -328,11 +328,21 @@ pub mod parsing {
         Err(lookahead.error())
     }
 
-    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
-    impl Parse for AngleBracketedGenericArguments {
-        fn parse(input: ParseStream) -> Result<Self> {
+    impl AngleBracketedGenericArguments {
+        /// Parse `::<…>` with mandatory leading `::`.
+        ///
+        /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`
+        /// parses optional leading `::`.
+        #[cfg(feature = "full")]
+        #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
+        pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
+            let colon2_token: Token![::] = input.parse()?;
+            Self::do_parse(Some(colon2_token), input)
+        }
+
+        fn do_parse(colon2_token: Option<Token![::]>, input: ParseStream) -> Result<Self> {
             Ok(AngleBracketedGenericArguments {
-                colon2_token: input.parse()?,
+                colon2_token,
                 lt_token: input.parse()?,
                 args: {
                     let mut args = Punctuated::new();
@@ -340,12 +350,12 @@ pub mod parsing {
                         if input.peek(Token![>]) {
                             break;
                         }
-                        let value = input.parse()?;
+                        let value: GenericArgument = input.parse()?;
                         args.push_value(value);
                         if input.peek(Token![>]) {
                             break;
                         }
-                        let punct = input.parse()?;
+                        let punct: Token![,] = input.parse()?;
                         args.push_punct(punct);
                     }
                     args
@@ -355,6 +365,14 @@ pub mod parsing {
         }
     }
 
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+    impl Parse for AngleBracketedGenericArguments {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let colon2_token: Option<Token![::]> = input.parse()?;
+            Self::do_parse(colon2_token, input)
+        }
+    }
+
     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
     impl Parse for ParenthesizedGenericArguments {
         fn parse(input: ParseStream) -> Result<Self> {
diff --git a/syn.json b/syn.json
index d8b59577..fcb69a99 100644
--- a/syn.json
+++ b/syn.json
@@ -1481,7 +1481,7 @@
         },
         "turbofish": {
           "option": {
-            "syn": "MethodTurbofish"
+            "syn": "AngleBracketedGenericArguments"
           }
         },
         "paren_token": {
@@ -3580,33 +3580,6 @@
         }
       }
     },
-    {
-      "ident": "MethodTurbofish",
-      "features": {
-        "any": [
-          "full"
-        ]
-      },
-      "fields": {
-        "colon2_token": {
-          "token": "Colon2"
-        },
-        "lt_token": {
-          "token": "Lt"
-        },
-        "args": {
-          "punctuated": {
-            "element": {
-              "syn": "GenericArgument"
-            },
-            "punct": "Comma"
-          }
-        },
-        "gt_token": {
-          "token": "Gt"
-        }
-      }
-    },
     {
       "ident": "ParenthesizedGenericArguments",
       "features": {


Test patch:
diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs
index ecaaf01d..867b37bb 100644
--- a/tests/debug/gen.rs
+++ b/tests/debug/gen.rs
@@ -838,7 +838,7 @@ impl Debug for Lite<syn::Expr> {
                 if let Some(val) = &_val.turbofish {
                     #[derive(RefCast)]
                     #[repr(transparent)]
-                    struct Print(syn::MethodTurbofish);
+                    struct Print(syn::AngleBracketedGenericArguments);
                     impl Debug for Print {
                         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                             formatter.write_str("Some")?;
@@ -1622,7 +1622,7 @@ impl Debug for Lite<syn::ExprMethodCall> {
         if let Some(val) = &_val.turbofish {
             #[derive(RefCast)]
             #[repr(transparent)]
-            struct Print(syn::MethodTurbofish);
+            struct Print(syn::AngleBracketedGenericArguments);
             impl Debug for Print {
                 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                     formatter.write_str("Some")?;
@@ -3700,16 +3700,6 @@ impl Debug for Lite<syn::MetaNameValue> {
         formatter.finish()
     }
 }
-impl Debug for Lite<syn::MethodTurbofish> {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        let _val = &self.value;
-        let mut formatter = formatter.debug_struct("MethodTurbofish");
-        if !_val.args.is_empty() {
-            formatter.field("args", Lite(&_val.args));
-        }
-        formatter.finish()
-    }
-}
 impl Debug for Lite<syn::ParenthesizedGenericArguments> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;