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