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