1 #[cfg(feature = "parsing")] 2 use crate::error::Result; 3 use crate::expr::Expr; 4 use crate::generics::TypeParamBound; 5 use crate::ident::Ident; 6 use crate::lifetime::Lifetime; 7 use crate::punctuated::Punctuated; 8 use crate::token; 9 use crate::ty::{ReturnType, Type}; 10 11 ast_struct! { 12 /// A path at which a named item is exported (e.g. `std::collections::HashMap`). 13 #[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 20 impl<T> From<T> for Path 21 where 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 34 impl 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(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 107 ast_struct! { 108 /// A segment of a path together with any path arguments on that segment. 109 #[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 116 impl<T> From<T> for PathSegment 117 where 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 128 ast_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(docsrs, 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 148 impl Default for PathArguments { 149 fn default() -> Self { 150 PathArguments::None 151 } 152 } 153 154 impl 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 171 ast_enum! { 172 /// An individual generic argument, like `'a`, `T`, or `Item = T`. 173 #[cfg_attr(docsrs, 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 196 ast_struct! { 197 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, 198 /// V>`. 199 #[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 208 ast_struct! { 209 /// A binding (equality constraint) on an associated type: the `Item = u8` 210 /// in `Iterator<Item = u8>`. 211 #[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 220 ast_struct! { 221 /// An equality constraint on an associated constant: the `PANIC = false` in 222 /// `Trait<PANIC = false>`. 223 #[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 232 ast_struct! { 233 /// An associated type bound: `Iterator<Item: Display>`. 234 #[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 243 ast_struct! { 244 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> 245 /// C`. 246 #[cfg_attr(docsrs, 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 256 ast_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(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")] 284 pub(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_const = true; 383 TypeParamBound::parse_single( 384 input, 385 allow_precise_capture, 386 allow_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 /// Parse `::<…>` with mandatory leading `::`. 449 /// 450 /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` 451 /// parses optional leading `::`. 452 #[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 /// Parse a `Path` containing no path arguments on any of its segments. 549 /// 550 /// # Example 551 /// 552 /// ``` 553 /// use syn::{Path, Result, Token}; 554 /// use syn::parse::{Parse, ParseStream}; 555 /// 556 /// // A simplified single `use` statement like: 557 /// // 558 /// // use std::collections::HashMap; 559 /// // 560 /// // Note that generic parameters are not allowed in a `use` statement 561 /// // so the following must not be accepted. 562 /// // 563 /// // use a::<b>::c; 564 /// struct SingleUse { 565 /// use_token: Token![use], 566 /// path: Path, 567 /// } 568 /// 569 /// impl Parse for SingleUse { 570 /// fn parse(input: ParseStream) -> Result<Self> { 571 /// Ok(SingleUse { 572 /// use_token: input.parse()?, 573 /// path: input.call(Path::parse_mod_style)?, 574 /// }) 575 /// } 576 /// } 577 /// ``` 578 #[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")] 700 pub(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 // Print lifetimes before types/consts/bindings, regardless of their 812 // order in args. 813 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 } 967