]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
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] | |
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] | |
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 | "###); | |
5869c6ff XL |
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] | |
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] | |
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 | "###); | |
f035d41b | 219 | } |
94222f64 XL |
220 | |
221 | #[test] | |
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 | } | |
3c0e092e XL |
288 | |
289 | #[test] | |
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 | } |