• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::punctuated::Punctuated;
3 
4 ast_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 
13 impl<T> From<T> for Path
14 where
15     T: Into<PathSegment>,
16 {
from(segment: T) -> Self17     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 
27 impl 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     /// ```
is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>,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.
get_ident(&self) -> Option<&Ident>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")))]
require_ident(&self) -> Result<&Ident>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 
100 ast_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 
109 impl<T> From<T> for PathSegment
110 where
111     T: Into<Ident>,
112 {
from(ident: T) -> Self113     fn from(ident: T) -> Self {
114         PathSegment {
115             ident: ident.into(),
116             arguments: PathArguments::None,
117         }
118     }
119 }
120 
121 ast_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 
141 impl Default for PathArguments {
default() -> Self142     fn default() -> Self {
143         PathArguments::None
144     }
145 }
146 
147 impl PathArguments {
is_empty(&self) -> bool148     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 
is_none(&self) -> bool156     pub fn is_none(&self) -> bool {
157         match self {
158             PathArguments::None => true,
159             PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
160         }
161     }
162 }
163 
164 ast_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 
189 ast_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 
201 ast_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 
213 ast_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 
225 ast_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 
236 ast_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 
249 ast_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")]
277 pub(crate) mod parsing {
278     use super::*;
279 
280     use crate::ext::IdentExt;
281     use crate::parse::{Parse, ParseStream, Result};
282 
283     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
284     impl Parse for Path {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>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 
const_argument(input: ParseStream) -> Result<Expr>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"))))]
parse_turbofish(input: ParseStream) -> Result<Self>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 
do_parse(colon2_token: Option<Token![::]>, input: ParseStream) -> Result<Self>427         fn do_parse(colon2_token: Option<Token![::]>, input: ParseStream) -> Result<Self> {
428             Ok(AngleBracketedGenericArguments {
429                 colon2_token,
430                 lt_token: input.parse()?,
431                 args: {
432                     let mut args = Punctuated::new();
433                     loop {
434                         if input.peek(Token![>]) {
435                             break;
436                         }
437                         let value: GenericArgument = input.parse()?;
438                         args.push_value(value);
439                         if input.peek(Token![>]) {
440                             break;
441                         }
442                         let punct: Token![,] = input.parse()?;
443                         args.push_punct(punct);
444                     }
445                     args
446                 },
447                 gt_token: input.parse()?,
448             })
449         }
450     }
451 
452     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
453     impl Parse for AngleBracketedGenericArguments {
parse(input: ParseStream) -> Result<Self>454         fn parse(input: ParseStream) -> Result<Self> {
455             let colon2_token: Option<Token![::]> = input.parse()?;
456             Self::do_parse(colon2_token, input)
457         }
458     }
459 
460     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
461     impl Parse for ParenthesizedGenericArguments {
parse(input: ParseStream) -> Result<Self>462         fn parse(input: ParseStream) -> Result<Self> {
463             let content;
464             Ok(ParenthesizedGenericArguments {
465                 paren_token: parenthesized!(content in input),
466                 inputs: content.parse_terminated(Type::parse, Token![,])?,
467                 output: input.call(ReturnType::without_plus)?,
468             })
469         }
470     }
471 
472     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
473     impl Parse for PathSegment {
parse(input: ParseStream) -> Result<Self>474         fn parse(input: ParseStream) -> Result<Self> {
475             Self::parse_helper(input, false)
476         }
477     }
478 
479     impl PathSegment {
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>480         fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
481             if input.peek(Token![super])
482                 || input.peek(Token![self])
483                 || input.peek(Token![crate])
484                 || cfg!(feature = "full") && input.peek(Token![try])
485             {
486                 let ident = input.call(Ident::parse_any)?;
487                 return Ok(PathSegment::from(ident));
488             }
489 
490             let ident = if input.peek(Token![Self]) {
491                 input.call(Ident::parse_any)?
492             } else {
493                 input.parse()?
494             };
495 
496             if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
497                 || input.peek(Token![::]) && input.peek3(Token![<])
498             {
499                 Ok(PathSegment {
500                     ident,
501                     arguments: PathArguments::AngleBracketed(input.parse()?),
502                 })
503             } else {
504                 Ok(PathSegment::from(ident))
505             }
506         }
507     }
508 
509     impl Path {
510         /// Parse a `Path` containing no path arguments on any of its segments.
511         ///
512         /// # Example
513         ///
514         /// ```
515         /// use syn::{Path, Result, Token};
516         /// use syn::parse::{Parse, ParseStream};
517         ///
518         /// // A simplified single `use` statement like:
519         /// //
520         /// //     use std::collections::HashMap;
521         /// //
522         /// // Note that generic parameters are not allowed in a `use` statement
523         /// // so the following must not be accepted.
524         /// //
525         /// //     use a::<b>::c;
526         /// struct SingleUse {
527         ///     use_token: Token![use],
528         ///     path: Path,
529         /// }
530         ///
531         /// impl Parse for SingleUse {
532         ///     fn parse(input: ParseStream) -> Result<Self> {
533         ///         Ok(SingleUse {
534         ///             use_token: input.parse()?,
535         ///             path: input.call(Path::parse_mod_style)?,
536         ///         })
537         ///     }
538         /// }
539         /// ```
540         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_mod_style(input: ParseStream) -> Result<Self>541         pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
542             Ok(Path {
543                 leading_colon: input.parse()?,
544                 segments: {
545                     let mut segments = Punctuated::new();
546                     loop {
547                         if !input.peek(Ident)
548                             && !input.peek(Token![super])
549                             && !input.peek(Token![self])
550                             && !input.peek(Token![Self])
551                             && !input.peek(Token![crate])
552                         {
553                             break;
554                         }
555                         let ident = Ident::parse_any(input)?;
556                         segments.push_value(PathSegment::from(ident));
557                         if !input.peek(Token![::]) {
558                             break;
559                         }
560                         let punct = input.parse()?;
561                         segments.push_punct(punct);
562                     }
563                     if segments.is_empty() {
564                         return Err(input.parse::<Ident>().unwrap_err());
565                     } else if segments.trailing_punct() {
566                         return Err(input.error("expected path segment after `::`"));
567                     }
568                     segments
569                 },
570             })
571         }
572 
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>573         pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
574             let mut path = Path {
575                 leading_colon: input.parse()?,
576                 segments: {
577                     let mut segments = Punctuated::new();
578                     let value = PathSegment::parse_helper(input, expr_style)?;
579                     segments.push_value(value);
580                     segments
581                 },
582             };
583             Path::parse_rest(input, &mut path, expr_style)?;
584             Ok(path)
585         }
586 
parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>587         pub(crate) fn parse_rest(
588             input: ParseStream,
589             path: &mut Self,
590             expr_style: bool,
591         ) -> Result<()> {
592             while input.peek(Token![::]) && !input.peek3(token::Paren) {
593                 let punct: Token![::] = input.parse()?;
594                 path.segments.push_punct(punct);
595                 let value = PathSegment::parse_helper(input, expr_style)?;
596                 path.segments.push_value(value);
597             }
598             Ok(())
599         }
600 
is_mod_style(&self) -> bool601         pub(crate) fn is_mod_style(&self) -> bool {
602             self.segments
603                 .iter()
604                 .all(|segment| segment.arguments.is_none())
605         }
606     }
607 
qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>608     pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
609         if input.peek(Token![<]) {
610             let lt_token: Token![<] = input.parse()?;
611             let this: Type = input.parse()?;
612             let path = if input.peek(Token![as]) {
613                 let as_token: Token![as] = input.parse()?;
614                 let path: Path = input.parse()?;
615                 Some((as_token, path))
616             } else {
617                 None
618             };
619             let gt_token: Token![>] = input.parse()?;
620             let colon2_token: Token![::] = input.parse()?;
621             let mut rest = Punctuated::new();
622             loop {
623                 let path = PathSegment::parse_helper(input, expr_style)?;
624                 rest.push_value(path);
625                 if !input.peek(Token![::]) {
626                     break;
627                 }
628                 let punct: Token![::] = input.parse()?;
629                 rest.push_punct(punct);
630             }
631             let (position, as_token, path) = match path {
632                 Some((as_token, mut path)) => {
633                     let pos = path.segments.len();
634                     path.segments.push_punct(colon2_token);
635                     path.segments.extend(rest.into_pairs());
636                     (pos, Some(as_token), path)
637                 }
638                 None => {
639                     let path = Path {
640                         leading_colon: Some(colon2_token),
641                         segments: rest,
642                     };
643                     (0, None, path)
644                 }
645             };
646             let qself = QSelf {
647                 lt_token,
648                 ty: Box::new(this),
649                 position,
650                 as_token,
651                 gt_token,
652             };
653             Ok((Some(qself), path))
654         } else {
655             let path = Path::parse_helper(input, expr_style)?;
656             Ok((None, path))
657         }
658     }
659 }
660 
661 #[cfg(feature = "printing")]
662 pub(crate) mod printing {
663     use super::*;
664     use crate::print::TokensOrDefault;
665     #[cfg(feature = "parsing")]
666     use crate::spanned::Spanned;
667     #[cfg(feature = "parsing")]
668     use proc_macro2::Span;
669     use proc_macro2::TokenStream;
670     use quote::ToTokens;
671     use std::cmp;
672 
673     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
674     impl ToTokens for Path {
to_tokens(&self, tokens: &mut TokenStream)675         fn to_tokens(&self, tokens: &mut TokenStream) {
676             self.leading_colon.to_tokens(tokens);
677             self.segments.to_tokens(tokens);
678         }
679     }
680 
681     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
682     impl ToTokens for PathSegment {
to_tokens(&self, tokens: &mut TokenStream)683         fn to_tokens(&self, tokens: &mut TokenStream) {
684             self.ident.to_tokens(tokens);
685             self.arguments.to_tokens(tokens);
686         }
687     }
688 
689     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
690     impl ToTokens for PathArguments {
to_tokens(&self, tokens: &mut TokenStream)691         fn to_tokens(&self, tokens: &mut TokenStream) {
692             match self {
693                 PathArguments::None => {}
694                 PathArguments::AngleBracketed(arguments) => {
695                     arguments.to_tokens(tokens);
696                 }
697                 PathArguments::Parenthesized(arguments) => {
698                     arguments.to_tokens(tokens);
699                 }
700             }
701         }
702     }
703 
704     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
705     impl ToTokens for GenericArgument {
706         #[allow(clippy::match_same_arms)]
to_tokens(&self, tokens: &mut TokenStream)707         fn to_tokens(&self, tokens: &mut TokenStream) {
708             match self {
709                 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
710                 GenericArgument::Type(ty) => ty.to_tokens(tokens),
711                 GenericArgument::Const(expr) => match expr {
712                     Expr::Lit(expr) => expr.to_tokens(tokens),
713 
714                     Expr::Path(expr)
715                         if expr.attrs.is_empty()
716                             && expr.qself.is_none()
717                             && expr.path.get_ident().is_some() =>
718                     {
719                         expr.to_tokens(tokens);
720                     }
721 
722                     #[cfg(feature = "full")]
723                     Expr::Block(expr) => expr.to_tokens(tokens),
724 
725                     #[cfg(not(feature = "full"))]
726                     Expr::Verbatim(expr) => expr.to_tokens(tokens),
727 
728                     // ERROR CORRECTION: Add braces to make sure that the
729                     // generated code is valid.
730                     _ => token::Brace::default().surround(tokens, |tokens| {
731                         expr.to_tokens(tokens);
732                     }),
733                 },
734                 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
735                 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
736                 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
737             }
738         }
739     }
740 
741     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
742     impl ToTokens for AngleBracketedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)743         fn to_tokens(&self, tokens: &mut TokenStream) {
744             self.colon2_token.to_tokens(tokens);
745             self.lt_token.to_tokens(tokens);
746 
747             // Print lifetimes before types/consts/bindings, regardless of their
748             // order in self.args.
749             let mut trailing_or_empty = true;
750             for param in self.args.pairs() {
751                 match param.value() {
752                     GenericArgument::Lifetime(_) => {
753                         param.to_tokens(tokens);
754                         trailing_or_empty = param.punct().is_some();
755                     }
756                     GenericArgument::Type(_)
757                     | GenericArgument::Const(_)
758                     | GenericArgument::AssocType(_)
759                     | GenericArgument::AssocConst(_)
760                     | GenericArgument::Constraint(_) => {}
761                 }
762             }
763             for param in self.args.pairs() {
764                 match param.value() {
765                     GenericArgument::Type(_)
766                     | GenericArgument::Const(_)
767                     | GenericArgument::AssocType(_)
768                     | GenericArgument::AssocConst(_)
769                     | GenericArgument::Constraint(_) => {
770                         if !trailing_or_empty {
771                             <Token![,]>::default().to_tokens(tokens);
772                         }
773                         param.to_tokens(tokens);
774                         trailing_or_empty = param.punct().is_some();
775                     }
776                     GenericArgument::Lifetime(_) => {}
777                 }
778             }
779 
780             self.gt_token.to_tokens(tokens);
781         }
782     }
783 
784     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
785     impl ToTokens for AssocType {
to_tokens(&self, tokens: &mut TokenStream)786         fn to_tokens(&self, tokens: &mut TokenStream) {
787             self.ident.to_tokens(tokens);
788             self.generics.to_tokens(tokens);
789             self.eq_token.to_tokens(tokens);
790             self.ty.to_tokens(tokens);
791         }
792     }
793 
794     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
795     impl ToTokens for AssocConst {
to_tokens(&self, tokens: &mut TokenStream)796         fn to_tokens(&self, tokens: &mut TokenStream) {
797             self.ident.to_tokens(tokens);
798             self.generics.to_tokens(tokens);
799             self.eq_token.to_tokens(tokens);
800             self.value.to_tokens(tokens);
801         }
802     }
803 
804     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
805     impl ToTokens for Constraint {
to_tokens(&self, tokens: &mut TokenStream)806         fn to_tokens(&self, tokens: &mut TokenStream) {
807             self.ident.to_tokens(tokens);
808             self.generics.to_tokens(tokens);
809             self.colon_token.to_tokens(tokens);
810             self.bounds.to_tokens(tokens);
811         }
812     }
813 
814     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
815     impl ToTokens for ParenthesizedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)816         fn to_tokens(&self, tokens: &mut TokenStream) {
817             self.paren_token.surround(tokens, |tokens| {
818                 self.inputs.to_tokens(tokens);
819             });
820             self.output.to_tokens(tokens);
821         }
822     }
823 
print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)824     pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
825         let qself = match qself {
826             Some(qself) => qself,
827             None => {
828                 path.to_tokens(tokens);
829                 return;
830             }
831         };
832         qself.lt_token.to_tokens(tokens);
833         qself.ty.to_tokens(tokens);
834 
835         let pos = cmp::min(qself.position, path.segments.len());
836         let mut segments = path.segments.pairs();
837         if pos > 0 {
838             TokensOrDefault(&qself.as_token).to_tokens(tokens);
839             path.leading_colon.to_tokens(tokens);
840             for (i, segment) in segments.by_ref().take(pos).enumerate() {
841                 if i + 1 == pos {
842                     segment.value().to_tokens(tokens);
843                     qself.gt_token.to_tokens(tokens);
844                     segment.punct().to_tokens(tokens);
845                 } else {
846                     segment.to_tokens(tokens);
847                 }
848             }
849         } else {
850             qself.gt_token.to_tokens(tokens);
851             path.leading_colon.to_tokens(tokens);
852         }
853         for segment in segments {
854             segment.to_tokens(tokens);
855         }
856     }
857 
858     #[cfg(feature = "parsing")]
859     #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
860     impl Spanned for QSelf {
span(&self) -> Span861         fn span(&self) -> Span {
862             struct QSelfDelimiters<'a>(&'a QSelf);
863 
864             impl<'a> ToTokens for QSelfDelimiters<'a> {
865                 fn to_tokens(&self, tokens: &mut TokenStream) {
866                     self.0.lt_token.to_tokens(tokens);
867                     self.0.gt_token.to_tokens(tokens);
868                 }
869             }
870 
871             QSelfDelimiters(self).span()
872         }
873     }
874 }
875