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