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; 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 fn do_parse(colon2_token: Option<Token![::]>, input: ParseStream) -> Result<Self> { 428 Ok(AngleBracketedGenericArguments { 429 colon2_token, 430 lt_token: input.parse()?, 431 args: { 432 let mut args = Punctuated::new(); 433 loop { 434 if input.peek(Token![>]) { 435 break; 436 } 437 let value: GenericArgument = input.parse()?; 438 args.push_value(value); 439 if input.peek(Token![>]) { 440 break; 441 } 442 let punct: Token![,] = input.parse()?; 443 args.push_punct(punct); 444 } 445 args 446 }, 447 gt_token: input.parse()?, 448 }) 449 } 450 } 451 452 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 453 impl Parse for AngleBracketedGenericArguments { parse(input: ParseStream) -> Result<Self>454 fn parse(input: ParseStream) -> Result<Self> { 455 let colon2_token: Option<Token![::]> = input.parse()?; 456 Self::do_parse(colon2_token, input) 457 } 458 } 459 460 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 461 impl Parse for ParenthesizedGenericArguments { parse(input: ParseStream) -> Result<Self>462 fn parse(input: ParseStream) -> Result<Self> { 463 let content; 464 Ok(ParenthesizedGenericArguments { 465 paren_token: parenthesized!(content in input), 466 inputs: content.parse_terminated(Type::parse, Token![,])?, 467 output: input.call(ReturnType::without_plus)?, 468 }) 469 } 470 } 471 472 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 473 impl Parse for PathSegment { parse(input: ParseStream) -> Result<Self>474 fn parse(input: ParseStream) -> Result<Self> { 475 Self::parse_helper(input, false) 476 } 477 } 478 479 impl PathSegment { parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>480 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 481 if input.peek(Token![super]) 482 || input.peek(Token![self]) 483 || input.peek(Token![crate]) 484 || cfg!(feature = "full") && input.peek(Token![try]) 485 { 486 let ident = input.call(Ident::parse_any)?; 487 return Ok(PathSegment::from(ident)); 488 } 489 490 let ident = if input.peek(Token![Self]) { 491 input.call(Ident::parse_any)? 492 } else { 493 input.parse()? 494 }; 495 496 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) 497 || input.peek(Token![::]) && input.peek3(Token![<]) 498 { 499 Ok(PathSegment { 500 ident, 501 arguments: PathArguments::AngleBracketed(input.parse()?), 502 }) 503 } else { 504 Ok(PathSegment::from(ident)) 505 } 506 } 507 } 508 509 impl Path { 510 /// Parse a `Path` containing no path arguments on any of its segments. 511 /// 512 /// # Example 513 /// 514 /// ``` 515 /// use syn::{Path, Result, Token}; 516 /// use syn::parse::{Parse, ParseStream}; 517 /// 518 /// // A simplified single `use` statement like: 519 /// // 520 /// // use std::collections::HashMap; 521 /// // 522 /// // Note that generic parameters are not allowed in a `use` statement 523 /// // so the following must not be accepted. 524 /// // 525 /// // use a::<b>::c; 526 /// struct SingleUse { 527 /// use_token: Token![use], 528 /// path: Path, 529 /// } 530 /// 531 /// impl Parse for SingleUse { 532 /// fn parse(input: ParseStream) -> Result<Self> { 533 /// Ok(SingleUse { 534 /// use_token: input.parse()?, 535 /// path: input.call(Path::parse_mod_style)?, 536 /// }) 537 /// } 538 /// } 539 /// ``` 540 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_mod_style(input: ParseStream) -> Result<Self>541 pub fn parse_mod_style(input: ParseStream) -> Result<Self> { 542 Ok(Path { 543 leading_colon: input.parse()?, 544 segments: { 545 let mut segments = Punctuated::new(); 546 loop { 547 if !input.peek(Ident) 548 && !input.peek(Token![super]) 549 && !input.peek(Token![self]) 550 && !input.peek(Token![Self]) 551 && !input.peek(Token![crate]) 552 { 553 break; 554 } 555 let ident = Ident::parse_any(input)?; 556 segments.push_value(PathSegment::from(ident)); 557 if !input.peek(Token![::]) { 558 break; 559 } 560 let punct = input.parse()?; 561 segments.push_punct(punct); 562 } 563 if segments.is_empty() { 564 return Err(input.parse::<Ident>().unwrap_err()); 565 } else if segments.trailing_punct() { 566 return Err(input.error("expected path segment after `::`")); 567 } 568 segments 569 }, 570 }) 571 } 572 parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>573 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 574 let mut path = Path { 575 leading_colon: input.parse()?, 576 segments: { 577 let mut segments = Punctuated::new(); 578 let value = PathSegment::parse_helper(input, expr_style)?; 579 segments.push_value(value); 580 segments 581 }, 582 }; 583 Path::parse_rest(input, &mut path, expr_style)?; 584 Ok(path) 585 } 586 parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>587 pub(crate) fn parse_rest( 588 input: ParseStream, 589 path: &mut Self, 590 expr_style: bool, 591 ) -> Result<()> { 592 while input.peek(Token![::]) && !input.peek3(token::Paren) { 593 let punct: Token![::] = input.parse()?; 594 path.segments.push_punct(punct); 595 let value = PathSegment::parse_helper(input, expr_style)?; 596 path.segments.push_value(value); 597 } 598 Ok(()) 599 } 600 is_mod_style(&self) -> bool601 pub(crate) fn is_mod_style(&self) -> bool { 602 self.segments 603 .iter() 604 .all(|segment| segment.arguments.is_none()) 605 } 606 } 607 qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>608 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { 609 if input.peek(Token![<]) { 610 let lt_token: Token![<] = input.parse()?; 611 let this: Type = input.parse()?; 612 let path = if input.peek(Token![as]) { 613 let as_token: Token![as] = input.parse()?; 614 let path: Path = input.parse()?; 615 Some((as_token, path)) 616 } else { 617 None 618 }; 619 let gt_token: Token![>] = input.parse()?; 620 let colon2_token: Token![::] = input.parse()?; 621 let mut rest = Punctuated::new(); 622 loop { 623 let path = PathSegment::parse_helper(input, expr_style)?; 624 rest.push_value(path); 625 if !input.peek(Token![::]) { 626 break; 627 } 628 let punct: Token![::] = input.parse()?; 629 rest.push_punct(punct); 630 } 631 let (position, as_token, path) = match path { 632 Some((as_token, mut path)) => { 633 let pos = path.segments.len(); 634 path.segments.push_punct(colon2_token); 635 path.segments.extend(rest.into_pairs()); 636 (pos, Some(as_token), path) 637 } 638 None => { 639 let path = Path { 640 leading_colon: Some(colon2_token), 641 segments: rest, 642 }; 643 (0, None, path) 644 } 645 }; 646 let qself = QSelf { 647 lt_token, 648 ty: Box::new(this), 649 position, 650 as_token, 651 gt_token, 652 }; 653 Ok((Some(qself), path)) 654 } else { 655 let path = Path::parse_helper(input, expr_style)?; 656 Ok((None, path)) 657 } 658 } 659 } 660 661 #[cfg(feature = "printing")] 662 pub(crate) mod printing { 663 use super::*; 664 use crate::print::TokensOrDefault; 665 #[cfg(feature = "parsing")] 666 use crate::spanned::Spanned; 667 #[cfg(feature = "parsing")] 668 use proc_macro2::Span; 669 use proc_macro2::TokenStream; 670 use quote::ToTokens; 671 use std::cmp; 672 673 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 674 impl ToTokens for Path { to_tokens(&self, tokens: &mut TokenStream)675 fn to_tokens(&self, tokens: &mut TokenStream) { 676 self.leading_colon.to_tokens(tokens); 677 self.segments.to_tokens(tokens); 678 } 679 } 680 681 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 682 impl ToTokens for PathSegment { to_tokens(&self, tokens: &mut TokenStream)683 fn to_tokens(&self, tokens: &mut TokenStream) { 684 self.ident.to_tokens(tokens); 685 self.arguments.to_tokens(tokens); 686 } 687 } 688 689 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 690 impl ToTokens for PathArguments { to_tokens(&self, tokens: &mut TokenStream)691 fn to_tokens(&self, tokens: &mut TokenStream) { 692 match self { 693 PathArguments::None => {} 694 PathArguments::AngleBracketed(arguments) => { 695 arguments.to_tokens(tokens); 696 } 697 PathArguments::Parenthesized(arguments) => { 698 arguments.to_tokens(tokens); 699 } 700 } 701 } 702 } 703 704 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 705 impl ToTokens for GenericArgument { 706 #[allow(clippy::match_same_arms)] to_tokens(&self, tokens: &mut TokenStream)707 fn to_tokens(&self, tokens: &mut TokenStream) { 708 match self { 709 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), 710 GenericArgument::Type(ty) => ty.to_tokens(tokens), 711 GenericArgument::Const(expr) => match expr { 712 Expr::Lit(expr) => expr.to_tokens(tokens), 713 714 Expr::Path(expr) 715 if expr.attrs.is_empty() 716 && expr.qself.is_none() 717 && expr.path.get_ident().is_some() => 718 { 719 expr.to_tokens(tokens); 720 } 721 722 #[cfg(feature = "full")] 723 Expr::Block(expr) => expr.to_tokens(tokens), 724 725 #[cfg(not(feature = "full"))] 726 Expr::Verbatim(expr) => expr.to_tokens(tokens), 727 728 // ERROR CORRECTION: Add braces to make sure that the 729 // generated code is valid. 730 _ => token::Brace::default().surround(tokens, |tokens| { 731 expr.to_tokens(tokens); 732 }), 733 }, 734 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens), 735 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens), 736 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens), 737 } 738 } 739 } 740 741 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 742 impl ToTokens for AngleBracketedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)743 fn to_tokens(&self, tokens: &mut TokenStream) { 744 self.colon2_token.to_tokens(tokens); 745 self.lt_token.to_tokens(tokens); 746 747 // Print lifetimes before types/consts/bindings, regardless of their 748 // order in self.args. 749 let mut trailing_or_empty = true; 750 for param in self.args.pairs() { 751 match param.value() { 752 GenericArgument::Lifetime(_) => { 753 param.to_tokens(tokens); 754 trailing_or_empty = param.punct().is_some(); 755 } 756 GenericArgument::Type(_) 757 | GenericArgument::Const(_) 758 | GenericArgument::AssocType(_) 759 | GenericArgument::AssocConst(_) 760 | GenericArgument::Constraint(_) => {} 761 } 762 } 763 for param in self.args.pairs() { 764 match param.value() { 765 GenericArgument::Type(_) 766 | GenericArgument::Const(_) 767 | GenericArgument::AssocType(_) 768 | GenericArgument::AssocConst(_) 769 | GenericArgument::Constraint(_) => { 770 if !trailing_or_empty { 771 <Token![,]>::default().to_tokens(tokens); 772 } 773 param.to_tokens(tokens); 774 trailing_or_empty = param.punct().is_some(); 775 } 776 GenericArgument::Lifetime(_) => {} 777 } 778 } 779 780 self.gt_token.to_tokens(tokens); 781 } 782 } 783 784 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 785 impl ToTokens for AssocType { to_tokens(&self, tokens: &mut TokenStream)786 fn to_tokens(&self, tokens: &mut TokenStream) { 787 self.ident.to_tokens(tokens); 788 self.generics.to_tokens(tokens); 789 self.eq_token.to_tokens(tokens); 790 self.ty.to_tokens(tokens); 791 } 792 } 793 794 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 795 impl ToTokens for AssocConst { to_tokens(&self, tokens: &mut TokenStream)796 fn to_tokens(&self, tokens: &mut TokenStream) { 797 self.ident.to_tokens(tokens); 798 self.generics.to_tokens(tokens); 799 self.eq_token.to_tokens(tokens); 800 self.value.to_tokens(tokens); 801 } 802 } 803 804 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 805 impl ToTokens for Constraint { to_tokens(&self, tokens: &mut TokenStream)806 fn to_tokens(&self, tokens: &mut TokenStream) { 807 self.ident.to_tokens(tokens); 808 self.generics.to_tokens(tokens); 809 self.colon_token.to_tokens(tokens); 810 self.bounds.to_tokens(tokens); 811 } 812 } 813 814 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 815 impl ToTokens for ParenthesizedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)816 fn to_tokens(&self, tokens: &mut TokenStream) { 817 self.paren_token.surround(tokens, |tokens| { 818 self.inputs.to_tokens(tokens); 819 }); 820 self.output.to_tokens(tokens); 821 } 822 } 823 print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)824 pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { 825 let qself = match qself { 826 Some(qself) => qself, 827 None => { 828 path.to_tokens(tokens); 829 return; 830 } 831 }; 832 qself.lt_token.to_tokens(tokens); 833 qself.ty.to_tokens(tokens); 834 835 let pos = cmp::min(qself.position, path.segments.len()); 836 let mut segments = path.segments.pairs(); 837 if pos > 0 { 838 TokensOrDefault(&qself.as_token).to_tokens(tokens); 839 path.leading_colon.to_tokens(tokens); 840 for (i, segment) in segments.by_ref().take(pos).enumerate() { 841 if i + 1 == pos { 842 segment.value().to_tokens(tokens); 843 qself.gt_token.to_tokens(tokens); 844 segment.punct().to_tokens(tokens); 845 } else { 846 segment.to_tokens(tokens); 847 } 848 } 849 } else { 850 qself.gt_token.to_tokens(tokens); 851 path.leading_colon.to_tokens(tokens); 852 } 853 for segment in segments { 854 segment.to_tokens(tokens); 855 } 856 } 857 858 #[cfg(feature = "parsing")] 859 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))] 860 impl Spanned for QSelf { span(&self) -> Span861 fn span(&self) -> Span { 862 struct QSelfDelimiters<'a>(&'a QSelf); 863 864 impl<'a> ToTokens for QSelfDelimiters<'a> { 865 fn to_tokens(&self, tokens: &mut TokenStream) { 866 self.0.lt_token.to_tokens(tokens); 867 self.0.gt_token.to_tokens(tokens); 868 } 869 } 870 871 QSelfDelimiters(self).span() 872 } 873 } 874 } 875