blob: dc3dd0d80b1adff8a9c6866545d6ba1953e1dd88 [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 Tolnayff3b8ae2016-10-08 11:54:18 -070086 let id = Ident::new(t);
87 if !id.as_ref().starts_with('\'') {
88 panic!("lifetime name must start with apostrophe as in \"'a\", \
David Tolnay3bcfb722016-10-08 11:58:36 -070089 got {:?}",
90 id.as_ref());
David Tolnayff3b8ae2016-10-08 11:54:18 -070091 }
92 Lifetime { ident: id }
David Tolnay01405f02016-10-02 09:05:02 -070093 }
94}
95
David Tolnay771ecf42016-09-23 19:26:37 -070096/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070097#[derive(Debug, Clone, Eq, PartialEq)]
98pub struct LifetimeDef {
99 pub lifetime: Lifetime,
100 pub bounds: Vec<Lifetime>,
101}
102
David Tolnayf9505b52016-10-02 09:18:52 -0700103impl LifetimeDef {
104 pub fn new<T: Into<Ident>>(t: T) -> Self {
105 LifetimeDef {
106 lifetime: Lifetime::new(t),
107 bounds: Vec::new(),
108 }
109 }
110}
111
David Tolnayb79ee962016-09-04 09:39:20 -0700112#[derive(Debug, Clone, Eq, PartialEq)]
113pub struct TyParam {
114 pub ident: Ident,
115 pub bounds: Vec<TyParamBound>,
116 pub default: Option<Ty>,
117}
118
David Tolnay771ecf42016-09-23 19:26:37 -0700119/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -0700120/// `typeck::collect::compute_bounds` matches these against
121/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -0700122/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -0700123#[derive(Debug, Clone, Eq, PartialEq)]
124pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -0700125 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -0700126 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -0700127}
128
David Tolnay771ecf42016-09-23 19:26:37 -0700129/// A modifier on a bound, currently this is only used for `?Sized`, where the
130/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -0700131#[derive(Debug, Copy, Clone, Eq, PartialEq)]
132pub enum TraitBoundModifier {
133 None,
134 Maybe,
135}
136
David Tolnay771ecf42016-09-23 19:26:37 -0700137/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -0700138#[derive(Debug, Clone, Eq, PartialEq, Default)]
139pub struct WhereClause {
140 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700141}
142
David Tolnayb153dbc2016-10-04 23:39:10 -0700143impl WhereClause {
144 pub fn none() -> Self {
David Tolnay2e737362016-10-05 23:44:15 -0700145 WhereClause { predicates: Vec::new() }
David Tolnayb153dbc2016-10-04 23:39:10 -0700146 }
147}
148
David Tolnayb79ee962016-09-04 09:39:20 -0700149/// A single predicate in a `where` clause
150#[derive(Debug, Clone, Eq, PartialEq)]
151pub enum WherePredicate {
152 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
153 BoundPredicate(WhereBoundPredicate),
154 /// A lifetime predicate, e.g. `'a: 'b+'c`
155 RegionPredicate(WhereRegionPredicate),
156}
157
158/// A type bound.
159///
160/// E.g. `for<'c> Foo: Send+Clone+'c`
161#[derive(Debug, Clone, Eq, PartialEq)]
162pub struct WhereBoundPredicate {
163 /// Any lifetimes from a `for` binding
164 pub bound_lifetimes: Vec<LifetimeDef>,
165 /// The type being bounded
166 pub bounded_ty: Ty,
167 /// Trait and lifetime bounds (`Clone+Send+'static`)
168 pub bounds: Vec<TyParamBound>,
169}
170
171/// A lifetime predicate.
172///
173/// E.g. `'a: 'b+'c`
174#[derive(Debug, Clone, Eq, PartialEq)]
175pub struct WhereRegionPredicate {
176 pub lifetime: Lifetime,
177 pub bounds: Vec<Lifetime>,
178}
179
David Tolnay86eca752016-09-04 11:26:41 -0700180#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700181pub mod parsing {
182 use super::*;
David Tolnay55337722016-09-11 12:58:56 -0700183 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700184 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700185
David Tolnay3cf52982016-10-01 17:11:37 -0700186 named!(pub generics -> Generics, map!(
187 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700188 do_parse!(
189 punct!("<") >>
190 lifetimes: separated_list!(punct!(","), lifetime_def) >>
191 ty_params: opt_vec!(preceded!(
192 cond!(!lifetimes.is_empty(), punct!(",")),
193 separated_nonempty_list!(punct!(","), ty_param)
194 )) >>
195 punct!(">") >>
196 (lifetimes, ty_params)
197 )
198 |
199 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700200 ),
201 |(lifetimes, ty_params)| Generics {
202 lifetimes: lifetimes,
203 ty_params: ty_params,
204 where_clause: Default::default(),
205 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700206 ));
207
David Tolnayb5a7b142016-09-13 22:46:39 -0700208 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700209 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700210 map!(ident, |id| Lifetime {
211 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700212 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700213 ));
214
David Tolnayb5a7b142016-09-13 22:46:39 -0700215 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700216 life: lifetime >>
217 bounds: opt_vec!(preceded!(
218 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700219 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700220 )) >>
221 (LifetimeDef {
222 lifetime: life,
223 bounds: bounds,
224 })
225 ));
226
David Tolnayb5a7b142016-09-13 22:46:39 -0700227 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700228 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700229 punct!("<") >>
230 lifetimes: separated_list!(punct!(","), lifetime_def) >>
231 punct!(">") >>
232 (lifetimes)
233 )));
234
David Tolnayb5a7b142016-09-13 22:46:39 -0700235 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700236 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700237 bounds: opt_vec!(preceded!(
238 punct!(":"),
239 separated_nonempty_list!(punct!("+"), ty_param_bound)
240 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700241 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700242 punct!("="),
243 ty
244 )) >>
245 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700246 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700247 bounds: bounds,
248 default: default,
249 })
250 ));
251
David Tolnayb5a7b142016-09-13 22:46:39 -0700252 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700253 preceded!(punct!("?"), poly_trait_ref) => {
254 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
255 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700256 |
257 lifetime => { TyParamBound::Region }
258 |
David Tolnay55337722016-09-11 12:58:56 -0700259 poly_trait_ref => {
260 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
261 }
262 ));
263
David Tolnayb5a7b142016-09-13 22:46:39 -0700264 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700265 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700266 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700267 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
268 option!(punct!(",")) >>
269 (WhereClause { predicates: predicates })
270 )
271 |
272 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700273 ));
274
David Tolnayb5a7b142016-09-13 22:46:39 -0700275 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700276 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700277 ident: lifetime >>
278 punct!(":") >>
279 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
280 (WherePredicate::RegionPredicate(WhereRegionPredicate {
281 lifetime: ident,
282 bounds: bounds,
283 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700284 )
285 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700286 do_parse!(
287 bound_lifetimes: bound_lifetimes >>
288 bounded_ty: ty >>
289 punct!(":") >>
290 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
291 (WherePredicate::BoundPredicate(WhereBoundPredicate {
292 bound_lifetimes: bound_lifetimes,
293 bounded_ty: bounded_ty,
294 bounds: bounds,
295 }))
296 )
297 ));
298}
David Tolnay87d0b442016-09-04 11:52:12 -0700299
300#[cfg(feature = "printing")]
301mod printing {
302 use super::*;
303 use quote::{Tokens, ToTokens};
304
David Tolnay8ef93042016-09-04 14:08:40 -0700305 impl ToTokens for Generics {
306 fn to_tokens(&self, tokens: &mut Tokens) {
307 let has_lifetimes = !self.lifetimes.is_empty();
308 let has_ty_params = !self.ty_params.is_empty();
309 if has_lifetimes || has_ty_params {
310 tokens.append("<");
311 tokens.append_separated(&self.lifetimes, ",");
312 if has_lifetimes && has_ty_params {
313 tokens.append(",");
314 }
315 tokens.append_separated(&self.ty_params, ",");
316 tokens.append(">");
317 }
David Tolnay8ef93042016-09-04 14:08:40 -0700318 }
319 }
320
David Tolnay87d0b442016-09-04 11:52:12 -0700321 impl ToTokens for Lifetime {
322 fn to_tokens(&self, tokens: &mut Tokens) {
323 self.ident.to_tokens(tokens);
324 }
325 }
326
327 impl ToTokens for LifetimeDef {
328 fn to_tokens(&self, tokens: &mut Tokens) {
329 self.lifetime.to_tokens(tokens);
330 if !self.bounds.is_empty() {
331 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700332 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700333 }
334 }
335 }
336
David Tolnay8ef93042016-09-04 14:08:40 -0700337 impl ToTokens for TyParam {
338 fn to_tokens(&self, tokens: &mut Tokens) {
339 self.ident.to_tokens(tokens);
340 if !self.bounds.is_empty() {
341 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700342 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700343 }
344 if let Some(ref default) = self.default {
345 tokens.append("=");
346 default.to_tokens(tokens);
347 }
348 }
349 }
350
David Tolnay87d0b442016-09-04 11:52:12 -0700351 impl ToTokens for TyParamBound {
352 fn to_tokens(&self, tokens: &mut Tokens) {
353 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700354 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700355 TyParamBound::Trait(ref trait_ref, modifier) => {
356 match modifier {
357 TraitBoundModifier::None => {}
358 TraitBoundModifier::Maybe => tokens.append("?"),
359 }
360 trait_ref.to_tokens(tokens);
361 }
362 }
363 }
364 }
365
366 impl ToTokens for WhereClause {
367 fn to_tokens(&self, tokens: &mut Tokens) {
368 if !self.predicates.is_empty() {
369 tokens.append("where");
370 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700371 }
372 }
373 }
David Tolnay8ef93042016-09-04 14:08:40 -0700374
375 impl ToTokens for WherePredicate {
376 fn to_tokens(&self, tokens: &mut Tokens) {
377 match *self {
378 WherePredicate::BoundPredicate(ref predicate) => {
379 predicate.to_tokens(tokens);
380 }
381 WherePredicate::RegionPredicate(ref predicate) => {
382 predicate.to_tokens(tokens);
383 }
384 }
385 }
386 }
387
388 impl ToTokens for WhereBoundPredicate {
389 fn to_tokens(&self, tokens: &mut Tokens) {
390 if !self.bound_lifetimes.is_empty() {
391 tokens.append("for");
392 tokens.append("<");
393 tokens.append_separated(&self.bound_lifetimes, ",");
394 tokens.append(">");
395 }
396 self.bounded_ty.to_tokens(tokens);
397 if !self.bounds.is_empty() {
398 tokens.append(":");
399 tokens.append_separated(&self.bounds, "+");
400 }
401 }
402 }
403
404 impl ToTokens for WhereRegionPredicate {
405 fn to_tokens(&self, tokens: &mut Tokens) {
406 self.lifetime.to_tokens(tokens);
407 if !self.bounds.is_empty() {
408 tokens.append(":");
409 tokens.append_separated(&self.bounds, "+");
410 }
411 }
412 }
David Tolnay87d0b442016-09-04 11:52:12 -0700413}