xref: /linux/rust/syn/path.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda 
3808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
4808c999fSMiguel Ojeda use crate::error::Result;
5808c999fSMiguel Ojeda use crate::expr::Expr;
6808c999fSMiguel Ojeda use crate::generics::TypeParamBound;
7808c999fSMiguel Ojeda use crate::ident::Ident;
8808c999fSMiguel Ojeda use crate::lifetime::Lifetime;
9808c999fSMiguel Ojeda use crate::punctuated::Punctuated;
10808c999fSMiguel Ojeda use crate::token;
11808c999fSMiguel Ojeda use crate::ty::{ReturnType, Type};
12808c999fSMiguel Ojeda 
13808c999fSMiguel Ojeda ast_struct! {
14808c999fSMiguel Ojeda     /// A path at which a named item is exported (e.g. `std::collections::HashMap`).
15808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
16808c999fSMiguel Ojeda     pub struct Path {
17808c999fSMiguel Ojeda         pub leading_colon: Option<Token![::]>,
18808c999fSMiguel Ojeda         pub segments: Punctuated<PathSegment, Token![::]>,
19808c999fSMiguel Ojeda     }
20808c999fSMiguel Ojeda }
21808c999fSMiguel Ojeda 
22808c999fSMiguel Ojeda impl<T> From<T> for Path
23808c999fSMiguel Ojeda where
24808c999fSMiguel Ojeda     T: Into<PathSegment>,
25808c999fSMiguel Ojeda {
from(segment: T) -> Self26808c999fSMiguel Ojeda     fn from(segment: T) -> Self {
27808c999fSMiguel Ojeda         let mut path = Path {
28808c999fSMiguel Ojeda             leading_colon: None,
29808c999fSMiguel Ojeda             segments: Punctuated::new(),
30808c999fSMiguel Ojeda         };
31808c999fSMiguel Ojeda         path.segments.push_value(segment.into());
32808c999fSMiguel Ojeda         path
33808c999fSMiguel Ojeda     }
34808c999fSMiguel Ojeda }
35808c999fSMiguel Ojeda 
36808c999fSMiguel Ojeda impl Path {
37808c999fSMiguel Ojeda     /// Determines whether this is a path of length 1 equal to the given
38808c999fSMiguel Ojeda     /// ident.
39808c999fSMiguel Ojeda     ///
40808c999fSMiguel Ojeda     /// For them to compare equal, it must be the case that:
41808c999fSMiguel Ojeda     ///
42808c999fSMiguel Ojeda     /// - the path has no leading colon,
43808c999fSMiguel Ojeda     /// - the number of path segments is 1,
44808c999fSMiguel Ojeda     /// - the first path segment has no angle bracketed or parenthesized
45808c999fSMiguel Ojeda     ///   path arguments, and
46808c999fSMiguel Ojeda     /// - the ident of the first path segment is equal to the given one.
47808c999fSMiguel Ojeda     ///
48808c999fSMiguel Ojeda     /// # Example
49808c999fSMiguel Ojeda     ///
50808c999fSMiguel Ojeda     /// ```
51808c999fSMiguel Ojeda     /// use proc_macro2::TokenStream;
52808c999fSMiguel Ojeda     /// use syn::{Attribute, Error, Meta, Result};
53808c999fSMiguel Ojeda     ///
54808c999fSMiguel Ojeda     /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> {
55808c999fSMiguel Ojeda     ///     if attr.path().is_ident("serde") {
56808c999fSMiguel Ojeda     ///         match &attr.meta {
57808c999fSMiguel Ojeda     ///             Meta::List(meta) => Ok(Some(&meta.tokens)),
58808c999fSMiguel Ojeda     ///             bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
59808c999fSMiguel Ojeda     ///         }
60808c999fSMiguel Ojeda     ///     } else {
61808c999fSMiguel Ojeda     ///         Ok(None)
62808c999fSMiguel Ojeda     ///     }
63808c999fSMiguel Ojeda     /// }
64808c999fSMiguel Ojeda     /// ```
is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>,65808c999fSMiguel Ojeda     pub fn is_ident<I>(&self, ident: &I) -> bool
66808c999fSMiguel Ojeda     where
67808c999fSMiguel Ojeda         I: ?Sized,
68808c999fSMiguel Ojeda         Ident: PartialEq<I>,
69808c999fSMiguel Ojeda     {
70808c999fSMiguel Ojeda         match self.get_ident() {
71808c999fSMiguel Ojeda             Some(id) => id == ident,
72808c999fSMiguel Ojeda             None => false,
73808c999fSMiguel Ojeda         }
74808c999fSMiguel Ojeda     }
75808c999fSMiguel Ojeda 
76808c999fSMiguel Ojeda     /// If this path consists of a single ident, returns the ident.
77808c999fSMiguel Ojeda     ///
78808c999fSMiguel Ojeda     /// A path is considered an ident if:
79808c999fSMiguel Ojeda     ///
80808c999fSMiguel Ojeda     /// - the path has no leading colon,
81808c999fSMiguel Ojeda     /// - the number of path segments is 1, and
82808c999fSMiguel Ojeda     /// - the first path segment has no angle bracketed or parenthesized
83808c999fSMiguel Ojeda     ///   path arguments.
get_ident(&self) -> Option<&Ident>84808c999fSMiguel Ojeda     pub fn get_ident(&self) -> Option<&Ident> {
85808c999fSMiguel Ojeda         if self.leading_colon.is_none()
86808c999fSMiguel Ojeda             && self.segments.len() == 1
87808c999fSMiguel Ojeda             && self.segments[0].arguments.is_none()
88808c999fSMiguel Ojeda         {
89808c999fSMiguel Ojeda             Some(&self.segments[0].ident)
90808c999fSMiguel Ojeda         } else {
91808c999fSMiguel Ojeda             None
92808c999fSMiguel Ojeda         }
93808c999fSMiguel Ojeda     }
94808c999fSMiguel Ojeda 
95808c999fSMiguel Ojeda     /// An error if this path is not a single ident, as defined in `get_ident`.
96808c999fSMiguel Ojeda     #[cfg(feature = "parsing")]
97808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
require_ident(&self) -> Result<&Ident>98808c999fSMiguel Ojeda     pub fn require_ident(&self) -> Result<&Ident> {
99808c999fSMiguel Ojeda         self.get_ident().ok_or_else(|| {
100808c999fSMiguel Ojeda             crate::error::new2(
101808c999fSMiguel Ojeda                 self.segments.first().unwrap().ident.span(),
102808c999fSMiguel Ojeda                 self.segments.last().unwrap().ident.span(),
103808c999fSMiguel Ojeda                 "expected this path to be an identifier",
104808c999fSMiguel Ojeda             )
105808c999fSMiguel Ojeda         })
106808c999fSMiguel Ojeda     }
107808c999fSMiguel Ojeda }
108808c999fSMiguel Ojeda 
109808c999fSMiguel Ojeda ast_struct! {
110808c999fSMiguel Ojeda     /// A segment of a path together with any path arguments on that segment.
111808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
112808c999fSMiguel Ojeda     pub struct PathSegment {
113808c999fSMiguel Ojeda         pub ident: Ident,
114808c999fSMiguel Ojeda         pub arguments: PathArguments,
115808c999fSMiguel Ojeda     }
116808c999fSMiguel Ojeda }
117808c999fSMiguel Ojeda 
118808c999fSMiguel Ojeda impl<T> From<T> for PathSegment
119808c999fSMiguel Ojeda where
120808c999fSMiguel Ojeda     T: Into<Ident>,
121808c999fSMiguel Ojeda {
from(ident: T) -> Self122808c999fSMiguel Ojeda     fn from(ident: T) -> Self {
123808c999fSMiguel Ojeda         PathSegment {
124808c999fSMiguel Ojeda             ident: ident.into(),
125808c999fSMiguel Ojeda             arguments: PathArguments::None,
126808c999fSMiguel Ojeda         }
127808c999fSMiguel Ojeda     }
128808c999fSMiguel Ojeda }
129808c999fSMiguel Ojeda 
130808c999fSMiguel Ojeda ast_enum! {
131808c999fSMiguel Ojeda     /// Angle bracketed or parenthesized arguments of a path segment.
132808c999fSMiguel Ojeda     ///
133808c999fSMiguel Ojeda     /// ## Angle bracketed
134808c999fSMiguel Ojeda     ///
135808c999fSMiguel Ojeda     /// The `<'a, T>` in `std::slice::iter<'a, T>`.
136808c999fSMiguel Ojeda     ///
137808c999fSMiguel Ojeda     /// ## Parenthesized
138808c999fSMiguel Ojeda     ///
139808c999fSMiguel Ojeda     /// The `(A, B) -> C` in `Fn(A, B) -> C`.
140808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
141808c999fSMiguel Ojeda     pub enum PathArguments {
142808c999fSMiguel Ojeda         None,
143808c999fSMiguel Ojeda         /// The `<'a, T>` in `std::slice::iter<'a, T>`.
144808c999fSMiguel Ojeda         AngleBracketed(AngleBracketedGenericArguments),
145808c999fSMiguel Ojeda         /// The `(A, B) -> C` in `Fn(A, B) -> C`.
146808c999fSMiguel Ojeda         Parenthesized(ParenthesizedGenericArguments),
147808c999fSMiguel Ojeda     }
148808c999fSMiguel Ojeda }
149808c999fSMiguel Ojeda 
150808c999fSMiguel Ojeda impl Default for PathArguments {
default() -> Self151808c999fSMiguel Ojeda     fn default() -> Self {
152808c999fSMiguel Ojeda         PathArguments::None
153808c999fSMiguel Ojeda     }
154808c999fSMiguel Ojeda }
155808c999fSMiguel Ojeda 
156808c999fSMiguel Ojeda impl PathArguments {
is_empty(&self) -> bool157808c999fSMiguel Ojeda     pub fn is_empty(&self) -> bool {
158808c999fSMiguel Ojeda         match self {
159808c999fSMiguel Ojeda             PathArguments::None => true,
160808c999fSMiguel Ojeda             PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
161808c999fSMiguel Ojeda             PathArguments::Parenthesized(_) => false,
162808c999fSMiguel Ojeda         }
163808c999fSMiguel Ojeda     }
164808c999fSMiguel Ojeda 
is_none(&self) -> bool165808c999fSMiguel Ojeda     pub fn is_none(&self) -> bool {
166808c999fSMiguel Ojeda         match self {
167808c999fSMiguel Ojeda             PathArguments::None => true,
168808c999fSMiguel Ojeda             PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
169808c999fSMiguel Ojeda         }
170808c999fSMiguel Ojeda     }
171808c999fSMiguel Ojeda }
172808c999fSMiguel Ojeda 
173808c999fSMiguel Ojeda ast_enum! {
174808c999fSMiguel Ojeda     /// An individual generic argument, like `'a`, `T`, or `Item = T`.
175808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
176808c999fSMiguel Ojeda     #[non_exhaustive]
177808c999fSMiguel Ojeda     pub enum GenericArgument {
178808c999fSMiguel Ojeda         /// A lifetime argument.
179808c999fSMiguel Ojeda         Lifetime(Lifetime),
180808c999fSMiguel Ojeda         /// A type argument.
181808c999fSMiguel Ojeda         Type(Type),
182808c999fSMiguel Ojeda         /// A const expression. Must be inside of a block.
183808c999fSMiguel Ojeda         ///
184808c999fSMiguel Ojeda         /// NOTE: Identity expressions are represented as Type arguments, as
185808c999fSMiguel Ojeda         /// they are indistinguishable syntactically.
186808c999fSMiguel Ojeda         Const(Expr),
187808c999fSMiguel Ojeda         /// A binding (equality constraint) on an associated type: the `Item =
188808c999fSMiguel Ojeda         /// u8` in `Iterator<Item = u8>`.
189808c999fSMiguel Ojeda         AssocType(AssocType),
190808c999fSMiguel Ojeda         /// An equality constraint on an associated constant: the `PANIC =
191808c999fSMiguel Ojeda         /// false` in `Trait<PANIC = false>`.
192808c999fSMiguel Ojeda         AssocConst(AssocConst),
193808c999fSMiguel Ojeda         /// An associated type bound: `Iterator<Item: Display>`.
194808c999fSMiguel Ojeda         Constraint(Constraint),
195808c999fSMiguel Ojeda     }
196808c999fSMiguel Ojeda }
197808c999fSMiguel Ojeda 
198808c999fSMiguel Ojeda ast_struct! {
199808c999fSMiguel Ojeda     /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
200808c999fSMiguel Ojeda     /// V>`.
201808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
202808c999fSMiguel Ojeda     pub struct AngleBracketedGenericArguments {
203808c999fSMiguel Ojeda         pub colon2_token: Option<Token![::]>,
204808c999fSMiguel Ojeda         pub lt_token: Token![<],
205808c999fSMiguel Ojeda         pub args: Punctuated<GenericArgument, Token![,]>,
206808c999fSMiguel Ojeda         pub gt_token: Token![>],
207808c999fSMiguel Ojeda     }
208808c999fSMiguel Ojeda }
209808c999fSMiguel Ojeda 
210808c999fSMiguel Ojeda ast_struct! {
211808c999fSMiguel Ojeda     /// A binding (equality constraint) on an associated type: the `Item = u8`
212808c999fSMiguel Ojeda     /// in `Iterator<Item = u8>`.
213808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
214808c999fSMiguel Ojeda     pub struct AssocType {
215808c999fSMiguel Ojeda         pub ident: Ident,
216808c999fSMiguel Ojeda         pub generics: Option<AngleBracketedGenericArguments>,
217808c999fSMiguel Ojeda         pub eq_token: Token![=],
218808c999fSMiguel Ojeda         pub ty: Type,
219808c999fSMiguel Ojeda     }
220808c999fSMiguel Ojeda }
221808c999fSMiguel Ojeda 
222808c999fSMiguel Ojeda ast_struct! {
223808c999fSMiguel Ojeda     /// An equality constraint on an associated constant: the `PANIC = false` in
224808c999fSMiguel Ojeda     /// `Trait<PANIC = false>`.
225808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
226808c999fSMiguel Ojeda     pub struct AssocConst {
227808c999fSMiguel Ojeda         pub ident: Ident,
228808c999fSMiguel Ojeda         pub generics: Option<AngleBracketedGenericArguments>,
229808c999fSMiguel Ojeda         pub eq_token: Token![=],
230808c999fSMiguel Ojeda         pub value: Expr,
231808c999fSMiguel Ojeda     }
232808c999fSMiguel Ojeda }
233808c999fSMiguel Ojeda 
234808c999fSMiguel Ojeda ast_struct! {
235808c999fSMiguel Ojeda     /// An associated type bound: `Iterator<Item: Display>`.
236808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
237808c999fSMiguel Ojeda     pub struct Constraint {
238808c999fSMiguel Ojeda         pub ident: Ident,
239808c999fSMiguel Ojeda         pub generics: Option<AngleBracketedGenericArguments>,
240808c999fSMiguel Ojeda         pub colon_token: Token![:],
241808c999fSMiguel Ojeda         pub bounds: Punctuated<TypeParamBound, Token![+]>,
242808c999fSMiguel Ojeda     }
243808c999fSMiguel Ojeda }
244808c999fSMiguel Ojeda 
245808c999fSMiguel Ojeda ast_struct! {
246808c999fSMiguel Ojeda     /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
247808c999fSMiguel Ojeda     /// C`.
248808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
249808c999fSMiguel Ojeda     pub struct ParenthesizedGenericArguments {
250808c999fSMiguel Ojeda         pub paren_token: token::Paren,
251808c999fSMiguel Ojeda         /// `(A, B)`
252808c999fSMiguel Ojeda         pub inputs: Punctuated<Type, Token![,]>,
253808c999fSMiguel Ojeda         /// `C`
254808c999fSMiguel Ojeda         pub output: ReturnType,
255808c999fSMiguel Ojeda     }
256808c999fSMiguel Ojeda }
257808c999fSMiguel Ojeda 
258808c999fSMiguel Ojeda ast_struct! {
259808c999fSMiguel Ojeda     /// The explicit Self type in a qualified path: the `T` in `<T as
260808c999fSMiguel Ojeda     /// Display>::fmt`.
261808c999fSMiguel Ojeda     ///
262808c999fSMiguel Ojeda     /// The actual path, including the trait and the associated item, is stored
263808c999fSMiguel Ojeda     /// separately. The `position` field represents the index of the associated
264808c999fSMiguel Ojeda     /// item qualified with this Self type.
265808c999fSMiguel Ojeda     ///
266808c999fSMiguel Ojeda     /// ```text
267808c999fSMiguel Ojeda     /// <Vec<T> as a::b::Trait>::AssociatedItem
268808c999fSMiguel Ojeda     ///  ^~~~~~    ~~~~~~~~~~~~~~^
269808c999fSMiguel Ojeda     ///  ty        position = 3
270808c999fSMiguel Ojeda     ///
271808c999fSMiguel Ojeda     /// <Vec<T>>::AssociatedItem
272808c999fSMiguel Ojeda     ///  ^~~~~~   ^
273808c999fSMiguel Ojeda     ///  ty       position = 0
274808c999fSMiguel Ojeda     /// ```
275808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
276808c999fSMiguel Ojeda     pub struct QSelf {
277808c999fSMiguel Ojeda         pub lt_token: Token![<],
278808c999fSMiguel Ojeda         pub ty: Box<Type>,
279808c999fSMiguel Ojeda         pub position: usize,
280808c999fSMiguel Ojeda         pub as_token: Option<Token![as]>,
281808c999fSMiguel Ojeda         pub gt_token: Token![>],
282808c999fSMiguel Ojeda     }
283808c999fSMiguel Ojeda }
284808c999fSMiguel Ojeda 
285808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
286808c999fSMiguel Ojeda pub(crate) mod parsing {
287808c999fSMiguel Ojeda     use crate::error::Result;
288808c999fSMiguel Ojeda     #[cfg(feature = "full")]
289808c999fSMiguel Ojeda     use crate::expr::ExprBlock;
290808c999fSMiguel Ojeda     use crate::expr::{Expr, ExprPath};
291808c999fSMiguel Ojeda     use crate::ext::IdentExt as _;
292808c999fSMiguel Ojeda     #[cfg(feature = "full")]
293808c999fSMiguel Ojeda     use crate::generics::TypeParamBound;
294808c999fSMiguel Ojeda     use crate::ident::Ident;
295808c999fSMiguel Ojeda     use crate::lifetime::Lifetime;
296808c999fSMiguel Ojeda     use crate::lit::Lit;
297808c999fSMiguel Ojeda     use crate::parse::{Parse, ParseStream};
298808c999fSMiguel Ojeda     #[cfg(feature = "full")]
299808c999fSMiguel Ojeda     use crate::path::Constraint;
300808c999fSMiguel Ojeda     use crate::path::{
301808c999fSMiguel Ojeda         AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument,
302808c999fSMiguel Ojeda         ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
303808c999fSMiguel Ojeda     };
304808c999fSMiguel Ojeda     use crate::punctuated::Punctuated;
305808c999fSMiguel Ojeda     use crate::token;
306808c999fSMiguel Ojeda     use crate::ty::{ReturnType, Type};
307808c999fSMiguel Ojeda     #[cfg(not(feature = "full"))]
308808c999fSMiguel Ojeda     use crate::verbatim;
309808c999fSMiguel Ojeda 
310808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
311808c999fSMiguel Ojeda     impl Parse for Path {
parse(input: ParseStream) -> Result<Self>312808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
313808c999fSMiguel Ojeda             Self::parse_helper(input, false)
314808c999fSMiguel Ojeda         }
315808c999fSMiguel Ojeda     }
316808c999fSMiguel Ojeda 
317808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
318808c999fSMiguel Ojeda     impl Parse for GenericArgument {
parse(input: ParseStream) -> Result<Self>319808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
320808c999fSMiguel Ojeda             if input.peek(Lifetime) && !input.peek2(Token![+]) {
321808c999fSMiguel Ojeda                 return Ok(GenericArgument::Lifetime(input.parse()?));
322808c999fSMiguel Ojeda             }
323808c999fSMiguel Ojeda 
324808c999fSMiguel Ojeda             if input.peek(Lit) || input.peek(token::Brace) {
325808c999fSMiguel Ojeda                 return const_argument(input).map(GenericArgument::Const);
326808c999fSMiguel Ojeda             }
327808c999fSMiguel Ojeda 
328808c999fSMiguel Ojeda             let mut argument: Type = input.parse()?;
329808c999fSMiguel Ojeda 
330808c999fSMiguel Ojeda             match argument {
331808c999fSMiguel Ojeda                 Type::Path(mut ty)
332808c999fSMiguel Ojeda                     if ty.qself.is_none()
333808c999fSMiguel Ojeda                         && ty.path.leading_colon.is_none()
334808c999fSMiguel Ojeda                         && ty.path.segments.len() == 1
335808c999fSMiguel Ojeda                         && match &ty.path.segments[0].arguments {
336808c999fSMiguel Ojeda                             PathArguments::None | PathArguments::AngleBracketed(_) => true,
337808c999fSMiguel Ojeda                             PathArguments::Parenthesized(_) => false,
338808c999fSMiguel Ojeda                         } =>
339808c999fSMiguel Ojeda                 {
340808c999fSMiguel Ojeda                     if let Some(eq_token) = input.parse::<Option<Token![=]>>()? {
341808c999fSMiguel Ojeda                         let segment = ty.path.segments.pop().unwrap().into_value();
342808c999fSMiguel Ojeda                         let ident = segment.ident;
343808c999fSMiguel Ojeda                         let generics = match segment.arguments {
344808c999fSMiguel Ojeda                             PathArguments::None => None,
345808c999fSMiguel Ojeda                             PathArguments::AngleBracketed(arguments) => Some(arguments),
346808c999fSMiguel Ojeda                             PathArguments::Parenthesized(_) => unreachable!(),
347808c999fSMiguel Ojeda                         };
348808c999fSMiguel Ojeda                         return if input.peek(Lit) || input.peek(token::Brace) {
349808c999fSMiguel Ojeda                             Ok(GenericArgument::AssocConst(AssocConst {
350808c999fSMiguel Ojeda                                 ident,
351808c999fSMiguel Ojeda                                 generics,
352808c999fSMiguel Ojeda                                 eq_token,
353808c999fSMiguel Ojeda                                 value: const_argument(input)?,
354808c999fSMiguel Ojeda                             }))
355808c999fSMiguel Ojeda                         } else {
356808c999fSMiguel Ojeda                             Ok(GenericArgument::AssocType(AssocType {
357808c999fSMiguel Ojeda                                 ident,
358808c999fSMiguel Ojeda                                 generics,
359808c999fSMiguel Ojeda                                 eq_token,
360808c999fSMiguel Ojeda                                 ty: input.parse()?,
361808c999fSMiguel Ojeda                             }))
362808c999fSMiguel Ojeda                         };
363808c999fSMiguel Ojeda                     }
364808c999fSMiguel Ojeda 
365808c999fSMiguel Ojeda                     #[cfg(feature = "full")]
366808c999fSMiguel Ojeda                     if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
367808c999fSMiguel Ojeda                         let segment = ty.path.segments.pop().unwrap().into_value();
368808c999fSMiguel Ojeda                         return Ok(GenericArgument::Constraint(Constraint {
369808c999fSMiguel Ojeda                             ident: segment.ident,
370808c999fSMiguel Ojeda                             generics: match segment.arguments {
371808c999fSMiguel Ojeda                                 PathArguments::None => None,
372808c999fSMiguel Ojeda                                 PathArguments::AngleBracketed(arguments) => Some(arguments),
373808c999fSMiguel Ojeda                                 PathArguments::Parenthesized(_) => unreachable!(),
374808c999fSMiguel Ojeda                             },
375808c999fSMiguel Ojeda                             colon_token,
376808c999fSMiguel Ojeda                             bounds: {
377808c999fSMiguel Ojeda                                 let mut bounds = Punctuated::new();
378808c999fSMiguel Ojeda                                 loop {
379808c999fSMiguel Ojeda                                     if input.peek(Token![,]) || input.peek(Token![>]) {
380808c999fSMiguel Ojeda                                         break;
381808c999fSMiguel Ojeda                                     }
382808c999fSMiguel Ojeda                                     bounds.push_value({
383808c999fSMiguel Ojeda                                         let allow_precise_capture = false;
384808c999fSMiguel Ojeda                                         let allow_const = true;
385808c999fSMiguel Ojeda                                         TypeParamBound::parse_single(
386808c999fSMiguel Ojeda                                             input,
387808c999fSMiguel Ojeda                                             allow_precise_capture,
388808c999fSMiguel Ojeda                                             allow_const,
389808c999fSMiguel Ojeda                                         )?
390808c999fSMiguel Ojeda                                     });
391808c999fSMiguel Ojeda                                     if !input.peek(Token![+]) {
392808c999fSMiguel Ojeda                                         break;
393808c999fSMiguel Ojeda                                     }
394808c999fSMiguel Ojeda                                     let punct: Token![+] = input.parse()?;
395808c999fSMiguel Ojeda                                     bounds.push_punct(punct);
396808c999fSMiguel Ojeda                                 }
397808c999fSMiguel Ojeda                                 bounds
398808c999fSMiguel Ojeda                             },
399808c999fSMiguel Ojeda                         }));
400808c999fSMiguel Ojeda                     }
401808c999fSMiguel Ojeda 
402808c999fSMiguel Ojeda                     argument = Type::Path(ty);
403808c999fSMiguel Ojeda                 }
404808c999fSMiguel Ojeda                 _ => {}
405808c999fSMiguel Ojeda             }
406808c999fSMiguel Ojeda 
407808c999fSMiguel Ojeda             Ok(GenericArgument::Type(argument))
408808c999fSMiguel Ojeda         }
409808c999fSMiguel Ojeda     }
410808c999fSMiguel Ojeda 
const_argument(input: ParseStream) -> Result<Expr>411808c999fSMiguel Ojeda     pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
412808c999fSMiguel Ojeda         let lookahead = input.lookahead1();
413808c999fSMiguel Ojeda 
414808c999fSMiguel Ojeda         if input.peek(Lit) {
415808c999fSMiguel Ojeda             let lit = input.parse()?;
416808c999fSMiguel Ojeda             return Ok(Expr::Lit(lit));
417808c999fSMiguel Ojeda         }
418808c999fSMiguel Ojeda 
419808c999fSMiguel Ojeda         if input.peek(Ident) {
420808c999fSMiguel Ojeda             let ident: Ident = input.parse()?;
421808c999fSMiguel Ojeda             return Ok(Expr::Path(ExprPath {
422808c999fSMiguel Ojeda                 attrs: Vec::new(),
423808c999fSMiguel Ojeda                 qself: None,
424808c999fSMiguel Ojeda                 path: Path::from(ident),
425808c999fSMiguel Ojeda             }));
426808c999fSMiguel Ojeda         }
427808c999fSMiguel Ojeda 
428808c999fSMiguel Ojeda         if input.peek(token::Brace) {
429808c999fSMiguel Ojeda             #[cfg(feature = "full")]
430808c999fSMiguel Ojeda             {
431808c999fSMiguel Ojeda                 let block: ExprBlock = input.parse()?;
432808c999fSMiguel Ojeda                 return Ok(Expr::Block(block));
433808c999fSMiguel Ojeda             }
434808c999fSMiguel Ojeda 
435808c999fSMiguel Ojeda             #[cfg(not(feature = "full"))]
436808c999fSMiguel Ojeda             {
437808c999fSMiguel Ojeda                 let begin = input.fork();
438808c999fSMiguel Ojeda                 let content;
439808c999fSMiguel Ojeda                 braced!(content in input);
440808c999fSMiguel Ojeda                 content.parse::<Expr>()?;
441808c999fSMiguel Ojeda                 let verbatim = verbatim::between(&begin, input);
442808c999fSMiguel Ojeda                 return Ok(Expr::Verbatim(verbatim));
443808c999fSMiguel Ojeda             }
444808c999fSMiguel Ojeda         }
445808c999fSMiguel Ojeda 
446808c999fSMiguel Ojeda         Err(lookahead.error())
447808c999fSMiguel Ojeda     }
448808c999fSMiguel Ojeda 
449808c999fSMiguel Ojeda     impl AngleBracketedGenericArguments {
450808c999fSMiguel Ojeda         /// Parse `::<…>` with mandatory leading `::`.
451808c999fSMiguel Ojeda         ///
452808c999fSMiguel Ojeda         /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`
453808c999fSMiguel Ojeda         /// parses optional leading `::`.
454808c999fSMiguel Ojeda         #[cfg(feature = "full")]
455808c999fSMiguel Ojeda         #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
parse_turbofish(input: ParseStream) -> Result<Self>456808c999fSMiguel Ojeda         pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
457808c999fSMiguel Ojeda             let colon2_token: Token![::] = input.parse()?;
458808c999fSMiguel Ojeda             Self::do_parse(Some(colon2_token), input)
459808c999fSMiguel Ojeda         }
460808c999fSMiguel Ojeda 
do_parse( colon2_token: Option<Token![::]>, input: ParseStream, ) -> Result<Self>461808c999fSMiguel Ojeda         pub(crate) fn do_parse(
462808c999fSMiguel Ojeda             colon2_token: Option<Token![::]>,
463808c999fSMiguel Ojeda             input: ParseStream,
464808c999fSMiguel Ojeda         ) -> Result<Self> {
465808c999fSMiguel Ojeda             Ok(AngleBracketedGenericArguments {
466808c999fSMiguel Ojeda                 colon2_token,
467808c999fSMiguel Ojeda                 lt_token: input.parse()?,
468808c999fSMiguel Ojeda                 args: {
469808c999fSMiguel Ojeda                     let mut args = Punctuated::new();
470808c999fSMiguel Ojeda                     loop {
471808c999fSMiguel Ojeda                         if input.peek(Token![>]) {
472808c999fSMiguel Ojeda                             break;
473808c999fSMiguel Ojeda                         }
474808c999fSMiguel Ojeda                         let value: GenericArgument = input.parse()?;
475808c999fSMiguel Ojeda                         args.push_value(value);
476808c999fSMiguel Ojeda                         if input.peek(Token![>]) {
477808c999fSMiguel Ojeda                             break;
478808c999fSMiguel Ojeda                         }
479808c999fSMiguel Ojeda                         let punct: Token![,] = input.parse()?;
480808c999fSMiguel Ojeda                         args.push_punct(punct);
481808c999fSMiguel Ojeda                     }
482808c999fSMiguel Ojeda                     args
483808c999fSMiguel Ojeda                 },
484808c999fSMiguel Ojeda                 gt_token: input.parse()?,
485808c999fSMiguel Ojeda             })
486808c999fSMiguel Ojeda         }
487808c999fSMiguel Ojeda     }
488808c999fSMiguel Ojeda 
489808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
490808c999fSMiguel Ojeda     impl Parse for AngleBracketedGenericArguments {
parse(input: ParseStream) -> Result<Self>491808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
492808c999fSMiguel Ojeda             let colon2_token: Option<Token![::]> = input.parse()?;
493808c999fSMiguel Ojeda             Self::do_parse(colon2_token, input)
494808c999fSMiguel Ojeda         }
495808c999fSMiguel Ojeda     }
496808c999fSMiguel Ojeda 
497808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
498808c999fSMiguel Ojeda     impl Parse for ParenthesizedGenericArguments {
parse(input: ParseStream) -> Result<Self>499808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
500808c999fSMiguel Ojeda             let content;
501808c999fSMiguel Ojeda             Ok(ParenthesizedGenericArguments {
502808c999fSMiguel Ojeda                 paren_token: parenthesized!(content in input),
503808c999fSMiguel Ojeda                 inputs: content.parse_terminated(Type::parse, Token![,])?,
504808c999fSMiguel Ojeda                 output: input.call(ReturnType::without_plus)?,
505808c999fSMiguel Ojeda             })
506808c999fSMiguel Ojeda         }
507808c999fSMiguel Ojeda     }
508808c999fSMiguel Ojeda 
509808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
510808c999fSMiguel Ojeda     impl Parse for PathSegment {
parse(input: ParseStream) -> Result<Self>511808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
512808c999fSMiguel Ojeda             Self::parse_helper(input, false)
513808c999fSMiguel Ojeda         }
514808c999fSMiguel Ojeda     }
515808c999fSMiguel Ojeda 
516808c999fSMiguel Ojeda     impl PathSegment {
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>517808c999fSMiguel Ojeda         fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
518808c999fSMiguel Ojeda             if input.peek(Token![super])
519808c999fSMiguel Ojeda                 || input.peek(Token![self])
520808c999fSMiguel Ojeda                 || input.peek(Token![crate])
521808c999fSMiguel Ojeda                 || cfg!(feature = "full") && input.peek(Token![try])
522808c999fSMiguel Ojeda             {
523808c999fSMiguel Ojeda                 let ident = input.call(Ident::parse_any)?;
524808c999fSMiguel Ojeda                 return Ok(PathSegment::from(ident));
525808c999fSMiguel Ojeda             }
526808c999fSMiguel Ojeda 
527808c999fSMiguel Ojeda             let ident = if input.peek(Token![Self]) {
528808c999fSMiguel Ojeda                 input.call(Ident::parse_any)?
529808c999fSMiguel Ojeda             } else {
530808c999fSMiguel Ojeda                 input.parse()?
531808c999fSMiguel Ojeda             };
532808c999fSMiguel Ojeda 
533808c999fSMiguel Ojeda             if !expr_style
534808c999fSMiguel Ojeda                 && input.peek(Token![<])
535808c999fSMiguel Ojeda                 && !input.peek(Token![<=])
536808c999fSMiguel Ojeda                 && !input.peek(Token![<<=])
537808c999fSMiguel Ojeda                 || input.peek(Token![::]) && input.peek3(Token![<])
538808c999fSMiguel Ojeda             {
539808c999fSMiguel Ojeda                 Ok(PathSegment {
540808c999fSMiguel Ojeda                     ident,
541808c999fSMiguel Ojeda                     arguments: PathArguments::AngleBracketed(input.parse()?),
542808c999fSMiguel Ojeda                 })
543808c999fSMiguel Ojeda             } else {
544808c999fSMiguel Ojeda                 Ok(PathSegment::from(ident))
545808c999fSMiguel Ojeda             }
546808c999fSMiguel Ojeda         }
547808c999fSMiguel Ojeda     }
548808c999fSMiguel Ojeda 
549808c999fSMiguel Ojeda     impl Path {
550808c999fSMiguel Ojeda         /// Parse a `Path` containing no path arguments on any of its segments.
551808c999fSMiguel Ojeda         ///
552808c999fSMiguel Ojeda         /// # Example
553808c999fSMiguel Ojeda         ///
554808c999fSMiguel Ojeda         /// ```
555808c999fSMiguel Ojeda         /// use syn::{Path, Result, Token};
556808c999fSMiguel Ojeda         /// use syn::parse::{Parse, ParseStream};
557808c999fSMiguel Ojeda         ///
558808c999fSMiguel Ojeda         /// // A simplified single `use` statement like:
559808c999fSMiguel Ojeda         /// //
560808c999fSMiguel Ojeda         /// //     use std::collections::HashMap;
561808c999fSMiguel Ojeda         /// //
562808c999fSMiguel Ojeda         /// // Note that generic parameters are not allowed in a `use` statement
563808c999fSMiguel Ojeda         /// // so the following must not be accepted.
564808c999fSMiguel Ojeda         /// //
565808c999fSMiguel Ojeda         /// //     use a::<b>::c;
566808c999fSMiguel Ojeda         /// struct SingleUse {
567808c999fSMiguel Ojeda         ///     use_token: Token![use],
568808c999fSMiguel Ojeda         ///     path: Path,
569808c999fSMiguel Ojeda         /// }
570808c999fSMiguel Ojeda         ///
571808c999fSMiguel Ojeda         /// impl Parse for SingleUse {
572808c999fSMiguel Ojeda         ///     fn parse(input: ParseStream) -> Result<Self> {
573808c999fSMiguel Ojeda         ///         Ok(SingleUse {
574808c999fSMiguel Ojeda         ///             use_token: input.parse()?,
575808c999fSMiguel Ojeda         ///             path: input.call(Path::parse_mod_style)?,
576808c999fSMiguel Ojeda         ///         })
577808c999fSMiguel Ojeda         ///     }
578808c999fSMiguel Ojeda         /// }
579808c999fSMiguel Ojeda         /// ```
580808c999fSMiguel Ojeda         #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse_mod_style(input: ParseStream) -> Result<Self>581808c999fSMiguel Ojeda         pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
582808c999fSMiguel Ojeda             Ok(Path {
583808c999fSMiguel Ojeda                 leading_colon: input.parse()?,
584808c999fSMiguel Ojeda                 segments: {
585808c999fSMiguel Ojeda                     let mut segments = Punctuated::new();
586808c999fSMiguel Ojeda                     loop {
587808c999fSMiguel Ojeda                         if !input.peek(Ident)
588808c999fSMiguel Ojeda                             && !input.peek(Token![super])
589808c999fSMiguel Ojeda                             && !input.peek(Token![self])
590808c999fSMiguel Ojeda                             && !input.peek(Token![Self])
591808c999fSMiguel Ojeda                             && !input.peek(Token![crate])
592808c999fSMiguel Ojeda                         {
593808c999fSMiguel Ojeda                             break;
594808c999fSMiguel Ojeda                         }
595808c999fSMiguel Ojeda                         let ident = Ident::parse_any(input)?;
596808c999fSMiguel Ojeda                         segments.push_value(PathSegment::from(ident));
597808c999fSMiguel Ojeda                         if !input.peek(Token![::]) {
598808c999fSMiguel Ojeda                             break;
599808c999fSMiguel Ojeda                         }
600808c999fSMiguel Ojeda                         let punct = input.parse()?;
601808c999fSMiguel Ojeda                         segments.push_punct(punct);
602808c999fSMiguel Ojeda                     }
603808c999fSMiguel Ojeda                     if segments.is_empty() {
604808c999fSMiguel Ojeda                         return Err(input.parse::<Ident>().unwrap_err());
605808c999fSMiguel Ojeda                     } else if segments.trailing_punct() {
606808c999fSMiguel Ojeda                         return Err(input.error("expected path segment after `::`"));
607808c999fSMiguel Ojeda                     }
608808c999fSMiguel Ojeda                     segments
609808c999fSMiguel Ojeda                 },
610808c999fSMiguel Ojeda             })
611808c999fSMiguel Ojeda         }
612808c999fSMiguel Ojeda 
parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>613808c999fSMiguel Ojeda         pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
614808c999fSMiguel Ojeda             let mut path = Path {
615808c999fSMiguel Ojeda                 leading_colon: input.parse()?,
616808c999fSMiguel Ojeda                 segments: {
617808c999fSMiguel Ojeda                     let mut segments = Punctuated::new();
618808c999fSMiguel Ojeda                     let value = PathSegment::parse_helper(input, expr_style)?;
619808c999fSMiguel Ojeda                     segments.push_value(value);
620808c999fSMiguel Ojeda                     segments
621808c999fSMiguel Ojeda                 },
622808c999fSMiguel Ojeda             };
623808c999fSMiguel Ojeda             Path::parse_rest(input, &mut path, expr_style)?;
624808c999fSMiguel Ojeda             Ok(path)
625808c999fSMiguel Ojeda         }
626808c999fSMiguel Ojeda 
parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>627808c999fSMiguel Ojeda         pub(crate) fn parse_rest(
628808c999fSMiguel Ojeda             input: ParseStream,
629808c999fSMiguel Ojeda             path: &mut Self,
630808c999fSMiguel Ojeda             expr_style: bool,
631808c999fSMiguel Ojeda         ) -> Result<()> {
632808c999fSMiguel Ojeda             while input.peek(Token![::]) && !input.peek3(token::Paren) {
633808c999fSMiguel Ojeda                 let punct: Token![::] = input.parse()?;
634808c999fSMiguel Ojeda                 path.segments.push_punct(punct);
635808c999fSMiguel Ojeda                 let value = PathSegment::parse_helper(input, expr_style)?;
636808c999fSMiguel Ojeda                 path.segments.push_value(value);
637808c999fSMiguel Ojeda             }
638808c999fSMiguel Ojeda             Ok(())
639808c999fSMiguel Ojeda         }
640808c999fSMiguel Ojeda 
is_mod_style(&self) -> bool641808c999fSMiguel Ojeda         pub(crate) fn is_mod_style(&self) -> bool {
642808c999fSMiguel Ojeda             self.segments
643808c999fSMiguel Ojeda                 .iter()
644808c999fSMiguel Ojeda                 .all(|segment| segment.arguments.is_none())
645808c999fSMiguel Ojeda         }
646808c999fSMiguel Ojeda     }
647808c999fSMiguel Ojeda 
qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>648808c999fSMiguel Ojeda     pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
649808c999fSMiguel Ojeda         if input.peek(Token![<]) {
650808c999fSMiguel Ojeda             let lt_token: Token![<] = input.parse()?;
651808c999fSMiguel Ojeda             let this: Type = input.parse()?;
652808c999fSMiguel Ojeda             let path = if input.peek(Token![as]) {
653808c999fSMiguel Ojeda                 let as_token: Token![as] = input.parse()?;
654808c999fSMiguel Ojeda                 let path: Path = input.parse()?;
655808c999fSMiguel Ojeda                 Some((as_token, path))
656808c999fSMiguel Ojeda             } else {
657808c999fSMiguel Ojeda                 None
658808c999fSMiguel Ojeda             };
659808c999fSMiguel Ojeda             let gt_token: Token![>] = input.parse()?;
660808c999fSMiguel Ojeda             let colon2_token: Token![::] = input.parse()?;
661808c999fSMiguel Ojeda             let mut rest = Punctuated::new();
662808c999fSMiguel Ojeda             loop {
663808c999fSMiguel Ojeda                 let path = PathSegment::parse_helper(input, expr_style)?;
664808c999fSMiguel Ojeda                 rest.push_value(path);
665808c999fSMiguel Ojeda                 if !input.peek(Token![::]) {
666808c999fSMiguel Ojeda                     break;
667808c999fSMiguel Ojeda                 }
668808c999fSMiguel Ojeda                 let punct: Token![::] = input.parse()?;
669808c999fSMiguel Ojeda                 rest.push_punct(punct);
670808c999fSMiguel Ojeda             }
671808c999fSMiguel Ojeda             let (position, as_token, path) = match path {
672808c999fSMiguel Ojeda                 Some((as_token, mut path)) => {
673808c999fSMiguel Ojeda                     let pos = path.segments.len();
674808c999fSMiguel Ojeda                     path.segments.push_punct(colon2_token);
675808c999fSMiguel Ojeda                     path.segments.extend(rest.into_pairs());
676808c999fSMiguel Ojeda                     (pos, Some(as_token), path)
677808c999fSMiguel Ojeda                 }
678808c999fSMiguel Ojeda                 None => {
679808c999fSMiguel Ojeda                     let path = Path {
680808c999fSMiguel Ojeda                         leading_colon: Some(colon2_token),
681808c999fSMiguel Ojeda                         segments: rest,
682808c999fSMiguel Ojeda                     };
683808c999fSMiguel Ojeda                     (0, None, path)
684808c999fSMiguel Ojeda                 }
685808c999fSMiguel Ojeda             };
686808c999fSMiguel Ojeda             let qself = QSelf {
687808c999fSMiguel Ojeda                 lt_token,
688808c999fSMiguel Ojeda                 ty: Box::new(this),
689808c999fSMiguel Ojeda                 position,
690808c999fSMiguel Ojeda                 as_token,
691808c999fSMiguel Ojeda                 gt_token,
692808c999fSMiguel Ojeda             };
693808c999fSMiguel Ojeda             Ok((Some(qself), path))
694808c999fSMiguel Ojeda         } else {
695808c999fSMiguel Ojeda             let path = Path::parse_helper(input, expr_style)?;
696808c999fSMiguel Ojeda             Ok((None, path))
697808c999fSMiguel Ojeda         }
698808c999fSMiguel Ojeda     }
699808c999fSMiguel Ojeda }
700808c999fSMiguel Ojeda 
701808c999fSMiguel Ojeda #[cfg(feature = "printing")]
702808c999fSMiguel Ojeda pub(crate) mod printing {
703808c999fSMiguel Ojeda     use crate::generics;
704808c999fSMiguel Ojeda     use crate::path::{
705808c999fSMiguel Ojeda         AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
706808c999fSMiguel Ojeda         ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
707808c999fSMiguel Ojeda     };
708808c999fSMiguel Ojeda     use crate::print::TokensOrDefault;
709808c999fSMiguel Ojeda     #[cfg(feature = "parsing")]
710808c999fSMiguel Ojeda     use crate::spanned::Spanned;
711808c999fSMiguel Ojeda     #[cfg(feature = "parsing")]
712808c999fSMiguel Ojeda     use proc_macro2::Span;
713808c999fSMiguel Ojeda     use proc_macro2::TokenStream;
714808c999fSMiguel Ojeda     use quote::ToTokens;
715808c999fSMiguel Ojeda     use std::cmp;
716808c999fSMiguel Ojeda 
717808c999fSMiguel Ojeda     pub(crate) enum PathStyle {
718808c999fSMiguel Ojeda         Expr,
719808c999fSMiguel Ojeda         Mod,
720808c999fSMiguel Ojeda         AsWritten,
721808c999fSMiguel Ojeda     }
722808c999fSMiguel Ojeda 
723808c999fSMiguel Ojeda     impl Copy for PathStyle {}
724808c999fSMiguel Ojeda 
725808c999fSMiguel Ojeda     impl Clone for PathStyle {
clone(&self) -> Self726808c999fSMiguel Ojeda         fn clone(&self) -> Self {
727808c999fSMiguel Ojeda             *self
728808c999fSMiguel Ojeda         }
729808c999fSMiguel Ojeda     }
730808c999fSMiguel Ojeda 
731808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
732808c999fSMiguel Ojeda     impl ToTokens for Path {
to_tokens(&self, tokens: &mut TokenStream)733808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
734808c999fSMiguel Ojeda             print_path(tokens, self, PathStyle::AsWritten);
735808c999fSMiguel Ojeda         }
736808c999fSMiguel Ojeda     }
737808c999fSMiguel Ojeda 
print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle)738808c999fSMiguel Ojeda     pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
739808c999fSMiguel Ojeda         path.leading_colon.to_tokens(tokens);
740808c999fSMiguel Ojeda         for segment in path.segments.pairs() {
741808c999fSMiguel Ojeda             print_path_segment(tokens, segment.value(), style);
742808c999fSMiguel Ojeda             segment.punct().to_tokens(tokens);
743808c999fSMiguel Ojeda         }
744808c999fSMiguel Ojeda     }
745808c999fSMiguel Ojeda 
746808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
747808c999fSMiguel Ojeda     impl ToTokens for PathSegment {
to_tokens(&self, tokens: &mut TokenStream)748808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
749808c999fSMiguel Ojeda             print_path_segment(tokens, self, PathStyle::AsWritten);
750808c999fSMiguel Ojeda         }
751808c999fSMiguel Ojeda     }
752808c999fSMiguel Ojeda 
print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle)753808c999fSMiguel Ojeda     fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
754808c999fSMiguel Ojeda         segment.ident.to_tokens(tokens);
755808c999fSMiguel Ojeda         print_path_arguments(tokens, &segment.arguments, style);
756808c999fSMiguel Ojeda     }
757808c999fSMiguel Ojeda 
758808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
759808c999fSMiguel Ojeda     impl ToTokens for PathArguments {
to_tokens(&self, tokens: &mut TokenStream)760808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
761808c999fSMiguel Ojeda             print_path_arguments(tokens, self, PathStyle::AsWritten);
762808c999fSMiguel Ojeda         }
763808c999fSMiguel Ojeda     }
764808c999fSMiguel Ojeda 
print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle)765808c999fSMiguel Ojeda     fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
766808c999fSMiguel Ojeda         match arguments {
767808c999fSMiguel Ojeda             PathArguments::None => {}
768808c999fSMiguel Ojeda             PathArguments::AngleBracketed(arguments) => {
769808c999fSMiguel Ojeda                 print_angle_bracketed_generic_arguments(tokens, arguments, style);
770808c999fSMiguel Ojeda             }
771808c999fSMiguel Ojeda             PathArguments::Parenthesized(arguments) => {
772808c999fSMiguel Ojeda                 print_parenthesized_generic_arguments(tokens, arguments, style);
773808c999fSMiguel Ojeda             }
774808c999fSMiguel Ojeda         }
775808c999fSMiguel Ojeda     }
776808c999fSMiguel Ojeda 
777808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
778808c999fSMiguel Ojeda     impl ToTokens for GenericArgument {
779808c999fSMiguel Ojeda         #[allow(clippy::match_same_arms)]
to_tokens(&self, tokens: &mut TokenStream)780808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
781808c999fSMiguel Ojeda             match self {
782808c999fSMiguel Ojeda                 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
783808c999fSMiguel Ojeda                 GenericArgument::Type(ty) => ty.to_tokens(tokens),
784808c999fSMiguel Ojeda                 GenericArgument::Const(expr) => {
785808c999fSMiguel Ojeda                     generics::printing::print_const_argument(expr, tokens);
786808c999fSMiguel Ojeda                 }
787808c999fSMiguel Ojeda                 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
788808c999fSMiguel Ojeda                 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
789808c999fSMiguel Ojeda                 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
790808c999fSMiguel Ojeda             }
791808c999fSMiguel Ojeda         }
792808c999fSMiguel Ojeda     }
793808c999fSMiguel Ojeda 
794808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
795808c999fSMiguel Ojeda     impl ToTokens for AngleBracketedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)796808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
797808c999fSMiguel Ojeda             print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
798808c999fSMiguel Ojeda         }
799808c999fSMiguel Ojeda     }
800808c999fSMiguel Ojeda 
print_angle_bracketed_generic_arguments( tokens: &mut TokenStream, arguments: &AngleBracketedGenericArguments, style: PathStyle, )801808c999fSMiguel Ojeda     pub(crate) fn print_angle_bracketed_generic_arguments(
802808c999fSMiguel Ojeda         tokens: &mut TokenStream,
803808c999fSMiguel Ojeda         arguments: &AngleBracketedGenericArguments,
804808c999fSMiguel Ojeda         style: PathStyle,
805808c999fSMiguel Ojeda     ) {
806808c999fSMiguel Ojeda         if let PathStyle::Mod = style {
807808c999fSMiguel Ojeda             return;
808808c999fSMiguel Ojeda         }
809808c999fSMiguel Ojeda 
810808c999fSMiguel Ojeda         conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
811808c999fSMiguel Ojeda         arguments.lt_token.to_tokens(tokens);
812808c999fSMiguel Ojeda 
813808c999fSMiguel Ojeda         // Print lifetimes before types/consts/bindings, regardless of their
814808c999fSMiguel Ojeda         // order in args.
815808c999fSMiguel Ojeda         let mut trailing_or_empty = true;
816808c999fSMiguel Ojeda         for param in arguments.args.pairs() {
817808c999fSMiguel Ojeda             match param.value() {
818808c999fSMiguel Ojeda                 GenericArgument::Lifetime(_) => {
819808c999fSMiguel Ojeda                     param.to_tokens(tokens);
820808c999fSMiguel Ojeda                     trailing_or_empty = param.punct().is_some();
821808c999fSMiguel Ojeda                 }
822808c999fSMiguel Ojeda                 GenericArgument::Type(_)
823808c999fSMiguel Ojeda                 | GenericArgument::Const(_)
824808c999fSMiguel Ojeda                 | GenericArgument::AssocType(_)
825808c999fSMiguel Ojeda                 | GenericArgument::AssocConst(_)
826808c999fSMiguel Ojeda                 | GenericArgument::Constraint(_) => {}
827808c999fSMiguel Ojeda             }
828808c999fSMiguel Ojeda         }
829808c999fSMiguel Ojeda         for param in arguments.args.pairs() {
830808c999fSMiguel Ojeda             match param.value() {
831808c999fSMiguel Ojeda                 GenericArgument::Type(_)
832808c999fSMiguel Ojeda                 | GenericArgument::Const(_)
833808c999fSMiguel Ojeda                 | GenericArgument::AssocType(_)
834808c999fSMiguel Ojeda                 | GenericArgument::AssocConst(_)
835808c999fSMiguel Ojeda                 | GenericArgument::Constraint(_) => {
836808c999fSMiguel Ojeda                     if !trailing_or_empty {
837808c999fSMiguel Ojeda                         <Token![,]>::default().to_tokens(tokens);
838808c999fSMiguel Ojeda                     }
839808c999fSMiguel Ojeda                     param.to_tokens(tokens);
840808c999fSMiguel Ojeda                     trailing_or_empty = param.punct().is_some();
841808c999fSMiguel Ojeda                 }
842808c999fSMiguel Ojeda                 GenericArgument::Lifetime(_) => {}
843808c999fSMiguel Ojeda             }
844808c999fSMiguel Ojeda         }
845808c999fSMiguel Ojeda 
846808c999fSMiguel Ojeda         arguments.gt_token.to_tokens(tokens);
847808c999fSMiguel Ojeda     }
848808c999fSMiguel Ojeda 
849808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
850808c999fSMiguel Ojeda     impl ToTokens for AssocType {
to_tokens(&self, tokens: &mut TokenStream)851808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
852808c999fSMiguel Ojeda             self.ident.to_tokens(tokens);
853808c999fSMiguel Ojeda             self.generics.to_tokens(tokens);
854808c999fSMiguel Ojeda             self.eq_token.to_tokens(tokens);
855808c999fSMiguel Ojeda             self.ty.to_tokens(tokens);
856808c999fSMiguel Ojeda         }
857808c999fSMiguel Ojeda     }
858808c999fSMiguel Ojeda 
859808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
860808c999fSMiguel Ojeda     impl ToTokens for AssocConst {
to_tokens(&self, tokens: &mut TokenStream)861808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
862808c999fSMiguel Ojeda             self.ident.to_tokens(tokens);
863808c999fSMiguel Ojeda             self.generics.to_tokens(tokens);
864808c999fSMiguel Ojeda             self.eq_token.to_tokens(tokens);
865808c999fSMiguel Ojeda             generics::printing::print_const_argument(&self.value, tokens);
866808c999fSMiguel Ojeda         }
867808c999fSMiguel Ojeda     }
868808c999fSMiguel Ojeda 
869808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
870808c999fSMiguel Ojeda     impl ToTokens for Constraint {
to_tokens(&self, tokens: &mut TokenStream)871808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
872808c999fSMiguel Ojeda             self.ident.to_tokens(tokens);
873808c999fSMiguel Ojeda             self.generics.to_tokens(tokens);
874808c999fSMiguel Ojeda             self.colon_token.to_tokens(tokens);
875808c999fSMiguel Ojeda             self.bounds.to_tokens(tokens);
876808c999fSMiguel Ojeda         }
877808c999fSMiguel Ojeda     }
878808c999fSMiguel Ojeda 
879808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
880808c999fSMiguel Ojeda     impl ToTokens for ParenthesizedGenericArguments {
to_tokens(&self, tokens: &mut TokenStream)881808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
882808c999fSMiguel Ojeda             print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
883808c999fSMiguel Ojeda         }
884808c999fSMiguel Ojeda     }
885808c999fSMiguel Ojeda 
print_parenthesized_generic_arguments( tokens: &mut TokenStream, arguments: &ParenthesizedGenericArguments, style: PathStyle, )886808c999fSMiguel Ojeda     fn print_parenthesized_generic_arguments(
887808c999fSMiguel Ojeda         tokens: &mut TokenStream,
888808c999fSMiguel Ojeda         arguments: &ParenthesizedGenericArguments,
889808c999fSMiguel Ojeda         style: PathStyle,
890808c999fSMiguel Ojeda     ) {
891808c999fSMiguel Ojeda         if let PathStyle::Mod = style {
892808c999fSMiguel Ojeda             return;
893808c999fSMiguel Ojeda         }
894808c999fSMiguel Ojeda 
895808c999fSMiguel Ojeda         conditionally_print_turbofish(tokens, &None, style);
896808c999fSMiguel Ojeda         arguments.paren_token.surround(tokens, |tokens| {
897808c999fSMiguel Ojeda             arguments.inputs.to_tokens(tokens);
898808c999fSMiguel Ojeda         });
899808c999fSMiguel Ojeda         arguments.output.to_tokens(tokens);
900808c999fSMiguel Ojeda     }
901808c999fSMiguel Ojeda 
print_qpath( tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path, style: PathStyle, )902808c999fSMiguel Ojeda     pub(crate) fn print_qpath(
903808c999fSMiguel Ojeda         tokens: &mut TokenStream,
904808c999fSMiguel Ojeda         qself: &Option<QSelf>,
905808c999fSMiguel Ojeda         path: &Path,
906808c999fSMiguel Ojeda         style: PathStyle,
907808c999fSMiguel Ojeda     ) {
908808c999fSMiguel Ojeda         let qself = match qself {
909808c999fSMiguel Ojeda             Some(qself) => qself,
910808c999fSMiguel Ojeda             None => {
911808c999fSMiguel Ojeda                 print_path(tokens, path, style);
912808c999fSMiguel Ojeda                 return;
913808c999fSMiguel Ojeda             }
914808c999fSMiguel Ojeda         };
915808c999fSMiguel Ojeda         qself.lt_token.to_tokens(tokens);
916808c999fSMiguel Ojeda         qself.ty.to_tokens(tokens);
917808c999fSMiguel Ojeda 
918808c999fSMiguel Ojeda         let pos = cmp::min(qself.position, path.segments.len());
919808c999fSMiguel Ojeda         let mut segments = path.segments.pairs();
920808c999fSMiguel Ojeda         if pos > 0 {
921808c999fSMiguel Ojeda             TokensOrDefault(&qself.as_token).to_tokens(tokens);
922808c999fSMiguel Ojeda             path.leading_colon.to_tokens(tokens);
923808c999fSMiguel Ojeda             for (i, segment) in segments.by_ref().take(pos).enumerate() {
924808c999fSMiguel Ojeda                 print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
925808c999fSMiguel Ojeda                 if i + 1 == pos {
926808c999fSMiguel Ojeda                     qself.gt_token.to_tokens(tokens);
927808c999fSMiguel Ojeda                 }
928808c999fSMiguel Ojeda                 segment.punct().to_tokens(tokens);
929808c999fSMiguel Ojeda             }
930808c999fSMiguel Ojeda         } else {
931808c999fSMiguel Ojeda             qself.gt_token.to_tokens(tokens);
932808c999fSMiguel Ojeda             path.leading_colon.to_tokens(tokens);
933808c999fSMiguel Ojeda         }
934808c999fSMiguel Ojeda         for segment in segments {
935808c999fSMiguel Ojeda             print_path_segment(tokens, segment.value(), style);
936808c999fSMiguel Ojeda             segment.punct().to_tokens(tokens);
937808c999fSMiguel Ojeda         }
938808c999fSMiguel Ojeda     }
939808c999fSMiguel Ojeda 
conditionally_print_turbofish( tokens: &mut TokenStream, colon2_token: &Option<Token![::]>, style: PathStyle, )940808c999fSMiguel Ojeda     fn conditionally_print_turbofish(
941808c999fSMiguel Ojeda         tokens: &mut TokenStream,
942808c999fSMiguel Ojeda         colon2_token: &Option<Token![::]>,
943808c999fSMiguel Ojeda         style: PathStyle,
944808c999fSMiguel Ojeda     ) {
945808c999fSMiguel Ojeda         match style {
946808c999fSMiguel Ojeda             PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
947808c999fSMiguel Ojeda             PathStyle::Mod => unreachable!(),
948808c999fSMiguel Ojeda             PathStyle::AsWritten => colon2_token.to_tokens(tokens),
949808c999fSMiguel Ojeda         }
950808c999fSMiguel Ojeda     }
951808c999fSMiguel Ojeda 
952808c999fSMiguel Ojeda     #[cfg(feature = "parsing")]
953808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
954808c999fSMiguel Ojeda     impl Spanned for QSelf {
span(&self) -> Span955808c999fSMiguel Ojeda         fn span(&self) -> Span {
956808c999fSMiguel Ojeda             struct QSelfDelimiters<'a>(&'a QSelf);
957808c999fSMiguel Ojeda 
958808c999fSMiguel Ojeda             impl<'a> ToTokens for QSelfDelimiters<'a> {
959808c999fSMiguel Ojeda                 fn to_tokens(&self, tokens: &mut TokenStream) {
960808c999fSMiguel Ojeda                     self.0.lt_token.to_tokens(tokens);
961808c999fSMiguel Ojeda                     self.0.gt_token.to_tokens(tokens);
962808c999fSMiguel Ojeda                 }
963808c999fSMiguel Ojeda             }
964808c999fSMiguel Ojeda 
965808c999fSMiguel Ojeda             QSelfDelimiters(self).span()
966808c999fSMiguel Ojeda         }
967808c999fSMiguel Ojeda     }
968808c999fSMiguel Ojeda }
969