blob: 0a1dbec5f2ac0b2df58b8476986c4e4c34f93469 [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 Tolnay55337722016-09-11 12:58:56 -0700183 map!(ident, |id| Lifetime {
184 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700185 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700186 ));
187
David Tolnayb5a7b142016-09-13 22:46:39 -0700188 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700189 attrs: many0!(outer_attr) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700190 life: lifetime >>
191 bounds: opt_vec!(preceded!(
192 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700193 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700194 )) >>
195 (LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -0700196 attrs: attrs,
David Tolnay9d8f1972016-09-04 11:58:48 -0700197 lifetime: life,
198 bounds: bounds,
199 })
200 ));
201
David Tolnayb5a7b142016-09-13 22:46:39 -0700202 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700203 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700204 punct!("<") >>
David Tolnayff46fd22016-10-08 13:53:28 -0700205 lifetimes: terminated_list!(punct!(","), lifetime_def) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700206 punct!(">") >>
207 (lifetimes)
208 )));
209
David Tolnayb5a7b142016-09-13 22:46:39 -0700210 named!(ty_param -> TyParam, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700211 attrs: many0!(outer_attr) >>
David Tolnay55337722016-09-11 12:58:56 -0700212 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700213 bounds: opt_vec!(preceded!(
214 punct!(":"),
215 separated_nonempty_list!(punct!("+"), ty_param_bound)
216 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700217 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700218 punct!("="),
219 ty
220 )) >>
221 (TyParam {
David Tolnaye7678922016-10-13 20:44:03 -0700222 attrs: attrs,
David Tolnay55337722016-09-11 12:58:56 -0700223 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700224 bounds: bounds,
225 default: default,
226 })
227 ));
228
David Tolnayb5a7b142016-09-13 22:46:39 -0700229 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700230 preceded!(punct!("?"), poly_trait_ref) => {
231 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
232 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700233 |
234 lifetime => { TyParamBound::Region }
235 |
David Tolnay55337722016-09-11 12:58:56 -0700236 poly_trait_ref => {
237 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
238 }
239 ));
240
David Tolnayb5a7b142016-09-13 22:46:39 -0700241 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700242 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700243 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700244 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
245 option!(punct!(",")) >>
246 (WhereClause { predicates: predicates })
247 )
248 |
249 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700250 ));
251
David Tolnayb5a7b142016-09-13 22:46:39 -0700252 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700253 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700254 ident: lifetime >>
255 punct!(":") >>
256 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
257 (WherePredicate::RegionPredicate(WhereRegionPredicate {
258 lifetime: ident,
259 bounds: bounds,
260 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700261 )
262 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700263 do_parse!(
264 bound_lifetimes: bound_lifetimes >>
265 bounded_ty: ty >>
266 punct!(":") >>
267 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
268 (WherePredicate::BoundPredicate(WhereBoundPredicate {
269 bound_lifetimes: bound_lifetimes,
270 bounded_ty: bounded_ty,
271 bounds: bounds,
272 }))
273 )
274 ));
275}
David Tolnay87d0b442016-09-04 11:52:12 -0700276
277#[cfg(feature = "printing")]
278mod printing {
279 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700280 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700281 use quote::{Tokens, ToTokens};
282
David Tolnay8ef93042016-09-04 14:08:40 -0700283 impl ToTokens for Generics {
284 fn to_tokens(&self, tokens: &mut Tokens) {
285 let has_lifetimes = !self.lifetimes.is_empty();
286 let has_ty_params = !self.ty_params.is_empty();
287 if has_lifetimes || has_ty_params {
288 tokens.append("<");
289 tokens.append_separated(&self.lifetimes, ",");
290 if has_lifetimes && has_ty_params {
291 tokens.append(",");
292 }
293 tokens.append_separated(&self.ty_params, ",");
294 tokens.append(">");
295 }
David Tolnay8ef93042016-09-04 14:08:40 -0700296 }
297 }
298
David Tolnaye7678922016-10-13 20:44:03 -0700299 impl<'a> ToTokens for ImplGenerics<'a> {
300 fn to_tokens(&self, tokens: &mut Tokens) {
301 let has_lifetimes = !self.0.lifetimes.is_empty();
302 let has_ty_params = !self.0.ty_params.is_empty();
303 if has_lifetimes || has_ty_params {
304 tokens.append("<");
305 tokens.append_separated(&self.0.lifetimes, ",");
306 // Leave off the type parameter defaults
307 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
308 if i > 0 || has_lifetimes {
309 tokens.append(",");
310 }
311 tokens.append_all(ty_param.attrs.outer());
312 ty_param.ident.to_tokens(tokens);
313 if !ty_param.bounds.is_empty() {
314 tokens.append(":");
315 tokens.append_separated(&ty_param.bounds, "+");
316 }
317 }
318 tokens.append(">");
319 }
320 }
321 }
322
323 impl<'a> ToTokens for TyGenerics<'a> {
324 fn to_tokens(&self, tokens: &mut Tokens) {
325 let has_lifetimes = !self.0.lifetimes.is_empty();
326 let has_ty_params = !self.0.ty_params.is_empty();
327 if has_lifetimes || has_ty_params {
328 tokens.append("<");
329 // Leave off the lifetime bounds and attributes
330 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
331 tokens.append_separated(lifetimes, ",");
332 if has_lifetimes && has_ty_params {
333 tokens.append(",");
334 }
335 // Leave off the type parameter bounds, defaults, and attributes
336 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
337 tokens.append_separated(ty_params, ",");
338 tokens.append(">");
339 }
340 }
341 }
342
David Tolnay87d0b442016-09-04 11:52:12 -0700343 impl ToTokens for Lifetime {
344 fn to_tokens(&self, tokens: &mut Tokens) {
345 self.ident.to_tokens(tokens);
346 }
347 }
348
349 impl ToTokens for LifetimeDef {
350 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700351 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700352 self.lifetime.to_tokens(tokens);
353 if !self.bounds.is_empty() {
354 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700355 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700356 }
357 }
358 }
359
David Tolnay8ef93042016-09-04 14:08:40 -0700360 impl ToTokens for TyParam {
361 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700362 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700363 self.ident.to_tokens(tokens);
364 if !self.bounds.is_empty() {
365 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700366 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700367 }
368 if let Some(ref default) = self.default {
369 tokens.append("=");
370 default.to_tokens(tokens);
371 }
372 }
373 }
374
David Tolnay87d0b442016-09-04 11:52:12 -0700375 impl ToTokens for TyParamBound {
376 fn to_tokens(&self, tokens: &mut Tokens) {
377 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700378 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700379 TyParamBound::Trait(ref trait_ref, modifier) => {
380 match modifier {
381 TraitBoundModifier::None => {}
382 TraitBoundModifier::Maybe => tokens.append("?"),
383 }
384 trait_ref.to_tokens(tokens);
385 }
386 }
387 }
388 }
389
390 impl ToTokens for WhereClause {
391 fn to_tokens(&self, tokens: &mut Tokens) {
392 if !self.predicates.is_empty() {
393 tokens.append("where");
394 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700395 }
396 }
397 }
David Tolnay8ef93042016-09-04 14:08:40 -0700398
399 impl ToTokens for WherePredicate {
400 fn to_tokens(&self, tokens: &mut Tokens) {
401 match *self {
402 WherePredicate::BoundPredicate(ref predicate) => {
403 predicate.to_tokens(tokens);
404 }
405 WherePredicate::RegionPredicate(ref predicate) => {
406 predicate.to_tokens(tokens);
407 }
408 }
409 }
410 }
411
412 impl ToTokens for WhereBoundPredicate {
413 fn to_tokens(&self, tokens: &mut Tokens) {
414 if !self.bound_lifetimes.is_empty() {
415 tokens.append("for");
416 tokens.append("<");
417 tokens.append_separated(&self.bound_lifetimes, ",");
418 tokens.append(">");
419 }
420 self.bounded_ty.to_tokens(tokens);
421 if !self.bounds.is_empty() {
422 tokens.append(":");
423 tokens.append_separated(&self.bounds, "+");
424 }
425 }
426 }
427
428 impl ToTokens for WhereRegionPredicate {
429 fn to_tokens(&self, tokens: &mut Tokens) {
430 self.lifetime.to_tokens(tokens);
431 if !self.bounds.is_empty() {
432 tokens.append(":");
433 tokens.append_separated(&self.bounds, "+");
434 }
435 }
436 }
David Tolnay87d0b442016-09-04 11:52:12 -0700437}