• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(
2     clippy::elidable_lifetime_names,
3     clippy::manual_let_else,
4     clippy::needless_lifetimes,
5     clippy::too_many_lines,
6     clippy::uninlined_format_args
7 )]
8 
9 #[macro_use]
10 mod macros;
11 
12 use quote::quote;
13 use syn::{DeriveInput, ItemFn, TypeParamBound, WhereClause, WherePredicate};
14 
15 #[test]
test_split_for_impl()16 fn test_split_for_impl() {
17     let input = quote! {
18         struct S<'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug;
19     };
20 
21     snapshot!(input as DeriveInput, @r#"
22     DeriveInput {
23         vis: Visibility::Inherited,
24         ident: "S",
25         generics: Generics {
26             lt_token: Some,
27             params: [
28                 GenericParam::Lifetime(LifetimeParam {
29                     lifetime: Lifetime {
30                         ident: "a",
31                     },
32                 }),
33                 Token![,],
34                 GenericParam::Lifetime(LifetimeParam {
35                     lifetime: Lifetime {
36                         ident: "b",
37                     },
38                     colon_token: Some,
39                     bounds: [
40                         Lifetime {
41                             ident: "a",
42                         },
43                     ],
44                 }),
45                 Token![,],
46                 GenericParam::Type(TypeParam {
47                     attrs: [
48                         Attribute {
49                             style: AttrStyle::Outer,
50                             meta: Meta::Path {
51                                 segments: [
52                                     PathSegment {
53                                         ident: "may_dangle",
54                                     },
55                                 ],
56                             },
57                         },
58                     ],
59                     ident: "T",
60                     colon_token: Some,
61                     bounds: [
62                         TypeParamBound::Lifetime {
63                             ident: "a",
64                         },
65                     ],
66                     eq_token: Some,
67                     default: Some(Type::Tuple),
68                 }),
69             ],
70             gt_token: Some,
71             where_clause: Some(WhereClause {
72                 predicates: [
73                     WherePredicate::Type(PredicateType {
74                         bounded_ty: Type::Path {
75                             path: Path {
76                                 segments: [
77                                     PathSegment {
78                                         ident: "T",
79                                     },
80                                 ],
81                             },
82                         },
83                         bounds: [
84                             TypeParamBound::Trait(TraitBound {
85                                 path: Path {
86                                     segments: [
87                                         PathSegment {
88                                             ident: "Debug",
89                                         },
90                                     ],
91                                 },
92                             }),
93                         ],
94                     }),
95                 ],
96             }),
97         },
98         data: Data::Struct {
99             fields: Fields::Unit,
100             semi_token: Some,
101         },
102     }
103     "#);
104 
105     let generics = input.generics;
106     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
107 
108     let generated = quote! {
109         impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
110     };
111     let expected = quote! {
112         impl<'a, 'b: 'a, #[may_dangle] T: 'a> MyTrait
113         for Test<'a, 'b, T>
114         where
115             T: Debug
116         {}
117     };
118     assert_eq!(generated.to_string(), expected.to_string());
119 
120     let turbofish = ty_generics.as_turbofish();
121     let generated = quote! {
122         Test #turbofish
123     };
124     let expected = quote! {
125         Test::<'a, 'b, T>
126     };
127     assert_eq!(generated.to_string(), expected.to_string());
128 }
129 
130 #[test]
test_ty_param_bound()131 fn test_ty_param_bound() {
132     let tokens = quote!('a);
133     snapshot!(tokens as TypeParamBound, @r#"
134     TypeParamBound::Lifetime {
135         ident: "a",
136     }
137     "#);
138 
139     let tokens = quote!('_);
140     snapshot!(tokens as TypeParamBound, @r#"
141     TypeParamBound::Lifetime {
142         ident: "_",
143     }
144     "#);
145 
146     let tokens = quote!(Debug);
147     snapshot!(tokens as TypeParamBound, @r#"
148     TypeParamBound::Trait(TraitBound {
149         path: Path {
150             segments: [
151                 PathSegment {
152                     ident: "Debug",
153                 },
154             ],
155         },
156     })
157     "#);
158 
159     let tokens = quote!(?Sized);
160     snapshot!(tokens as TypeParamBound, @r#"
161     TypeParamBound::Trait(TraitBound {
162         modifier: TraitBoundModifier::Maybe,
163         path: Path {
164             segments: [
165                 PathSegment {
166                     ident: "Sized",
167                 },
168             ],
169         },
170     })
171     "#);
172 }
173 
174 #[test]
test_fn_precedence_in_where_clause()175 fn test_fn_precedence_in_where_clause() {
176     // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not
177     // `FnOnce() -> (i32 + Send)`.
178     let input = quote! {
179         fn f<G>()
180         where
181             G: FnOnce() -> i32 + Send,
182         {
183         }
184     };
185 
186     snapshot!(input as ItemFn, @r#"
187     ItemFn {
188         vis: Visibility::Inherited,
189         sig: Signature {
190             ident: "f",
191             generics: Generics {
192                 lt_token: Some,
193                 params: [
194                     GenericParam::Type(TypeParam {
195                         ident: "G",
196                     }),
197                 ],
198                 gt_token: Some,
199                 where_clause: Some(WhereClause {
200                     predicates: [
201                         WherePredicate::Type(PredicateType {
202                             bounded_ty: Type::Path {
203                                 path: Path {
204                                     segments: [
205                                         PathSegment {
206                                             ident: "G",
207                                         },
208                                     ],
209                                 },
210                             },
211                             bounds: [
212                                 TypeParamBound::Trait(TraitBound {
213                                     path: Path {
214                                         segments: [
215                                             PathSegment {
216                                                 ident: "FnOnce",
217                                                 arguments: PathArguments::Parenthesized {
218                                                     output: ReturnType::Type(
219                                                         Type::Path {
220                                                             path: Path {
221                                                                 segments: [
222                                                                     PathSegment {
223                                                                         ident: "i32",
224                                                                     },
225                                                                 ],
226                                                             },
227                                                         },
228                                                     ),
229                                                 },
230                                             },
231                                         ],
232                                     },
233                                 }),
234                                 Token![+],
235                                 TypeParamBound::Trait(TraitBound {
236                                     path: Path {
237                                         segments: [
238                                             PathSegment {
239                                                 ident: "Send",
240                                             },
241                                         ],
242                                     },
243                                 }),
244                             ],
245                         }),
246                         Token![,],
247                     ],
248                 }),
249             },
250             output: ReturnType::Default,
251         },
252         block: Block {
253             stmts: [],
254         },
255     }
256     "#);
257 
258     let where_clause = input.sig.generics.where_clause.as_ref().unwrap();
259     assert_eq!(where_clause.predicates.len(), 1);
260 
261     let predicate = match &where_clause.predicates[0] {
262         WherePredicate::Type(pred) => pred,
263         _ => panic!("wrong predicate kind"),
264     };
265 
266     assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
267 
268     let first_bound = &predicate.bounds[0];
269     assert_eq!(quote!(#first_bound).to_string(), "FnOnce () -> i32");
270 
271     let second_bound = &predicate.bounds[1];
272     assert_eq!(quote!(#second_bound).to_string(), "Send");
273 }
274 
275 #[test]
test_where_clause_at_end_of_input()276 fn test_where_clause_at_end_of_input() {
277     let input = quote! {
278         where
279     };
280 
281     snapshot!(input as WhereClause, @"WhereClause");
282 
283     assert_eq!(input.predicates.len(), 0);
284 }
285