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 #[cfg_attr(docsrs, 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 {
26 leading_colon: None,
27 segments: Punctuated::new(),
28 };
29 path.segments.push_value(segment.into());
30 path
31 }
32}
33
34impl Path {
35 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 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 #[cfg(feature = "parsing")]
95 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
139 pub enum PathArguments {
140 None,
141 AngleBracketed(AngleBracketedGenericArguments),
143 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) => 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 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
174 #[non_exhaustive]
175 pub enum GenericArgument {
176 Lifetime(Lifetime),
178 Type(Type),
180 Const(Expr),
185 AssocType(AssocType),
188 AssocConst(AssocConst),
191 Constraint(Constraint),
193 }
194}
195
196ast_struct! {
197 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, 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 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
247 pub struct ParenthesizedGenericArguments {
248 pub paren_token: token::Paren,
249 pub inputs: Punctuated<Type, Token![,]>,
251 pub output: ReturnType,
253 }
254}
255
256ast_struct! {
257 #[cfg_attr(docsrs, 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(docsrs, 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(docsrs, 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 bounds.push_value({
381 let allow_precise_capture = false;
382 let allow_tilde_const = true;
383 TypeParamBound::parse_single(
384 input,
385 allow_precise_capture,
386 allow_tilde_const,
387 )?
388 });
389 if !input.peek(Token![+]) {
390 break;
391 }
392 let punct: Token![+] = input.parse()?;
393 bounds.push_punct(punct);
394 }
395 bounds
396 },
397 }));
398 }
399
400 argument = Type::Path(ty);
401 }
402 _ => {}
403 }
404
405 Ok(GenericArgument::Type(argument))
406 }
407 }
408
409 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
410 let lookahead = input.lookahead1();
411
412 if input.peek(Lit) {
413 let lit = input.parse()?;
414 return Ok(Expr::Lit(lit));
415 }
416
417 if input.peek(Ident) {
418 let ident: Ident = input.parse()?;
419 return Ok(Expr::Path(ExprPath {
420 attrs: Vec::new(),
421 qself: None,
422 path: Path::from(ident),
423 }));
424 }
425
426 if input.peek(token::Brace) {
427 #[cfg(feature = "full")]
428 {
429 let block: ExprBlock = input.parse()?;
430 return Ok(Expr::Block(block));
431 }
432
433 #[cfg(not(feature = "full"))]
434 {
435 let begin = input.fork();
436 let content;
437 braced!(content in input);
438 content.parse::<Expr>()?;
439 let verbatim = verbatim::between(&begin, input);
440 return Ok(Expr::Verbatim(verbatim));
441 }
442 }
443
444 Err(lookahead.error())
445 }
446
447 impl AngleBracketedGenericArguments {
448 #[cfg(feature = "full")]
453 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
454 pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
455 let colon2_token: Token![::] = input.parse()?;
456 Self::do_parse(Some(colon2_token), input)
457 }
458
459 pub(crate) fn do_parse(
460 colon2_token: Option<Token![::]>,
461 input: ParseStream,
462 ) -> Result<Self> {
463 Ok(AngleBracketedGenericArguments {
464 colon2_token,
465 lt_token: input.parse()?,
466 args: {
467 let mut args = Punctuated::new();
468 loop {
469 if input.peek(Token![>]) {
470 break;
471 }
472 let value: GenericArgument = input.parse()?;
473 args.push_value(value);
474 if input.peek(Token![>]) {
475 break;
476 }
477 let punct: Token![,] = input.parse()?;
478 args.push_punct(punct);
479 }
480 args
481 },
482 gt_token: input.parse()?,
483 })
484 }
485 }
486
487 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
488 impl Parse for AngleBracketedGenericArguments {
489 fn parse(input: ParseStream) -> Result<Self> {
490 let colon2_token: Option<Token![::]> = input.parse()?;
491 Self::do_parse(colon2_token, input)
492 }
493 }
494
495 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
496 impl Parse for ParenthesizedGenericArguments {
497 fn parse(input: ParseStream) -> Result<Self> {
498 let content;
499 Ok(ParenthesizedGenericArguments {
500 paren_token: parenthesized!(content in input),
501 inputs: content.parse_terminated(Type::parse, Token![,])?,
502 output: input.call(ReturnType::without_plus)?,
503 })
504 }
505 }
506
507 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
508 impl Parse for PathSegment {
509 fn parse(input: ParseStream) -> Result<Self> {
510 Self::parse_helper(input, false)
511 }
512 }
513
514 impl PathSegment {
515 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
516 if input.peek(Token![super])
517 || input.peek(Token![self])
518 || input.peek(Token![crate])
519 || cfg!(feature = "full") && input.peek(Token![try])
520 {
521 let ident = input.call(Ident::parse_any)?;
522 return Ok(PathSegment::from(ident));
523 }
524
525 let ident = if input.peek(Token![Self]) {
526 input.call(Ident::parse_any)?
527 } else {
528 input.parse()?
529 };
530
531 if !expr_style
532 && input.peek(Token![<])
533 && !input.peek(Token![<=])
534 && !input.peek(Token![<<=])
535 || input.peek(Token![::]) && input.peek3(Token![<])
536 {
537 Ok(PathSegment {
538 ident,
539 arguments: PathArguments::AngleBracketed(input.parse()?),
540 })
541 } else {
542 Ok(PathSegment::from(ident))
543 }
544 }
545 }
546
547 impl Path {
548 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
579 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
580 Ok(Path {
581 leading_colon: input.parse()?,
582 segments: {
583 let mut segments = Punctuated::new();
584 loop {
585 if !input.peek(Ident)
586 && !input.peek(Token![super])
587 && !input.peek(Token![self])
588 && !input.peek(Token![Self])
589 && !input.peek(Token![crate])
590 {
591 break;
592 }
593 let ident = Ident::parse_any(input)?;
594 segments.push_value(PathSegment::from(ident));
595 if !input.peek(Token![::]) {
596 break;
597 }
598 let punct = input.parse()?;
599 segments.push_punct(punct);
600 }
601 if segments.is_empty() {
602 return Err(input.parse::<Ident>().unwrap_err());
603 } else if segments.trailing_punct() {
604 return Err(input.error("expected path segment after `::`"));
605 }
606 segments
607 },
608 })
609 }
610
611 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
612 let mut path = Path {
613 leading_colon: input.parse()?,
614 segments: {
615 let mut segments = Punctuated::new();
616 let value = PathSegment::parse_helper(input, expr_style)?;
617 segments.push_value(value);
618 segments
619 },
620 };
621 Path::parse_rest(input, &mut path, expr_style)?;
622 Ok(path)
623 }
624
625 pub(crate) fn parse_rest(
626 input: ParseStream,
627 path: &mut Self,
628 expr_style: bool,
629 ) -> Result<()> {
630 while input.peek(Token![::]) && !input.peek3(token::Paren) {
631 let punct: Token![::] = input.parse()?;
632 path.segments.push_punct(punct);
633 let value = PathSegment::parse_helper(input, expr_style)?;
634 path.segments.push_value(value);
635 }
636 Ok(())
637 }
638
639 pub(crate) fn is_mod_style(&self) -> bool {
640 self.segments
641 .iter()
642 .all(|segment| segment.arguments.is_none())
643 }
644 }
645
646 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
647 if input.peek(Token![<]) {
648 let lt_token: Token![<] = input.parse()?;
649 let this: Type = input.parse()?;
650 let path = if input.peek(Token![as]) {
651 let as_token: Token![as] = input.parse()?;
652 let path: Path = input.parse()?;
653 Some((as_token, path))
654 } else {
655 None
656 };
657 let gt_token: Token![>] = input.parse()?;
658 let colon2_token: Token![::] = input.parse()?;
659 let mut rest = Punctuated::new();
660 loop {
661 let path = PathSegment::parse_helper(input, expr_style)?;
662 rest.push_value(path);
663 if !input.peek(Token![::]) {
664 break;
665 }
666 let punct: Token![::] = input.parse()?;
667 rest.push_punct(punct);
668 }
669 let (position, as_token, path) = match path {
670 Some((as_token, mut path)) => {
671 let pos = path.segments.len();
672 path.segments.push_punct(colon2_token);
673 path.segments.extend(rest.into_pairs());
674 (pos, Some(as_token), path)
675 }
676 None => {
677 let path = Path {
678 leading_colon: Some(colon2_token),
679 segments: rest,
680 };
681 (0, None, path)
682 }
683 };
684 let qself = QSelf {
685 lt_token,
686 ty: Box::new(this),
687 position,
688 as_token,
689 gt_token,
690 };
691 Ok((Some(qself), path))
692 } else {
693 let path = Path::parse_helper(input, expr_style)?;
694 Ok((None, path))
695 }
696 }
697}
698
699#[cfg(feature = "printing")]
700pub(crate) mod printing {
701 use crate::generics;
702 use crate::path::{
703 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
704 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
705 };
706 use crate::print::TokensOrDefault;
707 #[cfg(feature = "parsing")]
708 use crate::spanned::Spanned;
709 #[cfg(feature = "parsing")]
710 use proc_macro2::Span;
711 use proc_macro2::TokenStream;
712 use quote::ToTokens;
713 use std::cmp;
714
715 pub(crate) enum PathStyle {
716 Expr,
717 Mod,
718 AsWritten,
719 }
720
721 impl Copy for PathStyle {}
722
723 impl Clone for PathStyle {
724 fn clone(&self) -> Self {
725 *self
726 }
727 }
728
729 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
730 impl ToTokens for Path {
731 fn to_tokens(&self, tokens: &mut TokenStream) {
732 print_path(tokens, self, PathStyle::AsWritten);
733 }
734 }
735
736 pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
737 path.leading_colon.to_tokens(tokens);
738 for segment in path.segments.pairs() {
739 print_path_segment(tokens, segment.value(), style);
740 segment.punct().to_tokens(tokens);
741 }
742 }
743
744 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
745 impl ToTokens for PathSegment {
746 fn to_tokens(&self, tokens: &mut TokenStream) {
747 print_path_segment(tokens, self, PathStyle::AsWritten);
748 }
749 }
750
751 fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
752 segment.ident.to_tokens(tokens);
753 print_path_arguments(tokens, &segment.arguments, style);
754 }
755
756 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
757 impl ToTokens for PathArguments {
758 fn to_tokens(&self, tokens: &mut TokenStream) {
759 print_path_arguments(tokens, self, PathStyle::AsWritten);
760 }
761 }
762
763 fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
764 match arguments {
765 PathArguments::None => {}
766 PathArguments::AngleBracketed(arguments) => {
767 print_angle_bracketed_generic_arguments(tokens, arguments, style);
768 }
769 PathArguments::Parenthesized(arguments) => {
770 print_parenthesized_generic_arguments(tokens, arguments, style);
771 }
772 }
773 }
774
775 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
776 impl ToTokens for GenericArgument {
777 #[allow(clippy::match_same_arms)]
778 fn to_tokens(&self, tokens: &mut TokenStream) {
779 match self {
780 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
781 GenericArgument::Type(ty) => ty.to_tokens(tokens),
782 GenericArgument::Const(expr) => {
783 generics::printing::print_const_argument(expr, tokens);
784 }
785 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
786 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
787 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
788 }
789 }
790 }
791
792 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
793 impl ToTokens for AngleBracketedGenericArguments {
794 fn to_tokens(&self, tokens: &mut TokenStream) {
795 print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
796 }
797 }
798
799 pub(crate) fn print_angle_bracketed_generic_arguments(
800 tokens: &mut TokenStream,
801 arguments: &AngleBracketedGenericArguments,
802 style: PathStyle,
803 ) {
804 if let PathStyle::Mod = style {
805 return;
806 }
807
808 conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
809 arguments.lt_token.to_tokens(tokens);
810
811 let mut trailing_or_empty = true;
814 for param in arguments.args.pairs() {
815 match param.value() {
816 GenericArgument::Lifetime(_) => {
817 param.to_tokens(tokens);
818 trailing_or_empty = param.punct().is_some();
819 }
820 GenericArgument::Type(_)
821 | GenericArgument::Const(_)
822 | GenericArgument::AssocType(_)
823 | GenericArgument::AssocConst(_)
824 | GenericArgument::Constraint(_) => {}
825 }
826 }
827 for param in arguments.args.pairs() {
828 match param.value() {
829 GenericArgument::Type(_)
830 | GenericArgument::Const(_)
831 | GenericArgument::AssocType(_)
832 | GenericArgument::AssocConst(_)
833 | GenericArgument::Constraint(_) => {
834 if !trailing_or_empty {
835 <Token![,]>::default().to_tokens(tokens);
836 }
837 param.to_tokens(tokens);
838 trailing_or_empty = param.punct().is_some();
839 }
840 GenericArgument::Lifetime(_) => {}
841 }
842 }
843
844 arguments.gt_token.to_tokens(tokens);
845 }
846
847 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
848 impl ToTokens for AssocType {
849 fn to_tokens(&self, tokens: &mut TokenStream) {
850 self.ident.to_tokens(tokens);
851 self.generics.to_tokens(tokens);
852 self.eq_token.to_tokens(tokens);
853 self.ty.to_tokens(tokens);
854 }
855 }
856
857 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
858 impl ToTokens for AssocConst {
859 fn to_tokens(&self, tokens: &mut TokenStream) {
860 self.ident.to_tokens(tokens);
861 self.generics.to_tokens(tokens);
862 self.eq_token.to_tokens(tokens);
863 generics::printing::print_const_argument(&self.value, tokens);
864 }
865 }
866
867 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
868 impl ToTokens for Constraint {
869 fn to_tokens(&self, tokens: &mut TokenStream) {
870 self.ident.to_tokens(tokens);
871 self.generics.to_tokens(tokens);
872 self.colon_token.to_tokens(tokens);
873 self.bounds.to_tokens(tokens);
874 }
875 }
876
877 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
878 impl ToTokens for ParenthesizedGenericArguments {
879 fn to_tokens(&self, tokens: &mut TokenStream) {
880 print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
881 }
882 }
883
884 fn print_parenthesized_generic_arguments(
885 tokens: &mut TokenStream,
886 arguments: &ParenthesizedGenericArguments,
887 style: PathStyle,
888 ) {
889 if let PathStyle::Mod = style {
890 return;
891 }
892
893 conditionally_print_turbofish(tokens, &None, style);
894 arguments.paren_token.surround(tokens, |tokens| {
895 arguments.inputs.to_tokens(tokens);
896 });
897 arguments.output.to_tokens(tokens);
898 }
899
900 pub(crate) fn print_qpath(
901 tokens: &mut TokenStream,
902 qself: &Option<QSelf>,
903 path: &Path,
904 style: PathStyle,
905 ) {
906 let qself = match qself {
907 Some(qself) => qself,
908 None => {
909 print_path(tokens, path, style);
910 return;
911 }
912 };
913 qself.lt_token.to_tokens(tokens);
914 qself.ty.to_tokens(tokens);
915
916 let pos = cmp::min(qself.position, path.segments.len());
917 let mut segments = path.segments.pairs();
918 if pos > 0 {
919 TokensOrDefault(&qself.as_token).to_tokens(tokens);
920 path.leading_colon.to_tokens(tokens);
921 for (i, segment) in segments.by_ref().take(pos).enumerate() {
922 print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
923 if i + 1 == pos {
924 qself.gt_token.to_tokens(tokens);
925 }
926 segment.punct().to_tokens(tokens);
927 }
928 } else {
929 qself.gt_token.to_tokens(tokens);
930 path.leading_colon.to_tokens(tokens);
931 }
932 for segment in segments {
933 print_path_segment(tokens, segment.value(), style);
934 segment.punct().to_tokens(tokens);
935 }
936 }
937
938 fn conditionally_print_turbofish(
939 tokens: &mut TokenStream,
940 colon2_token: &Option<Token![::]>,
941 style: PathStyle,
942 ) {
943 match style {
944 PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
945 PathStyle::Mod => unreachable!(),
946 PathStyle::AsWritten => colon2_token.to_tokens(tokens),
947 }
948 }
949
950 #[cfg(feature = "parsing")]
951 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
952 impl Spanned for QSelf {
953 fn span(&self) -> Span {
954 struct QSelfDelimiters<'a>(&'a QSelf);
955
956 impl<'a> ToTokens for QSelfDelimiters<'a> {
957 fn to_tokens(&self, tokens: &mut TokenStream) {
958 self.0.lt_token.to_tokens(tokens);
959 self.0.gt_token.to_tokens(tokens);
960 }
961 }
962
963 QSelfDelimiters(self).span()
964 }
965 }
966}