blob: 301a06be6a30933678cfc60fba7795ff239eea04 [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 }
96}
97
98ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -080099 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -0800100 ///
101 /// *This type is available if Syn is built with the `"derive"` or `"full"`
102 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800103 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800104 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800105 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800106 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800107 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800108 /// A binding (equality constraint) on an associated type: the `Item =
109 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800110 Binding(Binding),
David Tolnay9d0882a2018-09-01 19:49:14 -0700111 /// An associated type bound: `Iterator<Item: Display>`.
112 Constraint(Constraint),
David Tolnaye826d812018-01-06 23:59:39 -0800113 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800114 ///
115 /// NOTE: Identity expressions are represented as Type arguments, as
116 /// they are indistinguishable syntactically.
117 Const(Expr),
118 }
119}
120
121ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800122 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
123 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800124 ///
125 /// *This type is available if Syn is built with the `"derive"` or `"full"`
126 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800127 pub struct AngleBracketedGenericArguments {
128 pub colon2_token: Option<Token![::]>,
129 pub lt_token: Token![<],
130 pub args: Punctuated<GenericArgument, Token![,]>,
131 pub gt_token: Token![>],
132 }
133}
134
135ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800136 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800137 ///
138 /// *This type is available if Syn is built with the `"derive"` or `"full"`
139 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800140 pub struct Binding {
141 pub ident: Ident,
142 pub eq_token: Token![=],
143 pub ty: Type,
144 }
145}
146
147ast_struct! {
David Tolnay9d0882a2018-09-01 19:49:14 -0700148 /// An associated type bound: `Iterator<Item: Display>`.
149 ///
150 /// *This type is available if Syn is built with the `"derive"` or `"full"`
151 /// feature.*
152 pub struct Constraint {
153 pub ident: Ident,
154 pub colon_token: Token![:],
155 pub bounds: Punctuated<TypeParamBound, Token![+]>,
156 }
157}
158
159ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800160 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
161 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800162 ///
163 /// *This type is available if Syn is built with the `"derive"` or `"full"`
164 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800165 pub struct ParenthesizedGenericArguments {
166 pub paren_token: token::Paren,
167 /// `(A, B)`
168 pub inputs: Punctuated<Type, Token![,]>,
169 /// `C`
170 pub output: ReturnType,
171 }
172}
173
174ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800175 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800176 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800177 ///
178 /// The actual path, including the trait and the associated item, is stored
179 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800180 /// item qualified with this Self type.
181 ///
182 /// ```text
183 /// <Vec<T> as a::b::Trait>::AssociatedItem
184 /// ^~~~~~ ~~~~~~~~~~~~~~^
185 /// ty position = 3
186 ///
187 /// <Vec<T>>::AssociatedItem
188 /// ^~~~~~ ^
189 /// ty position = 0
190 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800191 ///
192 /// *This type is available if Syn is built with the `"derive"` or `"full"`
193 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800194 pub struct QSelf {
195 pub lt_token: Token![<],
196 pub ty: Box<Type>,
197 pub position: usize,
198 pub as_token: Option<Token![as]>,
199 pub gt_token: Token![>],
200 }
201}
202
203#[cfg(feature = "parsing")]
204pub mod parsing {
205 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700206
David Tolnay310b3262018-08-30 15:33:00 -0700207 #[cfg(feature = "full")]
208 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700209 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700210 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800211
David Tolnay4fb71232018-08-25 23:14:50 -0400212 impl Parse for Path {
213 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700214 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800215 }
216 }
217
David Tolnay4fb71232018-08-25 23:14:50 -0400218 impl Parse for GenericArgument {
219 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700220 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400221 return Ok(GenericArgument::Lifetime(input.parse()?));
222 }
David Tolnay056de302018-01-05 14:29:05 -0800223
David Tolnay4fb71232018-08-25 23:14:50 -0400224 if input.peek(Ident) && input.peek2(Token![=]) {
225 return Ok(GenericArgument::Binding(input.parse()?));
226 }
David Tolnay056de302018-01-05 14:29:05 -0800227
David Tolnay4fb71232018-08-25 23:14:50 -0400228 #[cfg(feature = "full")]
229 {
David Tolnay9d0882a2018-09-01 19:49:14 -0700230 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
231 return Ok(GenericArgument::Constraint(input.parse()?));
232 }
233
David Tolnay4fb71232018-08-25 23:14:50 -0400234 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700235 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400236 return Ok(GenericArgument::Const(Expr::Lit(lit)));
237 }
238
239 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700240 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400241 return Ok(GenericArgument::Const(Expr::Block(block)));
242 }
243 }
244
David Tolnay8db2d662018-08-30 17:40:59 -0700245 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800246 }
247 }
248
David Tolnay4fb71232018-08-25 23:14:50 -0400249 impl Parse for AngleBracketedGenericArguments {
250 fn parse(input: ParseStream) -> Result<Self> {
251 Ok(AngleBracketedGenericArguments {
252 colon2_token: input.parse()?,
253 lt_token: input.parse()?,
254 args: {
255 let mut args = Punctuated::new();
256 loop {
257 if input.peek(Token![>]) {
258 break;
259 }
260 let value = input.parse()?;
261 args.push_value(value);
262 if input.peek(Token![>]) {
263 break;
264 }
265 let punct = input.parse()?;
266 args.push_punct(punct);
267 }
268 args
269 },
270 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800271 })
David Tolnay056de302018-01-05 14:29:05 -0800272 }
273 }
274
David Tolnay4fb71232018-08-25 23:14:50 -0400275 impl Parse for ParenthesizedGenericArguments {
276 fn parse(input: ParseStream) -> Result<Self> {
277 let content;
278 Ok(ParenthesizedGenericArguments {
279 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700280 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400281 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800282 })
David Tolnay056de302018-01-05 14:29:05 -0800283 }
284 }
285
David Tolnay4fb71232018-08-25 23:14:50 -0400286 impl Parse for PathSegment {
287 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700288 Self::parse_helper(input, false)
289 }
290 }
291
292 impl PathSegment {
293 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400294 if input.peek(Token![super])
295 || input.peek(Token![self])
296 || input.peek(Token![Self])
297 || input.peek(Token![crate])
298 || input.peek(Token![extern])
299 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700300 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400301 return Ok(PathSegment::from(ident));
302 }
303
304 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700305 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400306 || input.peek(Token![::]) && input.peek3(Token![<])
307 {
308 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800309 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400310 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800311 })
David Tolnay4fb71232018-08-25 23:14:50 -0400312 } else {
313 Ok(PathSegment::from(ident))
314 }
David Tolnay056de302018-01-05 14:29:05 -0800315 }
316 }
317
David Tolnay4fb71232018-08-25 23:14:50 -0400318 impl Parse for Binding {
319 fn parse(input: ParseStream) -> Result<Self> {
320 Ok(Binding {
321 ident: input.parse()?,
322 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400323 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800324 })
David Tolnay056de302018-01-05 14:29:05 -0800325 }
326 }
327
David Tolnay9d0882a2018-09-01 19:49:14 -0700328 #[cfg(feature = "full")]
329 impl Parse for Constraint {
330 fn parse(input: ParseStream) -> Result<Self> {
331 Ok(Constraint {
332 ident: input.parse()?,
333 colon_token: input.parse()?,
334 bounds: {
335 let mut bounds = Punctuated::new();
336 loop {
337 if input.peek(Token![,]) || input.peek(Token![>]) {
338 break;
339 }
340 let value = input.parse()?;
341 bounds.push_value(value);
342 if !input.peek(Token![+]) {
343 break;
344 }
345 let punct = input.parse()?;
346 bounds.push_punct(punct);
347 }
348 bounds
349 },
350 })
351 }
352 }
353
David Tolnay056de302018-01-05 14:29:05 -0800354 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700355 /// Parse a `Path` containing no path arguments on any of its segments.
356 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700357 /// *This function is available if Syn is built with the `"parsing"`
358 /// feature.*
359 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700360 /// # Example
361 ///
362 /// ```
David Tolnaya1c98072018-09-06 08:58:10 -0700363 /// #[macro_use]
364 /// extern crate syn;
365 ///
366 /// use syn::Path;
David Tolnaybbbd5302018-09-01 16:00:42 -0700367 /// use syn::parse::{Parse, ParseStream, Result};
368 ///
369 /// // A simplified single `use` statement like:
370 /// //
371 /// // use std::collections::HashMap;
372 /// //
373 /// // Note that generic parameters are not allowed in a `use` statement
374 /// // so the following must not be accepted.
375 /// //
376 /// // use a::<b>::c;
377 /// struct SingleUse {
378 /// use_token: Token![use],
379 /// path: Path,
380 /// }
381 ///
382 /// impl Parse for SingleUse {
383 /// fn parse(input: ParseStream) -> Result<Self> {
384 /// Ok(SingleUse {
385 /// use_token: input.parse()?,
386 /// path: input.call(Path::parse_mod_style)?,
387 /// })
388 /// }
389 /// }
390 /// #
391 /// # fn main() {}
392 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400393 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
394 Ok(Path {
395 leading_colon: input.parse()?,
396 segments: {
397 let mut segments = Punctuated::new();
398 loop {
399 if !input.peek(Ident)
400 && !input.peek(Token![super])
401 && !input.peek(Token![self])
402 && !input.peek(Token![Self])
403 && !input.peek(Token![crate])
404 && !input.peek(Token![extern])
405 {
406 break;
407 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700408 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400409 segments.push_value(PathSegment::from(ident));
410 if !input.peek(Token![::]) {
411 break;
412 }
413 let punct = input.parse()?;
414 segments.push_punct(punct);
415 }
416 if segments.is_empty() {
417 return Err(input.error("expected path"));
418 } else if segments.trailing_punct() {
419 return Err(input.error("expected path segment"));
420 }
421 segments
422 },
423 })
424 }
425
David Tolnay60291082018-08-28 09:54:49 -0700426 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
427 if input.peek(Token![dyn]) {
428 return Err(input.error("expected path"));
429 }
430
431 Ok(Path {
432 leading_colon: input.parse()?,
433 segments: {
434 let mut segments = Punctuated::new();
435 let value = PathSegment::parse_helper(input, expr_style)?;
436 segments.push_value(value);
437 while input.peek(Token![::]) {
438 let punct: Token![::] = input.parse()?;
439 segments.push_punct(punct);
440 let value = PathSegment::parse_helper(input, expr_style)?;
441 segments.push_value(value);
442 }
443 segments
444 },
445 })
446 }
David Tolnay056de302018-01-05 14:29:05 -0800447 }
448
David Tolnay60291082018-08-28 09:54:49 -0700449 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
450 if input.peek(Token![<]) {
451 let lt_token: Token![<] = input.parse()?;
452 let this: Type = input.parse()?;
453 let path = if input.peek(Token![as]) {
454 let as_token: Token![as] = input.parse()?;
455 let path: Path = input.parse()?;
456 Some((as_token, path))
457 } else {
458 None
459 };
460 let gt_token: Token![>] = input.parse()?;
461 let colon2_token: Token![::] = input.parse()?;
462 let mut rest = Punctuated::new();
463 loop {
464 let path = PathSegment::parse_helper(input, expr_style)?;
465 rest.push_value(path);
466 if !input.peek(Token![::]) {
467 break;
468 }
469 let punct: Token![::] = input.parse()?;
470 rest.push_punct(punct);
471 }
472 let (position, as_token, path) = match path {
473 Some((as_token, mut path)) => {
474 let pos = path.segments.len();
475 path.segments.push_punct(colon2_token);
476 path.segments.extend(rest.into_pairs());
477 (pos, Some(as_token), path)
478 }
479 None => {
480 let path = Path {
481 leading_colon: Some(colon2_token),
482 segments: rest,
483 };
484 (0, None, path)
485 }
486 };
487 let qself = QSelf {
488 lt_token: lt_token,
489 ty: Box::new(this),
490 position: position,
491 as_token: as_token,
492 gt_token: gt_token,
493 };
494 Ok((Some(qself), path))
495 } else {
496 let path = Path::parse_helper(input, expr_style)?;
497 Ok((None, path))
498 }
499 }
David Tolnay056de302018-01-05 14:29:05 -0800500}
501
502#[cfg(feature = "printing")]
503mod printing {
504 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700505
Alex Crichtona74a1c82018-05-16 10:20:44 -0700506 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700507 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800508
David Tolnay64023912018-08-31 09:51:12 -0700509 use print::TokensOrDefault;
510
David Tolnay056de302018-01-05 14:29:05 -0800511 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700512 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800513 self.leading_colon.to_tokens(tokens);
514 self.segments.to_tokens(tokens);
515 }
516 }
517
518 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700519 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800520 self.ident.to_tokens(tokens);
521 self.arguments.to_tokens(tokens);
522 }
523 }
524
525 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700526 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800527 match *self {
528 PathArguments::None => {}
529 PathArguments::AngleBracketed(ref arguments) => {
530 arguments.to_tokens(tokens);
531 }
532 PathArguments::Parenthesized(ref arguments) => {
533 arguments.to_tokens(tokens);
534 }
535 }
536 }
537 }
538
539 impl ToTokens for GenericArgument {
540 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700541 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800542 match *self {
543 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
544 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
545 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
David Tolnay9d0882a2018-09-01 19:49:14 -0700546 GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens),
David Tolnay056de302018-01-05 14:29:05 -0800547 GenericArgument::Const(ref e) => match *e {
548 Expr::Lit(_) => e.to_tokens(tokens),
549
550 // NOTE: We should probably support parsing blocks with only
551 // expressions in them without the full feature for const
552 // generics.
553 #[cfg(feature = "full")]
554 Expr::Block(_) => e.to_tokens(tokens),
555
556 // ERROR CORRECTION: Add braces to make sure that the
557 // generated code is valid.
558 _ => token::Brace::default().surround(tokens, |tokens| {
559 e.to_tokens(tokens);
560 }),
561 },
562 }
563 }
564 }
565
566 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700567 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800568 self.colon2_token.to_tokens(tokens);
569 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800570
571 // Print lifetimes before types and consts, all before bindings,
572 // regardless of their order in self.args.
573 //
574 // TODO: ordering rules for const arguments vs type arguments have
575 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
576 let mut trailing_or_empty = true;
577 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700578 match **param.value() {
579 GenericArgument::Lifetime(_) => {
580 param.to_tokens(tokens);
581 trailing_or_empty = param.punct().is_some();
582 }
583 GenericArgument::Type(_)
584 | GenericArgument::Binding(_)
585 | GenericArgument::Constraint(_)
586 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800587 }
588 }
589 for param in self.args.pairs() {
590 match **param.value() {
591 GenericArgument::Type(_) | GenericArgument::Const(_) => {
592 if !trailing_or_empty {
593 <Token![,]>::default().to_tokens(tokens);
594 }
595 param.to_tokens(tokens);
596 trailing_or_empty = param.punct().is_some();
597 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700598 GenericArgument::Lifetime(_)
599 | GenericArgument::Binding(_)
600 | GenericArgument::Constraint(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800601 }
602 }
603 for param in self.args.pairs() {
David Tolnay9d0882a2018-09-01 19:49:14 -0700604 match **param.value() {
605 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
606 if !trailing_or_empty {
607 <Token![,]>::default().to_tokens(tokens);
608 trailing_or_empty = true;
609 }
610 param.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800611 }
David Tolnay9d0882a2018-09-01 19:49:14 -0700612 GenericArgument::Lifetime(_)
613 | GenericArgument::Type(_)
614 | GenericArgument::Const(_) => {}
David Tolnay298570b2018-01-11 16:38:36 -0800615 }
616 }
617
David Tolnay056de302018-01-05 14:29:05 -0800618 self.gt_token.to_tokens(tokens);
619 }
620 }
621
622 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700623 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800624 self.ident.to_tokens(tokens);
625 self.eq_token.to_tokens(tokens);
626 self.ty.to_tokens(tokens);
627 }
628 }
629
David Tolnay9d0882a2018-09-01 19:49:14 -0700630 impl ToTokens for Constraint {
631 fn to_tokens(&self, tokens: &mut TokenStream) {
632 self.ident.to_tokens(tokens);
633 self.colon_token.to_tokens(tokens);
634 self.bounds.to_tokens(tokens);
635 }
636 }
637
David Tolnay056de302018-01-05 14:29:05 -0800638 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700639 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800640 self.paren_token.surround(tokens, |tokens| {
641 self.inputs.to_tokens(tokens);
642 });
643 self.output.to_tokens(tokens);
644 }
645 }
David Tolnay05658502018-01-07 09:56:37 -0800646
David Tolnay12f3b6f2018-09-01 16:10:53 -0700647 impl private {
648 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
649 let qself = match *qself {
David Tolnay05658502018-01-07 09:56:37 -0800650 Some(ref qself) => qself,
David Tolnay12f3b6f2018-09-01 16:10:53 -0700651 None => {
652 path.to_tokens(tokens);
653 return;
654 }
David Tolnay05658502018-01-07 09:56:37 -0800655 };
656 qself.lt_token.to_tokens(tokens);
657 qself.ty.to_tokens(tokens);
658
David Tolnay12f3b6f2018-09-01 16:10:53 -0700659 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
660 path.segments.len() - 1
David Tolnay05658502018-01-07 09:56:37 -0800661 } else {
662 qself.position
663 };
David Tolnay12f3b6f2018-09-01 16:10:53 -0700664 let mut segments = path.segments.pairs();
David Tolnay05658502018-01-07 09:56:37 -0800665 if pos > 0 {
666 TokensOrDefault(&qself.as_token).to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700667 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800668 for (i, segment) in segments.by_ref().take(pos).enumerate() {
669 if i + 1 == pos {
670 segment.value().to_tokens(tokens);
671 qself.gt_token.to_tokens(tokens);
672 segment.punct().to_tokens(tokens);
673 } else {
674 segment.to_tokens(tokens);
675 }
676 }
677 } else {
678 qself.gt_token.to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700679 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800680 }
681 for segment in segments {
682 segment.to_tokens(tokens);
683 }
684 }
685 }
David Tolnay056de302018-01-05 14:29:05 -0800686}