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         #[cfg(feature = "full")]
296         {
297             if input.peek(Ident) {
298                 let ident: Ident = input.parse()?;
299                 return Ok(Expr::Path(ExprPath {
300                     attrs: Vec::new(),
301                     qself: None,
302                     path: Path::from(ident),
303                 }));
304             }
305         }
306 
307         if input.peek(token::Brace) {
308             #[cfg(feature = "full")]
309             {
310                 let block: ExprBlock = input.parse()?;
311                 return Ok(Expr::Block(block));
312             }
313 
314             #[cfg(not(feature = "full"))]
315             {
316                 let begin = input.fork();
317                 let content;
318                 braced!(content in input);
319                 content.parse::<Expr>()?;
320                 let verbatim = verbatim::between(begin, input);
321                 return Ok(Expr::Verbatim(verbatim));
322             }
323         }
324 
325         Err(lookahead.error())
326     }
327 
328     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
329     impl Parse for AngleBracketedGenericArguments {
parse(input: ParseStream) -> Result<Self>330         fn parse(input: ParseStream) -> Result<Self> {
331             Ok(AngleBracketedGenericArguments {
332                 colon2_token: input.parse()?,
333                 lt_token: input.parse()?,
334                 args: {
335                     let mut args = Punctuated::new();
336                     loop {
337                         if input.peek(Token![>]) {
338                             break;
339                         }
340                         let value = input.parse()?;
341                         args.push_value(value);
342                         if input.peek(Token![>]) {
343                             break;
344                         }
345                         let punct = input.parse()?;
346                         args.push_punct(punct);
347                     }
348                     args
349                 },
350                 gt_token: input.parse()?,
351             })
352         }
353     }
354 
355     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
356     impl Parse for ParenthesizedGenericArguments {
parse(input: ParseStream) -> Result<Self>357         fn parse(input: ParseStream) -> Result<Self> {
358             let content;
359             Ok(ParenthesizedGenericArguments {
360                 paren_token: parenthesized!(content in input),
361                 inputs: content.parse_terminated(Type::parse)?,
362                 output: input.call(ReturnType::without_plus)?,
363             })
364         }
365     }
366 
367     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
368     impl Parse for PathSegment {
parse(input: ParseStream) -> Result<Self>369         fn parse(input: ParseStream) -> Result<Self> {
370             Self::parse_helper(input, false)
371         }
372     }
373 
374     impl PathSegment {
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>375         fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
376             if input.peek(Token![super]) || input.peek(Token![self]) || input.peek(Token![crate]) {
377                 let ident = input.call(Ident::parse_any)?;
378                 return Ok(PathSegment::from(ident));
379             }
380 
381             let ident = if input.peek(Token![Self]) {
382                 input.call(Ident::parse_any)?
383             } else {
384                 input.parse()?
385             };
386 
387             if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
388                 || input.peek(Token![::]) && input.peek3(Token![<])
389             {
390                 Ok(PathSegment {
391                     ident,
392                     arguments: PathArguments::AngleBracketed(input.parse()?),
393                 })
394             } else {
395                 Ok(PathSegment::from(ident))
396             }
397         }
398     }
399 
400     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
401     impl Parse for Binding {
parse(input: ParseStream) -> Result<Self>402         fn parse(input: ParseStream) -> Result<Self> {
403             Ok(Binding {
404                 ident: input.parse()?,
405                 eq_token: input.parse()?,
406                 ty: input.parse()?,
407             })
408         }
409     }
410 
411     #[cfg(feature = "full")]
412     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
413     impl Parse for Constraint {
parse(input: ParseStream) -> Result<Self>414         fn parse(input: ParseStream) -> Result<Self> {
415             Ok(Constraint {
416                 ident: input.parse()?,
417                 colon_token: input.parse()?,
418                 bounds: constraint_bounds(input)?,
419             })
420         }
421     }
422 
423     #[cfg(feature = "full")]
constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>>424     fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
425         let mut bounds = Punctuated::new();
426         loop {
427             if input.peek(Token![,]) || input.peek(Token![>]) {
428                 break;
429             }
430             let value = input.parse()?;
431             bounds.push_value(value);
432             if !input.peek(Token![+]) {
433                 break;
434             }
435             let punct = input.parse()?;
436             bounds.push_punct(punct);
437         }
438         Ok(bounds)
439     }
440 
441     impl Path {
442         /// Parse a `Path` containing no path arguments on any of its segments.
443         ///
444         /// *This function is available only if Syn is built with the `"parsing"`
445         /// feature.*
446         ///
447         /// # Example
448         ///
449         /// ```
450         /// use syn::{Path, Result, Token};
451         /// use syn::parse::{Parse, ParseStream};
452         ///
453         /// // A simplified single `use` statement like:
454         /// //
455         /// //     use std::collections::HashMap;
456         /// //
457         /// // Note that generic parameters are not allowed in a `use` statement
458         /// // so the following must not be accepted.
459         /// //
460         /// //     use a::<b>::c;
461         /// struct SingleUse {
462         ///     use_token: Token![use],
463         ///     path: Path,
464         /// }
465         ///
466         /// impl Parse for SingleUse {
467         ///     fn parse(input: ParseStream) -> Result<Self> {
468         ///         Ok(SingleUse {
469         ///             use_token: input.parse()?,
470         ///             path: input.call(Path::parse_mod_style)?,
471         ///         })
472         ///     }
473         /// }
474         /// ```
475         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_mod_style(input: ParseStream) -> Result<Self>476         pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
477             Ok(Path {
478                 leading_colon: input.parse()?,
479                 segments: {
480                     let mut segments = Punctuated::new();
481                     loop {
482                         if !input.peek(Ident)
483                             && !input.peek(Token![super])
484                             && !input.peek(Token![self])
485                             && !input.peek(Token![Self])
486                             && !input.peek(Token![crate])
487                         {
488                             break;
489                         }
490                         let ident = Ident::parse_any(input)?;
491                         segments.push_value(PathSegment::from(ident));
492                         if !input.peek(Token![::]) {
493                             break;
494                         }
495                         let punct = input.parse()?;
496                         segments.push_punct(punct);
497                     }
498                     if segments.is_empty() {
499                         return Err(input.error("expected path"));
500                     } else if segments.trailing_punct() {
501                         return Err(input.error("expected path segment"));
502                     }
503                     segments
504                 },
505             })
506         }
507 
508         /// Determines whether this is a path of length 1 equal to the given
509         /// ident.
510         ///
511         /// For them to compare equal, it must be the case that:
512         ///
513         /// - the path has no leading colon,
514         /// - the number of path segments is 1,
515         /// - the first path segment has no angle bracketed or parenthesized
516         ///   path arguments, and
517         /// - the ident of the first path segment is equal to the given one.
518         ///
519         /// *This function is available only if Syn is built with the `"parsing"`
520         /// feature.*
521         ///
522         /// # Example
523         ///
524         /// ```
525         /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
526         /// # use std::iter::FromIterator;
527         ///
528         /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
529         ///     if attr.path.is_ident("serde") {
530         ///         match attr.parse_meta()? {
531         ///             Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
532         ///             bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
533         ///         }
534         ///     } else {
535         ///         Ok(Vec::new())
536         ///     }
537         /// }
538         /// ```
539         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
is_ident<I: ?Sized>(&self, ident: &I) -> bool where Ident: PartialEq<I>,540         pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
541         where
542             Ident: PartialEq<I>,
543         {
544             match self.get_ident() {
545                 Some(id) => id == ident,
546                 None => false,
547             }
548         }
549 
550         /// If this path consists of a single ident, returns the ident.
551         ///
552         /// A path is considered an ident if:
553         ///
554         /// - the path has no leading colon,
555         /// - the number of path segments is 1, and
556         /// - the first path segment has no angle bracketed or parenthesized
557         ///   path arguments.
558         ///
559         /// *This function is available only if Syn is built with the `"parsing"`
560         /// feature.*
561         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
get_ident(&self) -> Option<&Ident>562         pub fn get_ident(&self) -> Option<&Ident> {
563             if self.leading_colon.is_none()
564                 && self.segments.len() == 1
565                 && self.segments[0].arguments.is_none()
566             {
567                 Some(&self.segments[0].ident)
568             } else {
569                 None
570             }
571         }
572 
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>573         pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
574             let mut path = Path {
575                 leading_colon: input.parse()?,
576                 segments: {
577                     let mut segments = Punctuated::new();
578                     let value = PathSegment::parse_helper(input, expr_style)?;
579                     segments.push_value(value);
580                     segments
581                 },
582             };
583             Path::parse_rest(input, &mut path, expr_style)?;
584             Ok(path)
585         }
586 
parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>587         pub(crate) fn parse_rest(
588             input: ParseStream,
589             path: &mut Self,
590             expr_style: bool,
591         ) -> Result<()> {
592             while input.peek(Token![::]) && !input.peek3(token::Paren) {
593                 let punct: Token![::] = input.parse()?;
594                 path.segments.push_punct(punct);
595                 let value = PathSegment::parse_helper(input, expr_style)?;
596                 path.segments.push_value(value);
597             }
598             Ok(())
599         }
600     }
601 
qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>602     pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
603         if input.peek(Token![<]) {
604             let lt_token: Token![<] = input.parse()?;
605             let this: Type = input.parse()?;
606             let path = if input.peek(Token![as]) {
607                 let as_token: Token![as] = input.parse()?;
608                 let path: Path = input.parse()?;
609                 Some((as_token, path))
610             } else {
611                 None
612             };
613             let gt_token: Token![>] = input.parse()?;
614             let colon2_token: Token![::] = input.parse()?;
615             let mut rest = Punctuated::new();
616             loop {
617                 let path = PathSegment::parse_helper(input, expr_style)?;
618                 rest.push_value(path);
619                 if !input.peek(Token![::]) {
620                     break;
621                 }
622                 let punct: Token![::] = input.parse()?;
623                 rest.push_punct(punct);
624             }
625             let (position, as_token, path) = match path {
626                 Some((as_token, mut path)) => {
627                     let pos = path.segments.len();
628                     path.segments.push_punct(colon2_token);
629                     path.segments.extend(rest.into_pairs());
630                     (pos, Some(as_token), path)
631                 }
632                 None => {
633                     let path = Path {
634                         leading_colon: Some(colon2_token),
635                         segments: rest,
636                     };
637                     (0, None, path)
638                 }
639             };
640             let qself = QSelf {
641                 lt_token,
642                 ty: Box::new(this),
643                 position,
644                 as_token,
645                 gt_token,
646             };
647             Ok((Some(qself), path))
648         } else {
649             let path = Path::parse_helper(input, expr_style)?;
650             Ok((None, path))
651         }
652     }
653 }
654 
655 #[cfg(feature = "printing")]
656 mod printing {
657     use super::*;
658     use crate::print::TokensOrDefault;
659     use proc_macro2::TokenStream;
660     use quote::ToTokens;
661     use std::cmp;
662 
663     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
664     impl ToTokens for Path {
to_tokens(&self, tokens: &mut TokenStream)665         fn to_tokens(&self, tokens: &mut TokenStream) {
666             self.leading_colon.to_tokens(tokens);
667             self.segments.to_tokens(tokens);
668         }
669     }
670 
671     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
672     impl ToTokens for PathSegment {
to_tokens(&self, tokens: &mut TokenStream)673         fn to_tokens(&self, tokens: &mut TokenStream) {
674             self.ident.to_tokens(tokens);
675             self.arguments.to_tokens(tokens);
676         }
677     }
678 
679     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
680     impl ToTokens for PathArguments {
to_tokens(&self, tokens: &mut TokenStream)681         fn to_tokens(&self, tokens: &mut TokenStream) {
682             match self {
683                 PathArguments::None => {}
684                 PathArguments::AngleBracketed(arguments) => {
685                     arguments.to_tokens(tokens);
686                 }
687                 PathArguments::Parenthesized(arguments) => {
688                     arguments.to_tokens(tokens);
689                 }
690             }
691         }
692     }
693 
694     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
695     impl ToTokens for GenericArgument {
696         #[allow(clippy::match_same_arms)]
to_tokens(&self, tokens: &mut TokenStream)697         fn to_tokens(&self, tokens: &mut TokenStream) {
698             match self {
699                 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
700                 GenericArgument::Type(ty) => ty.to_tokens(tokens),
701                 GenericArgument::Binding(tb) => tb.to_tokens(tokens),
702                 GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
703                 GenericArgument::Const(e) => match *e {
704                     Expr::Lit(_) => e.to_tokens(tokens),
705 
706                     // NOTE: We should probably support parsing blocks with only
707                     // expressions in them without the full feature for const
708                     // generics.
709                     #[cfg(feature = "full")]
710                     Expr::Block(_) => e.to_tokens(tokens),
711 
712                     // ERROR CORRECTION: Add braces to make sure that the
713                     // generated code is valid.
714                     _ => token::Brace::default().surround(tokens, |tokens| {
715                         e.to_tokens(tokens);
716                     }),
717                 },
718             }
719         }
720     }
721 
722     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
723     impl ToTokens for AngleBracketedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)724         fn to_tokens(&self, tokens: &mut TokenStream) {
725             self.colon2_token.to_tokens(tokens);
726             self.lt_token.to_tokens(tokens);
727 
728             // Print lifetimes before types and consts, all before bindings,
729             // regardless of their order in self.args.
730             //
731             // TODO: ordering rules for const arguments vs type arguments have
732             // not been settled yet. https://github.com/rust-lang/rust/issues/44580
733             let mut trailing_or_empty = true;
734             for param in self.args.pairs() {
735                 match **param.value() {
736                     GenericArgument::Lifetime(_) => {
737                         param.to_tokens(tokens);
738                         trailing_or_empty = param.punct().is_some();
739                     }
740                     GenericArgument::Type(_)
741                     | GenericArgument::Binding(_)
742                     | GenericArgument::Constraint(_)
743                     | GenericArgument::Const(_) => {}
744                 }
745             }
746             for param in self.args.pairs() {
747                 match **param.value() {
748                     GenericArgument::Type(_) | GenericArgument::Const(_) => {
749                         if !trailing_or_empty {
750                             <Token![,]>::default().to_tokens(tokens);
751                         }
752                         param.to_tokens(tokens);
753                         trailing_or_empty = param.punct().is_some();
754                     }
755                     GenericArgument::Lifetime(_)
756                     | GenericArgument::Binding(_)
757                     | GenericArgument::Constraint(_) => {}
758                 }
759             }
760             for param in self.args.pairs() {
761                 match **param.value() {
762                     GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
763                         if !trailing_or_empty {
764                             <Token![,]>::default().to_tokens(tokens);
765                         }
766                         param.to_tokens(tokens);
767                         trailing_or_empty = param.punct().is_some();
768                     }
769                     GenericArgument::Lifetime(_)
770                     | GenericArgument::Type(_)
771                     | GenericArgument::Const(_) => {}
772                 }
773             }
774 
775             self.gt_token.to_tokens(tokens);
776         }
777     }
778 
779     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
780     impl ToTokens for Binding {
to_tokens(&self, tokens: &mut TokenStream)781         fn to_tokens(&self, tokens: &mut TokenStream) {
782             self.ident.to_tokens(tokens);
783             self.eq_token.to_tokens(tokens);
784             self.ty.to_tokens(tokens);
785         }
786     }
787 
788     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
789     impl ToTokens for Constraint {
to_tokens(&self, tokens: &mut TokenStream)790         fn to_tokens(&self, tokens: &mut TokenStream) {
791             self.ident.to_tokens(tokens);
792             self.colon_token.to_tokens(tokens);
793             self.bounds.to_tokens(tokens);
794         }
795     }
796 
797     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
798     impl ToTokens for ParenthesizedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)799         fn to_tokens(&self, tokens: &mut TokenStream) {
800             self.paren_token.surround(tokens, |tokens| {
801                 self.inputs.to_tokens(tokens);
802             });
803             self.output.to_tokens(tokens);
804         }
805     }
806 
807     impl private {
print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)808         pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
809             let qself = match qself {
810                 Some(qself) => qself,
811                 None => {
812                     path.to_tokens(tokens);
813                     return;
814                 }
815             };
816             qself.lt_token.to_tokens(tokens);
817             qself.ty.to_tokens(tokens);
818 
819             let pos = cmp::min(qself.position, path.segments.len());
820             let mut segments = path.segments.pairs();
821             if pos > 0 {
822                 TokensOrDefault(&qself.as_token).to_tokens(tokens);
823                 path.leading_colon.to_tokens(tokens);
824                 for (i, segment) in segments.by_ref().take(pos).enumerate() {
825                     if i + 1 == pos {
826                         segment.value().to_tokens(tokens);
827                         qself.gt_token.to_tokens(tokens);
828                         segment.punct().to_tokens(tokens);
829                     } else {
830                         segment.to_tokens(tokens);
831                     }
832                 }
833             } else {
834                 qself.gt_token.to_tokens(tokens);
835                 path.leading_colon.to_tokens(tokens);
836             }
837             for segment in segments {
838                 segment.to_tokens(tokens);
839             }
840         }
841     }
842 }
843