blob: 50b980291fdf467b53e5f20c1b7aa9dca3ef0c89 [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 Tolnay9bf4af82017-01-07 11:17:46 -08005#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -07006pub 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 Tolnay9bf4af82017-01-07 11:17:46 -080048#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070049pub 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 Tolnay9bf4af82017-01-07 11:17:46 -080066#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070067pub 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 Tolnay9bf4af82017-01-07 11:17:46 -080083#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070084pub 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 Tolnay9bf4af82017-01-07 11:17:46 -080095#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -070096pub 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 Tolnay9bf4af82017-01-07 11:17:46 -0800103#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnay55337722016-09-11 12:58:56 -0700104pub enum TraitBoundModifier {
105 None,
106 Maybe,
107}
108
David Tolnay771ecf42016-09-23 19:26:37 -0700109/// A `where` clause in a definition
David Tolnay9bf4af82017-01-07 11:17:46 -0800110#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
David Tolnay55337722016-09-11 12:58:56 -0700111pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -0800122#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700123pub 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),
David Tolnayf8e08832017-01-23 00:04:32 -0800128 /// An equality predicate (unsupported)
129 EqPredicate(WhereEqPredicate),
David Tolnayb79ee962016-09-04 09:39:20 -0700130}
131
132/// A type bound.
133///
134/// E.g. `for<'c> Foo: Send+Clone+'c`
David Tolnay9bf4af82017-01-07 11:17:46 -0800135#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700136pub struct WhereBoundPredicate {
137 /// Any lifetimes from a `for` binding
138 pub bound_lifetimes: Vec<LifetimeDef>,
139 /// The type being bounded
140 pub bounded_ty: Ty,
141 /// Trait and lifetime bounds (`Clone+Send+'static`)
142 pub bounds: Vec<TyParamBound>,
143}
144
145/// A lifetime predicate.
146///
147/// E.g. `'a: 'b+'c`
David Tolnay9bf4af82017-01-07 11:17:46 -0800148#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700149pub struct WhereRegionPredicate {
150 pub lifetime: Lifetime,
151 pub bounds: Vec<Lifetime>,
152}
153
David Tolnayf8e08832017-01-23 00:04:32 -0800154/// An equality predicate (unsupported).
155///
156/// E.g. `T=int`
157#[derive(Debug, Clone, Eq, PartialEq, Hash)]
158pub struct WhereEqPredicate {
159 pub lhs_ty: Ty,
160 pub rhs_ty: Ty,
161}
162
David Tolnay86eca752016-09-04 11:26:41 -0700163#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700164pub mod parsing {
165 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700166 use attr::parsing::outer_attr;
David Tolnay55337722016-09-11 12:58:56 -0700167 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700168 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700169
David Tolnay3cf52982016-10-01 17:11:37 -0700170 named!(pub generics -> Generics, map!(
171 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700172 do_parse!(
173 punct!("<") >>
174 lifetimes: separated_list!(punct!(","), lifetime_def) >>
175 ty_params: opt_vec!(preceded!(
176 cond!(!lifetimes.is_empty(), punct!(",")),
177 separated_nonempty_list!(punct!(","), ty_param)
178 )) >>
David Tolnay82a47d52016-10-30 13:01:38 -0700179 cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700180 punct!(">") >>
181 (lifetimes, ty_params)
182 )
183 |
184 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700185 ),
186 |(lifetimes, ty_params)| Generics {
187 lifetimes: lifetimes,
188 ty_params: ty_params,
189 where_clause: Default::default(),
190 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700191 ));
192
David Tolnayb5a7b142016-09-13 22:46:39 -0700193 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700194 punct!("'"),
David Tolnaye43ffb72016-10-24 22:33:31 -0700195 alt!(
196 map!(ident, |id| Lifetime {
197 ident: format!("'{}", id).into(),
198 })
199 |
200 map!(keyword!("static"), |_| Lifetime {
201 ident: "'static".into(),
202 })
203 )
David Tolnay9d8f1972016-09-04 11:58:48 -0700204 ));
205
David Tolnayb5a7b142016-09-13 22:46:39 -0700206 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700207 attrs: many0!(outer_attr) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700208 life: lifetime >>
209 bounds: opt_vec!(preceded!(
210 punct!(":"),
David Tolnayd95baae2016-10-30 00:47:53 -0700211 separated_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700212 )) >>
213 (LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -0700214 attrs: attrs,
David Tolnay9d8f1972016-09-04 11:58:48 -0700215 lifetime: life,
216 bounds: bounds,
217 })
218 ));
219
David Tolnayb5a7b142016-09-13 22:46:39 -0700220 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700221 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700222 punct!("<") >>
David Tolnayff46fd22016-10-08 13:53:28 -0700223 lifetimes: terminated_list!(punct!(","), lifetime_def) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700224 punct!(">") >>
225 (lifetimes)
226 )));
227
David Tolnayb5a7b142016-09-13 22:46:39 -0700228 named!(ty_param -> TyParam, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700229 attrs: many0!(outer_attr) >>
David Tolnay55337722016-09-11 12:58:56 -0700230 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700231 bounds: opt_vec!(preceded!(
232 punct!(":"),
233 separated_nonempty_list!(punct!("+"), ty_param_bound)
234 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700235 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700236 punct!("="),
237 ty
238 )) >>
239 (TyParam {
David Tolnaye7678922016-10-13 20:44:03 -0700240 attrs: attrs,
David Tolnay55337722016-09-11 12:58:56 -0700241 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700242 bounds: bounds,
243 default: default,
244 })
245 ));
246
David Tolnayb5a7b142016-09-13 22:46:39 -0700247 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700248 preceded!(punct!("?"), poly_trait_ref) => {
249 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
250 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700251 |
252 lifetime => { TyParamBound::Region }
253 |
David Tolnay55337722016-09-11 12:58:56 -0700254 poly_trait_ref => {
255 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
256 }
257 ));
258
David Tolnayb5a7b142016-09-13 22:46:39 -0700259 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700260 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700261 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700262 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
263 option!(punct!(",")) >>
264 (WhereClause { predicates: predicates })
265 )
266 |
267 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700268 ));
269
David Tolnayb5a7b142016-09-13 22:46:39 -0700270 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700271 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700272 ident: lifetime >>
David Tolnayd95baae2016-10-30 00:47:53 -0700273 bounds: opt_vec!(preceded!(
274 punct!(":"),
275 separated_list!(punct!("+"), lifetime)
276 )) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700277 (WherePredicate::RegionPredicate(WhereRegionPredicate {
278 lifetime: ident,
279 bounds: bounds,
280 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700281 )
282 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700283 do_parse!(
284 bound_lifetimes: bound_lifetimes >>
285 bounded_ty: ty >>
286 punct!(":") >>
287 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
288 (WherePredicate::BoundPredicate(WhereBoundPredicate {
289 bound_lifetimes: bound_lifetimes,
290 bounded_ty: bounded_ty,
291 bounds: bounds,
292 }))
293 )
294 ));
295}
David Tolnay87d0b442016-09-04 11:52:12 -0700296
297#[cfg(feature = "printing")]
298mod printing {
299 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700300 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700301 use quote::{Tokens, ToTokens};
302
David Tolnay8ef93042016-09-04 14:08:40 -0700303 impl ToTokens for Generics {
304 fn to_tokens(&self, tokens: &mut Tokens) {
305 let has_lifetimes = !self.lifetimes.is_empty();
306 let has_ty_params = !self.ty_params.is_empty();
307 if has_lifetimes || has_ty_params {
308 tokens.append("<");
309 tokens.append_separated(&self.lifetimes, ",");
310 if has_lifetimes && has_ty_params {
311 tokens.append(",");
312 }
313 tokens.append_separated(&self.ty_params, ",");
314 tokens.append(">");
315 }
David Tolnay8ef93042016-09-04 14:08:40 -0700316 }
317 }
318
David Tolnaye7678922016-10-13 20:44:03 -0700319 impl<'a> ToTokens for ImplGenerics<'a> {
320 fn to_tokens(&self, tokens: &mut Tokens) {
321 let has_lifetimes = !self.0.lifetimes.is_empty();
322 let has_ty_params = !self.0.ty_params.is_empty();
323 if has_lifetimes || has_ty_params {
324 tokens.append("<");
325 tokens.append_separated(&self.0.lifetimes, ",");
326 // Leave off the type parameter defaults
327 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
328 if i > 0 || has_lifetimes {
329 tokens.append(",");
330 }
331 tokens.append_all(ty_param.attrs.outer());
332 ty_param.ident.to_tokens(tokens);
333 if !ty_param.bounds.is_empty() {
334 tokens.append(":");
335 tokens.append_separated(&ty_param.bounds, "+");
336 }
337 }
338 tokens.append(">");
339 }
340 }
341 }
342
343 impl<'a> ToTokens for TyGenerics<'a> {
344 fn to_tokens(&self, tokens: &mut Tokens) {
345 let has_lifetimes = !self.0.lifetimes.is_empty();
346 let has_ty_params = !self.0.ty_params.is_empty();
347 if has_lifetimes || has_ty_params {
348 tokens.append("<");
349 // Leave off the lifetime bounds and attributes
350 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
351 tokens.append_separated(lifetimes, ",");
352 if has_lifetimes && has_ty_params {
353 tokens.append(",");
354 }
355 // Leave off the type parameter bounds, defaults, and attributes
356 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
357 tokens.append_separated(ty_params, ",");
358 tokens.append(">");
359 }
360 }
361 }
362
David Tolnay87d0b442016-09-04 11:52:12 -0700363 impl ToTokens for Lifetime {
364 fn to_tokens(&self, tokens: &mut Tokens) {
365 self.ident.to_tokens(tokens);
366 }
367 }
368
369 impl ToTokens for LifetimeDef {
370 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700371 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700372 self.lifetime.to_tokens(tokens);
373 if !self.bounds.is_empty() {
374 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700375 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700376 }
377 }
378 }
379
David Tolnay8ef93042016-09-04 14:08:40 -0700380 impl ToTokens for TyParam {
381 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700382 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700383 self.ident.to_tokens(tokens);
384 if !self.bounds.is_empty() {
385 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700386 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700387 }
388 if let Some(ref default) = self.default {
389 tokens.append("=");
390 default.to_tokens(tokens);
391 }
392 }
393 }
394
David Tolnay87d0b442016-09-04 11:52:12 -0700395 impl ToTokens for TyParamBound {
396 fn to_tokens(&self, tokens: &mut Tokens) {
397 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700398 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700399 TyParamBound::Trait(ref trait_ref, modifier) => {
400 match modifier {
401 TraitBoundModifier::None => {}
402 TraitBoundModifier::Maybe => tokens.append("?"),
403 }
404 trait_ref.to_tokens(tokens);
405 }
406 }
407 }
408 }
409
410 impl ToTokens for WhereClause {
411 fn to_tokens(&self, tokens: &mut Tokens) {
412 if !self.predicates.is_empty() {
413 tokens.append("where");
414 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700415 }
416 }
417 }
David Tolnay8ef93042016-09-04 14:08:40 -0700418
419 impl ToTokens for WherePredicate {
420 fn to_tokens(&self, tokens: &mut Tokens) {
421 match *self {
422 WherePredicate::BoundPredicate(ref predicate) => {
423 predicate.to_tokens(tokens);
424 }
425 WherePredicate::RegionPredicate(ref predicate) => {
426 predicate.to_tokens(tokens);
427 }
David Tolnayf8e08832017-01-23 00:04:32 -0800428 WherePredicate::EqPredicate(ref predicate) => {
429 predicate.to_tokens(tokens);
430 }
David Tolnay8ef93042016-09-04 14:08:40 -0700431 }
432 }
433 }
434
435 impl ToTokens for WhereBoundPredicate {
436 fn to_tokens(&self, tokens: &mut Tokens) {
437 if !self.bound_lifetimes.is_empty() {
438 tokens.append("for");
439 tokens.append("<");
440 tokens.append_separated(&self.bound_lifetimes, ",");
441 tokens.append(">");
442 }
443 self.bounded_ty.to_tokens(tokens);
444 if !self.bounds.is_empty() {
445 tokens.append(":");
446 tokens.append_separated(&self.bounds, "+");
447 }
448 }
449 }
450
451 impl ToTokens for WhereRegionPredicate {
452 fn to_tokens(&self, tokens: &mut Tokens) {
453 self.lifetime.to_tokens(tokens);
454 if !self.bounds.is_empty() {
455 tokens.append(":");
456 tokens.append_separated(&self.bounds, "+");
457 }
458 }
459 }
David Tolnayf8e08832017-01-23 00:04:32 -0800460
461 impl ToTokens for WhereEqPredicate {
462 fn to_tokens(&self, tokens: &mut Tokens) {
463 self.lhs_ty.to_tokens(tokens);
464 tokens.append("=");
465 self.rhs_ty.to_tokens(tokens);
466 }
467 }
David Tolnay87d0b442016-09-04 11:52:12 -0700468}