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(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 14 pub struct Path { 15 pub leading_colon: Option<Token![::]>, 16 pub segments: Punctuated<PathSegment, Token![::]>, 17 } 18 } 19 20 impl<T> From<T> for Path 21 where 22 T: Into<PathSegment>, 23 { from(segment: T) -> Self24 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 /// ``` is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>,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. get_ident(&self) -> Option<&Ident>82 pub fn get_ident(&self) -> Option<&Ident> { 83 if self.leading_colon.is_none() 84 && self.segments.len() == 1 85 && self.segments[0].arguments.is_none() 86 { 87 Some(&self.segments[0].ident) 88 } else { 89 None 90 } 91 } 92 93 /// An error if this path is not a single ident, as defined in `get_ident`. 94 #[cfg(feature = "parsing")] 95 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] require_ident(&self) -> Result<&Ident>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(doc_cfg, 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 { from(ident: T) -> Self120 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(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 139 pub enum PathArguments { 140 None, 141 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 142 AngleBracketed(AngleBracketedGenericArguments), 143 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 144 Parenthesized(ParenthesizedGenericArguments), 145 } 146 } 147 148 impl Default for PathArguments { default() -> Self149 fn default() -> Self { 150 PathArguments::None 151 } 152 } 153 154 impl PathArguments { is_empty(&self) -> bool155 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 is_none(&self) -> bool163 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(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 174 #[non_exhaustive] 175 pub enum GenericArgument { 176 /// A lifetime argument. 177 Lifetime(Lifetime), 178 /// A type argument. 179 Type(Type), 180 /// A const expression. Must be inside of a block. 181 /// 182 /// NOTE: Identity expressions are represented as Type arguments, as 183 /// they are indistinguishable syntactically. 184 Const(Expr), 185 /// A binding (equality constraint) on an associated type: the `Item = 186 /// u8` in `Iterator<Item = u8>`. 187 AssocType(AssocType), 188 /// An equality constraint on an associated constant: the `PANIC = 189 /// false` in `Trait<PANIC = false>`. 190 AssocConst(AssocConst), 191 /// An associated type bound: `Iterator<Item: Display>`. 192 Constraint(Constraint), 193 } 194 } 195 196 ast_struct! { 197 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, 198 /// V>`. 199 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 200 pub struct AngleBracketedGenericArguments { 201 pub colon2_token: Option<Token![::]>, 202 pub lt_token: Token![<], 203 pub args: Punctuated<GenericArgument, Token![,]>, 204 pub gt_token: Token![>], 205 } 206 } 207 208 ast_struct! { 209 /// A binding (equality constraint) on an associated type: the `Item = u8` 210 /// in `Iterator<Item = u8>`. 211 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 212 pub struct AssocType { 213 pub ident: Ident, 214 pub generics: Option<AngleBracketedGenericArguments>, 215 pub eq_token: Token![=], 216 pub ty: Type, 217 } 218 } 219 220 ast_struct! { 221 /// An equality constraint on an associated constant: the `PANIC = false` in 222 /// `Trait<PANIC = false>`. 223 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 224 pub struct AssocConst { 225 pub ident: Ident, 226 pub generics: Option<AngleBracketedGenericArguments>, 227 pub eq_token: Token![=], 228 pub value: Expr, 229 } 230 } 231 232 ast_struct! { 233 /// An associated type bound: `Iterator<Item: Display>`. 234 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 235 pub struct Constraint { 236 pub ident: Ident, 237 pub generics: Option<AngleBracketedGenericArguments>, 238 pub colon_token: Token![:], 239 pub bounds: Punctuated<TypeParamBound, Token![+]>, 240 } 241 } 242 243 ast_struct! { 244 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> 245 /// C`. 246 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 247 pub struct ParenthesizedGenericArguments { 248 pub paren_token: token::Paren, 249 /// `(A, B)` 250 pub inputs: Punctuated<Type, Token![,]>, 251 /// `C` 252 pub output: ReturnType, 253 } 254 } 255 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(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 274 pub struct QSelf { 275 pub lt_token: Token![<], 276 pub ty: Box<Type>, 277 pub position: usize, 278 pub as_token: Option<Token![as]>, 279 pub gt_token: Token![>], 280 } 281 } 282 283 #[cfg(feature = "parsing")] 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(doc_cfg, doc(cfg(feature = "parsing")))] 309 impl Parse for Path { parse(input: ParseStream) -> Result<Self>310 fn parse(input: ParseStream) -> Result<Self> { 311 Self::parse_helper(input, false) 312 } 313 } 314 315 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 316 impl Parse for GenericArgument { parse(input: ParseStream) -> Result<Self>317 fn parse(input: ParseStream) -> Result<Self> { 318 if input.peek(Lifetime) && !input.peek2(Token![+]) { 319 return Ok(GenericArgument::Lifetime(input.parse()?)); 320 } 321 322 if input.peek(Lit) || input.peek(token::Brace) { 323 return const_argument(input).map(GenericArgument::Const); 324 } 325 326 let mut argument: Type = input.parse()?; 327 328 match argument { 329 Type::Path(mut ty) 330 if ty.qself.is_none() 331 && ty.path.leading_colon.is_none() 332 && ty.path.segments.len() == 1 333 && match &ty.path.segments[0].arguments { 334 PathArguments::None | PathArguments::AngleBracketed(_) => true, 335 PathArguments::Parenthesized(_) => false, 336 } => 337 { 338 if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { 339 let segment = ty.path.segments.pop().unwrap().into_value(); 340 let ident = segment.ident; 341 let generics = match segment.arguments { 342 PathArguments::None => None, 343 PathArguments::AngleBracketed(arguments) => Some(arguments), 344 PathArguments::Parenthesized(_) => unreachable!(), 345 }; 346 return if input.peek(Lit) || input.peek(token::Brace) { 347 Ok(GenericArgument::AssocConst(AssocConst { 348 ident, 349 generics, 350 eq_token, 351 value: const_argument(input)?, 352 })) 353 } else { 354 Ok(GenericArgument::AssocType(AssocType { 355 ident, 356 generics, 357 eq_token, 358 ty: input.parse()?, 359 })) 360 }; 361 } 362 363 #[cfg(feature = "full")] 364 if let Some(colon_token) = input.parse::<Option<Token![:]>>()? { 365 let segment = ty.path.segments.pop().unwrap().into_value(); 366 return Ok(GenericArgument::Constraint(Constraint { 367 ident: segment.ident, 368 generics: match segment.arguments { 369 PathArguments::None => None, 370 PathArguments::AngleBracketed(arguments) => Some(arguments), 371 PathArguments::Parenthesized(_) => unreachable!(), 372 }, 373 colon_token, 374 bounds: { 375 let mut bounds = Punctuated::new(); 376 loop { 377 if input.peek(Token![,]) || input.peek(Token![>]) { 378 break; 379 } 380 let value: TypeParamBound = input.parse()?; 381 bounds.push_value(value); 382 if !input.peek(Token![+]) { 383 break; 384 } 385 let punct: Token![+] = input.parse()?; 386 bounds.push_punct(punct); 387 } 388 bounds 389 }, 390 })); 391 } 392 393 argument = Type::Path(ty); 394 } 395 _ => {} 396 } 397 398 Ok(GenericArgument::Type(argument)) 399 } 400 } 401 const_argument(input: ParseStream) -> Result<Expr>402 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> { 403 let lookahead = input.lookahead1(); 404 405 if input.peek(Lit) { 406 let lit = input.parse()?; 407 return Ok(Expr::Lit(lit)); 408 } 409 410 if input.peek(Ident) { 411 let ident: Ident = input.parse()?; 412 return Ok(Expr::Path(ExprPath { 413 attrs: Vec::new(), 414 qself: None, 415 path: Path::from(ident), 416 })); 417 } 418 419 if input.peek(token::Brace) { 420 #[cfg(feature = "full")] 421 { 422 let block: ExprBlock = input.parse()?; 423 return Ok(Expr::Block(block)); 424 } 425 426 #[cfg(not(feature = "full"))] 427 { 428 let begin = input.fork(); 429 let content; 430 braced!(content in input); 431 content.parse::<Expr>()?; 432 let verbatim = verbatim::between(&begin, input); 433 return Ok(Expr::Verbatim(verbatim)); 434 } 435 } 436 437 Err(lookahead.error()) 438 } 439 440 impl AngleBracketedGenericArguments { 441 /// Parse `::<…>` with mandatory leading `::`. 442 /// 443 /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` 444 /// parses optional leading `::`. 445 #[cfg(feature = "full")] 446 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))] parse_turbofish(input: ParseStream) -> Result<Self>447 pub fn parse_turbofish(input: ParseStream) -> Result<Self> { 448 let colon2_token: Token![::] = input.parse()?; 449 Self::do_parse(Some(colon2_token), input) 450 } 451 do_parse( colon2_token: Option<Token![::]>, input: ParseStream, ) -> Result<Self>452 pub(crate) fn do_parse( 453 colon2_token: Option<Token![::]>, 454 input: ParseStream, 455 ) -> Result<Self> { 456 Ok(AngleBracketedGenericArguments { 457 colon2_token, 458 lt_token: input.parse()?, 459 args: { 460 let mut args = Punctuated::new(); 461 loop { 462 if input.peek(Token![>]) { 463 break; 464 } 465 let value: GenericArgument = input.parse()?; 466 args.push_value(value); 467 if input.peek(Token![>]) { 468 break; 469 } 470 let punct: Token![,] = input.parse()?; 471 args.push_punct(punct); 472 } 473 args 474 }, 475 gt_token: input.parse()?, 476 }) 477 } 478 } 479 480 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 481 impl Parse for AngleBracketedGenericArguments { parse(input: ParseStream) -> Result<Self>482 fn parse(input: ParseStream) -> Result<Self> { 483 let colon2_token: Option<Token![::]> = input.parse()?; 484 Self::do_parse(colon2_token, input) 485 } 486 } 487 488 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 489 impl Parse for ParenthesizedGenericArguments { parse(input: ParseStream) -> Result<Self>490 fn parse(input: ParseStream) -> Result<Self> { 491 let content; 492 Ok(ParenthesizedGenericArguments { 493 paren_token: parenthesized!(content in input), 494 inputs: content.parse_terminated(Type::parse, Token![,])?, 495 output: input.call(ReturnType::without_plus)?, 496 }) 497 } 498 } 499 500 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 501 impl Parse for PathSegment { parse(input: ParseStream) -> Result<Self>502 fn parse(input: ParseStream) -> Result<Self> { 503 Self::parse_helper(input, false) 504 } 505 } 506 507 impl PathSegment { parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>508 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 509 if input.peek(Token![super]) 510 || input.peek(Token![self]) 511 || input.peek(Token![crate]) 512 || cfg!(feature = "full") && input.peek(Token![try]) 513 { 514 let ident = input.call(Ident::parse_any)?; 515 return Ok(PathSegment::from(ident)); 516 } 517 518 let ident = if input.peek(Token![Self]) { 519 input.call(Ident::parse_any)? 520 } else { 521 input.parse()? 522 }; 523 524 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) 525 || input.peek(Token![::]) && input.peek3(Token![<]) 526 { 527 Ok(PathSegment { 528 ident, 529 arguments: PathArguments::AngleBracketed(input.parse()?), 530 }) 531 } else { 532 Ok(PathSegment::from(ident)) 533 } 534 } 535 } 536 537 impl Path { 538 /// Parse a `Path` containing no path arguments on any of its segments. 539 /// 540 /// # Example 541 /// 542 /// ``` 543 /// use syn::{Path, Result, Token}; 544 /// use syn::parse::{Parse, ParseStream}; 545 /// 546 /// // A simplified single `use` statement like: 547 /// // 548 /// // use std::collections::HashMap; 549 /// // 550 /// // Note that generic parameters are not allowed in a `use` statement 551 /// // so the following must not be accepted. 552 /// // 553 /// // use a::<b>::c; 554 /// struct SingleUse { 555 /// use_token: Token![use], 556 /// path: Path, 557 /// } 558 /// 559 /// impl Parse for SingleUse { 560 /// fn parse(input: ParseStream) -> Result<Self> { 561 /// Ok(SingleUse { 562 /// use_token: input.parse()?, 563 /// path: input.call(Path::parse_mod_style)?, 564 /// }) 565 /// } 566 /// } 567 /// ``` 568 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_mod_style(input: ParseStream) -> Result<Self>569 pub fn parse_mod_style(input: ParseStream) -> Result<Self> { 570 Ok(Path { 571 leading_colon: input.parse()?, 572 segments: { 573 let mut segments = Punctuated::new(); 574 loop { 575 if !input.peek(Ident) 576 && !input.peek(Token![super]) 577 && !input.peek(Token![self]) 578 && !input.peek(Token![Self]) 579 && !input.peek(Token![crate]) 580 { 581 break; 582 } 583 let ident = Ident::parse_any(input)?; 584 segments.push_value(PathSegment::from(ident)); 585 if !input.peek(Token![::]) { 586 break; 587 } 588 let punct = input.parse()?; 589 segments.push_punct(punct); 590 } 591 if segments.is_empty() { 592 return Err(input.parse::<Ident>().unwrap_err()); 593 } else if segments.trailing_punct() { 594 return Err(input.error("expected path segment after `::`")); 595 } 596 segments 597 }, 598 }) 599 } 600 parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>601 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 602 let mut path = Path { 603 leading_colon: input.parse()?, 604 segments: { 605 let mut segments = Punctuated::new(); 606 let value = PathSegment::parse_helper(input, expr_style)?; 607 segments.push_value(value); 608 segments 609 }, 610 }; 611 Path::parse_rest(input, &mut path, expr_style)?; 612 Ok(path) 613 } 614 parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>615 pub(crate) fn parse_rest( 616 input: ParseStream, 617 path: &mut Self, 618 expr_style: bool, 619 ) -> Result<()> { 620 while input.peek(Token![::]) && !input.peek3(token::Paren) { 621 let punct: Token![::] = input.parse()?; 622 path.segments.push_punct(punct); 623 let value = PathSegment::parse_helper(input, expr_style)?; 624 path.segments.push_value(value); 625 } 626 Ok(()) 627 } 628 is_mod_style(&self) -> bool629 pub(crate) fn is_mod_style(&self) -> bool { 630 self.segments 631 .iter() 632 .all(|segment| segment.arguments.is_none()) 633 } 634 } 635 qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>636 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { 637 if input.peek(Token![<]) { 638 let lt_token: Token![<] = input.parse()?; 639 let this: Type = input.parse()?; 640 let path = if input.peek(Token![as]) { 641 let as_token: Token![as] = input.parse()?; 642 let path: Path = input.parse()?; 643 Some((as_token, path)) 644 } else { 645 None 646 }; 647 let gt_token: Token![>] = input.parse()?; 648 let colon2_token: Token![::] = input.parse()?; 649 let mut rest = Punctuated::new(); 650 loop { 651 let path = PathSegment::parse_helper(input, expr_style)?; 652 rest.push_value(path); 653 if !input.peek(Token![::]) { 654 break; 655 } 656 let punct: Token![::] = input.parse()?; 657 rest.push_punct(punct); 658 } 659 let (position, as_token, path) = match path { 660 Some((as_token, mut path)) => { 661 let pos = path.segments.len(); 662 path.segments.push_punct(colon2_token); 663 path.segments.extend(rest.into_pairs()); 664 (pos, Some(as_token), path) 665 } 666 None => { 667 let path = Path { 668 leading_colon: Some(colon2_token), 669 segments: rest, 670 }; 671 (0, None, path) 672 } 673 }; 674 let qself = QSelf { 675 lt_token, 676 ty: Box::new(this), 677 position, 678 as_token, 679 gt_token, 680 }; 681 Ok((Some(qself), path)) 682 } else { 683 let path = Path::parse_helper(input, expr_style)?; 684 Ok((None, path)) 685 } 686 } 687 } 688 689 #[cfg(feature = "printing")] 690 pub(crate) mod printing { 691 use crate::expr::Expr; 692 use crate::path::{ 693 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, 694 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, 695 }; 696 use crate::print::TokensOrDefault; 697 #[cfg(feature = "parsing")] 698 use crate::spanned::Spanned; 699 use crate::token; 700 #[cfg(feature = "parsing")] 701 use proc_macro2::Span; 702 use proc_macro2::TokenStream; 703 use quote::ToTokens; 704 use std::cmp; 705 706 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 707 impl ToTokens for Path { to_tokens(&self, tokens: &mut TokenStream)708 fn to_tokens(&self, tokens: &mut TokenStream) { 709 self.leading_colon.to_tokens(tokens); 710 self.segments.to_tokens(tokens); 711 } 712 } 713 714 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 715 impl ToTokens for PathSegment { to_tokens(&self, tokens: &mut TokenStream)716 fn to_tokens(&self, tokens: &mut TokenStream) { 717 self.ident.to_tokens(tokens); 718 self.arguments.to_tokens(tokens); 719 } 720 } 721 722 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 723 impl ToTokens for PathArguments { to_tokens(&self, tokens: &mut TokenStream)724 fn to_tokens(&self, tokens: &mut TokenStream) { 725 match self { 726 PathArguments::None => {} 727 PathArguments::AngleBracketed(arguments) => { 728 arguments.to_tokens(tokens); 729 } 730 PathArguments::Parenthesized(arguments) => { 731 arguments.to_tokens(tokens); 732 } 733 } 734 } 735 } 736 737 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 738 impl ToTokens for GenericArgument { 739 #[allow(clippy::match_same_arms)] to_tokens(&self, tokens: &mut TokenStream)740 fn to_tokens(&self, tokens: &mut TokenStream) { 741 match self { 742 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), 743 GenericArgument::Type(ty) => ty.to_tokens(tokens), 744 GenericArgument::Const(expr) => match expr { 745 Expr::Lit(expr) => expr.to_tokens(tokens), 746 747 Expr::Path(expr) 748 if expr.attrs.is_empty() 749 && expr.qself.is_none() 750 && expr.path.get_ident().is_some() => 751 { 752 expr.to_tokens(tokens); 753 } 754 755 #[cfg(feature = "full")] 756 Expr::Block(expr) => expr.to_tokens(tokens), 757 758 #[cfg(not(feature = "full"))] 759 Expr::Verbatim(expr) => expr.to_tokens(tokens), 760 761 // ERROR CORRECTION: Add braces to make sure that the 762 // generated code is valid. 763 _ => token::Brace::default().surround(tokens, |tokens| { 764 expr.to_tokens(tokens); 765 }), 766 }, 767 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens), 768 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens), 769 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens), 770 } 771 } 772 } 773 774 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 775 impl ToTokens for AngleBracketedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)776 fn to_tokens(&self, tokens: &mut TokenStream) { 777 self.colon2_token.to_tokens(tokens); 778 self.lt_token.to_tokens(tokens); 779 780 // Print lifetimes before types/consts/bindings, regardless of their 781 // order in self.args. 782 let mut trailing_or_empty = true; 783 for param in self.args.pairs() { 784 match param.value() { 785 GenericArgument::Lifetime(_) => { 786 param.to_tokens(tokens); 787 trailing_or_empty = param.punct().is_some(); 788 } 789 GenericArgument::Type(_) 790 | GenericArgument::Const(_) 791 | GenericArgument::AssocType(_) 792 | GenericArgument::AssocConst(_) 793 | GenericArgument::Constraint(_) => {} 794 } 795 } 796 for param in self.args.pairs() { 797 match param.value() { 798 GenericArgument::Type(_) 799 | GenericArgument::Const(_) 800 | GenericArgument::AssocType(_) 801 | GenericArgument::AssocConst(_) 802 | GenericArgument::Constraint(_) => { 803 if !trailing_or_empty { 804 <Token![,]>::default().to_tokens(tokens); 805 } 806 param.to_tokens(tokens); 807 trailing_or_empty = param.punct().is_some(); 808 } 809 GenericArgument::Lifetime(_) => {} 810 } 811 } 812 813 self.gt_token.to_tokens(tokens); 814 } 815 } 816 817 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 818 impl ToTokens for AssocType { to_tokens(&self, tokens: &mut TokenStream)819 fn to_tokens(&self, tokens: &mut TokenStream) { 820 self.ident.to_tokens(tokens); 821 self.generics.to_tokens(tokens); 822 self.eq_token.to_tokens(tokens); 823 self.ty.to_tokens(tokens); 824 } 825 } 826 827 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 828 impl ToTokens for AssocConst { to_tokens(&self, tokens: &mut TokenStream)829 fn to_tokens(&self, tokens: &mut TokenStream) { 830 self.ident.to_tokens(tokens); 831 self.generics.to_tokens(tokens); 832 self.eq_token.to_tokens(tokens); 833 self.value.to_tokens(tokens); 834 } 835 } 836 837 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 838 impl ToTokens for Constraint { to_tokens(&self, tokens: &mut TokenStream)839 fn to_tokens(&self, tokens: &mut TokenStream) { 840 self.ident.to_tokens(tokens); 841 self.generics.to_tokens(tokens); 842 self.colon_token.to_tokens(tokens); 843 self.bounds.to_tokens(tokens); 844 } 845 } 846 847 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 848 impl ToTokens for ParenthesizedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)849 fn to_tokens(&self, tokens: &mut TokenStream) { 850 self.paren_token.surround(tokens, |tokens| { 851 self.inputs.to_tokens(tokens); 852 }); 853 self.output.to_tokens(tokens); 854 } 855 } 856 print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)857 pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { 858 let qself = match qself { 859 Some(qself) => qself, 860 None => { 861 path.to_tokens(tokens); 862 return; 863 } 864 }; 865 qself.lt_token.to_tokens(tokens); 866 qself.ty.to_tokens(tokens); 867 868 let pos = cmp::min(qself.position, path.segments.len()); 869 let mut segments = path.segments.pairs(); 870 if pos > 0 { 871 TokensOrDefault(&qself.as_token).to_tokens(tokens); 872 path.leading_colon.to_tokens(tokens); 873 for (i, segment) in segments.by_ref().take(pos).enumerate() { 874 if i + 1 == pos { 875 segment.value().to_tokens(tokens); 876 qself.gt_token.to_tokens(tokens); 877 segment.punct().to_tokens(tokens); 878 } else { 879 segment.to_tokens(tokens); 880 } 881 } 882 } else { 883 qself.gt_token.to_tokens(tokens); 884 path.leading_colon.to_tokens(tokens); 885 } 886 for segment in segments { 887 segment.to_tokens(tokens); 888 } 889 } 890 891 #[cfg(feature = "parsing")] 892 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))] 893 impl Spanned for QSelf { span(&self) -> Span894 fn span(&self) -> Span { 895 struct QSelfDelimiters<'a>(&'a QSelf); 896 897 impl<'a> ToTokens for QSelfDelimiters<'a> { 898 fn to_tokens(&self, tokens: &mut TokenStream) { 899 self.0.lt_token.to_tokens(tokens); 900 self.0.gt_token.to_tokens(tokens); 901 } 902 } 903 904 QSelfDelimiters(self).span() 905 } 906 } 907 } 908