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