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