blob: 916ebb75dc89c3f9ab22d46c9069578eae6d6743 [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\", \
89 got {:?}", id.as_ref());
90 }
91 Lifetime { ident: id }
David Tolnay01405f02016-10-02 09:05:02 -070092 }
93}
94
David Tolnay771ecf42016-09-23 19:26:37 -070095/// A lifetime definition, e.g. `'a: 'b+'c+'d`
David Tolnayb79ee962016-09-04 09:39:20 -070096#[derive(Debug, Clone, Eq, PartialEq)]
97pub struct LifetimeDef {
98 pub lifetime: Lifetime,
99 pub bounds: Vec<Lifetime>,
100}
101
David Tolnayf9505b52016-10-02 09:18:52 -0700102impl LifetimeDef {
103 pub fn new<T: Into<Ident>>(t: T) -> Self {
104 LifetimeDef {
105 lifetime: Lifetime::new(t),
106 bounds: Vec::new(),
107 }
108 }
109}
110
David Tolnayb79ee962016-09-04 09:39:20 -0700111#[derive(Debug, Clone, Eq, PartialEq)]
112pub struct TyParam {
113 pub ident: Ident,
114 pub bounds: Vec<TyParamBound>,
115 pub default: Option<Ty>,
116}
117
David Tolnay771ecf42016-09-23 19:26:37 -0700118/// The AST represents all type param bounds as types.
David Tolnayaed77b02016-09-23 20:50:31 -0700119/// `typeck::collect::compute_bounds` matches these against
120/// the "special" built-in traits (see `middle::lang_items`) and
David Tolnay771ecf42016-09-23 19:26:37 -0700121/// detects Copy, Send and Sync.
David Tolnayb79ee962016-09-04 09:39:20 -0700122#[derive(Debug, Clone, Eq, PartialEq)]
123pub enum TyParamBound {
David Tolnay55337722016-09-11 12:58:56 -0700124 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -0700125 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -0700126}
127
David Tolnay771ecf42016-09-23 19:26:37 -0700128/// A modifier on a bound, currently this is only used for `?Sized`, where the
129/// modifier is `Maybe`. Negative bounds should also be handled here.
David Tolnay55337722016-09-11 12:58:56 -0700130#[derive(Debug, Copy, Clone, Eq, PartialEq)]
131pub enum TraitBoundModifier {
132 None,
133 Maybe,
134}
135
David Tolnay771ecf42016-09-23 19:26:37 -0700136/// A `where` clause in a definition
David Tolnay55337722016-09-11 12:58:56 -0700137#[derive(Debug, Clone, Eq, PartialEq, Default)]
138pub struct WhereClause {
139 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -0700140}
141
David Tolnayb153dbc2016-10-04 23:39:10 -0700142impl WhereClause {
143 pub fn none() -> Self {
David Tolnay2e737362016-10-05 23:44:15 -0700144 WhereClause { predicates: Vec::new() }
David Tolnayb153dbc2016-10-04 23:39:10 -0700145 }
146}
147
David Tolnayb79ee962016-09-04 09:39:20 -0700148/// A single predicate in a `where` clause
149#[derive(Debug, Clone, Eq, PartialEq)]
150pub enum WherePredicate {
151 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
152 BoundPredicate(WhereBoundPredicate),
153 /// A lifetime predicate, e.g. `'a: 'b+'c`
154 RegionPredicate(WhereRegionPredicate),
155}
156
157/// A type bound.
158///
159/// E.g. `for<'c> Foo: Send+Clone+'c`
160#[derive(Debug, Clone, Eq, PartialEq)]
161pub struct WhereBoundPredicate {
162 /// Any lifetimes from a `for` binding
163 pub bound_lifetimes: Vec<LifetimeDef>,
164 /// The type being bounded
165 pub bounded_ty: Ty,
166 /// Trait and lifetime bounds (`Clone+Send+'static`)
167 pub bounds: Vec<TyParamBound>,
168}
169
170/// A lifetime predicate.
171///
172/// E.g. `'a: 'b+'c`
173#[derive(Debug, Clone, Eq, PartialEq)]
174pub struct WhereRegionPredicate {
175 pub lifetime: Lifetime,
176 pub bounds: Vec<Lifetime>,
177}
178
David Tolnay86eca752016-09-04 11:26:41 -0700179#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700180pub mod parsing {
181 use super::*;
David Tolnay55337722016-09-11 12:58:56 -0700182 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -0700183 use ty::parsing::{ty, poly_trait_ref};
David Tolnay9d8f1972016-09-04 11:58:48 -0700184
David Tolnay3cf52982016-10-01 17:11:37 -0700185 named!(pub generics -> Generics, map!(
186 alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700187 do_parse!(
188 punct!("<") >>
189 lifetimes: separated_list!(punct!(","), lifetime_def) >>
190 ty_params: opt_vec!(preceded!(
191 cond!(!lifetimes.is_empty(), punct!(",")),
192 separated_nonempty_list!(punct!(","), ty_param)
193 )) >>
194 punct!(">") >>
195 (lifetimes, ty_params)
196 )
197 |
198 epsilon!() => { |_| (Vec::new(), Vec::new()) }
David Tolnay3cf52982016-10-01 17:11:37 -0700199 ),
200 |(lifetimes, ty_params)| Generics {
201 lifetimes: lifetimes,
202 ty_params: ty_params,
203 where_clause: Default::default(),
204 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700205 ));
206
David Tolnayb5a7b142016-09-13 22:46:39 -0700207 named!(pub lifetime -> Lifetime, preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700208 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700209 map!(ident, |id| Lifetime {
210 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700211 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700212 ));
213
David Tolnayb5a7b142016-09-13 22:46:39 -0700214 named!(pub lifetime_def -> LifetimeDef, do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700215 life: lifetime >>
216 bounds: opt_vec!(preceded!(
217 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700218 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700219 )) >>
220 (LifetimeDef {
221 lifetime: life,
222 bounds: bounds,
223 })
224 ));
225
David Tolnayb5a7b142016-09-13 22:46:39 -0700226 named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700227 keyword!("for") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700228 punct!("<") >>
229 lifetimes: separated_list!(punct!(","), lifetime_def) >>
230 punct!(">") >>
231 (lifetimes)
232 )));
233
David Tolnayb5a7b142016-09-13 22:46:39 -0700234 named!(ty_param -> TyParam, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700235 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700236 bounds: opt_vec!(preceded!(
237 punct!(":"),
238 separated_nonempty_list!(punct!("+"), ty_param_bound)
239 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700240 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700241 punct!("="),
242 ty
243 )) >>
244 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700245 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700246 bounds: bounds,
247 default: default,
248 })
249 ));
250
David Tolnayb5a7b142016-09-13 22:46:39 -0700251 named!(pub ty_param_bound -> TyParamBound, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700252 preceded!(punct!("?"), poly_trait_ref) => {
253 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
254 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700255 |
256 lifetime => { TyParamBound::Region }
257 |
David Tolnay55337722016-09-11 12:58:56 -0700258 poly_trait_ref => {
259 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
260 }
261 ));
262
David Tolnayb5a7b142016-09-13 22:46:39 -0700263 named!(pub where_clause -> WhereClause, alt!(
David Tolnay55337722016-09-11 12:58:56 -0700264 do_parse!(
David Tolnay10413f02016-09-30 09:12:02 -0700265 keyword!("where") >>
David Tolnay55337722016-09-11 12:58:56 -0700266 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
267 option!(punct!(",")) >>
268 (WhereClause { predicates: predicates })
269 )
270 |
271 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700272 ));
273
David Tolnayb5a7b142016-09-13 22:46:39 -0700274 named!(where_predicate -> WherePredicate, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700275 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700276 ident: lifetime >>
277 punct!(":") >>
278 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
279 (WherePredicate::RegionPredicate(WhereRegionPredicate {
280 lifetime: ident,
281 bounds: bounds,
282 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700283 )
284 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700285 do_parse!(
286 bound_lifetimes: bound_lifetimes >>
287 bounded_ty: ty >>
288 punct!(":") >>
289 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
290 (WherePredicate::BoundPredicate(WhereBoundPredicate {
291 bound_lifetimes: bound_lifetimes,
292 bounded_ty: bounded_ty,
293 bounds: bounds,
294 }))
295 )
296 ));
297}
David Tolnay87d0b442016-09-04 11:52:12 -0700298
299#[cfg(feature = "printing")]
300mod printing {
301 use super::*;
302 use quote::{Tokens, ToTokens};
303
David Tolnay8ef93042016-09-04 14:08:40 -0700304 impl ToTokens for Generics {
305 fn to_tokens(&self, tokens: &mut Tokens) {
306 let has_lifetimes = !self.lifetimes.is_empty();
307 let has_ty_params = !self.ty_params.is_empty();
308 if has_lifetimes || has_ty_params {
309 tokens.append("<");
310 tokens.append_separated(&self.lifetimes, ",");
311 if has_lifetimes && has_ty_params {
312 tokens.append(",");
313 }
314 tokens.append_separated(&self.ty_params, ",");
315 tokens.append(">");
316 }
David Tolnay8ef93042016-09-04 14:08:40 -0700317 }
318 }
319
David Tolnay87d0b442016-09-04 11:52:12 -0700320 impl ToTokens for Lifetime {
321 fn to_tokens(&self, tokens: &mut Tokens) {
322 self.ident.to_tokens(tokens);
323 }
324 }
325
326 impl ToTokens for LifetimeDef {
327 fn to_tokens(&self, tokens: &mut Tokens) {
328 self.lifetime.to_tokens(tokens);
329 if !self.bounds.is_empty() {
330 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700331 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700332 }
333 }
334 }
335
David Tolnay8ef93042016-09-04 14:08:40 -0700336 impl ToTokens for TyParam {
337 fn to_tokens(&self, tokens: &mut Tokens) {
338 self.ident.to_tokens(tokens);
339 if !self.bounds.is_empty() {
340 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700341 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700342 }
343 if let Some(ref default) = self.default {
344 tokens.append("=");
345 default.to_tokens(tokens);
346 }
347 }
348 }
349
David Tolnay87d0b442016-09-04 11:52:12 -0700350 impl ToTokens for TyParamBound {
351 fn to_tokens(&self, tokens: &mut Tokens) {
352 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700353 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700354 TyParamBound::Trait(ref trait_ref, modifier) => {
355 match modifier {
356 TraitBoundModifier::None => {}
357 TraitBoundModifier::Maybe => tokens.append("?"),
358 }
359 trait_ref.to_tokens(tokens);
360 }
361 }
362 }
363 }
364
365 impl ToTokens for WhereClause {
366 fn to_tokens(&self, tokens: &mut Tokens) {
367 if !self.predicates.is_empty() {
368 tokens.append("where");
369 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700370 }
371 }
372 }
David Tolnay8ef93042016-09-04 14:08:40 -0700373
374 impl ToTokens for WherePredicate {
375 fn to_tokens(&self, tokens: &mut Tokens) {
376 match *self {
377 WherePredicate::BoundPredicate(ref predicate) => {
378 predicate.to_tokens(tokens);
379 }
380 WherePredicate::RegionPredicate(ref predicate) => {
381 predicate.to_tokens(tokens);
382 }
383 }
384 }
385 }
386
387 impl ToTokens for WhereBoundPredicate {
388 fn to_tokens(&self, tokens: &mut Tokens) {
389 if !self.bound_lifetimes.is_empty() {
390 tokens.append("for");
391 tokens.append("<");
392 tokens.append_separated(&self.bound_lifetimes, ",");
393 tokens.append(">");
394 }
395 self.bounded_ty.to_tokens(tokens);
396 if !self.bounds.is_empty() {
397 tokens.append(":");
398 tokens.append_separated(&self.bounds, "+");
399 }
400 }
401 }
402
403 impl ToTokens for WhereRegionPredicate {
404 fn to_tokens(&self, tokens: &mut Tokens) {
405 self.lifetime.to_tokens(tokens);
406 if !self.bounds.is_empty() {
407 tokens.append(":");
408 tokens.append_separated(&self.bounds, "+");
409 }
410 }
411 }
David Tolnay87d0b442016-09-04 11:52:12 -0700412}