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