1 | use crate::attr::Attribute; |
2 | use crate::expr::Expr; |
3 | use crate::generics::{BoundLifetimes, TypeParamBound}; |
4 | use crate::ident::Ident; |
5 | use crate::lifetime::Lifetime; |
6 | use crate::lit::LitStr; |
7 | use crate::mac::Macro; |
8 | use crate::path::{Path, QSelf}; |
9 | use crate::punctuated::Punctuated; |
10 | use crate::token; |
11 | use proc_macro2::TokenStream; |
12 | |
13 | ast_enum_of_structs! { |
14 | /// The possible types that a Rust value could have. |
15 | /// |
16 | /// # Syntax tree enum |
17 | /// |
18 | /// This type is a [syntax tree enum]. |
19 | /// |
20 | /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums |
21 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
22 | #[non_exhaustive ] |
23 | pub enum Type { |
24 | /// A fixed size array type: `[T; n]`. |
25 | Array(TypeArray), |
26 | |
27 | /// A bare function type: `fn(usize) -> bool`. |
28 | BareFn(TypeBareFn), |
29 | |
30 | /// A type contained within invisible delimiters. |
31 | Group(TypeGroup), |
32 | |
33 | /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or |
34 | /// a lifetime. |
35 | ImplTrait(TypeImplTrait), |
36 | |
37 | /// Indication that a type should be inferred by the compiler: `_`. |
38 | Infer(TypeInfer), |
39 | |
40 | /// A macro in the type position. |
41 | Macro(TypeMacro), |
42 | |
43 | /// The never type: `!`. |
44 | Never(TypeNever), |
45 | |
46 | /// A parenthesized type equivalent to the inner type. |
47 | Paren(TypeParen), |
48 | |
49 | /// A path like `std::slice::Iter`, optionally qualified with a |
50 | /// self-type as in `<Vec<T> as SomeTrait>::Associated`. |
51 | Path(TypePath), |
52 | |
53 | /// A raw pointer type: `*const T` or `*mut T`. |
54 | Ptr(TypePtr), |
55 | |
56 | /// A reference type: `&'a T` or `&'a mut T`. |
57 | Reference(TypeReference), |
58 | |
59 | /// A dynamically sized slice type: `[T]`. |
60 | Slice(TypeSlice), |
61 | |
62 | /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a |
63 | /// trait or a lifetime. |
64 | TraitObject(TypeTraitObject), |
65 | |
66 | /// A tuple type: `(A, B, C, String)`. |
67 | Tuple(TypeTuple), |
68 | |
69 | /// Tokens in type position not interpreted by Syn. |
70 | Verbatim(TokenStream), |
71 | |
72 | // For testing exhaustiveness in downstream code, use the following idiom: |
73 | // |
74 | // match ty { |
75 | // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] |
76 | // |
77 | // Type::Array(ty) => {...} |
78 | // Type::BareFn(ty) => {...} |
79 | // ... |
80 | // Type::Verbatim(ty) => {...} |
81 | // |
82 | // _ => { /* some sane fallback */ } |
83 | // } |
84 | // |
85 | // This way we fail your tests but don't break your library when adding |
86 | // a variant. You will be notified by a test failure when a variant is |
87 | // added, so that you can add code to handle it, but your library will |
88 | // continue to compile and work for downstream users in the interim. |
89 | } |
90 | } |
91 | |
92 | ast_struct! { |
93 | /// A fixed size array type: `[T; n]`. |
94 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
95 | pub struct TypeArray { |
96 | pub bracket_token: token::Bracket, |
97 | pub elem: Box<Type>, |
98 | pub semi_token: Token![;], |
99 | pub len: Expr, |
100 | } |
101 | } |
102 | |
103 | ast_struct! { |
104 | /// A bare function type: `fn(usize) -> bool`. |
105 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
106 | pub struct TypeBareFn { |
107 | pub lifetimes: Option<BoundLifetimes>, |
108 | pub unsafety: Option<Token![unsafe]>, |
109 | pub abi: Option<Abi>, |
110 | pub fn_token: Token![fn], |
111 | pub paren_token: token::Paren, |
112 | pub inputs: Punctuated<BareFnArg, Token![,]>, |
113 | pub variadic: Option<BareVariadic>, |
114 | pub output: ReturnType, |
115 | } |
116 | } |
117 | |
118 | ast_struct! { |
119 | /// A type contained within invisible delimiters. |
120 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
121 | pub struct TypeGroup { |
122 | pub group_token: token::Group, |
123 | pub elem: Box<Type>, |
124 | } |
125 | } |
126 | |
127 | ast_struct! { |
128 | /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or |
129 | /// a lifetime. |
130 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
131 | pub struct TypeImplTrait { |
132 | pub impl_token: Token![impl], |
133 | pub bounds: Punctuated<TypeParamBound, Token![+]>, |
134 | } |
135 | } |
136 | |
137 | ast_struct! { |
138 | /// Indication that a type should be inferred by the compiler: `_`. |
139 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
140 | pub struct TypeInfer { |
141 | pub underscore_token: Token![_], |
142 | } |
143 | } |
144 | |
145 | ast_struct! { |
146 | /// A macro in the type position. |
147 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
148 | pub struct TypeMacro { |
149 | pub mac: Macro, |
150 | } |
151 | } |
152 | |
153 | ast_struct! { |
154 | /// The never type: `!`. |
155 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
156 | pub struct TypeNever { |
157 | pub bang_token: Token![!], |
158 | } |
159 | } |
160 | |
161 | ast_struct! { |
162 | /// A parenthesized type equivalent to the inner type. |
163 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
164 | pub struct TypeParen { |
165 | pub paren_token: token::Paren, |
166 | pub elem: Box<Type>, |
167 | } |
168 | } |
169 | |
170 | ast_struct! { |
171 | /// A path like `std::slice::Iter`, optionally qualified with a |
172 | /// self-type as in `<Vec<T> as SomeTrait>::Associated`. |
173 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
174 | pub struct TypePath { |
175 | pub qself: Option<QSelf>, |
176 | pub path: Path, |
177 | } |
178 | } |
179 | |
180 | ast_struct! { |
181 | /// A raw pointer type: `*const T` or `*mut T`. |
182 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
183 | pub struct TypePtr { |
184 | pub star_token: Token![*], |
185 | pub const_token: Option<Token![const]>, |
186 | pub mutability: Option<Token![mut]>, |
187 | pub elem: Box<Type>, |
188 | } |
189 | } |
190 | |
191 | ast_struct! { |
192 | /// A reference type: `&'a T` or `&'a mut T`. |
193 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
194 | pub struct TypeReference { |
195 | pub and_token: Token![&], |
196 | pub lifetime: Option<Lifetime>, |
197 | pub mutability: Option<Token![mut]>, |
198 | pub elem: Box<Type>, |
199 | } |
200 | } |
201 | |
202 | ast_struct! { |
203 | /// A dynamically sized slice type: `[T]`. |
204 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
205 | pub struct TypeSlice { |
206 | pub bracket_token: token::Bracket, |
207 | pub elem: Box<Type>, |
208 | } |
209 | } |
210 | |
211 | ast_struct! { |
212 | /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a |
213 | /// trait or a lifetime. |
214 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
215 | pub struct TypeTraitObject { |
216 | pub dyn_token: Option<Token![dyn]>, |
217 | pub bounds: Punctuated<TypeParamBound, Token![+]>, |
218 | } |
219 | } |
220 | |
221 | ast_struct! { |
222 | /// A tuple type: `(A, B, C, String)`. |
223 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
224 | pub struct TypeTuple { |
225 | pub paren_token: token::Paren, |
226 | pub elems: Punctuated<Type, Token![,]>, |
227 | } |
228 | } |
229 | |
230 | ast_struct! { |
231 | /// The binary interface of a function: `extern "C"`. |
232 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
233 | pub struct Abi { |
234 | pub extern_token: Token![extern], |
235 | pub name: Option<LitStr>, |
236 | } |
237 | } |
238 | |
239 | ast_struct! { |
240 | /// An argument in a function type: the `usize` in `fn(usize) -> bool`. |
241 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
242 | pub struct BareFnArg { |
243 | pub attrs: Vec<Attribute>, |
244 | pub name: Option<(Ident, Token![:])>, |
245 | pub ty: Type, |
246 | } |
247 | } |
248 | |
249 | ast_struct! { |
250 | /// The variadic argument of a function pointer like `fn(usize, ...)`. |
251 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
252 | pub struct BareVariadic { |
253 | pub attrs: Vec<Attribute>, |
254 | pub name: Option<(Ident, Token![:])>, |
255 | pub dots: Token![...], |
256 | pub comma: Option<Token![,]>, |
257 | } |
258 | } |
259 | |
260 | ast_enum! { |
261 | /// Return type of a function signature. |
262 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
263 | pub enum ReturnType { |
264 | /// Return type is not specified. |
265 | /// |
266 | /// Functions default to `()` and closures default to type inference. |
267 | Default, |
268 | /// A particular type is returned. |
269 | Type(Token![->], Box<Type>), |
270 | } |
271 | } |
272 | |
273 | #[cfg (feature = "parsing" )] |
274 | pub(crate) mod parsing { |
275 | use crate::attr::Attribute; |
276 | use crate::error::{self, Result}; |
277 | use crate::ext::IdentExt as _; |
278 | use crate::generics::{BoundLifetimes, TraitBound, TraitBoundModifier, TypeParamBound}; |
279 | use crate::ident::Ident; |
280 | use crate::lifetime::Lifetime; |
281 | use crate::mac::{self, Macro}; |
282 | use crate::parse::{Parse, ParseStream}; |
283 | use crate::path; |
284 | use crate::path::{Path, PathArguments, QSelf}; |
285 | use crate::punctuated::Punctuated; |
286 | use crate::token; |
287 | use crate::ty::{ |
288 | Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, |
289 | TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, |
290 | TypeReference, TypeSlice, TypeTraitObject, TypeTuple, |
291 | }; |
292 | use crate::verbatim; |
293 | use proc_macro2::Span; |
294 | |
295 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
296 | impl Parse for Type { |
297 | fn parse(input: ParseStream) -> Result<Self> { |
298 | let allow_plus = true; |
299 | let allow_group_generic = true; |
300 | ambig_ty(input, allow_plus, allow_group_generic) |
301 | } |
302 | } |
303 | |
304 | impl Type { |
305 | /// In some positions, types may not contain the `+` character, to |
306 | /// disambiguate them. For example in the expression `1 as T`, T may not |
307 | /// contain a `+` character. |
308 | /// |
309 | /// This parser does not allow a `+`, while the default parser does. |
310 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
311 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
312 | let allow_plus = false; |
313 | let allow_group_generic = true; |
314 | ambig_ty(input, allow_plus, allow_group_generic) |
315 | } |
316 | } |
317 | |
318 | pub(crate) fn ambig_ty( |
319 | input: ParseStream, |
320 | allow_plus: bool, |
321 | allow_group_generic: bool, |
322 | ) -> Result<Type> { |
323 | let begin = input.fork(); |
324 | |
325 | if input.peek(token::Group) { |
326 | let mut group: TypeGroup = input.parse()?; |
327 | if input.peek(Token![::]) && input.peek3(Ident::peek_any) { |
328 | if let Type::Path(mut ty) = *group.elem { |
329 | Path::parse_rest(input, &mut ty.path, false)?; |
330 | return Ok(Type::Path(ty)); |
331 | } else { |
332 | return Ok(Type::Path(TypePath { |
333 | qself: Some(QSelf { |
334 | lt_token: Token, |
335 | position: 0, |
336 | as_token: None, |
337 | gt_token: Token, |
338 | ty: group.elem, |
339 | }), |
340 | path: Path::parse_helper(input, false)?, |
341 | })); |
342 | } |
343 | } else if input.peek(Token![<]) && allow_group_generic |
344 | || input.peek(Token![::]) && input.peek3(Token![<]) |
345 | { |
346 | if let Type::Path(mut ty) = *group.elem { |
347 | let arguments = &mut ty.path.segments.last_mut().unwrap().arguments; |
348 | if arguments.is_none() { |
349 | *arguments = PathArguments::AngleBracketed(input.parse()?); |
350 | Path::parse_rest(input, &mut ty.path, false)?; |
351 | return Ok(Type::Path(ty)); |
352 | } else { |
353 | group.elem = Box::new(Type::Path(ty)); |
354 | } |
355 | } |
356 | } |
357 | return Ok(Type::Group(group)); |
358 | } |
359 | |
360 | let mut lifetimes = None::<BoundLifetimes>; |
361 | let mut lookahead = input.lookahead1(); |
362 | if lookahead.peek(Token![for]) { |
363 | lifetimes = input.parse()?; |
364 | lookahead = input.lookahead1(); |
365 | if !lookahead.peek(Ident) |
366 | && !lookahead.peek(Token![fn]) |
367 | && !lookahead.peek(Token![unsafe]) |
368 | && !lookahead.peek(Token![extern]) |
369 | && !lookahead.peek(Token![super]) |
370 | && !lookahead.peek(Token![self]) |
371 | && !lookahead.peek(Token![Self]) |
372 | && !lookahead.peek(Token![crate]) |
373 | || input.peek(Token![dyn]) |
374 | { |
375 | return Err(lookahead.error()); |
376 | } |
377 | } |
378 | |
379 | if lookahead.peek(token::Paren) { |
380 | let content; |
381 | let paren_token = parenthesized!(content in input); |
382 | if content.is_empty() { |
383 | return Ok(Type::Tuple(TypeTuple { |
384 | paren_token, |
385 | elems: Punctuated::new(), |
386 | })); |
387 | } |
388 | if content.peek(Lifetime) { |
389 | return Ok(Type::Paren(TypeParen { |
390 | paren_token, |
391 | elem: Box::new(Type::TraitObject(content.parse()?)), |
392 | })); |
393 | } |
394 | if content.peek(Token![?]) { |
395 | return Ok(Type::TraitObject(TypeTraitObject { |
396 | dyn_token: None, |
397 | bounds: { |
398 | let mut bounds = Punctuated::new(); |
399 | bounds.push_value(TypeParamBound::Trait(TraitBound { |
400 | paren_token: Some(paren_token), |
401 | ..content.parse()? |
402 | })); |
403 | while let Some(plus) = input.parse()? { |
404 | bounds.push_punct(plus); |
405 | bounds.push_value({ |
406 | let allow_precise_capture = false; |
407 | let allow_tilde_const = false; |
408 | TypeParamBound::parse_single( |
409 | input, |
410 | allow_precise_capture, |
411 | allow_tilde_const, |
412 | )? |
413 | }); |
414 | } |
415 | bounds |
416 | }, |
417 | })); |
418 | } |
419 | let mut first: Type = content.parse()?; |
420 | if content.peek(Token![,]) { |
421 | return Ok(Type::Tuple(TypeTuple { |
422 | paren_token, |
423 | elems: { |
424 | let mut elems = Punctuated::new(); |
425 | elems.push_value(first); |
426 | elems.push_punct(content.parse()?); |
427 | while !content.is_empty() { |
428 | elems.push_value(content.parse()?); |
429 | if content.is_empty() { |
430 | break; |
431 | } |
432 | elems.push_punct(content.parse()?); |
433 | } |
434 | elems |
435 | }, |
436 | })); |
437 | } |
438 | if allow_plus && input.peek(Token![+]) { |
439 | loop { |
440 | let first = match first { |
441 | Type::Path(TypePath { qself: None, path }) => { |
442 | TypeParamBound::Trait(TraitBound { |
443 | paren_token: Some(paren_token), |
444 | modifier: TraitBoundModifier::None, |
445 | lifetimes: None, |
446 | path, |
447 | }) |
448 | } |
449 | Type::TraitObject(TypeTraitObject { |
450 | dyn_token: None, |
451 | bounds, |
452 | }) => { |
453 | if bounds.len() > 1 || bounds.trailing_punct() { |
454 | first = Type::TraitObject(TypeTraitObject { |
455 | dyn_token: None, |
456 | bounds, |
457 | }); |
458 | break; |
459 | } |
460 | match bounds.into_iter().next().unwrap() { |
461 | TypeParamBound::Trait(trait_bound) => { |
462 | TypeParamBound::Trait(TraitBound { |
463 | paren_token: Some(paren_token), |
464 | ..trait_bound |
465 | }) |
466 | } |
467 | other @ (TypeParamBound::Lifetime(_) |
468 | | TypeParamBound::PreciseCapture(_) |
469 | | TypeParamBound::Verbatim(_)) => other, |
470 | } |
471 | } |
472 | _ => break, |
473 | }; |
474 | return Ok(Type::TraitObject(TypeTraitObject { |
475 | dyn_token: None, |
476 | bounds: { |
477 | let mut bounds = Punctuated::new(); |
478 | bounds.push_value(first); |
479 | while let Some(plus) = input.parse()? { |
480 | bounds.push_punct(plus); |
481 | bounds.push_value({ |
482 | let allow_precise_capture = false; |
483 | let allow_tilde_const = false; |
484 | TypeParamBound::parse_single( |
485 | input, |
486 | allow_precise_capture, |
487 | allow_tilde_const, |
488 | )? |
489 | }); |
490 | } |
491 | bounds |
492 | }, |
493 | })); |
494 | } |
495 | } |
496 | Ok(Type::Paren(TypeParen { |
497 | paren_token, |
498 | elem: Box::new(first), |
499 | })) |
500 | } else if lookahead.peek(Token![fn]) |
501 | || lookahead.peek(Token![unsafe]) |
502 | || lookahead.peek(Token![extern]) |
503 | { |
504 | let mut bare_fn: TypeBareFn = input.parse()?; |
505 | bare_fn.lifetimes = lifetimes; |
506 | Ok(Type::BareFn(bare_fn)) |
507 | } else if lookahead.peek(Ident) |
508 | || input.peek(Token![super]) |
509 | || input.peek(Token![self]) |
510 | || input.peek(Token![Self]) |
511 | || input.peek(Token![crate]) |
512 | || lookahead.peek(Token![::]) |
513 | || lookahead.peek(Token![<]) |
514 | { |
515 | let ty: TypePath = input.parse()?; |
516 | if ty.qself.is_some() { |
517 | return Ok(Type::Path(ty)); |
518 | } |
519 | |
520 | if input.peek(Token![!]) && !input.peek(Token![!=]) && ty.path.is_mod_style() { |
521 | let bang_token: Token![!] = input.parse()?; |
522 | let (delimiter, tokens) = mac::parse_delimiter(input)?; |
523 | return Ok(Type::Macro(TypeMacro { |
524 | mac: Macro { |
525 | path: ty.path, |
526 | bang_token, |
527 | delimiter, |
528 | tokens, |
529 | }, |
530 | })); |
531 | } |
532 | |
533 | if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { |
534 | let mut bounds = Punctuated::new(); |
535 | bounds.push_value(TypeParamBound::Trait(TraitBound { |
536 | paren_token: None, |
537 | modifier: TraitBoundModifier::None, |
538 | lifetimes, |
539 | path: ty.path, |
540 | })); |
541 | if allow_plus { |
542 | while input.peek(Token![+]) { |
543 | bounds.push_punct(input.parse()?); |
544 | if !(input.peek(Ident::peek_any) |
545 | || input.peek(Token![::]) |
546 | || input.peek(Token![?]) |
547 | || input.peek(Lifetime) |
548 | || input.peek(token::Paren)) |
549 | { |
550 | break; |
551 | } |
552 | bounds.push_value({ |
553 | let allow_precise_capture = false; |
554 | let allow_tilde_const = false; |
555 | TypeParamBound::parse_single( |
556 | input, |
557 | allow_precise_capture, |
558 | allow_tilde_const, |
559 | )? |
560 | }); |
561 | } |
562 | } |
563 | return Ok(Type::TraitObject(TypeTraitObject { |
564 | dyn_token: None, |
565 | bounds, |
566 | })); |
567 | } |
568 | |
569 | Ok(Type::Path(ty)) |
570 | } else if lookahead.peek(Token![dyn]) { |
571 | let dyn_token: Token![dyn] = input.parse()?; |
572 | let dyn_span = dyn_token.span; |
573 | let star_token: Option<Token![*]> = input.parse()?; |
574 | let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?; |
575 | return Ok(if star_token.is_some() { |
576 | Type::Verbatim(verbatim::between(&begin, input)) |
577 | } else { |
578 | Type::TraitObject(TypeTraitObject { |
579 | dyn_token: Some(dyn_token), |
580 | bounds, |
581 | }) |
582 | }); |
583 | } else if lookahead.peek(token::Bracket) { |
584 | let content; |
585 | let bracket_token = bracketed!(content in input); |
586 | let elem: Type = content.parse()?; |
587 | if content.peek(Token![;]) { |
588 | Ok(Type::Array(TypeArray { |
589 | bracket_token, |
590 | elem: Box::new(elem), |
591 | semi_token: content.parse()?, |
592 | len: content.parse()?, |
593 | })) |
594 | } else { |
595 | Ok(Type::Slice(TypeSlice { |
596 | bracket_token, |
597 | elem: Box::new(elem), |
598 | })) |
599 | } |
600 | } else if lookahead.peek(Token![*]) { |
601 | input.parse().map(Type::Ptr) |
602 | } else if lookahead.peek(Token![&]) { |
603 | input.parse().map(Type::Reference) |
604 | } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { |
605 | input.parse().map(Type::Never) |
606 | } else if lookahead.peek(Token![impl]) { |
607 | TypeImplTrait::parse(input, allow_plus).map(Type::ImplTrait) |
608 | } else if lookahead.peek(Token![_]) { |
609 | input.parse().map(Type::Infer) |
610 | } else if lookahead.peek(Lifetime) { |
611 | input.parse().map(Type::TraitObject) |
612 | } else { |
613 | Err(lookahead.error()) |
614 | } |
615 | } |
616 | |
617 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
618 | impl Parse for TypeSlice { |
619 | fn parse(input: ParseStream) -> Result<Self> { |
620 | let content; |
621 | Ok(TypeSlice { |
622 | bracket_token: bracketed!(content in input), |
623 | elem: content.parse()?, |
624 | }) |
625 | } |
626 | } |
627 | |
628 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
629 | impl Parse for TypeArray { |
630 | fn parse(input: ParseStream) -> Result<Self> { |
631 | let content; |
632 | Ok(TypeArray { |
633 | bracket_token: bracketed!(content in input), |
634 | elem: content.parse()?, |
635 | semi_token: content.parse()?, |
636 | len: content.parse()?, |
637 | }) |
638 | } |
639 | } |
640 | |
641 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
642 | impl Parse for TypePtr { |
643 | fn parse(input: ParseStream) -> Result<Self> { |
644 | let star_token: Token![*] = input.parse()?; |
645 | |
646 | let lookahead = input.lookahead1(); |
647 | let (const_token, mutability) = if lookahead.peek(Token![const]) { |
648 | (Some(input.parse()?), None) |
649 | } else if lookahead.peek(Token![mut]) { |
650 | (None, Some(input.parse()?)) |
651 | } else { |
652 | return Err(lookahead.error()); |
653 | }; |
654 | |
655 | Ok(TypePtr { |
656 | star_token, |
657 | const_token, |
658 | mutability, |
659 | elem: Box::new(input.call(Type::without_plus)?), |
660 | }) |
661 | } |
662 | } |
663 | |
664 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
665 | impl Parse for TypeReference { |
666 | fn parse(input: ParseStream) -> Result<Self> { |
667 | Ok(TypeReference { |
668 | and_token: input.parse()?, |
669 | lifetime: input.parse()?, |
670 | mutability: input.parse()?, |
671 | // & binds tighter than +, so we don't allow + here. |
672 | elem: Box::new(input.call(Type::without_plus)?), |
673 | }) |
674 | } |
675 | } |
676 | |
677 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
678 | impl Parse for TypeBareFn { |
679 | fn parse(input: ParseStream) -> Result<Self> { |
680 | let args; |
681 | let mut variadic = None; |
682 | |
683 | Ok(TypeBareFn { |
684 | lifetimes: input.parse()?, |
685 | unsafety: input.parse()?, |
686 | abi: input.parse()?, |
687 | fn_token: input.parse()?, |
688 | paren_token: parenthesized!(args in input), |
689 | inputs: { |
690 | let mut inputs = Punctuated::new(); |
691 | |
692 | while !args.is_empty() { |
693 | let attrs = args.call(Attribute::parse_outer)?; |
694 | |
695 | if inputs.empty_or_trailing() |
696 | && (args.peek(Token![...]) |
697 | || (args.peek(Ident) || args.peek(Token![_])) |
698 | && args.peek2(Token![:]) |
699 | && args.peek3(Token![...])) |
700 | { |
701 | variadic = Some(parse_bare_variadic(&args, attrs)?); |
702 | break; |
703 | } |
704 | |
705 | let allow_self = inputs.is_empty(); |
706 | let arg = parse_bare_fn_arg(&args, allow_self)?; |
707 | inputs.push_value(BareFnArg { attrs, ..arg }); |
708 | if args.is_empty() { |
709 | break; |
710 | } |
711 | |
712 | let comma = args.parse()?; |
713 | inputs.push_punct(comma); |
714 | } |
715 | |
716 | inputs |
717 | }, |
718 | variadic, |
719 | output: input.call(ReturnType::without_plus)?, |
720 | }) |
721 | } |
722 | } |
723 | |
724 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
725 | impl Parse for TypeNever { |
726 | fn parse(input: ParseStream) -> Result<Self> { |
727 | Ok(TypeNever { |
728 | bang_token: input.parse()?, |
729 | }) |
730 | } |
731 | } |
732 | |
733 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
734 | impl Parse for TypeInfer { |
735 | fn parse(input: ParseStream) -> Result<Self> { |
736 | Ok(TypeInfer { |
737 | underscore_token: input.parse()?, |
738 | }) |
739 | } |
740 | } |
741 | |
742 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
743 | impl Parse for TypeTuple { |
744 | fn parse(input: ParseStream) -> Result<Self> { |
745 | let content; |
746 | let paren_token = parenthesized!(content in input); |
747 | |
748 | if content.is_empty() { |
749 | return Ok(TypeTuple { |
750 | paren_token, |
751 | elems: Punctuated::new(), |
752 | }); |
753 | } |
754 | |
755 | let first: Type = content.parse()?; |
756 | Ok(TypeTuple { |
757 | paren_token, |
758 | elems: { |
759 | let mut elems = Punctuated::new(); |
760 | elems.push_value(first); |
761 | elems.push_punct(content.parse()?); |
762 | while !content.is_empty() { |
763 | elems.push_value(content.parse()?); |
764 | if content.is_empty() { |
765 | break; |
766 | } |
767 | elems.push_punct(content.parse()?); |
768 | } |
769 | elems |
770 | }, |
771 | }) |
772 | } |
773 | } |
774 | |
775 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
776 | impl Parse for TypeMacro { |
777 | fn parse(input: ParseStream) -> Result<Self> { |
778 | Ok(TypeMacro { |
779 | mac: input.parse()?, |
780 | }) |
781 | } |
782 | } |
783 | |
784 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
785 | impl Parse for TypePath { |
786 | fn parse(input: ParseStream) -> Result<Self> { |
787 | let expr_style = false; |
788 | let (qself, path) = path::parsing::qpath(input, expr_style)?; |
789 | Ok(TypePath { qself, path }) |
790 | } |
791 | } |
792 | |
793 | impl ReturnType { |
794 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
795 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
796 | let allow_plus = false; |
797 | Self::parse(input, allow_plus) |
798 | } |
799 | |
800 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
801 | if input.peek(Token![->]) { |
802 | let arrow = input.parse()?; |
803 | let allow_group_generic = true; |
804 | let ty = ambig_ty(input, allow_plus, allow_group_generic)?; |
805 | Ok(ReturnType::Type(arrow, Box::new(ty))) |
806 | } else { |
807 | Ok(ReturnType::Default) |
808 | } |
809 | } |
810 | } |
811 | |
812 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
813 | impl Parse for ReturnType { |
814 | fn parse(input: ParseStream) -> Result<Self> { |
815 | let allow_plus = true; |
816 | Self::parse(input, allow_plus) |
817 | } |
818 | } |
819 | |
820 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
821 | impl Parse for TypeTraitObject { |
822 | fn parse(input: ParseStream) -> Result<Self> { |
823 | let allow_plus = true; |
824 | Self::parse(input, allow_plus) |
825 | } |
826 | } |
827 | |
828 | impl TypeTraitObject { |
829 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
830 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
831 | let allow_plus = false; |
832 | Self::parse(input, allow_plus) |
833 | } |
834 | |
835 | // Only allow multiple trait references if allow_plus is true. |
836 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
837 | let dyn_token: Option<Token![dyn]> = input.parse()?; |
838 | let dyn_span = match &dyn_token { |
839 | Some(token) => token.span, |
840 | None => input.span(), |
841 | }; |
842 | let bounds = Self::parse_bounds(dyn_span, input, allow_plus)?; |
843 | Ok(TypeTraitObject { dyn_token, bounds }) |
844 | } |
845 | |
846 | fn parse_bounds( |
847 | dyn_span: Span, |
848 | input: ParseStream, |
849 | allow_plus: bool, |
850 | ) -> Result<Punctuated<TypeParamBound, Token![+]>> { |
851 | let allow_precise_capture = false; |
852 | let allow_tilde_const = false; |
853 | let bounds = TypeParamBound::parse_multiple( |
854 | input, |
855 | allow_plus, |
856 | allow_precise_capture, |
857 | allow_tilde_const, |
858 | )?; |
859 | let mut last_lifetime_span = None; |
860 | let mut at_least_one_trait = false; |
861 | for bound in &bounds { |
862 | match bound { |
863 | TypeParamBound::Trait(_) => { |
864 | at_least_one_trait = true; |
865 | break; |
866 | } |
867 | TypeParamBound::Lifetime(lifetime) => { |
868 | last_lifetime_span = Some(lifetime.ident.span()); |
869 | } |
870 | TypeParamBound::PreciseCapture(_) | TypeParamBound::Verbatim(_) => { |
871 | unreachable!() |
872 | } |
873 | } |
874 | } |
875 | // Just lifetimes like `'a + 'b` is not a TraitObject. |
876 | if !at_least_one_trait { |
877 | let msg = "at least one trait is required for an object type" ; |
878 | return Err(error::new2(dyn_span, last_lifetime_span.unwrap(), msg)); |
879 | } |
880 | Ok(bounds) |
881 | } |
882 | } |
883 | |
884 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
885 | impl Parse for TypeImplTrait { |
886 | fn parse(input: ParseStream) -> Result<Self> { |
887 | let allow_plus = true; |
888 | Self::parse(input, allow_plus) |
889 | } |
890 | } |
891 | |
892 | impl TypeImplTrait { |
893 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
894 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
895 | let allow_plus = false; |
896 | Self::parse(input, allow_plus) |
897 | } |
898 | |
899 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
900 | let impl_token: Token![impl] = input.parse()?; |
901 | let allow_precise_capture = true; |
902 | let allow_tilde_const = false; |
903 | let bounds = TypeParamBound::parse_multiple( |
904 | input, |
905 | allow_plus, |
906 | allow_precise_capture, |
907 | allow_tilde_const, |
908 | )?; |
909 | let mut last_nontrait_span = None; |
910 | let mut at_least_one_trait = false; |
911 | for bound in &bounds { |
912 | match bound { |
913 | TypeParamBound::Trait(_) => { |
914 | at_least_one_trait = true; |
915 | break; |
916 | } |
917 | TypeParamBound::Lifetime(lifetime) => { |
918 | last_nontrait_span = Some(lifetime.ident.span()); |
919 | } |
920 | TypeParamBound::PreciseCapture(precise_capture) => { |
921 | #[cfg (feature = "full" )] |
922 | { |
923 | last_nontrait_span = Some(precise_capture.gt_token.span); |
924 | } |
925 | #[cfg (not(feature = "full" ))] |
926 | { |
927 | _ = precise_capture; |
928 | unreachable!(); |
929 | } |
930 | } |
931 | TypeParamBound::Verbatim(_) => { |
932 | // ~const Trait |
933 | at_least_one_trait = true; |
934 | break; |
935 | } |
936 | } |
937 | } |
938 | if !at_least_one_trait { |
939 | let msg = "at least one trait must be specified" ; |
940 | return Err(error::new2( |
941 | impl_token.span, |
942 | last_nontrait_span.unwrap(), |
943 | msg, |
944 | )); |
945 | } |
946 | Ok(TypeImplTrait { impl_token, bounds }) |
947 | } |
948 | } |
949 | |
950 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
951 | impl Parse for TypeGroup { |
952 | fn parse(input: ParseStream) -> Result<Self> { |
953 | let group = crate::group::parse_group(input)?; |
954 | Ok(TypeGroup { |
955 | group_token: group.token, |
956 | elem: group.content.parse()?, |
957 | }) |
958 | } |
959 | } |
960 | |
961 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
962 | impl Parse for TypeParen { |
963 | fn parse(input: ParseStream) -> Result<Self> { |
964 | let allow_plus = false; |
965 | Self::parse(input, allow_plus) |
966 | } |
967 | } |
968 | |
969 | impl TypeParen { |
970 | fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
971 | let content; |
972 | Ok(TypeParen { |
973 | paren_token: parenthesized!(content in input), |
974 | elem: Box::new({ |
975 | let allow_group_generic = true; |
976 | ambig_ty(&content, allow_plus, allow_group_generic)? |
977 | }), |
978 | }) |
979 | } |
980 | } |
981 | |
982 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
983 | impl Parse for BareFnArg { |
984 | fn parse(input: ParseStream) -> Result<Self> { |
985 | let allow_self = false; |
986 | parse_bare_fn_arg(input, allow_self) |
987 | } |
988 | } |
989 | |
990 | fn parse_bare_fn_arg(input: ParseStream, allow_self: bool) -> Result<BareFnArg> { |
991 | let attrs = input.call(Attribute::parse_outer)?; |
992 | |
993 | let begin = input.fork(); |
994 | |
995 | let has_mut_self = allow_self && input.peek(Token![mut]) && input.peek2(Token![self]); |
996 | if has_mut_self { |
997 | input.parse::<Token![mut]>()?; |
998 | } |
999 | |
1000 | let mut has_self = false; |
1001 | let mut name = if (input.peek(Ident) || input.peek(Token![_]) || { |
1002 | has_self = allow_self && input.peek(Token![self]); |
1003 | has_self |
1004 | }) && input.peek2(Token![:]) |
1005 | && !input.peek2(Token![::]) |
1006 | { |
1007 | let name = input.call(Ident::parse_any)?; |
1008 | let colon: Token![:] = input.parse()?; |
1009 | Some((name, colon)) |
1010 | } else { |
1011 | has_self = false; |
1012 | None |
1013 | }; |
1014 | |
1015 | let ty = if allow_self && !has_self && input.peek(Token![mut]) && input.peek2(Token![self]) |
1016 | { |
1017 | input.parse::<Token![mut]>()?; |
1018 | input.parse::<Token![self]>()?; |
1019 | None |
1020 | } else if has_mut_self && name.is_none() { |
1021 | input.parse::<Token![self]>()?; |
1022 | None |
1023 | } else { |
1024 | Some(input.parse()?) |
1025 | }; |
1026 | |
1027 | let ty = match ty { |
1028 | Some(ty) if !has_mut_self => ty, |
1029 | _ => { |
1030 | name = None; |
1031 | Type::Verbatim(verbatim::between(&begin, input)) |
1032 | } |
1033 | }; |
1034 | |
1035 | Ok(BareFnArg { attrs, name, ty }) |
1036 | } |
1037 | |
1038 | fn parse_bare_variadic(input: ParseStream, attrs: Vec<Attribute>) -> Result<BareVariadic> { |
1039 | Ok(BareVariadic { |
1040 | attrs, |
1041 | name: if input.peek(Ident) || input.peek(Token![_]) { |
1042 | let name = input.call(Ident::parse_any)?; |
1043 | let colon: Token![:] = input.parse()?; |
1044 | Some((name, colon)) |
1045 | } else { |
1046 | None |
1047 | }, |
1048 | dots: input.parse()?, |
1049 | comma: input.parse()?, |
1050 | }) |
1051 | } |
1052 | |
1053 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
1054 | impl Parse for Abi { |
1055 | fn parse(input: ParseStream) -> Result<Self> { |
1056 | Ok(Abi { |
1057 | extern_token: input.parse()?, |
1058 | name: input.parse()?, |
1059 | }) |
1060 | } |
1061 | } |
1062 | |
1063 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
1064 | impl Parse for Option<Abi> { |
1065 | fn parse(input: ParseStream) -> Result<Self> { |
1066 | if input.peek(Token![extern]) { |
1067 | input.parse().map(Some) |
1068 | } else { |
1069 | Ok(None) |
1070 | } |
1071 | } |
1072 | } |
1073 | } |
1074 | |
1075 | #[cfg (feature = "printing" )] |
1076 | mod printing { |
1077 | use crate::attr::FilterAttrs; |
1078 | use crate::path; |
1079 | use crate::path::printing::PathStyle; |
1080 | use crate::print::TokensOrDefault; |
1081 | use crate::ty::{ |
1082 | Abi, BareFnArg, BareVariadic, ReturnType, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, |
1083 | TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, |
1084 | TypeTraitObject, TypeTuple, |
1085 | }; |
1086 | use proc_macro2::TokenStream; |
1087 | use quote::{ToTokens, TokenStreamExt}; |
1088 | |
1089 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1090 | impl ToTokens for TypeSlice { |
1091 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1092 | self.bracket_token.surround(tokens, |tokens| { |
1093 | self.elem.to_tokens(tokens); |
1094 | }); |
1095 | } |
1096 | } |
1097 | |
1098 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1099 | impl ToTokens for TypeArray { |
1100 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1101 | self.bracket_token.surround(tokens, |tokens| { |
1102 | self.elem.to_tokens(tokens); |
1103 | self.semi_token.to_tokens(tokens); |
1104 | self.len.to_tokens(tokens); |
1105 | }); |
1106 | } |
1107 | } |
1108 | |
1109 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1110 | impl ToTokens for TypePtr { |
1111 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1112 | self.star_token.to_tokens(tokens); |
1113 | match &self.mutability { |
1114 | Some(tok) => tok.to_tokens(tokens), |
1115 | None => { |
1116 | TokensOrDefault(&self.const_token).to_tokens(tokens); |
1117 | } |
1118 | } |
1119 | self.elem.to_tokens(tokens); |
1120 | } |
1121 | } |
1122 | |
1123 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1124 | impl ToTokens for TypeReference { |
1125 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1126 | self.and_token.to_tokens(tokens); |
1127 | self.lifetime.to_tokens(tokens); |
1128 | self.mutability.to_tokens(tokens); |
1129 | self.elem.to_tokens(tokens); |
1130 | } |
1131 | } |
1132 | |
1133 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1134 | impl ToTokens for TypeBareFn { |
1135 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1136 | self.lifetimes.to_tokens(tokens); |
1137 | self.unsafety.to_tokens(tokens); |
1138 | self.abi.to_tokens(tokens); |
1139 | self.fn_token.to_tokens(tokens); |
1140 | self.paren_token.surround(tokens, |tokens| { |
1141 | self.inputs.to_tokens(tokens); |
1142 | if let Some(variadic) = &self.variadic { |
1143 | if !self.inputs.empty_or_trailing() { |
1144 | let span = variadic.dots.spans[0]; |
1145 | Token.to_tokens(tokens); |
1146 | } |
1147 | variadic.to_tokens(tokens); |
1148 | } |
1149 | }); |
1150 | self.output.to_tokens(tokens); |
1151 | } |
1152 | } |
1153 | |
1154 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1155 | impl ToTokens for TypeNever { |
1156 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1157 | self.bang_token.to_tokens(tokens); |
1158 | } |
1159 | } |
1160 | |
1161 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1162 | impl ToTokens for TypeTuple { |
1163 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1164 | self.paren_token.surround(tokens, |tokens| { |
1165 | self.elems.to_tokens(tokens); |
1166 | // If we only have one argument, we need a trailing comma to |
1167 | // distinguish TypeTuple from TypeParen. |
1168 | if self.elems.len() == 1 && !self.elems.trailing_punct() { |
1169 | <Token![,]>::default().to_tokens(tokens); |
1170 | } |
1171 | }); |
1172 | } |
1173 | } |
1174 | |
1175 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1176 | impl ToTokens for TypePath { |
1177 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1178 | path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::AsWritten); |
1179 | } |
1180 | } |
1181 | |
1182 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1183 | impl ToTokens for TypeTraitObject { |
1184 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1185 | self.dyn_token.to_tokens(tokens); |
1186 | self.bounds.to_tokens(tokens); |
1187 | } |
1188 | } |
1189 | |
1190 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1191 | impl ToTokens for TypeImplTrait { |
1192 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1193 | self.impl_token.to_tokens(tokens); |
1194 | self.bounds.to_tokens(tokens); |
1195 | } |
1196 | } |
1197 | |
1198 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1199 | impl ToTokens for TypeGroup { |
1200 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1201 | self.group_token.surround(tokens, |tokens| { |
1202 | self.elem.to_tokens(tokens); |
1203 | }); |
1204 | } |
1205 | } |
1206 | |
1207 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1208 | impl ToTokens for TypeParen { |
1209 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1210 | self.paren_token.surround(tokens, |tokens| { |
1211 | self.elem.to_tokens(tokens); |
1212 | }); |
1213 | } |
1214 | } |
1215 | |
1216 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1217 | impl ToTokens for TypeInfer { |
1218 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1219 | self.underscore_token.to_tokens(tokens); |
1220 | } |
1221 | } |
1222 | |
1223 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1224 | impl ToTokens for TypeMacro { |
1225 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1226 | self.mac.to_tokens(tokens); |
1227 | } |
1228 | } |
1229 | |
1230 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1231 | impl ToTokens for ReturnType { |
1232 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1233 | match self { |
1234 | ReturnType::Default => {} |
1235 | ReturnType::Type(arrow, ty) => { |
1236 | arrow.to_tokens(tokens); |
1237 | ty.to_tokens(tokens); |
1238 | } |
1239 | } |
1240 | } |
1241 | } |
1242 | |
1243 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1244 | impl ToTokens for BareFnArg { |
1245 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1246 | tokens.append_all(self.attrs.outer()); |
1247 | if let Some((name, colon)) = &self.name { |
1248 | name.to_tokens(tokens); |
1249 | colon.to_tokens(tokens); |
1250 | } |
1251 | self.ty.to_tokens(tokens); |
1252 | } |
1253 | } |
1254 | |
1255 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1256 | impl ToTokens for BareVariadic { |
1257 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1258 | tokens.append_all(self.attrs.outer()); |
1259 | if let Some((name, colon)) = &self.name { |
1260 | name.to_tokens(tokens); |
1261 | colon.to_tokens(tokens); |
1262 | } |
1263 | self.dots.to_tokens(tokens); |
1264 | self.comma.to_tokens(tokens); |
1265 | } |
1266 | } |
1267 | |
1268 | #[cfg_attr (docsrs, doc(cfg(feature = "printing" )))] |
1269 | impl ToTokens for Abi { |
1270 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1271 | self.extern_token.to_tokens(tokens); |
1272 | self.name.to_tokens(tokens); |
1273 | } |
1274 | } |
1275 | } |
1276 | |