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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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 (doc_cfg, 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![<](group.group_token.span), |
335 | position: 0, |
336 | as_token: None, |
337 | gt_token: Token![>](group.group_token.span), |
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(input.parse()?); |
406 | } |
407 | bounds |
408 | }, |
409 | })); |
410 | } |
411 | let mut first: Type = content.parse()?; |
412 | if content.peek(Token![,]) { |
413 | return Ok(Type::Tuple(TypeTuple { |
414 | paren_token, |
415 | elems: { |
416 | let mut elems = Punctuated::new(); |
417 | elems.push_value(first); |
418 | elems.push_punct(content.parse()?); |
419 | while !content.is_empty() { |
420 | elems.push_value(content.parse()?); |
421 | if content.is_empty() { |
422 | break; |
423 | } |
424 | elems.push_punct(content.parse()?); |
425 | } |
426 | elems |
427 | }, |
428 | })); |
429 | } |
430 | if allow_plus && input.peek(Token![+]) { |
431 | loop { |
432 | let first = match first { |
433 | Type::Path(TypePath { qself: None, path }) => { |
434 | TypeParamBound::Trait(TraitBound { |
435 | paren_token: Some(paren_token), |
436 | modifier: TraitBoundModifier::None, |
437 | lifetimes: None, |
438 | path, |
439 | }) |
440 | } |
441 | Type::TraitObject(TypeTraitObject { |
442 | dyn_token: None, |
443 | bounds, |
444 | }) => { |
445 | if bounds.len() > 1 || bounds.trailing_punct() { |
446 | first = Type::TraitObject(TypeTraitObject { |
447 | dyn_token: None, |
448 | bounds, |
449 | }); |
450 | break; |
451 | } |
452 | match bounds.into_iter().next().unwrap() { |
453 | TypeParamBound::Trait(trait_bound) => { |
454 | TypeParamBound::Trait(TraitBound { |
455 | paren_token: Some(paren_token), |
456 | ..trait_bound |
457 | }) |
458 | } |
459 | other @ (TypeParamBound::Lifetime(_) |
460 | | TypeParamBound::Verbatim(_)) => other, |
461 | } |
462 | } |
463 | _ => break, |
464 | }; |
465 | return Ok(Type::TraitObject(TypeTraitObject { |
466 | dyn_token: None, |
467 | bounds: { |
468 | let mut bounds = Punctuated::new(); |
469 | bounds.push_value(first); |
470 | while let Some(plus) = input.parse()? { |
471 | bounds.push_punct(plus); |
472 | bounds.push_value(input.parse()?); |
473 | } |
474 | bounds |
475 | }, |
476 | })); |
477 | } |
478 | } |
479 | Ok(Type::Paren(TypeParen { |
480 | paren_token, |
481 | elem: Box::new(first), |
482 | })) |
483 | } else if lookahead.peek(Token![fn]) |
484 | || lookahead.peek(Token![unsafe]) |
485 | || lookahead.peek(Token![extern]) |
486 | { |
487 | let mut bare_fn: TypeBareFn = input.parse()?; |
488 | bare_fn.lifetimes = lifetimes; |
489 | Ok(Type::BareFn(bare_fn)) |
490 | } else if lookahead.peek(Ident) |
491 | || input.peek(Token![super]) |
492 | || input.peek(Token![self]) |
493 | || input.peek(Token![Self]) |
494 | || input.peek(Token![crate]) |
495 | || lookahead.peek(Token![::]) |
496 | || lookahead.peek(Token![<]) |
497 | { |
498 | let ty: TypePath = input.parse()?; |
499 | if ty.qself.is_some() { |
500 | return Ok(Type::Path(ty)); |
501 | } |
502 | |
503 | if input.peek(Token![!]) && !input.peek(Token![!=]) && ty.path.is_mod_style() { |
504 | let bang_token: Token![!] = input.parse()?; |
505 | let (delimiter, tokens) = mac::parse_delimiter(input)?; |
506 | return Ok(Type::Macro(TypeMacro { |
507 | mac: Macro { |
508 | path: ty.path, |
509 | bang_token, |
510 | delimiter, |
511 | tokens, |
512 | }, |
513 | })); |
514 | } |
515 | |
516 | if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { |
517 | let mut bounds = Punctuated::new(); |
518 | bounds.push_value(TypeParamBound::Trait(TraitBound { |
519 | paren_token: None, |
520 | modifier: TraitBoundModifier::None, |
521 | lifetimes, |
522 | path: ty.path, |
523 | })); |
524 | if allow_plus { |
525 | while input.peek(Token![+]) { |
526 | bounds.push_punct(input.parse()?); |
527 | if !(input.peek(Ident::peek_any) |
528 | || input.peek(Token![::]) |
529 | || input.peek(Token![?]) |
530 | || input.peek(Lifetime) |
531 | || input.peek(token::Paren)) |
532 | { |
533 | break; |
534 | } |
535 | bounds.push_value(input.parse()?); |
536 | } |
537 | } |
538 | return Ok(Type::TraitObject(TypeTraitObject { |
539 | dyn_token: None, |
540 | bounds, |
541 | })); |
542 | } |
543 | |
544 | Ok(Type::Path(ty)) |
545 | } else if lookahead.peek(Token![dyn]) { |
546 | let dyn_token: Token![dyn] = input.parse()?; |
547 | let dyn_span = dyn_token.span; |
548 | let star_token: Option<Token![*]> = input.parse()?; |
549 | let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?; |
550 | return Ok(if star_token.is_some() { |
551 | Type::Verbatim(verbatim::between(&begin, input)) |
552 | } else { |
553 | Type::TraitObject(TypeTraitObject { |
554 | dyn_token: Some(dyn_token), |
555 | bounds, |
556 | }) |
557 | }); |
558 | } else if lookahead.peek(token::Bracket) { |
559 | let content; |
560 | let bracket_token = bracketed!(content in input); |
561 | let elem: Type = content.parse()?; |
562 | if content.peek(Token![;]) { |
563 | Ok(Type::Array(TypeArray { |
564 | bracket_token, |
565 | elem: Box::new(elem), |
566 | semi_token: content.parse()?, |
567 | len: content.parse()?, |
568 | })) |
569 | } else { |
570 | Ok(Type::Slice(TypeSlice { |
571 | bracket_token, |
572 | elem: Box::new(elem), |
573 | })) |
574 | } |
575 | } else if lookahead.peek(Token![*]) { |
576 | input.parse().map(Type::Ptr) |
577 | } else if lookahead.peek(Token![&]) { |
578 | input.parse().map(Type::Reference) |
579 | } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { |
580 | input.parse().map(Type::Never) |
581 | } else if lookahead.peek(Token![impl]) { |
582 | TypeImplTrait::parse(input, allow_plus).map(Type::ImplTrait) |
583 | } else if lookahead.peek(Token![_]) { |
584 | input.parse().map(Type::Infer) |
585 | } else if lookahead.peek(Lifetime) { |
586 | input.parse().map(Type::TraitObject) |
587 | } else { |
588 | Err(lookahead.error()) |
589 | } |
590 | } |
591 | |
592 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
593 | impl Parse for TypeSlice { |
594 | fn parse(input: ParseStream) -> Result<Self> { |
595 | let content; |
596 | Ok(TypeSlice { |
597 | bracket_token: bracketed!(content in input), |
598 | elem: content.parse()?, |
599 | }) |
600 | } |
601 | } |
602 | |
603 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
604 | impl Parse for TypeArray { |
605 | fn parse(input: ParseStream) -> Result<Self> { |
606 | let content; |
607 | Ok(TypeArray { |
608 | bracket_token: bracketed!(content in input), |
609 | elem: content.parse()?, |
610 | semi_token: content.parse()?, |
611 | len: content.parse()?, |
612 | }) |
613 | } |
614 | } |
615 | |
616 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
617 | impl Parse for TypePtr { |
618 | fn parse(input: ParseStream) -> Result<Self> { |
619 | let star_token: Token![*] = input.parse()?; |
620 | |
621 | let lookahead = input.lookahead1(); |
622 | let (const_token, mutability) = if lookahead.peek(Token![const]) { |
623 | (Some(input.parse()?), None) |
624 | } else if lookahead.peek(Token![mut]) { |
625 | (None, Some(input.parse()?)) |
626 | } else { |
627 | return Err(lookahead.error()); |
628 | }; |
629 | |
630 | Ok(TypePtr { |
631 | star_token, |
632 | const_token, |
633 | mutability, |
634 | elem: Box::new(input.call(Type::without_plus)?), |
635 | }) |
636 | } |
637 | } |
638 | |
639 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
640 | impl Parse for TypeReference { |
641 | fn parse(input: ParseStream) -> Result<Self> { |
642 | Ok(TypeReference { |
643 | and_token: input.parse()?, |
644 | lifetime: input.parse()?, |
645 | mutability: input.parse()?, |
646 | // & binds tighter than +, so we don't allow + here. |
647 | elem: Box::new(input.call(Type::without_plus)?), |
648 | }) |
649 | } |
650 | } |
651 | |
652 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
653 | impl Parse for TypeBareFn { |
654 | fn parse(input: ParseStream) -> Result<Self> { |
655 | let args; |
656 | let mut variadic = None; |
657 | |
658 | Ok(TypeBareFn { |
659 | lifetimes: input.parse()?, |
660 | unsafety: input.parse()?, |
661 | abi: input.parse()?, |
662 | fn_token: input.parse()?, |
663 | paren_token: parenthesized!(args in input), |
664 | inputs: { |
665 | let mut inputs = Punctuated::new(); |
666 | |
667 | while !args.is_empty() { |
668 | let attrs = args.call(Attribute::parse_outer)?; |
669 | |
670 | if inputs.empty_or_trailing() |
671 | && (args.peek(Token![...]) |
672 | || args.peek(Ident) |
673 | && args.peek2(Token![:]) |
674 | && args.peek3(Token![...])) |
675 | { |
676 | variadic = Some(parse_bare_variadic(&args, attrs)?); |
677 | break; |
678 | } |
679 | |
680 | let allow_self = inputs.is_empty(); |
681 | let arg = parse_bare_fn_arg(&args, allow_self)?; |
682 | inputs.push_value(BareFnArg { attrs, ..arg }); |
683 | if args.is_empty() { |
684 | break; |
685 | } |
686 | |
687 | let comma = args.parse()?; |
688 | inputs.push_punct(comma); |
689 | } |
690 | |
691 | inputs |
692 | }, |
693 | variadic, |
694 | output: input.call(ReturnType::without_plus)?, |
695 | }) |
696 | } |
697 | } |
698 | |
699 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
700 | impl Parse for TypeNever { |
701 | fn parse(input: ParseStream) -> Result<Self> { |
702 | Ok(TypeNever { |
703 | bang_token: input.parse()?, |
704 | }) |
705 | } |
706 | } |
707 | |
708 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
709 | impl Parse for TypeInfer { |
710 | fn parse(input: ParseStream) -> Result<Self> { |
711 | Ok(TypeInfer { |
712 | underscore_token: input.parse()?, |
713 | }) |
714 | } |
715 | } |
716 | |
717 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
718 | impl Parse for TypeTuple { |
719 | fn parse(input: ParseStream) -> Result<Self> { |
720 | let content; |
721 | let paren_token = parenthesized!(content in input); |
722 | |
723 | if content.is_empty() { |
724 | return Ok(TypeTuple { |
725 | paren_token, |
726 | elems: Punctuated::new(), |
727 | }); |
728 | } |
729 | |
730 | let first: Type = content.parse()?; |
731 | Ok(TypeTuple { |
732 | paren_token, |
733 | elems: { |
734 | let mut elems = Punctuated::new(); |
735 | elems.push_value(first); |
736 | elems.push_punct(content.parse()?); |
737 | while !content.is_empty() { |
738 | elems.push_value(content.parse()?); |
739 | if content.is_empty() { |
740 | break; |
741 | } |
742 | elems.push_punct(content.parse()?); |
743 | } |
744 | elems |
745 | }, |
746 | }) |
747 | } |
748 | } |
749 | |
750 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
751 | impl Parse for TypeMacro { |
752 | fn parse(input: ParseStream) -> Result<Self> { |
753 | Ok(TypeMacro { |
754 | mac: input.parse()?, |
755 | }) |
756 | } |
757 | } |
758 | |
759 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
760 | impl Parse for TypePath { |
761 | fn parse(input: ParseStream) -> Result<Self> { |
762 | let expr_style = false; |
763 | let (qself, path) = path::parsing::qpath(input, expr_style)?; |
764 | Ok(TypePath { qself, path }) |
765 | } |
766 | } |
767 | |
768 | impl ReturnType { |
769 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
770 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
771 | let allow_plus = false; |
772 | Self::parse(input, allow_plus) |
773 | } |
774 | |
775 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
776 | if input.peek(Token![->]) { |
777 | let arrow = input.parse()?; |
778 | let allow_group_generic = true; |
779 | let ty = ambig_ty(input, allow_plus, allow_group_generic)?; |
780 | Ok(ReturnType::Type(arrow, Box::new(ty))) |
781 | } else { |
782 | Ok(ReturnType::Default) |
783 | } |
784 | } |
785 | } |
786 | |
787 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
788 | impl Parse for ReturnType { |
789 | fn parse(input: ParseStream) -> Result<Self> { |
790 | let allow_plus = true; |
791 | Self::parse(input, allow_plus) |
792 | } |
793 | } |
794 | |
795 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
796 | impl Parse for TypeTraitObject { |
797 | fn parse(input: ParseStream) -> Result<Self> { |
798 | let allow_plus = true; |
799 | Self::parse(input, allow_plus) |
800 | } |
801 | } |
802 | |
803 | impl TypeTraitObject { |
804 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
805 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
806 | let allow_plus = false; |
807 | Self::parse(input, allow_plus) |
808 | } |
809 | |
810 | // Only allow multiple trait references if allow_plus is true. |
811 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
812 | let dyn_token: Option<Token![dyn]> = input.parse()?; |
813 | let dyn_span = match &dyn_token { |
814 | Some(token) => token.span, |
815 | None => input.span(), |
816 | }; |
817 | let bounds = Self::parse_bounds(dyn_span, input, allow_plus)?; |
818 | Ok(TypeTraitObject { dyn_token, bounds }) |
819 | } |
820 | |
821 | fn parse_bounds( |
822 | dyn_span: Span, |
823 | input: ParseStream, |
824 | allow_plus: bool, |
825 | ) -> Result<Punctuated<TypeParamBound, Token![+]>> { |
826 | let bounds = TypeParamBound::parse_multiple(input, allow_plus)?; |
827 | let mut last_lifetime_span = None; |
828 | let mut at_least_one_trait = false; |
829 | for bound in &bounds { |
830 | match bound { |
831 | TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => { |
832 | at_least_one_trait = true; |
833 | break; |
834 | } |
835 | TypeParamBound::Lifetime(lifetime) => { |
836 | last_lifetime_span = Some(lifetime.ident.span()); |
837 | } |
838 | } |
839 | } |
840 | // Just lifetimes like `'a + 'b` is not a TraitObject. |
841 | if !at_least_one_trait { |
842 | let msg = "at least one trait is required for an object type" ; |
843 | return Err(error::new2(dyn_span, last_lifetime_span.unwrap(), msg)); |
844 | } |
845 | Ok(bounds) |
846 | } |
847 | } |
848 | |
849 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
850 | impl Parse for TypeImplTrait { |
851 | fn parse(input: ParseStream) -> Result<Self> { |
852 | let allow_plus = true; |
853 | Self::parse(input, allow_plus) |
854 | } |
855 | } |
856 | |
857 | impl TypeImplTrait { |
858 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
859 | pub fn without_plus(input: ParseStream) -> Result<Self> { |
860 | let allow_plus = false; |
861 | Self::parse(input, allow_plus) |
862 | } |
863 | |
864 | pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
865 | let impl_token: Token![impl] = input.parse()?; |
866 | let bounds = TypeParamBound::parse_multiple(input, allow_plus)?; |
867 | let mut last_lifetime_span = None; |
868 | let mut at_least_one_trait = false; |
869 | for bound in &bounds { |
870 | match bound { |
871 | TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => { |
872 | at_least_one_trait = true; |
873 | break; |
874 | } |
875 | TypeParamBound::Lifetime(lifetime) => { |
876 | last_lifetime_span = Some(lifetime.ident.span()); |
877 | } |
878 | } |
879 | } |
880 | if !at_least_one_trait { |
881 | let msg = "at least one trait must be specified" ; |
882 | return Err(error::new2( |
883 | impl_token.span, |
884 | last_lifetime_span.unwrap(), |
885 | msg, |
886 | )); |
887 | } |
888 | Ok(TypeImplTrait { impl_token, bounds }) |
889 | } |
890 | } |
891 | |
892 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
893 | impl Parse for TypeGroup { |
894 | fn parse(input: ParseStream) -> Result<Self> { |
895 | let group = crate::group::parse_group(input)?; |
896 | Ok(TypeGroup { |
897 | group_token: group.token, |
898 | elem: group.content.parse()?, |
899 | }) |
900 | } |
901 | } |
902 | |
903 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
904 | impl Parse for TypeParen { |
905 | fn parse(input: ParseStream) -> Result<Self> { |
906 | let allow_plus = false; |
907 | Self::parse(input, allow_plus) |
908 | } |
909 | } |
910 | |
911 | impl TypeParen { |
912 | fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { |
913 | let content; |
914 | Ok(TypeParen { |
915 | paren_token: parenthesized!(content in input), |
916 | elem: Box::new({ |
917 | let allow_group_generic = true; |
918 | ambig_ty(&content, allow_plus, allow_group_generic)? |
919 | }), |
920 | }) |
921 | } |
922 | } |
923 | |
924 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
925 | impl Parse for BareFnArg { |
926 | fn parse(input: ParseStream) -> Result<Self> { |
927 | let allow_self = false; |
928 | parse_bare_fn_arg(input, allow_self) |
929 | } |
930 | } |
931 | |
932 | fn parse_bare_fn_arg(input: ParseStream, allow_self: bool) -> Result<BareFnArg> { |
933 | let attrs = input.call(Attribute::parse_outer)?; |
934 | |
935 | let begin = input.fork(); |
936 | |
937 | let has_mut_self = allow_self && input.peek(Token![mut]) && input.peek2(Token![self]); |
938 | if has_mut_self { |
939 | input.parse::<Token![mut]>()?; |
940 | } |
941 | |
942 | let mut has_self = false; |
943 | let mut name = if (input.peek(Ident) || input.peek(Token![_]) || { |
944 | has_self = allow_self && input.peek(Token![self]); |
945 | has_self |
946 | }) && input.peek2(Token![:]) |
947 | && !input.peek2(Token![::]) |
948 | { |
949 | let name = input.call(Ident::parse_any)?; |
950 | let colon: Token![:] = input.parse()?; |
951 | Some((name, colon)) |
952 | } else { |
953 | has_self = false; |
954 | None |
955 | }; |
956 | |
957 | let ty = if allow_self && !has_self && input.peek(Token![mut]) && input.peek2(Token![self]) |
958 | { |
959 | input.parse::<Token![mut]>()?; |
960 | input.parse::<Token![self]>()?; |
961 | None |
962 | } else if has_mut_self && name.is_none() { |
963 | input.parse::<Token![self]>()?; |
964 | None |
965 | } else { |
966 | Some(input.parse()?) |
967 | }; |
968 | |
969 | let ty = match ty { |
970 | Some(ty) if !has_mut_self => ty, |
971 | _ => { |
972 | name = None; |
973 | Type::Verbatim(verbatim::between(&begin, input)) |
974 | } |
975 | }; |
976 | |
977 | Ok(BareFnArg { attrs, name, ty }) |
978 | } |
979 | |
980 | fn parse_bare_variadic(input: ParseStream, attrs: Vec<Attribute>) -> Result<BareVariadic> { |
981 | Ok(BareVariadic { |
982 | attrs, |
983 | name: if input.peek(Ident) || input.peek(Token![_]) { |
984 | let name = input.call(Ident::parse_any)?; |
985 | let colon: Token![:] = input.parse()?; |
986 | Some((name, colon)) |
987 | } else { |
988 | None |
989 | }, |
990 | dots: input.parse()?, |
991 | comma: input.parse()?, |
992 | }) |
993 | } |
994 | |
995 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
996 | impl Parse for Abi { |
997 | fn parse(input: ParseStream) -> Result<Self> { |
998 | Ok(Abi { |
999 | extern_token: input.parse()?, |
1000 | name: input.parse()?, |
1001 | }) |
1002 | } |
1003 | } |
1004 | |
1005 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
1006 | impl Parse for Option<Abi> { |
1007 | fn parse(input: ParseStream) -> Result<Self> { |
1008 | if input.peek(Token![extern]) { |
1009 | input.parse().map(Some) |
1010 | } else { |
1011 | Ok(None) |
1012 | } |
1013 | } |
1014 | } |
1015 | } |
1016 | |
1017 | #[cfg (feature = "printing" )] |
1018 | mod printing { |
1019 | use crate::attr::FilterAttrs; |
1020 | use crate::path; |
1021 | use crate::print::TokensOrDefault; |
1022 | use crate::ty::{ |
1023 | Abi, BareFnArg, BareVariadic, ReturnType, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, |
1024 | TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, |
1025 | TypeTraitObject, TypeTuple, |
1026 | }; |
1027 | use proc_macro2::TokenStream; |
1028 | use quote::{ToTokens, TokenStreamExt}; |
1029 | |
1030 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1031 | impl ToTokens for TypeSlice { |
1032 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1033 | self.bracket_token.surround(tokens, |tokens| { |
1034 | self.elem.to_tokens(tokens); |
1035 | }); |
1036 | } |
1037 | } |
1038 | |
1039 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1040 | impl ToTokens for TypeArray { |
1041 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1042 | self.bracket_token.surround(tokens, |tokens| { |
1043 | self.elem.to_tokens(tokens); |
1044 | self.semi_token.to_tokens(tokens); |
1045 | self.len.to_tokens(tokens); |
1046 | }); |
1047 | } |
1048 | } |
1049 | |
1050 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1051 | impl ToTokens for TypePtr { |
1052 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1053 | self.star_token.to_tokens(tokens); |
1054 | match &self.mutability { |
1055 | Some(tok) => tok.to_tokens(tokens), |
1056 | None => { |
1057 | TokensOrDefault(&self.const_token).to_tokens(tokens); |
1058 | } |
1059 | } |
1060 | self.elem.to_tokens(tokens); |
1061 | } |
1062 | } |
1063 | |
1064 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1065 | impl ToTokens for TypeReference { |
1066 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1067 | self.and_token.to_tokens(tokens); |
1068 | self.lifetime.to_tokens(tokens); |
1069 | self.mutability.to_tokens(tokens); |
1070 | self.elem.to_tokens(tokens); |
1071 | } |
1072 | } |
1073 | |
1074 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1075 | impl ToTokens for TypeBareFn { |
1076 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1077 | self.lifetimes.to_tokens(tokens); |
1078 | self.unsafety.to_tokens(tokens); |
1079 | self.abi.to_tokens(tokens); |
1080 | self.fn_token.to_tokens(tokens); |
1081 | self.paren_token.surround(tokens, |tokens| { |
1082 | self.inputs.to_tokens(tokens); |
1083 | if let Some(variadic) = &self.variadic { |
1084 | if !self.inputs.empty_or_trailing() { |
1085 | let span = variadic.dots.spans[0]; |
1086 | Token![,](span).to_tokens(tokens); |
1087 | } |
1088 | variadic.to_tokens(tokens); |
1089 | } |
1090 | }); |
1091 | self.output.to_tokens(tokens); |
1092 | } |
1093 | } |
1094 | |
1095 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1096 | impl ToTokens for TypeNever { |
1097 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1098 | self.bang_token.to_tokens(tokens); |
1099 | } |
1100 | } |
1101 | |
1102 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1103 | impl ToTokens for TypeTuple { |
1104 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1105 | self.paren_token.surround(tokens, |tokens| { |
1106 | self.elems.to_tokens(tokens); |
1107 | // If we only have one argument, we need a trailing comma to |
1108 | // distinguish TypeTuple from TypeParen. |
1109 | if self.elems.len() == 1 && !self.elems.trailing_punct() { |
1110 | <Token![,]>::default().to_tokens(tokens); |
1111 | } |
1112 | }); |
1113 | } |
1114 | } |
1115 | |
1116 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1117 | impl ToTokens for TypePath { |
1118 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1119 | path::printing::print_path(tokens, &self.qself, &self.path); |
1120 | } |
1121 | } |
1122 | |
1123 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1124 | impl ToTokens for TypeTraitObject { |
1125 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1126 | self.dyn_token.to_tokens(tokens); |
1127 | self.bounds.to_tokens(tokens); |
1128 | } |
1129 | } |
1130 | |
1131 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1132 | impl ToTokens for TypeImplTrait { |
1133 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1134 | self.impl_token.to_tokens(tokens); |
1135 | self.bounds.to_tokens(tokens); |
1136 | } |
1137 | } |
1138 | |
1139 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1140 | impl ToTokens for TypeGroup { |
1141 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1142 | self.group_token.surround(tokens, |tokens| { |
1143 | self.elem.to_tokens(tokens); |
1144 | }); |
1145 | } |
1146 | } |
1147 | |
1148 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1149 | impl ToTokens for TypeParen { |
1150 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1151 | self.paren_token.surround(tokens, |tokens| { |
1152 | self.elem.to_tokens(tokens); |
1153 | }); |
1154 | } |
1155 | } |
1156 | |
1157 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1158 | impl ToTokens for TypeInfer { |
1159 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1160 | self.underscore_token.to_tokens(tokens); |
1161 | } |
1162 | } |
1163 | |
1164 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1165 | impl ToTokens for TypeMacro { |
1166 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1167 | self.mac.to_tokens(tokens); |
1168 | } |
1169 | } |
1170 | |
1171 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1172 | impl ToTokens for ReturnType { |
1173 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1174 | match self { |
1175 | ReturnType::Default => {} |
1176 | ReturnType::Type(arrow, ty) => { |
1177 | arrow.to_tokens(tokens); |
1178 | ty.to_tokens(tokens); |
1179 | } |
1180 | } |
1181 | } |
1182 | } |
1183 | |
1184 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1185 | impl ToTokens for BareFnArg { |
1186 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1187 | tokens.append_all(self.attrs.outer()); |
1188 | if let Some((name, colon)) = &self.name { |
1189 | name.to_tokens(tokens); |
1190 | colon.to_tokens(tokens); |
1191 | } |
1192 | self.ty.to_tokens(tokens); |
1193 | } |
1194 | } |
1195 | |
1196 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1197 | impl ToTokens for BareVariadic { |
1198 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1199 | tokens.append_all(self.attrs.outer()); |
1200 | if let Some((name, colon)) = &self.name { |
1201 | name.to_tokens(tokens); |
1202 | colon.to_tokens(tokens); |
1203 | } |
1204 | self.dots.to_tokens(tokens); |
1205 | self.comma.to_tokens(tokens); |
1206 | } |
1207 | } |
1208 | |
1209 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
1210 | impl ToTokens for Abi { |
1211 | fn to_tokens(&self, tokens: &mut TokenStream) { |
1212 | self.extern_token.to_tokens(tokens); |
1213 | self.name.to_tokens(tokens); |
1214 | } |
1215 | } |
1216 | } |
1217 | |