blob: 47ff003b9128eb420fe9592c65c68a2111a8c5c6 [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 Tolnayc94c38a2016-09-05 17:02:03 -0700199 separated_nonempty_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 >>
261 punct!(":") >>
262 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
263 (WherePredicate::RegionPredicate(WhereRegionPredicate {
264 lifetime: ident,
265 bounds: bounds,
266 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700267 )
268 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700269 do_parse!(
270 bound_lifetimes: bound_lifetimes >>
271 bounded_ty: ty >>
272 punct!(":") >>
273 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
274 (WherePredicate::BoundPredicate(WhereBoundPredicate {
275 bound_lifetimes: bound_lifetimes,
276 bounded_ty: bounded_ty,
277 bounds: bounds,
278 }))
279 )
280 ));
281}
David Tolnay87d0b442016-09-04 11:52:12 -0700282
283#[cfg(feature = "printing")]
284mod printing {
285 use super::*;
David Tolnaye7678922016-10-13 20:44:03 -0700286 use attr::FilterAttrs;
David Tolnay87d0b442016-09-04 11:52:12 -0700287 use quote::{Tokens, ToTokens};
288
David Tolnay8ef93042016-09-04 14:08:40 -0700289 impl ToTokens for Generics {
290 fn to_tokens(&self, tokens: &mut Tokens) {
291 let has_lifetimes = !self.lifetimes.is_empty();
292 let has_ty_params = !self.ty_params.is_empty();
293 if has_lifetimes || has_ty_params {
294 tokens.append("<");
295 tokens.append_separated(&self.lifetimes, ",");
296 if has_lifetimes && has_ty_params {
297 tokens.append(",");
298 }
299 tokens.append_separated(&self.ty_params, ",");
300 tokens.append(">");
301 }
David Tolnay8ef93042016-09-04 14:08:40 -0700302 }
303 }
304
David Tolnaye7678922016-10-13 20:44:03 -0700305 impl<'a> ToTokens for ImplGenerics<'a> {
306 fn to_tokens(&self, tokens: &mut Tokens) {
307 let has_lifetimes = !self.0.lifetimes.is_empty();
308 let has_ty_params = !self.0.ty_params.is_empty();
309 if has_lifetimes || has_ty_params {
310 tokens.append("<");
311 tokens.append_separated(&self.0.lifetimes, ",");
312 // Leave off the type parameter defaults
313 for (i, ty_param) in self.0.ty_params.iter().enumerate() {
314 if i > 0 || has_lifetimes {
315 tokens.append(",");
316 }
317 tokens.append_all(ty_param.attrs.outer());
318 ty_param.ident.to_tokens(tokens);
319 if !ty_param.bounds.is_empty() {
320 tokens.append(":");
321 tokens.append_separated(&ty_param.bounds, "+");
322 }
323 }
324 tokens.append(">");
325 }
326 }
327 }
328
329 impl<'a> ToTokens for TyGenerics<'a> {
330 fn to_tokens(&self, tokens: &mut Tokens) {
331 let has_lifetimes = !self.0.lifetimes.is_empty();
332 let has_ty_params = !self.0.ty_params.is_empty();
333 if has_lifetimes || has_ty_params {
334 tokens.append("<");
335 // Leave off the lifetime bounds and attributes
336 let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
337 tokens.append_separated(lifetimes, ",");
338 if has_lifetimes && has_ty_params {
339 tokens.append(",");
340 }
341 // Leave off the type parameter bounds, defaults, and attributes
342 let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
343 tokens.append_separated(ty_params, ",");
344 tokens.append(">");
345 }
346 }
347 }
348
David Tolnay87d0b442016-09-04 11:52:12 -0700349 impl ToTokens for Lifetime {
350 fn to_tokens(&self, tokens: &mut Tokens) {
351 self.ident.to_tokens(tokens);
352 }
353 }
354
355 impl ToTokens for LifetimeDef {
356 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700357 tokens.append_all(self.attrs.outer());
David Tolnay87d0b442016-09-04 11:52:12 -0700358 self.lifetime.to_tokens(tokens);
359 if !self.bounds.is_empty() {
360 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700361 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700362 }
363 }
364 }
365
David Tolnay8ef93042016-09-04 14:08:40 -0700366 impl ToTokens for TyParam {
367 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnaye7678922016-10-13 20:44:03 -0700368 tokens.append_all(self.attrs.outer());
David Tolnay8ef93042016-09-04 14:08:40 -0700369 self.ident.to_tokens(tokens);
370 if !self.bounds.is_empty() {
371 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700372 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700373 }
374 if let Some(ref default) = self.default {
375 tokens.append("=");
376 default.to_tokens(tokens);
377 }
378 }
379 }
380
David Tolnay87d0b442016-09-04 11:52:12 -0700381 impl ToTokens for TyParamBound {
382 fn to_tokens(&self, tokens: &mut Tokens) {
383 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700384 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700385 TyParamBound::Trait(ref trait_ref, modifier) => {
386 match modifier {
387 TraitBoundModifier::None => {}
388 TraitBoundModifier::Maybe => tokens.append("?"),
389 }
390 trait_ref.to_tokens(tokens);
391 }
392 }
393 }
394 }
395
396 impl ToTokens for WhereClause {
397 fn to_tokens(&self, tokens: &mut Tokens) {
398 if !self.predicates.is_empty() {
399 tokens.append("where");
400 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700401 }
402 }
403 }
David Tolnay8ef93042016-09-04 14:08:40 -0700404
405 impl ToTokens for WherePredicate {
406 fn to_tokens(&self, tokens: &mut Tokens) {
407 match *self {
408 WherePredicate::BoundPredicate(ref predicate) => {
409 predicate.to_tokens(tokens);
410 }
411 WherePredicate::RegionPredicate(ref predicate) => {
412 predicate.to_tokens(tokens);
413 }
414 }
415 }
416 }
417
418 impl ToTokens for WhereBoundPredicate {
419 fn to_tokens(&self, tokens: &mut Tokens) {
420 if !self.bound_lifetimes.is_empty() {
421 tokens.append("for");
422 tokens.append("<");
423 tokens.append_separated(&self.bound_lifetimes, ",");
424 tokens.append(">");
425 }
426 self.bounded_ty.to_tokens(tokens);
427 if !self.bounds.is_empty() {
428 tokens.append(":");
429 tokens.append_separated(&self.bounds, "+");
430 }
431 }
432 }
433
434 impl ToTokens for WhereRegionPredicate {
435 fn to_tokens(&self, tokens: &mut Tokens) {
436 self.lifetime.to_tokens(tokens);
437 if !self.bounds.is_empty() {
438 tokens.append(":");
439 tokens.append_separated(&self.bounds, "+");
440 }
441 }
442 }
David Tolnay87d0b442016-09-04 11:52:12 -0700443}