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