1#[cfg(feature = "parsing")]
2use crate::error::Result;
3use crate::expr::Expr;
4use crate::generics::TypeParamBound;
5use crate::ident::Ident;
6use crate::lifetime::Lifetime;
7use crate::punctuated::Punctuated;
8use crate::token;
9use crate::ty::{ReturnType, Type};
10
11ast_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
20impl<T> From<T> for Path
21where
22 T: Into<PathSegment>,
23{
24 fn from(segment: T) -> Self {
25 let mut path: Path = Path {
26 leading_colon: None,
27 segments: Punctuated::new(),
28 };
29 path.segments.push_value(segment.into());
30 path
31 }
32}
33
34impl 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 /// ```
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.
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")))]
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
107ast_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
116impl<T> From<T> for PathSegment
117where
118 T: Into<Ident>,
119{
120 fn from(ident: T) -> Self {
121 PathSegment {
122 ident: ident.into(),
123 arguments: PathArguments::None,
124 }
125 }
126}
127
128ast_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
148impl Default for PathArguments {
149 fn default() -> Self {
150 PathArguments::None
151 }
152}
153
154impl PathArguments {
155 pub fn is_empty(&self) -> bool {
156 match self {
157 PathArguments::None => true,
158 PathArguments::AngleBracketed(bracketed: &AngleBracketedGenericArguments) => bracketed.args.is_empty(),
159 PathArguments::Parenthesized(_) => false,
160 }
161 }
162
163 pub fn is_none(&self) -> bool {
164 match self {
165 PathArguments::None => true,
166 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
167 }
168 }
169}
170
171ast_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
196ast_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
208ast_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
220ast_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
232ast_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
243ast_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
256ast_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")]
284pub(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 {
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 {
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
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"))))]
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
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 {
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 {
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 {
502 fn parse(input: ParseStream) -> Result<Self> {
503 Self::parse_helper(input, false)
504 }
505 }
506
507 impl PathSegment {
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")))]
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
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
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
629 pub(crate) fn is_mod_style(&self) -> bool {
630 self.segments
631 .iter()
632 .all(|segment| segment.arguments.is_none())
633 }
634 }
635
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")]
690pub(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 {
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 {
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 {
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)]
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 {
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 {
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 {
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 {
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 {
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
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 {
894 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