blob: aa8856d20a3c2d81e38cfb3dde2d63b14c763538 [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(),
David Tolnay2e737362016-10-05 23:44:15 -070036 ty_params: self.ty_params
37 .iter()
38 .map(|ty_param| {
39 TyParam {
40 ident: ty_param.ident.clone(),
41 bounds: ty_param.bounds.clone(),
42 default: None,
43 }
44 })
45 .collect(),
David Tolnayb153dbc2016-10-04 23:39:10 -070046 where_clause: WhereClause::none(),
47 };
48
49 // Remove where clause, type parameter defaults, and bounds.
50 let ty_generics = Generics {
David Tolnay2e737362016-10-05 23:44:15 -070051 lifetimes: self.lifetimes
52 .iter()
53 .map(|lifetime_def| {
54 LifetimeDef {
55 lifetime: lifetime_def.lifetime.clone(),
56 bounds: Vec::new(),
57 }
58 })
59 .collect(),
60 ty_params: self.ty_params
61 .iter()
62 .map(|ty_param| {
63 TyParam {
64 ident: ty_param.ident.clone(),
65 bounds: Vec::new(),
66 default: None,
67 }
68 })
69 .collect(),
David Tolnayb153dbc2016-10-04 23:39:10 -070070 where_clause: WhereClause::none(),
71 };
72
73 let where_clause = self.where_clause.clone();
74
75 (impl_generics, ty_generics, where_clause)
76 }
77}
78
David Tolnayb79ee962016-09-04 09:39:20 -070079#[derive(Debug, Clone, Eq, PartialEq)]
80pub struct Lifetime {
81 pub ident: Ident,
82}
83
David Tolnay01405f02016-10-02 09:05:02 -070084impl Lifetime {
85 pub fn new<T: Into<Ident>>(t: T) -> Self {
David Tolnaydaaf7742016-10-03 11:11:43 -070086 Lifetime { ident: Ident::new(t) }
David Tolnay01405f02016-10-02 09:05:02 -070087 }
88}
89
David Tolnay771ecf42016-09-23 19:26:37 -070090/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070091#[derive(Debug, Clone, Eq, PartialEq)]
92pub struct LifetimeDef {
93 pub lifetime: Lifetime,
94 pub bounds: Vec<Lifetime>,
95}
96
David Tolnayf9505b52016-10-02 09:18:52 -070097impl LifetimeDef {
98 pub fn new<T: Into<Ident>>(t: T) -> Self {
99 LifetimeDef {
100 lifetime: Lifetime::new(t),
101 bounds: Vec::new(),
102 }
103 }
104}
105
David Tolnayb79ee962016-09-04 09:39:20 -0700106#[derive(Debug, Clone, Eq, PartialEq)]
107pub struct TyParam {
108 pub ident: Ident,
109 pub bounds: Vec<TyParamBound>,
110 pub default: Option<Ty>,
111}
112
David Tolnay771ecf42016-09-23 19:26:37 -0700113/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -0700114/// `typeck::collect::compute_bounds` matches these against
115/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -0700116/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -0700117#[derive(Debug, Clone, Eq, PartialEq)]
118pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -0700119 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -0700120 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -0700121}
122
David Tolnay771ecf42016-09-23 19:26:37 -0700123/// A modifier on a bound, currently this is only used for `?Sized`, where the
124/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -0700125#[derive(Debug, Copy, Clone, Eq, PartialEq)]
126pub enum TraitBoundModifier {
127 None,
128 Maybe,
129}
130
David Tolnay771ecf42016-09-23 19:26:37 -0700131/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -0700132#[derive(Debug, Clone, Eq, PartialEq, Default)]
133pub struct WhereClause {
134 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700135}
136
David Tolnayb153dbc2016-10-04 23:39:10 -0700137impl WhereClause {
138 pub fn none() -> Self {
David Tolnay2e737362016-10-05 23:44:15 -0700139 WhereClause { predicates: Vec::new() }
David Tolnayb153dbc2016-10-04 23:39:10 -0700140 }
141}
142
David Tolnayb79ee962016-09-04 09:39:20 -0700143/// A single predicate in a `where` clause
144#[derive(Debug, Clone, Eq, PartialEq)]
145pub enum WherePredicate {
146 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
147 BoundPredicate(WhereBoundPredicate),
148 /// A lifetime predicate, e.g. `'a: 'b+'c`
149 RegionPredicate(WhereRegionPredicate),
150}
151
152/// A type bound.
153///
154/// E.g. `for<'c> Foo: Send+Clone+'c`
155#[derive(Debug, Clone, Eq, PartialEq)]
156pub struct WhereBoundPredicate {
157 /// Any lifetimes from a `for` binding
158 pub bound_lifetimes: Vec<LifetimeDef>,
159 /// The type being bounded
160 pub bounded_ty: Ty,
161 /// Trait and lifetime bounds (`Clone+Send+'static`)
162 pub bounds: Vec<TyParamBound>,
163}
164
165/// A lifetime predicate.
166///
167/// E.g. `'a: 'b+'c`
168#[derive(Debug, Clone, Eq, PartialEq)]
169pub struct WhereRegionPredicate {
170 pub lifetime: Lifetime,
171 pub bounds: Vec<Lifetime>,
172}
173
David Tolnay86eca752016-09-04 11:26:41 -0700174#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700175pub mod parsing {
176 use super::*;
David Tolnay55337722016-09-11 12:58:56 -0700177 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700178 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700179
David Tolnay3cf52982016-10-01 17:11:37 -0700180 named!(pub generics -> Generics, map!(
181 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700182 do_parse!(
183 punct!("<") >>
184 lifetimes: separated_list!(punct!(","), lifetime_def) >>
185 ty_params: opt_vec!(preceded!(
186 cond!(!lifetimes.is_empty(), punct!(",")),
187 separated_nonempty_list!(punct!(","), ty_param)
188 )) >>
189 punct!(">") >>
190 (lifetimes, ty_params)
191 )
192 |
193 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700194 ),
195 |(lifetimes, ty_params)| Generics {
196 lifetimes: lifetimes,
197 ty_params: ty_params,
198 where_clause: Default::default(),
199 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700200 ));
201
David Tolnayb5a7b142016-09-13 22:46:39 -0700202 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700203 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700204 map!(ident, |id| Lifetime {
205 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700206 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700207 ));
208
David Tolnayb5a7b142016-09-13 22:46:39 -0700209 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700210 life: lifetime >>
211 bounds: opt_vec!(preceded!(
212 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700213 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700214 )) >>
215 (LifetimeDef {
216 lifetime: life,
217 bounds: bounds,
218 })
219 ));
220
David Tolnayb5a7b142016-09-13 22:46:39 -0700221 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700222 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700223 punct!("<") >>
224 lifetimes: separated_list!(punct!(","), lifetime_def) >>
225 punct!(">") >>
226 (lifetimes)
227 )));
228
David Tolnayb5a7b142016-09-13 22:46:39 -0700229 named!(ty_param -> TyParam, do_parse!(
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 Tolnay55337722016-09-11 12:58:56 -0700240 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700241 bounds: bounds,
242 default: default,
243 })
244 ));
245
David Tolnayb5a7b142016-09-13 22:46:39 -0700246 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700247 preceded!(punct!("?"), poly_trait_ref) => {
248 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
249 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700250 |
251 lifetime => { TyParamBound::Region }
252 |
David Tolnay55337722016-09-11 12:58:56 -0700253 poly_trait_ref => {
254 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
255 }
256 ));
257
David Tolnayb5a7b142016-09-13 22:46:39 -0700258 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700259 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700260 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700261 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
262 option!(punct!(",")) >>
263 (WhereClause { predicates: predicates })
264 )
265 |
266 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700267 ));
268
David Tolnayb5a7b142016-09-13 22:46:39 -0700269 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700270 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700271 ident: lifetime >>
272 punct!(":") >>
273 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
274 (WherePredicate::RegionPredicate(WhereRegionPredicate {
275 lifetime: ident,
276 bounds: bounds,
277 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700278 )
279 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700280 do_parse!(
281 bound_lifetimes: bound_lifetimes >>
282 bounded_ty: ty >>
283 punct!(":") >>
284 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
285 (WherePredicate::BoundPredicate(WhereBoundPredicate {
286 bound_lifetimes: bound_lifetimes,
287 bounded_ty: bounded_ty,
288 bounds: bounds,
289 }))
290 )
291 ));
292}
David Tolnay87d0b442016-09-04 11:52:12 -0700293
294#[cfg(feature = "printing")]
295mod printing {
296 use super::*;
297 use quote::{Tokens, ToTokens};
298
David Tolnay8ef93042016-09-04 14:08:40 -0700299 impl ToTokens for Generics {
300 fn to_tokens(&self, tokens: &mut Tokens) {
301 let has_lifetimes = !self.lifetimes.is_empty();
302 let has_ty_params = !self.ty_params.is_empty();
303 if has_lifetimes || has_ty_params {
304 tokens.append("<");
305 tokens.append_separated(&self.lifetimes, ",");
306 if has_lifetimes && has_ty_params {
307 tokens.append(",");
308 }
309 tokens.append_separated(&self.ty_params, ",");
310 tokens.append(">");
311 }
David Tolnay8ef93042016-09-04 14:08:40 -0700312 }
313 }
314
David Tolnay87d0b442016-09-04 11:52:12 -0700315 impl ToTokens for Lifetime {
316 fn to_tokens(&self, tokens: &mut Tokens) {
317 self.ident.to_tokens(tokens);
318 }
319 }
320
321 impl ToTokens for LifetimeDef {
322 fn to_tokens(&self, tokens: &mut Tokens) {
323 self.lifetime.to_tokens(tokens);
324 if !self.bounds.is_empty() {
325 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700326 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700327 }
328 }
329 }
330
David Tolnay8ef93042016-09-04 14:08:40 -0700331 impl ToTokens for TyParam {
332 fn to_tokens(&self, tokens: &mut Tokens) {
333 self.ident.to_tokens(tokens);
334 if !self.bounds.is_empty() {
335 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700336 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700337 }
338 if let Some(ref default) = self.default {
339 tokens.append("=");
340 default.to_tokens(tokens);
341 }
342 }
343 }
344
David Tolnay87d0b442016-09-04 11:52:12 -0700345 impl ToTokens for TyParamBound {
346 fn to_tokens(&self, tokens: &mut Tokens) {
347 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700348 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700349 TyParamBound::Trait(ref trait_ref, modifier) => {
350 match modifier {
351 TraitBoundModifier::None => {}
352 TraitBoundModifier::Maybe => tokens.append("?"),
353 }
354 trait_ref.to_tokens(tokens);
355 }
356 }
357 }
358 }
359
360 impl ToTokens for WhereClause {
361 fn to_tokens(&self, tokens: &mut Tokens) {
362 if !self.predicates.is_empty() {
363 tokens.append("where");
364 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700365 }
366 }
367 }
David Tolnay8ef93042016-09-04 14:08:40 -0700368
369 impl ToTokens for WherePredicate {
370 fn to_tokens(&self, tokens: &mut Tokens) {
371 match *self {
372 WherePredicate::BoundPredicate(ref predicate) => {
373 predicate.to_tokens(tokens);
374 }
375 WherePredicate::RegionPredicate(ref predicate) => {
376 predicate.to_tokens(tokens);
377 }
378 }
379 }
380 }
381
382 impl ToTokens for WhereBoundPredicate {
383 fn to_tokens(&self, tokens: &mut Tokens) {
384 if !self.bound_lifetimes.is_empty() {
385 tokens.append("for");
386 tokens.append("<");
387 tokens.append_separated(&self.bound_lifetimes, ",");
388 tokens.append(">");
389 }
390 self.bounded_ty.to_tokens(tokens);
391 if !self.bounds.is_empty() {
392 tokens.append(":");
393 tokens.append_separated(&self.bounds, "+");
394 }
395 }
396 }
397
398 impl ToTokens for WhereRegionPredicate {
399 fn to_tokens(&self, tokens: &mut Tokens) {
400 self.lifetime.to_tokens(tokens);
401 if !self.bounds.is_empty() {
402 tokens.append(":");
403 tokens.append_separated(&self.bounds, "+");
404 }
405 }
406 }
David Tolnay87d0b442016-09-04 11:52:12 -0700407}