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