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};
10use alloc::boxed::Box;
11
12ast_struct! {
13 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
15 pub struct Path {
16 pub leading_colon: Option<Token![::]>,
17 pub segments: Punctuated<PathSegment, Token![::]>,
18 }
19}
20
21impl<T> From<T> for Path
22where
23 T: Into<PathSegment>,
24{
25 fn from(segment: T) -> Self {
26 let mut path = Path {
27 leading_colon: None,
28 segments: Punctuated::new(),
29 };
30 path.segments.push_value(segment.into());
31 path
32 }
33}
34
35impl Path {
36 pub fn is_ident<I>(&self, ident: &I) -> bool
65 where
66 I: ?Sized,
67 Ident: PartialEq<I>,
68 {
69 match self.get_ident() {
70 Some(id) => id == ident,
71 None => false,
72 }
73 }
74
75 pub fn get_ident(&self) -> Option<&Ident> {
84 if self.leading_colon.is_none()
85 && self.segments.len() == 1
86 && self.segments[0].arguments.is_none()
87 {
88 Some(&self.segments[0].ident)
89 } else {
90 None
91 }
92 }
93
94 #[cfg(feature = "parsing")]
96 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
97 pub fn require_ident(&self) -> Result<&Ident> {
98 self.get_ident().ok_or_else(|| {
99 crate::error::new2(
100 self.segments.first().unwrap().ident.span(),
101 self.segments.last().unwrap().ident.span(),
102 "expected this path to be an identifier",
103 )
104 })
105 }
106}
107
108ast_struct! {
109 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
111 pub struct PathSegment {
112 pub ident: Ident,
113 pub arguments: PathArguments,
114 }
115}
116
117impl<T> From<T> for PathSegment
118where
119 T: Into<Ident>,
120{
121 fn from(ident: T) -> Self {
122 PathSegment {
123 ident: ident.into(),
124 arguments: PathArguments::None,
125 }
126 }
127}
128
129ast_enum! {
130 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
140 pub enum PathArguments {
141 None,
142 AngleBracketed(AngleBracketedGenericArguments),
144 Parenthesized(ParenthesizedGenericArguments),
146 }
147}
148
149impl Default for PathArguments {
150 fn default() -> Self {
151 PathArguments::None
152 }
153}
154
155impl PathArguments {
156 pub fn is_empty(&self) -> bool {
157 match self {
158 PathArguments::None => true,
159 PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
160 PathArguments::Parenthesized(_) => false,
161 }
162 }
163
164 pub fn is_none(&self) -> bool {
165 match self {
166 PathArguments::None => true,
167 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
168 }
169 }
170}
171
172ast_enum! {
173 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
175 #[non_exhaustive]
176 pub enum GenericArgument {
177 Lifetime(Lifetime),
179 Type(Type),
181 Const(Expr),
186 AssocType(AssocType),
189 AssocConst(AssocConst),
192 Constraint(Constraint),
194 }
195}
196
197ast_struct! {
198 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
201 pub struct AngleBracketedGenericArguments {
202 pub colon2_token: Option<Token![::]>,
203 pub lt_token: Token![<],
204 pub args: Punctuated<GenericArgument, Token![,]>,
205 pub gt_token: Token![>],
206 }
207}
208
209ast_struct! {
210 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
213 pub struct AssocType {
214 pub ident: Ident,
215 pub generics: Option<AngleBracketedGenericArguments>,
216 pub eq_token: Token![=],
217 pub ty: Type,
218 }
219}
220
221ast_struct! {
222 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
225 pub struct AssocConst {
226 pub ident: Ident,
227 pub generics: Option<AngleBracketedGenericArguments>,
228 pub eq_token: Token![=],
229 pub value: Expr,
230 }
231}
232
233ast_struct! {
234 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
236 pub struct Constraint {
237 pub ident: Ident,
238 pub generics: Option<AngleBracketedGenericArguments>,
239 pub colon_token: Token![:],
240 pub bounds: Punctuated<TypeParamBound, Token![+]>,
241 }
242}
243
244ast_struct! {
245 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
248 pub struct ParenthesizedGenericArguments {
249 pub paren_token: token::Paren,
250 pub inputs: Punctuated<Type, Token![,]>,
252 pub output: ReturnType,
254 }
255}
256
257ast_struct! {
258 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
275 pub struct QSelf {
276 pub lt_token: Token![<],
277 pub ty: Box<Type>,
278 pub position: usize,
279 pub as_token: Option<Token![as]>,
280 pub gt_token: Token![>],
281 }
282}
283
284#[cfg(feature = "parsing")]
285pub(crate) mod parsing {
286 use crate::error::Result;
287 #[cfg(feature = "full")]
288 use crate::expr::ExprBlock;
289 use crate::expr::{Expr, ExprPath};
290 use crate::ext::IdentExt as _;
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 use crate::path::{
297 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
298 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
299 };
300 use crate::punctuated::Punctuated;
301 use crate::token;
302 use crate::ty::{ReturnType, Type};
303 #[cfg(not(feature = "full"))]
304 use crate::verbatim;
305 use alloc::boxed::Box;
306 use alloc::vec::Vec;
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 if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
364 let segment = ty.path.segments.pop().unwrap().into_value();
365 return Ok(GenericArgument::Constraint(Constraint {
366 ident: segment.ident,
367 generics: match segment.arguments {
368 PathArguments::None => None,
369 PathArguments::AngleBracketed(arguments) => Some(arguments),
370 PathArguments::Parenthesized(_) => unreachable!(),
371 },
372 colon_token,
373 bounds: {
374 let mut bounds = Punctuated::new();
375 loop {
376 if input.peek(Token![,]) || input.peek(Token![>]) {
377 break;
378 }
379 bounds.push_value({
380 let allow_precise_capture = false;
381 let allow_const = true;
382 TypeParamBound::parse_single(
383 input,
384 allow_precise_capture,
385 allow_const,
386 )?
387 });
388 if !input.peek(Token![+]) {
389 break;
390 }
391 let punct: Token![+] = input.parse()?;
392 bounds.push_punct(punct);
393 }
394 bounds
395 },
396 }));
397 }
398
399 argument = Type::Path(ty);
400 }
401 _ => {}
402 }
403
404 Ok(GenericArgument::Type(argument))
405 }
406 }
407
408 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
409 let lookahead = input.lookahead1();
410
411 if input.peek(Lit) {
412 let lit = input.parse()?;
413 return Ok(Expr::Lit(lit));
414 }
415
416 if input.peek(Ident) {
417 let ident: Ident = input.parse()?;
418 return Ok(Expr::Path(ExprPath {
419 attrs: Vec::new(),
420 qself: None,
421 path: Path::from(ident),
422 }));
423 }
424
425 if input.peek(token::Brace) {
426 #[cfg(feature = "full")]
427 {
428 let block: ExprBlock = input.parse()?;
429 return Ok(Expr::Block(block));
430 }
431
432 #[cfg(not(feature = "full"))]
433 {
434 let begin = input.fork();
435 let content;
436 braced!(content in input);
437 content.parse::<Expr>()?;
438 let verbatim = verbatim::between(&begin, input);
439 return Ok(Expr::Verbatim(verbatim));
440 }
441 }
442
443 Err(lookahead.error())
444 }
445
446 impl AngleBracketedGenericArguments {
447 #[cfg(feature = "full")]
452 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
453 pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
454 let colon2_token: Token![::] = input.parse()?;
455 Self::do_parse(Some(colon2_token), input)
456 }
457
458 pub(crate) fn do_parse(
459 colon2_token: Option<Token![::]>,
460 input: ParseStream,
461 ) -> Result<Self> {
462 Ok(AngleBracketedGenericArguments {
463 colon2_token,
464 lt_token: input.parse()?,
465 args: {
466 let mut args = Punctuated::new();
467 loop {
468 if input.peek(Token![>]) {
469 break;
470 }
471 let value: GenericArgument = input.parse()?;
472 args.push_value(value);
473 if input.peek(Token![>]) {
474 break;
475 }
476 let punct: Token![,] = input.parse()?;
477 args.push_punct(punct);
478 }
479 args
480 },
481 gt_token: input.parse()?,
482 })
483 }
484 }
485
486 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
487 impl Parse for AngleBracketedGenericArguments {
488 fn parse(input: ParseStream) -> Result<Self> {
489 let colon2_token: Option<Token![::]> = input.parse()?;
490 Self::do_parse(colon2_token, input)
491 }
492 }
493
494 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
495 impl Parse for ParenthesizedGenericArguments {
496 fn parse(input: ParseStream) -> Result<Self> {
497 let content;
498 Ok(ParenthesizedGenericArguments {
499 paren_token: parenthesized!(content in input),
500 inputs: content.parse_terminated(Type::parse, Token![,])?,
501 output: input.call(ReturnType::without_plus)?,
502 })
503 }
504 }
505
506 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
507 impl Parse for PathSegment {
508 fn parse(input: ParseStream) -> Result<Self> {
509 Self::parse_helper(input, false)
510 }
511 }
512
513 impl PathSegment {
514 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
515 if input.peek(Token![super])
516 || input.peek(Token![self])
517 || input.peek(Token![crate])
518 || cfg!(feature = "full") && input.peek(Token![try])
519 {
520 let ident = input.call(Ident::parse_any)?;
521 return Ok(PathSegment::from(ident));
522 }
523
524 let ident = if input.peek(Token![Self]) {
525 input.call(Ident::parse_any)?
526 } else {
527 input.parse()?
528 };
529
530 if !expr_style
531 && input.peek(Token![<])
532 && !input.peek(Token![<=])
533 && !input.peek(Token![<<=])
534 || input.peek(Token![::]) && input.peek3(Token![<])
535 {
536 Ok(PathSegment {
537 ident,
538 arguments: PathArguments::AngleBracketed(input.parse()?),
539 })
540 } else {
541 Ok(PathSegment::from(ident))
542 }
543 }
544 }
545
546 impl Path {
547 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
578 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
579 Ok(Path {
580 leading_colon: input.parse()?,
581 segments: {
582 let mut segments = Punctuated::new();
583 loop {
584 if !input.peek(Ident)
585 && !input.peek(Token![super])
586 && !input.peek(Token![self])
587 && !input.peek(Token![Self])
588 && !input.peek(Token![crate])
589 {
590 break;
591 }
592 let ident = Ident::parse_any(input)?;
593 segments.push_value(PathSegment::from(ident));
594 if !input.peek(Token![::]) {
595 break;
596 }
597 let punct = input.parse()?;
598 segments.push_punct(punct);
599 }
600 if segments.is_empty() {
601 return Err(input.parse::<Ident>().unwrap_err());
602 } else if segments.trailing_punct() {
603 return Err(input.error("expected path segment after `::`"));
604 }
605 segments
606 },
607 })
608 }
609
610 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
611 let mut path = Path {
612 leading_colon: input.parse()?,
613 segments: {
614 let mut segments = Punctuated::new();
615 let value = PathSegment::parse_helper(input, expr_style)?;
616 segments.push_value(value);
617 segments
618 },
619 };
620 Path::parse_rest(input, &mut path, expr_style)?;
621 Ok(path)
622 }
623
624 pub(crate) fn parse_rest(
625 input: ParseStream,
626 path: &mut Self,
627 expr_style: bool,
628 ) -> Result<()> {
629 while input.peek(Token![::]) && !input.peek3(token::Paren) {
630 let punct: Token![::] = input.parse()?;
631 path.segments.push_punct(punct);
632 let value = PathSegment::parse_helper(input, expr_style)?;
633 path.segments.push_value(value);
634 }
635 Ok(())
636 }
637
638 pub(crate) fn is_mod_style(&self) -> bool {
639 self.segments
640 .iter()
641 .all(|segment| segment.arguments.is_none())
642 }
643 }
644
645 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
646 if input.peek(Token![<]) {
647 let lt_token: Token![<] = input.parse()?;
648 let this: Type = input.parse()?;
649 let path = if input.peek(Token![as]) {
650 let as_token: Token![as] = input.parse()?;
651 let path: Path = input.parse()?;
652 Some((as_token, path))
653 } else {
654 None
655 };
656 let gt_token: Token![>] = input.parse()?;
657 let colon2_token: Token![::] = input.parse()?;
658 let mut rest = Punctuated::new();
659 loop {
660 let path = PathSegment::parse_helper(input, expr_style)?;
661 rest.push_value(path);
662 if !input.peek(Token![::]) {
663 break;
664 }
665 let punct: Token![::] = input.parse()?;
666 rest.push_punct(punct);
667 }
668 let (position, as_token, path) = match path {
669 Some((as_token, mut path)) => {
670 let pos = path.segments.len();
671 path.segments.push_punct(colon2_token);
672 path.segments.extend(rest.into_pairs());
673 (pos, Some(as_token), path)
674 }
675 None => {
676 let path = Path {
677 leading_colon: Some(colon2_token),
678 segments: rest,
679 };
680 (0, None, path)
681 }
682 };
683 let qself = QSelf {
684 lt_token,
685 ty: Box::new(this),
686 position,
687 as_token,
688 gt_token,
689 };
690 Ok((Some(qself), path))
691 } else {
692 let path = Path::parse_helper(input, expr_style)?;
693 Ok((None, path))
694 }
695 }
696}
697
698#[cfg(feature = "printing")]
699pub(crate) mod printing {
700 use crate::generics;
701 use crate::path::{
702 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
703 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
704 };
705 use crate::print::TokensOrDefault;
706 #[cfg(feature = "parsing")]
707 use crate::spanned::Spanned;
708 use core::cmp;
709 #[cfg(feature = "parsing")]
710 use proc_macro2::Span;
711 use proc_macro2::TokenStream;
712 use quote::ToTokens;
713
714 pub(crate) enum PathStyle {
715 Expr,
716 Mod,
717 AsWritten,
718 }
719
720 impl Copy for PathStyle {}
721
722 impl Clone for PathStyle {
723 fn clone(&self) -> Self {
724 *self
725 }
726 }
727
728 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
729 impl ToTokens for Path {
730 fn to_tokens(&self, tokens: &mut TokenStream) {
731 print_path(tokens, self, PathStyle::AsWritten);
732 }
733 }
734
735 pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
736 path.leading_colon.to_tokens(tokens);
737 for segment in path.segments.pairs() {
738 print_path_segment(tokens, segment.value(), style);
739 segment.punct().to_tokens(tokens);
740 }
741 }
742
743 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
744 impl ToTokens for PathSegment {
745 fn to_tokens(&self, tokens: &mut TokenStream) {
746 print_path_segment(tokens, self, PathStyle::AsWritten);
747 }
748 }
749
750 fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
751 segment.ident.to_tokens(tokens);
752 print_path_arguments(tokens, &segment.arguments, style);
753 }
754
755 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
756 impl ToTokens for PathArguments {
757 fn to_tokens(&self, tokens: &mut TokenStream) {
758 print_path_arguments(tokens, self, PathStyle::AsWritten);
759 }
760 }
761
762 fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
763 match arguments {
764 PathArguments::None => {}
765 PathArguments::AngleBracketed(arguments) => {
766 print_angle_bracketed_generic_arguments(tokens, arguments, style);
767 }
768 PathArguments::Parenthesized(arguments) => {
769 print_parenthesized_generic_arguments(tokens, arguments, style);
770 }
771 }
772 }
773
774 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
775 impl ToTokens for GenericArgument {
776 #[allow(clippy::match_same_arms)]
777 fn to_tokens(&self, tokens: &mut TokenStream) {
778 match self {
779 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
780 GenericArgument::Type(ty) => ty.to_tokens(tokens),
781 GenericArgument::Const(expr) => {
782 generics::printing::print_const_argument(expr, tokens);
783 }
784 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
785 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
786 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
787 }
788 }
789 }
790
791 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
792 impl ToTokens for AngleBracketedGenericArguments {
793 fn to_tokens(&self, tokens: &mut TokenStream) {
794 print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
795 }
796 }
797
798 pub(crate) fn print_angle_bracketed_generic_arguments(
799 tokens: &mut TokenStream,
800 arguments: &AngleBracketedGenericArguments,
801 style: PathStyle,
802 ) {
803 if let PathStyle::Mod = style {
804 return;
805 }
806
807 conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
808 arguments.lt_token.to_tokens(tokens);
809
810 let mut trailing_or_empty = true;
813 for param in arguments.args.pairs() {
814 match param.value() {
815 GenericArgument::Lifetime(_) => {
816 param.to_tokens(tokens);
817 trailing_or_empty = param.punct().is_some();
818 }
819 GenericArgument::Type(_)
820 | GenericArgument::Const(_)
821 | GenericArgument::AssocType(_)
822 | GenericArgument::AssocConst(_)
823 | GenericArgument::Constraint(_) => {}
824 }
825 }
826 for param in arguments.args.pairs() {
827 match param.value() {
828 GenericArgument::Type(_)
829 | GenericArgument::Const(_)
830 | GenericArgument::AssocType(_)
831 | GenericArgument::AssocConst(_)
832 | GenericArgument::Constraint(_) => {
833 if !trailing_or_empty {
834 <Token![,]>::default().to_tokens(tokens);
835 }
836 param.to_tokens(tokens);
837 trailing_or_empty = param.punct().is_some();
838 }
839 GenericArgument::Lifetime(_) => {}
840 }
841 }
842
843 arguments.gt_token.to_tokens(tokens);
844 }
845
846 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
847 impl ToTokens for AssocType {
848 fn to_tokens(&self, tokens: &mut TokenStream) {
849 self.ident.to_tokens(tokens);
850 self.generics.to_tokens(tokens);
851 self.eq_token.to_tokens(tokens);
852 self.ty.to_tokens(tokens);
853 }
854 }
855
856 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
857 impl ToTokens for AssocConst {
858 fn to_tokens(&self, tokens: &mut TokenStream) {
859 self.ident.to_tokens(tokens);
860 self.generics.to_tokens(tokens);
861 self.eq_token.to_tokens(tokens);
862 generics::printing::print_const_argument(&self.value, tokens);
863 }
864 }
865
866 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
867 impl ToTokens for Constraint {
868 fn to_tokens(&self, tokens: &mut TokenStream) {
869 self.ident.to_tokens(tokens);
870 self.generics.to_tokens(tokens);
871 self.colon_token.to_tokens(tokens);
872 self.bounds.to_tokens(tokens);
873 }
874 }
875
876 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
877 impl ToTokens for ParenthesizedGenericArguments {
878 fn to_tokens(&self, tokens: &mut TokenStream) {
879 print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
880 }
881 }
882
883 fn print_parenthesized_generic_arguments(
884 tokens: &mut TokenStream,
885 arguments: &ParenthesizedGenericArguments,
886 style: PathStyle,
887 ) {
888 if let PathStyle::Mod = style {
889 return;
890 }
891
892 conditionally_print_turbofish(tokens, &None, style);
893 arguments.paren_token.surround(tokens, |tokens| {
894 arguments.inputs.to_tokens(tokens);
895 });
896 arguments.output.to_tokens(tokens);
897 }
898
899 pub(crate) fn print_qpath(
900 tokens: &mut TokenStream,
901 qself: &Option<QSelf>,
902 path: &Path,
903 style: PathStyle,
904 ) {
905 let qself = match qself {
906 Some(qself) => qself,
907 None => {
908 print_path(tokens, path, style);
909 return;
910 }
911 };
912 qself.lt_token.to_tokens(tokens);
913 qself.ty.to_tokens(tokens);
914
915 let pos = cmp::min(qself.position, path.segments.len());
916 let mut segments = path.segments.pairs();
917 if pos > 0 {
918 TokensOrDefault(&qself.as_token).to_tokens(tokens);
919 path.leading_colon.to_tokens(tokens);
920 for (i, segment) in segments.by_ref().take(pos).enumerate() {
921 print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
922 if i + 1 == pos {
923 qself.gt_token.to_tokens(tokens);
924 }
925 segment.punct().to_tokens(tokens);
926 }
927 } else {
928 qself.gt_token.to_tokens(tokens);
929 path.leading_colon.to_tokens(tokens);
930 }
931 for segment in segments {
932 print_path_segment(tokens, segment.value(), style);
933 segment.punct().to_tokens(tokens);
934 }
935 }
936
937 fn conditionally_print_turbofish(
938 tokens: &mut TokenStream,
939 colon2_token: &Option<Token![::]>,
940 style: PathStyle,
941 ) {
942 match style {
943 PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
944 PathStyle::Mod => unreachable!(),
945 PathStyle::AsWritten => colon2_token.to_tokens(tokens),
946 }
947 }
948
949 #[cfg(feature = "parsing")]
950 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
951 impl Spanned for QSelf {
952 fn span(&self) -> Span {
953 struct QSelfDelimiters<'a>(&'a QSelf);
954
955 impl<'a> ToTokens for QSelfDelimiters<'a> {
956 fn to_tokens(&self, tokens: &mut TokenStream) {
957 self.0.lt_token.to_tokens(tokens);
958 self.0.gt_token.to_tokens(tokens);
959 }
960 }
961
962 QSelfDelimiters(self).span()
963 }
964 }
965}