blob: 7c1f78d15bbf3fd0b775a0b37bf9bb3d92df6acc [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnay056de302018-01-05 14:29:05 -08009use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -070010use punctuated::Punctuated;
David Tolnay056de302018-01-05 14:29:05 -080011
12ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080013 /// A path at which a named item is exported: `std::collections::HashMap`.
David Tolnay461d98e2018-01-07 11:07:19 -080014 ///
15 /// *This type is available if Syn is built with the `"derive"` or `"full"`
16 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080017 pub struct Path {
David Tolnay056de302018-01-05 14:29:05 -080018 pub leading_colon: Option<Token![::]>,
David Tolnay056de302018-01-05 14:29:05 -080019 pub segments: Punctuated<PathSegment, Token![::]>,
20 }
21}
22
David Tolnay056de302018-01-05 14:29:05 -080023impl<T> From<T> for Path
24where
25 T: Into<PathSegment>,
26{
27 fn from(segment: T) -> Self {
28 let mut path = Path {
29 leading_colon: None,
30 segments: Punctuated::new(),
31 };
David Tolnay56080682018-01-06 14:01:52 -080032 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080033 path
34 }
35}
36
37ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080038 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080039 ///
40 /// *This type is available if Syn is built with the `"derive"` or `"full"`
41 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080042 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080043 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080044 pub arguments: PathArguments,
45 }
46}
47
48impl<T> From<T> for PathSegment
49where
50 T: Into<Ident>,
51{
52 fn from(ident: T) -> Self {
53 PathSegment {
54 ident: ident.into(),
55 arguments: PathArguments::None,
56 }
57 }
58}
59
60ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080061 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -080062 ///
63 /// *This type is available if Syn is built with the `"derive"` or `"full"`
64 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -080065 ///
66 /// ## Angle bracketed
67 ///
68 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
69 ///
70 /// ## Parenthesized
71 ///
72 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -080073 pub enum PathArguments {
74 None,
David Tolnaye826d812018-01-06 23:59:39 -080075 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -080076 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -080077 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -080078 Parenthesized(ParenthesizedGenericArguments),
79 }
80}
81
82impl Default for PathArguments {
83 fn default() -> Self {
84 PathArguments::None
85 }
86}
87
88impl PathArguments {
89 pub fn is_empty(&self) -> bool {
90 match *self {
91 PathArguments::None => true,
92 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
93 PathArguments::Parenthesized(_) => false,
94 }
95 }
David Tolnaya2d17062018-11-10 14:14:23 -080096
97 fn is_none(&self) -> bool {
98 match *self {
99 PathArguments::None => true,
100 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
101 }
102 }
David Tolnay056de302018-01-05 14:29:05 -0800103}
104
105ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -0800106 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -0800107 ///
108 /// *This type is available if Syn is built with the `"derive"` or `"full"`
109 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800110 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800111 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800112 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800113 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800114 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800115 /// A binding (equality constraint) on an associated type: the `Item =
116 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800117 Binding(Binding),
David Tolnay9d0882a2018-09-01 19:49:14 -0700118 /// An associated type bound: `Iterator<Item: Display>`.
119 Constraint(Constraint),
David Tolnaye826d812018-01-06 23:59:39 -0800120 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800121 ///
122 /// NOTE: Identity expressions are represented as Type arguments, as
123 /// they are indistinguishable syntactically.
124 Const(Expr),
125 }
126}
127
128ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800129 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
130 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800131 ///
132 /// *This type is available if Syn is built with the `"derive"` or `"full"`
133 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800134 pub struct AngleBracketedGenericArguments {
135 pub colon2_token: Option<Token![::]>,
136 pub lt_token: Token![<],
137 pub args: Punctuated<GenericArgument, Token![,]>,
138 pub gt_token: Token![>],
139 }
140}
141
142ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800143 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800144 ///
145 /// *This type is available if Syn is built with the `"derive"` or `"full"`
146 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800147 pub struct Binding {
148 pub ident: Ident,
149 pub eq_token: Token![=],
150 pub ty: Type,
151 }
152}
153
154ast_struct! {
David Tolnay9d0882a2018-09-01 19:49:14 -0700155 /// An associated type bound: `Iterator<Item: Display>`.
156 ///
157 /// *This type is available if Syn is built with the `"derive"` or `"full"`
158 /// feature.*
159 pub struct Constraint {
160 pub ident: Ident,
161 pub colon_token: Token![:],
162 pub bounds: Punctuated<TypeParamBound, Token![+]>,
163 }
164}
165
166ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800167 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
168 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800169 ///
170 /// *This type is available if Syn is built with the `"derive"` or `"full"`
171 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800172 pub struct ParenthesizedGenericArguments {
173 pub paren_token: token::Paren,
174 /// `(A, B)`
175 pub inputs: Punctuated<Type, Token![,]>,
176 /// `C`
177 pub output: ReturnType,
178 }
179}
180
181ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800182 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800183 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800184 ///
185 /// The actual path, including the trait and the associated item, is stored
186 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800187 /// item qualified with this Self type.
188 ///
189 /// ```text
190 /// <Vec<T> as a::b::Trait>::AssociatedItem
191 /// ^~~~~~ ~~~~~~~~~~~~~~^
192 /// ty position = 3
193 ///
194 /// <Vec<T>>::AssociatedItem
195 /// ^~~~~~ ^
196 /// ty position = 0
197 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800198 ///
199 /// *This type is available if Syn is built with the `"derive"` or `"full"`
200 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800201 pub struct QSelf {
202 pub lt_token: Token![<],
203 pub ty: Box<Type>,
204 pub position: usize,
205 pub as_token: Option<Token![as]>,
206 pub gt_token: Token![>],
207 }
208}
209
210#[cfg(feature = "parsing")]
211pub mod parsing {
212 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700213
David Tolnay310b3262018-08-30 15:33:00 -0700214 #[cfg(feature = "full")]
215 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700216 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700217 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800218
David Tolnay4fb71232018-08-25 23:14:50 -0400219 impl Parse for Path {
220 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700221 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800222 }
223 }
224
David Tolnay4fb71232018-08-25 23:14:50 -0400225 impl Parse for GenericArgument {
226 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700227 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400228 return Ok(GenericArgument::Lifetime(input.parse()?));
229 }
David Tolnay056de302018-01-05 14:29:05 -0800230
David Tolnay4fb71232018-08-25 23:14:50 -0400231 if input.peek(Ident) && input.peek2(Token![=]) {
232 return Ok(GenericArgument::Binding(input.parse()?));
233 }
David Tolnay056de302018-01-05 14:29:05 -0800234
David Tolnay4fb71232018-08-25 23:14:50 -0400235 #[cfg(feature = "full")]
236 {
David Tolnay9d0882a2018-09-01 19:49:14 -0700237 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
238 return Ok(GenericArgument::Constraint(input.parse()?));
239 }
240
David Tolnay4fb71232018-08-25 23:14:50 -0400241 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700242 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400243 return Ok(GenericArgument::Const(Expr::Lit(lit)));
244 }
245
246 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700247 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400248 return Ok(GenericArgument::Const(Expr::Block(block)));
249 }
250 }
251
David Tolnay8db2d662018-08-30 17:40:59 -0700252 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800253 }
254 }
255
David Tolnay4fb71232018-08-25 23:14:50 -0400256 impl Parse for AngleBracketedGenericArguments {
257 fn parse(input: ParseStream) -> Result<Self> {
258 Ok(AngleBracketedGenericArguments {
259 colon2_token: input.parse()?,
260 lt_token: input.parse()?,
261 args: {
262 let mut args = Punctuated::new();
263 loop {
264 if input.peek(Token![>]) {
265 break;
266 }
267 let value = input.parse()?;
268 args.push_value(value);
269 if input.peek(Token![>]) {
270 break;
271 }
272 let punct = input.parse()?;
273 args.push_punct(punct);
274 }
275 args
276 },
277 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800278 })
David Tolnay056de302018-01-05 14:29:05 -0800279 }
280 }
281
David Tolnay4fb71232018-08-25 23:14:50 -0400282 impl Parse for ParenthesizedGenericArguments {
283 fn parse(input: ParseStream) -> Result<Self> {
284 let content;
285 Ok(ParenthesizedGenericArguments {
286 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700287 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400288 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800289 })
David Tolnay056de302018-01-05 14:29:05 -0800290 }
291 }
292
David Tolnay4fb71232018-08-25 23:14:50 -0400293 impl Parse for PathSegment {
294 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700295 Self::parse_helper(input, false)
296 }
297 }
298
299 impl PathSegment {
300 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400301 if input.peek(Token![super])
302 || input.peek(Token![self])
303 || input.peek(Token![Self])
304 || input.peek(Token![crate])
305 || input.peek(Token![extern])
306 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700307 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400308 return Ok(PathSegment::from(ident));
309 }
310
311 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700312 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400313 || input.peek(Token![::]) && input.peek3(Token![<])
314 {
315 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800316 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400317 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800318 })
David Tolnay4fb71232018-08-25 23:14:50 -0400319 } else {
320 Ok(PathSegment::from(ident))
321 }
David Tolnay056de302018-01-05 14:29:05 -0800322 }
323 }
324
David Tolnay4fb71232018-08-25 23:14:50 -0400325 impl Parse for Binding {
326 fn parse(input: ParseStream) -> Result<Self> {
327 Ok(Binding {
328 ident: input.parse()?,
329 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400330 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800331 })
David Tolnay056de302018-01-05 14:29:05 -0800332 }
333 }
334
David Tolnay9d0882a2018-09-01 19:49:14 -0700335 #[cfg(feature = "full")]
336 impl Parse for Constraint {
337 fn parse(input: ParseStream) -> Result<Self> {
338 Ok(Constraint {
339 ident: input.parse()?,
340 colon_token: input.parse()?,
341 bounds: {
342 let mut bounds = Punctuated::new();
343 loop {
344 if input.peek(Token![,]) || input.peek(Token![>]) {
345 break;
346 }
347 let value = input.parse()?;
348 bounds.push_value(value);
349 if !input.peek(Token![+]) {
350 break;
351 }
352 let punct = input.parse()?;
353 bounds.push_punct(punct);
354 }
355 bounds
356 },
357 })
358 }
359 }
360
David Tolnay056de302018-01-05 14:29:05 -0800361 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700362 /// Parse a `Path` containing no path arguments on any of its segments.
363 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700364 /// *This function is available if Syn is built with the `"parsing"`
365 /// feature.*
366 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700367 /// # Example
368 ///
369 /// ```
David Tolnaya1c98072018-09-06 08:58:10 -0700370 /// #[macro_use]
371 /// extern crate syn;
372 ///
373 /// use syn::Path;
David Tolnaybbbd5302018-09-01 16:00:42 -0700374 /// use syn::parse::{Parse, ParseStream, Result};
375 ///
376 /// // A simplified single `use` statement like:
377 /// //
378 /// // use std::collections::HashMap;
379 /// //
380 /// // Note that generic parameters are not allowed in a `use` statement
381 /// // so the following must not be accepted.
382 /// //
383 /// // use a::<b>::c;
384 /// struct SingleUse {
385 /// use_token: Token![use],
386 /// path: Path,
387 /// }
388 ///
389 /// impl Parse for SingleUse {
390 /// fn parse(input: ParseStream) -> Result<Self> {
391 /// Ok(SingleUse {
392 /// use_token: input.parse()?,
393 /// path: input.call(Path::parse_mod_style)?,
394 /// })
395 /// }
396 /// }
397 /// #
398 /// # fn main() {}
399 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400400 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
401 Ok(Path {
402 leading_colon: input.parse()?,
403 segments: {
404 let mut segments = Punctuated::new();
405 loop {
406 if !input.peek(Ident)
407 && !input.peek(Token![super])
408 && !input.peek(Token![self])
409 && !input.peek(Token![Self])
410 && !input.peek(Token![crate])
411 && !input.peek(Token![extern])
412 {
413 break;
414 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700415 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400416 segments.push_value(PathSegment::from(ident));
417 if !input.peek(Token![::]) {
418 break;
419 }
420 let punct = input.parse()?;
421 segments.push_punct(punct);
422 }
423 if segments.is_empty() {
424 return Err(input.error("expected path"));
425 } else if segments.trailing_punct() {
426 return Err(input.error("expected path segment"));
427 }
428 segments
429 },
430 })
431 }
432
David Tolnaya2d17062018-11-10 14:14:23 -0800433 /// Determines whether this is a path of length 1 equal to the given
434 /// ident.
435 ///
436 /// For them to compare equal, it must be the case that:
437 ///
438 /// - the path has no leading colon,
439 /// - the number of path segments is 1,
440 /// - the first path segment has no angle bracketed or parenthesized
441 /// path arguments
442 /// - and the ident of the first path segment is equal to the given one.
443 pub fn is_ident<I>(&self, ident: I) -> bool
444 where
445 Ident: PartialEq<I>,
446 {
447 self.leading_colon.is_none()
448 && self.segments.len() == 1
449 && self.segments[0].arguments.is_none()
450 && self.segments[0].ident == ident
451 }
452
David Tolnay60291082018-08-28 09:54:49 -0700453 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
454 if input.peek(Token![dyn]) {
455 return Err(input.error("expected path"));
456 }
457
458 Ok(Path {
459 leading_colon: input.parse()?,
460 segments: {
461 let mut segments = Punctuated::new();
462 let value = PathSegment::parse_helper(input, expr_style)?;
463 segments.push_value(value);
464 while input.peek(Token![::]) {
465 let punct: Token![::] = input.parse()?;
466 segments.push_punct(punct);
467 let value = PathSegment::parse_helper(input, expr_style)?;
468 segments.push_value(value);
469 }
470 segments
471 },
472 })
473 }
David Tolnay056de302018-01-05 14:29:05 -0800474 }
475
David Tolnay60291082018-08-28 09:54:49 -0700476 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
477 if input.peek(Token![<]) {
478 let lt_token: Token![<] = input.parse()?;
479 let this: Type = input.parse()?;
480 let path = if input.peek(Token![as]) {
481 let as_token: Token![as] = input.parse()?;
482 let path: Path = input.parse()?;
483 Some((as_token, path))
484 } else {
485 None
486 };
487 let gt_token: Token![>] = input.parse()?;
488 let colon2_token: Token![::] = input.parse()?;
489 let mut rest = Punctuated::new();
490 loop {
491 let path = PathSegment::parse_helper(input, expr_style)?;
492 rest.push_value(path);
493 if !input.peek(Token![::]) {
494 break;
495 }
496 let punct: Token![::] = input.parse()?;
497 rest.push_punct(punct);
498 }
499 let (position, as_token, path) = match path {
500 Some((as_token, mut path)) => {
501 let pos = path.segments.len();
502 path.segments.push_punct(colon2_token);
503 path.segments.extend(rest.into_pairs());
504 (pos, Some(as_token), path)
505 }
506 None => {
507 let path = Path {
508 leading_colon: Some(colon2_token),
509 segments: rest,
510 };
511 (0, None, path)
512 }
513 };
514 let qself = QSelf {
515 lt_token: lt_token,
516 ty: Box::new(this),
517 position: position,
518 as_token: as_token,
519 gt_token: gt_token,
520 };
521 Ok((Some(qself), path))
522 } else {
523 let path = Path::parse_helper(input, expr_style)?;
524 Ok((None, path))
525 }
526 }
David Tolnay056de302018-01-05 14:29:05 -0800527}
528
529#[cfg(feature = "printing")]
530mod printing {
531 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700532
Alex Crichtona74a1c82018-05-16 10:20:44 -0700533 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700534 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800535
David Tolnay64023912018-08-31 09:51:12 -0700536 use print::TokensOrDefault;
537
David Tolnay056de302018-01-05 14:29:05 -0800538 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700539 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800540 self.leading_colon.to_tokens(tokens);
541 self.segments.to_tokens(tokens);
542 }
543 }
544
545 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700546 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800547 self.ident.to_tokens(tokens);
548 self.arguments.to_tokens(tokens);
549 }
550 }
551
552 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700553 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800554 match *self {
555 PathArguments::None => {}
556 PathArguments::AngleBracketed(ref arguments) => {
557 arguments.to_tokens(tokens);
558 }
559 PathArguments::Parenthesized(ref arguments) => {
560 arguments.to_tokens(tokens);
561 }
562 }
563 }
564 }
565
566 impl ToTokens for GenericArgument {
567 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700568 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800569 match *self {
570 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
571 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
572 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
David Tolnay9d0882a2018-09-01 19:49:14 -0700573 GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens),
David Tolnay056de302018-01-05 14:29:05 -0800574 GenericArgument::Const(ref e) => match *e {
575 Expr::Lit(_) => e.to_tokens(tokens),
576
577 // NOTE: We should probably support parsing blocks with only
578 // expressions in them without the full feature for const
579 // generics.
580 #[cfg(feature = "full")]
581 Expr::Block(_) => e.to_tokens(tokens),
582
583 // ERROR CORRECTION: Add braces to make sure that the
584 // generated code is valid.
585 _ => token::Brace::default().surround(tokens, |tokens| {
586 e.to_tokens(tokens);
587 }),
588 },
589 }
590 }
591 }
592
593 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700594 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800595 self.colon2_token.to_tokens(tokens);
596 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800597
598 // Print lifetimes before types and consts, all before bindings,
599 // regardless of their order in self.args.
600 //
601 // TODO: ordering rules for const arguments vs type arguments have
602 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
603 let mut trailing_or_empty = true;
604 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700605 match **param.value() {
606 GenericArgument::Lifetime(_) => {
607 param.to_tokens(tokens);
608 trailing_or_empty = param.punct().is_some();
609 }
610 GenericArgument::Type(_)
611 | GenericArgument::Binding(_)
612 | GenericArgument::Constraint(_)
613 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800614 }
615 }
616 for param in self.args.pairs() {
617 match **param.value() {
618 GenericArgument::Type(_) | GenericArgument::Const(_) => {
619 if !trailing_or_empty {
620 <Token![,]>::default().to_tokens(tokens);
621 }
622 param.to_tokens(tokens);
623 trailing_or_empty = param.punct().is_some();
624 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700625 GenericArgument::Lifetime(_)
626 | GenericArgument::Binding(_)
627 | GenericArgument::Constraint(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800628 }
629 }
630 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700631 match **param.value() {
632 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
633 if !trailing_or_empty {
634 <Token![,]>::default().to_tokens(tokens);
635 trailing_or_empty = true;
636 }
637 param.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800638 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700639 GenericArgument::Lifetime(_)
640 | GenericArgument::Type(_)
641 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800642 }
643 }
644
David Tolnay056de302018-01-05 14:29:05 -0800645 self.gt_token.to_tokens(tokens);
646 }
647 }
648
649 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700650 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800651 self.ident.to_tokens(tokens);
652 self.eq_token.to_tokens(tokens);
653 self.ty.to_tokens(tokens);
654 }
655 }
656
David Tolnay9d0882a2018-09-01 19:49:14 -0700657 impl ToTokens for Constraint {
658 fn to_tokens(&self, tokens: &mut TokenStream) {
659 self.ident.to_tokens(tokens);
660 self.colon_token.to_tokens(tokens);
661 self.bounds.to_tokens(tokens);
662 }
663 }
664
David Tolnay056de302018-01-05 14:29:05 -0800665 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700666 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800667 self.paren_token.surround(tokens, |tokens| {
668 self.inputs.to_tokens(tokens);
669 });
670 self.output.to_tokens(tokens);
671 }
672 }
David Tolnay05658502018-01-07 09:56:37 -0800673
David Tolnay12f3b6f2018-09-01 16:10:53 -0700674 impl private {
675 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
676 let qself = match *qself {
David Tolnay05658502018-01-07 09:56:37 -0800677 Some(ref qself) => qself,
David Tolnay12f3b6f2018-09-01 16:10:53 -0700678 None => {
679 path.to_tokens(tokens);
680 return;
681 }
David Tolnay05658502018-01-07 09:56:37 -0800682 };
683 qself.lt_token.to_tokens(tokens);
684 qself.ty.to_tokens(tokens);
685
David Tolnay12f3b6f2018-09-01 16:10:53 -0700686 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
687 path.segments.len() - 1
David Tolnay05658502018-01-07 09:56:37 -0800688 } else {
689 qself.position
690 };
David Tolnay12f3b6f2018-09-01 16:10:53 -0700691 let mut segments = path.segments.pairs();
David Tolnay05658502018-01-07 09:56:37 -0800692 if pos > 0 {
693 TokensOrDefault(&qself.as_token).to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700694 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800695 for (i, segment) in segments.by_ref().take(pos).enumerate() {
696 if i + 1 == pos {
697 segment.value().to_tokens(tokens);
698 qself.gt_token.to_tokens(tokens);
699 segment.punct().to_tokens(tokens);
700 } else {
701 segment.to_tokens(tokens);
702 }
703 }
704 } else {
705 qself.gt_token.to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700706 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800707 }
708 for segment in segments {
709 segment.to_tokens(tokens);
710 }
711 }
712 }
David Tolnay056de302018-01-05 14:29:05 -0800713}