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