blob: 10a043ec1e235fd336cc98629d66ad399228e25f [file] [log] [blame]
David Tolnay056de302018-01-05 14:29:05 -08001use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -07002use punctuated::Punctuated;
David Tolnay056de302018-01-05 14:29:05 -08003
4ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -08005 /// A path at which a named item is exported: `std::collections::HashMap`.
David Tolnay461d98e2018-01-07 11:07:19 -08006 ///
7 /// *This type is available if Syn is built with the `"derive"` or `"full"`
8 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -08009 pub struct Path {
David Tolnay056de302018-01-05 14:29:05 -080010 pub leading_colon: Option<Token![::]>,
David Tolnay056de302018-01-05 14:29:05 -080011 pub segments: Punctuated<PathSegment, Token![::]>,
12 }
13}
14
David Tolnay056de302018-01-05 14:29:05 -080015impl<T> From<T> for Path
16where
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 };
David Tolnay56080682018-01-06 14:01:52 -080024 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080025 path
26 }
27}
28
29ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080030 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080031 ///
32 /// *This type is available if Syn is built with the `"derive"` or `"full"`
33 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080034 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080035 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080036 pub arguments: PathArguments,
37 }
38}
39
40impl<T> From<T> for PathSegment
41where
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
52ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080053 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -080054 ///
55 /// *This type is available if Syn is built with the `"derive"` or `"full"`
56 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -080057 ///
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`.
David Tolnay056de302018-01-05 14:29:05 -080065 pub enum PathArguments {
66 None,
David Tolnaye826d812018-01-06 23:59:39 -080067 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -080068 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -080069 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -080070 Parenthesized(ParenthesizedGenericArguments),
71 }
72}
73
74impl Default for PathArguments {
75 fn default() -> Self {
76 PathArguments::None
77 }
78}
79
80impl PathArguments {
81 pub fn is_empty(&self) -> bool {
82 match *self {
83 PathArguments::None => true,
84 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
85 PathArguments::Parenthesized(_) => false,
86 }
87 }
David Tolnaya2d17062018-11-10 14:14:23 -080088
89 fn is_none(&self) -> bool {
90 match *self {
91 PathArguments::None => true,
92 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
93 }
94 }
David Tolnay056de302018-01-05 14:29:05 -080095}
96
97ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -080098 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -080099 ///
100 /// *This type is available if Syn is built with the `"derive"` or `"full"`
101 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800102 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800103 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800104 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800105 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800106 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800107 /// A binding (equality constraint) on an associated type: the `Item =
108 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800109 Binding(Binding),
David Tolnay9d0882a2018-09-01 19:49:14 -0700110 /// An associated type bound: `Iterator<Item: Display>`.
111 Constraint(Constraint),
David Tolnaye826d812018-01-06 23:59:39 -0800112 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800113 ///
114 /// NOTE: Identity expressions are represented as Type arguments, as
115 /// they are indistinguishable syntactically.
116 Const(Expr),
117 }
118}
119
120ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800121 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
122 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800123 ///
124 /// *This type is available if Syn is built with the `"derive"` or `"full"`
125 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800126 pub struct AngleBracketedGenericArguments {
127 pub colon2_token: Option<Token![::]>,
128 pub lt_token: Token![<],
129 pub args: Punctuated<GenericArgument, Token![,]>,
130 pub gt_token: Token![>],
131 }
132}
133
134ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800135 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800136 ///
137 /// *This type is available if Syn is built with the `"derive"` or `"full"`
138 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800139 pub struct Binding {
140 pub ident: Ident,
141 pub eq_token: Token![=],
142 pub ty: Type,
143 }
144}
145
146ast_struct! {
David Tolnay9d0882a2018-09-01 19:49:14 -0700147 /// An associated type bound: `Iterator<Item: Display>`.
148 ///
149 /// *This type is available if Syn is built with the `"derive"` or `"full"`
150 /// feature.*
151 pub struct Constraint {
152 pub ident: Ident,
153 pub colon_token: Token![:],
154 pub bounds: Punctuated<TypeParamBound, Token![+]>,
155 }
156}
157
158ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800159 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
160 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800161 ///
162 /// *This type is available if Syn is built with the `"derive"` or `"full"`
163 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800164 pub struct ParenthesizedGenericArguments {
165 pub paren_token: token::Paren,
166 /// `(A, B)`
167 pub inputs: Punctuated<Type, Token![,]>,
168 /// `C`
169 pub output: ReturnType,
170 }
171}
172
173ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800174 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800175 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800176 ///
177 /// The actual path, including the trait and the associated item, is stored
178 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800179 /// item qualified with this Self type.
180 ///
181 /// ```text
182 /// <Vec<T> as a::b::Trait>::AssociatedItem
183 /// ^~~~~~ ~~~~~~~~~~~~~~^
184 /// ty position = 3
185 ///
186 /// <Vec<T>>::AssociatedItem
187 /// ^~~~~~ ^
188 /// ty position = 0
189 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800190 ///
191 /// *This type is available if Syn is built with the `"derive"` or `"full"`
192 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800193 pub struct QSelf {
194 pub lt_token: Token![<],
195 pub ty: Box<Type>,
196 pub position: usize,
197 pub as_token: Option<Token![as]>,
198 pub gt_token: Token![>],
199 }
200}
201
202#[cfg(feature = "parsing")]
203pub mod parsing {
204 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700205
David Tolnay310b3262018-08-30 15:33:00 -0700206 #[cfg(feature = "full")]
207 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700208 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700209 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800210
David Tolnay4fb71232018-08-25 23:14:50 -0400211 impl Parse for Path {
212 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700213 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800214 }
215 }
216
David Tolnay4fb71232018-08-25 23:14:50 -0400217 impl Parse for GenericArgument {
218 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700219 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400220 return Ok(GenericArgument::Lifetime(input.parse()?));
221 }
David Tolnay056de302018-01-05 14:29:05 -0800222
David Tolnay4fb71232018-08-25 23:14:50 -0400223 if input.peek(Ident) && input.peek2(Token![=]) {
224 return Ok(GenericArgument::Binding(input.parse()?));
225 }
David Tolnay056de302018-01-05 14:29:05 -0800226
David Tolnay4fb71232018-08-25 23:14:50 -0400227 #[cfg(feature = "full")]
228 {
David Tolnay9d0882a2018-09-01 19:49:14 -0700229 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
230 return Ok(GenericArgument::Constraint(input.parse()?));
231 }
232
David Tolnay4fb71232018-08-25 23:14:50 -0400233 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700234 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400235 return Ok(GenericArgument::Const(Expr::Lit(lit)));
236 }
237
238 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700239 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400240 return Ok(GenericArgument::Const(Expr::Block(block)));
241 }
242 }
243
David Tolnay8db2d662018-08-30 17:40:59 -0700244 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800245 }
246 }
247
David Tolnay4fb71232018-08-25 23:14:50 -0400248 impl Parse for AngleBracketedGenericArguments {
249 fn parse(input: ParseStream) -> Result<Self> {
250 Ok(AngleBracketedGenericArguments {
251 colon2_token: input.parse()?,
252 lt_token: input.parse()?,
253 args: {
254 let mut args = Punctuated::new();
255 loop {
256 if input.peek(Token![>]) {
257 break;
258 }
259 let value = input.parse()?;
260 args.push_value(value);
261 if input.peek(Token![>]) {
262 break;
263 }
264 let punct = input.parse()?;
265 args.push_punct(punct);
266 }
267 args
268 },
269 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800270 })
David Tolnay056de302018-01-05 14:29:05 -0800271 }
272 }
273
David Tolnay4fb71232018-08-25 23:14:50 -0400274 impl Parse for ParenthesizedGenericArguments {
275 fn parse(input: ParseStream) -> Result<Self> {
276 let content;
277 Ok(ParenthesizedGenericArguments {
278 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700279 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400280 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800281 })
David Tolnay056de302018-01-05 14:29:05 -0800282 }
283 }
284
David Tolnay4fb71232018-08-25 23:14:50 -0400285 impl Parse for PathSegment {
286 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700287 Self::parse_helper(input, false)
288 }
289 }
290
291 impl PathSegment {
292 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400293 if input.peek(Token![super])
294 || input.peek(Token![self])
295 || input.peek(Token![Self])
296 || input.peek(Token![crate])
297 || input.peek(Token![extern])
298 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700299 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400300 return Ok(PathSegment::from(ident));
301 }
302
303 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700304 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400305 || input.peek(Token![::]) && input.peek3(Token![<])
306 {
307 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800308 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400309 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800310 })
David Tolnay4fb71232018-08-25 23:14:50 -0400311 } else {
312 Ok(PathSegment::from(ident))
313 }
David Tolnay056de302018-01-05 14:29:05 -0800314 }
315 }
316
David Tolnay4fb71232018-08-25 23:14:50 -0400317 impl Parse for Binding {
318 fn parse(input: ParseStream) -> Result<Self> {
319 Ok(Binding {
320 ident: input.parse()?,
321 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400322 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800323 })
David Tolnay056de302018-01-05 14:29:05 -0800324 }
325 }
326
David Tolnay9d0882a2018-09-01 19:49:14 -0700327 #[cfg(feature = "full")]
328 impl Parse for Constraint {
329 fn parse(input: ParseStream) -> Result<Self> {
330 Ok(Constraint {
331 ident: input.parse()?,
332 colon_token: input.parse()?,
333 bounds: {
334 let mut bounds = Punctuated::new();
335 loop {
336 if input.peek(Token![,]) || input.peek(Token![>]) {
337 break;
338 }
339 let value = input.parse()?;
340 bounds.push_value(value);
341 if !input.peek(Token![+]) {
342 break;
343 }
344 let punct = input.parse()?;
345 bounds.push_punct(punct);
346 }
347 bounds
348 },
349 })
350 }
351 }
352
David Tolnay056de302018-01-05 14:29:05 -0800353 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700354 /// Parse a `Path` containing no path arguments on any of its segments.
355 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700356 /// *This function is available if Syn is built with the `"parsing"`
357 /// feature.*
358 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700359 /// # Example
360 ///
David Tolnay95989db2019-01-01 15:05:57 -0500361 /// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -0500362 /// use syn::{Path, Result, Token};
David Tolnay67fea042018-11-24 14:50:20 -0800363 /// use syn::parse::{Parse, ParseStream};
David Tolnaybbbd5302018-09-01 16:00:42 -0700364 ///
365 /// // A simplified single `use` statement like:
366 /// //
367 /// // use std::collections::HashMap;
368 /// //
369 /// // Note that generic parameters are not allowed in a `use` statement
370 /// // so the following must not be accepted.
371 /// //
372 /// // use a::<b>::c;
373 /// struct SingleUse {
374 /// use_token: Token![use],
375 /// path: Path,
376 /// }
377 ///
378 /// impl Parse for SingleUse {
379 /// fn parse(input: ParseStream) -> Result<Self> {
380 /// Ok(SingleUse {
381 /// use_token: input.parse()?,
382 /// path: input.call(Path::parse_mod_style)?,
383 /// })
384 /// }
385 /// }
David Tolnaybbbd5302018-09-01 16:00:42 -0700386 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400387 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
388 Ok(Path {
389 leading_colon: input.parse()?,
390 segments: {
391 let mut segments = Punctuated::new();
392 loop {
393 if !input.peek(Ident)
394 && !input.peek(Token![super])
395 && !input.peek(Token![self])
396 && !input.peek(Token![Self])
397 && !input.peek(Token![crate])
398 && !input.peek(Token![extern])
399 {
400 break;
401 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700402 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400403 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
David Tolnaya2d17062018-11-10 14:14:23 -0800420 /// 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
429 /// - and the ident of the first path segment is equal to the given one.
430 pub fn is_ident<I>(&self, ident: I) -> bool
431 where
432 Ident: PartialEq<I>,
433 {
434 self.leading_colon.is_none()
435 && self.segments.len() == 1
436 && self.segments[0].arguments.is_none()
437 && self.segments[0].ident == ident
438 }
439
David Tolnay60291082018-08-28 09:54:49 -0700440 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
441 if input.peek(Token![dyn]) {
442 return Err(input.error("expected path"));
443 }
444
445 Ok(Path {
446 leading_colon: input.parse()?,
447 segments: {
448 let mut segments = Punctuated::new();
449 let value = PathSegment::parse_helper(input, expr_style)?;
450 segments.push_value(value);
451 while input.peek(Token![::]) {
452 let punct: Token![::] = input.parse()?;
453 segments.push_punct(punct);
454 let value = PathSegment::parse_helper(input, expr_style)?;
455 segments.push_value(value);
456 }
457 segments
458 },
459 })
460 }
David Tolnay056de302018-01-05 14:29:05 -0800461 }
462
David Tolnay60291082018-08-28 09:54:49 -0700463 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
464 if input.peek(Token![<]) {
465 let lt_token: Token![<] = input.parse()?;
466 let this: Type = input.parse()?;
467 let path = if input.peek(Token![as]) {
468 let as_token: Token![as] = input.parse()?;
469 let path: Path = input.parse()?;
470 Some((as_token, path))
471 } else {
472 None
473 };
474 let gt_token: Token![>] = input.parse()?;
475 let colon2_token: Token![::] = input.parse()?;
476 let mut rest = Punctuated::new();
477 loop {
478 let path = PathSegment::parse_helper(input, expr_style)?;
479 rest.push_value(path);
480 if !input.peek(Token![::]) {
481 break;
482 }
483 let punct: Token![::] = input.parse()?;
484 rest.push_punct(punct);
485 }
486 let (position, as_token, path) = match path {
487 Some((as_token, mut path)) => {
488 let pos = path.segments.len();
489 path.segments.push_punct(colon2_token);
490 path.segments.extend(rest.into_pairs());
491 (pos, Some(as_token), path)
492 }
493 None => {
494 let path = Path {
495 leading_colon: Some(colon2_token),
496 segments: rest,
497 };
498 (0, None, path)
499 }
500 };
501 let qself = QSelf {
502 lt_token: lt_token,
503 ty: Box::new(this),
504 position: position,
505 as_token: as_token,
506 gt_token: gt_token,
507 };
508 Ok((Some(qself), path))
509 } else {
510 let path = Path::parse_helper(input, expr_style)?;
511 Ok((None, path))
512 }
513 }
David Tolnay056de302018-01-05 14:29:05 -0800514}
515
516#[cfg(feature = "printing")]
517mod printing {
518 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700519
Alex Crichtona74a1c82018-05-16 10:20:44 -0700520 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700521 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800522
David Tolnay64023912018-08-31 09:51:12 -0700523 use print::TokensOrDefault;
524
David Tolnay056de302018-01-05 14:29:05 -0800525 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700526 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800527 self.leading_colon.to_tokens(tokens);
528 self.segments.to_tokens(tokens);
529 }
530 }
531
532 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700533 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800534 self.ident.to_tokens(tokens);
535 self.arguments.to_tokens(tokens);
536 }
537 }
538
539 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700540 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800541 match *self {
542 PathArguments::None => {}
543 PathArguments::AngleBracketed(ref arguments) => {
544 arguments.to_tokens(tokens);
545 }
546 PathArguments::Parenthesized(ref arguments) => {
547 arguments.to_tokens(tokens);
548 }
549 }
550 }
551 }
552
553 impl ToTokens for GenericArgument {
554 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700555 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800556 match *self {
557 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
558 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
559 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
David Tolnay9d0882a2018-09-01 19:49:14 -0700560 GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens),
David Tolnay056de302018-01-05 14:29:05 -0800561 GenericArgument::Const(ref e) => match *e {
562 Expr::Lit(_) => e.to_tokens(tokens),
563
564 // NOTE: We should probably support parsing blocks with only
565 // expressions in them without the full feature for const
566 // generics.
567 #[cfg(feature = "full")]
568 Expr::Block(_) => e.to_tokens(tokens),
569
570 // ERROR CORRECTION: Add braces to make sure that the
571 // generated code is valid.
572 _ => token::Brace::default().surround(tokens, |tokens| {
573 e.to_tokens(tokens);
574 }),
575 },
576 }
577 }
578 }
579
580 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700581 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800582 self.colon2_token.to_tokens(tokens);
583 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800584
585 // Print lifetimes before types and consts, all before bindings,
586 // regardless of their order in self.args.
587 //
588 // TODO: ordering rules for const arguments vs type arguments have
589 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
590 let mut trailing_or_empty = true;
591 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700592 match **param.value() {
593 GenericArgument::Lifetime(_) => {
594 param.to_tokens(tokens);
595 trailing_or_empty = param.punct().is_some();
596 }
597 GenericArgument::Type(_)
598 | GenericArgument::Binding(_)
599 | GenericArgument::Constraint(_)
600 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800601 }
602 }
603 for param in self.args.pairs() {
604 match **param.value() {
605 GenericArgument::Type(_) | GenericArgument::Const(_) => {
606 if !trailing_or_empty {
607 <Token![,]>::default().to_tokens(tokens);
608 }
609 param.to_tokens(tokens);
610 trailing_or_empty = param.punct().is_some();
611 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700612 GenericArgument::Lifetime(_)
613 | GenericArgument::Binding(_)
614 | GenericArgument::Constraint(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800615 }
616 }
617 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700618 match **param.value() {
619 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
620 if !trailing_or_empty {
621 <Token![,]>::default().to_tokens(tokens);
622 trailing_or_empty = true;
623 }
624 param.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800625 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700626 GenericArgument::Lifetime(_)
627 | GenericArgument::Type(_)
628 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800629 }
630 }
631
David Tolnay056de302018-01-05 14:29:05 -0800632 self.gt_token.to_tokens(tokens);
633 }
634 }
635
636 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700637 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800638 self.ident.to_tokens(tokens);
639 self.eq_token.to_tokens(tokens);
640 self.ty.to_tokens(tokens);
641 }
642 }
643
David Tolnay9d0882a2018-09-01 19:49:14 -0700644 impl ToTokens for Constraint {
645 fn to_tokens(&self, tokens: &mut TokenStream) {
646 self.ident.to_tokens(tokens);
647 self.colon_token.to_tokens(tokens);
648 self.bounds.to_tokens(tokens);
649 }
650 }
651
David Tolnay056de302018-01-05 14:29:05 -0800652 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700653 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800654 self.paren_token.surround(tokens, |tokens| {
655 self.inputs.to_tokens(tokens);
656 });
657 self.output.to_tokens(tokens);
658 }
659 }
David Tolnay05658502018-01-07 09:56:37 -0800660
David Tolnay12f3b6f2018-09-01 16:10:53 -0700661 impl private {
662 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
663 let qself = match *qself {
David Tolnay05658502018-01-07 09:56:37 -0800664 Some(ref qself) => qself,
David Tolnay12f3b6f2018-09-01 16:10:53 -0700665 None => {
666 path.to_tokens(tokens);
667 return;
668 }
David Tolnay05658502018-01-07 09:56:37 -0800669 };
670 qself.lt_token.to_tokens(tokens);
671 qself.ty.to_tokens(tokens);
672
David Tolnay12f3b6f2018-09-01 16:10:53 -0700673 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
674 path.segments.len() - 1
David Tolnay05658502018-01-07 09:56:37 -0800675 } else {
676 qself.position
677 };
David Tolnay12f3b6f2018-09-01 16:10:53 -0700678 let mut segments = path.segments.pairs();
David Tolnay05658502018-01-07 09:56:37 -0800679 if pos > 0 {
680 TokensOrDefault(&qself.as_token).to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700681 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800682 for (i, segment) in segments.by_ref().take(pos).enumerate() {
683 if i + 1 == pos {
684 segment.value().to_tokens(tokens);
685 qself.gt_token.to_tokens(tokens);
686 segment.punct().to_tokens(tokens);
687 } else {
688 segment.to_tokens(tokens);
689 }
690 }
691 } else {
692 qself.gt_token.to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700693 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800694 }
695 for segment in segments {
696 segment.to_tokens(tokens);
697 }
698 }
699 }
David Tolnay056de302018-01-05 14:29:05 -0800700}