xref: /third_party/rust/crates/syn/tests/test_ty.rs (revision fad3a1d3)
1#![allow(clippy::uninlined_format_args)]
2
3#[macro_use]
4mod macros;
5
6use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
7use quote::{quote, ToTokens as _};
8use syn::punctuated::Punctuated;
9use syn::{parse_quote, token, Token, Type, TypeTuple};
10
11#[test]
12fn test_mut_self() {
13    syn::parse_str::<Type>("fn(mut self)").unwrap();
14    syn::parse_str::<Type>("fn(mut self,)").unwrap();
15    syn::parse_str::<Type>("fn(mut self: ())").unwrap();
16    syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
17    syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
18    syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
19}
20
21#[test]
22fn test_macro_variable_type() {
23    // mimics the token stream corresponding to `$ty<T>`
24    let tokens = TokenStream::from_iter(vec![
25        TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
26        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
27        TokenTree::Ident(Ident::new("T", Span::call_site())),
28        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
29    ]);
30
31    snapshot!(tokens as Type, @r###"
32    Type::Path {
33        path: Path {
34            segments: [
35                PathSegment {
36                    ident: "ty",
37                    arguments: PathArguments::AngleBracketed {
38                        args: [
39                            GenericArgument::Type(Type::Path {
40                                path: Path {
41                                    segments: [
42                                        PathSegment {
43                                            ident: "T",
44                                        },
45                                    ],
46                                },
47                            }),
48                        ],
49                    },
50                },
51            ],
52        },
53    }
54    "###);
55
56    // mimics the token stream corresponding to `$ty::<T>`
57    let tokens = TokenStream::from_iter(vec![
58        TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
59        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
60        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
61        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
62        TokenTree::Ident(Ident::new("T", Span::call_site())),
63        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
64    ]);
65
66    snapshot!(tokens as Type, @r###"
67    Type::Path {
68        path: Path {
69            segments: [
70                PathSegment {
71                    ident: "ty",
72                    arguments: PathArguments::AngleBracketed {
73                        colon2_token: Some,
74                        args: [
75                            GenericArgument::Type(Type::Path {
76                                path: Path {
77                                    segments: [
78                                        PathSegment {
79                                            ident: "T",
80                                        },
81                                    ],
82                                },
83                            }),
84                        ],
85                    },
86                },
87            ],
88        },
89    }
90    "###);
91}
92
93#[test]
94fn 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                            GenericArgument::Type(Type::Group {
112                                elem: Type::Path {
113                                    path: Path {
114                                        segments: [
115                                            PathSegment {
116                                                ident: "Vec",
117                                                arguments: PathArguments::AngleBracketed {
118                                                    args: [
119                                                        GenericArgument::Type(Type::Path {
120                                                            path: Path {
121                                                                segments: [
122                                                                    PathSegment {
123                                                                        ident: "u8",
124                                                                    },
125                                                                ],
126                                                            },
127                                                        }),
128                                                    ],
129                                                },
130                                            },
131                                        ],
132                                    },
133                                },
134                            }),
135                        ],
136                    },
137                },
138            ],
139        },
140    }
141    "###);
142}
143
144#[test]
145fn 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                            GenericArgument::Type(Type::Path {
163                                path: Path {
164                                    segments: [
165                                        PathSegment {
166                                            ident: "u8",
167                                        },
168                                    ],
169                                },
170                            }),
171                        ],
172                    },
173                },
174                Token![::],
175                PathSegment {
176                    ident: "Item",
177                },
178            ],
179        },
180    }
181    "###);
182
183    let tokens = TokenStream::from_iter(vec![
184        TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })),
185        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
186        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
187        TokenTree::Ident(Ident::new("Element", Span::call_site())),
188    ]);
189
190    snapshot!(tokens as Type, @r###"
191    Type::Path {
192        qself: Some(QSelf {
193            ty: Type::Slice {
194                elem: Type::Path {
195                    path: Path {
196                        segments: [
197                            PathSegment {
198                                ident: "T",
199                            },
200                        ],
201                    },
202                },
203            },
204            position: 0,
205        }),
206        path: Path {
207            leading_colon: Some,
208            segments: [
209                PathSegment {
210                    ident: "Element",
211                },
212            ],
213        },
214    }
215    "###);
216}
217
218#[test]
219fn test_trait_object() {
220    let tokens = quote!(dyn for<'a> Trait<'a> + 'static);
221    snapshot!(tokens as Type, @r###"
222    Type::TraitObject {
223        dyn_token: Some,
224        bounds: [
225            TypeParamBound::Trait(TraitBound {
226                lifetimes: Some(BoundLifetimes {
227                    lifetimes: [
228                        GenericParam::Lifetime(LifetimeParam {
229                            lifetime: Lifetime {
230                                ident: "a",
231                            },
232                        }),
233                    ],
234                }),
235                path: Path {
236                    segments: [
237                        PathSegment {
238                            ident: "Trait",
239                            arguments: PathArguments::AngleBracketed {
240                                args: [
241                                    GenericArgument::Lifetime(Lifetime {
242                                        ident: "a",
243                                    }),
244                                ],
245                            },
246                        },
247                    ],
248                },
249            }),
250            Token![+],
251            TypeParamBound::Lifetime {
252                ident: "static",
253            },
254        ],
255    }
256    "###);
257
258    let tokens = quote!(dyn 'a + Trait);
259    snapshot!(tokens as Type, @r###"
260    Type::TraitObject {
261        dyn_token: Some,
262        bounds: [
263            TypeParamBound::Lifetime {
264                ident: "a",
265            },
266            Token![+],
267            TypeParamBound::Trait(TraitBound {
268                path: Path {
269                    segments: [
270                        PathSegment {
271                            ident: "Trait",
272                        },
273                    ],
274                },
275            }),
276        ],
277    }
278    "###);
279
280    // None of the following are valid Rust types.
281    syn::parse_str::<Type>("for<'a> dyn Trait<'a>").unwrap_err();
282    syn::parse_str::<Type>("dyn for<'a> 'a + Trait").unwrap_err();
283}
284
285#[test]
286fn test_trailing_plus() {
287    #[rustfmt::skip]
288    let tokens = quote!(impl Trait +);
289    snapshot!(tokens as Type, @r###"
290    Type::ImplTrait {
291        bounds: [
292            TypeParamBound::Trait(TraitBound {
293                path: Path {
294                    segments: [
295                        PathSegment {
296                            ident: "Trait",
297                        },
298                    ],
299                },
300            }),
301            Token![+],
302        ],
303    }
304    "###);
305
306    #[rustfmt::skip]
307    let tokens = quote!(dyn Trait +);
308    snapshot!(tokens as Type, @r###"
309    Type::TraitObject {
310        dyn_token: Some,
311        bounds: [
312            TypeParamBound::Trait(TraitBound {
313                path: Path {
314                    segments: [
315                        PathSegment {
316                            ident: "Trait",
317                        },
318                    ],
319                },
320            }),
321            Token![+],
322        ],
323    }
324    "###);
325
326    #[rustfmt::skip]
327    let tokens = quote!(Trait +);
328    snapshot!(tokens as Type, @r###"
329    Type::TraitObject {
330        bounds: [
331            TypeParamBound::Trait(TraitBound {
332                path: Path {
333                    segments: [
334                        PathSegment {
335                            ident: "Trait",
336                        },
337                    ],
338                },
339            }),
340            Token![+],
341        ],
342    }
343    "###);
344}
345
346#[test]
347fn test_tuple_comma() {
348    let mut expr = TypeTuple {
349        paren_token: token::Paren::default(),
350        elems: Punctuated::new(),
351    };
352    snapshot!(expr.to_token_stream() as Type, @"Type::Tuple");
353
354    expr.elems.push_value(parse_quote!(_));
355    // Must not parse to Type::Paren
356    snapshot!(expr.to_token_stream() as Type, @r###"
357    Type::Tuple {
358        elems: [
359            Type::Infer,
360            Token![,],
361        ],
362    }
363    "###);
364
365    expr.elems.push_punct(<Token![,]>::default());
366    snapshot!(expr.to_token_stream() as Type, @r###"
367    Type::Tuple {
368        elems: [
369            Type::Infer,
370            Token![,],
371        ],
372    }
373    "###);
374
375    expr.elems.push_value(parse_quote!(_));
376    snapshot!(expr.to_token_stream() as Type, @r###"
377    Type::Tuple {
378        elems: [
379            Type::Infer,
380            Token![,],
381            Type::Infer,
382        ],
383    }
384    "###);
385
386    expr.elems.push_punct(<Token![,]>::default());
387    snapshot!(expr.to_token_stream() as Type, @r###"
388    Type::Tuple {
389        elems: [
390            Type::Infer,
391            Token![,],
392            Type::Infer,
393            Token![,],
394        ],
395    }
396    "###);
397}
398