• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[macro_use]
2 mod macros;
3 
4 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
5 use quote::quote;
6 use std::iter::FromIterator;
7 use syn::Type;
8 
9 #[test]
test_mut_self()10 fn test_mut_self() {
11     syn::parse_str::<Type>("fn(mut self)").unwrap();
12     syn::parse_str::<Type>("fn(mut self,)").unwrap();
13     syn::parse_str::<Type>("fn(mut self: ())").unwrap();
14     syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
15     syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
16     syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
17 }
18 
19 #[test]
test_macro_variable_type()20 fn test_macro_variable_type() {
21     // mimics the token stream corresponding to `$ty<T>`
22     let tokens = TokenStream::from_iter(vec![
23         TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
24         TokenTree::Punct(Punct::new('<', Spacing::Alone)),
25         TokenTree::Ident(Ident::new("T", Span::call_site())),
26         TokenTree::Punct(Punct::new('>', Spacing::Alone)),
27     ]);
28 
29     snapshot!(tokens as Type, @r###"
30     Type::Path {
31         path: Path {
32             segments: [
33                 PathSegment {
34                     ident: "ty",
35                     arguments: PathArguments::AngleBracketed {
36                         args: [
37                             Type(Type::Path {
38                                 path: Path {
39                                     segments: [
40                                         PathSegment {
41                                             ident: "T",
42                                             arguments: None,
43                                         },
44                                     ],
45                                 },
46                             }),
47                         ],
48                     },
49                 },
50             ],
51         },
52     }
53     "###);
54 
55     // mimics the token stream corresponding to `$ty::<T>`
56     let tokens = TokenStream::from_iter(vec![
57         TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
58         TokenTree::Punct(Punct::new(':', Spacing::Joint)),
59         TokenTree::Punct(Punct::new(':', Spacing::Alone)),
60         TokenTree::Punct(Punct::new('<', Spacing::Alone)),
61         TokenTree::Ident(Ident::new("T", Span::call_site())),
62         TokenTree::Punct(Punct::new('>', Spacing::Alone)),
63     ]);
64 
65     snapshot!(tokens as Type, @r###"
66     Type::Path {
67         path: Path {
68             segments: [
69                 PathSegment {
70                     ident: "ty",
71                     arguments: PathArguments::AngleBracketed {
72                         colon2_token: Some,
73                         args: [
74                             Type(Type::Path {
75                                 path: Path {
76                                     segments: [
77                                         PathSegment {
78                                             ident: "T",
79                                             arguments: None,
80                                         },
81                                     ],
82                                 },
83                             }),
84                         ],
85                     },
86                 },
87             ],
88         },
89     }
90     "###);
91 }
92 
93 #[test]
test_group_angle_brackets()94 fn test_group_angle_brackets() {
95     // mimics the token stream corresponding to `Option<$ty>`
96     let tokens = TokenStream::from_iter(vec![
97         TokenTree::Ident(Ident::new("Option", Span::call_site())),
98         TokenTree::Punct(Punct::new('<', Spacing::Alone)),
99         TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
100         TokenTree::Punct(Punct::new('>', Spacing::Alone)),
101     ]);
102 
103     snapshot!(tokens as Type, @r###"
104     Type::Path {
105         path: Path {
106             segments: [
107                 PathSegment {
108                     ident: "Option",
109                     arguments: PathArguments::AngleBracketed {
110                         args: [
111                             Type(Type::Group {
112                                 elem: Type::Path {
113                                     path: Path {
114                                         segments: [
115                                             PathSegment {
116                                                 ident: "Vec",
117                                                 arguments: PathArguments::AngleBracketed {
118                                                     args: [
119                                                         Type(Type::Path {
120                                                             path: Path {
121                                                                 segments: [
122                                                                     PathSegment {
123                                                                         ident: "u8",
124                                                                         arguments: None,
125                                                                     },
126                                                                 ],
127                                                             },
128                                                         }),
129                                                     ],
130                                                 },
131                                             },
132                                         ],
133                                     },
134                                 },
135                             }),
136                         ],
137                     },
138                 },
139             ],
140         },
141     }
142     "###);
143 }
144 
145 #[test]
test_group_colons()146 fn test_group_colons() {
147     // mimics the token stream corresponding to `$ty::Item`
148     let tokens = TokenStream::from_iter(vec![
149         TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
150         TokenTree::Punct(Punct::new(':', Spacing::Joint)),
151         TokenTree::Punct(Punct::new(':', Spacing::Alone)),
152         TokenTree::Ident(Ident::new("Item", Span::call_site())),
153     ]);
154 
155     snapshot!(tokens as Type, @r###"
156     Type::Path {
157         path: Path {
158             segments: [
159                 PathSegment {
160                     ident: "Vec",
161                     arguments: PathArguments::AngleBracketed {
162                         args: [
163                             Type(Type::Path {
164                                 path: Path {
165                                     segments: [
166                                         PathSegment {
167                                             ident: "u8",
168                                             arguments: None,
169                                         },
170                                     ],
171                                 },
172                             }),
173                         ],
174                     },
175                 },
176                 PathSegment {
177                     ident: "Item",
178                     arguments: None,
179                 },
180             ],
181         },
182     }
183     "###);
184 
185     let tokens = TokenStream::from_iter(vec![
186         TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })),
187         TokenTree::Punct(Punct::new(':', Spacing::Joint)),
188         TokenTree::Punct(Punct::new(':', Spacing::Alone)),
189         TokenTree::Ident(Ident::new("Element", Span::call_site())),
190     ]);
191 
192     snapshot!(tokens as Type, @r###"
193     Type::Path {
194         qself: Some(QSelf {
195             ty: Type::Slice {
196                 elem: Type::Path {
197                     path: Path {
198                         segments: [
199                             PathSegment {
200                                 ident: "T",
201                                 arguments: None,
202                             },
203                         ],
204                     },
205                 },
206             },
207             position: 0,
208         }),
209         path: Path {
210             leading_colon: Some,
211             segments: [
212                 PathSegment {
213                     ident: "Element",
214                     arguments: None,
215                 },
216             ],
217         },
218     }
219     "###);
220 }
221 
222 #[test]
test_trait_object()223 fn test_trait_object() {
224     let tokens = quote!(dyn for<'a> Trait<'a> + 'static);
225     snapshot!(tokens as Type, @r###"
226     Type::TraitObject {
227         dyn_token: Some,
228         bounds: [
229             Trait(TraitBound {
230                 modifier: None,
231                 lifetimes: Some(BoundLifetimes {
232                     lifetimes: [
233                         LifetimeDef {
234                             lifetime: Lifetime {
235                                 ident: "a",
236                             },
237                         },
238                     ],
239                 }),
240                 path: Path {
241                     segments: [
242                         PathSegment {
243                             ident: "Trait",
244                             arguments: PathArguments::AngleBracketed {
245                                 args: [
246                                     Lifetime(Lifetime {
247                                         ident: "a",
248                                     }),
249                                 ],
250                             },
251                         },
252                     ],
253                 },
254             }),
255             Lifetime(Lifetime {
256                 ident: "static",
257             }),
258         ],
259     }
260     "###);
261 
262     let tokens = quote!(dyn 'a + Trait);
263     snapshot!(tokens as Type, @r###"
264     Type::TraitObject {
265         dyn_token: Some,
266         bounds: [
267             Lifetime(Lifetime {
268                 ident: "a",
269             }),
270             Trait(TraitBound {
271                 modifier: None,
272                 path: Path {
273                     segments: [
274                         PathSegment {
275                             ident: "Trait",
276                             arguments: None,
277                         },
278                     ],
279                 },
280             }),
281         ],
282     }
283     "###);
284 
285     // None of the following are valid Rust types.
286     syn::parse_str::<Type>("for<'a> dyn Trait<'a>").unwrap_err();
287     syn::parse_str::<Type>("dyn for<'a> 'a + Trait").unwrap_err();
288 }
289 
290 #[test]
test_trailing_plus()291 fn test_trailing_plus() {
292     #[rustfmt::skip]
293     let tokens = quote!(impl Trait +);
294     snapshot!(tokens as Type, @r###"
295     Type::ImplTrait {
296         bounds: [
297             Trait(TraitBound {
298                 modifier: None,
299                 path: Path {
300                     segments: [
301                         PathSegment {
302                             ident: "Trait",
303                             arguments: None,
304                         },
305                     ],
306                 },
307             }),
308         ],
309     }
310     "###);
311 
312     #[rustfmt::skip]
313     let tokens = quote!(dyn Trait +);
314     snapshot!(tokens as Type, @r###"
315     Type::TraitObject {
316         dyn_token: Some,
317         bounds: [
318             Trait(TraitBound {
319                 modifier: None,
320                 path: Path {
321                     segments: [
322                         PathSegment {
323                             ident: "Trait",
324                             arguments: None,
325                         },
326                     ],
327                 },
328             }),
329         ],
330     }
331     "###);
332 
333     #[rustfmt::skip]
334     let tokens = quote!(Trait +);
335     snapshot!(tokens as Type, @r###"
336     Type::TraitObject {
337         bounds: [
338             Trait(TraitBound {
339                 modifier: None,
340                 path: Path {
341                     segments: [
342                         PathSegment {
343                             ident: "Trait",
344                             arguments: None,
345                         },
346                     ],
347                 },
348             }),
349         ],
350     }
351     "###);
352 }
353