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