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