blob: 674e62664e128b8047eefc1c18ba2a3b6e6b366e [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 Tolnayb153dbc2016-10-04 23:39:10 -070012impl Generics {
13 /// Split a type's generics into the pieces required for impl'ing a trait
14 /// for that type.
15 ///
16 /// ```
17 /// # extern crate syn;
18 /// # #[macro_use]
19 /// # extern crate quote;
20 /// # fn main() {
21 /// # let generics: syn::Generics = Default::default();
22 /// # let name = syn::Ident::new("MyType");
23 /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
24 /// quote! {
25 /// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
26 /// // ...
27 /// }
28 /// }
29 /// # ;
30 /// # }
31 /// ```
32 pub fn split_for_impl(&self) -> (Generics, Generics, WhereClause) {
33 // Remove where clause and type parameter defaults.
34 let impl_generics = Generics {
35 lifetimes: self.lifetimes.clone(),
36 ty_params: self.ty_params.iter().map(|ty_param| {
37 TyParam {
38 ident: ty_param.ident.clone(),
39 bounds: ty_param.bounds.clone(),
40 default: None,
41 }}).collect(),
42 where_clause: WhereClause::none(),
43 };
44
45 // Remove where clause, type parameter defaults, and bounds.
46 let ty_generics = Generics {
47 lifetimes: self.lifetimes.iter().map(|lifetime_def| {
48 LifetimeDef {
49 lifetime: lifetime_def.lifetime.clone(),
50 bounds: Vec::new(),
51 }}).collect(),
52 ty_params: self.ty_params.iter().map(|ty_param| {
53 TyParam {
54 ident: ty_param.ident.clone(),
55 bounds: Vec::new(),
56 default: None,
57 }}).collect(),
58 where_clause: WhereClause::none(),
59 };
60
61 let where_clause = self.where_clause.clone();
62
63 (impl_generics, ty_generics, where_clause)
64 }
65}
66
David Tolnayb79ee962016-09-04 09:39:20 -070067#[derive(Debug, Clone, Eq, PartialEq)]
68pub struct Lifetime {
69 pub ident: Ident,
70}
71
David Tolnay01405f02016-10-02 09:05:02 -070072impl Lifetime {
73 pub fn new<T: Into<Ident>>(t: T) -> Self {
David Tolnaydaaf7742016-10-03 11:11:43 -070074 Lifetime { ident: Ident::new(t) }
David Tolnay01405f02016-10-02 09:05:02 -070075 }
76}
77
David Tolnay771ecf42016-09-23 19:26:37 -070078/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070079#[derive(Debug, Clone, Eq, PartialEq)]
80pub struct LifetimeDef {
81 pub lifetime: Lifetime,
82 pub bounds: Vec<Lifetime>,
83}
84
David Tolnayf9505b52016-10-02 09:18:52 -070085impl LifetimeDef {
86 pub fn new<T: Into<Ident>>(t: T) -> Self {
87 LifetimeDef {
88 lifetime: Lifetime::new(t),
89 bounds: Vec::new(),
90 }
91 }
92}
93
David Tolnayb79ee962016-09-04 09:39:20 -070094#[derive(Debug, Clone, Eq, PartialEq)]
95pub struct TyParam {
96 pub ident: Ident,
97 pub bounds: Vec<TyParamBound>,
98 pub default: Option<Ty>,
99}
100
David Tolnay771ecf42016-09-23 19:26:37 -0700101/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -0700102/// `typeck::collect::compute_bounds` matches these against
103/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -0700104/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -0700105#[derive(Debug, Clone, Eq, PartialEq)]
106pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -0700107 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -0700108 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -0700109}
110
David Tolnay771ecf42016-09-23 19:26:37 -0700111/// A modifier on a bound, currently this is only used for `?Sized`, where the
112/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -0700113#[derive(Debug, Copy, Clone, Eq, PartialEq)]
114pub enum TraitBoundModifier {
115 None,
116 Maybe,
117}
118
David Tolnay771ecf42016-09-23 19:26:37 -0700119/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -0700120#[derive(Debug, Clone, Eq, PartialEq, Default)]
121pub struct WhereClause {
122 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700123}
124
David Tolnayb153dbc2016-10-04 23:39:10 -0700125impl WhereClause {
126 pub fn none() -> Self {
127 WhereClause {
128 predicates: Vec::new(),
129 }
130 }
131}
132
David Tolnayb79ee962016-09-04 09:39:20 -0700133/// A single predicate in a `where` clause
134#[derive(Debug, Clone, Eq, PartialEq)]
135pub enum WherePredicate {
136 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
137 BoundPredicate(WhereBoundPredicate),
138 /// A lifetime predicate, e.g. `'a: 'b+'c`
139 RegionPredicate(WhereRegionPredicate),
140}
141
142/// A type bound.
143///
144/// E.g. `for<'c> Foo: Send+Clone+'c`
145#[derive(Debug, Clone, Eq, PartialEq)]
146pub struct WhereBoundPredicate {
147 /// Any lifetimes from a `for` binding
148 pub bound_lifetimes: Vec<LifetimeDef>,
149 /// The type being bounded
150 pub bounded_ty: Ty,
151 /// Trait and lifetime bounds (`Clone+Send+'static`)
152 pub bounds: Vec<TyParamBound>,
153}
154
155/// A lifetime predicate.
156///
157/// E.g. `'a: 'b+'c`
158#[derive(Debug, Clone, Eq, PartialEq)]
159pub struct WhereRegionPredicate {
160 pub lifetime: Lifetime,
161 pub bounds: Vec<Lifetime>,
162}
163
David Tolnay86eca752016-09-04 11:26:41 -0700164#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700165pub mod parsing {
166 use super::*;
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 )) >>
179 punct!(">") >>
180 (lifetimes, ty_params)
181 )
182 |
183 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700184 ),
185 |(lifetimes, ty_params)| Generics {
186 lifetimes: lifetimes,
187 ty_params: ty_params,
188 where_clause: Default::default(),
189 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700190 ));
191
David Tolnayb5a7b142016-09-13 22:46:39 -0700192 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700193 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700194 map!(ident, |id| Lifetime {
195 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700196 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700197 ));
198
David Tolnayb5a7b142016-09-13 22:46:39 -0700199 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700200 life: lifetime >>
201 bounds: opt_vec!(preceded!(
202 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700203 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700204 )) >>
205 (LifetimeDef {
206 lifetime: life,
207 bounds: bounds,
208 })
209 ));
210
David Tolnayb5a7b142016-09-13 22:46:39 -0700211 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700212 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700213 punct!("<") >>
214 lifetimes: separated_list!(punct!(","), lifetime_def) >>
215 punct!(">") >>
216 (lifetimes)
217 )));
218
David Tolnayb5a7b142016-09-13 22:46:39 -0700219 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700220 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700221 bounds: opt_vec!(preceded!(
222 punct!(":"),
223 separated_nonempty_list!(punct!("+"), ty_param_bound)
224 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700225 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700226 punct!("="),
227 ty
228 )) >>
229 (TyParam {
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 >>
262 punct!(":") >>
263 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
264 (WherePredicate::RegionPredicate(WhereRegionPredicate {
265 lifetime: ident,
266 bounds: bounds,
267 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700268 )
269 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700270 do_parse!(
271 bound_lifetimes: bound_lifetimes >>
272 bounded_ty: ty >>
273 punct!(":") >>
274 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
275 (WherePredicate::BoundPredicate(WhereBoundPredicate {
276 bound_lifetimes: bound_lifetimes,
277 bounded_ty: bounded_ty,
278 bounds: bounds,
279 }))
280 )
281 ));
282}
David Tolnay87d0b442016-09-04 11:52:12 -0700283
284#[cfg(feature = "printing")]
285mod printing {
286 use super::*;
287 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 Tolnay87d0b442016-09-04 11:52:12 -0700305 impl ToTokens for Lifetime {
306 fn to_tokens(&self, tokens: &mut Tokens) {
307 self.ident.to_tokens(tokens);
308 }
309 }
310
311 impl ToTokens for LifetimeDef {
312 fn to_tokens(&self, tokens: &mut Tokens) {
313 self.lifetime.to_tokens(tokens);
314 if !self.bounds.is_empty() {
315 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700316 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700317 }
318 }
319 }
320
David Tolnay8ef93042016-09-04 14:08:40 -0700321 impl ToTokens for TyParam {
322 fn to_tokens(&self, tokens: &mut Tokens) {
323 self.ident.to_tokens(tokens);
324 if !self.bounds.is_empty() {
325 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700326 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700327 }
328 if let Some(ref default) = self.default {
329 tokens.append("=");
330 default.to_tokens(tokens);
331 }
332 }
333 }
334
David Tolnay87d0b442016-09-04 11:52:12 -0700335 impl ToTokens for TyParamBound {
336 fn to_tokens(&self, tokens: &mut Tokens) {
337 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700338 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700339 TyParamBound::Trait(ref trait_ref, modifier) => {
340 match modifier {
341 TraitBoundModifier::None => {}
342 TraitBoundModifier::Maybe => tokens.append("?"),
343 }
344 trait_ref.to_tokens(tokens);
345 }
346 }
347 }
348 }
349
350 impl ToTokens for WhereClause {
351 fn to_tokens(&self, tokens: &mut Tokens) {
352 if !self.predicates.is_empty() {
353 tokens.append("where");
354 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700355 }
356 }
357 }
David Tolnay8ef93042016-09-04 14:08:40 -0700358
359 impl ToTokens for WherePredicate {
360 fn to_tokens(&self, tokens: &mut Tokens) {
361 match *self {
362 WherePredicate::BoundPredicate(ref predicate) => {
363 predicate.to_tokens(tokens);
364 }
365 WherePredicate::RegionPredicate(ref predicate) => {
366 predicate.to_tokens(tokens);
367 }
368 }
369 }
370 }
371
372 impl ToTokens for WhereBoundPredicate {
373 fn to_tokens(&self, tokens: &mut Tokens) {
374 if !self.bound_lifetimes.is_empty() {
375 tokens.append("for");
376 tokens.append("<");
377 tokens.append_separated(&self.bound_lifetimes, ",");
378 tokens.append(">");
379 }
380 self.bounded_ty.to_tokens(tokens);
381 if !self.bounds.is_empty() {
382 tokens.append(":");
383 tokens.append_separated(&self.bounds, "+");
384 }
385 }
386 }
387
388 impl ToTokens for WhereRegionPredicate {
389 fn to_tokens(&self, tokens: &mut Tokens) {
390 self.lifetime.to_tokens(tokens);
391 if !self.bounds.is_empty() {
392 tokens.append(":");
393 tokens.append_separated(&self.bounds, "+");
394 }
395 }
396 }
David Tolnay87d0b442016-09-04 11:52:12 -0700397}