• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::punctuated::Punctuated;
3 
4 ast_struct! {
5     /// A path at which a named item is exported: `std::collections::HashMap`.
6     ///
7     /// *This type is available 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 {
from(segment: T) -> Self19     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 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 {
from(ident: T) -> Self44     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 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 {
default() -> Self75     fn default() -> Self {
76         PathArguments::None
77     }
78 }
79 
80 impl PathArguments {
is_empty(&self) -> bool81     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")]
is_none(&self) -> bool90     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 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 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 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 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 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 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 {
parse(input: ParseStream) -> Result<Self>213         fn parse(input: ParseStream) -> Result<Self> {
214             Self::parse_helper(input, false)
215         }
216     }
217 
218     impl Parse for GenericArgument {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>287         fn parse(input: ParseStream) -> Result<Self> {
288             Self::parse_helper(input, false)
289         }
290     }
291 
292     impl PathSegment {
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>293         fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
294             if input.peek(Token![super])
295                 || input.peek(Token![self])
296                 || input.peek(Token![crate])
297                 || input.peek(Token![extern])
298             {
299                 let ident = input.call(Ident::parse_any)?;
300                 return Ok(PathSegment::from(ident));
301             }
302 
303             let ident = if input.peek(Token![Self]) {
304                 input.call(Ident::parse_any)?
305             } else {
306                 input.parse()?
307             };
308 
309             if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
310                 || input.peek(Token![::]) && input.peek3(Token![<])
311             {
312                 Ok(PathSegment {
313                     ident,
314                     arguments: PathArguments::AngleBracketed(input.parse()?),
315                 })
316             } else {
317                 Ok(PathSegment::from(ident))
318             }
319         }
320     }
321 
322     impl Parse for Binding {
parse(input: ParseStream) -> Result<Self>323         fn parse(input: ParseStream) -> Result<Self> {
324             Ok(Binding {
325                 ident: input.parse()?,
326                 eq_token: input.parse()?,
327                 ty: input.parse()?,
328             })
329         }
330     }
331 
332     #[cfg(feature = "full")]
333     impl Parse for Constraint {
parse(input: ParseStream) -> Result<Self>334         fn parse(input: ParseStream) -> Result<Self> {
335             Ok(Constraint {
336                 ident: input.parse()?,
337                 colon_token: input.parse()?,
338                 bounds: {
339                     let mut bounds = Punctuated::new();
340                     loop {
341                         if input.peek(Token![,]) || input.peek(Token![>]) {
342                             break;
343                         }
344                         let value = input.parse()?;
345                         bounds.push_value(value);
346                         if !input.peek(Token![+]) {
347                             break;
348                         }
349                         let punct = input.parse()?;
350                         bounds.push_punct(punct);
351                     }
352                     bounds
353                 },
354             })
355         }
356     }
357 
358     impl Path {
359         /// Parse a `Path` containing no path arguments on any of its segments.
360         ///
361         /// *This function is available if Syn is built with the `"parsing"`
362         /// feature.*
363         ///
364         /// # Example
365         ///
366         /// ```
367         /// use syn::{Path, Result, Token};
368         /// use syn::parse::{Parse, ParseStream};
369         ///
370         /// // A simplified single `use` statement like:
371         /// //
372         /// //     use std::collections::HashMap;
373         /// //
374         /// // Note that generic parameters are not allowed in a `use` statement
375         /// // so the following must not be accepted.
376         /// //
377         /// //     use a::<b>::c;
378         /// struct SingleUse {
379         ///     use_token: Token![use],
380         ///     path: Path,
381         /// }
382         ///
383         /// impl Parse for SingleUse {
384         ///     fn parse(input: ParseStream) -> Result<Self> {
385         ///         Ok(SingleUse {
386         ///             use_token: input.parse()?,
387         ///             path: input.call(Path::parse_mod_style)?,
388         ///         })
389         ///     }
390         /// }
391         /// ```
parse_mod_style(input: ParseStream) -> Result<Self>392         pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
393             Ok(Path {
394                 leading_colon: input.parse()?,
395                 segments: {
396                     let mut segments = Punctuated::new();
397                     loop {
398                         if !input.peek(Ident)
399                             && !input.peek(Token![super])
400                             && !input.peek(Token![self])
401                             && !input.peek(Token![Self])
402                             && !input.peek(Token![crate])
403                             && !input.peek(Token![extern])
404                         {
405                             break;
406                         }
407                         let ident = Ident::parse_any(input)?;
408                         segments.push_value(PathSegment::from(ident));
409                         if !input.peek(Token![::]) {
410                             break;
411                         }
412                         let punct = input.parse()?;
413                         segments.push_punct(punct);
414                     }
415                     if segments.is_empty() {
416                         return Err(input.error("expected path"));
417                     } else if segments.trailing_punct() {
418                         return Err(input.error("expected path segment"));
419                     }
420                     segments
421                 },
422             })
423         }
424 
425         /// Determines whether this is a path of length 1 equal to the given
426         /// ident.
427         ///
428         /// For them to compare equal, it must be the case that:
429         ///
430         /// - the path has no leading colon,
431         /// - the number of path segments is 1,
432         /// - the first path segment has no angle bracketed or parenthesized
433         ///   path arguments, and
434         /// - the ident of the first path segment is equal to the given one.
435         ///
436         /// *This function is available if Syn is built with the `"parsing"`
437         /// feature.*
438         ///
439         /// # Example
440         ///
441         /// ```
442         /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
443         /// # use std::iter::FromIterator;
444         ///
445         /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
446         ///     if attr.path.is_ident("serde") {
447         ///         match attr.parse_meta()? {
448         ///             Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
449         ///             bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
450         ///         }
451         ///     } else {
452         ///         Ok(Vec::new())
453         ///     }
454         /// }
455         /// ```
is_ident<I: ?Sized>(&self, ident: &I) -> bool where Ident: PartialEq<I>,456         pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
457         where
458             Ident: PartialEq<I>,
459         {
460             match self.get_ident() {
461                 Some(id) => id == ident,
462                 None => false,
463             }
464         }
465 
466         /// If this path consists of a single ident, returns the ident.
467         ///
468         /// A path is considered an ident if:
469         ///
470         /// - the path has no leading colon,
471         /// - the number of path segments is 1, and
472         /// - the first path segment has no angle bracketed or parenthesized
473         ///   path arguments.
474         ///
475         /// *This function is available if Syn is built with the `"parsing"`
476         /// feature.*
get_ident(&self) -> Option<&Ident>477         pub fn get_ident(&self) -> Option<&Ident> {
478             if self.leading_colon.is_none()
479                 && self.segments.len() == 1
480                 && self.segments[0].arguments.is_none()
481             {
482                 Some(&self.segments[0].ident)
483             } else {
484                 None
485             }
486         }
487 
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>488         fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
489             Ok(Path {
490                 leading_colon: input.parse()?,
491                 segments: {
492                     let mut segments = Punctuated::new();
493                     let value = PathSegment::parse_helper(input, expr_style)?;
494                     segments.push_value(value);
495                     while input.peek(Token![::]) {
496                         let punct: Token![::] = input.parse()?;
497                         segments.push_punct(punct);
498                         let value = PathSegment::parse_helper(input, expr_style)?;
499                         segments.push_value(value);
500                     }
501                     segments
502                 },
503             })
504         }
505     }
506 
qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>507     pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
508         if input.peek(Token![<]) {
509             let lt_token: Token![<] = input.parse()?;
510             let this: Type = input.parse()?;
511             let path = if input.peek(Token![as]) {
512                 let as_token: Token![as] = input.parse()?;
513                 let path: Path = input.parse()?;
514                 Some((as_token, path))
515             } else {
516                 None
517             };
518             let gt_token: Token![>] = input.parse()?;
519             let colon2_token: Token![::] = input.parse()?;
520             let mut rest = Punctuated::new();
521             loop {
522                 let path = PathSegment::parse_helper(input, expr_style)?;
523                 rest.push_value(path);
524                 if !input.peek(Token![::]) {
525                     break;
526                 }
527                 let punct: Token![::] = input.parse()?;
528                 rest.push_punct(punct);
529             }
530             let (position, as_token, path) = match path {
531                 Some((as_token, mut path)) => {
532                     let pos = path.segments.len();
533                     path.segments.push_punct(colon2_token);
534                     path.segments.extend(rest.into_pairs());
535                     (pos, Some(as_token), path)
536                 }
537                 None => {
538                     let path = Path {
539                         leading_colon: Some(colon2_token),
540                         segments: rest,
541                     };
542                     (0, None, path)
543                 }
544             };
545             let qself = QSelf {
546                 lt_token,
547                 ty: Box::new(this),
548                 position,
549                 as_token,
550                 gt_token,
551             };
552             Ok((Some(qself), path))
553         } else {
554             let path = Path::parse_helper(input, expr_style)?;
555             Ok((None, path))
556         }
557     }
558 }
559 
560 #[cfg(feature = "printing")]
561 mod printing {
562     use super::*;
563 
564     use proc_macro2::TokenStream;
565     use quote::ToTokens;
566 
567     use crate::print::TokensOrDefault;
568 
569     impl ToTokens for Path {
to_tokens(&self, tokens: &mut TokenStream)570         fn to_tokens(&self, tokens: &mut TokenStream) {
571             self.leading_colon.to_tokens(tokens);
572             self.segments.to_tokens(tokens);
573         }
574     }
575 
576     impl ToTokens for PathSegment {
to_tokens(&self, tokens: &mut TokenStream)577         fn to_tokens(&self, tokens: &mut TokenStream) {
578             self.ident.to_tokens(tokens);
579             self.arguments.to_tokens(tokens);
580         }
581     }
582 
583     impl ToTokens for PathArguments {
to_tokens(&self, tokens: &mut TokenStream)584         fn to_tokens(&self, tokens: &mut TokenStream) {
585             match self {
586                 PathArguments::None => {}
587                 PathArguments::AngleBracketed(arguments) => {
588                     arguments.to_tokens(tokens);
589                 }
590                 PathArguments::Parenthesized(arguments) => {
591                     arguments.to_tokens(tokens);
592                 }
593             }
594         }
595     }
596 
597     impl ToTokens for GenericArgument {
598         #[allow(clippy::match_same_arms)]
to_tokens(&self, tokens: &mut TokenStream)599         fn to_tokens(&self, tokens: &mut TokenStream) {
600             match self {
601                 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
602                 GenericArgument::Type(ty) => ty.to_tokens(tokens),
603                 GenericArgument::Binding(tb) => tb.to_tokens(tokens),
604                 GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
605                 GenericArgument::Const(e) => match *e {
606                     Expr::Lit(_) => e.to_tokens(tokens),
607 
608                     // NOTE: We should probably support parsing blocks with only
609                     // expressions in them without the full feature for const
610                     // generics.
611                     #[cfg(feature = "full")]
612                     Expr::Block(_) => e.to_tokens(tokens),
613 
614                     // ERROR CORRECTION: Add braces to make sure that the
615                     // generated code is valid.
616                     _ => token::Brace::default().surround(tokens, |tokens| {
617                         e.to_tokens(tokens);
618                     }),
619                 },
620             }
621         }
622     }
623 
624     impl ToTokens for AngleBracketedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)625         fn to_tokens(&self, tokens: &mut TokenStream) {
626             self.colon2_token.to_tokens(tokens);
627             self.lt_token.to_tokens(tokens);
628 
629             // Print lifetimes before types and consts, all before bindings,
630             // regardless of their order in self.args.
631             //
632             // TODO: ordering rules for const arguments vs type arguments have
633             // not been settled yet. https://github.com/rust-lang/rust/issues/44580
634             let mut trailing_or_empty = true;
635             for param in self.args.pairs() {
636                 match **param.value() {
637                     GenericArgument::Lifetime(_) => {
638                         param.to_tokens(tokens);
639                         trailing_or_empty = param.punct().is_some();
640                     }
641                     GenericArgument::Type(_)
642                     | GenericArgument::Binding(_)
643                     | GenericArgument::Constraint(_)
644                     | GenericArgument::Const(_) => {}
645                 }
646             }
647             for param in self.args.pairs() {
648                 match **param.value() {
649                     GenericArgument::Type(_) | GenericArgument::Const(_) => {
650                         if !trailing_or_empty {
651                             <Token![,]>::default().to_tokens(tokens);
652                         }
653                         param.to_tokens(tokens);
654                         trailing_or_empty = param.punct().is_some();
655                     }
656                     GenericArgument::Lifetime(_)
657                     | GenericArgument::Binding(_)
658                     | GenericArgument::Constraint(_) => {}
659                 }
660             }
661             for param in self.args.pairs() {
662                 match **param.value() {
663                     GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
664                         if !trailing_or_empty {
665                             <Token![,]>::default().to_tokens(tokens);
666                             trailing_or_empty = true;
667                         }
668                         param.to_tokens(tokens);
669                     }
670                     GenericArgument::Lifetime(_)
671                     | GenericArgument::Type(_)
672                     | GenericArgument::Const(_) => {}
673                 }
674             }
675 
676             self.gt_token.to_tokens(tokens);
677         }
678     }
679 
680     impl ToTokens for Binding {
to_tokens(&self, tokens: &mut TokenStream)681         fn to_tokens(&self, tokens: &mut TokenStream) {
682             self.ident.to_tokens(tokens);
683             self.eq_token.to_tokens(tokens);
684             self.ty.to_tokens(tokens);
685         }
686     }
687 
688     impl ToTokens for Constraint {
to_tokens(&self, tokens: &mut TokenStream)689         fn to_tokens(&self, tokens: &mut TokenStream) {
690             self.ident.to_tokens(tokens);
691             self.colon_token.to_tokens(tokens);
692             self.bounds.to_tokens(tokens);
693         }
694     }
695 
696     impl ToTokens for ParenthesizedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)697         fn to_tokens(&self, tokens: &mut TokenStream) {
698             self.paren_token.surround(tokens, |tokens| {
699                 self.inputs.to_tokens(tokens);
700             });
701             self.output.to_tokens(tokens);
702         }
703     }
704 
705     impl private {
print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)706         pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
707             let qself = match qself {
708                 Some(qself) => qself,
709                 None => {
710                     path.to_tokens(tokens);
711                     return;
712                 }
713             };
714             qself.lt_token.to_tokens(tokens);
715             qself.ty.to_tokens(tokens);
716 
717             let pos = if qself.position > 0 && qself.position >= path.segments.len() {
718                 path.segments.len() - 1
719             } else {
720                 qself.position
721             };
722             let mut segments = path.segments.pairs();
723             if pos > 0 {
724                 TokensOrDefault(&qself.as_token).to_tokens(tokens);
725                 path.leading_colon.to_tokens(tokens);
726                 for (i, segment) in segments.by_ref().take(pos).enumerate() {
727                     if i + 1 == pos {
728                         segment.value().to_tokens(tokens);
729                         qself.gt_token.to_tokens(tokens);
730                         segment.punct().to_tokens(tokens);
731                     } else {
732                         segment.to_tokens(tokens);
733                     }
734                 }
735             } else {
736                 qself.gt_token.to_tokens(tokens);
737                 path.leading_colon.to_tokens(tokens);
738             }
739             for segment in segments {
740                 segment.to_tokens(tokens);
741             }
742         }
743     }
744 }
745