1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 #[cfg(feature = "parsing")] 4 use crate::error::Result; 5 use crate::expr::Expr; 6 use crate::generics::TypeParamBound; 7 use crate::ident::Ident; 8 use crate::lifetime::Lifetime; 9 use crate::punctuated::Punctuated; 10 use crate::token; 11 use crate::ty::{ReturnType, Type}; 12 13 ast_struct! { 14 /// A path at which a named item is exported (e.g. `std::collections::HashMap`). 15 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 16 pub struct Path { 17 pub leading_colon: Option<Token![::]>, 18 pub segments: Punctuated<PathSegment, Token![::]>, 19 } 20 } 21 22 impl<T> From<T> for Path 23 where 24 T: Into<PathSegment>, 25 { from(segment: T) -> Self26 fn from(segment: T) -> Self { 27 let mut path = Path { 28 leading_colon: None, 29 segments: Punctuated::new(), 30 }; 31 path.segments.push_value(segment.into()); 32 path 33 } 34 } 35 36 impl Path { 37 /// Determines whether this is a path of length 1 equal to the given 38 /// ident. 39 /// 40 /// For them to compare equal, it must be the case that: 41 /// 42 /// - the path has no leading colon, 43 /// - the number of path segments is 1, 44 /// - the first path segment has no angle bracketed or parenthesized 45 /// path arguments, and 46 /// - the ident of the first path segment is equal to the given one. 47 /// 48 /// # Example 49 /// 50 /// ``` 51 /// use proc_macro2::TokenStream; 52 /// use syn::{Attribute, Error, Meta, Result}; 53 /// 54 /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> { 55 /// if attr.path().is_ident("serde") { 56 /// match &attr.meta { 57 /// Meta::List(meta) => Ok(Some(&meta.tokens)), 58 /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), 59 /// } 60 /// } else { 61 /// Ok(None) 62 /// } 63 /// } 64 /// ``` is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>,65 pub fn is_ident<I>(&self, ident: &I) -> bool 66 where 67 I: ?Sized, 68 Ident: PartialEq<I>, 69 { 70 match self.get_ident() { 71 Some(id) => id == ident, 72 None => false, 73 } 74 } 75 76 /// If this path consists of a single ident, returns the ident. 77 /// 78 /// A path is considered an ident if: 79 /// 80 /// - the path has no leading colon, 81 /// - the number of path segments is 1, and 82 /// - the first path segment has no angle bracketed or parenthesized 83 /// path arguments. get_ident(&self) -> Option<&Ident>84 pub fn get_ident(&self) -> Option<&Ident> { 85 if self.leading_colon.is_none() 86 && self.segments.len() == 1 87 && self.segments[0].arguments.is_none() 88 { 89 Some(&self.segments[0].ident) 90 } else { 91 None 92 } 93 } 94 95 /// An error if this path is not a single ident, as defined in `get_ident`. 96 #[cfg(feature = "parsing")] 97 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] require_ident(&self) -> Result<&Ident>98 pub fn require_ident(&self) -> Result<&Ident> { 99 self.get_ident().ok_or_else(|| { 100 crate::error::new2( 101 self.segments.first().unwrap().ident.span(), 102 self.segments.last().unwrap().ident.span(), 103 "expected this path to be an identifier", 104 ) 105 }) 106 } 107 } 108 109 ast_struct! { 110 /// A segment of a path together with any path arguments on that segment. 111 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 112 pub struct PathSegment { 113 pub ident: Ident, 114 pub arguments: PathArguments, 115 } 116 } 117 118 impl<T> From<T> for PathSegment 119 where 120 T: Into<Ident>, 121 { from(ident: T) -> Self122 fn from(ident: T) -> Self { 123 PathSegment { 124 ident: ident.into(), 125 arguments: PathArguments::None, 126 } 127 } 128 } 129 130 ast_enum! { 131 /// Angle bracketed or parenthesized arguments of a path segment. 132 /// 133 /// ## Angle bracketed 134 /// 135 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 136 /// 137 /// ## Parenthesized 138 /// 139 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 140 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 141 pub enum PathArguments { 142 None, 143 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 144 AngleBracketed(AngleBracketedGenericArguments), 145 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 146 Parenthesized(ParenthesizedGenericArguments), 147 } 148 } 149 150 impl Default for PathArguments { default() -> Self151 fn default() -> Self { 152 PathArguments::None 153 } 154 } 155 156 impl PathArguments { is_empty(&self) -> bool157 pub fn is_empty(&self) -> bool { 158 match self { 159 PathArguments::None => true, 160 PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(), 161 PathArguments::Parenthesized(_) => false, 162 } 163 } 164 is_none(&self) -> bool165 pub fn is_none(&self) -> bool { 166 match self { 167 PathArguments::None => true, 168 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, 169 } 170 } 171 } 172 173 ast_enum! { 174 /// An individual generic argument, like `'a`, `T`, or `Item = T`. 175 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 176 #[non_exhaustive] 177 pub enum GenericArgument { 178 /// A lifetime argument. 179 Lifetime(Lifetime), 180 /// A type argument. 181 Type(Type), 182 /// A const expression. Must be inside of a block. 183 /// 184 /// NOTE: Identity expressions are represented as Type arguments, as 185 /// they are indistinguishable syntactically. 186 Const(Expr), 187 /// A binding (equality constraint) on an associated type: the `Item = 188 /// u8` in `Iterator<Item = u8>`. 189 AssocType(AssocType), 190 /// An equality constraint on an associated constant: the `PANIC = 191 /// false` in `Trait<PANIC = false>`. 192 AssocConst(AssocConst), 193 /// An associated type bound: `Iterator<Item: Display>`. 194 Constraint(Constraint), 195 } 196 } 197 198 ast_struct! { 199 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, 200 /// V>`. 201 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 202 pub struct AngleBracketedGenericArguments { 203 pub colon2_token: Option<Token![::]>, 204 pub lt_token: Token![<], 205 pub args: Punctuated<GenericArgument, Token![,]>, 206 pub gt_token: Token![>], 207 } 208 } 209 210 ast_struct! { 211 /// A binding (equality constraint) on an associated type: the `Item = u8` 212 /// in `Iterator<Item = u8>`. 213 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 214 pub struct AssocType { 215 pub ident: Ident, 216 pub generics: Option<AngleBracketedGenericArguments>, 217 pub eq_token: Token![=], 218 pub ty: Type, 219 } 220 } 221 222 ast_struct! { 223 /// An equality constraint on an associated constant: the `PANIC = false` in 224 /// `Trait<PANIC = false>`. 225 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 226 pub struct AssocConst { 227 pub ident: Ident, 228 pub generics: Option<AngleBracketedGenericArguments>, 229 pub eq_token: Token![=], 230 pub value: Expr, 231 } 232 } 233 234 ast_struct! { 235 /// An associated type bound: `Iterator<Item: Display>`. 236 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 237 pub struct Constraint { 238 pub ident: Ident, 239 pub generics: Option<AngleBracketedGenericArguments>, 240 pub colon_token: Token![:], 241 pub bounds: Punctuated<TypeParamBound, Token![+]>, 242 } 243 } 244 245 ast_struct! { 246 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> 247 /// C`. 248 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 249 pub struct ParenthesizedGenericArguments { 250 pub paren_token: token::Paren, 251 /// `(A, B)` 252 pub inputs: Punctuated<Type, Token![,]>, 253 /// `C` 254 pub output: ReturnType, 255 } 256 } 257 258 ast_struct! { 259 /// The explicit Self type in a qualified path: the `T` in `<T as 260 /// Display>::fmt`. 261 /// 262 /// The actual path, including the trait and the associated item, is stored 263 /// separately. The `position` field represents the index of the associated 264 /// item qualified with this Self type. 265 /// 266 /// ```text 267 /// <Vec<T> as a::b::Trait>::AssociatedItem 268 /// ^~~~~~ ~~~~~~~~~~~~~~^ 269 /// ty position = 3 270 /// 271 /// <Vec<T>>::AssociatedItem 272 /// ^~~~~~ ^ 273 /// ty position = 0 274 /// ``` 275 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 276 pub struct QSelf { 277 pub lt_token: Token![<], 278 pub ty: Box<Type>, 279 pub position: usize, 280 pub as_token: Option<Token![as]>, 281 pub gt_token: Token![>], 282 } 283 } 284 285 #[cfg(feature = "parsing")] 286 pub(crate) mod parsing { 287 use crate::error::Result; 288 #[cfg(feature = "full")] 289 use crate::expr::ExprBlock; 290 use crate::expr::{Expr, ExprPath}; 291 use crate::ext::IdentExt as _; 292 #[cfg(feature = "full")] 293 use crate::generics::TypeParamBound; 294 use crate::ident::Ident; 295 use crate::lifetime::Lifetime; 296 use crate::lit::Lit; 297 use crate::parse::{Parse, ParseStream}; 298 #[cfg(feature = "full")] 299 use crate::path::Constraint; 300 use crate::path::{ 301 AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument, 302 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, 303 }; 304 use crate::punctuated::Punctuated; 305 use crate::token; 306 use crate::ty::{ReturnType, Type}; 307 #[cfg(not(feature = "full"))] 308 use crate::verbatim; 309 310 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 311 impl Parse for Path { parse(input: ParseStream) -> Result<Self>312 fn parse(input: ParseStream) -> Result<Self> { 313 Self::parse_helper(input, false) 314 } 315 } 316 317 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 318 impl Parse for GenericArgument { parse(input: ParseStream) -> Result<Self>319 fn parse(input: ParseStream) -> Result<Self> { 320 if input.peek(Lifetime) && !input.peek2(Token![+]) { 321 return Ok(GenericArgument::Lifetime(input.parse()?)); 322 } 323 324 if input.peek(Lit) || input.peek(token::Brace) { 325 return const_argument(input).map(GenericArgument::Const); 326 } 327 328 let mut argument: Type = input.parse()?; 329 330 match argument { 331 Type::Path(mut ty) 332 if ty.qself.is_none() 333 && ty.path.leading_colon.is_none() 334 && ty.path.segments.len() == 1 335 && match &ty.path.segments[0].arguments { 336 PathArguments::None | PathArguments::AngleBracketed(_) => true, 337 PathArguments::Parenthesized(_) => false, 338 } => 339 { 340 if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { 341 let segment = ty.path.segments.pop().unwrap().into_value(); 342 let ident = segment.ident; 343 let generics = match segment.arguments { 344 PathArguments::None => None, 345 PathArguments::AngleBracketed(arguments) => Some(arguments), 346 PathArguments::Parenthesized(_) => unreachable!(), 347 }; 348 return if input.peek(Lit) || input.peek(token::Brace) { 349 Ok(GenericArgument::AssocConst(AssocConst { 350 ident, 351 generics, 352 eq_token, 353 value: const_argument(input)?, 354 })) 355 } else { 356 Ok(GenericArgument::AssocType(AssocType { 357 ident, 358 generics, 359 eq_token, 360 ty: input.parse()?, 361 })) 362 }; 363 } 364 365 #[cfg(feature = "full")] 366 if let Some(colon_token) = input.parse::<Option<Token![:]>>()? { 367 let segment = ty.path.segments.pop().unwrap().into_value(); 368 return Ok(GenericArgument::Constraint(Constraint { 369 ident: segment.ident, 370 generics: match segment.arguments { 371 PathArguments::None => None, 372 PathArguments::AngleBracketed(arguments) => Some(arguments), 373 PathArguments::Parenthesized(_) => unreachable!(), 374 }, 375 colon_token, 376 bounds: { 377 let mut bounds = Punctuated::new(); 378 loop { 379 if input.peek(Token![,]) || input.peek(Token![>]) { 380 break; 381 } 382 bounds.push_value({ 383 let allow_precise_capture = false; 384 let allow_const = true; 385 TypeParamBound::parse_single( 386 input, 387 allow_precise_capture, 388 allow_const, 389 )? 390 }); 391 if !input.peek(Token![+]) { 392 break; 393 } 394 let punct: Token![+] = input.parse()?; 395 bounds.push_punct(punct); 396 } 397 bounds 398 }, 399 })); 400 } 401 402 argument = Type::Path(ty); 403 } 404 _ => {} 405 } 406 407 Ok(GenericArgument::Type(argument)) 408 } 409 } 410 const_argument(input: ParseStream) -> Result<Expr>411 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> { 412 let lookahead = input.lookahead1(); 413 414 if input.peek(Lit) { 415 let lit = input.parse()?; 416 return Ok(Expr::Lit(lit)); 417 } 418 419 if input.peek(Ident) { 420 let ident: Ident = input.parse()?; 421 return Ok(Expr::Path(ExprPath { 422 attrs: Vec::new(), 423 qself: None, 424 path: Path::from(ident), 425 })); 426 } 427 428 if input.peek(token::Brace) { 429 #[cfg(feature = "full")] 430 { 431 let block: ExprBlock = input.parse()?; 432 return Ok(Expr::Block(block)); 433 } 434 435 #[cfg(not(feature = "full"))] 436 { 437 let begin = input.fork(); 438 let content; 439 braced!(content in input); 440 content.parse::<Expr>()?; 441 let verbatim = verbatim::between(&begin, input); 442 return Ok(Expr::Verbatim(verbatim)); 443 } 444 } 445 446 Err(lookahead.error()) 447 } 448 449 impl AngleBracketedGenericArguments { 450 /// Parse `::<…>` with mandatory leading `::`. 451 /// 452 /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` 453 /// parses optional leading `::`. 454 #[cfg(feature = "full")] 455 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] parse_turbofish(input: ParseStream) -> Result<Self>456 pub fn parse_turbofish(input: ParseStream) -> Result<Self> { 457 let colon2_token: Token![::] = input.parse()?; 458 Self::do_parse(Some(colon2_token), input) 459 } 460 do_parse( colon2_token: Option<Token![::]>, input: ParseStream, ) -> Result<Self>461 pub(crate) fn do_parse( 462 colon2_token: Option<Token![::]>, 463 input: ParseStream, 464 ) -> Result<Self> { 465 Ok(AngleBracketedGenericArguments { 466 colon2_token, 467 lt_token: input.parse()?, 468 args: { 469 let mut args = Punctuated::new(); 470 loop { 471 if input.peek(Token![>]) { 472 break; 473 } 474 let value: GenericArgument = input.parse()?; 475 args.push_value(value); 476 if input.peek(Token![>]) { 477 break; 478 } 479 let punct: Token![,] = input.parse()?; 480 args.push_punct(punct); 481 } 482 args 483 }, 484 gt_token: input.parse()?, 485 }) 486 } 487 } 488 489 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 490 impl Parse for AngleBracketedGenericArguments { parse(input: ParseStream) -> Result<Self>491 fn parse(input: ParseStream) -> Result<Self> { 492 let colon2_token: Option<Token![::]> = input.parse()?; 493 Self::do_parse(colon2_token, input) 494 } 495 } 496 497 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 498 impl Parse for ParenthesizedGenericArguments { parse(input: ParseStream) -> Result<Self>499 fn parse(input: ParseStream) -> Result<Self> { 500 let content; 501 Ok(ParenthesizedGenericArguments { 502 paren_token: parenthesized!(content in input), 503 inputs: content.parse_terminated(Type::parse, Token![,])?, 504 output: input.call(ReturnType::without_plus)?, 505 }) 506 } 507 } 508 509 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 510 impl Parse for PathSegment { parse(input: ParseStream) -> Result<Self>511 fn parse(input: ParseStream) -> Result<Self> { 512 Self::parse_helper(input, false) 513 } 514 } 515 516 impl PathSegment { parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>517 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 518 if input.peek(Token![super]) 519 || input.peek(Token![self]) 520 || input.peek(Token![crate]) 521 || cfg!(feature = "full") && input.peek(Token![try]) 522 { 523 let ident = input.call(Ident::parse_any)?; 524 return Ok(PathSegment::from(ident)); 525 } 526 527 let ident = if input.peek(Token![Self]) { 528 input.call(Ident::parse_any)? 529 } else { 530 input.parse()? 531 }; 532 533 if !expr_style 534 && input.peek(Token![<]) 535 && !input.peek(Token![<=]) 536 && !input.peek(Token![<<=]) 537 || input.peek(Token![::]) && input.peek3(Token![<]) 538 { 539 Ok(PathSegment { 540 ident, 541 arguments: PathArguments::AngleBracketed(input.parse()?), 542 }) 543 } else { 544 Ok(PathSegment::from(ident)) 545 } 546 } 547 } 548 549 impl Path { 550 /// Parse a `Path` containing no path arguments on any of its segments. 551 /// 552 /// # Example 553 /// 554 /// ``` 555 /// use syn::{Path, Result, Token}; 556 /// use syn::parse::{Parse, ParseStream}; 557 /// 558 /// // A simplified single `use` statement like: 559 /// // 560 /// // use std::collections::HashMap; 561 /// // 562 /// // Note that generic parameters are not allowed in a `use` statement 563 /// // so the following must not be accepted. 564 /// // 565 /// // use a::<b>::c; 566 /// struct SingleUse { 567 /// use_token: Token![use], 568 /// path: Path, 569 /// } 570 /// 571 /// impl Parse for SingleUse { 572 /// fn parse(input: ParseStream) -> Result<Self> { 573 /// Ok(SingleUse { 574 /// use_token: input.parse()?, 575 /// path: input.call(Path::parse_mod_style)?, 576 /// }) 577 /// } 578 /// } 579 /// ``` 580 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] parse_mod_style(input: ParseStream) -> Result<Self>581 pub fn parse_mod_style(input: ParseStream) -> Result<Self> { 582 Ok(Path { 583 leading_colon: input.parse()?, 584 segments: { 585 let mut segments = Punctuated::new(); 586 loop { 587 if !input.peek(Ident) 588 && !input.peek(Token![super]) 589 && !input.peek(Token![self]) 590 && !input.peek(Token![Self]) 591 && !input.peek(Token![crate]) 592 { 593 break; 594 } 595 let ident = Ident::parse_any(input)?; 596 segments.push_value(PathSegment::from(ident)); 597 if !input.peek(Token![::]) { 598 break; 599 } 600 let punct = input.parse()?; 601 segments.push_punct(punct); 602 } 603 if segments.is_empty() { 604 return Err(input.parse::<Ident>().unwrap_err()); 605 } else if segments.trailing_punct() { 606 return Err(input.error("expected path segment after `::`")); 607 } 608 segments 609 }, 610 }) 611 } 612 parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>613 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 614 let mut path = Path { 615 leading_colon: input.parse()?, 616 segments: { 617 let mut segments = Punctuated::new(); 618 let value = PathSegment::parse_helper(input, expr_style)?; 619 segments.push_value(value); 620 segments 621 }, 622 }; 623 Path::parse_rest(input, &mut path, expr_style)?; 624 Ok(path) 625 } 626 parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>627 pub(crate) fn parse_rest( 628 input: ParseStream, 629 path: &mut Self, 630 expr_style: bool, 631 ) -> Result<()> { 632 while input.peek(Token![::]) && !input.peek3(token::Paren) { 633 let punct: Token![::] = input.parse()?; 634 path.segments.push_punct(punct); 635 let value = PathSegment::parse_helper(input, expr_style)?; 636 path.segments.push_value(value); 637 } 638 Ok(()) 639 } 640 is_mod_style(&self) -> bool641 pub(crate) fn is_mod_style(&self) -> bool { 642 self.segments 643 .iter() 644 .all(|segment| segment.arguments.is_none()) 645 } 646 } 647 qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>648 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { 649 if input.peek(Token![<]) { 650 let lt_token: Token![<] = input.parse()?; 651 let this: Type = input.parse()?; 652 let path = if input.peek(Token![as]) { 653 let as_token: Token![as] = input.parse()?; 654 let path: Path = input.parse()?; 655 Some((as_token, path)) 656 } else { 657 None 658 }; 659 let gt_token: Token![>] = input.parse()?; 660 let colon2_token: Token![::] = input.parse()?; 661 let mut rest = Punctuated::new(); 662 loop { 663 let path = PathSegment::parse_helper(input, expr_style)?; 664 rest.push_value(path); 665 if !input.peek(Token![::]) { 666 break; 667 } 668 let punct: Token![::] = input.parse()?; 669 rest.push_punct(punct); 670 } 671 let (position, as_token, path) = match path { 672 Some((as_token, mut path)) => { 673 let pos = path.segments.len(); 674 path.segments.push_punct(colon2_token); 675 path.segments.extend(rest.into_pairs()); 676 (pos, Some(as_token), path) 677 } 678 None => { 679 let path = Path { 680 leading_colon: Some(colon2_token), 681 segments: rest, 682 }; 683 (0, None, path) 684 } 685 }; 686 let qself = QSelf { 687 lt_token, 688 ty: Box::new(this), 689 position, 690 as_token, 691 gt_token, 692 }; 693 Ok((Some(qself), path)) 694 } else { 695 let path = Path::parse_helper(input, expr_style)?; 696 Ok((None, path)) 697 } 698 } 699 } 700 701 #[cfg(feature = "printing")] 702 pub(crate) mod printing { 703 use crate::generics; 704 use crate::path::{ 705 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, 706 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, 707 }; 708 use crate::print::TokensOrDefault; 709 #[cfg(feature = "parsing")] 710 use crate::spanned::Spanned; 711 #[cfg(feature = "parsing")] 712 use proc_macro2::Span; 713 use proc_macro2::TokenStream; 714 use quote::ToTokens; 715 use std::cmp; 716 717 pub(crate) enum PathStyle { 718 Expr, 719 Mod, 720 AsWritten, 721 } 722 723 impl Copy for PathStyle {} 724 725 impl Clone for PathStyle { clone(&self) -> Self726 fn clone(&self) -> Self { 727 *self 728 } 729 } 730 731 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 732 impl ToTokens for Path { to_tokens(&self, tokens: &mut TokenStream)733 fn to_tokens(&self, tokens: &mut TokenStream) { 734 print_path(tokens, self, PathStyle::AsWritten); 735 } 736 } 737 print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle)738 pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) { 739 path.leading_colon.to_tokens(tokens); 740 for segment in path.segments.pairs() { 741 print_path_segment(tokens, segment.value(), style); 742 segment.punct().to_tokens(tokens); 743 } 744 } 745 746 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 747 impl ToTokens for PathSegment { to_tokens(&self, tokens: &mut TokenStream)748 fn to_tokens(&self, tokens: &mut TokenStream) { 749 print_path_segment(tokens, self, PathStyle::AsWritten); 750 } 751 } 752 print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle)753 fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) { 754 segment.ident.to_tokens(tokens); 755 print_path_arguments(tokens, &segment.arguments, style); 756 } 757 758 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 759 impl ToTokens for PathArguments { to_tokens(&self, tokens: &mut TokenStream)760 fn to_tokens(&self, tokens: &mut TokenStream) { 761 print_path_arguments(tokens, self, PathStyle::AsWritten); 762 } 763 } 764 print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle)765 fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) { 766 match arguments { 767 PathArguments::None => {} 768 PathArguments::AngleBracketed(arguments) => { 769 print_angle_bracketed_generic_arguments(tokens, arguments, style); 770 } 771 PathArguments::Parenthesized(arguments) => { 772 print_parenthesized_generic_arguments(tokens, arguments, style); 773 } 774 } 775 } 776 777 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 778 impl ToTokens for GenericArgument { 779 #[allow(clippy::match_same_arms)] to_tokens(&self, tokens: &mut TokenStream)780 fn to_tokens(&self, tokens: &mut TokenStream) { 781 match self { 782 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), 783 GenericArgument::Type(ty) => ty.to_tokens(tokens), 784 GenericArgument::Const(expr) => { 785 generics::printing::print_const_argument(expr, tokens); 786 } 787 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens), 788 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens), 789 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens), 790 } 791 } 792 } 793 794 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 795 impl ToTokens for AngleBracketedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)796 fn to_tokens(&self, tokens: &mut TokenStream) { 797 print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten); 798 } 799 } 800 print_angle_bracketed_generic_arguments( tokens: &mut TokenStream, arguments: &AngleBracketedGenericArguments, style: PathStyle, )801 pub(crate) fn print_angle_bracketed_generic_arguments( 802 tokens: &mut TokenStream, 803 arguments: &AngleBracketedGenericArguments, 804 style: PathStyle, 805 ) { 806 if let PathStyle::Mod = style { 807 return; 808 } 809 810 conditionally_print_turbofish(tokens, &arguments.colon2_token, style); 811 arguments.lt_token.to_tokens(tokens); 812 813 // Print lifetimes before types/consts/bindings, regardless of their 814 // order in args. 815 let mut trailing_or_empty = true; 816 for param in arguments.args.pairs() { 817 match param.value() { 818 GenericArgument::Lifetime(_) => { 819 param.to_tokens(tokens); 820 trailing_or_empty = param.punct().is_some(); 821 } 822 GenericArgument::Type(_) 823 | GenericArgument::Const(_) 824 | GenericArgument::AssocType(_) 825 | GenericArgument::AssocConst(_) 826 | GenericArgument::Constraint(_) => {} 827 } 828 } 829 for param in arguments.args.pairs() { 830 match param.value() { 831 GenericArgument::Type(_) 832 | GenericArgument::Const(_) 833 | GenericArgument::AssocType(_) 834 | GenericArgument::AssocConst(_) 835 | GenericArgument::Constraint(_) => { 836 if !trailing_or_empty { 837 <Token![,]>::default().to_tokens(tokens); 838 } 839 param.to_tokens(tokens); 840 trailing_or_empty = param.punct().is_some(); 841 } 842 GenericArgument::Lifetime(_) => {} 843 } 844 } 845 846 arguments.gt_token.to_tokens(tokens); 847 } 848 849 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 850 impl ToTokens for AssocType { to_tokens(&self, tokens: &mut TokenStream)851 fn to_tokens(&self, tokens: &mut TokenStream) { 852 self.ident.to_tokens(tokens); 853 self.generics.to_tokens(tokens); 854 self.eq_token.to_tokens(tokens); 855 self.ty.to_tokens(tokens); 856 } 857 } 858 859 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 860 impl ToTokens for AssocConst { to_tokens(&self, tokens: &mut TokenStream)861 fn to_tokens(&self, tokens: &mut TokenStream) { 862 self.ident.to_tokens(tokens); 863 self.generics.to_tokens(tokens); 864 self.eq_token.to_tokens(tokens); 865 generics::printing::print_const_argument(&self.value, tokens); 866 } 867 } 868 869 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 870 impl ToTokens for Constraint { to_tokens(&self, tokens: &mut TokenStream)871 fn to_tokens(&self, tokens: &mut TokenStream) { 872 self.ident.to_tokens(tokens); 873 self.generics.to_tokens(tokens); 874 self.colon_token.to_tokens(tokens); 875 self.bounds.to_tokens(tokens); 876 } 877 } 878 879 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 880 impl ToTokens for ParenthesizedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)881 fn to_tokens(&self, tokens: &mut TokenStream) { 882 print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten); 883 } 884 } 885 print_parenthesized_generic_arguments( tokens: &mut TokenStream, arguments: &ParenthesizedGenericArguments, style: PathStyle, )886 fn print_parenthesized_generic_arguments( 887 tokens: &mut TokenStream, 888 arguments: &ParenthesizedGenericArguments, 889 style: PathStyle, 890 ) { 891 if let PathStyle::Mod = style { 892 return; 893 } 894 895 conditionally_print_turbofish(tokens, &None, style); 896 arguments.paren_token.surround(tokens, |tokens| { 897 arguments.inputs.to_tokens(tokens); 898 }); 899 arguments.output.to_tokens(tokens); 900 } 901 print_qpath( tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path, style: PathStyle, )902 pub(crate) fn print_qpath( 903 tokens: &mut TokenStream, 904 qself: &Option<QSelf>, 905 path: &Path, 906 style: PathStyle, 907 ) { 908 let qself = match qself { 909 Some(qself) => qself, 910 None => { 911 print_path(tokens, path, style); 912 return; 913 } 914 }; 915 qself.lt_token.to_tokens(tokens); 916 qself.ty.to_tokens(tokens); 917 918 let pos = cmp::min(qself.position, path.segments.len()); 919 let mut segments = path.segments.pairs(); 920 if pos > 0 { 921 TokensOrDefault(&qself.as_token).to_tokens(tokens); 922 path.leading_colon.to_tokens(tokens); 923 for (i, segment) in segments.by_ref().take(pos).enumerate() { 924 print_path_segment(tokens, segment.value(), PathStyle::AsWritten); 925 if i + 1 == pos { 926 qself.gt_token.to_tokens(tokens); 927 } 928 segment.punct().to_tokens(tokens); 929 } 930 } else { 931 qself.gt_token.to_tokens(tokens); 932 path.leading_colon.to_tokens(tokens); 933 } 934 for segment in segments { 935 print_path_segment(tokens, segment.value(), style); 936 segment.punct().to_tokens(tokens); 937 } 938 } 939 conditionally_print_turbofish( tokens: &mut TokenStream, colon2_token: &Option<Token![::]>, style: PathStyle, )940 fn conditionally_print_turbofish( 941 tokens: &mut TokenStream, 942 colon2_token: &Option<Token![::]>, 943 style: PathStyle, 944 ) { 945 match style { 946 PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens), 947 PathStyle::Mod => unreachable!(), 948 PathStyle::AsWritten => colon2_token.to_tokens(tokens), 949 } 950 } 951 952 #[cfg(feature = "parsing")] 953 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] 954 impl Spanned for QSelf { span(&self) -> Span955 fn span(&self) -> Span { 956 struct QSelfDelimiters<'a>(&'a QSelf); 957 958 impl<'a> ToTokens for QSelfDelimiters<'a> { 959 fn to_tokens(&self, tokens: &mut TokenStream) { 960 self.0.lt_token.to_tokens(tokens); 961 self.0.gt_token.to_tokens(tokens); 962 } 963 } 964 965 QSelfDelimiters(self).span() 966 } 967 } 968 } 969