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