syn/
path.rs

1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5    /// A path at which a named item is exported (e.g. `std::collections::HashMap`).
6    ///
7    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
8    /// feature.*
9    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
10    pub struct Path {
11        pub leading_colon: Option<Token![::]>,
12        pub segments: Punctuated<PathSegment, Token![::]>,
13    }
14}
15
16impl<T> From<T> for Path
17where
18    T: Into<PathSegment>,
19{
20    fn from(segment: T) -> Self {
21        let mut path = Path {
22            leading_colon: None,
23            segments: Punctuated::new(),
24        };
25        path.segments.push_value(segment.into());
26        path
27    }
28}
29
30ast_struct! {
31    /// A segment of a path together with any path arguments on that segment.
32    ///
33    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
34    /// feature.*
35    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
36    pub struct PathSegment {
37        pub ident: Ident,
38        pub arguments: PathArguments,
39    }
40}
41
42impl<T> From<T> for PathSegment
43where
44    T: Into<Ident>,
45{
46    fn from(ident: T) -> Self {
47        PathSegment {
48            ident: ident.into(),
49            arguments: PathArguments::None,
50        }
51    }
52}
53
54ast_enum! {
55    /// Angle bracketed or parenthesized arguments of a path segment.
56    ///
57    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
58    /// feature.*
59    ///
60    /// ## Angle bracketed
61    ///
62    /// The `<'a, T>` in `std::slice::iter<'a, T>`.
63    ///
64    /// ## Parenthesized
65    ///
66    /// The `(A, B) -> C` in `Fn(A, B) -> C`.
67    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
68    pub enum PathArguments {
69        None,
70        /// The `<'a, T>` in `std::slice::iter<'a, T>`.
71        AngleBracketed(AngleBracketedGenericArguments),
72        /// The `(A, B) -> C` in `Fn(A, B) -> C`.
73        Parenthesized(ParenthesizedGenericArguments),
74    }
75}
76
77impl Default for PathArguments {
78    fn default() -> Self {
79        PathArguments::None
80    }
81}
82
83impl PathArguments {
84    pub fn is_empty(&self) -> bool {
85        match self {
86            PathArguments::None => true,
87            PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
88            PathArguments::Parenthesized(_) => false,
89        }
90    }
91
92    #[cfg(feature = "parsing")]
93    fn is_none(&self) -> bool {
94        match *self {
95            PathArguments::None => true,
96            PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
97        }
98    }
99}
100
101ast_enum! {
102    /// An individual generic argument, like `'a`, `T`, or `Item = T`.
103    ///
104    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
105    /// feature.*
106    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
107    pub enum GenericArgument {
108        /// A lifetime argument.
109        Lifetime(Lifetime),
110        /// A type argument.
111        Type(Type),
112        /// A const expression. Must be inside of a block.
113        ///
114        /// NOTE: Identity expressions are represented as Type arguments, as
115        /// they are indistinguishable syntactically.
116        Const(Expr),
117        /// A binding (equality constraint) on an associated type: the `Item =
118        /// u8` in `Iterator<Item = u8>`.
119        Binding(Binding),
120        /// An associated type bound: `Iterator<Item: Display>`.
121        Constraint(Constraint),
122    }
123}
124
125ast_struct! {
126    /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
127    /// V>`.
128    ///
129    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
130    /// feature.*
131    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
132    pub struct AngleBracketedGenericArguments {
133        pub colon2_token: Option<Token![::]>,
134        pub lt_token: Token![<],
135        pub args: Punctuated<GenericArgument, Token![,]>,
136        pub gt_token: Token![>],
137    }
138}
139
140ast_struct! {
141    /// A binding (equality constraint) on an associated type: `Item = u8`.
142    ///
143    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
144    /// feature.*
145    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
146    pub struct Binding {
147        pub ident: Ident,
148        pub eq_token: Token![=],
149        pub ty: Type,
150    }
151}
152
153ast_struct! {
154    /// An associated type bound: `Iterator<Item: Display>`.
155    ///
156    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
157    /// feature.*
158    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
159    pub struct Constraint {
160        pub ident: Ident,
161        pub colon_token: Token![:],
162        pub bounds: Punctuated<TypeParamBound, Token![+]>,
163    }
164}
165
166ast_struct! {
167    /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
168    /// C`.
169    ///
170    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
171    /// feature.*
172    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
173    pub struct ParenthesizedGenericArguments {
174        pub paren_token: token::Paren,
175        /// `(A, B)`
176        pub inputs: Punctuated<Type, Token![,]>,
177        /// `C`
178        pub output: ReturnType,
179    }
180}
181
182ast_struct! {
183    /// The explicit Self type in a qualified path: the `T` in `<T as
184    /// Display>::fmt`.
185    ///
186    /// The actual path, including the trait and the associated item, is stored
187    /// separately. The `position` field represents the index of the associated
188    /// item qualified with this Self type.
189    ///
190    /// ```text
191    /// <Vec<T> as a::b::Trait>::AssociatedItem
192    ///  ^~~~~~    ~~~~~~~~~~~~~~^
193    ///  ty        position = 3
194    ///
195    /// <Vec<T>>::AssociatedItem
196    ///  ^~~~~~   ^
197    ///  ty       position = 0
198    /// ```
199    ///
200    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
201    /// feature.*
202    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
203    pub struct QSelf {
204        pub lt_token: Token![<],
205        pub ty: Box<Type>,
206        pub position: usize,
207        pub as_token: Option<Token![as]>,
208        pub gt_token: Token![>],
209    }
210}
211
212#[cfg(feature = "parsing")]
213pub mod parsing {
214    use super::*;
215
216    use crate::ext::IdentExt;
217    use crate::parse::{Parse, ParseStream, Result};
218
219    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
220    impl Parse for Path {
221        fn parse(input: ParseStream) -> Result<Self> {
222            Self::parse_helper(input, false)
223        }
224    }
225
226    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
227    impl Parse for GenericArgument {
228        fn parse(input: ParseStream) -> Result<Self> {
229            if input.peek(Lifetime) && !input.peek2(Token![+]) {
230                return Ok(GenericArgument::Lifetime(input.parse()?));
231            }
232
233            if input.peek(Ident) && input.peek2(Token![=]) {
234                let ident: Ident = input.parse()?;
235                let eq_token: Token![=] = input.parse()?;
236
237                let ty = if input.peek(Lit) {
238                    let begin = input.fork();
239                    input.parse::<Lit>()?;
240                    Type::Verbatim(verbatim::between(begin, input))
241                } else if input.peek(token::Brace) {
242                    let begin = input.fork();
243
244                    #[cfg(feature = "full")]
245                    {
246                        input.parse::<ExprBlock>()?;
247                    }
248
249                    #[cfg(not(feature = "full"))]
250                    {
251                        let content;
252                        braced!(content in input);
253                        content.parse::<Expr>()?;
254                    }
255
256                    Type::Verbatim(verbatim::between(begin, input))
257                } else {
258                    input.parse()?
259                };
260
261                return Ok(GenericArgument::Binding(Binding {
262                    ident,
263                    eq_token,
264                    ty,
265                }));
266            }
267
268            #[cfg(feature = "full")]
269            {
270                if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
271                    return Ok(GenericArgument::Constraint(input.parse()?));
272                }
273            }
274
275            if input.peek(Lit) || input.peek(token::Brace) {
276                return const_argument(input).map(GenericArgument::Const);
277            }
278
279            #[cfg(feature = "full")]
280            let begin = input.fork();
281
282            let argument: Type = input.parse()?;
283
284            #[cfg(feature = "full")]
285            {
286                if match &argument {
287                    Type::Path(argument)
288                        if argument.qself.is_none()
289                            && argument.path.leading_colon.is_none()
290                            && argument.path.segments.len() == 1 =>
291                    {
292                        match argument.path.segments[0].arguments {
293                            PathArguments::AngleBracketed(_) => true,
294                            _ => false,
295                        }
296                    }
297                    _ => false,
298                } && if input.peek(Token![=]) {
299                    input.parse::<Token![=]>()?;
300                    input.parse::<Type>()?;
301                    true
302                } else if input.peek(Token![:]) {
303                    input.parse::<Token![:]>()?;
304                    input.call(constraint_bounds)?;
305                    true
306                } else {
307                    false
308                } {
309                    let verbatim = verbatim::between(begin, input);
310                    return Ok(GenericArgument::Type(Type::Verbatim(verbatim)));
311                }
312            }
313
314            Ok(GenericArgument::Type(argument))
315        }
316    }
317
318    pub fn const_argument(input: ParseStream) -> Result<Expr> {
319        let lookahead = input.lookahead1();
320
321        if input.peek(Lit) {
322            let lit = input.parse()?;
323            return Ok(Expr::Lit(lit));
324        }
325
326        #[cfg(feature = "full")]
327        {
328            if input.peek(Ident) {
329                let ident: Ident = input.parse()?;
330                return Ok(Expr::Path(ExprPath {
331                    attrs: Vec::new(),
332                    qself: None,
333                    path: Path::from(ident),
334                }));
335            }
336        }
337
338        if input.peek(token::Brace) {
339            #[cfg(feature = "full")]
340            {
341                let block: ExprBlock = input.parse()?;
342                return Ok(Expr::Block(block));
343            }
344
345            #[cfg(not(feature = "full"))]
346            {
347                let begin = input.fork();
348                let content;
349                braced!(content in input);
350                content.parse::<Expr>()?;
351                let verbatim = verbatim::between(begin, input);
352                return Ok(Expr::Verbatim(verbatim));
353            }
354        }
355
356        Err(lookahead.error())
357    }
358
359    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
360    impl Parse for AngleBracketedGenericArguments {
361        fn parse(input: ParseStream) -> Result<Self> {
362            Ok(AngleBracketedGenericArguments {
363                colon2_token: input.parse()?,
364                lt_token: input.parse()?,
365                args: {
366                    let mut args = Punctuated::new();
367                    loop {
368                        if input.peek(Token![>]) {
369                            break;
370                        }
371                        let value = input.parse()?;
372                        args.push_value(value);
373                        if input.peek(Token![>]) {
374                            break;
375                        }
376                        let punct = input.parse()?;
377                        args.push_punct(punct);
378                    }
379                    args
380                },
381                gt_token: input.parse()?,
382            })
383        }
384    }
385
386    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
387    impl Parse for ParenthesizedGenericArguments {
388        fn parse(input: ParseStream) -> Result<Self> {
389            let content;
390            Ok(ParenthesizedGenericArguments {
391                paren_token: parenthesized!(content in input),
392                inputs: content.parse_terminated(Type::parse)?,
393                output: input.call(ReturnType::without_plus)?,
394            })
395        }
396    }
397
398    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
399    impl Parse for PathSegment {
400        fn parse(input: ParseStream) -> Result<Self> {
401            Self::parse_helper(input, false)
402        }
403    }
404
405    impl PathSegment {
406        fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
407            if input.peek(Token![super]) || input.peek(Token![self]) || input.peek(Token![crate]) {
408                let ident = input.call(Ident::parse_any)?;
409                return Ok(PathSegment::from(ident));
410            }
411
412            let ident = if input.peek(Token![Self]) {
413                input.call(Ident::parse_any)?
414            } else {
415                input.parse()?
416            };
417
418            if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
419                || input.peek(Token![::]) && input.peek3(Token![<])
420            {
421                Ok(PathSegment {
422                    ident,
423                    arguments: PathArguments::AngleBracketed(input.parse()?),
424                })
425            } else {
426                Ok(PathSegment::from(ident))
427            }
428        }
429    }
430
431    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
432    impl Parse for Binding {
433        fn parse(input: ParseStream) -> Result<Self> {
434            Ok(Binding {
435                ident: input.parse()?,
436                eq_token: input.parse()?,
437                ty: input.parse()?,
438            })
439        }
440    }
441
442    #[cfg(feature = "full")]
443    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
444    impl Parse for Constraint {
445        fn parse(input: ParseStream) -> Result<Self> {
446            Ok(Constraint {
447                ident: input.parse()?,
448                colon_token: input.parse()?,
449                bounds: constraint_bounds(input)?,
450            })
451        }
452    }
453
454    #[cfg(feature = "full")]
455    fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
456        let mut bounds = Punctuated::new();
457        loop {
458            if input.peek(Token![,]) || input.peek(Token![>]) {
459                break;
460            }
461            let value = input.parse()?;
462            bounds.push_value(value);
463            if !input.peek(Token![+]) {
464                break;
465            }
466            let punct = input.parse()?;
467            bounds.push_punct(punct);
468        }
469        Ok(bounds)
470    }
471
472    impl Path {
473        /// Parse a `Path` containing no path arguments on any of its segments.
474        ///
475        /// *This function is available only if Syn is built with the `"parsing"`
476        /// feature.*
477        ///
478        /// # Example
479        ///
480        /// ```
481        /// use syn::{Path, Result, Token};
482        /// use syn::parse::{Parse, ParseStream};
483        ///
484        /// // A simplified single `use` statement like:
485        /// //
486        /// //     use std::collections::HashMap;
487        /// //
488        /// // Note that generic parameters are not allowed in a `use` statement
489        /// // so the following must not be accepted.
490        /// //
491        /// //     use a::<b>::c;
492        /// struct SingleUse {
493        ///     use_token: Token![use],
494        ///     path: Path,
495        /// }
496        ///
497        /// impl Parse for SingleUse {
498        ///     fn parse(input: ParseStream) -> Result<Self> {
499        ///         Ok(SingleUse {
500        ///             use_token: input.parse()?,
501        ///             path: input.call(Path::parse_mod_style)?,
502        ///         })
503        ///     }
504        /// }
505        /// ```
506        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
507        pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
508            Ok(Path {
509                leading_colon: input.parse()?,
510                segments: {
511                    let mut segments = Punctuated::new();
512                    loop {
513                        if !input.peek(Ident)
514                            && !input.peek(Token![super])
515                            && !input.peek(Token![self])
516                            && !input.peek(Token![Self])
517                            && !input.peek(Token![crate])
518                        {
519                            break;
520                        }
521                        let ident = Ident::parse_any(input)?;
522                        segments.push_value(PathSegment::from(ident));
523                        if !input.peek(Token![::]) {
524                            break;
525                        }
526                        let punct = input.parse()?;
527                        segments.push_punct(punct);
528                    }
529                    if segments.is_empty() {
530                        return Err(input.error("expected path"));
531                    } else if segments.trailing_punct() {
532                        return Err(input.error("expected path segment"));
533                    }
534                    segments
535                },
536            })
537        }
538
539        /// Determines whether this is a path of length 1 equal to the given
540        /// ident.
541        ///
542        /// For them to compare equal, it must be the case that:
543        ///
544        /// - the path has no leading colon,
545        /// - the number of path segments is 1,
546        /// - the first path segment has no angle bracketed or parenthesized
547        ///   path arguments, and
548        /// - the ident of the first path segment is equal to the given one.
549        ///
550        /// *This function is available only if Syn is built with the `"parsing"`
551        /// feature.*
552        ///
553        /// # Example
554        ///
555        /// ```
556        /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
557        /// # use std::iter::FromIterator;
558        ///
559        /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
560        ///     if attr.path.is_ident("serde") {
561        ///         match attr.parse_meta()? {
562        ///             Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
563        ///             bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
564        ///         }
565        ///     } else {
566        ///         Ok(Vec::new())
567        ///     }
568        /// }
569        /// ```
570        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
571        pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
572        where
573            Ident: PartialEq<I>,
574        {
575            match self.get_ident() {
576                Some(id) => id == ident,
577                None => false,
578            }
579        }
580
581        /// If this path consists of a single ident, returns the ident.
582        ///
583        /// A path is considered an ident if:
584        ///
585        /// - the path has no leading colon,
586        /// - the number of path segments is 1, and
587        /// - the first path segment has no angle bracketed or parenthesized
588        ///   path arguments.
589        ///
590        /// *This function is available only if Syn is built with the `"parsing"`
591        /// feature.*
592        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
593        pub fn get_ident(&self) -> Option<&Ident> {
594            if self.leading_colon.is_none()
595                && self.segments.len() == 1
596                && self.segments[0].arguments.is_none()
597            {
598                Some(&self.segments[0].ident)
599            } else {
600                None
601            }
602        }
603
604        pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
605            let mut path = Path {
606                leading_colon: input.parse()?,
607                segments: {
608                    let mut segments = Punctuated::new();
609                    let value = PathSegment::parse_helper(input, expr_style)?;
610                    segments.push_value(value);
611                    segments
612                },
613            };
614            Path::parse_rest(input, &mut path, expr_style)?;
615            Ok(path)
616        }
617
618        pub(crate) fn parse_rest(
619            input: ParseStream,
620            path: &mut Self,
621            expr_style: bool,
622        ) -> Result<()> {
623            while input.peek(Token![::]) && !input.peek3(token::Paren) {
624                let punct: Token![::] = input.parse()?;
625                path.segments.push_punct(punct);
626                let value = PathSegment::parse_helper(input, expr_style)?;
627                path.segments.push_value(value);
628            }
629            Ok(())
630        }
631    }
632
633    pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
634        if input.peek(Token![<]) {
635            let lt_token: Token![<] = input.parse()?;
636            let this: Type = input.parse()?;
637            let path = if input.peek(Token![as]) {
638                let as_token: Token![as] = input.parse()?;
639                let path: Path = input.parse()?;
640                Some((as_token, path))
641            } else {
642                None
643            };
644            let gt_token: Token![>] = input.parse()?;
645            let colon2_token: Token![::] = input.parse()?;
646            let mut rest = Punctuated::new();
647            loop {
648                let path = PathSegment::parse_helper(input, expr_style)?;
649                rest.push_value(path);
650                if !input.peek(Token![::]) {
651                    break;
652                }
653                let punct: Token![::] = input.parse()?;
654                rest.push_punct(punct);
655            }
656            let (position, as_token, path) = match path {
657                Some((as_token, mut path)) => {
658                    let pos = path.segments.len();
659                    path.segments.push_punct(colon2_token);
660                    path.segments.extend(rest.into_pairs());
661                    (pos, Some(as_token), path)
662                }
663                None => {
664                    let path = Path {
665                        leading_colon: Some(colon2_token),
666                        segments: rest,
667                    };
668                    (0, None, path)
669                }
670            };
671            let qself = QSelf {
672                lt_token,
673                ty: Box::new(this),
674                position,
675                as_token,
676                gt_token,
677            };
678            Ok((Some(qself), path))
679        } else {
680            let path = Path::parse_helper(input, expr_style)?;
681            Ok((None, path))
682        }
683    }
684}
685
686#[cfg(feature = "printing")]
687pub(crate) mod printing {
688    use super::*;
689    use crate::print::TokensOrDefault;
690    use proc_macro2::TokenStream;
691    use quote::ToTokens;
692    use std::cmp;
693
694    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
695    impl ToTokens for Path {
696        fn to_tokens(&self, tokens: &mut TokenStream) {
697            self.leading_colon.to_tokens(tokens);
698            self.segments.to_tokens(tokens);
699        }
700    }
701
702    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
703    impl ToTokens for PathSegment {
704        fn to_tokens(&self, tokens: &mut TokenStream) {
705            self.ident.to_tokens(tokens);
706            self.arguments.to_tokens(tokens);
707        }
708    }
709
710    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
711    impl ToTokens for PathArguments {
712        fn to_tokens(&self, tokens: &mut TokenStream) {
713            match self {
714                PathArguments::None => {}
715                PathArguments::AngleBracketed(arguments) => {
716                    arguments.to_tokens(tokens);
717                }
718                PathArguments::Parenthesized(arguments) => {
719                    arguments.to_tokens(tokens);
720                }
721            }
722        }
723    }
724
725    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
726    impl ToTokens for GenericArgument {
727        #[allow(clippy::match_same_arms)]
728        fn to_tokens(&self, tokens: &mut TokenStream) {
729            match self {
730                GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
731                GenericArgument::Type(ty) => ty.to_tokens(tokens),
732                GenericArgument::Const(e) => match *e {
733                    Expr::Lit(_) => e.to_tokens(tokens),
734
735                    // NOTE: We should probably support parsing blocks with only
736                    // expressions in them without the full feature for const
737                    // generics.
738                    #[cfg(feature = "full")]
739                    Expr::Block(_) => e.to_tokens(tokens),
740
741                    // ERROR CORRECTION: Add braces to make sure that the
742                    // generated code is valid.
743                    _ => token::Brace::default().surround(tokens, |tokens| {
744                        e.to_tokens(tokens);
745                    }),
746                },
747                GenericArgument::Binding(tb) => tb.to_tokens(tokens),
748                GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
749            }
750        }
751    }
752
753    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
754    impl ToTokens for AngleBracketedGenericArguments {
755        fn to_tokens(&self, tokens: &mut TokenStream) {
756            self.colon2_token.to_tokens(tokens);
757            self.lt_token.to_tokens(tokens);
758
759            // Print lifetimes before types/consts/bindings, regardless of their
760            // order in self.args.
761            let mut trailing_or_empty = true;
762            for param in self.args.pairs() {
763                match **param.value() {
764                    GenericArgument::Lifetime(_) => {
765                        param.to_tokens(tokens);
766                        trailing_or_empty = param.punct().is_some();
767                    }
768                    GenericArgument::Type(_)
769                    | GenericArgument::Const(_)
770                    | GenericArgument::Binding(_)
771                    | GenericArgument::Constraint(_) => {}
772                }
773            }
774            for param in self.args.pairs() {
775                match **param.value() {
776                    GenericArgument::Type(_)
777                    | GenericArgument::Const(_)
778                    | GenericArgument::Binding(_)
779                    | GenericArgument::Constraint(_) => {
780                        if !trailing_or_empty {
781                            <Token![,]>::default().to_tokens(tokens);
782                        }
783                        param.to_tokens(tokens);
784                        trailing_or_empty = param.punct().is_some();
785                    }
786                    GenericArgument::Lifetime(_) => {}
787                }
788            }
789
790            self.gt_token.to_tokens(tokens);
791        }
792    }
793
794    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
795    impl ToTokens for Binding {
796        fn to_tokens(&self, tokens: &mut TokenStream) {
797            self.ident.to_tokens(tokens);
798            self.eq_token.to_tokens(tokens);
799            self.ty.to_tokens(tokens);
800        }
801    }
802
803    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
804    impl ToTokens for Constraint {
805        fn to_tokens(&self, tokens: &mut TokenStream) {
806            self.ident.to_tokens(tokens);
807            self.colon_token.to_tokens(tokens);
808            self.bounds.to_tokens(tokens);
809        }
810    }
811
812    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
813    impl ToTokens for ParenthesizedGenericArguments {
814        fn to_tokens(&self, tokens: &mut TokenStream) {
815            self.paren_token.surround(tokens, |tokens| {
816                self.inputs.to_tokens(tokens);
817            });
818            self.output.to_tokens(tokens);
819        }
820    }
821
822    pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
823        let qself = match qself {
824            Some(qself) => qself,
825            None => {
826                path.to_tokens(tokens);
827                return;
828            }
829        };
830        qself.lt_token.to_tokens(tokens);
831        qself.ty.to_tokens(tokens);
832
833        let pos = cmp::min(qself.position, path.segments.len());
834        let mut segments = path.segments.pairs();
835        if pos > 0 {
836            TokensOrDefault(&qself.as_token).to_tokens(tokens);
837            path.leading_colon.to_tokens(tokens);
838            for (i, segment) in segments.by_ref().take(pos).enumerate() {
839                if i + 1 == pos {
840                    segment.value().to_tokens(tokens);
841                    qself.gt_token.to_tokens(tokens);
842                    segment.punct().to_tokens(tokens);
843                } else {
844                    segment.to_tokens(tokens);
845                }
846            }
847        } else {
848            qself.gt_token.to_tokens(tokens);
849            path.leading_colon.to_tokens(tokens);
850        }
851        for segment in segments {
852            segment.to_tokens(tokens);
853        }
854    }
855}