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