blob: 6f89adba8c550b3a3d6bf956c359a39846dae246 [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
2
David Tolnay771ecf42016-09-23 19:26:37 -07003/// Represents lifetimes and type parameters attached to a declaration
4/// of a function, enum, trait, etc.
David Tolnayb79ee962016-09-04 09:39:20 -07005#[derive(Debug, Clone, Eq, PartialEq, Default)]
6pub struct Generics {
7 pub lifetimes: Vec<LifetimeDef>,
8 pub ty_params: Vec<TyParam>,
David Tolnay55337722016-09-11 12:58:56 -07009 pub where_clause: WhereClause,
David Tolnayb79ee962016-09-04 09:39:20 -070010}
11
David Tolnaye7678922016-10-13 20:44:03 -070012#[cfg(feature = "printing")]
13/// Returned by `Generics::split_for_impl`.
14#[derive(Debug)]
15pub struct ImplGenerics<'a>(&'a Generics);
16
17#[cfg(feature = "printing")]
18/// Returned by `Generics::split_for_impl`.
19#[derive(Debug)]
20pub struct TyGenerics<'a>(&'a Generics);
21
David Tolnayb153dbc2016-10-04 23:39:10 -070022impl Generics {
David Tolnaye7678922016-10-13 20:44:03 -070023 #[cfg(feature = "printing")]
David Tolnayb153dbc2016-10-04 23:39:10 -070024 /// Split a type's generics into the pieces required for impl'ing a trait
25 /// for that type.
26 ///
27 /// ```
28 /// # extern crate syn;
29 /// # #[macro_use]
30 /// # extern crate quote;
31 /// # fn main() {
32 /// # let generics: syn::Generics = Default::default();
33 /// # let name = syn::Ident::new("MyType");
34 /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
35 /// quote! {
36 /// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
37 /// // ...
38 /// }
39 /// }
40 /// # ;
41 /// # }
42 /// ```
David Tolnaye7678922016-10-13 20:44:03 -070043 pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
44 (ImplGenerics(self), TyGenerics(self), &self.where_clause)
David Tolnayb153dbc2016-10-04 23:39:10 -070045 }
46}
47
David Tolnayb79ee962016-09-04 09:39:20 -070048#[derive(Debug, Clone, Eq, PartialEq)]
49pub struct Lifetime {
50 pub ident: Ident,
51}
52
David Tolnay01405f02016-10-02 09:05:02 -070053impl Lifetime {
54 pub fn new<T: Into<Ident>>(t: T) -> Self {
David Tolnayff3b8ae2016-10-08 11:54:18 -070055 let id = Ident::new(t);
56 if !id.as_ref().starts_with('\'') {
57 panic!("lifetime name must start with apostrophe as in \"'a\", \
David Tolnay3bcfb722016-10-08 11:58:36 -070058 got {:?}",
59 id.as_ref());
David Tolnayff3b8ae2016-10-08 11:54:18 -070060 }
61 Lifetime { ident: id }
David Tolnay01405f02016-10-02 09:05:02 -070062 }
63}
64
David Tolnay771ecf42016-09-23 19:26:37 -070065/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070066#[derive(Debug, Clone, Eq, PartialEq)]
67pub struct LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -070068 pub attrs: Vec<Attribute>,
David Tolnayb79ee962016-09-04 09:39:20 -070069 pub lifetime: Lifetime,
70 pub bounds: Vec<Lifetime>,
71}
72
David Tolnayf9505b52016-10-02 09:18:52 -070073impl LifetimeDef {
74 pub fn new<T: Into<Ident>>(t: T) -> Self {
75 LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -070076 attrs: Vec::new(),
David Tolnayf9505b52016-10-02 09:18:52 -070077 lifetime: Lifetime::new(t),
78 bounds: Vec::new(),
79 }
80 }
81}
82
David Tolnayb79ee962016-09-04 09:39:20 -070083#[derive(Debug, Clone, Eq, PartialEq)]
84pub struct TyParam {
David Tolnaye7678922016-10-13 20:44:03 -070085 pub attrs: Vec<Attribute>,
David Tolnayb79ee962016-09-04 09:39:20 -070086 pub ident: Ident,
87 pub bounds: Vec<TyParamBound>,
88 pub default: Option<Ty>,
89}
90
David Tolnay771ecf42016-09-23 19:26:37 -070091/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -070092/// `typeck::collect::compute_bounds` matches these against
93/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -070094/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -070095#[derive(Debug, Clone, Eq, PartialEq)]
96pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -070097 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070098 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070099}
100
David Tolnay771ecf42016-09-23 19:26:37 -0700101/// A modifier on a bound, currently this is only used for `?Sized`, where the
102/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -0700103#[derive(Debug, Copy, Clone, Eq, PartialEq)]
104pub enum TraitBoundModifier {
105 None,
106 Maybe,
107}
108
David Tolnay771ecf42016-09-23 19:26:37 -0700109/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -0700110#[derive(Debug, Clone, Eq, PartialEq, Default)]
111pub struct WhereClause {
112 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700113}
114
David Tolnayb153dbc2016-10-04 23:39:10 -0700115impl WhereClause {
116 pub fn none() -> Self {
David Tolnay2e737362016-10-05 23:44:15 -0700117 WhereClause { predicates: Vec::new() }
David Tolnayb153dbc2016-10-04 23:39:10 -0700118 }
119}
120
David Tolnayb79ee962016-09-04 09:39:20 -0700121/// A single predicate in a `where` clause
122#[derive(Debug, Clone, Eq, PartialEq)]
123pub enum WherePredicate {
124 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
125 BoundPredicate(WhereBoundPredicate),
126 /// A lifetime predicate, e.g. `'a: 'b+'c`
127 RegionPredicate(WhereRegionPredicate),
128}
129
130/// A type bound.
131///
132/// E.g. `for<'c> Foo: Send+Clone+'c`
133#[derive(Debug, Clone, Eq, PartialEq)]
134pub struct WhereBoundPredicate {
135 /// Any lifetimes from a `for` binding
136 pub bound_lifetimes: Vec<LifetimeDef>,
137 /// The type being bounded
138 pub bounded_ty: Ty,
139 /// Trait and lifetime bounds (`Clone+Send+'static`)
140 pub bounds: Vec<TyParamBound>,
141}
142
143/// A lifetime predicate.
144///
145/// E.g. `'a: 'b+'c`
146#[derive(Debug, Clone, Eq, PartialEq)]
147pub struct WhereRegionPredicate {
148 pub lifetime: Lifetime,
149 pub bounds: Vec<Lifetime>,
150}
151
David Tolnay86eca752016-09-04 11:26:41 -0700152#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700153pub mod parsing {
154 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700155 use attr::parsing::outer_attr;
David Tolnay55337722016-09-11 12:58:56 -0700156 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700157 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700158
David Tolnay3cf52982016-10-01 17:11:37 -0700159 named!(pub generics -> Generics, map!(
160 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700161 do_parse!(
162 punct!("<") >>
163 lifetimes: separated_list!(punct!(","), lifetime_def) >>
164 ty_params: opt_vec!(preceded!(
165 cond!(!lifetimes.is_empty(), punct!(",")),
166 separated_nonempty_list!(punct!(","), ty_param)
167 )) >>
168 punct!(">") >>
169 (lifetimes, ty_params)
170 )
171 |
172 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700173 ),
174 |(lifetimes, ty_params)| Generics {
175 lifetimes: lifetimes,
176 ty_params: ty_params,
177 where_clause: Default::default(),
178 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700179 ));
180
David Tolnayb5a7b142016-09-13 22:46:39 -0700181 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700182 punct!("'"),
David Tolnaye43ffb72016-10-24 22:33:31 -0700183 alt!(
184 map!(ident, |id| Lifetime {
185 ident: format!("'{}", id).into(),
186 })
187 |
188 map!(keyword!("static"), |_| Lifetime {
189 ident: "'static".into(),
190 })
191 )
David Tolnay9d8f1972016-09-04 11:58:48 -0700192 ));
193
David Tolnayb5a7b142016-09-13 22:46:39 -0700194 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700195 attrs: many0!(outer_attr) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700196 life: lifetime >>
197 bounds: opt_vec!(preceded!(
198 punct!(":"),
David Tolnayd95baae2016-10-30 00:47:53 -0700199 separated_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700200 )) >>
201 (LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -0700202 attrs: attrs,
David Tolnay9d8f1972016-09-04 11:58:48 -0700203 lifetime: life,
204 bounds: bounds,
205 })
206 ));
207
David Tolnayb5a7b142016-09-13 22:46:39 -0700208 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700209 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700210 punct!("<") >>
David Tolnayff46fd22016-10-08 13:53:28 -0700211 lifetimes: terminated_list!(punct!(","), lifetime_def) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700212 punct!(">") >>
213 (lifetimes)
214 )));
215
David Tolnayb5a7b142016-09-13 22:46:39 -0700216 named!(ty_param -> TyParam, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700217 attrs: many0!(outer_attr) >>
David Tolnay55337722016-09-11 12:58:56 -0700218 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700219 bounds: opt_vec!(preceded!(
220 punct!(":"),
221 separated_nonempty_list!(punct!("+"), ty_param_bound)
222 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700223 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700224 punct!("="),
225 ty
226 )) >>
227 (TyParam {
David Tolnaye7678922016-10-13 20:44:03 -0700228 attrs: attrs,
David Tolnay55337722016-09-11 12:58:56 -0700229 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700230 bounds: bounds,
231 default: default,
232 })
233 ));
234
David Tolnayb5a7b142016-09-13 22:46:39 -0700235 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700236 preceded!(punct!("?"), poly_trait_ref) => {
237 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
238 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700239 |
240 lifetime => { TyParamBound::Region }
241 |
David Tolnay55337722016-09-11 12:58:56 -0700242 poly_trait_ref => {
243 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
244 }
245 ));
246
David Tolnayb5a7b142016-09-13 22:46:39 -0700247 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700248 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700249 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700250 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
251 option!(punct!(",")) >>
252 (WhereClause { predicates: predicates })
253 )
254 |
255 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700256 ));
257
David Tolnayb5a7b142016-09-13 22:46:39 -0700258 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700259 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700260 ident: lifetime >>
David Tolnayd95baae2016-10-30 00:47:53 -0700261 bounds: opt_vec!(preceded!(
262 punct!(":"),
263 separated_list!(punct!("+"), lifetime)
264 )) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700265 (WherePredicate::RegionPredicate(WhereRegionPredicate {
266 lifetime: ident,
267 bounds: bounds,
268 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700269 )
270 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700271 do_parse!(
272 bound_lifetimes: bound_lifetimes >>
273 bounded_ty: ty >>
274 punct!(":") >>
275 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
276 (WherePredicate::BoundPredicate(WhereBoundPredicate {
277 bound_lifetimes: bound_lifetimes,
278 bounded_ty: bounded_ty,
279 bounds: bounds,
280 }))
281 )
282 ));
283}
David Tolnay87d0b442016-09-04 11:52:12 -0700284
285#[cfg(feature = "printing")]
286mod printing {
287 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700288 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700289 use quote::{Tokens, ToTokens};
290
David Tolnay8ef93042016-09-04 14:08:40 -0700291 impl ToTokens for Generics {
292 fn to_tokens(&self, tokens: &mut Tokens) {
293 let has_lifetimes = !self.lifetimes.is_empty();
294 let has_ty_params = !self.ty_params.is_empty();
295 if has_lifetimes || has_ty_params {
296 tokens.append("<");
297 tokens.append_separated(&self.lifetimes, ",");
298 if has_lifetimes && has_ty_params {
299 tokens.append(",");
300 }
301 tokens.append_separated(&self.ty_params, ",");
302 tokens.append(">");
303 }
David Tolnay8ef93042016-09-04 14:08:40 -0700304 }
305 }
306
David Tolnaye7678922016-10-13 20:44:03 -0700307 impl<'a> ToTokens for ImplGenerics<'a> {
308 fn to_tokens(&self, tokens: &mut Tokens) {
309 let has_lifetimes = !self.0.lifetimes.is_empty();
310 let has_ty_params = !self.0.ty_params.is_empty();
311 if has_lifetimes || has_ty_params {
312 tokens.append("<");
313 tokens.append_separated(&self.0.lifetimes, ",");
314 // Leave off the type parameter defaults
315 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
316 if i > 0 || has_lifetimes {
317 tokens.append(",");
318 }
319 tokens.append_all(ty_param.attrs.outer());
320 ty_param.ident.to_tokens(tokens);
321 if !ty_param.bounds.is_empty() {
322 tokens.append(":");
323 tokens.append_separated(&ty_param.bounds, "+");
324 }
325 }
326 tokens.append(">");
327 }
328 }
329 }
330
331 impl<'a> ToTokens for TyGenerics<'a> {
332 fn to_tokens(&self, tokens: &mut Tokens) {
333 let has_lifetimes = !self.0.lifetimes.is_empty();
334 let has_ty_params = !self.0.ty_params.is_empty();
335 if has_lifetimes || has_ty_params {
336 tokens.append("<");
337 // Leave off the lifetime bounds and attributes
338 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
339 tokens.append_separated(lifetimes, ",");
340 if has_lifetimes && has_ty_params {
341 tokens.append(",");
342 }
343 // Leave off the type parameter bounds, defaults, and attributes
344 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
345 tokens.append_separated(ty_params, ",");
346 tokens.append(">");
347 }
348 }
349 }
350
David Tolnay87d0b442016-09-04 11:52:12 -0700351 impl ToTokens for Lifetime {
352 fn to_tokens(&self, tokens: &mut Tokens) {
353 self.ident.to_tokens(tokens);
354 }
355 }
356
357 impl ToTokens for LifetimeDef {
358 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700359 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700360 self.lifetime.to_tokens(tokens);
361 if !self.bounds.is_empty() {
362 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700363 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700364 }
365 }
366 }
367
David Tolnay8ef93042016-09-04 14:08:40 -0700368 impl ToTokens for TyParam {
369 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700370 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700371 self.ident.to_tokens(tokens);
372 if !self.bounds.is_empty() {
373 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700374 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700375 }
376 if let Some(ref default) = self.default {
377 tokens.append("=");
378 default.to_tokens(tokens);
379 }
380 }
381 }
382
David Tolnay87d0b442016-09-04 11:52:12 -0700383 impl ToTokens for TyParamBound {
384 fn to_tokens(&self, tokens: &mut Tokens) {
385 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700386 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700387 TyParamBound::Trait(ref trait_ref, modifier) => {
388 match modifier {
389 TraitBoundModifier::None => {}
390 TraitBoundModifier::Maybe => tokens.append("?"),
391 }
392 trait_ref.to_tokens(tokens);
393 }
394 }
395 }
396 }
397
398 impl ToTokens for WhereClause {
399 fn to_tokens(&self, tokens: &mut Tokens) {
400 if !self.predicates.is_empty() {
401 tokens.append("where");
402 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700403 }
404 }
405 }
David Tolnay8ef93042016-09-04 14:08:40 -0700406
407 impl ToTokens for WherePredicate {
408 fn to_tokens(&self, tokens: &mut Tokens) {
409 match *self {
410 WherePredicate::BoundPredicate(ref predicate) => {
411 predicate.to_tokens(tokens);
412 }
413 WherePredicate::RegionPredicate(ref predicate) => {
414 predicate.to_tokens(tokens);
415 }
416 }
417 }
418 }
419
420 impl ToTokens for WhereBoundPredicate {
421 fn to_tokens(&self, tokens: &mut Tokens) {
422 if !self.bound_lifetimes.is_empty() {
423 tokens.append("for");
424 tokens.append("<");
425 tokens.append_separated(&self.bound_lifetimes, ",");
426 tokens.append(">");
427 }
428 self.bounded_ty.to_tokens(tokens);
429 if !self.bounds.is_empty() {
430 tokens.append(":");
431 tokens.append_separated(&self.bounds, "+");
432 }
433 }
434 }
435
436 impl ToTokens for WhereRegionPredicate {
437 fn to_tokens(&self, tokens: &mut Tokens) {
438 self.lifetime.to_tokens(tokens);
439 if !self.bounds.is_empty() {
440 tokens.append(":");
441 tokens.append_separated(&self.bounds, "+");
442 }
443 }
444 }
David Tolnay87d0b442016-09-04 11:52:12 -0700445}