blob: d76051f4089b996cdb570597dba11684c84fb38f [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),
128}
129
130/// A type bound.
131///
132/// E.g. `for<'c> Foo: Send+Clone+'c`
David Tolnay9bf4af82017-01-07 11:17:46 -0800133#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700134pub 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`
David Tolnay9bf4af82017-01-07 11:17:46 -0800146#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayb79ee962016-09-04 09:39:20 -0700147pub 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 )) >>
David Tolnay82a47d52016-10-30 13:01:38 -0700168 cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700169 punct!(">") >>
170 (lifetimes, ty_params)
171 )
172 |
173 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700174 ),
175 |(lifetimes, ty_params)| Generics {
176 lifetimes: lifetimes,
177 ty_params: ty_params,
178 where_clause: Default::default(),
179 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700180 ));
181
David Tolnayb5a7b142016-09-13 22:46:39 -0700182 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700183 punct!("'"),
David Tolnaye43ffb72016-10-24 22:33:31 -0700184 alt!(
185 map!(ident, |id| Lifetime {
186 ident: format!("'{}", id).into(),
187 })
188 |
189 map!(keyword!("static"), |_| Lifetime {
190 ident: "'static".into(),
191 })
192 )
David Tolnay9d8f1972016-09-04 11:58:48 -0700193 ));
194
David Tolnayb5a7b142016-09-13 22:46:39 -0700195 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700196 attrs: many0!(outer_attr) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700197 life: lifetime >>
198 bounds: opt_vec!(preceded!(
199 punct!(":"),
David Tolnayd95baae2016-10-30 00:47:53 -0700200 separated_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700201 )) >>
202 (LifetimeDef {
David Tolnaye7678922016-10-13 20:44:03 -0700203 attrs: attrs,
David Tolnay9d8f1972016-09-04 11:58:48 -0700204 lifetime: life,
205 bounds: bounds,
206 })
207 ));
208
David Tolnayb5a7b142016-09-13 22:46:39 -0700209 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700210 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700211 punct!("<") >>
David Tolnayff46fd22016-10-08 13:53:28 -0700212 lifetimes: terminated_list!(punct!(","), lifetime_def) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700213 punct!(">") >>
214 (lifetimes)
215 )));
216
David Tolnayb5a7b142016-09-13 22:46:39 -0700217 named!(ty_param -> TyParam, do_parse!(
David Tolnaye7678922016-10-13 20:44:03 -0700218 attrs: many0!(outer_attr) >>
David Tolnay55337722016-09-11 12:58:56 -0700219 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700220 bounds: opt_vec!(preceded!(
221 punct!(":"),
222 separated_nonempty_list!(punct!("+"), ty_param_bound)
223 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700224 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700225 punct!("="),
226 ty
227 )) >>
228 (TyParam {
David Tolnaye7678922016-10-13 20:44:03 -0700229 attrs: attrs,
David Tolnay55337722016-09-11 12:58:56 -0700230 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700231 bounds: bounds,
232 default: default,
233 })
234 ));
235
David Tolnayb5a7b142016-09-13 22:46:39 -0700236 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700237 preceded!(punct!("?"), poly_trait_ref) => {
238 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
239 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700240 |
241 lifetime => { TyParamBound::Region }
242 |
David Tolnay55337722016-09-11 12:58:56 -0700243 poly_trait_ref => {
244 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
245 }
246 ));
247
David Tolnayb5a7b142016-09-13 22:46:39 -0700248 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700249 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700250 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700251 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
252 option!(punct!(",")) >>
253 (WhereClause { predicates: predicates })
254 )
255 |
256 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700257 ));
258
David Tolnayb5a7b142016-09-13 22:46:39 -0700259 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700260 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700261 ident: lifetime >>
David Tolnayd95baae2016-10-30 00:47:53 -0700262 bounds: opt_vec!(preceded!(
263 punct!(":"),
264 separated_list!(punct!("+"), lifetime)
265 )) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700266 (WherePredicate::RegionPredicate(WhereRegionPredicate {
267 lifetime: ident,
268 bounds: bounds,
269 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700270 )
271 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700272 do_parse!(
273 bound_lifetimes: bound_lifetimes >>
274 bounded_ty: ty >>
275 punct!(":") >>
276 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
277 (WherePredicate::BoundPredicate(WhereBoundPredicate {
278 bound_lifetimes: bound_lifetimes,
279 bounded_ty: bounded_ty,
280 bounds: bounds,
281 }))
282 )
283 ));
284}
David Tolnay87d0b442016-09-04 11:52:12 -0700285
286#[cfg(feature = "printing")]
287mod printing {
288 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700289 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700290 use quote::{Tokens, ToTokens};
291
David Tolnay8ef93042016-09-04 14:08:40 -0700292 impl ToTokens for Generics {
293 fn to_tokens(&self, tokens: &mut Tokens) {
294 let has_lifetimes = !self.lifetimes.is_empty();
295 let has_ty_params = !self.ty_params.is_empty();
296 if has_lifetimes || has_ty_params {
297 tokens.append("<");
298 tokens.append_separated(&self.lifetimes, ",");
299 if has_lifetimes && has_ty_params {
300 tokens.append(",");
301 }
302 tokens.append_separated(&self.ty_params, ",");
303 tokens.append(">");
304 }
David Tolnay8ef93042016-09-04 14:08:40 -0700305 }
306 }
307
David Tolnaye7678922016-10-13 20:44:03 -0700308 impl<'a> ToTokens for ImplGenerics<'a> {
309 fn to_tokens(&self, tokens: &mut Tokens) {
310 let has_lifetimes = !self.0.lifetimes.is_empty();
311 let has_ty_params = !self.0.ty_params.is_empty();
312 if has_lifetimes || has_ty_params {
313 tokens.append("<");
314 tokens.append_separated(&self.0.lifetimes, ",");
315 // Leave off the type parameter defaults
316 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
317 if i > 0 || has_lifetimes {
318 tokens.append(",");
319 }
320 tokens.append_all(ty_param.attrs.outer());
321 ty_param.ident.to_tokens(tokens);
322 if !ty_param.bounds.is_empty() {
323 tokens.append(":");
324 tokens.append_separated(&ty_param.bounds, "+");
325 }
326 }
327 tokens.append(">");
328 }
329 }
330 }
331
332 impl<'a> ToTokens for TyGenerics<'a> {
333 fn to_tokens(&self, tokens: &mut Tokens) {
334 let has_lifetimes = !self.0.lifetimes.is_empty();
335 let has_ty_params = !self.0.ty_params.is_empty();
336 if has_lifetimes || has_ty_params {
337 tokens.append("<");
338 // Leave off the lifetime bounds and attributes
339 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
340 tokens.append_separated(lifetimes, ",");
341 if has_lifetimes && has_ty_params {
342 tokens.append(",");
343 }
344 // Leave off the type parameter bounds, defaults, and attributes
345 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
346 tokens.append_separated(ty_params, ",");
347 tokens.append(">");
348 }
349 }
350 }
351
David Tolnay87d0b442016-09-04 11:52:12 -0700352 impl ToTokens for Lifetime {
353 fn to_tokens(&self, tokens: &mut Tokens) {
354 self.ident.to_tokens(tokens);
355 }
356 }
357
358 impl ToTokens for LifetimeDef {
359 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700360 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700361 self.lifetime.to_tokens(tokens);
362 if !self.bounds.is_empty() {
363 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700364 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700365 }
366 }
367 }
368
David Tolnay8ef93042016-09-04 14:08:40 -0700369 impl ToTokens for TyParam {
370 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700371 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700372 self.ident.to_tokens(tokens);
373 if !self.bounds.is_empty() {
374 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700375 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700376 }
377 if let Some(ref default) = self.default {
378 tokens.append("=");
379 default.to_tokens(tokens);
380 }
381 }
382 }
383
David Tolnay87d0b442016-09-04 11:52:12 -0700384 impl ToTokens for TyParamBound {
385 fn to_tokens(&self, tokens: &mut Tokens) {
386 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700387 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700388 TyParamBound::Trait(ref trait_ref, modifier) => {
389 match modifier {
390 TraitBoundModifier::None => {}
391 TraitBoundModifier::Maybe => tokens.append("?"),
392 }
393 trait_ref.to_tokens(tokens);
394 }
395 }
396 }
397 }
398
399 impl ToTokens for WhereClause {
400 fn to_tokens(&self, tokens: &mut Tokens) {
401 if !self.predicates.is_empty() {
402 tokens.append("where");
403 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700404 }
405 }
406 }
David Tolnay8ef93042016-09-04 14:08:40 -0700407
408 impl ToTokens for WherePredicate {
409 fn to_tokens(&self, tokens: &mut Tokens) {
410 match *self {
411 WherePredicate::BoundPredicate(ref predicate) => {
412 predicate.to_tokens(tokens);
413 }
414 WherePredicate::RegionPredicate(ref predicate) => {
415 predicate.to_tokens(tokens);
416 }
417 }
418 }
419 }
420
421 impl ToTokens for WhereBoundPredicate {
422 fn to_tokens(&self, tokens: &mut Tokens) {
423 if !self.bound_lifetimes.is_empty() {
424 tokens.append("for");
425 tokens.append("<");
426 tokens.append_separated(&self.bound_lifetimes, ",");
427 tokens.append(">");
428 }
429 self.bounded_ty.to_tokens(tokens);
430 if !self.bounds.is_empty() {
431 tokens.append(":");
432 tokens.append_separated(&self.bounds, "+");
433 }
434 }
435 }
436
437 impl ToTokens for WhereRegionPredicate {
438 fn to_tokens(&self, tokens: &mut Tokens) {
439 self.lifetime.to_tokens(tokens);
440 if !self.bounds.is_empty() {
441 tokens.append(":");
442 tokens.append_separated(&self.bounds, "+");
443 }
444 }
445 }
David Tolnay87d0b442016-09-04 11:52:12 -0700446}